简体   繁体   English

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

[英]Verifying the chain of a self-signed certificate when using SslStream

I have a chain.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-----

as well as a server.key.pem 以及server.key.pem

-----BEGIN RSA PRIVATE KEY-----
// Private key for server cert
-----END RSA PRIVATE KEY-----

From there, I generate a pfx file - which has the server cert with its private key along with the rest of the chain. 从那里,我生成一个pfx文件-该文件包含带有私有密钥的服务器证书以及该链的其余部分。

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

I leave the export password blank 我将导出密码留空

Next I host an TcpListener with an SslStream 接下来,我用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
                }
            }
        }
    }
}

But when I try to check the chain from openssl, it fails 但是当我尝试从openssl检查链时,它失败了

openssl s_client -connect 127.0.0.1:1443 -CAfile ca.cert.pem 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

issuer=CN = Intermediate

---
No client certificate CA names sent
Client Certificate Types: RSA sign, DSA sign, ECDSA sign
Requested Signature Algorithms: RSA+SHA256:RSA+SHA384:RSA+SHA1:ECDSA+SHA256:ECDSA+SHA384:ECDSA+SHA1:DSA+SHA1:RSA+SHA512:ECDSA+SHA512
Shared Requested Signature Algorithms: RSA+SHA256:RSA+SHA384:RSA+SHA1:ECDSA+SHA256:ECDSA+SHA384:ECDSA+SHA1:DSA+SHA1:RSA+SHA512:ECDSA+SHA512
Peer signing digest: SHA256
Peer signature type: RSA
Server Temp Key: ECDH, P-384, 384 bits
---
SSL handshake has read 1439 bytes and written 481 bytes
Verification error: unable to verify the first certificate
---
New, TLSv1.2, Cipher is ECDHE-RSA-AES256-GCM-SHA384
Server public key is 2048 bit
Secure Renegotiation IS supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
SSL-Session:
    Protocol  : TLSv1.2
    Cipher    : ECDHE-RSA-AES256-GCM-SHA384
    Session-ID: E82C0000B86186D0051CFE6290C12F0D62C4D376B7E40437029B8B85687C4B18
    Session-ID-ctx:
    Master-Key: 13681EAE940F241726072A4586A96A9FEEEF29B8309B9122FA2F07AC7C9F949128CB66D0F9C430E1D2480E61E287C578
    PSK identity: None
    PSK identity hint: None
    SRP username: None
    Start Time: 1566533377
    Timeout   : 7200 (sec)
    Verify return code: 21 (unable to verify the first certificate)
    Extended master secret: yes
---
140266287337920:error:14094416:SSL routines:ssl3_read_bytes:sslv3 alert certificate unknown:../ssl/record/rec_layer_s3.c:1528:SSL alert number 46

I doesn't seem as though it is presenting the intermediate or the root certificate so that it can verify the chain. 我似乎并没有提出中间证书或根证书,以便它可以验证链。 What am I missing here? 我在这里想念什么?

In my scenario, the client would have the root certificate public key. 在我的情况下,客户端将具有根证书公用密钥。

  • Even if the PFX contained the entire chain, using the single-certificate constructor makes it only load the cert which had a private key, and the rest are discarded. 即使PFX包含整个链,使用单证书构造函数也使其仅加载具有私钥的证书,其余的将被丢弃。
  • Even if the load-the-PFX-as-a-collection method is used, SslStream only uses a collection to find an acceptable server certificate (has a private key and the proper EKU value), then ignores the rest. 即使使用了将PFX作为集合加载的方法,SslStream也仅使用集合来查找可接受的服务器证书(具有私钥和正确的EKU值),然后忽略其余的证书。

The intermediate certificate is only sent when it can be found, via system ambient context, by X509Chain. 仅当X509Chain通过系统环境上下文找到中间证书时,才发送中间证书。 If your certificate is not public-trust then the best answer for your scenario is to add the intermediate (and, optionally, the root) to the CurrentUser\\CA ( X509StoreName.CertificateAuthority ) certificate store. 如果您的证书不是公共信任的,则针对您的方案的最佳答案是将中间(以及根)(可选)添加到CurrentUser \\ CA( X509StoreName.CertificateAuthority )证书存储中。 The "CA" store doesn't provide trust, it's just a grab bag of all the intermediate issuer CAs the system has seen, and the system uses it as a cache when building new chains. “ CA”存储区不提供信任,它只是系统看到的所有中间发行人CA的抓包,系统在构建新链时将其用作缓存。

You can do this programmatically at startup by 您可以在启动时以编程方式执行以下操作:

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.

Other options: Feed the whole collection into X509Chain.ChainPolicy.ExtraStore, call X509Chain.Build on serverCert, only add the certs after the first one (and optionally not the last one)... just depends on how much extra stuff is expected to be in the PFX. 其他选项:将整个集合提供给X509Chain.ChainPolicy.ExtraStore,调用X509Chain.Build on serverCert,仅在第一个证书(可能不是最后一个证书)之后添加证书...仅取决于预期有多少额外的东西在PFX中。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM