Python - извлечь сертификат из файла p7s - PullRequest
0 голосов
/ 22 ноября 2018

Расшифровывая входящее письмо на Python, у меня есть вложение "smime.p7s".Если я запишу это в файл, то его можно извлечь и просмотреть, используя

openssl pkcs7 -inform der -print_certs <smime.p7s

Я хотел бы сделать это в Python.Здесь есть пример здесь обратного процесса, т.е. как подписать письмо.

При просмотре документации OpenSSL API есть записьточка PKCS7_get0_signers, которая, кажется, делает это.

Вот фрагмент кода, который я пробую, основанный на наивной переработке кода подписи.

with open(fname, 'wb') as p7sfile:
    p7sfile.write(sig)
    pkcs7 = crypto._lib.PKCS7_get0_signers(sig, None, 0)

Это не работает -

pkcs7 = crypto._lib.PKCS7_get0_signers(sig, None, 0)
TypeError: initializer for ctype 'PKCS7 *' must be a cdata pointer, not bytes

Кажется, что функция требует трех параметров, хотя, возможно, флаги необязательны?

Эта строка кода (из более старой библиотеки M2Crypto) также предполагает, чтоточке входа нужны три параметра.

Я не понимаю, зачем ей нужен «certs.stack» в качестве входного параметра, когда мы пытаемся извлечь сертификаты, а я неЯ не уверен, что нужно помещать в «флаги».

Я почти уверен, что мне нужны специальные буферизованные объявления для настройки вызова, а также для получения результатов (например, преамбула bio_in = crypto._new_mem_buf(data) в 1 ).Может кто-нибудь подсказать, как это сделать?

Также - библиотека M2Crypto не совместима с Python 3.x, поэтому ищет альтернативу.

1 Ответ

0 голосов
/ 23 ноября 2018

Я нашел полезный фрагмент кода здесь .Это извлекает сертификаты из двоичного объекта PKCS7 в список OpenSSL.crypto.X509 объектов.

Объект OpenSSL.crypto.X509 в порядке для выгрузки содержимого сертификата (у него есть метод dump_certificate), ноС атрибутами трудно работать, поскольку они все еще закодированы в ASN.1 и являются типами C.

После получения списка сертификатов каждый из них можно преобразовать в объект cryptography Certificate, которыйPython родной и более податливый.Например:

class Cert(object):
    """
    Convenient container object for human-readable and output-file friendly certificate contents
    """
    pem = ''
    email_signer = None
    startT = None
    endT = None
    issuer = {}
    algorithm = None


def extract_smime_signature(payload):
    """
    Extract public certificates from the PKCS7 binary payload

    :param payload: bytes
    :return: list of Cert objects
    """
    pkcs7 = crypto.load_pkcs7_data(crypto.FILETYPE_ASN1, payload)
    certs = get_certificates(pkcs7)
    certList = []
    # Collect the following info from the certificates
    all_cert_times_valid = True
    for c in certs:
        # Convert to the modern & easier to use https://cryptography.io library objects
        c2 = crypto.X509.to_cryptography(c)
        c3 = Cert()

        # check each certificate's time validity, ANDing cumulatively across each one
        c3.startT = c2.not_valid_before
        c3.endT = c2.not_valid_after
        now = datetime.now()
        all_cert_times_valid = all_cert_times_valid and (c3.startT <= now) and (now <= c3.endT)

        # get Issuer, unpacking the ASN.1 structure into a dict
        for i in c2.issuer.rdns:
            for j in i:
                c3.issuer[j.oid._name] = j.value

        # get email address from the cert "subject" - consider more than one address in the bundle as an error
        for i in c2.subject.rdns:
            for j in i:
                attrName = j.oid._name
                if attrName == 'emailAddress':
                    c3.email_signer = j.value

        # Get hash alg - just for interest
        c3.algorithm = c2.signature_hash_algorithm.name
        c3.pem = c2.public_bytes(serialization.Encoding.PEM).decode('utf8')
        certList.append(c3)
    return certList
...