使用Python Openssl库解析X509证书信息!应该很多人都碰到过!

X.509 证书结构描述

常见的X.509证书格式包括:

后缀作用cer/crt用于存放证书,它是2进制形式存放的,不含私钥pem以Ascii来表示,可以用于存放证书或私钥。pfx/p12用于存放个人证书/私钥,他通常包含保护密码,2进制方式。p10证书请求p7rCA对证书请求的回复,只用于导入p7b以树状展示证书链(certificate chain),同时也支持单个证书,不含私钥。

对于常见的https证书 一般是用crt或者pem来保存, http证书可点击网页前的锁按钮得到, 并且进行导出

注意,此处导出的证书可能是 .cer 文件,在使用 python3 处理的时候,可能报告如下错误:

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 工具转换成文本格式,执行如下命令:

$ openssl x509 -inform DER -in test.cer -out certificate.crt

然后解析 certificate.crt 文件即可。

证书数据结构

此证书结构来着白皮书

https://tools.ietf.org/html/rfc2459#section-4.1

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

通过阅读说明文档, 可以轻松读取证书相关信息

代码如下

#!/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 处理的时候,可能报告如下错误:

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 工具转换成文本格式,执行如下命令:

$ openssl x509 -inform DER -in test.cer -out certificate.crt

然后解析 certificate.crt 文件即可。

Chrome 自带的解析结果对比

是相同的。

更多有趣案例视频教程源码获取加群:850591259

发布了23 篇原创文章 · 获赞 0 · 访问量 8053

猜你喜欢

转载自blog.csdn.net/weixin_43881394/article/details/105680058