Like most of my articles, this posting focuses on the script, and assumes you already know the basic technology behind it. In this case, you need to understand how X.509
certificates work, as well as SSL
, and what a Certificate Authority
(CA) is (at least from a technology perspective, if not from the process and security side). You also need to understand HERE documents in the shell, and how (and when) to escape variables and other special shell characters.
I actually run my own Certificate Authority using tinyCA
, which I use to create and manage X.509 certificates and keys for my HTTPS, Secure SMTP, and Open VPN servers. Although I don't lock the Root CA key in a safe, maintain a countersigned chain of custody log, nor did I videotape my key signing ceremony, I do treat it with same concern and circumspection that I apply to my ATM PIN, house keys, and bank account password.
Sometimes I need certificate & key material for purposes where I don't want to use my personal CA key, either because it's not that critical for it to remain secure, it's a one-time/temporary application, or I'm doing it for someone else (like a friend or employer). Usually, this comes about when playing with stunnel or socat, and I need at least one certificate so I can use SSL/TLS for session encryption. So I finally automated the creation of a Certificate Authority and the request and signing of certificates by that CA. I realize this has been done lots of times by lots of people, but I haven't seen one that creates a re-usable (but single-purpose) CA, nor one that is so convenient to use (again, for a single-purpose).
I call this tool mini_ca, and it works like this:
usage: mini_ca <project_name>
There are two parts to the following example. The first one creates the CA, called "tunnels_R_us". The second one uses it to create a single certificate for a user called "first_one".BEGIN EXAMPLE1
( Collapse )
This example actually runs it twice, with the same argument each time. The second time does NOT overwrite the CA certificate, key, or config file, but does re-write the user certificate script. (Not sure if that's a bug or a feature.)
The major deliverables of this step are the CA's signing certificate, "tunnels_R_us-cacert.pem", and the "create_tunnels_R_us_ucer_cert.sh", which will be demo'd in Example2. All the data the new CA needs is in a directory called "tunnels_R_us-ca" in the current directory. You can move this directory around--although you'll have to edit the appropriate path variable in create_tunnels_R_us_user_cert.sh file. It doesn't depend on mini_ca, but it does still depend on openssl, though.
I tried to make the script proof against spaces in the project name, but I suspect it's not (because the OpenSSL config file that gets created probably won't like it), so don't use spaces. Note that you have to set a password for the CA's private key. You gotta remember this password. I couldn't figure out how to override that behaviour Fortunately, it's pretty easy to delete and re-create the CA if you forget it, although if you re-create the CA, all old certificates won't be valid in the new CA.
On some systems I get an error message from openssl that says "unable to write 'random state'". According to the OpenSSL FAQ
, "This message refers to the default seeding file (see previous answer). A possible reason is that no default filename is known because neither RANDFILE nor HOME is set. (Versions up to 0.9.6 used file ".rnd" in the current directory in this case, but this has changed with 0.9.6a.)" I'm ignoring this, because I don't generally have strong security concerns when using this script (really, because I'm lazy and ignorance is bliss). BEGIN EXAMPLE2( Collapse )END EXAMPLE2
Example2 runs the what I call the create user cert script. The script was created in Example1, which put it in the CA directory. In this case, the script name is "create_tunnels_R_us_user_cert.sh". To run it, just give it a unique name for the user for whom you want to create a certificate. It delivers an all-in-one certificate file that contains the user's private key, certificate, and a Diffie Hellman parameters. This example names it "tunnels_R_us-first_one.pem". This file, along with the "tunnels_R_us-cacert.pem" from the first example, are the things most SSL tools (like socat and stunnel) want to have in order to do SSL.
By "user" I don't necessarily mean a person. In fact, this tool wouldn't be a good choice for generated certificates for personal use (i.e. personal identification & authentication or for use in encrypted and signed email). The user is just a way to uniquely ID each certificate generated.
Here's the code. It makes use of the "openssl" utility, part of the OpenSSL library distribution. This script is very ugly, because it auto-generates both an OpenSSL configuration file, and the create_user_cert.sh file. It uses HERE documents to do that, and requires some awkward & confusing escaping in both in order to get the desired results. So it's ugly and ungainly, but otherwise it's pretty simple, because it isn't much more than a wrapper around the previously mentioned openssl command.BEGIN CODE( Collapse )END CODE
As I said, it's very simple: first, it sets up a directory to put the CA files. These include a private directory where the CA's private key will live; a certs directory where (one copy of) the generated certificates will live; the CA cert password (hardcoded to "1234"!!) and does a bit of houskeeping by creating files and setting permissions to make the openssl tool happy. Second, it generates the OpenSSL configuration file. I haven't stopped to fully understand all the settings in the OpenSSL config file or in the creation of the user certificate request, but I know they work for creating SSL certs for Apache web server, stunnel, socat, and OpenVPN. Third, it creates the CA's key and certificate. It creates 2048 bit certificates, which you can change my modifying $CERTBITS, and it makes the valid for 100000 days, which you can change by modifying $CADAYS. Finally, it generates another script that knows how to use the newly created CA to create user certificates.
This autogenerated script is relatively simple as well. It generates a private key and a certificate request for the user, and immediately has the CA key sign the request. It uses the "yes" command to automatically answer "y" when prompted for permission to sign the certificate. Then it generates the the Diffie Helman parameters. Finally, it concatenates the private key, the certificate, and the DH parameters into a single file. It also saves every individual file in the users directory, but you don't really need them anymore once you have the concatenated file.
Both scripts have a shell function called indent defined. Indent inserts one or more tabs at the beginning of each line of standard input it receives, then passes the input along to standard output. I use it to offset the output and error from calls to the openssl tool, so that I can visually distinguish between what openssl says and what my script says.
Now you have a user's concatenated key-cert-dh file that can be authenticated with the CA's certificate. I'm planning future postings that will require this ability.
You can dowload mini_ca here: http://impson.tzo.com/~jdimpson/bin/mini_ca
Some updates, including typo fix, adding link to mini_ca, creation of the "indent" function, parameterization of the certificate key bit length, and removal of prompting from openssl for CA password and permission to sign certificates.