Schannel TLS Decrypt Error (Pure C)

Pablo Diez 0 Puntos de reputación
2024-12-15T16:13:50.1666667+00:00

Buenas, estoy desarrollando un programa con sockets en puro "C" y estoy mirando de cifrar las conexiones con TLS, estoy usando schannel, el handshake TLS esta completado, puedo ver desde WireShark los siguientes mensajes:

7983 1534.290037 192.168.131.34 192.168.131.34 TLSv1.2 191 Client Hello

7985 1534.290850 192.168.131.34 192.168.131.34 TLSv1.2 1292 Server Hello, Certificate, Server Key Exchange, Server Hello Done

7987 1534.293445 192.168.131.34 192.168.131.34 TLSv1.2 202 Client Key Exchange, Change Cipher Spec, Encrypted Handshake Message

7989 1534.294099 192.168.131.34 192.168.131.34 TLSv1.2 95 Change Cipher Spec, Encrypted Handshake Message


Conozco que existen las funciones "EncryptMessage" y "DecryptMessage" que el servidor cifra con su hContext y el cliente descifra con su hContext configurado después del Handshake TLS.

He creado dos funciones que facilitan el envió y recibo de mensajes cifrados, en concreto tengo dos funciones "SendEncrypted" y "ReciveEncrypted". La funcion de SendEncrypted funciona perfecto y permite cifrar y enviar mensajes. Desde wireshark veo como lo detecta como application data.

El cliente lo recibe, puedo ver como llega la data, mostrarla en hexadecimal, pero a la hora de descifrar arroja el siguiente error

Encrypted data (hex): 17 03 03 00 1f 00 00 00 00 00 00 00 01 2d 15 8b ef 38 95 49 7a 3f 63 3f 09 7c f7 b7 44 2b 00 88 00 00 00 00
DecryptMessage failed with error code: 0x80090330 (SEC_E_DECRYPT_FAILURE)

Se ve como tiene los encabezados correctos (o eso creo)

17: Application data
03 03: Version del protocolo TLS (TLS 1.2)

Otra cosa que veo, con el siguiente codigo:

SecPkgContext_ConnectionInfo connInfo;

