Python: reading a pkcs12 certificate with pyOpenSSL.crypto
It's fairly straight-forward to use. This isn't tested, but should work:
# load OpenSSL.cryptofrom 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 objectp12.get_privatekey() # private key.p12.get_ca_certificates() # ca chain.
For more examples, have a look through the unit test code of pyopenssl. Pretty much every way you might want to use the library is there
Maybe is wrong answering to an old Q, but I thought that it may help someone that find this Q after me. This solution work for python 3, and I think is a little bit better. I found it in the repo of zeep and is a class to encapsule the usage.
Class
import osfrom OpenSSL import cryptoclass 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)
Usage
from requests import Sessionfrom zeep import Clientfrom zeep.transports import Transport# https://github.com/mvantellingen/python-zeep/issues/824pkcs12 = PKCS12Manager('cert.p12', 'password_for_cert')session = Session()session.cert = (pkcs12.getCert(), pkcs12.getKey())transport = Transport(session=session)client = Client('url_service', transport=transport)
As pyOpenSSL.crypto.load_pkcs12 is now deprecated, here is the equivalent solution using cryptography, with loading inside a requests Session as a bonus.
from cryptography.hazmat.primitives import serializationfrom requests import Sessionwith 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)