Kiruthiga Muthuswamy
Kiruthiga Muthuswamy

Reputation: 21

Client certificates with typed HttpClient not working in .net 5 Linux container

Adding client certificates to a typed HttpClient in .net 3.1 linux docker container works, but fails on upgrading to .net 5. I see that there is a breaking change in .net 5 to use TLS 1.3 and restricted Ciphersuites, how can I override that in .net 5 with a typed HttpClient ?
How can I use the SocketsHttpHandler.SslOptions with a typed HttpClient to specify a wider set of Ciphersuites. The site am try to send a payment request supports only tls 1.2 and its ssllabs report is this https://www.ssllabs.com/ssltest/analyze.html?d=mss.cpc.getswish.net

This is a sample of my code

 services.AddHttpClient<ISwishpayService, SwishpayService>()
 .ConfigurePrimaryHttpMessageHandler<SwishpayHandler>();
public class SwishpayHandler: HttpClientHandler
    {
        private readonly IConfiguration _config;
        private readonly ILogger<SwishpayHandler> _logger;
        public SwishpayHandler(IConfiguration config, ILogger<SwishpayHandler> logger)
        {
            _config = config;
            _logger = logger;
              SslProtocols = System.Security.Authentication.SslProtocols.Tls12 | System.Security.Authentication.SslProtocols.Tls13;
            ClientCertificateOptions = ClientCertificateOption.Manual;
        }
        protected override async Task<HttpResponseMessage> SendAsync(
            HttpRequestMessage request,
            CancellationToken cancellationToken)
        {            
            
            if (ClientCertificates == null || ClientCertificates.Count == 0)
            {
               _logger.LogInformation("Invoked SwishpayHandler");
                using (X509Store store = new X509Store(StoreName.CertificateAuthority, StoreLocation.CurrentUser, OpenFlags.ReadWrite))
                {                  
                    var certs = new X509Certificate2Collection();
                    certs.Import(Path.Combine("Certificates", _config.GetValue<string>("SwishApi:key:certificatefile")), GetCertificatePassword(), X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet);
                    
                    foreach (X509Certificate2 cert in certs)
                    {
                        if (cert.HasPrivateKey)
                        {
                            ClientCertificates.Add(cert);
                        }
                        else
                        {
                            store.Add(cert);
                        }
                    }
                    store.Close();
                }
            }

            return await base.SendAsync(request, cancellationToken).ConfigureAwait(false);
        }

        private string GetCertificatePassword()
        {          
            var cert_password = File.ReadAllText(_config.GetValue<string>("SWISHPAY_CERT_PWD").Trim()).Replace(Environment.NewLine, "");

            return cert_password;
        }
    }

UPDATE

Exception in .net 5

System.Net.Http.HttpRequestException: The SSL connection could not be established, see inner exception.
 ---> 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

Upvotes: 2

Views: 1467

Answers (2)

AMIT KAMAT
AMIT KAMAT

Reputation: 11

Try the following,

 using (X509Store store = new X509Store(StoreName.CertificateAuthority, StoreLocation.CurrentUser, OpenFlags.ReadWrite))
        {
            var certs = new X509Certificate2Collection();
            certs.Import(settings.Value.ClientCertPath, settings.Value.ClientCertSecret, X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet);

            foreach (X509Certificate2 cert in certs)
            {
                if (cert.HasPrivateKey)
                {
                    ClientCertificates.Add(cert);
                    logger.LogInformation("CertTest: " + cert.Thumbprint);
                }
                else
                {
                    store.Add(cert);
                    logger.LogInformation("CertTest store: " + cert.Thumbprint);
                }
            }
            store.Close();
        }

Upvotes: 1

Crypt32
Crypt32

Reputation: 13974

There are several issues with your code which isn't related to .NET 5.

Issue #1:

X509Store store = new X509Store(StoreName.CertificateAuthority, StoreLocation.CurrentUser, OpenFlags.ReadWrite)

why you search for client certificates in StoreName.CertificateAuthority? It is incorrect, store name MUST be StoreName.My.

Issue #2:

certs.Import(Path.Combine("Certificates", _config.GetValue<string>("SwishApi:key:certificatefile")), GetCertificatePassword(), X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet);

Sotre is opened in CurrentUser context, but you specify X509KeyStorageFlags.MachineKeySet for some unknown reason. Why? It MUST be X509KeyStorageFlags.UserKeySet.

Upvotes: 1

Related Questions