SslStream.AuthenticateAsServer证书在从SQL加载时失败,但在从嵌入文件加载时有效



我有一个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证书业务看起来过于复杂?

最新更新