簡體   English   中英

Windows/Linux dotnet 核心 SslStream 差異

[英]Windows/Linux dotnet core SslStream differences

我正在嘗試使用與 dotnet core 5 一起使用的本地(文件)證書獲取 SslStream。在 Linux(Alpine Linux 3.14.0)上,一切都按預期運行,服務器對遠程客戶端進行身份驗證。 在 Windows(Windows 10 企業版,版本 20H2)上,身份驗證過程似乎仍在嘗試使用 Windows 證書存儲進行驗證,即使證書驗證應由 SslStream 構造函數覆蓋。

這是 SslStream 的 Windows 實現中的錯誤,還是我缺少強制它僅使用加載的證書文件所需的配置?

測試程序如下。 該程序將為客戶端和服務器生成 CA 和證書。 然后它將創建 2 個線程來使用這些證書測試SslStream Linux 運行沒有任何問題,但 Windows 會拋出System.ComponentModel.Win32Exception (0x80090304): The Local Security Authority cannot be contacted運行時System.ComponentModel.Win32Exception (0x80090304): The Local Security Authority cannot be contacted

using System;

namespace sslstream
{
    class Program
    {
        static bool VerifyCertificate(object sender, System.Security.Cryptography.X509Certificates.X509Certificate certificate, System.Security.Cryptography.X509Certificates.X509Chain chain, System.Net.Security.SslPolicyErrors sslPolicyErrors)
        {
            return true; //TODO: verify certificate chain and hostnames
        }

