Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

error:14094410:SSL routines:ssl3_read_bytes:sslv3 alert handshake failure while using .NET Core #28473

Closed
ramsubbaraoc opened this issue Jan 22, 2019 · 19 comments
Labels
area-System.Net.Security os-linux Linux OS (any supported distro) question Answer questions and provide assistance, not an issue with source code or documentation.
Milestone

Comments

@ramsubbaraoc
Copy link

I get the following error during Authentication on Linux:

System.Security.Authentication.AuthenticationException: Authentication failed, see inner exception. 
---> Interop+OpenSsl+SslException: SSL Handshake failed with OpenSSL error - SSL_ERROR_SSL. 
---> Interop+Crypto+OpenSslCryptographicException: error:14094410:SSL routines:ssl3_read_bytes:sslv3 alert handshake failure
   --- End of inner exception stack trace ---
   at Interop.OpenSsl.DoSslHandshake(SafeSslHandle context, Byte[] recvBuf, Int32 recvOffset, Int32 recvCount, Byte[]& sendBuf, Int32& sendCount)
   at System.Net.Security.SslStreamPal.HandshakeInternal(SafeFreeCredentials credential, SafeDeleteContext& context, SecurityBuffer inputBuffer, SecurityBuffer outputBuffer, SslAuthenticationOptions sslAuthenticationOptions)

I had added the certificates using the following code:

         X509Store personalStore = new X509Store(StoreName.Root, StoreLocation.CurrentUser);
            personalStore.Open(OpenFlags.ReadWrite);
            X509Certificate2Collection collection2 = new X509Certificate2Collection();

            collection2.Import("client.p12", "12345", X509KeyStorageFlags.PersistKeySet);
            Console.WriteLine("Adding certificates into trusted store");
            foreach (X509Certificate2 cert in collection2)
            {
                Console.WriteLine("Subject is: '{0}'", cert.Subject);
                Console.WriteLine("Issuer is:  '{0}'", cert.Issuer);
                personalStore.Add(cert);
            }

The error occurs during authentication and during the following call stream.AuthenticateAsClient(SERVERNAME, currentClientCerts, sslProtocol, sslCertRevocationCheck);

@ramsubbaraoc
Copy link
Author

@bartonjs Please can you provide your inputs on this issue.

@bartonjs
Copy link
Member

IIRC, alert handshake failure means the other party (the server role, in this case) sent an alert and closed the connection. You'd need to grab a network trace to see what happened (no mutual ciphersuites, no mutual protocols, etc).

@ramsubbaraoc
Copy link
Author

ramsubbaraoc commented Jan 22, 2019

@bartonjs:Thank you for the response,the server had closed the connection because the client hadn't provided the certificate even after the server requested for the certificate.
Is there a way to figure out if the client had sent the certificate or not?

@bartonjs
Copy link
Member

Is there a way to figure out if the client had sent the certificate or not?

IIRC: if currentClientCerts only contains one value, and HasPrivateKey is true, it's always sent (if the server says it will accept a client cert).

Wireshark/et-al will of course say whether or not the client sent one.

Otherwise, I'm not sure. @davidsh?

@ramsubbaraoc
Copy link
Author

HasPrivateKey value is true.I did check that

@davidsh
Copy link
Contributor

davidsh commented Jan 22, 2019

IIRC: if currentClientCerts only contains one value, and HasPrivateKey is true, it's always sent (if the server says it will accept a client cert).

Actually, "it's always sent" is not true. HttpClient and SslStream will still filter the collection of client certificates to find one meets all criteria to be sent. So, for example, If the certificate has EKU attribute, then it must contain 'Client Authentication'. And similarly for KU attribute, it must have 'Digital Signature', etc.

Wireshark/et-al will of course say whether or not the client sent one.
Otherwise, I'm not sure. @davidsh?

Wireshark can detect this usually but I thought that the sending of the client certificate is done after the channel is encrypted. So, unless you have TLS decryption you wouldn't see this.

You can turn on System.Net tracing and it should indicate information about client certificates being sent:

https://github.com/dotnet/corefx/blob/master/Documentation/debugging/windows-instructions.md#Traces

@bartonjs
Copy link
Member

I thought that the sending of the client certificate is done after the channel is encrypted

In TLS 1.2 the optional client certificate is one of the last things before the ChangeCipherSpec. In TLS 1.3 both certs are after the first ChangeCipherSpec, making it much harder to debug with Wireshark 😄.

@ramsubbaraoc
Copy link
Author

@davidsh @bartonjs Thank you
The same configuration works on windows,but on linux it fails with error i have stated.

@ramsubbaraoc
Copy link
Author

@davidsh Please can you provide a way to debug on Linux

@ramsubbaraoc
Copy link
Author

ramsubbaraoc commented Jan 31, 2019

