On a recent project, I was adding certificates and their private keys to a CredHub instance so that Concourse could retrieve them to configure and then deploy a Cloud Foundry foundation that would then use these certificates.
To do this, I ran:
credhub set --name /path/to/certificate --certificate "$(cat certchain.pem)" --private "$(cat privatekey.pem)
However, the CredHub CLI gave me the following error:
The provided key format is not supported. Keys must be PEM-encoded PKCS#1 keys.
I did not immediately know how to fix this because the private keys had been provided to me by a separate team. I could not re-generate them and simply check the “Please give me a PKCS#1 key” option. I also wasn’t sure what the difference is between PKCS#1 keys and whatever format my keys were in.
Thanks to this CredHub error, I now know that my keys were in PKCS#8 format. This blog will show how to convert between PKCS#1 and PKCS#8, and explain the difference.
What are PKCS#1 keys?
PKCS#1 keys are private keys of the form:
-----BEGIN RSA PRIVATE KEY----- <Key Payload> -----END RSA PRIVATE KEY-----
PKCS#8 keys (which the ones I had been provided were) are of the form:
-----BEGIN PRIVATE KEY----- <Key Payload> -----END PRIVATE KEY-----
The difference between these two key representations is that PKCS#1 specifies in its envelope (first and last line of the file) that it was generated using an
RSA cipher, while PKCS#8 specifies the same information inside of the key payload.
As their numbers imply, PKCS#8 was released after PKCS#1 chronologically. Specifying the cipher in its payload instead of directly in the header allowed for flexibility and compatibility that was built upon in later formats, such as PKCS#12.
Converting PKCS#8 to PKCS#1
Now one might think, “Wow, I just need to add
RSA to my PKCS#8 keys’ envelopes and they’ll become PKCS#1 keys??”
PKCS#8 includes the cipher information in its key payload, so a private key in PKCS#8 format has a completely different key payload than the equivalent key in PKCS#1 format. Convert your keys and then look at their differing contents and you will see what I mean.
Converting a PKCS#8 key to a PKCS#1 key is incredibly easy. Simply run:
openssl rsa -in privateKeyPKCS8.pem -out privateKeyPKCS1.pem
Now my previous
credhub set command works and properly sets the certificate and key:
credhub set --name /path/to/certificate --certificate "$(cat certchain.pem)" --private "$(cat privatekeyPKCS1.pem)
Converting PKCS#1 back to PKCS#8:
openssl pkcs8 -topk8 -inform PEM -outform PEM -in privateKeyPKCS1.pem -out privateKeyPKCS8.pem -nocrypt