        static void RunClient()
        {
            var clientCert = new System.Security.Cryptography.X509Certificates.X509Certificate2("Client.pfx");
            var collection = new System.Security.Cryptography.X509Certificates.X509CertificateCollection(new System.Security.Cryptography.X509Certificates.X509Certificate[] { clientCert });
            using var client = new System.Net.Sockets.TcpClient();
            client.Connect(System.Net.IPAddress.Loopback, 12345);
            var clientStream = client.GetStream();
            using var sStream = new System.Net.Security.SslStream(clientStream, false, new System.Net.Security.RemoteCertificateValidationCallback(VerifyCertificate), null, System.Net.Security.EncryptionPolicy.RequireEncryption);
            sStream.AuthenticateAsClient("127.0.0.1", collection, System.Security.Authentication.SslProtocols.Tls12, false);
            sStream.Write(new byte[1] { 55 });
        }
        static void RunServer()
        {
            var serverCert = new System.Security.Cryptography.X509Certificates.X509Certificate2("127.0.0.1.pfx");
            var listener = new System.Net.Sockets.TcpListener(new System.Net.IPEndPoint(System.Net.IPAddress.Loopback, 12345));
            listener.Start();
            using var client = listener.AcceptTcpClient();
            var clientStream = client.GetStream();
            using var sStream = new System.Net.Security.SslStream(clientStream, false, new System.Net.Security.RemoteCertificateValidationCallback(VerifyCertificate), null, System.Net.Security.EncryptionPolicy.RequireEncryption);
            sStream.AuthenticateAsServer(serverCert, true, System.Security.Authentication.SslProtocols.Tls12, false);
            var fiftyFive = sStream.ReadByte();
            if (fiftyFive != 55)
                throw new Exception($"Expected 55, got {fiftyFive}");
        }
        static void Main(string[] args)
        {
            if (!System.IO.File.Exists("CA.pfx"))
                MakeCertificates();
            CRNG.Dispose();
            var t1 = new System.Threading.Thread(RunServer);
            t1.Start();
            //TODO: wait for server to start before starting client
            System.Threading.Thread.Sleep(1000);
            var t2 = new System.Threading.Thread(RunClient);
            t2.Start();
            t1.Join();
            t2.Join();
        }
        static void MakeCertificates()
        {
            MakeCA();
            MakeCert("127.0.0.1");
            MakeCert("Client");
        }
        static void MakeCA()
        {
            var ecdsa = System.Security.Cryptography.ECDsa.Create(); // generate asymmetric key pair
            var req = new System.Security.Cryptography.X509Certificates.CertificateRequest($"cn=Certificate Authority", ecdsa, System.Security.Cryptography.HashAlgorithmName.SHA256);
            req.CertificateExtensions.Add(new System.Security.Cryptography.X509Certificates.X509BasicConstraintsExtension(true, false, 0, true));
            req.CertificateExtensions.Add(new System.Security.Cryptography.X509Certificates.X509SubjectKeyIdentifierExtension(req.PublicKey, false));
            var cert = req.CreateSelfSigned(System.DateTimeOffset.Now, System.DateTimeOffset.Now.AddYears(1000));
            System.IO.File.WriteAllBytes("CA.pfx", cert.Export(System.Security.Cryptography.X509Certificates.X509ContentType.Pfx));
            System.IO.File.WriteAllText("CA.crt",
                "-----BEGIN CERTIFICATE-----\r\n"
                + System.Convert.ToBase64String(cert.Export(System.Security.Cryptography.X509Certificates.X509ContentType.Cert), System.Base64FormattingOptions.InsertLineBreaks)
                + "\r\n-----END CERTIFICATE-----");
        }
        static System.Security.Cryptography.RandomNumberGenerator CRNG = System.Security.Cryptography.RandomNumberGenerator.Create();
        static void MakeCert(string cn)
        {
            var ecdsa = System.Security.Cryptography.ECDsa.Create(); // generate asymmetric key pair
            var ca = new System.Security.Cryptography.X509Certificates.X509Certificate2("CA.pfx");
            var req = new System.Security.Cryptography.X509Certificates.CertificateRequest($"cn={cn}", ecdsa, System.Security.Cryptography.HashAlgorithmName.SHA256);
            req.CertificateExtensions.Add(new System.Security.Cryptography.X509Certificates.X509BasicConstraintsExtension(false, false, 0, false));
            req.CertificateExtensions.Add(new System.Security.Cryptography.X509Certificates.X509KeyUsageExtension(System.Security.Cryptography.X509Certificates.X509KeyUsageFlags.DigitalSignature | System.Security.Cryptography.X509Certificates.X509KeyUsageFlags.NonRepudiation, false));
            req.CertificateExtensions.Add(new System.Security.Cryptography.X509Certificates.X509SubjectKeyIdentifierExtension(req.PublicKey, false));
            req.CertificateExtensions.Add(new System.Security.Cryptography.X509Certificates.X509EnhancedKeyUsageExtension(new System.Security.Cryptography.OidCollection { new System.Security.Cryptography.Oid("1.3.6.1.5.5.7.3.8") }, true));
            var serial = new byte[20];
            CRNG.GetBytes(serial);
            var cert = req.Create(ca, System.DateTime.Now, System.DateTime.Now.AddYears(500), serial);
            cert = System.Security.Cryptography.X509Certificates.ECDsaCertificateExtensions.CopyWithPrivateKey(cert, ecdsa);
            System.IO.File.WriteAllBytes($"{cn}.pfx", cert.Export(System.Security.Cryptography.X509Certificates.X509ContentType.Pfx));
            System.IO.File.WriteAllText($"{cn}.crt",
                "-----BEGIN CERTIFICATE-----\r\n"
                + System.Convert.ToBase64String(cert.Export(System.Security.Cryptography.X509Certificates.X509ContentType.Cert), System.Base64FormattingOptions.InsertLineBreaks)
                + "\r\n-----END CERTIFICATE-----");
        }
    }
}

我不確定這是否只是 Windows 上的錯誤,但我切換到 RSA 而不是 ECDSA,現在它可以在 Linux 和 Windows 上運行。

密鑰生成要慢得多(還不確定數據傳輸的處理開銷),所以如果有人有在 Windows 上使用 ECDSA 的解決方案,我更喜歡那個。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM