Actualmente estoy tratando de conectarme a una API REST de AWS que requiere al menos TLS v1.2. La documentación establece que los clientes también deben admitir conjuntos de cifrado con secreto directo perfecto (PFS) como Ephemeral Diffie-Hellman (DHE) o Elliptic Curve Ephemeral Diffie-Hellman (ECDHE).
Al enviar una solicitud GET
mediante HttpClient
, la conexión simplemente se agota. Configuré la versión TLS explícitamente en TLSv1.2
de esta manera:
httpClientHandler.SslProtocols = SslProtocols.Tls12;
Esto funciona, puedo ver en el seguimiento de Wireshark que se usa la versión TLS correcta. También he confirmado que no hay ningún problema de firewall o similar.
Cuando uso cURL, puedo ver que el conjunto de cifrado en la respuesta de Sever Hello
es TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (0xc030)
, que también es lo que requiere el servidor.
Cuando se usa HttpClient
en .NET 6, el conjunto de cifrado mencionado anteriormente se ofrece en Client Hello
, pero la respuesta del servidor usa de repente TLS_RSA_WITH_AES_256_GCM_SHA384
:
Puedo ver que hay extensiones adicionales en la solicitud de cURL, por ejemplo, Extension: psk_key_exchange_modes
. ¿Hay alguna explicación de por qué el servidor no exceptúa el primer conjunto de cifrado? Según tengo entendido, el primer conjunto de cifrado ofrecido debería ser el preferido, ¿es correcto?
¿Hay alguna manera de forzar un determinado conjunto de cifrado en .NET 6?
Este es el ejemplo que uso para reproducir el problema:
public async void PollUrl(string url) { HttpResponseMessage msg = new HttpResponseMessage(); ServicePointManager.Expect100Continue = true; ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls12 | SecurityProtocolType.Tls13; using HttpClientHandler httpClientHandler = new(); httpClientHandler.ServerCertificateCustomValidationCallback = (message, cert, chain, sslPolicyErrors) => true; httpClientHandler.SslProtocols = SslProtocols.Tls12; using HttpClient client = new(httpClientHandler); // This content type is required for the API call client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/xml")); try { client.Timeout = TimeSpan.FromSeconds(5); msg = await client.GetAsync(url); } catch (Exception e) { Console.WriteLine(e); } string stringValue = await msg.Content.ReadAsStringAsync(); Console.WriteLine(stringValue); }
La aplicación se ejecuta en el servidor 2016.