使用临时密钥证书做服务器认证时出现Win32Exception问题
解决自签名证书SSL流HTTPS连接的SSPI异常问题
问题描述
尝试使用最新版Google Chrome通过SSL流与Web服务器建立HTTPS连接,通过CreateSelfSignedCertificate(string commonName)生成自签名证书,但访问https://localhost/时始终抛出以下异常:
System.Security.Authentication.AuthenticationException : A call to SSPI failed, see inner exception -> Win32Exception: An unknown error occurred while processing the certificate
使用Ephemeral Key,且不希望存储该证书。另外需要注意:Google Chrome强制要求证书包含SAN(Subject Alternative Name)扩展,不再支持CN回退。
原代码如下:
... ServerCertificate = CreateSelfSignedCertificate("localhost"); ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; SslStream s = new SslStream(_stream, false, ValidateServerCertificate); s.AuthenticateAsServer(ServerCertificate, false, SslProtocols.Tls12, false); _stream = s; ... ... public bool ValidateServerCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { return true; } public static X509Certificate2 CreateSelfSignedCertificate(string commonName) { X500DistinguishedName subjectName = new X500DistinguishedName($"CN={commonName}"); using (RSA rsa = RSA.Create(2048)) { CertificateRequest certificateRequest = new CertificateRequest(subjectName, rsa, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1); certificateRequest.CertificateExtensions.Add(new X509KeyUsageExtension(X509KeyUsageFlags.DataEncipherment | X509KeyUsageFlags.KeyEncipherment | X509KeyUsageFlags.DigitalSignature, false)); X509Certificate2 certificate = certificateRequest.CreateSelfSigned(DateTimeOffset.UtcNow, DateTimeOffset.UtcNow.AddYears(1)); byte[] pfxData = certificate.Export(X509ContentType.Pkcs12); return new X509Certificate2(pfxData, "", X509KeyStorageFlags.Exportable | X509KeyStorageFlags.EphemeralKeySet); } }
解决方案
核心问题是原证书未添加SAN扩展,导致Chrome拒绝验证证书。修改CreateSelfSignedCertificate方法,添加包含localhost的SAN扩展即可解决。
修改后的完整代码:
... ServerCertificate = CreateSelfSignedCertificate("localhost"); ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; SslStream s = new SslStream(_stream, false, ValidateServerCertificate); s.AuthenticateAsServer(ServerCertificate, false, SslProtocols.Tls12, false); _stream = s; ... ... public bool ValidateServerCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { return true; } public static X509Certificate2 CreateSelfSignedCertificate(string commonName) { X500DistinguishedName subjectName = new X500DistinguishedName($"CN={commonName}"); using (RSA rsa = RSA.Create(2048)) { CertificateRequest certificateRequest = new CertificateRequest(subjectName, rsa, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1); // 添加SAN扩展,包含localhost var sanBuilder = new SubjectAlternativeNameBuilder(); sanBuilder.AddDnsName(commonName); certificateRequest.CertificateExtensions.Add(sanBuilder.Build()); certificateRequest.CertificateExtensions.Add(new X509KeyUsageExtension(X509KeyUsageFlags.DataEncipherment | X509KeyUsageFlags.KeyEncipherment | X509KeyUsageFlags.DigitalSignature, false)); // 添加增强密钥用法,确保证书适用于服务器身份验证 certificateRequest.CertificateExtensions.Add( new X509EnhancedKeyUsageExtension( new OidCollection { new Oid("1.3.6.1.5.5.7.3.1") }, // 服务器身份验证OID false)); X509Certificate2 certificate = certificateRequest.CreateSelfSigned(DateTimeOffset.UtcNow, DateTimeOffset.UtcNow.AddYears(1)); byte[] pfxData = certificate.Export(X509ContentType.Pkcs12); return new X509Certificate2(pfxData, "", X509KeyStorageFlags.Exportable | X509KeyStorageFlags.EphemeralKeySet); } }
关键修改说明
- 添加SAN扩展:通过
SubjectAlternativeNameBuilder添加DNS名称localhost,满足Chrome对SAN的强制要求,避免CN回退失效导致的证书验证失败。 - 增强密钥用法:添加服务器身份验证的OID(
1.3.6.1.5.5.7.3.1),明确证书用途,进一步确保SSL握手过程的兼容性。 - 保持EphemeralKeySet:保留
X509KeyStorageFlags.EphemeralKeySet,确保证书不会持久存储到系统证书库中。
内容的提问来源于stack exchange,提问作者Hugo_vdms
相关产品推荐
相关产品推荐

