.net core X509Certificates2 with Fleck WebSocket -> 身份验证失败 -> 处理证书时发生未知错误
.net core X509Certificates2 with Fleck WebSocket -> Authentication failed -> An unknown error occurred while processing the certificate
我们有一个较旧的 .net 核心项目,它使用 HttpListener 和 Fleck,但没有 ssl。我们现在需要 ssl,所以我开始更新所有内容。一切都适用于网络服务器,但是当我尝试将 websocket 与 ssl 一起使用时,出现以下异常:
Failed to Authenticate System.AggregateException: One or more errors occurred. (Authentication failed, see inner exception.)
---> System.Security.Authentication.AuthenticationException: Authentication failed, see inner exception.
---> System.ComponentModel.Win32Exception (0x80090327): An unknown error occurred while processing the certificate.
--- End of inner exception stack trace ---
at System.Net.Security.SslStream.ForceAuthenticationAsync[TIOAdapter](TIOAdapter adapter, Boolean receiveFirst, Byte[] reAuthenticationData, Boolean isApm)
at System.Threading.Tasks.TaskToApm.End(IAsyncResult asyncResult)
at System.Net.Security.SslStream.EndAuthenticateAsServer(IAsyncResult asyncResult)
at System.Threading.Tasks.TaskFactory1.FromAsyncCoreLogic(IAsyncResult iar, Func
2 endFunction, Action1 endAction, Task
1 promise, Boolean requiresSynchronization)
--- End of inner exception stack trace ---
我使用 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ý
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,就会抛出上述异常。
老实说,我不知道我在做什么,以前从未使用过证书。
没有真正找到问题的解决方案,但我通过将 websocket 支持集成到我们的 httplistener 而不是使用库来解决它。
http 侦听器已经在使用 ssl,因此 websockets 自动工作。
我们有一个较旧的 .net 核心项目,它使用 HttpListener 和 Fleck,但没有 ssl。我们现在需要 ssl,所以我开始更新所有内容。一切都适用于网络服务器,但是当我尝试将 websocket 与 ssl 一起使用时,出现以下异常:
Failed to Authenticate System.AggregateException: One or more errors occurred. (Authentication failed, see inner exception.) ---> System.Security.Authentication.AuthenticationException: Authentication failed, see inner exception. ---> System.ComponentModel.Win32Exception (0x80090327): An unknown error occurred while processing the certificate. --- End of inner exception stack trace --- at System.Net.Security.SslStream.ForceAuthenticationAsync[TIOAdapter](TIOAdapter adapter, Boolean receiveFirst, Byte[] reAuthenticationData, Boolean isApm) at System.Threading.Tasks.TaskToApm.End(IAsyncResult asyncResult) at System.Net.Security.SslStream.EndAuthenticateAsServer(IAsyncResult asyncResult) at System.Threading.Tasks.TaskFactory
1.FromAsyncCoreLogic(IAsyncResult iar, Func
2 endFunction, Action1 endAction, Task
1 promise, Boolean requiresSynchronization) --- End of inner exception stack trace ---
我使用 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ý
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,就会抛出上述异常。 老实说,我不知道我在做什么,以前从未使用过证书。
没有真正找到问题的解决方案,但我通过将 websocket 支持集成到我们的 httplistener 而不是使用库来解决它。 http 侦听器已经在使用 ssl,因此 websockets 自动工作。