PKI、TLS、证书概念整理

1. PKI

Public Key Infrastructure - 公钥基础设施,这个名字,直译出来总觉得少点味,尤其是对于非安全领域,在接触到这个概念时,第一感觉它只是个“设施”,主要是用来管理“公钥”的,让人非常的疑惑。这类专有名词为什么不能稍微意译一下呢?

PKI是一个体系,一个架构,一系列东西的集合,这个集合中规定了各种元素,元素的作用,元素和元素之间的通讯协议等等。在这个集合所构成的体系之下,能够保证集合中的两个节点的通讯是安全的。而我们广袤的互联网所使用的PKI,就是一种基于可信第三方(CA,Certificate Authority)的PKI。下文所说的PKI如无特殊说明,就是指基于可信第三方的PKI。

2. HTTP over TLS

https_handshake

HTTPS的交互过程网络上资料很多,不再做赘述。比较令我好奇的是,当进行双向校验时,客户端如何选择证书?

在一个TLS建链过程中,有两个角色,一个客户端(client)主动发起,一个服务端(server)。

服务端必须有秘钥对(证书+私钥)。用于认证以及用于对称秘钥加密。如果服务端不校验客户端,同时客户端也不校验服务端证书,那客户端可以不配置任何证书相关的东西。如果服务端需要校验客户端,则需要有CA,用来验证客户端证书是否为其签发。当客户端配置的方式为keystore时,其中可能存在许多对秘钥对,客户端如何选择用哪个密钥对来通信呢?从协议交互图中看出来,有一个5过程,该过程为服务端要求客户端提供证书。

该博客中记录了TLS中,Certificate Request的内容 :https://blog.csdn.net/mrpre/article/details/77868263

3. 证书(X509)、秘钥对

  • X.509,证书标准,定义证书格式,遵循ASN.1规范。X.509定义的证书结构:

    • Version Number,版本

    • Serial Number,序列号

    • Signature Algorithm ID,签名算法ID

    • Issuer Name,颁发者

    • Validity period,有效期

      • Not Before
      • Not After
    • Subject name,使用者

    • Subject Public Key Info,公钥信息

      • Public Key Algorithm
      • Subject Public Key
    • Issuer Unique Identifier (optional),颁发者唯一ID

    • Subject Unique Identifier (optional),使用者唯一ID

    • Extensions (optional),扩展字段

    • Certificate Signature Algorithm,证书签名算法

    • Certificate Signature,证书签名

    #使用openssl查看一张证书,此证书选自jdk中默认证书中的一张
    openssl x509 -text -in actalisauthenticationrootca.cer -noout
    
    Certificate:
        Data:
            Version: 3 (0x2)
            Serial Number: 6271844772424770508 (0x570a119742c4e3cc)
        Signature Algorithm: sha256WithRSAEncryption
            Issuer: C=IT, L=Milan, O=Actalis S.p.A./03358520967, CN=Actalis Authentication Root CA
            Validity
                Not Before: Sep 22 11:22:02 2011 GMT
                Not After : Sep 22 11:22:02 2030 GMT
            Subject: C=IT, L=Milan, O=Actalis S.p.A./03358520967, CN=Actalis Authentication Root CA
            Subject Public Key Info:
                Public Key Algorithm: rsaEncryption
                    Public-Key: (4096 bit)
                    Modulus:
                        00:a7:c6:c4:a5:29:a4:2c:ef:e5:18:c5:b0:50:a3:
                      ...省略
                    Exponent: 65537 (0x10001)
            X509v3 extensions:
                X509v3 Subject Key Identifier:
                    52:D8:88:3A:C8:9F:78:66:ED:89:F3:7B:38:70:94:C9:02:02:36:D0
                X509v3 Basic Constraints: critical
                    CA:TRUE
                X509v3 Authority Key Identifier:
                    keyid:52:D8:88:3A:C8:9F:78:66:ED:89:F3:7B:38:70:94:C9:02:02:36:D0
      
                X509v3 Key Usage: critical
                    Certificate Sign, CRL Sign
        Signature Algorithm: sha256WithRSAEncryption
             0b:7b:72:87:c0:60:a6:49:4c:88:58:e6:1d:88:f7:14:64:48:
             ...省略
    
  • 证书类型:

    • DV,domain validated,域名验证,网站一般都使用DV
    • OV,organization validated,组织验证
    • EV,extended validated,扩展验证
  • 秘钥对,证书+私钥

4. Practice

