Python - извлечь сертификат из файла p7s

Расшифровывая входящее письмо на 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 ответ

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

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

Получив список сертификатов, каждый из них может быть преобразован в cryptographyCertificate объект, который является родным 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
Другие вопросы по тегам