0

In .NET 4.8 we are trying to establish a TLS connection using a machine certificate. One one machine, that works fine, on a different machine the exact same code will throw:

System.ServiceModel.Security.SecurityNegotiationException: Could not establish secure channel for SSL/TLS with authority '[Wcf Service]'. ---> System.Net.WebException: The request was aborted: Could not create SSL/TLS secure channel. at System.Net.HttpWebRequest.GetResponse()

Wireshark shows this on the machine where the connection works:

3.590109    ClientIp    ServerIp    TLSv1.2 221 Client Hello
3.617942    ServerIp    ClientIp    TLSv1.2 1514    Server Hello
3.618151    ServerIp    ClientIp    TLSv1.2 1143    Certificate, Server Key Exchange, Certificate Request, Server Hello Done
3.627569    ClientIp    ServerIp    TLSv1.2 3593    Certificate, Client Key Exchange, Certificate Verify, Change Cipher Spec, Encrypted Handshake Message
3.660094    ServerIp    ClientIp    TLSv1.2 105 Change Cipher Spec, Encrypted Handshake Message

Connection established, data flowing. The exact same client (a .NET program) on a different machine is not so lucky, I can see in Wireshark that the client just does not seem to answer to the server's certificate request:

10.792079   ClientIp    ProxyIp TLSv1.2 221 Client Hello
10.827628   ServerIp    ClientIp    TLSv1.2 1374    Server Hello
10.827753   ServerIp    ClientIp    TLSv1.2 1374    Certificate [TCP segment of a reassembled PDU]
10.827840   ServerIp    ClientIp    TLSv1.2 103 Server Key Exchange, Certificate Request, Server Hello Done

Is there anything in .NET or the machine configuration that could cause the WebClient to stop responding to the certificate request?

This looks very much like our problem. But all certificates in our certificate chain use SHA256 hashes. Also, a certificate error should not arise on one machine and not on the other. We checked that all involved root / intermediate certificates are present on both machines. If the .NET client has problems loading the certificate from the machine store, we get a different exception.

EDIT: Sample Code

public static void Test()
{
    try
    {
        WebRequest.DefaultWebProxy = new WebProxy("[proxy.local]", 8080)
        {
            Credentials = new NetworkCredential("[proxyUser]", "[proxyPassword]")
        };

        X509Store store = new X509Store("MY", StoreLocation.LocalMachine);
        store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);

        X509Certificate2Collection collection = (X509Certificate2Collection)store.Certificates;
        X509Certificate2Collection fcollection = (X509Certificate2Collection)collection.Find(X509FindType.FindByTimeValid, DateTime.Now, false);

        X509Certificate2 certificate = null;
        foreach (var c in fcollection)
        {
            if (c.SerialNumber == "112233")
            {
                certificate = c;
                break;
            }
        }

        ServicePointManager.ServerCertificateValidationCallback = (a, b, c, d) => true;
        HttpWebRequest req = (HttpWebRequest)WebRequest.Create("[TheUrl]");
        req.AllowAutoRedirect = true;
        req.ClientCertificates.Add(certificate);
        req.Method = "GET";
        WebResponse resp = req.GetResponse();

        Stream stream = resp.GetResponseStream();
        using (StreamReader reader = new StreamReader(stream))
        {
            string line = reader.ReadLine();
            while (line != null)
            {
                Console.WriteLine(line);
                line = reader.ReadLine();
            }
        }

        stream.Close();
    }
    catch (Exception e)
    {
        Console.WriteLine(e);
    }
}
TvdH
  • 1,088
  • 14
  • 29
  • `root / intermediate certificates are present on both machines` where are they present? Please also [ediy] and add your code that tells WebClient to authenticate the client-side – Charlieface Apr 18 '21 at 19:46
  • 1
    I assume the `certificate` variable is not null. What are the permissions on the certificate's private key? https://www.codyhosterman.com/2019/06/assigning-read-access-to-windows-private-key/ – Charlieface Apr 18 '21 at 20:37
  • You are right on! But sadly, this solved the connection problem on my local dev machine, but it did not make a difference on the servers (W2012 R2). – TvdH Apr 19 '21 at 07:23
  • Right on about what, `certificate` or permissions? And what did you try to fix it – Charlieface Apr 19 '21 at 09:46
  • Yes permission of the private key fixed the problem on my Windows 10 desktop. But the Windows 2012 R2 servers still have the TLS/SSL problem. I believe that maybe Windows 2012 R2 does not support a required cipher. Still in the dark. – TvdH Apr 19 '21 at 10:45
  • See https://www.admin-enclave.com/en/articles/windows/305-enable-tls-1-2-on-windows-2012-r2.html and https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2012-R2-and-2012/dn786418(v=ws.11)?redirectedfrom=MSDN – Charlieface Apr 19 '21 at 12:13
  • No, TLS 1.2 is working in general, only the client stops responding in the middle of negotiation. We installed the client on a Windows 2019 server, and the connection works there (same proxy, same everything). I think a cipher missing in W2012 R2 is the culprit. We will move to W2019 because of this. – TvdH Apr 19 '21 at 12:26

0 Answers0