使用 SslStream 时验证自签名证书链

我有一个链.pem


-----BEGIN CERTIFICATE-----

// My server cert signed by intemediate CA

-----END CERTIFICATE-----

-----BEGIN CERTIFICATE-----

// My intermediate cert signed by root CA

-----END CERTIFICATE-----

-----BEGIN CERTIFICATE-----

// My self signed root cert

-----END CERTIFICATE-----

以及server.key.pem


-----BEGIN RSA PRIVATE KEY-----

// Private key for server cert

-----END RSA PRIVATE KEY-----

从那里,我生成一个 pfx 文件 - 其中包含服务器证书及其私钥以及链的其余部分。


openssl pkcs12 -export -out certificate.pfx -inkey server.key.pem -in chain.pem

我将导出密码留空


接下来我用 SslStream 托管一个 TcpListener


namespace fun_with_ssl

{

    internal class Program

    {

        public static int Main(string[] args)

        {

            var serverCertificate = new X509Certificate2("certificate.pfx");

            var listener = new TcpListener(IPAddress.Any, 1443);

            listener.Start();


            while (true)

            {

                using (var client = listener.AcceptTcpClient())

                using (var sslStream = new SslStream(client.GetStream(), false))

                {

                    sslStream.AuthenticateAsServer(serverCertificate, false, SslProtocols.Tls12, false);

                    //send/receive from the sslStream

                }

            }

        }

    }

}

但是当我尝试从 openssl 检查链时,它失败了


openssl s_client -connect 127.0.0.1:1443 -CAfile ca.cert.pem


CONNECTED(00000005)

depth=0 CN = SERVER

verify error:num=20:unable to get local issuer certificate

verify return:1

depth=0 CN = SERVER

verify error:num=21:unable to verify the first certificate

verify return:1

---

Certificate chain

 0 s:CN = SERVER

   i:CN = Intermediate

---

Server certificate

-----BEGIN CERTIFICATE-----

// My Server certificate

-----END CERTIFICATE-----

subject=CN = SERVER


我似乎没有提供中间证书或根证书,以便它可以验证链。我在这里缺少什么?


在我的场景中,客户端将拥有根证书公钥。


慕尼黑8549860
浏览 51回答 1
1回答

吃鸡游戏

即使 PFX 包含整个链,使用单证书构造函数也会使其仅加载具有私钥的证书,其余的都会被丢弃。即使使用 load-the-PFX-as-a-collection 方法,SslStream 也仅使用集合来查找可接受的服务器证书(具有私钥和正确的 EKU 值),然后忽略其余部分。仅当 X509Chain 通过系统环境上下文找到中间证书时才会发送中间证书。如果您的证书不是公共信任的,那么您的方案的最佳答案是将中间证书(以及可选的根证书)添加到 CurrentUser\CA ( )X509StoreName.CertificateAuthority证书存储中。“CA”存储不提供信任,它只是系统见过的所有中间发行者 CA 的一个抓包,系统在构建新链时将其用作缓存。您可以在启动时以编程方式执行此操作X509Certificate2 serverCertificate = null;using (X509Store store = new X509Store(StoreName.CertificateAuthority, StoreLocation.CurrentUser)){    store.Open(OpenFlags.ReadWrite);    X509Certificate2Collection coll = new X509Certificate2Collection();    coll.Import("certificate.pfx");    foreach (X509Certificate2 cert in coll)    {        if (cert.HasPrivateKey)        {            // Maybe apply more complex logic if you really expect multiple private-key certs.            if (serverCertificate == null)            {                serverCertificate = cert;            }            else            {                cert.Dispose();            }        }        else        {            // This handles duplicates (as long as no custom properties have been applied using MMC)            store.Add(cert);            cert.Dispose();        }    }}// tcpListener, et al.其他选项:将整个集合输入 X509Chain.ChainPolicy.ExtraStore,在 serverCert 上调用 X509Chain.Build,仅在第一个证书之后添加证书(也可以不添加最后一个证书)...仅取决于预计需要多少额外内容位于 PFX 中。
打开App,查看更多内容
随时随地看视频慕课网APP