JDK/JRE默认证书路径,这就是个jks文件:

$JAVA_HOME/lib/security/cacerts

确认某个站点发送了证书:

openssl s_client -showcerts -connect shareif.cn:443
~/Projects ᐅ openssl s_client -showcerts -connect shareif.cn:443
CONNECTED(00000005)
depth=2 C = US, O = DigiCert Inc, OU = www.digicert.com, CN = DigiCert High Assurance EV Root CA
verify return:1
depth=1 C = US, O = DigiCert Inc, OU = www.digicert.com, CN = DigiCert SHA2 High Assurance Server CA
verify return:1
depth=0 C = US, ST = California, L = San Francisco, O = "GitHub, Inc.", CN = www.github.com
verify return:1
---
Certificate chain
 0 s:/C=US/ST=California/L=San Francisco/O=GitHub, Inc./CN=www.github.com
   i:/C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert SHA2 High Assurance Server CA
-----BEGIN CERTIFICATE-----
...省略
-----END CERTIFICATE-----
 1 s:/C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert SHA2 High Assurance Server CA
   i:/C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert High Assurance EV Root CA
-----BEGIN CERTIFICATE-----
...省略
-----END CERTIFICATE-----
---
Server certificate
subject=/C=US/ST=California/L=San Francisco/O=GitHub, Inc./CN=www.github.com
issuer=/C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert SHA2 High Assurance Server CA
---
No client certificate CA names sent
Server Temp Key: ECDH, X25519, 253 bits
---
SSL handshake has read 3674 bytes and written 289 bytes
---
New, TLSv1/SSLv3, Cipher is ECDHE-RSA-AES128-GCM-SHA256
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-AES128-GCM-SHA256
    Session-ID: D11A4DD2C801FADA75D685893D661809EBCD8D1D071203A0681DC57959B69670
    Session-ID-ctx:
    Master-Key: 9CFDC956C3EB2BCCD5693041A34A92F43755D88172A5B1E72AFED2A77273F4593A3B0D1F52BA2A8F29A0B5AECF112F09
    TLS session ticket lifetime hint: 7200 (seconds)
    TLS session ticket:
    0000 - de 13 86 32 27 39 ff 04-80 a1 38 9b 76 32 8e d6   ...2'9....8.v2..
    0010 - 5f 7b 98 f4 1d 26 1e bf-03 ae 69 5d 3c fc 71 9c   _{...&....i]<.q.
    0020 - 09 77 f5 10 e7 c0 d2 b8-1c 6b f1 51 5d 26 25 3d   .w.......k.Q]&%=
    0030 - f9 c6 be 79 53 b0 37 0c-74 8a e8 72 67 00 72 aa   ...yS.7.t..rg.r.
    0040 - 2a 05 d7 07 fa 26 ca e4-ab c1 92 45 2f 01 6b a0   *....&.....E/.k.
    0050 - d9 14 4f bc 6c 85 43 c1-74 1f dd d9 56 b4 bf 8d   ..O.l.C.t...V...
    0060 - 16 d1 fa f0 68 b4 fd 4b-bd bd 2f e1 7b bc 16 cc   ....h..K../.{...
    0070 - 92 26 8c 2f b2 55 25 b4-79 b2 ab 34 2a 1a 1f f6   .&./.U%.y..4*...
    0080 - 85 a8 8d 9b 63 3f cd f4-d2 60 5c 2c 10 ac 99 06   ....c?...`\,....
    0090 - 1d 02 bc 78 ca 37 d2 65-46 7f 16 56 12 b1 e2 5f   ...x.7.eF..V..._

    Start Time: 1586685050
    Timeout   : 7200 (sec)
    Verify return code: 0 (ok)
---

Java代码扫描KeyStore中的证书有效期

KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(new FileInputStream(new File(PATH)), PASSWORD.toCharArray());

Enumeration<String> aliases = keyStore.aliases();
while (aliases.hasMoreElements()) {
	String alias = aliases.nextElement();
	X509Certificate cert = (X509Certificate) keyStore.getCertificate(alias);
	try {
		cert.checkValidity(DateTime.now().toDate());
	} catch (CertificateExpiredException cee) {
        System.out.println("cert is expired.")
	} catch (CertificateNotYetValidException cnyve) {
		System.out.println("certi is not yet valid")
    }
}

5. 参考

  1. PKI from wikipedia
  2. X.509 from wikipedia
  3. 《HTTPS权威指南》
  4. Java Developer Guide to SSL VPN needed