浅谈HTTPS证书文件格式
我们在使用HTTPS加密时,通常需要申请2个文件,一个是证书,一个是私钥,其中证书文件常见的后缀有pem,crt,cer等,那这些格式都有什么区别,里面的存储格式是怎样的?存储了什么内容?今天来研究一下。
证书类型
常用的证书类型有:X.509证书、PKCS#7证书、PKCS#12证书
从使用场景的角度来对比 X.509、PKCS#7 和 PKCS#12,可以简要总结如下:
-
X.509:
- 使用场景:X.509 数字证书主要用于建立和验证安全通信,例如在 SSL/TLS 加密通信中进行客户端和服务器的身份认证。
- 典型应用:SSL/TLS、VPN、S/MIME(安全的电子邮件)等。
-
PKCS#7:
- 使用场景:PKCS#7 主要用于封装和传输加密数据、数字签名和证书等信息,提供了一种通用的数据结构和容器格式。
- 典型应用:数字签名、加密数据传输、数字证书交换、证书吊销列表(CRL)等。
-
PKCS#12:
- 使用场景:PKCS#12 主要用于存储和传输个人身份证书、私钥和相关信息,方便在不同设备或应用程序之间共享和导入。
- 典型应用:个人身份证书的导出和导入、客户端证书存储、身份验证、加密私钥的保护等。
需要注意的是,这些使用场景并不是绝对的,有一些重叠和交叉的情况。例如,PKCS#12 文件可以包含 X.509 数字证书和相关的私钥,并且在一些情况下,PKCS#7 可能会用于封装和传输 X.509 数字证书和 CRL。
总结:X.509只包含公钥,没有私钥,可用于放在客户端使用,用于加密、验签,PKCS#12同时包含了公钥和私钥,一般放在服务端使用,用于解密、签名(记得做微信支付时,有些双向加密的场景就要使用到p12证书,因为要有私钥才可以双向加密)
文件存储格式
这里是常见证书文件后缀名的一些区别说明:
-
.pem:
- PEM(Privacy-Enhanced Mail)格式是一种基于ASCII编码的文件格式,通常用于存储X.509证书、私钥和其他相关数据。
- PEM格式的证书文件可以包含BEGIN和END标记,以及Base64编码的证书数据。
- .pem后缀通常用于表示包含单个PEM格式证书的文件。
-
.crt:
- .crt后缀通常用于表示X.509证书文件。
- .crt文件可以使用不同的编码格式,包括DER编码或PEM编码。具体取决于文件的内容。
-
.cer:
- .cer后缀也通常用于表示X.509证书文件。
- 与.crt文件类似,.cer文件可以使用不同的编码格式,包括DER编码或PEM编码。
-
.der:
- .der后缀表示DER(Distinguished Encoding Rules)编码的二进制格式证书文件。
- DER格式是一种二进制格式,不像PEM格式那样使用Base64编码的ASCII文本。
-
.pfx / .p12:
- .pfx或.p12后缀表示PKCS#12格式的证书文件。
- PKCS#12格式是一种二进制格式,可以包含证书、私钥和中间证书等。
- .pfx或.p12文件通常使用密码进行加密。
总结:der是证书原本的二进制格式,pem是der进行base64编码后的结果,crt和cer则只是另外一种文件后缀名,里面的内容可以是二进制也可以是base64格式。
明白了证书文件的格式,那证书里都存了些什么呢?由于证书格式最终都是二进制存储的,我们使用openssl来解析看看
[ych@centos internal.rxxy.icu]$ openssl x509 -in internal.rxxy.icu.crt -pubkey --text
-----BEGIN PUBLIC KEY-----
MIIBIjAN...
-----END PUBLIC KEY-----
Certificate:
Data:
Version: 3 (0x2)
Serial Number:
5e:9e:bf:e2:4e:c3:1d:e4:36:c0:01:c0:83:43:d4:86:4a:6b:02:9f
Signature Algorithm: sha256WithRSAEncryption
Issuer: C = CN, ST = Beijing, L = HaiDian, O = xxx, CN = xxx.cn
Validity
Not Before: May 31 09:13:28 2023 GMT
Not After : May 28 09:13:28 2033 GMT
Subject: C = CN, ST = BeiJing, L = HaiDian, O = xxx, CN = xxx
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public-Key: (2048 bit)
Modulus:
00:c2:6d:1e:97...
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Alternative Name:
DNS:*.internal.rxxy.icu
Signature Algorithm: sha256WithRSAEncryption
84:a1:c3:1f:63:42...
-----BEGIN CERTIFICATE-----
MIIEczCCAlugAwIBAgIUXp6/4k7DHeQ2...
-----END CERTIFICATE-----
这是我解析自签发的一张证书(省略部分私密信息用...代替),可以看到,里面存有公钥、X509协议的版本,序列号,约定的签名算法(RSA只是非对称加密的一种,还有ECC等),签发者,有效期,签发目标,签发目标的公钥,而签发的DNS信息作为一个扩展信息被标注出来。
证书的二进制格式不是HTTP证书专有的,而是遵循了一个叫ASN.1的协议,我们同样可以使用openssl解析符合ASN.1格式的数据
[ych@centos-oracle internal.rxxy.icu]$ openssl asn1parse -in internal.rxxy.icu.crt
0:d=0 hl=4 l=1139 cons: SEQUENCE
4:d=1 hl=4 l= 603 cons: SEQUENCE
8:d=2 hl=2 l= 3 cons: cont [ 0 ]
10:d=3 hl=2 l= 1 prim: INTEGER :02
13:d=2 hl=2 l= 20 prim: INTEGER :5E9EBFE...
35:d=2 hl=2 l= 13 cons: SEQUENCE
37:d=3 hl=2 l= 9 prim: OBJECT :sha256WithRSAEncryption
48:d=3 hl=2 l= 0 prim: NULL
50:d=2 hl=2 l= 97 cons: SEQUENCE
52:d=3 hl=2 l= 11 cons: SET
54:d=4 hl=2 l= 9 cons: SEQUENCE
56:d=5 hl=2 l= 3 prim: OBJECT :countryName
61:d=5 hl=2 l= 2 prim: PRINTABLESTRING :CN
65:d=3 hl=2 l= 16 cons: SET
67:d=4 hl=2 l= 14 cons: SEQUENCE
69:d=5 hl=2 l= 3 prim: OBJECT :stateOrProvinceName
74:d=5 hl=2 l= 7 prim: UTF8STRING :Beijing
83:d=3 hl=2 l= 16 cons: SET
85:d=4 hl=2 l= 14 cons: SEQUENCE
87:d=5 hl=2 l= 3 prim: OBJECT :localityName
92:d=5 hl=2 l= 7 prim: UTF8STRING :HaiDian
101:d=3 hl=2 l= 19 cons: SET
103:d=4 hl=2 l= 17 cons: SEQUENCE
105:d=5 hl=2 l= 3 prim: OBJECT :organizationName
110:d=5 hl=2 l= 10 prim: UTF8STRING :xxx
122:d=3 hl=2 l= 25 cons: SET
124:d=4 hl=2 l= 23 cons: SEQUENCE
126:d=5 hl=2 l= 3 prim: OBJECT :commonName
131:d=5 hl=2 l= 16 prim: UTF8STRING :xxx.cn
149:d=2 hl=2 l= 30 cons: SEQUENCE
151:d=3 hl=2 l= 13 prim: UTCTIME :230531091328Z
166:d=3 hl=2 l= 13 prim: UTCTIME :330528091328Z
181:d=2 hl=2 l= 98 cons: SEQUENCE
183:d=3 hl=2 l= 11 cons: SET
185:d=4 hl=2 l= 9 cons: SEQUENCE
187:d=5 hl=2 l= 3 prim: OBJECT :countryName
192:d=5 hl=2 l= 2 prim: PRINTABLESTRING :CN
196:d=3 hl=2 l= 16 cons: SET
198:d=4 hl=2 l= 14 cons: SEQUENCE
200:d=5 hl=2 l= 3 prim: OBJECT :stateOrProvinceName
205:d=5 hl=2 l= 7 prim: UTF8STRING :BeiJing
214:d=3 hl=2 l= 16 cons: SET
216:d=4 hl=2 l= 14 cons: SEQUENCE
218:d=5 hl=2 l= 3 prim: OBJECT :localityName
223:d=5 hl=2 l= 7 prim: UTF8STRING :HaiDian
232:d=3 hl=2 l= 19 cons: SET
234:d=4 hl=2 l= 17 cons: SEQUENCE
236:d=5 hl=2 l= 3 prim: OBJECT :organizationName
241:d=5 hl=2 l= 10 prim: UTF8STRING :xxx
253:d=3 hl=2 l= 26 cons: SET
255:d=4 hl=2 l= 24 cons: SEQUENCE
257:d=5 hl=2 l= 3 prim: OBJECT :commonName
262:d=5 hl=2 l= 17 prim: UTF8STRING :xxx
281:d=2 hl=4 l= 290 cons: SEQUENCE
285:d=3 hl=2 l= 13 cons: SEQUENCE
287:d=4 hl=2 l= 9 prim: OBJECT :rsaEncryption
298:d=4 hl=2 l= 0 prim: NULL
300:d=3 hl=4 l= 271 prim: BIT STRING
575:d=2 hl=2 l= 34 cons: cont [ 3 ]
577:d=3 hl=2 l= 32 cons: SEQUENCE
579:d=4 hl=2 l= 30 cons: SEQUENCE
581:d=5 hl=2 l= 3 prim: OBJECT :X509v3 Subject Alternative Name
586:d=5 hl=2 l= 23 prim: OCTET STRING [HEX DUMP]:301582132A2E696...
611:d=1 hl=2 l= 13 cons: SEQUENCE
613:d=2 hl=2 l= 9 prim: OBJECT :sha256WithRSAEncryption
624:d=2 hl=2 l= 0 prim: NULL
626:d=1 hl=4 l= 513 prim: BIT STRING
可以看到,
下面来深入了解下证书的结构PKCS#1&PKCS#8
PKCS#1
PKCS#1形式的密钥专指RSA的密钥,如果一个ECC的密钥就无法用PKCS#1形式来表达
RSAPrivateKey ::= SEQUENCE {
version Version,
modulus INTEGER, -- n
publicExponent INTEGER, -- e
privateExponent INTEGER, -- d
prime1 INTEGER, -- p
prime2 INTEGER, -- q
exponent1 INTEGER, -- d mod (p-1)
exponent2 INTEGER, -- d mod (q-1)
coefficient INTEGER -- (inverse of q) mod p
}
PKCS#8
既可以表示RSA密钥,又可以表示ECC的密钥
PrivateKeyInfo ::= SEQUENCE {
version Version,
privateKeyAlgorithm AlgorithmIdentifier {{PrivateKeyAlgorithms}},
privateKey PrivateKey,
attributes [0] Attributes OPTIONAL
}
下面是一些使用openssl查看和操作解析证书的命令,再深入就要解析证书里的公钥和私钥啦,推荐看完阮一峰的RSA算法原理后再来研究,我就暂时止步于此了哈哈-_-||(其实是被劝退)
OPENSSL操作
- 生成RSA密钥PKCS#1
openssl genrsa -out private_pkcs1.pem 2048
- 从生成的RSA密钥中提取RSA公钥
openssl rsa -in private_pkcs1.pem -out public_pkcs8.pem -pubout
openssl rsa -in private_pkcs1.pem -out public_pkcs1.pem -pubout -RSAPublicKey_out
openssl rsa -in private_pkcs8.pem -out public_pkcs8.pem -pubout
openssl rsa -in private_pkcs8.pem -out public_pkcs1.pem -pubout -RSAPublicKey_out
- 导出DER格式的公钥
openssl rsa -in private_pkcs1.pem -out public_pkcs1.der -pubout -RSAPublicKey_out -outform DER
- 查看我们密钥的n、e、d值
openssl rsa -in private_pkcs1.pem -text -noout
- RSA公钥格式转换(PKCS#8 ==> PKCS#1)
openssl rsa -in public_pkcs8.pem -out public_pkcs1.pem -pubin -RSAPublicKey_out
- RSA私钥格式转换(PKCS#1 ==> PKCS#8)
openssl pkcs8 -in private_pkcs1.pem -out private_pkcs8.pem -topk8 -nocrypt
- RSA私钥格式转换(PKCS#8 ==> PKCS#1)
openssl rsa -in private_pkcs8.pem -out private_pkcs1.pem
- RSA公钥编码格式转换(PKCS#8:PEM ==> DER)
openssl rsa -pubin -in public_pkcs8.pem -out public_pkcs8.der -outform DER
openssl rsa -in private_pkcs8.pem -out private_pkcs1.der -outform DER
- 查看私钥及公钥n、e、d
输出到命令行窗口
openssl rsa -in private_pkcs8.pem -text
openssl rsa -in private_pkcs1.pem -text
openssl rsa -in public_pkcs8.pem -text -pubin
openssl rsa -in public_pkcs1.pem -text -pubin (命令报错,不可执行)
输出到文件
openssl rsa -in private_pkcs8.pem -text -out out.txt
- 从pfx文件中提取私钥(==> PKCS#8)
openssl pkcs12 -in demo_749054.pfx -nocerts -nodes -out private_pkcs8.pem