311

I have OpenSSL x64 on Windows 7 which I downloaded from openssl-for-windows on Google Code. I'm attempting to run:

openssl pkcs12 -export -in "path.p12" -out "newfile.pem" 

but I get an error.

unable to load private key

How do I extract the certificate in PEM from PKCS#12 store using OpenSSL?

Benoit Duffez
  • 11,839
  • 12
  • 77
  • 125
Dean MacGregor
  • 11,847
  • 9
  • 34
  • 72
  • @jww I think given that this question is over 3 years old that it is a bit late to signal the off-topic flag. – Dean MacGregor Nov 27 '16 at 23:11
  • Just a formality so folks know its off-topic. People are asking the same off-topic questions, and citing this question. If folks are not told its off-topic, then they will continue to ask on Stack Overflow. – jww Nov 27 '16 at 23:26
  • 4
    @jww the highest voted answer on the meta question you link says "DevOps questions should be allowed on Stack Overflow." I will upvote, because the answer met my needs (although, for me, I wasn't programming, I could easily incorporate the answer in a program if I wished) – dcorking Feb 28 '17 at 14:41

6 Answers6

765

Try:

openssl pkcs12 -in path.p12 -out newfile.crt.pem -clcerts -nokeys
openssl pkcs12 -in path.p12 -out newfile.key.pem -nocerts -nodes

After that you have:

  • certificate in newfile.crt.pem
  • private key in newfile.key.pem

To put the certificate and key in the same file without a password, use the following, as an empty password will cause the key to not be exported:

openssl pkcs12 -in path.p12 -out newfile.pem -nodes

Or, if you want to provide a password for the private key, omit -nodes and input a password:

openssl pkcs12 -in path.p12 -out newfile.pem

If you need to input the PKCS#12 password directly from the command line (e.g. a script), just add -passin pass:${PASSWORD}:

openssl pkcs12 -in path.p12 -out newfile.crt.pem -clcerts -nokeys -passin 'pass:P@s5w0rD'
nickdnk
  • 4,010
  • 4
  • 24
  • 43
kmx
  • 7,912
  • 1
  • 15
  • 9
25

You just need to supply a password. You can do it within the same command line with the following syntax:

openssl pkcs12 -export -in "path.p12" -out "newfile.pem" -passin pass:[password]

You will then be prompted for a password to encrypt the private key in your output file. Include the "nodes" option in the line above if you want to export the private key unencrypted (plaintext):

openssl pkcs12 -export -in "path.p12" -out "newfile.pem" -passin pass:[password] -nodes

More info: http://www.openssl.org/docs/apps/pkcs12.html

Colin
  • 251
  • 3
  • 2
19

If you can use Python, it is even easier if you have the pyopenssl module. Here it is:

from OpenSSL import crypto

# May require "" for empty password depending on version

with open("push.p12", "rb") as file:
    p12 = crypto.load_pkcs12(file.read(), "my_passphrase")

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

# PEM formatted certificate
print crypto.dump_certificate(crypto.FILETYPE_PEM, p12.get_certificate())
Géry Ogam
  • 6,336
  • 4
  • 38
  • 67
KVISH
  • 12,923
  • 17
  • 86
  • 162
  • Is there any reason to open the file using `file` and not `open`? I just want to understand it as I am going to use it in future (to simplify my solution calling openssh as command) – Jan Vlcinsky May 08 '14 at 21:40
  • Nope, no difference. You can just do `open("push.p12", 'rb').read()`. – KVISH May 09 '14 at 00:03
  • 3
    If using python 3 you'll probably want to write the contents to files: ```with open("push.pem", "wb") as fobj: fobj.write(crypto.dump_certificate(crypto.FILETYPE_PEM, p12.get_certificate()))``` to write the cert and ```with open("push.key", "wb") as fobj: fobj.write(crypto.dump_privatekey(crypto.FILETYPE_PEM, p12.get_privatekey()))``` for the key. – Adam Parkin Jun 18 '18 at 18:55
  • I'm using python 3.7, when running the above example, I get the following: "TypeError: initializer for ctype 'char' must be a bytes of length 1, not str" Is there something wrong with my password – getaglow Nov 29 '18 at 15:29
  • Why is it "even easier" to create a file, enter the code, save it, and run it -- rather than just executing a single command? – Torben Gundtofte-Bruun Jul 02 '19 at 11:57
  • You can automate with a script. – KVISH Jul 02 '19 at 19:06
  • So, updated code will be: `from OpenSSL import crypto # May require "" for empty password depending on version with open("push.p12", "rb") as file: p12 = crypto.load_pkcs12(file.read(), "my_passphrase") with open("push.pem", "wb") as fobj: fobj.write(crypto.dump_certificate(crypto.FILETYPE_PEM, p12.get_certificate())) with open("push.key", "wb") as fobj: fobj.write(crypto.dump_privatekey(crypto.FILETYPE_PEM, p12.get_privatekey())) ` – Googr Aug 15 '22 at 10:30
  • Please submit an edit to the answer. Pasting code into comments doesn't really work. – Matthias Urlichs Dec 29 '22 at 12:35
12

There is a free and open-source GUI tool KeyStore Explorer to work with crypto key containers. Using it you can export a certificate or private key into separate files or convert the container into another format (jks, pem, p12, pkcs12, etc)

enter image description here

Sergey Nemchinov
  • 1,348
  • 15
  • 21
4

I had a PFX file and needed to create KEY file for NGINX, so I did this:

openssl pkcs12 -in file.pfx -out file.key -nocerts -nodes

Then I had to edit the KEY file and remove all content up to -----BEGIN PRIVATE KEY-----. After that NGINX accepted the KEY file.

KTCO
  • 2,115
  • 23
  • 21
3
#!/usr/bin/env python3
from optparse import Option
from OpenSSL import crypto
import os
import warnings
from getpass import getpass
warnings.filterwarnings("ignore", category=DeprecationWarning) 

def sanitize_path(path):
    return os.path.expandvars(os.path.expanduser(path))

def main(in_file, out_file, passphrase=None):
    if not passphrase:
        passphrase = getpass(prompt=("SSL Private Key Passphrase: "))
   
    in_file = sanitize_path(in_file)
    out_file = sanitize_path(out_file)
    
    with open(in_file, "rb") as input_file:
        p12 = crypto.load_pkcs12(input_file.read(), passphrase)
        pem = crypto.dump_privatekey(crypto.FILETYPE_PEM, p12.get_privatekey())
    with open(out_file, "w") as output_file:
        output_file.write(pem.decode('utf-8'))

if __name__ == '__main__':
    from optparse import OptionParser
    usage = "usage: %prog  input_file output_file [passphrase]"
    p = OptionParser(usage=usage)
    opt, args = p.parse_args()
    main(*args)