SSL has been around for long enough you'd think that there would be agreed upon container formats. And you're right, there are. Too many standards as it happens. In the end, all of these are different ways to encode Abstract Syntax Notation 1 (ASN.1) formatted data — which happens to be the format x509 certificates are defined in — in machine-readable ways.
- .csr - This is a Certificate Signing Request. Some applications can generate these for submission to certificate-authorities. The actual format is PKCS10 which is defined in RFC 2986. It includes some/all of the key details of the requested certificate such as subject, organization, state, whatnot, as well as the public key of the certificate to get signed. These get signed by the CA and a certificate is returned. The returned certificate is the public certificate (which includes the public key but not the private key), which itself can be in a couple of formats.
- .pem - Defined in RFC 1422 (part of a series from 1421 through 1424) this is a container format that may include just the public certificate (such as with Apache installs, and CA certificate files
/etc/ssl/certs
), or may include an entire certificate chain including public key, private key, and root certificates. Confusingly, it may also encode a CSR (e.g. as used here) as the PKCS10 format can be translated into PEM. The name is from Privacy Enhanced Mail (PEM), a failed method for secure email but the container format it used lives on, and is a base64 translation of the x509 ASN.1 keys.
- .key - This is a (usually) PEM formatted file containing just the private-key of a specific certificate and is merely a conventional name and not a standardized one. In Apache installs, this frequently resides in
/etc/ssl/private
. The rights on these files are very important, and some programs will refuse to load these certificates if they are set wrong.
- .pkcs12 .pfx .p12 - Originally defined by RSA in the Public-Key Cryptography Standards (abbreviated PKCS), the "12" variant was originally enhanced by Microsoft, and later submitted as RFC 7292. This is a password-protected container format that contains both public and private certificate pairs. Unlike .pem files, this container is fully encrypted. Openssl can turn this into a .pem file with both public and private keys:
openssl pkcs12 -in file-to-convert.p12 -out converted-file.pem -nodes
A few other formats that show up from time to time:
- .der - A way to encode ASN.1 syntax in binary, a .pem file is just a Base64 encoded .der file. OpenSSL can convert these to .pem (
openssl x509 -inform der -in to-convert.der -out converted.pem
). Windows sees these as Certificate files. By default, Windows will export certificates as .DER formatted files with a different extension. Like...
- .cert .cer .crt - A .pem (or rarely .der) formatted file with a different extension, one that is recognized by Windows Explorer as a certificate, which .pem is not.
- .p7b .keystore - Defined in RFC 2315 as PKCS number 7, this is a format used by Windows for certificate interchange. Java understands these natively, and often uses
.keystore
as an extension instead. Unlike .pem style certificates, this format has a defined way to include certification-path certificates.
- .crl - A certificate revocation list. Certificate Authorities produce these as a way to de-authorize certificates before expiration. You can sometimes download them from CA websites.
In summary, there are four different ways to present certificates and their components:
- PEM - Governed by RFCs, used preferentially by open-source software because it is text-based and therefore less prone to translation/transmission errors. It can have a variety of extensions (.pem, .key, .cer, .cert, more)
- PKCS7 - An open standard used by Java and supported by Windows. Does not contain private key material.
- PKCS12 - A Microsoft private standard that was later defined in an RFC that provides enhanced security versus the plain-text PEM format. This can contain private key and certificate chain material. Its used preferentially by Windows systems, and can be freely converted to PEM format through use of openssl.
- DER - The parent format of PEM. It's useful to think of it as a binary version of the base64-encoded PEM file. Not routinely used very much outside of Windows.
I hope this helps.
The structure of this IIS7 renewal request is actually quite elegant. It seems to start from the premise that because this is a request to renew a current certificate, it needs to prove that the request is coming from the correct host -- i.e. the host that is actually using the current certificate & ∴ owns the associated private key. In the Internet world, you prove that you are allowed to request renewals for a certificate by authenticating to your CA as the original user, rather than creating a signed CSR.
To prove the right to issue a renewal request, IIS7 creates a normal CSR (PKCS#10 object), and then signs it, and provides the cert of the key that signed it.
- IIS7 renewal CSR
- PKCS#7 Data
- PKCS#10 Data (the ordinary CSR)
- Normal server certificate
- Issuing CA data
- RSA signature (I assume)
Use openssl asn1parse -in iis7rcsr -i
to see the structure of the file, and compare this to normal CSRs. You should see an OCTET STRING near the beginning, in an object labelled ":pkcs7-data", which is what you need to extract to get the CSR.
$ openssl asn1parse -in iis7rcsr -i
0:d=0 hl=4 l=4273 cons: SEQUENCE
4:d=1 hl=2 l= 9 prim: OBJECT :pkcs7-signedData
15:d=1 hl=4 l=4258 cons: cont [ 0 ]
19:d=2 hl=4 l=4254 cons: SEQUENCE
23:d=3 hl=2 l= 1 prim: INTEGER :01
26:d=3 hl=2 l= 11 cons: SET
28:d=4 hl=2 l= 9 cons: SEQUENCE
30:d=5 hl=2 l= 5 prim: OBJECT :sha1
37:d=5 hl=2 l= 0 prim: NULL
39:d=3 hl=4 l=2426 cons: SEQUENCE
43:d=4 hl=2 l= 9 prim: OBJECT :pkcs7-data
54:d=4 hl=4 l=2411 cons: cont [ 0 ]
58:d=5 hl=4 l=2407 prim: OCTET STRING [HEX DUMP]:3082096330820...
In order to get the actual PKCS#10 CSR out of here, we need that offset number, "58" in this example. Then we can use that offset to extract the binary version of that object :-
$ openssl asn1parse -in iis7rcsr -strparse 58 -out thecsr -noout
Next we can read that output file 'thecsr' with openssl req
, remembering to specify the input format DER.
$ openssl req -in thecsr -inform DER -text -noout
Certificate Request:
Data:
Version: 0 (0x0)
Subject: (normal CSR Subject: line, censored)
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
...
I can wrap all this up into one command-line with no temporary files (but sadly 2 reads of the original cert), as long as I can use Linux's /proc/self/fd/
to fool openssl (it will do native tricks with file descriptors for password handling, but not normal output).
$ openssl asn1parse -in iis7rcsr -strparse $(openssl asn1parse -in iis7rcsr | grep -A2 ':pkcs7-data'|tail -1|cut -d: -f1) -out /dev/stdout -noout | openssl req -inform DER -noout -text
Certificate Request:
Data:
Version: 0 (0x0)
Subject: (Subject: line censored again)
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public Key: (1024 bit)
Modulus (1024 bit):
...
This long command line is directly equivalent to the simple openssl req -in non-iis7rcsr -noout -text
that I normally use :-)
Best Answer
I found steps that led to the solution here.
Since the answer is spread out across the question, and the answer, I'll just put exactly what I did below.
Create the key and cert (-nodes creates without password, means no DES encryption [thanks to jewbix.cube for correction])
Create pkcs12 file