【问题标题】:Python: reading a pkcs12 certificate with pyOpenSSL.cryptoPython:使用 pyOpenSSL.crypto 读取 pkcs12 证书
【发布时间】:2011-09-14 19:18:36
【问题描述】:

我有西班牙当局 (FNMT) 颁发的有效证书,我想使用它来了解更多信息。 该文件的扩展名为 .p12

我想阅读其中的信息(名字和姓氏)并检查证书是否有效。是否可以使用 pyOpenSSL 做到这一点?我想我必须在 OpenSSL 中使用加密模块。 任何帮助或有用的链接?尝试在这里阅读:http://packages.python.org/pyOpenSSL/openssl-crypto.html 但信息不多:-(

【问题讨论】:

    标签: python cryptography openssl digital-certificate pyopenssl


    【解决方案1】:

    由于 pyOpenSSL.crypto.load_pkcs12 现在已被弃用,这里是使用加密的等效解决方案,在请求会话中加载作为奖励。

    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)
    

    【讨论】:

    • 这行得通,我只需要添加方法的手动导入(import cryptography.hazmat.primitives.serialization.pkcs12),否则我会收到属性错误(AttributeError: module 'cryptography.hazmat.primitives.serialization' has no attribute 'pkcs12'
    【解决方案2】:

    也许回答一个旧的 Q 是错误的,但我认为它可能会帮助那些在我之后找到这个 Q 的人。这个解决方案适用于 python 3,我认为更好一点。我在the repo of 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)
    

    【讨论】:

      【解决方案3】:

      使用起来相当简单。这未经测试,但应该可以工作:

      # 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.
      

      如需更多示例,请查看unit test code of pyopenssl。几乎所有您可能想要使用该库的方式都在那里

      另见here 或无广告here

      【讨论】:

      • 抱歉,我没有看到带有 Adblock 的广告... 已编辑。
      • 这总是打印无。 get_certificate、get_privatekey 等始终返回 None。它对任何人都有效吗?
      • python3解决方案怎么样?我在使用 load_pkcs12 时遇到问题,因为现在没有文件命令,而且我用 open() 尝试过的任何操作都会给我带来很多错误。 :( 尝试时:p12 = load_pkcs12(open('foo.p12', 'rb').read(), passwd) 我收到:OpenSSL.crypto.Error: [('asn1 encoding routines', 'ASN1_get_object', 'header too long')]
      • @Stan - 你确定你的 .p12 文件格式正确吗?尝试用 openssl 工具打开它:openssl pkcs12 -noout -info -in foo.p12 看看你得到了什么输出。
      猜你喜欢
      • 2013-06-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-11-11
      • 1970-01-01
      • 1970-01-01
      • 2014-09-08
      相关资源
      最近更新 更多