【发布时间】:2021-08-16 15:37:04
【问题描述】:
我们有一个较旧的 .net 核心项目,它使用 HttpListener 和 Fleck,没有 ssl。我们现在需要 ssl,所以我开始更新所有内容。一切都适用于网络服务器,但是当我尝试将 websocket 与 ssl 一起使用时,出现以下异常:
无法验证 System.AggregateException:发生一个或多个错误。 (身份验证失败,请参阅内部异常。) ---> System.Security.Authentication.AuthenticationException:身份验证失败,请参阅内部异常。 ---> System.ComponentModel.Win32Exception (0x80090327):处理证书时发生未知错误。 --- 内部异常堆栈跟踪结束 --- 在 System.Net.Security.SslStream.ForceAuthenticationAsync[TIOAdapter](TIOAdapter 适配器,布尔接收第一,字节 [] reAuthenticationData,布尔 isApm) 在 System.Threading.Tasks.TaskToApm.End(IAsyncResult asyncResult) 在 System.Net.Security.SslStream.EndAuthenticateAsServer(IAsyncResult asyncResult) 在 System.Threading.Tasks.TaskFactory
1.FromAsyncCoreLogic(IAsyncResult iar, Func2 endFunction, Action1 endAction, Task1 promise, Boolean requiresSynchronization) --- 内部异常堆栈跟踪结束 ---
我使用 Portable.BouncyCastle 1.8.10 生成这样的证书(这是我尝试生成证书的第三个代码):
using System;
using System.IO;
using System.Security.Cryptography.X509Certificates;
using Org.BouncyCastle.Asn1.X509;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Generators;
using Org.BouncyCastle.Crypto.Operators;
using Org.BouncyCastle.Crypto.Prng;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Pkcs;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Utilities;
using Org.BouncyCastle.X509;
namespace WebServer
{
public static class CertificateHelper
{
private const string DefaultName = "X509Cert2.PFX";
// Source: Přemysl Šťastný https://stackoverflow.com/questions/51684883/generate-self-signed-x509certificate2-using-net-standard-2-0
public static X509Certificate2 GenerateCertificate(string subjectName = "CN=root ca", int keyStrength = 4096)
{
// Generating Random Numbers
var randomGenerator = new CryptoApiRandomGenerator();
var random = new SecureRandom(randomGenerator);
// The Certificate Generator
var certificateGenerator = new X509V3CertificateGenerator();
// Serial Number
var serialNumber = BigIntegers.CreateRandomInRange(BigInteger.One, BigInteger.ValueOf(Int64.MaxValue), random);
certificateGenerator.SetSerialNumber(serialNumber);
// Signature Algorithm
const string signatureAlgorithm = "SHA256WithRSA";
// Issuer and Subject Name
var subjectDN = new X509Name(subjectName);
var issuerDN = subjectDN;
certificateGenerator.SetIssuerDN(issuerDN);
certificateGenerator.SetSubjectDN(subjectDN);
// Valid For
var notBefore = DateTime.UtcNow.Date;
var notAfter = notBefore.AddYears(20);
certificateGenerator.SetNotBefore(notBefore);
certificateGenerator.SetNotAfter(notAfter);
// Subject Public Key
AsymmetricCipherKeyPair subjectKeyPair;
var keyGenerationParameters = new KeyGenerationParameters(random, keyStrength);
var keyPairGenerator = new RsaKeyPairGenerator();
keyPairGenerator.Init(keyGenerationParameters);
subjectKeyPair = keyPairGenerator.GenerateKeyPair();
certificateGenerator.SetPublicKey(subjectKeyPair.Public);
// Generating the Certificate
var issuerKeyPair = subjectKeyPair;
ISignatureFactory signatureFactory = new Asn1SignatureFactory(signatureAlgorithm, issuerKeyPair.Private, random);
// selfsign certificate
var certificate = certificateGenerator.Generate(signatureFactory);
// in-memory PFX stream
var pkcs12Store = new Pkcs12Store();
var certEntry = new X509CertificateEntry(certificate);
pkcs12Store.SetCertificateEntry(subjectName, certEntry);
pkcs12Store.SetKeyEntry(subjectName, new AsymmetricKeyEntry(subjectKeyPair.Private), new[] {certEntry});
X509Certificate2 keyedCert;
using (MemoryStream pfxStream = new MemoryStream())
{
pkcs12Store.Save(pfxStream, new char[0], new SecureRandom());
pfxStream.Seek(0, SeekOrigin.Begin);
keyedCert = new X509Certificate2(pfxStream.ToArray(), string.Empty, X509KeyStorageFlags.Exportable);
}
return keyedCert;
}
public static void Save(this X509Certificate2 cert, string outputFileName)
{
var bytes = cert.Export(System.Security.Cryptography.X509Certificates.X509ContentType.Pkcs12);
File.WriteAllBytes(outputFileName, bytes);
}
public static X509Certificate2 SaveNewX509Certificate2(string fileName = DefaultName)
{
var cert = GenerateCertificate();
cert.Save(DefaultName);
return cert;
}
public static string GetInstallX509Certificate2(string fileName = DefaultName)
{
if (!File.Exists(fileName))
{
var cert = SaveNewX509Certificate2(fileName);
X509Store store = new X509Store(StoreName.Root, StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadWrite);
if (!store.Certificates.Contains(cert))
{
store.Add(cert);
}
store.Close();
return fileName;
}
else
{
return fileName;
}
}
}
}
我最后运行的是 CertificateHelper.GetInstallX509Certificate2() 方法。
然后我像这样启动 Fleck 1.2.0 websocket(SSLCertificatePath 是一个保存文件路径的字符串):
var server = new WebSocketServer(wsLocation)
{
SupportedSubProtocols = webSocketHandlers.Keys
};
if (SSLCertificatePath != null)
{
server.EnabledSslProtocols = System.Security.Authentication.SslProtocols.Tls12;
server.Certificate = new X509Certificate2(SSLCertificatePath);
}
server.Start(...);
服务器启动正常,但一旦我尝试连接到 websocket,就会抛出上述异常。 老实说,我不知道自己在做什么,以前从未使用过证书。
【问题讨论】:
标签: ssl .net-core websocket certificate bouncycastle