使用 pyOpenSSL 解析证书的正确姿势

前言

需求很简单,通过域名证书的私钥分析证书的 DNS 域名以及有效期

实现

分析后决定用 pyOpenSSL 来实现,具体代码如下

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
from OpenSSL import crypto
from dateutil import parser

class Ssl():
def parse(self, certificate):
res = {
"domain": []
}
cert = crypto.load_certificate(crypto.FILETYPE_PEM, certificate)
# 有效期
datetime_struct_start = parser.parse(cert.get_notBefore().decode("UTF-8"))
datetime_struct_end = parser.parse(cert.get_notAfter().decode("UTF-8"))
res['start_time'] = datetime_struct_start.strftime('%Y-%m-%d %H:%M:%S')
res['end_time'] = datetime_struct_end.strftime('%Y-%m-%d %H:%M:%S')
# 扩展
count = cert.get_extension_count()
for i in range(count):
crt = cert.get_extension(i)
name = str(crt.get_short_name(), encoding="utf-8")
if name == "subjectAltName":
_list = str(crt).split(',')
_it = iter(_list) # 创建迭代器对象
for x in _it:
res["domain"].append(x.strip().replace("DNS:", ""))
break
return res

if __name__ == '__main__':
_certificate="""证书私钥"""
ssl = Ssl()
print(ssl.parse(_certificate))
# {'domain': ['*.jakehu.me', 'jakehu.me'], 'start_time': '2021-07-12 18:01:16', 'end_time': '2021-10-10 18:01:15'}

最后

通过 get_subject()get_issuer() 获取证书的其他信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
subject = cert.get_subject()
issuer = cert.get_issuer()

print("证书版本:", cert.get_version() + 1)
print("证书序列号:", hex(cert.get_serial_number()))
print("证书中使用的签名算法:", cert.get_signature_algorithm().decode("UTF-8"))
print("颁发者:", issuer.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", crypto.dump_publickey(crypto.FILETYPE_PEM, cert.get_pubkey()).decode("utf-8"))
print("主体信息:")
print("CN:通用名称 OU:机构单元名称")
print("O:机构名 L:地理位置")
print("S:州/省名 C:国名")
for item in issuer.get_components():
print(item[0].decode("utf-8"), " —— ", item[1].decode("utf-8"))