在C#的http客户端应用程序中使用客户端证书时遇到问题。客户端证书在运行时由服务器作为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 ======
这是使用充气桥X509Certficate和私钥生成DotNet X509Certificate2对象的方法。
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;
}