if (QueryContextAttributes(&hContext, SECPKG_ATTR_CONNECTION_INFO, &connInfo) == SEC_E_OK) {
printf("TLS protocol: %u\n", connInfo.dwProtocol); // Debe ser TLS 1.2 o 1.3
else {
    printf("Failed to query context attributes\n");
}   

Es que el servidor arroja 1024 y el cliente 2048, no se si esto puede ser un error, creo saber que se debe a las longitudes de las claves.

Cabe recalcar que se esta usando un certificado autofirmado para TLS con RSA 2048, he configurado el cliente para confiar en el certificado con lo siguiente y no creo que sea un problema ya que la funcion "InitializeSecurityContext" ya no me da error de SEC_E_UNTRUSTED_ROOT

schannelCred.dwFlags = SCH_CRED_NO_DEFAULT_CREDS | SCH_CRED_MANUAL_CRED_VALIDATION | SCH_CRED_IGNORE_NO_REVOCATION_CHECK | SCH_CRED_IGNORE_REVOCATION_OFFLINE | SCH_CRED_NO_SERVERNAME_CHECK;
  • Server: TLS protocol: 1024
  • Client: TLS protocol: 2048

El problema grave es el no poder descifrar los mensajes enviados, os dejo un código parcial de la funcion de como estoy descifrando el mensaje una vez recibido, no he conseguido pasar de "DecryptMEssage failed with error code: ..."

...
	char encryptedData[4096]; // Buffer para los datos cifrados
    SecBuffer InBuffers[4];
    SecBufferDesc InBuffer;

    // Recibir datos cifrados desde el servidor
    int bytesReceived = recv(conn, encryptedData, sizeof(encryptedData), 0);
    if (bytesReceived <= 0) {
        printf("recv failed or connection closed\n");
        return SOCKET_ERROR;
    }

    printf("Encrypted data (hex): ");
    for (int i = 0; i < bytesReceived; i++) {
        printf("%02x ", (unsigned char)encryptedData[i]);
    }
    printf("\n");
 
    InBuffers[0].pvBuffer = encryptedData;
    InBuffers[0].cbBuffer = bytesReceived;
    InBuffers[0].BufferType = SECBUFFER_DATA;

    InBuffers[1].BufferType = SECBUFFER_EMPTY;
    InBuffers[2].BufferType = SECBUFFER_EMPTY;
    InBuffers[3].BufferType = SECBUFFER_EMPTY;

    InBuffer.cBuffers = ARRAYSIZE(InBuffers);
    InBuffer.pBuffers = InBuffers;
    InBuffer.ulVersion = SECBUFFER_VERSION;

 
    SECURITY_STATUS secStatus = DecryptMessage(hContext, &InBuffer, 0, NULL);
    if (secStatus != SEC_E_OK) {
        printf("DecryptMessage failed with error code: 0x%x\n", secStatus); // No pasa de aquí
        if (secStatus == SEC_E_CONTEXT_EXPIRED) {
            printf("The context has expired. Re-handshake may be needed.\n");
        }
        return SOCKET_ERROR;
    }

Muchas gracias de antemano.

ASP.NET
ASP.NET
Conjunto de tecnologías de .NET Framework para la creación de aplicaciones y servicios web XML.
46 preguntas
0 comentarios No hay comentarios
{count} votos

6 respuestas

Ordenar por: Muy útil
  1. Jonathan Pereira Castillo 10,505 Puntos de reputación Proveedor de Microsoft
    2024-12-23T16:30:31.1933333+00:00

    ¡Hola Pablo Diez!

    Entiendo que estás enfrentando un problema complejo y frustrante. Vamos a intentar desglosarlo y ver si podemos encontrar una solución.

    Verificación de la Longitud de los Datos Cifrados

    Parece que la longitud de los datos cifrados es consistente entre el cliente y el servidor, lo cual es un buen punto de partida.

    Alineación y Configuración de los Buffers

    Cuando se habla de "alineación" de los buffers, se refiere a asegurarse de que los datos estén correctamente organizados y que no haya desbordamientos o datos adicionales que puedan causar problemas. En tu código, los buffers parecen estar bien configurados, pero asegúrate de que encryptedData y bytesReceived contengan los datos correctos y que no haya corrupción de datos.

    Revisión de las Versiones del Protocolo TLS

    Has mencionado que estás usando TLS 1.2, lo cual es adecuado. Asegúrate de que tanto el cliente como el servidor estén configurados para usar el mismo conjunto de cifrados y versiones de protocolo.

    Certificados y Claves

    Dado que has añadido el certificado en la raíz de certificados y el problema persiste, es menos probable que este sea el problema. Sin embargo, asegúrate de que el certificado no esté caducado y que las claves privadas sean correctas.

    Debugging de Schannel

    Para depurar más a fondo el problema de "decrypt failure" con Schannel, puedes habilitar el registro detallado de Schannel en el registro de Windows. Aquí tienes cómo hacerlo:

    Abrir el Editor del Registro:

    • Presiona Win + R, escribe regedit y presiona Enter.

    Navegar a la Clave de Registro:

    • Ve a HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL.

    Crear o Modificar Valores:

    • Crea o modifica los siguientes valores DWORD:
    • EventLogging y establece su valor a 0x00000001 para habilitar el registro detallado.

    Reiniciar el Sistema:

    • Reinicia tu sistema para que los cambios surtan efecto.

    Revisar los Registros:

    • Después de reiniciar, reproduce el problema y revisa los registros en el Visor de Eventos bajo Aplicación y Servicios Logs -> Microsoft -> Windows -> Schannel.

    Herramientas Adicionales

    • Wireshark: Puedes usar Wireshark para capturar y analizar el tráfico de red. Esto puede ayudarte a identificar si hay problemas en la negociación del protocolo TLS.
    • SSL Labs: Usa la herramienta de prueba de SSL Labs para verificar la configuración del servidor TLS.

    Espero que estos pasos te ayuden a identificar y resolver el problema.

    Saludos,

    Jonathan.

    ----------*

    Tu opinión es muy importante para nosotros! Si esta respuesta resolvió tu consulta, por favor haz clic en 'SÍ'. Esto nos ayuda a mejorar continuamente la calidad y relevancia de nuestras soluciones.

    0 comentarios No hay comentarios

Su respuesta

Las respuestas se pueden marcar como respuestas aceptadas por el autor de la pregunta, lo que ayuda a los usuarios a conocer la respuesta que resolvió el problema del autor.