• 使用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 }

    源代码

    这里利用的是python3 的 Openssl 库进行解析, 此库的说明文档如下,
    https://pyopenssl.org/en/0.15.1/api/crypto.html#x509name-objects

    crypto — Generic cryptographic module
    OpenSSL.crypto.X509Type
    See X509.
    
    classOpenSSL.crypto.X509
    A class representing X.509 certificates.
    
    OpenSSL.crypto.X509NameType
    See X509Name.
    
    classOpenSSL.crypto.X509Name(x509name)
    A class representing X.509 Distinguished Names.
    
    This constructor creates a copy of x509name which should be an instance of X509Name.
    
    OpenSSL.crypto.X509ReqType
    See X509Req.
    
    classOpenSSL.crypto.X509Req
    A class representing X.509 certificate requests.
    
    OpenSSL.crypto.X509StoreType
    See X509Store
    
    OpenSSL.crypto.X509StoreContext
    A class representing the X.509 store context.
    
    OpenSSL.crypto.PKeyType
    See PKey.
    
    classOpenSSL.crypto.PKey
    A class representing DSA or RSA keys.
    
    OpenSSL.crypto.PKCS7Type
    A Python type object representing the PKCS7 object type.
    
    OpenSSL.crypto.PKCS12Type
    A Python type object representing the PKCS12 object type.
    
    OpenSSL.crypto.X509ExtensionType
    See X509Extension.
    
    classOpenSSL.crypto.X509Extension(typename, critical, value[, subject][, issuer])
    A class representing an X.509 v3 certificate extensions. See http://openssl.org/docs/apps/x509v3_config.html#STANDARD_EXTENSIONS for typename strings and their options. Optional parameters subject and issuer must be X509 objects.
    
    OpenSSL.crypto.NetscapeSPKIType
    See NetscapeSPKI.
    
    classOpenSSL.crypto.NetscapeSPKI([enc])
    A class representing Netscape SPKI objects.
    
    If the enc argument is present, it should be a base64-encoded string representing a NetscapeSPKI object, as returned by the b64_encode() method.
    
    classOpenSSL.crypto.CRL
    A class representing Certifcate Revocation List objects.
    
    classOpenSSL.crypto.Revoked
    A class representing Revocation objects of CRL.
    
    OpenSSL.crypto.FILETYPE_PEM
    OpenSSL.crypto.FILETYPE_ASN1
    File type constants.
    
    OpenSSL.crypto.TYPE_RSA
    OpenSSL.crypto.TYPE_DSA
    Key type constants.
    
    exceptionOpenSSL.crypto.Error
    Generic exception used in the crypto module.
    
    OpenSSL.crypto.get_elliptic_curves()
    Return a set of objects representing the elliptic curves supported in the OpenSSL build in use.
    
    The curve objects have a unicode name attribute by which they identify themselves.
    
    The curve objects are useful as values for the argument accepted by Context.set_tmp_ecdh() to specify which elliptical curve should be used for ECDHE key exchange.
    
    OpenSSL.crypto.get_elliptic_curve()
    Return a single curve object selected by name.
    
    See get_elliptic_curves() for information about curve objects.
    
    If the named curve is not supported then ValueError is raised.
    
    OpenSSL.crypto.dump_certificate(type, cert)
    Dump the certificate cert into a buffer string encoded with the type type.
    
    OpenSSL.crypto.dump_certificate_request(type, req)
    Dump the certificate request req into a buffer string encoded with the type type.
    
    OpenSSL.crypto.dump_privatekey(type, pkey[, cipher, passphrase])
    Dump the private key pkey into a buffer string encoded with the type type, optionally (if type is FILETYPE_PEM) encrypting it using cipher and passphrase.
    
    passphrase must be either a string or a callback for providing the pass phrase.
    
    OpenSSL.crypto.load_certificate(type, buffer)
    Load a certificate (X509) from the string buffer encoded with the type type.
    
    OpenSSL.crypto.load_certificate_request(type, buffer)
    Load a certificate request (X509Req) from the string buffer encoded with the type type.
    
    OpenSSL.crypto.load_privatekey(type, buffer[, passphrase])
    Load a private key (PKey) from the string buffer encoded with the type type (must be one of FILETYPE_PEM and FILETYPE_ASN1).
    
    passphrase must be either a string or a callback for providing the pass phrase.
    
    OpenSSL.crypto.load_crl(type, buffer)
    Load Certificate Revocation List (CRL) data from a string buffer. buffer encoded with the type type. The type type must either FILETYPE_PEM or FILETYPE_ASN1).
    
    OpenSSL.crypto.load_pkcs7_data(type, buffer)
    Load pkcs7 data from the string buffer encoded with the type type.
    
    OpenSSL.crypto.load_pkcs12(buffer[, passphrase])
    Load pkcs12 data from the string buffer. If the pkcs12 structure is encrypted, a passphrase must be included. The MAC is always checked and thus required.
    
    See also the man page for the C function PKCS12_parse().
    
    OpenSSL.crypto.sign(key, data, digest)
    Sign a data string using the given key and message digest.
    
    key is a PKey instance. data is a str instance. digest is a str naming a supported message digest type, for example sha1.
    
    New in version 0.11.
    
    OpenSSL.crypto.verify(certificate, signature, data, digest)
    Verify the signature for a data string.
    
    certificate is a X509 instance corresponding to the private key which generated the signature. signature is a str instance giving the signature itself. data is a str instance giving the data to which the signature applies. digest is a str instance naming the message digest type of the signature, for example sha1.
    
    New in version 0.11.
    
    X509 objects
    X509 objects have the following methods:
    
    X509.get_issuer()
    Return an X509Name object representing the issuer of the certificate.
    
    X509.get_pubkey()
    Return a PKey object representing the public key of the certificate.
    
    X509.get_serial_number()
    Return the certificate serial number.
    
    X509.get_signature_algorithm()
    Return the signature algorithm used in the certificate. If the algorithm is undefined, raise ValueError.
    
    New in version 0.13.
    
    X509.get_subject()
    Return an X509Name object representing the subject of the certificate.
    
    X509.get_version()
    Return the certificate version.
    
    X509.get_notBefore()
    Return a string giving the time before which the certificate is not valid. The string is formatted as an ASN1 GENERALIZEDTIME:
    
    YYYYMMDDhhmmssZ
    YYYYMMDDhhmmss+hhmm
    YYYYMMDDhhmmss-hhmm
    If no value exists for this field, None is returned.
    
    X509.get_notAfter()
    Return a string giving the time after which the certificate is not valid. The string is formatted as an ASN1 GENERALIZEDTIME:
    
    YYYYMMDDhhmmssZ
    YYYYMMDDhhmmss+hhmm
    YYYYMMDDhhmmss-hhmm
    If no value exists for this field, None is returned.
    
    X509.set_notBefore(when)
    Change the time before which the certificate is not valid. when is a string formatted as an ASN1 GENERALIZEDTIME:
    
    YYYYMMDDhhmmssZ
    YYYYMMDDhhmmss+hhmm
    YYYYMMDDhhmmss-hhmm
    X509.set_notAfter(when)
    Change the time after which the certificate is not valid. when is a string formatted as an ASN1 GENERALIZEDTIME:
    
    YYYYMMDDhhmmssZ
    YYYYMMDDhhmmss+hhmm
    YYYYMMDDhhmmss-hhmm
    X509.gmtime_adj_notBefore(time)
    Adjust the timestamp (in GMT) when the certificate starts being valid.
    
    X509.gmtime_adj_notAfter(time)
    Adjust the timestamp (in GMT) when the certificate stops being valid.
    
    X509.has_expired()
    Checks the certificate’s time stamp against current time. Returns true if the certificate has expired and false otherwise.
    
    X509.set_issuer(issuer)
    Set the issuer of the certificate to issuer.
    
    X509.set_pubkey(pkey)
    Set the public key of the certificate to pkey.
    
    X509.set_serial_number(serialno)
    Set the serial number of the certificate to serialno.
    
    X509.set_subject(subject)
    Set the subject of the certificate to subject.
    
    X509.set_version(version)
    Set the certificate version to version.
    
    X509.sign(pkey, digest)
    Sign the certificate, using the key pkey and the message digest algorithm identified by the string digest.
    
    X509.subject_name_hash()
    Return the hash of the certificate subject.
    
    X509.digest(digest_name)
    Return a digest of the certificate, using the digest_name method. digest_name must be a string describing a digest algorithm supported by OpenSSL (by EVP_get_digestbyname, specifically). For example, "md5" or "sha1".
    
    X509.add_extensions(extensions)
    Add the extensions in the sequence extensions to the certificate.
    
    X509.get_extension_count()
    Return the number of extensions on this certificate.
    
    New in version 0.12.
    
    X509.get_extension(index)
    Retrieve the extension on this certificate at the given index.
    
    Extensions on a certificate are kept in order. The index parameter selects which extension will be returned. The returned object will be an X509Extension instance.
    
    New in version 0.12.
    
    X509Name objects
    X509Name objects have the following methods:
    
    X509Name.hash()
    Return an integer giving the first four bytes of the MD5 digest of the DER representation of the name.
    
    X509Name.der()
    Return a string giving the DER representation of the name.
    
    X509Name.get_components()
    Return a list of two-tuples of strings giving the components of the name.
    
    X509Name objects have the following members:
    
    X509Name.countryName
    The country of the entity. C may be used as an alias for countryName.
    
    X509Name.stateOrProvinceName
    The state or province of the entity. ST may be used as an alias for stateOrProvinceName.
    
    X509Name.localityName
    The locality of the entity. L may be used as an alias for localityName.
    
    X509Name.organizationName
    The organization name of the entity. O may be used as an alias for organizationName.
    
    X509Name.organizationalUnitName
    The organizational unit of the entity. OU may be used as an alias for organizationalUnitName.
    
    X509Name.commonName
    The common name of the entity. CN may be used as an alias for commonName.
    
    X509Name.emailAddress
    The e-mail address of the entity.
    
    X509Req objects
    X509Req objects have the following methods:
    
    X509Req.get_pubkey()
    Return a PKey object representing the public key of the certificate request.
    
    X509Req.get_subject()
    Return an X509Name object representing the subject of the certificate.
    
    X509Req.set_pubkey(pkey)
    Set the public key of the certificate request to pkey.
    
    X509Req.sign(pkey, digest)
    Sign the certificate request, using the key pkey and the message digest algorithm identified by the string digest.
    
    X509Req.verify(pkey)
    Verify a certificate request using the public key pkey.
    
    X509Req.set_version(version)
    Set the version (RFC 2459, 4.1.2.1) of the certificate request to version.
    
    X509Req.get_version()
    Get the version (RFC 2459, 4.1.2.1) of the certificate request.
    
    X509Req.get_extensions()
    Get extensions to the request.
    
    New in version 0.15.
    
    X509Store objects
    The X509Store object has currently just one method:
    
    X509Store.add_cert(cert)
    Add the certificate cert to the certificate store.
    
    X509StoreContextError objects
    The X509StoreContextError is an exception raised from X509StoreContext.verify_certificate in circumstances where a certificate cannot be verified in a provided context.
    
    The certificate for which the verification error was detected is given by the certificate attribute of the exception instance as a X509 instance.
    
    Details about the verification error are given in the exception’s args attribute.
    
    X509StoreContext objects
    The X509StoreContext object is used for verifying a certificate against a set of trusted certificates.
    
    X509StoreContext.verify_certificate()
    Verify a certificate in the context of this initialized X509StoreContext. On error, raises X509StoreContextError, otherwise does nothing.
    
    New in version 0.15.
    
    PKey objects
    The PKey object has the following methods:
    
    PKey.bits()
    Return the number of bits of the key.
    
    PKey.generate_key(type, bits)
    Generate a public/private key pair of the type type (one of TYPE_RSA and TYPE_DSA) with the size bits.
    
    PKey.type()
    Return the type of the key.
    
    PKey.check()
    Check the consistency of this key, returning True if it is consistent and raising an exception otherwise. This is only valid for RSA keys. See the OpenSSL RSA_check_key man page for further limitations.
    
    PKCS7 objects
    PKCS7 objects have the following methods:
    
    PKCS7.type_is_signed()
    FIXME
    
    PKCS7.type_is_enveloped()
    FIXME
    
    PKCS7.type_is_signedAndEnveloped()
    FIXME
    
    PKCS7.type_is_data()
    FIXME
    
    PKCS7.get_type_name()
    Get the type name of the PKCS7.
    
    PKCS12 objects
    PKCS12 objects have the following methods:
    
    PKCS12.export([passphrase=None][, iter=2048][, maciter=1])
    Returns a PKCS12 object as a string.
    
    The optional passphrase must be a string not a callback.
    
    See also the man page for the C function PKCS12_create().
    
    PKCS12.get_ca_certificates()
    Return CA certificates within the PKCS12 object as a tuple. Returns None if no CA certificates are present.
    
    PKCS12.get_certificate()
    Return certificate portion of the PKCS12 structure.
    
    PKCS12.get_friendlyname()
    Return friendlyName portion of the PKCS12 structure.
    
    PKCS12.get_privatekey()
    Return private key portion of the PKCS12 structure
    
    PKCS12.set_ca_certificates(cacerts)
    Replace or set the CA certificates within the PKCS12 object with the sequence cacerts.
    
    Set cacerts to None to remove all CA certificates.
    
    PKCS12.set_certificate(cert)
    Replace or set the certificate portion of the PKCS12 structure.
    
    PKCS12.set_friendlyname(name)
    Replace or set the friendlyName portion of the PKCS12 structure.
    
    PKCS12.set_privatekey(pkey)
    Replace or set private key portion of the PKCS12 structure
    
    X509Extension objects
    X509Extension objects have several methods:
    
    X509Extension.get_critical()
    Return the critical field of the extension object.
    
    X509Extension.get_short_name()
    Retrieve the short descriptive name for this extension.
    
    The result is a byte string like basicConstraints.
    
    New in version 0.12.
    
    X509Extension.get_data()
    Retrieve the data for this extension.
    
    The result is the ASN.1 encoded form of the extension data as a byte string.
    
    New in version 0.12.
    
    NetscapeSPKI objects
    NetscapeSPKI objects have the following methods:
    
    NetscapeSPKI.b64_encode()
    Return a base64-encoded string representation of the object.
    
    NetscapeSPKI.get_pubkey()
    Return the public key of object.
    
    NetscapeSPKI.set_pubkey(key)
    Set the public key of the object to key.
    
    NetscapeSPKI.sign(key, digest_name)
    Sign the NetscapeSPKI object using the given key and digest_name. digest_name must be a string describing a digest algorithm supported by OpenSSL (by EVP_get_digestbyname, specifically). For example, "md5" or "sha1".
    
    NetscapeSPKI.verify(key)
    Verify the NetscapeSPKI object using the given key.
    
    CRL objects
    CRL objects have the following methods:
    
    CRL.add_revoked(revoked)
    Add a Revoked object to the CRL, by value not reference.
    
    CRL.export(cert, key[, type=FILETYPE_PEM][, days=100][, digest=b'md5'])
    Use cert and key to sign the CRL and return the CRL as a string. days is the number of days before the next CRL is due. digest is the algorithm that will be used to sign CRL.
    
    CRL.get_revoked()
    Return a tuple of Revoked objects, by value not reference.
    
    Revoked objects
    Revoked objects have the following methods:
    
    Revoked.all_reasons()
    Return a list of all supported reasons.
    
    Revoked.get_reason()
    Return the revocation reason as a str. Can be None, which differs from “Unspecified”.
    
    Revoked.get_rev_date()
    Return the revocation date as a str. The string is formatted as an ASN1 GENERALIZEDTIME.
    
    Revoked.get_serial()
    Return a str containing a hex number of the serial of the revoked certificate.
    
    Revoked.set_reason(reason)
    Set the revocation reason. reason must be None or a string, but the values are limited. Spaces and case are ignored. See all_reasons().
    
    Revoked.set_rev_date(date)
    Set the revocation date. The string is formatted as an ASN1 GENERALIZEDTIME.
    
    Revoked.set_serial(serial)
    serial is a string containing a hex number of the serial of the revoked certificate.
    PyopenSSL

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

    安装依赖库

    $ 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("公钥:
    " ,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())

    运行结果:

     和chrome中证书查看是一样的。

  • 相关阅读:
    反流技术之IE插件技术研究第一部分
    c# post和接收的实现
    C# post提交表单的例程
    用C#搭建IE BHO勾子, 取表单密码
    复杂的 DataBinding 接受 IList 或 IListSource 作为数据源" 错误原来是自己的笔误
    C#判断ContextMenuStrip右键菜单的来源(从哪个控件弹出来的)
    练习5.1
    示例:实用函数(Utilities)
    闭包
    一个错误
  • 原文地址:https://www.cnblogs.com/yunlong-study/p/14537390.html
Copyright © 2020-2023  润新知