Обязательно ли устанавливать сертификат PKCS12 / PFX в хранилище ключей перед его использованием? - PullRequest
0 голосов
/ 16 сентября 2018

Возникла проблема при использовании сертификата клиента в клиентском приложении http на C #. Сертификат клиента доставляется сервером во время выполнения как X509Certificate. У меня также есть закрытый ключ. Поэтому я генерирую объект PKCS12 / PFX (X509Certificate2). Теперь, когда я запускаю это приложение в многопоточной среде, где в каждом потоке создается новое SSL-соединение с использованием различных клиентских сертификатов, полученных от сервера, случайным образом происходит сбой рукопожатия SSL, а некоторые проходит. Трассировка сети показывает, что рукопожатие SSL завершается неудачно сразу после отправки клиентом сертификата.

Обратите внимание, что я не хранил X509Certificate2 в магазине. Если я не использую сертификат клиента, все работает нормально (сервер отправляет 401, так как ему требуется сертификат клиента, но рукопожатие SSL никогда не дает сбой).

Это потому, что я не устанавливаю объект сертификата клиента X509Certificate2 в хранилище? Обязательно ли устанавливать сертификаты PKCS12 в магазине?

Вот метод для рукопожатия SSL:

        public void SslHandshake(ConnectionParams connectionParams)
        {
            TcpClient mClient = new TcpClient(connectionParams.HostFqdn, connectionParams.Port);
            SslStream mSslStream = new SslStream(mClient.GetStream(), false, new RemoteCertificateValidationCallback(ValidateServerCertificate), null);
            try
            {
                if (connectionParams.ClientCertificate != null)
                {
                    mSslStream.AuthenticateAsClient(connectionParams.HostFqdn, new X509Certificate2Collection(connectionParams.ClientCertificate), SslProtocols.Tls12, false);
                }
                else
                {
                    mSslStream.AuthenticateAsClient(connectionParams.HostFqdn);
                }
            }
            catch (AuthenticationException e)
            {
                sLog.Error("Exception establishing SSL connection: " + e.Message);
                if (e.InnerException != null)
                {
                    sLog.Error("Inner exception establishing SSL connection: " + e.InnerException.Message);
                }
                mSslStream.Close();
                mClient.Close();
                throw new ApiException("SSL handshake failed - closing the connection.");
            }
        }

======= ======= EDIT

Это метод генерации объекта DotNet X509Certificate2 с использованием bouncycastle X509Certficate и закрытого ключа.

public System.Security.Cryptography.X509Certificates.X509Certificate2 CreatePkcs12(X509Certificate bcCert, AsymmetricKeyParameter privateKey)
        {
            var x509Certificate = DotNetUtilities.ToX509Certificate(bcCert);
            var certBytes = x509Certificate.Export(System.Security.Cryptography.X509Certificates.X509ContentType.Pkcs12, IosHelper.DEVICE_CERT_PFX_PASSWORD);
            var certificate = new System.Security.Cryptography.X509Certificates.X509Certificate2(certBytes, IosHelper.DEVICE_CERT_PFX_PASSWORD, System.Security.Cryptography.X509Certificates.X509KeyStorageFlags.PersistKeySet | System.Security.Cryptography.X509Certificates.X509KeyStorageFlags.MachineKeySet);
            if(privateKey != null)
            {
                var rsaParams = DotNetUtilities.ToRSAParameters(privateKey as RsaPrivateCrtKeyParameters);
                var cspParams = new CspParameters();
                cspParams.KeyContainerName = "KeyContainer";
                var rsaPrivate = new RSACryptoServiceProvider(cspParams);
                rsaPrivate.ImportParameters(rsaParams);
                certificate.PrivateKey = rsaPrivate;
            }
            return certificate;
        }
...