I'm using openssl to convert an exported *.p12 file into a *.pem file that has a certificate and an encrypted private key.

The P12 file was exported with a password, this is the command that I'm using to generate the PEM file:

openssl pkcs12 -clcerts -in exported.p12 -out both.pem 

When I run that command I provide a PEM passphrase, the contents look like this:

Bag Attributes
    friendlyName: Some Friendly Name: com.example.org
    localKeyID: 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99
    ... other attributes omitted ...
... contents of certificate ...
Bag Attributes
    friendlyName: My Name
    localKeyID: 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99 99
Key Attributes: <No Attributes>
... contents of key ...

After I have that PEM file; I'm trying to load it using Go's crypto/tls and crypto/x509 package, like this:

var block *pem.Block
for {
  block, bytes = pem.Decode(bytes)
  if block.Type == "PRIVATE KEY" || strings.HasSuffix(block.Type, "PRIVATE KEY") {
    bytes, err := x509.DecryptPEMBlock(block, []byte(password))
    if err != nil {
        return nil, err

However that snippet returns the following error:

Error: fromPEMBytes: x509: no DEK-Info header in block

Reading a bit on the DEK-Info header it seems that it should look like this:

Proc-Type: 4,ENCRYPTED
DEK-Info: DES-EDE3-CBC,5B01E932988DC66B

... contents of private key ...

However I can't seem to figure out how to get OpenSSL to add such headers to the PEM file, I'm using the following OpenSSL version:

➜  ~ openssl version
LibreSSL 2.8.3

Am I' missing something obvious?, any help is really appreciated!

1 Answer 1


That's not any version of OpenSSL. LibreSSL is a fork of OpenSSL and has its own version numbering and history that is now separate from OpenSSL, although it continues to use the same external interfaces including the program name. However, the fork started from OpenSSL 1.0.2-something, which is greater than 1.0.0, and in all OpenSSL versions from 1.0.0 in 2010 up pkcs12 (import) writes the privatekey in 'new' (2000!) PKCS8 formats rather than the 'legacy' or 'traditional' formats from about 1990, which is what your software apparently wants.

In OpenSSL you can use the rsa subcommand to write a traditional-format file:

openssl rsa <p8file >oldfile -des3 # or other supported -$cipher

I can't guarantee LibreSSL retained this functionality, but it's worth a try.

FYI the encryption, or more specifically the password-based key derivation, used in traditional-format files is extremely weak. Unless you use a very strong password -- i.e. one strong enough a normal human can't rememeber it -- this file can probably be broken by an adversary who gets their hands on it. That's why PKCS8 is preferable and it was used at the first opportunity for an incompatible change. This has been asked and answered dozens of times on security.SX and/or crypto.SX; if interested searching for EVP_BytesToKey should find you many of them and links to more. (This issue also affects the enc subcommand, possibly excepting version 1.1.1, so you may need to skip over questions about that.)

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .