Python:使用pyOpenSSL.crypto读取pkcs12证书

22 投票
3 回答
53095 浏览
提问于 2025-04-16 19:32

我有一个由西班牙机构(FNMT)发的有效证书,我想玩玩这个证书,学习更多相关知识。这个文件的扩展名是 .p12。

我想读取里面的信息(比如名字和姓氏),并检查这个证书是否有效。请问可以用 pyOpenSSL 来做到这一点吗?我想我需要使用 OpenSSL 中的 crypto 模块。有没有人能提供一些帮助或者有用的链接?我试着在这里阅读过:http://packages.python.org/pyOpenSSL/openssl-crypto.html,但信息不多 :-(

3 个回答

3

可能我在回答一个旧问题,但我觉得这个答案可能会对后面看到这个问题的人有帮助。这个解决方案适用于Python 3,我觉得它稍微好一点。我是在zeep的仓库里找到的,这是一个用来封装使用方法的类。

import os
from OpenSSL import crypto

class PKCS12Manager():

    def __init__(self, p12file, passphrase):
        self.p12file = p12file
        self.unlock = passphrase
        self.webservices_dir = ''
        self.keyfile = ''
        self.certfile = ''

        # Get filename without extension
        ext = os.path.splitext(p12file)
        self.filebasename = os.path.basename(ext[0])

        self.createPrivateCertStore()
        self.p12topem()

    def getKey(self):
        return self.keyfile

    def getCert(self):
        return self.certfile

    def createPrivateCertStore(self):
        home = os.path.expanduser('~')
        webservices_dir = os.path.join(home, '.webservices')
        if not os.path.exists(webservices_dir):
            os.mkdir(webservices_dir)
        os.chmod(webservices_dir, 0o700)
        self.webservices_dir = webservices_dir

    def p12topem(self):
        p12 = crypto.load_pkcs12(open(self.p12file, 'rb').read(), bytes(self.unlock, 'utf-8'))

        # PEM formatted private key
        key = crypto.dump_privatekey(crypto.FILETYPE_PEM, p12.get_privatekey())

        self.keyfile = os.path.join(self.webservices_dir, self.filebasename + ".key.pem")
        open(self.keyfile, 'a').close()
        os.chmod(self.keyfile, 0o600)
        with open(self.keyfile, 'wb') as f:
            f.write(key)


        # PEM formatted certificate
        cert = crypto.dump_certificate(crypto.FILETYPE_PEM, p12.get_certificate())

        self.certfile = os.path.join(self.webservices_dir, self.filebasename + ".crt.pem")
        open(self.certfile, 'a').close()
        os.chmod(self.certfile, 0o644)
        with open(self.certfile, 'wb') as f:
            f.write(cert)

用法

from requests import Session
from zeep import Client
from zeep.transports import Transport

# https://github.com/mvantellingen/python-zeep/issues/824
pkcs12 = PKCS12Manager('cert.p12', 'password_for_cert')
session = Session()
session.cert = (pkcs12.getCert(), pkcs12.getKey())

transport = Transport(session=session)
client = Client('url_service', transport=transport)
16

由于pyOpenSSL.crypto.load_pkcs12这个功能已经不再推荐使用,这里提供一个用cryptography库实现的相似解决方案,并且还附带了在requests会话中加载的额外内容。

from cryptography.hazmat.primitives import serialization
from requests import Session

with open("./cert.p12", "rb") as f:
    (
        private_key,
        certificate,
        additional_certificates,
    ) = serialization.pkcs12.load_key_and_certificates(
        f.read(), CLIENT_CERT_KEY.encode()
    )
# key will be available in user readable temporary file for the time of the
# program run (until key and cert get gc'ed)
key = tempfile.NamedTemporaryFile()
cert = tempfile.NamedTemporaryFile()
key.write(
    private_key.private_bytes(
        encoding=serialization.Encoding.PEM,
        format=serialization.PrivateFormat.PKCS8,
        encryption_algorithm=serialization.NoEncryption(),
    )
)
key.flush()
cert.write(
    certificate.public_bytes(serialization.Encoding.PEM),
)
cert.flush()
session = Session()
session.cert = (cert.name, key.name)
48

使用起来相当简单。这段代码虽然没有经过测试,但应该可以正常工作:

# load OpenSSL.crypto
from OpenSSL import crypto

# open it, using password. Supply/read your own from stdin.
p12 = crypto.load_pkcs12(open("/path/to/cert.p12", 'rb').read(), passwd)

# get various properties of said file.
# note these are PyOpenSSL objects, not strings although you
# can convert them to PEM-encoded strings.
p12.get_certificate()     # (signed) certificate object
p12.get_privatekey()      # private key.
p12.get_ca_certificates() # ca chain.

如果想要更多的例子,可以看看 pyopenssl的单元测试代码。几乎所有你可能想用到这个库的方式都在里面。

你还可以查看 这里,或者没有广告的版本 在这里

撰写回答