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