SslStream.AuthenticateAsServer证书在从SQL加载时失败,但在从嵌入文件加载时有效
本文关键字:加载 文件 有效 SQL AuthenticateAsServer SslStream 失败 证书 | 更新日期: 2023-09-27 18:07:56
我有一个Azure云服务,它使用自签名证书来保护我在本地运行的应用程序的SslStream。由于这两个应用程序都不应该暴露给外部世界以及其他原因,我对从机器存储"正确"加载证书不感兴趣;我只是想要一个加密的流和一个简单的认证方法。
当从嵌入式项目资源加载证书时,以下代码按预期工作(SslStream进行身份验证和加密),但当从数据库中的字节加载证书时,调用AuthenticateAsServer()时失败。我已经验证了证书是相同的(字节逐字节),无论它们是从嵌入式文件还是从SQL加载的,所以我不明白为什么当我使用SQL时,我会得到一个异常("服务器模式ssl必须使用带有关联私钥的证书"):
NetStream = new SslStream(Client.GetStream(), false, new RemoteCertificateValidationCallback(ValidateClientCertificate));
NetStream.AuthenticateAsServer(cert, true, System.Security.Authentication.SslProtocols.Default, false);
bool ValidateClientCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
{
try
{
byte[] clientCertBytes = certificate.GetRawCertData();
byte[] serverCertBytes = _serverCert.GetRawCertData();
if(clientCertBytes.Length != serverCertBytes.Length)
{
throw new Exception("Client/server certificates do not match");
}
for(int i = 0; i < clientCertBytes.Length; i++)
{
if(clientCertBytes[i] != serverCertBytes[i])
{
throw new Exception("Client/server certificates do not match");
}
}
}
catch(Exception ex)
{
SystemLogger.LogException(ex, "SslServerClient");
return false;
}
return true;
}
这是从嵌入式资源加载证书的代码:
Assembly assembly = Assembly.GetExecutingAssembly();
using(Stream stream = assembly.GetManifestResourceStream("Resources.localhost.pfx"))
{
using(MemoryStream memoryStream = new MemoryStream())
{
stream.CopyTo(memoryStream);
_serverCert = new X509Certificate2(memoryStream.ToArray(), "password");
}
}
这是从SQL加载证书的代码:
private static X509Certificate2 readCertificateFromSql(SqlParameterHelper sph)
{
X509Certificate2 result = null;
byte[] certBytes;
string certPassword;
using(IDataReader reader = sph.ExecuteReader())
{
if(reader.Read())
{
try
{
certBytes = (byte[])reader["Data"];
certPassword = (string)reader["Password"];
result = new X509Certificate2(certBytes, certPassword);
}
catch(Exception ex)
{
throw ex;
}
}
}
return result;
}
EDIT:我发现两个X509Certificate2对象之间的区别似乎是从SQL加载的对象具有NULL的PrivateKey属性。我不明白为什么,因为从每个证书调用GetRawCertData()返回完全相同的字节数组。
我把问题解决了。
我存储在SQL中的证书数据是通过在X509Certificate2对象上调用GetRawCertData()生成的。我需要做的是通过调用Export(X509ContentType)来获取数据。Pfx,"password"),它要求通过包含X509KeyStorageFlags来实例化X509Certificate2。构造函数中的可导出参数。
是只有我一个人,还是这个SSL证书业务看起来过于复杂?