Возникла проблема при использовании сертификата клиента в клиентском приложении 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;
}