X.509 证书结构描述
常见的X.509证书格式包括:
后缀 | 作用 |
---|---|
cer/crt | 用于存放证书,它是2进制形式存放的,不含私钥 |
pem | 以Ascii来表示,可以用于存放证书或私钥。 |
pfx/p12 | 用于存放个人证书/私钥,他通常包含保护密码,2进制方式。 |
p10 | 证书请求 |
p7r | CA对证书请求的回复,只用于导入 |
p7b | 以树状展示证书链(certificate chain),同时也支持单个证书,不含私钥。 |
对于常见的https证书 一般是用crt或者pem来保存, http证书可点击网页前的锁按钮得到, 并且进行导出
注意,此处导出的证书可能是.cer
文件,在使用python3
处理的时候,可能报告如下错误:
1 2 3 4 5 6 |
Traceback (most recent call last): File "tool.py", line 9, in <module> crt_data = fp.read() File "/usr/local/Cellar/python/3.7.7/Frameworks/Python.framework/Versions/3.7/lib/python3.7/codecs.py", line 322, in decode (result, consumed) = self._buffer_decode(data, self.errors, final) UnicodeDecodeError: 'utf-8' codec can't decode byte 0x82 in position 1: invalid start byte |
这个错误是由于python3
处理二进制数据的时候编码不正确导致的,简单的解决方法使用使用openssl
工具转换成文本格式,执行如下命令:
1 |
$ openssl x509 -inform DER -in test.cer -out certificate.crt |
然后解析 certificate.crt
文件即可。
证书数据结构
此证书结构来着白皮书
https://tools.ietf.org/html/rfc2459#section-4.1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 |
Certificate ::= SEQUENCE { tbsCertificate TBSCertificate, -- 证书主体 signatureAlgorithm AlgorithmIdentifier, -- 证书签名算法标识 signatureValue BIT STRING --证书签名值,是使用signatureAlgorithm部分指定的签名算法对tbsCertificate证书主题部分签名后的值. } TBSCertificate ::= SEQUENCE { version [0] EXPLICIT Version DEFAULT v1, -- 证书版本号 serialNumber CertificateSerialNumber, -- 证书序列号,对同一CA所颁发的证书,序列号唯一标识证书 signature AlgorithmIdentifier, --证书签名算法标识 issuer Name, --证书发行者名称 validity Validity, --证书有效期 subject Name, --证书主体名称 subjectPublicKeyInfo SubjectPublicKeyInfo,--证书公钥 issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL, -- 证书发行者ID(可选),只在证书版本2、3中才有 subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL, -- 证书主体ID(可选),只在证书版本2、3中才有 extensions [3] EXPLICIT Extensions OPTIONAL -- 证书扩展段(可选),只在证书版本3中才有 } Version ::= INTEGER { v1(0), v2(1), v3(2) } CertificateSerialNumber ::= INTEGER AlgorithmIdentifier ::= SEQUENCE { algorithm OBJECT IDENTIFIER, parameters ANY DEFINED BY algorithm OPTIONAL } parameters: Dss-Parms ::= SEQUENCE { -- parameters ,DSA(DSS)算法时的parameters, RSA算法没有此参数 p INTEGER, q INTEGER, g INTEGER } signatureValue: Dss-Sig-Value ::= SEQUENCE { -- sha1DSA签名算法时,签名值 r INTEGER, s INTEGER } Name ::= CHOICE { RDNSequence } RDNSequence ::= SEQUENCE OF RelativeDistinguishedName RelativeDistinguishedName ::= SET OF AttributeTypeAndValue AttributeTypeAndValue ::= SEQUENCE { type AttributeType, value AttributeValue } AttributeType ::= OBJECT IDENTIFIER AttributeValue ::= ANY DEFINED BY AttributeType Validity ::= SEQUENCE { notBefore Time, -- 证书有效期起始时间 notAfter Time -- 证书有效期终止时间 } Time ::= CHOICE { utcTime UTCTime, generalTime GeneralizedTime } UniqueIdentifier ::= BIT STRING SubjectPublicKeyInfo ::= SEQUENCE { algorithm AlgorithmIdentifier, -- 公钥算法 subjectPublicKey BIT STRING -- 公钥值 } subjectPublicKey: RSAPublicKey ::= SEQUENCE { -- RSA算法时的公钥值 modulus INTEGER, -- n publicExponent INTEGER -- e -- } Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension Extension ::= SEQUENCE { extnID OBJECT IDENTIFIER, critical BOOLEAN DEFAULT FALSE, extnValue OCTET STRING } |
参考博客:
https://blog.csdn.net/xy010902100449/article/details/52145009
源代码
这里利用的是python3 的 Openssl 库进行解析, 此库的说明文档如下,
https://pyopenssl.org/en/0.15.1/api/crypto.html#x509name-objects
通过阅读说明文档, 可以轻松读取证书相关信息。
安装依赖库
1 2 3 |
$ pip3 install pyOpenSSL $ pip3 install python-dateutil |
代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
#!/usr/bin/python3 # -*- coding: utf-8 -*- import OpenSSL import time from dateutil import parser #openssl x509 -inform DER -in test.cer -out certificate.crt with open("certificate.crt", "r") as fp: crt_data = fp.read() cert = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, crt_data) certIssue = cert.get_issuer() print ("证书版本: ",cert.get_version() + 1) print ("证书序列号: ",hex(cert.get_serial_number())) print ("证书中使用的签名算法: ",cert.get_signature_algorithm().decode("UTF-8")) print ("颁发者: ",certIssue.commonName) datetime_struct = parser.parse(cert.get_notBefore().decode("UTF-8")) print ("有效期从: ",datetime_struct.strftime('%Y-%m-%d %H:%M:%S')) datetime_struct = parser.parse(cert.get_notAfter().decode("UTF-8")) print ("到: ",datetime_struct.strftime('%Y-%m-%d %H:%M:%S')) print ("证书是否已经过期: ",cert.has_expired()) print("公钥长度" ,cert.get_pubkey().bits()) print("公钥:\n" ,OpenSSL.crypto.dump_publickey(OpenSSL.crypto.FILETYPE_PEM, cert.get_pubkey()).decode("utf-8")) print("主体信息:") print("CN : 通用名称 OU : 机构单元名称") print("O : 机构名 L : 地理位置") print("S : 州/省名 C : 国名") for item in certIssue.get_components(): print(item[0].decode("utf-8"), " —— ",item[1].decode("utf-8")) print(cert.get_extension_count()) |
编译运行输出结果
注意,.cer
格式的文件,在使用python3
处理的时候,可能报告如下错误:
1 2 3 4 5 6 |
Traceback (most recent call last): File "tool.py", line 9, in <module> crt_data = fp.read() File "/usr/local/Cellar/python/3.7.7/Frameworks/Python.framework/Versions/3.7/lib/python3.7/codecs.py", line 322, in decode (result, consumed) = self._buffer_decode(data, self.errors, final) UnicodeDecodeError: 'utf-8' codec can't decode byte 0x82 in position 1: invalid start byte |
这个错误是由于python3
处理二进制数据的时候编码不正确导致的,简单的解决方法使用使用openssl
工具转换成文本格式,执行如下命令:
1 |
$ openssl x509 -inform DER -in test.cer -out certificate.crt |
然后解析 certificate.crt
文件即可。
Chrome
自带的解析结果对比
是相同的。