Простой анализ сертификата DER в python

Как лучше всего проанализировать с помощью python двоичный файл с сертификатом X509 в формате DER для извлечения открытого ключа.


person David A    schedule 14.09.2013    source источник


Ответы (3)


Ни встроенный модуль SSL Python, ни PyOpenSSL не имеют API для извлечения закрытого ключа и доступа к его информации. M2Crypto больше не поддерживается и не работает с OpenSSL 1.0 и новее.

PyOpenSSL имеет класс открытого ключа, но его возможности ограничены:

>>> with open("cert.der", "rb") as f:
...     der = f.read()
... 
>>> import OpenSSL.crypto
>>> x509 = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_ASN1, der)
>>> pkey = x509.get_pubkey()
>>> dir(pkey)
['__class__', '__delattr__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'bits', 'check', 'generate_key', 'type']
>>> pkey.bits()
4096L
>>> pkey.type() == OpenSSL.crypto.TYPE_RSA
True

Python 3.4 может получить тип X509, который предоставляет больше информации, такой как SPKI.

person Christian Heimes    schedule 15.09.2013
comment
существует любой способ распечатать почти все проанализированные сертификаты (так же, как pyasn1.printPretty()) или, по крайней мере, распечатать pubkey как шестнадцатеричную строку. - person David A; 15.09.2013

Приведенные выше ответы несколько устарели (по состоянию на 2017 год).

Вы можете использовать asn1crypto, чтобы сделать это более удобным способом:

from asn1crypto.x509 import Certificate

with open("mycert.der", "rb") as f:
    cert = Certificate.load(f.read())

n = cert.public_key.native["public_key"]["modulus"]
e = cert.public_key.native["public_key"]["public_exponent"]

print("{:#x}".format(n))    # prints the modulus (hexadecimal)
print("{:#x}".format(e))    # same, for the public exponent

Он относительно новый (насколько я вижу, середина 2015 года), предоставляет более приятный интерфейс, чем уже упомянутые библиотеки, и, по словам автора, намного быстрее, чем pyasn1.

person De117    schedule 15.05.2017
comment
команда печати модуля выдает ошибку ValueError: Error parsing asn1crypto.x509.Certificate - tag should have been 16, but 13 was found Почему это так? - person Bogota; 17.06.2020
comment
Это может произойти, если вы пытаетесь прочитать сертификат в формате PEM. Приведенный выше код работает с кодировкой DER. (См. Здесь для получения дополнительной информации о форматах сертификатов.) Преобразование из PEM в DER должно быть вопросом простого удаления верхнего/нижнего колонтитула и декодирования base64 средней части. - person De117; 19.06.2020

Прошло много времени с тех пор, как я задавал этот вопрос, хотя из-за количества просмотров я хотел бы описать, как мне удалось заставить его работать.

Используя OpenSSL API, мы можем легко распечатать сертификат DER в удобном для чтения виде. Несмотря на то, что его возможности очень ограничены, это пример.

print OpenSSL.crypto.dump_certificate(OpenSSL.crypto.FILETYPE_TEXT,x509)

Однако я хотел иметь контроль над ключами в var напрямую (нужно было отправить его в другую функцию), и для этого я сделал следующую функцию

def parse_asn1_der(derfile):
    from pyasn1_modules import  rfc2437,rfc2459
    from pyasn1.codec.der import decoder
    certType = rfc2459.Certificate(); 
    raw=derfile #the result of open(fname,"rb").read()
    cert,rest = decoder.decode(raw, asn1Spec=certType)
    RSAKEYSDATA=frombits(cert.getComponentByName("tbsCertificate").getComponentByName("subjectPublicKeyInfo").getComponentByName("subjectPublicKey"))
    SignatureCert=frombits(cert.getComponentByName("signatureValue")).encode("hex")
    rsaType=rfc2437.RSAPublicKey();
    rsadata,rsadata_rest = decoder.decode(RSAKEYSDATA, asn1Spec=rsaType)
    print "----"
    print "Certificate Plain Data"
    print "RSA Modulus: %X" %rsadata.getComponentByName("modulus")
    print "RSA Public exponent: %X" %rsadata.getComponentByName("publicExponent")
    print "Signature: %s"%SignatureCert
    return rsadata.getComponentByName("modulus")

Надеюсь, это поможет любому, кто смотрит вокруг.

person David A    schedule 13.11.2015