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.
通过阅读说明文档, 可以轻松读取证书相关信息。
安装依赖库
$ 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中证书查看是一样的。