使用Python Openssl库解析X509证书信息

X.509 证书结构描述

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

后缀 作用
cer/crt 用于存放证书,它是2进制形式存放的,不含私钥
pem 以Ascii来表示,可以用于存放证书或私钥。
pfx/p12 用于存放个人证书/私钥,他通常包含保护密码,2进制方式。
p10 证书请求
p7r CA对证书请求的回复,只用于导入
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

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

安装依赖库

$ pip3 install pyOpenSSL

$ pip3 install python-dateutil

代码如下

#!/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`自带的解析结果对比

是相同的。

参考链接


发布者

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注