在Python中解码传入的电子邮件,我有一个附件“ smime.p7s”。 如果我将其写入文件,则可以使用
将其提取并查看 openssl pkcs7 -inform der -print_certs <smime.p7s
我想用Python做到这一点。有一个相反过程的示例here,即如何签名邮件。
看一下OpenSSL API documentation,似乎有一个入口点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
该功能似乎需要三个参数,尽管标志可能是可选的?
This line代码(来自较早的M2Crypto库)也表明入口点需要三个参数。
当我们尝试提取证书时,我不明白为什么它需要一个“ certs.stack”作为输入参数,而且我也不知道在“ flags”中添加什么“。
我敢肯定,我需要一些特殊类型的缓冲区声明来建立调用,并检索结果(例如1中的bio_in = crypto._new_mem_buf(data)
前言)。有人可以建议如何做吗?
此外-M2Crypto
库与Python 3.x不兼容,因此正在寻找替代方法。
答案 0 :(得分:0)
我找到了一个有用的代码段here。这会将证书从PKCS7二进制对象提取到OpenSSL.crypto.X509
个对象的列表中。
可以将OpenSSL.crypto.X509对象用于转储证书内容(它具有dump_certificate
方法),但是很难使用这些属性,因为它们仍然是ASN.1编码并且是C类型
一旦您有了一份证书列表,就可以将每个证书转换为{原生的cryptography
Certificate
对象,并且更易于使用。例如:
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