从 python 中的 pkcs7 提取签名数据

extract signed data from pkcs7 in python

我有一个 USB 加密令牌,能够签署数据并将其打包到 pkcs 文件中。然后我可以使用 openssl 从该文件中提取证书和数据,如下所示:

openssl cms -verify -in signature.p7s -inform DER -noverify -outform DER -signer cert.pem -out textdata

所以我的问题是如何使用 python (pyopenssl) 做同样的事情?

我已经尝试按照描述的方式去做 here,但是有不同的情况 - 我附加了签名但没有单独的签名和证书文件 - 我有 ASN.1 编码文件,其中包含作为数据和签名的证书

要实现您的目标,需要克服几个障碍。

首先,pyopenssl 绑定本身在其 crypto 模块(您需要的功能所在的模块)方面受到限制。事实上,the pyopenssl crypto documentation 指出: 提到的 pyca/cryptography 模块通过 pyopenssl crypto 模块的两个内部属性公开,名称为 _lib_ffi,需要使用它们来获得所需的功能。

那么 CMS_verify() 函数将是您合乎逻辑的选择,它也不包含在 pyca/cryptography 绑定中。但是,为了您的目的,使用 PKCS7_verify() 可能就足够了——您可以在 StackExchange 问题中阅读所有相关内容 OpenSSL PKCS#7 vs. S/MIME. The function crypto.load_pkcs7_data() 派上用场。

综上所述,以下代码片段可能会为您完成——尽管根据您的描述,我不清楚签名者的证书是否包含在 .p7s 文件中(在那种情况下您不必像以前那样将 -signer 作为 openssl cms -verify 的参数)。它对我有用,所以试试看:

from OpenSSL import crypto
from OpenSSL._util import (
    ffi as _ffi,
    lib as _lib,
)

# Or, alternatively:
# from cryptography.hazmat.bindings.openssl.binding import Binding
# _lib = Binding.lib
# _ffi = Binding.ffi

with open('message_der.p7s', 'rb') as f:
    p7data = f.read()
p7 = crypto.load_pkcs7_data(crypto.FILETYPE_ASN1, p7data)

bio_out =crypto._new_mem_buf()
res = _lib.PKCS7_verify(p7._pkcs7, _ffi.NULL, _ffi.NULL, _ffi.NULL, bio_out, _lib.PKCS7_NOVERIFY)
if res == 1:
    databytes = crypto._bio_to_string(bio_out)
    print(databytes)
else:
    errno = _lib.ERR_get_error()
    errstrlib = _ffi.string(_lib.ERR_lib_error_string(errno))
    errstrfunc = _ffi.string(_lib.ERR_func_error_string(errno))
    errstrreason = _ffi.string(_lib.ERR_reason_error_string(errno)) 

如果您决定使用这种方法,这里是 a caveat about using this OpenSSL bindings module directly