OpenSSL tips and tricks
You're probably at least peripherally familiar with OpenSSL as a library that provides SSL capability to internet servers and clients. OpenSSL, however, in addition to providing a library for integration, includes a useful command line tool that can be used for effectively every aspect of SSL/PKI administration. It's a bit under-documented though; this post doesn't aim to fully document it, but I've come across some fairly useful shortcuts that I thought I'd share with you, in "cookbook" style format.
Get help on OpenSSL subcommands
The OpenSSL command-line application is a wrapper application for many
"sub-programs". When you invoke OpenSSL from the command line, you must pass
the name of a sub-program to invoke such as ca
, x509
,
asn1parse
, etc. However, if you want information on these
sub-programs, the OpenSSL man page isn't going to be much help. Instead, each
one has its own man page, so to see the options available for openssl
x509
, type:
$ man x509
See the raw structure of an ASN.1 file
SSL is an implementation of a Public-Key Infrastructure (PKI) and as such,
deals quite a bit with certificates. In fact, it's safe to say that if something goes
wrong with an SSL setup, there's a 90% probability that a misconfigured
certificate will end up being the root cause. Certificates (X.509 certificates,
to be precise) are described in a formal language called "ASN.1" or
Abstract Syntax Notation
(.1). (ASN.1 is somewhat similar, at
least in concept, to XML or JSON). There are quite a few different
sorts of file associated with certificates, and there are no standards on
exactly how they should be named or what extensions they should use. When
presented with a mysterious PKI-related file, viewing the raw structure can
be helpful in determining what exactly you're dealing with or possibly what's
gone wrong with it. However, if you open one up in, say, a text editor, it probably looks something
like:
MIICbDCCAioCAQAwaDELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlRYMQ4wDAYDVQQHEwVQbGFubzER
MA8GA1UEChMIMnhvZmZpY2UxETAPBgNVBAsTCFJlc2VhcmNoMRYwFAYDVQQDEw1Kb3NodWEgRGF2
aWVzMIIBtzCCASwGByqGSM44BAEwggEfAoGBAP1/U4EddRIpUt9KnC7s5Of2EbdSPO9EAMMeP4C2
USZpRV1AIlH7WT2NWPq/xfW6MPbLm1Vs14E7gB00b/JmYLdrmVClpJ+f6AR7ECLCT7up1/63xhv4
O1fnxqimFQ8E+4P208UewwI1VBNaFpEy9nXzrith1yrv8iIDGZ3RSAHHAhUAl2BQjxUjC8yykrmC
ouuEC/BYHPUCgYEA9+GghdabPd7LvKtcNrhXuXmUr7v6OuqC+VdMCz0HgmdRWVeOutRZT+ZxBxCB
gLRJFnEj6EwoFhO3zwkyjMim4TwWeotUfI0o4KOuHiuzpnWRbqN/C/ohNWLx+2J6ASQ7zKTxvqhR
kImog9/hWuWfBpKLZl6Ae1UlZAFMO/7PSSoDgYQAAoGAOPlkQGq47HhKxmGBTDWaLaa140+Rl3b+
rZk3TpODy/BTS6O+v608EEBnJvF6ck26qFjLBHPC8IihovdcczKEAofIiR+do7CMjUEWdWIFnwKX
6W46ElBJN1ieWl1HtGj5RXnSfcfitiRGOiee1jsyV7wVn0Y4/8vbYPAUFRSPpk2gADALBgcqhkjO
OAQDBQADLwAwLAIUFgkt1lvVhcR1JE6wW7pyBAsgA1wCFHcSuOTaZdIM/dKwJ5dOFgsK0zOi
This is clearly Base64 encoded, but Base64 decoding it won't provide you with any useful information; it's a Base64 encoding of the Distinguished Encoding Rule (DER) representation of an ASN.1-formatted file. To parse it more meaningfully, use the asn1parse subcommand:
$ openssl asn1parse -in mysterious_file.pem
0:d=0 hl=4 l= 620 cons: SEQUENCE
4:d=1 hl=4 l= 554 cons: SEQUENCE
8:d=2 hl=2 l= 1 prim: INTEGER :00
11:d=2 hl=2 l= 104 cons: SEQUENCE
13:d=3 hl=2 l= 11 cons: SET
15:d=4 hl=2 l= 9 cons: SEQUENCE
17:d=5 hl=2 l= 3 prim: OBJECT :countryName
22:d=5 hl=2 l= 2 prim: PRINTABLESTRING :US
26:d=3 hl=2 l= 11 cons: SET
28:d=4 hl=2 l= 9 cons: SEQUENCE
30:d=5 hl=2 l= 3 prim: OBJECT :stateOrProvinceName
35:d=5 hl=2 l= 2 prim: PRINTABLESTRING :TX
39:d=3 hl=2 l= 14 cons: SET
41:d=4 hl=2 l= 12 cons: SEQUENCE
43:d=5 hl=2 l= 3 prim: OBJECT :localityName
48:d=5 hl=2 l= 5 prim: PRINTABLESTRING :Plano
55:d=3 hl=2 l= 17 cons: SET
57:d=4 hl=2 l= 15 cons: SEQUENCE
59:d=5 hl=2 l= 3 prim: OBJECT :organizationName
64:d=5 hl=2 l= 8 prim: PRINTABLESTRING :2xoffice
74:d=3 hl=2 l= 17 cons: SET
76:d=4 hl=2 l= 15 cons: SEQUENCE
78:d=5 hl=2 l= 3 prim: OBJECT :organizationalUnitName
83:d=5 hl=2 l= 8 prim: PRINTABLESTRING :Research
93:d=3 hl=2 l= 22 cons: SET
95:d=4 hl=2 l= 20 cons: SEQUENCE
97:d=5 hl=2 l= 3 prim: OBJECT :commonName
102:d=5 hl=2 l= 13 prim: PRINTABLESTRING :Joshua Davies
117:d=2 hl=4 l= 439 cons: SEQUENCE
121:d=3 hl=4 l= 300 cons: SEQUENCE
125:d=4 hl=2 l= 7 prim: OBJECT :dsaEncryption
134:d=4 hl=4 l= 287 cons: SEQUENCE
138:d=5 hl=3 l= 129 prim: INTEGER :FD7F53811D75122952DF4A9C2...
270:d=5 hl=2 l= 21 prim: INTEGER :9760508F15230BCCB292B982A...
293:d=5 hl=3 l= 129 prim: INTEGER :F7E1A085D69B3DDECBBCAB5C3...
425:d=3 hl=3 l= 132 prim: BIT STRING
560:d=2 hl=2 l= 0 cons: cont [ 0 ]
562:d=1 hl=2 l= 11 cons: SEQUENCE
564:d=2 hl=2 l= 7 prim: OBJECT :dsaWithSHA1
573:d=2 hl=2 l= 0 prim: NULL
575:d=1 hl=2 l= 47 prim: BIT STRING
If you have some familiarity with PKI concepts and workflows, you can see
immediately that this is a certificate signing request. More recent versions
of OpenSSL include the -i
parameter to asn1parse
that will indent based on parse depth — this can be useful especially
in longer structures like certificate chains.
Deal with PEM and DER-encoded files
Most of the time, the command above (openssl asn1parse -in file
)
will work with any SSL/PKI related file. However, you might use it as shown
and be presented with the error:
$ openssl asn1parse -in request.der
Error: offset too large
Most likely, this means that you're dealing with a DER-encoded, rather than
PEM-encoded, file. What's the difference? Well, DER is the "raw form" that
SSL itself needs in order to process the certificate correctly; this is what's
actually transferred by the server to the client to authenticate itself. As
you probably know, though, binary files and e-mail don't mix, so files are
usually (but not always) Base64 encoded before being attached to an e-mail.
A Base-64 representation of a DER-encoded certificate or signing request is
called (somewhat illogically) a Privacy Enhanced Mail
or PEM
format. In fact, a common (but not required) convention is to name raw
certificate files with a .der
extension and Base64-encoded files
with a .pem
extension.
The term PEM originates from its first uses as part of Phil Zimmerman's PGP (Pretty Good Privacy) secure e-mail efforts from the 90's which itself was based on an IETF effort to describe an encryption infrastructure for e-mail. Nowadays, we call any Base64 encoded representation of a certificate-related file "PEM-encoded", even though it's not necessarily private.
OpenSSL assumes this Base64 encoding of everything it deals with and
automatically tries to do an in-place Base64 decode before processing its input.
However, if you need to bypass this, specify -inform der
:
$ openssl asn1parse -inform der -in request.der
0:d=0 hl=4 l= 342 cons: SEQUENCE
4:d=1 hl=4 l= 256 cons: SEQUENCE
8:d=2 hl=2 l= 1 prim: INTEGER :00
...
If you try this and you still get an "offset too large" error, you may not be dealing with a certificate file at all, or the file itself may have been corrupted in transit.
View the contents of a certificate
Now, let's say that you've determined that you're dealing with a bona-fide
X.509 certificate, and you've figured out what format it's in.
asn1parse
will give you all the details about the certificate
file; probably more than you were looking for. What you really want is a
summary — what is its validity period and what distinguished name is it
a certificate for?
OpenSSL has a dedicated x509
subcommand for precisely this.
However, If you just type:
$ openssl x509 -in sample.cer
You won't be too impressed by the results:
-----BEGIN CERTIFICATE-----
MIIEszCCA5ugAwIBAgIJAMR0RhX+M2iEMA0GCSqGSIb3DQEBBQUAMIGXMQswCQYD
VQQGEwJVUzELMAkGA1UECBMCVFgxDjAMBgNVBAcTBVBsYW5vMREwDwYDVQQKEwgy
...
qRH8SwcC2/+kLp5/SqpC7Tv1K1466jrxltb4ncJL6Is8p2FDRn1GTLTj3Z086JgX
s9y/DGoyTw==
-----END CERTIFICATE-----
All this does is (fairly uselessly) show you the exact text contents of the certificate, just as if you had typed:
$ cat sample.cer
OpenSSL can display useful bits and pieces of the certificate as well, but you have to pass in the correct command-line attributes to see them. Some of the more useful ones are:
-subject Output the subject name
-issuer Output the issuer name
-dates Output the validity dates of the certificate
However, by default these will all be printed below the dump of the full
text contents of the Base64-encoded certificate file. The useful
-noout
(which, honestly, ought to be the default) suppresses this,
so you just get the information you asked for. If you'd like a summary, which
is a good assumption in most cases, you can pass in the -text
option which displays a readable overview of all of the information in the
certificate:
$ openssl x509 -in sample.cer -noout -text
Certificate:
Data:
Version: 3 (0x2)
Serial Number:
af:69:46:11:10:bd:82:88
Signature Algorithm: sha1WithRSAEncryption
Issuer: C=US, ST=Texas, L=Plano, O=2xoffice, OU=Architecture, CN=Joshua Davies/emailAddress=joshua.davies.tx@gmail.com
Validity
Not Before: May 21 21:49:10 2014 GMT
Not After : Jun 20 21:49:10 2014 GMT
Subject: C=US, ST=Texas, L=Plano, O=2xoffice, OU=Architecture, CN=Joshua Davies/emailAddress=joshua.davies.tx@gmail.com
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public Key: (512 bit)
Modulus (512 bit):
00:b7:38:0d:e0:ab:37:18:a7:26:95:9d:9e:6f:a2:
69:b1:b9:ee:b3:7f:29:04:fb:f0:94:b3:d0:d5:55:
c0:d8:6b:14:7f:94:13:3c:d9:a2:61:bf:ba:3f:0a:
44:37:dc:18:b5:23:c7:ee:96:2d:7c:d8:92:04:48:
74:f8:c6:46:a5
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Key Identifier:
1A:A5:C9:C8:36:EA:7D:FA:B4:DF:A4:9C:11:F9:C1:BE:78:C4:42:DD
X509v3 Authority Key Identifier:
keyid:1A:A5:C9:C8:36:EA:7D:FA:B4:DF:A4:9C:11:F9:C1:BE:78:C4:42:DD
DirName:/C=US/ST=Texas/L=Plano/O=2xoffice/OU=Architecture/CN=Joshua Davies/emailAddress=joshua.davies.tx@gmail.com
serial:AF:69:46:11:10:BD:82:88
X509v3 Basic Constraints:
CA:TRUE
Signature Algorithm: sha1WithRSAEncryption
56:32:44:76:86:8c:08:92:74:71:0e:ac:a6:7d:ba:1d:7c:d3:
b6:74:ef:27:7a:5e:53:21:fc:8e:eb:26:58:e0:6e:4f:5c:01:
f1:40:ca:0a:e9:d2:0e:00:60:ae:1f:f6:a5:a4:4c:47:fb:e0:
68:7f:25:63:ab:60:38:0f:74:94
Create a self-signed test certificate
For production use in a real public-key infrastructure (like the one that the
Internet relies on), a certificate must be signed by a trusted root certificate
authority like Verisign or Thawte. However, these certificates are expensive
and time-consuming to obtain; it's perfectly reasonable to want to be able to
test security out in a closed environment using a "fake" certificate. You
can do this by creating a "self-signed" certificate — one that defines
a public key and then includes a signature using that same public key. Such
a certificate is perfectly valid — a browser can verify its validity
— although it doesn't assert anything useful since anybody can create
one. However, since they're so useful for testing purposes, OpenSSL includes
a shortcut command to create one with the -x509
option to the
req
subcommand.
$ openssl req -x509 -newkey rsa:2048
Generating a 512 bit RSA private key
...++++++++++++
..++++++++++++
writing new private key to 'privkey.pem'
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:
...
The -newkey
option tells OpenSSL that you want it to generate
a private key as well; if you forget it, OpenSSL will hang waiting for you
to input a private key.
This will output the certificate to stdout, which is probably not what you
want; you should provide a -out
parameter as well.
$ openssl req -x509 -newkey rsa:2048 -out selfsign.cer
Also, the private key will go to a file named privkey.pem
,
overwriting any identically-named file that happens to be there (with no
warning!) This can be frustrating, especially if you're already using the
corresponding certificate. So, get in the habit early of always
specifying a private key file:
$ openssl req -x509 -newkey rsa:2048 -out selfsign.cer -keyout selfsign.key
In fact, if you'd like to get SSL up and running for a test Apache2 instance (for testing ONLY!), uncomment the line:
#Include /private/etc/apache2/extra/httpd-ssl.conf
in /etc/apache2/httpd.conf
and run the command:
$ openssl req -x509 -newkey rsa:2048 -out server.crt -keyout server.key
You'll be prompted for a few elements of the subject; the only one that matters is the Common Name; must be "localhost".
Create a certificate request for upload to a certificate authority
Of course, eventually, you're going to need to use a real certificate. If you install a self-signed certificate in a web server, for example, it will sort of work, but the browser will present a dire warning message scaring users away from your site:
Even if the user clicks through the "Proceed Anyway" message, some parts just
won't work at all in some browsers (Chrome won't load
images from your unprotected site if the page was loaded as HTTPS, for example).
This is workable while testing, but for a real site, you need a real
certificate. You can't create a "real" certificate by yourself — you
need to have one signed by a "real" certificate authority. I use
GoDaddy because they're cheap and easy
— but before you can use them, you first need to create a certificate
signing request (CSR). The CSR contains all the information that you
want the end certificate to contain including the public key and the domain
name of the site being protected, but without the signature. You create one
just as you created the self-signed certificate above, but omitting the
-x509
option:
$ openssl req -newkey rsa:2048 -out selfsign.cer -keyout selfsign.key
This command form creates a PKCS #10 file (AKA certificate signing request), which you should upload to the certificate authority. Procedures vary from one CA to the next, but in general they'll let you upload a CSR file to a web form as the first step. The CA will do some verification that you are authorized to create a certificate identifying the site in the first place and when finished, will make a signed certificate available to you. Note that there's nothing sensitive about this certificate — it doesn't contain the private key (you generated that separately when you generated the certificate) and in fact, is a public piece of information that your server will present to every single client that tries to connect using HTTPS.
Remember what I said before about being frustrated when accidentally overwriting your private key file? Well, it's more than frustrating when you generate a CSR, submit it to an expensive CA like Verisign and then accidentally overwrite it. Remember, a private key file cannot be recovered, ever, if lost. If it could, the entire architecture that SSL relies on would be broken. If the private key file is lost or overwritten, the certificate that it goes with is useless. Managing backups is a big part of a server administrators job — managing backups of secure files like private key files is an even bigger part.
Sign a certificate request (as a certificate authority)
In more advanced usage, SSL permits clients to authenticate themselves by presenting certificates, rather than just the server. In this case, the client certificates must be signed by a certificate authority to be trustworthy and, although you can certainly create a request for a commercial certificate authority in this case, you can save quite a bit of money by acting as your own mini certificate authority. OpenSSL provides the tools to do so.
Somewhat by accident, actually. The documentation states that these tools
were never intended to be used as a real certificate authority, but just to
demonstrate that it could be done. From the man page:
"The ca utility was originally meant as an example of how to do things
in a CA. It was not supposed to be used as a full blown CA itself:
nevertheless some people are using it for this purpose."
However, for casual/light use, this works just fine; if you need it to scale
to multiple administrators and certificate revocation, however, you'll need
a more robust certificate management infrastructure.
The first step is to create a self-signed root certificate to act as the certificate authority as shown above. Once this has been done, create a CA configuration file. OpenSSL installs a sample openssl.cnf file in its configuration directory (which varies from one installation to the next). For the most part, especially for testing purposes, you can just use this sample configuration file as is; if you're going to be spending much time dealing with certificates, though, it's worth getting acquainted with exactly what is in this file. Some of the interesting options, at least with regards to certicate authority management, are the location of the serial numbers and the location of the Certificate Revocation List. I won't review all of the options here (and to be honest, there are a few I'm not that familiar with myself), but for the most part you can get away with accepting the defaults, especially for non-production (i.e. test) usage.
However, some of the options in the [ CA_default ]
section
refer to directories and files which, if not present, will cause the CA to
fail, so you must create them before you can sign a CSR. The OpenSSL source
distribution ships with a simple perl utility called CA.pl
that
simplifies this process, but all it's really doing is creating the directory
structure that the default openssl.cnf
expects. The relevant
section is:
mkdir demoCA
mkdir demoCA/certs
mkdir demoCA/crl
mkdir demoCA/newcerts
mkdir demoCA/private
touch demoCA/index.txt
echo "01" | demoCA/crlnumber
This is enough to get a basic sample CA up and running; if you don't like
the directory or filenames, each can be changed in openssl.cnf
.
In particular, you may want to change dir
to something more
meaningful than demoCA
.
Finally, once you have the configuration file and a valid CSR, sign the certificate signing request:
openssl ca -config ca.cnf -in csr.pem -out certificate.pem
The certificate can be sent unsecured to the requester — remember that one of the reasons PKI works is that the security is in the private key, so the CSR and the certificate are not sensitive data.
If you take a look at the generated certificate, you'll notice that there's
a text summary (identical to what openssl x509 -noout -text
would
generate) at the top. This section, included by default, confuses some systems.
You can include the -notext
option to omit this — or just
delete it by hand if you forget (it's not necessary).
So, from start to finish, here are the minimum steps you need to take in order to create your own certificate authority:
- Create the configuration file. The smallest configuration file that will
allow you to sign certificates is:
[ ca ] default_ca = miniCA [ miniCA ] certificate = ./cacert.pem database = ./index.txt private_key = ./cakey.pem new_certs_dir = ./certs default_md = sha1 policy = policy_match serial = ./serial default_days = 365 [policy_match] commonName = supplied
- Create the directory structure:
$ mkdir certs $ touch index.txt $ echo "01" | serial
- Create the root certificate:
$ openssl req -x509 -newkey rsa:2048 -out cacert.pem -keyout cakey.pem Generating a 2048 bit RSA private key ...........+++ .................................................+++ writing new private key to 'cakey.pem' Enter PEM pass phrase: Verifying - Enter PEM pass phrase: ----- You are about to be asked to enter information that will be incorporated into your certificate request. What you are about to enter is what is called a Distinguished Name or a DN. There are quite a few fields but you can leave some blank For some fields there will be a default value, If you enter '.', the field will be left blank. ----- Country Name (2 letter code) [AU]:US State or Province Name (full name) [Some-State]:Texas Locality Name (eg, city) []:Plano Organization Name (eg, company) [Internet Widgits Pty Ltd]:2xoffice Organizational Unit Name (eg, section) []:Architecture Common Name (e.g. server FQDN or YOUR name) []:Certificate Authority Email Address []:joshua.davies.tx@gmail.com
$ chmod 400 cakey.pem
cakey.pem
in this case) will be distributed to the endpoints that will be validating the signed certificates; e.g. the web servers that are configured to request client certificates. - Create a certificate signing request:
$ openssl req -newkey rsa:2048 -out csr.pem -keyout privkey.pem
- Finally, sign the request. Before you do, you may want to take note of
the directory contents of the CA directory, just to get a sense of what
signing a certificate does with regards to the CA directory:
$ ls ca.cnf certs index.txt serial cacert.pem cakey.pem
$ openssl ca -config ca.cnf -in csr.pem -out signed.pem Using configuration from ca.cnf Enter pass phrase for ./cakey.pem: Check that the request matches the signature Signature ok The Subject's Distinguished Name is as follows countryName :PRINTABLE:'US' stateOrProvinceName :PRINTABLE:'Texas' localityName :PRINTABLE:'Plano' organizationName :PRINTABLE:'2xoffice' organizationalUnitName:PRINTABLE:'Architecture' commonName :PRINTABLE:'Joshua Davies' emailAddress :IA5STRING:'joshua.davies.tx@gmail.com' Certificate is to be certified until May 29 14:54:35 2015 GMT (365 days) Sign the certificate? [y/n]:y 1 out of 1 certificate requests certified, commit? [y/n]y Write out database with 1 new entries Data Base Updated
$ ls ca.cnf certs index.txt.attr serial cacert.pem index.txt.old serial.old cakey.pem index.txt signed.pem
index.txt.attr
,index.txt.old
andserial.old
are new, added by theca
command. Also, thecerts
directory now contains a copy of the signed certificate:$ ls certs/ 01.pem
signed.pem
file.
It's also worth noting that the signed certificate's subject is simply:
$ openssl x509 -in signed.pem -noout -subject
subject= /CN=Joshua Davies
This doesn't match the subject of the request:
$ openssl req -in csr.pem -noout -subject
subject=/C=US/ST=Texas/L=Plano/O=2xoffice/OU=Architecture/CN=Joshua Davies/emailAddress=joshua.davies.tx@gmail.com
The reason is the [ policy ]
section of the configuration file;
since I only listed commonName in the policy section, that's the only attribute
that's output. If I wanted to allow the requester to include other attributes,
I'd have to list them individually:
countryName = optional
stateOrProvinceName = optional
The important takeaway here is that the subject of the signed certificate won't necessarily be identical to the subject in the request; only the public key is guaranteed to be propagated forward.
This minimal CA leaves a lot to be desired; in particular, I haven't added any support for certificate revocation. This is meant to be illustrative to make the certificate authority process clearer, not intended for production use. You've been warned.
Sign a certificate with a back-dated start date
One issue I've run into with certificates has to do with time zones; by default,
when a certificate is signed, its notBefore
timestamp is the
time on the server when it was created, in the timezone of the server. I've
run into scenarios where I wasn't able to install a certificate on a server
located on the west coast because it was signed by a certificate authority
located on the east until a few hours had passed. Not life-threatening, but
annoying, and the OpenSSL ca
command allows you to "backdate" a
certificate via:
$ openssl ca -in csr.pem -startdate 140529000000Z
Provide subject information on the command line
If you've been following along, creating test certificates (and maybe even submitting one to a commercial CA!), you've probably gotten a bit tired of typing in the country, state, locality, etc. over and over again. You can pass this information in on the command line; it doesn't save much time since you still have to type it in, but you can take advantage of this to create an automation script:
#!/bin/sh
if [$# -ne 1]
then
echo "Usage: $0 "
exit
fi
openssl req -subj /C=US/ST=Texas/L=Plano/O=2xoffice/OU=Architecture/CN=$1
The codes here (C, ST, L, etc.) are from the X.509 distinguished name
(DN) specification
CN | Common Name |
---|---|
L | Locality (city) |
ST | State (or province) |
O | Organization (for example, company) |
OU | Organizational Unit |
C | Country |
Technically speaking, the only value you must provide for an SSL certificate is the common name (CN), and it must match the server host name. So, you can get away with:
$ openssl req -x509 -newkey rsa:2048 -out server.crt -keyout server.key -subj /CN=localhost
However, I prefer to fill in at least the organization and organizational unit
as documentation in case I ever have to determine what or where I created this
certificate for in the first place. Another non-standard, but widely recognized
attribute is emailAddress
; there's no short form of this one, but
you can type it out as in:
$ openssl req -x509 -newkey rsa:2048 -out server.crt -keyout server.key -subj /CN=localhost/emailAddress=joshua.davies.tx@gmail.com
This email address is strictly informational, but can be handy if it identifies the administrator when the certificate causes problems (such as when it expires).
Check to see if the public key in a certificate matches a private key
Once you start dealing with a reasonable volume of certificates — more than about ten or so, you'll run into issues where you're trying to match a private key with a certificate. You can deal with a lot of this via naming conventions (I include a timestamp in all of my certificate and key names), but you're likely to come across a certificate that came from a source outside your control at some point.
Reconciling these would actually be practically impossible, except for the fact that private
key files (although they strictly don't have to) include the public key that
corresponds to the private key. You can dump the entire structure of a private
key file just as you can the structure of a certificate.
$ openssl rsa -in privkey.pem -noout -text
Enter pass phrase for privkey.pem:
Private-Key: (512 bit)
modulus:
00:b7:ed:99:89:e3:37:fa:28:54:7e:1e:4c:72:1b:
d1:b3:be:d1:99:50:59:83:8e:bf:8a:42:2f:42:fb:
38:2a:d1:3f:31:9e:20:26:7f:2e:c2:02:62:e8:b4:
8d:fc:1b:60:49:b6:78:f6:7d:74:21:56:c7:f5:f9:
53:ae:e3:a9:59
publicExponent: 65537 (0x10001)
privateExponent:
00:9e:98:13:b2:5f:e8:5e:9d:f3:ed:23:b7:0b:15:
8d:c6:8d:9d:31:b3:a4:db:d9:74:b3:84:ca:37:d9:
62:df:17:43:1a:56:21:eb:02:3e:44:04:b1:4c:48:
72:ef:cc:9e:a2:e5:d3:1d:da:57:83:d8:48:ad:e0:
19:8d:ec:55:01
prime1:
00:eb:15:16:7b:3c:69:2b:df:a8:e3:78:98:a4:3b:
c6:99:2e:24:ec:33:c4:52:e1:18:30:1a:06:3e:bf:
98:23:71
prime2:
00:c8:4b:46:90:06:6f:60:70:aa:46:1b:d4:b3:cb:
bb:28:5d:14:f1:60:90:dc:09:c3:fc:7b:8d:92:80:
7f:20:69
exponent1:
00:8d:77:e8:4a:8b:45:43:48:da:6a:e1:75:02:48:
92:b0:36:0b:b4:35:46:ed:15:56:a8:03:d1:44:4b:
aa:73:91
exponent2:
00:9f:b7:87:19:2a:48:7e:3a:d9:4c:f6:bc:72:73:
2f:57:4c:82:7a:c8:6a:3b:4c:7e:40:43:b5:ec:f1:
12:6e:a1
coefficient:
00:88:14:47:88:9a:c1:31:b0:16:74:1a:2d:5d:9e:
17:a9:c8:ef:c4:b4:72:4a:9d:8b:19:ec:c7:b2:4f:
a8:54:eb
There's quite a bit of information in here — the first three entries are the public key (which takes the form of a modulus and a public exponent) and the private key (the private exponent) and then 5 values that represent the components of the private exponent and can be used to speed up private key calculations. Notice that you'll probably be prompted for a password — key files are stored in encrypted form by default. If you open the file in a text editor, you'll see that it starts out like this:
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: DES-EDE3-CBC,DCD8BE451A81F09A
bc6tsFhLlJ9bouUgr6H4F4u8ROSqZBrIABX1/oUlqbESK30Ubjz2ZINCkpuyW6QS
Those entries at the top are a signal to the OpenSSL parser to prompt you for a decryption password. However, encrypted or not, key files should still be treated with the highest level of sensitivity and protected by the OS to the greatest extent possible — a determined adversary can brute force this, given enough time.
If you're trying to match a private key file to a certificate,
though, all you really care about is the modulus — if the modulii match
in the private key and the certificate, the key is the private key for the
certificate. So output the public modulus of the private key:
$ openssl rsa -in privkey.pem -noout -modulus
Enter pass phrase for privkey.pem:
Modulus=B7ED9989E337FA28547E1E4C721BD1B3BED1995059838EBF8A422F42FB382AD13F319E20267F2EC20262E8B48DFC1B6049B678F67D742156C7F5F953AEE3A959
And that of the certificate:
$ openssl x509 -in selfsign.cer -noout -modulus
Modulus=B7ED9989E337FA28547E1E4C721BD1B3BED1995059838EBF8A422F42FB382AD13F319E20267F2EC20262E8B48DFC1B6049B678F67D742156C7F5F953AEE3A959
This works whether you're using RSA or DSA (but... why would you use DSA?)
Extract and output a private key
Certificates and their keys can be bundled in PKCS #12 format — when you
export a
client certificate from a browser, you'll get a PKCS #12 file, for example.
This bundle includes the certificate and the private key in a single list;
it may have an extension like .p12
or .pfx
. You can parse, manage, and
manipulate it with the pkcs12
OpenSSL subcommand. If you just want to dump
the contents of the file on the console, use:
$ openssl pkcs12 -in private.pfx
As with the x509
and rsa
subcommands, by default
this just shows you a base64-encrypted representation of the certificate,
followed by a base64-encrypted representation of the corresponding private key.
Unlike x509
and rsa
, though, there's no
-text
option to summarize the contents of the files. However, the
output appears like this:
MAC verified OK
Bag Attributes
friendlyName: Client Certificate
localKeyID: A3 78 69 B4 A2 12 96 A7
subject=/CN=Joshua Davies/OU=Architecture/O=2xoffice
issuer=/CN=Joshua Davies/OU=Architecture/O=2xoffice
-----BEGIN CERTIFICATE-----
MIIFqTCCBJGgAwIBAgIIcho1mMr1AE0wDQYJKoZIhvcNAQEFBQAwgZYxCzAJBgNV
BAYTAlVTMRMwEQYDVQQKDApBcHBsZSBJbmMuMSwwKgYDVQQLDCNBcHBsZSBXb3Js
ZHdpZGUgRGV2ZWxvcGVyIFJlbGF0aW9uczFEMEIGA1UEAww7QXBwbGUgV29ybGR3
...
vBdHySICRxmp3onOOj86v/+SdRyvHLc6Nl4aP6J/l4lF/IVfni2flWXgB5pPjBx1
f/T4I5bCAqzvQTdfPw==
-----END CERTIFICATE-----
...
The OpenSSL developers made OpenSSL's x509
smart enough to
look for those BEGIN CERTIFICATE
and END CERTIFICATE
markers and parse the certificate in between them, so you can actually do this
if you just want a quick summary of the certificate:
$ openssl pkcs12 -in private.pfx | openssl x509 -noout -text
If you do, you'll be prompted for the password for the .pfx file and then
again for the password for the private key; since there's no reason to output
the private key just to discard it, you can issue the -nokeys
option to omit the prompt:
$ openssl pkcs12 -nokeys -in private.pfx | openssl x509 -noout -text
You can use the same piping trick to output the private key in summary form
(there's even a -nocerts
to omit the certificate if you'd like),
but I can't think of a case where that would actually be useful, since you
already have the certificate that corresponds to the private key.
Modify default parameters
I mentioned above that if you create a certificate request and don't specify
a private key file name, the private key will go to privkey.pem
by default. While that is the default, you can change the default default
by changing the openssl.cnf
file. I mentioned that there's a default one when
I talked about certificate authorities above; this is actually used in
addition to certificate authorities as the principal configuration file for
all OpenSSL usage. It might be a bit tricky to find; it may be under
/etc/pki/tls or /usr/share/ssl, for example.
If you look under the [ req ]
section, for example, you'll find
this entry:
default_keyfile = privkey.pem
As I mentioned above, if you forget to provide the -keyout
attribute when generating self-signed certificates or signing requests,
OpenSSL will overwrite any existing privkey.pem
file that already
may exist. One way to avoid ever allowing this to happen is to remove the
filename completely:
default_keyfile =
Now, if you try to generate a CSR without specifying -keyout
,
you'll get a command line error:
$ openssl req -x509 -newkey rsa:2048 -config openssl.cnf
Generating a 512 bit RSA private key
.++++++++++++
.............++++++++++++
writing new private key to ''
No such file or directory
2995:error:02001002:system library:fopen:No such file or directory:/SourceCache
/OpenSSL098/OpenSSL098-50/src/crypto/bio/bss_file.c:356:fopen('','w')
2995:error:20074002:BIO routines:FILE_CTRL:system lib:/SourceCache/OpenSSL098
/OpenSSL098-50/src/crypto/bio/bss_file.c:358:
Much better than clobbering any existing file that may have been laying around!
Add a comment:
openssl ca -config ca.cnf -in csr.pem -out signed.pem
Using configuration from ca2.cnf
Enter pass phrase for ./cakey.pem:
wrong number of fields on line 1 (looking for field 6, got 1, '' left)
what are the drawbacks from creating a CA and signing like theses steps and your exampled way?
dst.lbl.gov/~boverhof/openssl_certs.html
Error: offset too largeerror for the asn1parse command when the output certificate included the text representation as well.
I needed the -notext option on the openssl ca command.
It's explained in a very detailed way to generate/exploring/verifying self-signed certificate
Found my way to this article while trying to diagnose an error/warning relating to a self-signed certificate I'm using on an in-house development server. It's been a while since I last used the host and now both Firefox and Edge are throwing up an "Error Code: SSL_ERROR_BAD_CERT_DOMAIN"...
After an inevitable search for clues based on the error message, I amended my CSR statement to:-
openssl req -new -addext "subjectAltName = DNS:nc2.{mydomain}.net" -key private-key.pem -out signing_request.csr
Obviously this didn't work... Although it's a bit sketchy on my part, the evidence I'm seeing sort-of points to the fact that maybe I haven't given my CSR the right set of optional parameters to satisfy a heightened bar of requirements being set by e.g. Firefox and Edge.
I don't think it is relevant, but I'm using the Texadactyl CA, "DIYCA", hosted at GitHub, which I've found to be excellent. Thought perhaps you might consider revisiting this with a thought to exploring this new security requirements in a little more detail.
Nice article! Your comment "You won't be too impressed by the results:" with regard about the command "openssl x509 -in sample.cer" was sugar coated. My takeaway was that "It is completely useless command as it doesn't tell you much haha:)"
On a different note could you shed some light on the "self signing process" and what happens under the covers - ie. would be good to get more details on what you meant by the sentence "one that defines a public key and then includes a signature using that same public key" when talking about self signed certificates - does self signing mean you take the public key + some additional info and encrypt it with the private key - and the output of that operation is the self signed cert?
thx!