@davidsh @bartonjs
I was able to resolve the issue by modifying my sample which adds the certificate to the keystore.Following is the sample that i had used:

           X509Store personalStore = new X509Store(StoreName.Root, StoreLocation.CurrentUser);
            personalStore.Open(OpenFlags.ReadWrite);
            X509Certificate2Collection personalStoreCertificateCollection = (X509Certificate2Collection)personalStore.Certificates;
            int i = 0;
            foreach (X509Certificate2 x509 in personalStoreCertificateCollection)
            {
                personalStore.Remove(x509);
                ++i;
            }
            X509Certificate2 certificate1 = new X509Certificate2("client.p12", "12345");
            //Create a collection and add two of the certificates.
            X509Certificate2Collection collection = new X509Certificate2Collection();
            collection.Add(certificate1);
            //Add certificates to the store.
            **personalStore.Add(certificate1); 
            personalStore.AddRange(collection);**
            X509Certificate2Collection collection2 = new X509Certificate2Collection();
            collection2.Import("client.p12", "12345", X509KeyStorageFlags.PersistKeySet);
            foreach (X509Certificate2 cert in collection2)
            {
                personalStore.Add(cert);
            }

By adding the following couple of lines it started working on

        personalStore.Add(certificate1); 
        personalStore.AddRange(collection);

@helder-goncalves-cko
Copy link

helder-goncalves-cko commented Feb 25, 2019

Having the same issue running on docker with microsoft/dotnet:2.2-runtime-alpine (also tried 2.1)

MyHttpClientHandler :

public class MyHttpClientHandler : HttpClientHandler
{
     public MyHttpClientHandler(List<X509Certificate2> certificates)
     {
         ClientCertificateOptions = ClientCertificateOption.Manual;
         SslProtocols = SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12;
         ServerCertificateCustomValidationCallback = delegate { return true; };

         foreach (var certificate in certificates)
         {
             ClientCertificates.Add(certificate);
         }
     }
}

Program:

class Program
{
     static async Task Main(string[] args)
     {
         try
         {
             var path = Path.Combine(Directory.GetCurrentDirectory(), @"certs/mycert.pfx");

              var certificates = new List<X509Certificate2>()
              {
                  new X509Certificate2(path, "password")
              };

             var httpClient = new HttpClient(new MyHttpClientHandler(certificates));

             var payload = /*my payload*/;

             var httpContent = new StringContent(payload, Encoding.UTF8, "application/json");

             var response = await httpClient.PostAsync("https://mysecreturl.com", httpContent);

             Console.WriteLine(await response.Content.ReadAsStringAsync());
         }
         catch (System.Exception ex)
         {
             Console.WriteLine($"Failed - {ex.Message}");

             var innerException = ex.InnerException;

             while(innerException != null)
             {
                 Console.WriteLine($"Inner - {innerException.Message}");
                 innerException = innerException.InnerException;
             }

             return;
         }

         Console.WriteLine("Works!!!!!");
    }
}

Output:

load_certificate    | Failed - The SSL connection could not be established, see inner exception.
load_certificate    | Inner - Authentication failed, see inner exception.
load_certificate    | Inner - SSL Handshake failed with OpenSSL error - SSL_ERROR_SSL.
load_certificate    | Inner - error:14094410:SSL routines:ssl3_read_bytes:sslv3 alert handshake failure

Same code runs fine on Windows 10.

PS: getting a similar response when using OpenSSL 1.0.2l 25 May 2017 directly:

image

@karelz
Copy link
Member

karelz commented Sep 5, 2019

@helder-goncalves-cko @ramsubbaraoc can you please try it out on 3.0 if it is still a problem? Thank you!

@wfurt
Copy link
Member

wfurt commented Oct 9, 2019

Is there any update @helder-goncalves-cko @ramsubbaraoc ? It seems like this did not update for quite a while. Note that if you use self-signed certificate on server, OpenSSL is more strict about EKU and it will fail to connect unless expected flags are set.

@davidsh
Copy link
Contributor

davidsh commented Oct 10, 2019

Note that if you use self-signed certificate on server, OpenSSL is more strict about EKU and it will fail to connect unless expected flags are set.

To clarify, it is not just about EKU field. It is about KU field (Key Usage).

See this ASP.NET issue for a full analysis of best-practices for using self-signed certificates on Linux.
dotnet/aspnetcore#7246

@wfurt wfurt self-assigned this Oct 10, 2019
@wfurt
Copy link
Member

wfurt commented Jan 27, 2020

Closing, since there is no response for a long time. On Linux, proper certificate extensions must be used (see linked issue). This is a platform limitation we will not be able to address.
Reopen with more details if there is new evidence.

@wfurt wfurt closed this as completed Jan 27, 2020
@networkfusion
Copy link

networkfusion commented Jan 27, 2020

I would not define it as adding a proper certificate extension, but define it by adding the proper certificate to the store... I think it is a documentation issue (and possibly an ifdef between systems windows and Linux) where a note needs to be made to do this... and how to do it properly in a dokerfile (that is generated in docker via VS context menu)...

@wfurt wfurt removed their assignment Jan 27, 2020
@wfurt
Copy link
Member

wfurt commented Jan 27, 2020

https://github.com/dotnet/docs would be the right repo to track that unless @bartonjs or @davidsh have other suggestions.

@msftgits msftgits transferred this issue from dotnet/corefx Feb 1, 2020
@msftgits msftgits added this to the 5.0 milestone Feb 1, 2020
@ghost ghost locked as resolved and limited conversation to collaborators Dec 14, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-System.Net.Security os-linux Linux OS (any supported distro) question Answer questions and provide assistance, not an issue with source code or documentation.
Projects
None yet
Development

No branches or pull requests

8 participants