pythonpython-3.xpkcs#12python-cryptography

How do/can I generate a PKCS#12 file using python and the cryptography module?


How do/can I generate a PKCS#12 file using python and the cryptography module?

It's pretty easy using said module to generate the contents of .pem file for a private key:

keyPEMBytes = privateKey.private_bytes(
    encoding=serialization.Encoding.PEM,
    format=serialization.PrivateFormat.TraditionalOpenSSL,
    encryption_algorithm=serialization.NoEncryption())

Also easy to generate the contents of a .cer/.pem file for an associated cert:

certBytes = certificate.public_bytes(encoding=serialization.Encoding.PEM)

But I need them (and their chain) balled up on a single .p12 (PKCS12 file). Said module documents how to parse/consume PKCS12 formats, but nothing (that I can find) about how one can generate them.

My understanding of PKI stuff is hit and miss though, so maybe I'm just not searching the right keyword in the documentation?

I can create the .p12 file at the command line on Linux using

openssl pkcs12 -export -out myIdentity.p12 -inkey myPrivKey.pem -in myCert.crt -certfile myCertChain.crt

So I could just wrap calls like this with subprocess/cmd and mess with tempfiles/pipes. I was hoping to keep it all in memory/python though.

Is there a different python TLS library that I should be considering, that can do this?


Solution

  • This use the python module cryptography and generate a p12 file:

    from cryptography import x509
    from cryptography.hazmat.primitives import hashes
    from cryptography.hazmat.primitives.asymmetric import rsa
    from cryptography.hazmat.primitives.serialization import pkcs12, PrivateFormat
    
    common_name = "John Doe"
    password = "secret"
    
    private_key = rsa.generate_private_key(
         public_exponent=65537,
         key_size=4096,
    )
    
    cert = x509.load_pem_x509_certificate("cert.pem")
    
    encryption = (
         PrivateFormat.PKCS12.encryption_builder().
         kdf_rounds(50000).
         key_cert_algorithm(pkcs12.PBES.PBESv1SHA1And3KeyTripleDESCBC).
         hmac_hash(hashes.SHA256()).build(f"{password}".encode())
    )
    
    p12 = pkcs12.serialize_key_and_certificates(
        f"{common_name}".encode(), private_key, cert, None, encryption
    )
    
    
    with open(f"{common_name}.p12", "wb") as p12_file:
        p12_file.write(p12)
    

    You have to use PBESv1SHA1And3KeyTripleDESCBC because the Windows and macOS certificate store only supports 3DES.