从SQL加载时,SslStream.AuthenticateAsServer证书失败,但从嵌入文件加载时可以正常工作

时间:2014-06-10 20:44:15

标签: c# sql-server azure ssl

我有一个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;
    }

编辑:我发现两个X509Certificate2对象之间的区别似乎是从SQL加载的对象具有NULL的PrivateKey属性。我不明白为什么,因为从每个证书调用GetRawCertData()会返回完全相同的字节数组。

1 个答案:

答案 0 :(得分:1)

我发现了问题。

我在SQL中存储的证书数据是通过在X509Certificate2对象上调用GetRawCertData()生成的。我需要做的是通过调用Export(X509ContentType.Pfx,&#34; password&#34;)来获取数据,这需要通过在构造函数中包含X509KeyStorageFlags.Exportable参数来实例化X509Certificate2。

这只是我,还是这个SSL证书业务看起来过于复杂?