People often talk about security. There are many different types of security. Personal security. Security theater. Physical security. In this post, we’ll talk about securing communications channels so that others cannot listen in, and so that others cannot connect.
In this article, I’ll talk about using a toolkit, ssl-admin, to create a certificate authority, create self-signed certificates, and use them for both backups (via Bacula) and for a VPN (using OpenVPN). We will not cover the installation/configuration of software other than ssl-admin.
Please note: ssl-admin assumes you are creating SSL certificates for using with OpenVPN. Why? Because it was written by a member of the OpenVPN core developer team, for use by OpenVPN admins. Thus, you’ll be expected, but not required, to supply a copy of your OpenVPN client configuration file during the configuration process.
I’ll be installing ssl-admin 1.0.5 on FreeBSD 8.2 (STABLE) but deploying the certificates to FreeBSD 8.2 and FreeBSD 9.1 clients (but that shouldn’t matter).
Background
I became aware of ssl-admin some time ago, and then stumbled across it again recently. I played with it a bit, generating a CA, certificates, etc, but never deployed anything with it. Today, that will change. I am going to generate certificates for my OpenVPN clients and for my Bacula clients. It just so happens that all of my OpenVPN clients are also Bacula clients. However, the hostnames on the VPN differ from their other hostnames. Thus, I need two certificates for each host, each with a different FQDN (Fully Qualified Domain Name, e.g. myhost.example.org, as opposed to myhost).
Why did the issue of certificate arise? My old certificates expired:
01-Jan 07:42 bacula-main JobId 125950: Start Backup JobId 115950, Job=supernews_basic.2013-01-01_05.55.08_10 01-Jan 07:42 bacula-main JobId 125950: Using Device "Mega" 01-Jan 07:42 bacula-main JobId 125950: Error: tls.c:92 Error with certificate at depth: 0, issuer = /O=CAcert Inc./OU=http://www.CAcert.org/CN=CAcert Class 3 Root, subject = /CN=supernews-vpn.example.org, ERR=10:certificate has expired 01-Jan 07:42 bacula-main JobId 125950: Error: openssl.c:86 Connect failure: ERR=error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed 01-Jan 07:42 bacula-main JobId 125950: Fatal error: TLS negotiation failed with FD at "supernews-vpn.example.org:9102". 01-Jan 07:42 bacula-main JobId 125950: Fatal error: bsock.c:543 Packet size too big from "Client: supernews-fd:supernews-vpn.example.org:9102. Terminating connection. 01-Jan 07:42 bacula-main JobId 125950: Fatal error: No Job status returned from FD. 01-Jan 07:42 bacula-main JobId 125950: Error: Bacula bacula-dir 5.2.12 (12Sep12):
Happy New Year!
Installing ssl-admin
Installing software on FreeBSD is easy:
cd /usr/ports/security/ssl-admin make install clean
Configuration of ssl-admin
If you were to run ssl-admin now, you’d get this message:
# ssl-admin /usr/local/etc/ssl-admin/ssl-admin.conf doesn't exist. Did you copy the sample from /usr/local/etc/ssl-admin/ssl-admin.conf.sample? at /usr/local/bin/ssl-admin line 39.
Yes, you need to create a configuration file first. NOTE: there is a typo in the above. The sample file is ssl-admin.conf.default, not ssl-admin.conf.sample.
The configuration files are stored under /usr/local/etc/ssl-admin. Your first step is to set up ssl-admin.conf:
cd /usr/local/etc/ssl-admin cp ssl-admin.conf.default ssl-admin.conf
Then edit the new ssl-admin.conf file. Here are my values:
## Set default values here. # # The following values can be changed without affecting # your CA key. $ENV{'KEY_SIZE'} = "4096"; $ENV{'KEY_DAYS'} = "3650"; $ENV{'KEY_CN'} = ""; $ENV{'KEY_CRL_LOC'} = "URI:http://CRL_URI"; ## WARNING!!! ## # # Changing the following values has vast consequences. # These values must match what's in your root CA certificate. $ENV{'KEY_COUNTRY'} = "US"; $ENV{'KEY_PROVINCE'} = "PA"; $ENV{'KEY_CITY'} = "Pittsburgh"; $ENV{'KEY_ORG'} = "Data Center"; $ENV{'KEY_EMAIL'} = 'admin@example.org';
NOTE: if you leave $ENV{‘KEY_CRL_LOC’} empty, you will get an error. See the next section for details. Unless you’re creating a CRL distribution point, or have access to one, you can use the default for this field.
KEY_CN can remain blank – unless you want a default used on every start of ssl-admin. I prefer leaving it blank
I am not sure what value should be in there, but do not leave it empty. I left the field unchanged from the default. I also do not know what KEY_CN should be.
You’ll see that I’m running with 4096 bit keys. Perhaps that is gross overkill, and 2046 is plenty good for now. I’m also using the default value of 10-year (3650 days) for certificate validity. That is, they expire in 10 years.
At this point, these are the files you will have:
[dvl@bast:/usr/local/etc/ssl-admin] $ ls openssl.conf openssl.conf.default ssl-admin.conf ssl-admin.conf.default [dvl@bast:/usr/local/etc/ssl-admin] $
Creating your certificate authority
When first running ssl-admin, this is what you should see. The first step is creating your own private CA (Certificate Authority).
# ssl-admin This program will walk you through requesting, signing, organizing and revoking SSL certificates. Looks like this is a new install, installing... You will first need to edit the /usr/local/etc/ssl-admin/ssl-admin.conf default variables. Have you done this? (y/n): y I need the CA credentials. Would you like to create a new CA key and certificate now? (y/n): y Please enter certifcate owner's name or ID. Usual format is first initial-last name (jdoe) or hostname of server which will use this certificate. All lower case, numbers OK. Owner []: TheFreeBSDDiaryCertificateAuthority File names will use TheFreeBSDDiaryCertificateAuthority. ===> Creating private key with 4096 bits and generating request. Do you want to password protect your CA private key? (y/n): y Generating RSA private key, 4096 bit long modulus .................++ .....................++ e is 65537 (0x10001) Enter pass phrase for TheFreeBSDDiaryCertificateAuthority.key: Verifying - Enter pass phrase for TheFreeBSDDiaryCertificateAuthority.key: ===> Self-Signing request. Enter pass phrase for /usr/local/etc/ssl-admin/TheFreeBSDDiaryCertificateAuthority.key: ===> Moving certficate and key to appropriate directory. Creating initial CRL...Using configuration from /usr/local/etc/ssl-admin/openssl.conf Enter pass phrase for /usr/local/etc/ssl-admin/active/ca.key: FAILssl-admin installed Wed Jan 2 20:13:50 UTC 2013 I can't find your OpenVPN client config. Please copy your config to /usr/local/etc/ssl-admin/packages/client.ovpn ===================================================== # SSL-ADMIN # ===================================================== Please enter the menu option from the following list: 1) Update run-time options: Key Duration (days): 3650 Current Serial #: 01 Key Size (bits): 4096 Intermediate CA Signing: NO 2) Create new Certificate Request 3) Sign a Certificate Request 4) Perform a one-step request/sign 5) Revoke a Certificate 6) Renew/Re-sign a past Certificate Request 7) View current Certificate Revokation List 8) View index information for certificate. z) Zip files for end user. dh) Generate Diffie Hellman parameters. CA) Create new Self-Signed CA certificate. S) Create new Signed Server certificate. q) Quit ssl-admin Menu Item:
NOTES
- Line 7 : if you have not done your configuration as described in a previous section, you’re doing it wrong.
- Line 9 : it is prudent to have a pass prhase on your Certificate Authority.
- Line 17 : pick a name. I chose something that will make sense to me.
- Lines 23-24 : the number of periods and the length of this line isn’t important. The length of time to find a suitable private and public key is variable
- lines 26 -27 : first, enter the pass phrase, then enter it again, to make you know what you typed
- line 32 : enter the pass phrase you just entered above on lines 26-27
- line 33 : you can safely ignore that FAIL message above. I have confirmed with the author that it is a spurious message. A ticket has been raised to fix this bug.
- lines 34 -35 : If you are deploying certificates for OpenVPN, you’ll want to supply the configuration file for the clients. As shown above, copy this file to /usr/local/etc/ssl-admin/packages/client.ovpn. If you are not deploying for OpenVPN, you can ignore this step. This file will be required if you want to use option z) Zip files for end user. See the next secction for what I use in my openvpn.conf file.
After running the above step, these are the files you can expect to see:
$ ls active openssl.conf packages revoked ssl-admin.conf.default csr openssl.conf.default prog ssl-admin.conf $ ls active csr packages prog revoked active: ca.crt ca.key csr: packages: ca.crt prog: crl.pem index.txt index.txt.attr install serial revoked:
If you’d like to see the contents of the certificate that you just created, issue this command. I will only show part of the output:
$ openssl x509 -text -in active/ca.crt Certificate: Data: Version: 3 (0x2) Serial Number: 90:7e:94:5b:a0:18:d7:ce Signature Algorithm: md5WithRSAEncryption Issuer: C=US, ST=PA, L=Warrington, O=Data Center, CN=TheFreeBSDDiaryCertificateAuthority/emailAddress=admin@example.org Validity Not Before: Jan 2 20:13:49 2013 GMT Not After : Dec 31 20:13:49 2022 GMT Subject: C=US, ST=PA, L=Pittsburgh, O=Data Center, CN=TheFreeBSDDiaryCertificateAuthority/emailAddress=admin@example.org Subject Public Key Info: Public Key Algorithm: rsaEncryption RSA Public Key: (4096 bit) Modulus (4096 bit): ... ...
In the above output, you can see the various values which I specified in ssl-admin.conf, such as:
- C – $ENV{‘KEY_COUNTRY’} = “US”;
- ST – $ENV{‘KEY_PROVINCE’} = “PA”;
- L – $ENV{‘KEY_CITY’} = “Pittsburgh”;
- O – $ENV{‘KEY_ORG’} = “Data Center”;
- emailAddress – $ENV{‘KEY_EMAIL’} = ‘admin@example.org’;
Sample OpenVPN configuration file
This step is useful only if you are using OpenVPN, or more specifically, if you are going to use these certificates for your OpenVPN network. Otherwise, please skip this step.
Before using ssl-admin, my openvpn.conf file differed from client to client. Specifically, the file names referenced by that file. I will demonstrate.
client dev tun proto udp remote my.openvpn.example.org 1194 resolv-retry infinite nobind user nobody group nobody persist-key persist-tun pull ns-cert-type server tls-auth keys/ta.key 1 ca keys/ca.crt cert keys/client.crt key keys/client.key comp-lzo verb 1
Look at lines 15 and 16. In my previous life as an OpenVPN novice, I would use lines such as:
cert /usr/local/etc/openvpn/keys/supernews.example.org.crt key /usr/local/etc/openvpn/keys/supernews.example.org.key
Why? When the certificates and keys are created, the filename contains the hostname. That’s just the way I did it. I’m pretty sure that’s common. I kept the certificates around just in case I needed them later. However, with ssl-admin, it does this, but then when it zips up the relevant files for distribution to the client, it renames the files to the generic versions. This also means you have just one configuration file; no customization for each client. Unless you need do. I don’t.
In addition, the sample file above uses relative paths. On FreeBSD, the openvpn.conf file is located at /usr/local/etc/openvpn. Thus, I have removed that part of the path from the filenames because the FreeBSD port adds the –cd option to the startup.
This is the file that I placed at /usr/local/etc/ssl-admin/packages/client.ovpn as you will see in the examples below. You can do this at any time. The file is used only for the zip process (which is explained later).
Creating a client certificate
In this section, I will create a certificate for one OpenVPN client. I will create the certificate for the server later; it requires a different process.
The first thing to realize is that you have already created your CA (Certificate Authority). It has a certificate and a key. You now want to create a certificate for the OpenVPN server. Thus, you need to change the Common Name (listed as CN above in the certificate extract). Thus, you want to specify option 1.
Starting off from where we were at the end of the last step:
Menu Item: 4 Please enter certificate owner's name or ID. Usual format is first initial-last name (jdoe) or hostname of server which will use this certificate. All lower case, numbers OK. Owner [TheFreeBSDDiaryCertificateAuthority]: supernews.example.org File names will use supernews.example.org. Please enter certificate owner's name or ID. Usual format is first initial-last name (jdoe) or hostname of server which will use this certificate. All lower case, numbers OK. Owner [supernews.example.org]: Would you like to password protect the private key (y/n): n Generating a 4096 bit RSA private key .......................................................................................................................................................................++ ..........................++ writing new private key to 'supernews.example.org.key' ----- ===> Serial Number = 01 =========> Signing request for supernews.example.org Using configuration from /usr/local/etc/ssl-admin/openssl.conf Enter pass phrase for /usr/local/etc/ssl-admin/active/ca.key: Check that the request matches the signature Signature ok The Subject's Distinguished Name is as follows countryName :PRINTABLE:'US' stateOrProvinceName :PRINTABLE:'PA' localityName :PRINTABLE:'Pitsburgh' organizationName :PRINTABLE:'Data Center' commonName :PRINTABLE:'supernews.example.org' emailAddress :IA5STRING:'admin@example.org' Certificate is to be certified until Dec 31 20:47:58 2022 GMT (3650 days) Write out database with 1 new entries Data Base Updated =========> Moving certificates and keys to /usr/local/etc/ssl-admin/active for production. Can I move signing request (supernews.example.org.csr) to the csr directory for archiving? (y/n): ===> supernews.example.org.csr moved. ===================================================== # SSL-ADMIN # ===================================================== Please enter the menu option from the following list: 1) Update run-time options: Key Duration (days): 3650 Current Serial #: 02 Key Size (bits): Intermediate CA Signing: NO 2) Create new Certificate Request 3) Sign a Certificate Request 4) Perform a one-step request/sign 5) Revoke a Certificate 6) Renew/Re-sign a past Certificate Request 7) View current Certificate Revokation List 8) View index information for certificate. z) Zip files for end user. dh) Generate Diffie Hellman parameters. CA) Create new Self-Signed CA certificate. S) Create new Signed Server certificate. q) Quit ssl-admin Menu Item:
NOTE: If you use option 4, the signing request question (on line 39) is automatically answered for you, with Y.
Now that we have the certificate, let’s zip it up for distribution.
Menu Item: z Please enter certificate owner's name or ID. Usual format is first initial-last name (jdoe) or hostname of server which will use this certificate. All lower case, numbers OK. Owner [supernews.example.org]: =========> Creating .zip file for supernews.example.org in /usr/local/etc/ssl-admin/packages =================> Moving supernews.example.org.crt =================> Moving supernews.example.org.key Is this certificate for an OpenVPN client install? (y/n): y =================> Zipping File updating: client.crt (deflated 45%) updating: client.key (deflated 24%) updating: ca.crt (deflated 32%) adding: client.ovpn (deflated 49%) =================> Cleaning up files: client.crt, client.key. You may distribute /usr/local/etc/ssl-admin/packages/supernews.example.org.zip to the end user.
Those files should be copied to your server. Where they go, and how you install them is outside the scope of this article. Really. If you’re reading this post, you should also be reading something on configuring OpenVPN.
The zip file will be created in the packages subdirectory.
Updating your client
Here is how I updated the supernews client:
cd /usr/local/etc/ssl-admin/packages scp supernews.example.org.zip supernews:
There, the zip file is on the client. Now, let me ssh to the client. Here is what I did on the client:
$ su # cd /usr/local/etc/openvpn/keys unzip ~dvl/supernews.example.org.zip Archive: /home/dan/supernews.example.org.zip inflating: client.crt inflating: client.key inflating: ca.crt inflating: client.ovpn # mv client.ovpn ../openvpn.conf
Creating the server certificate
Don’t do my mistake and create the same type of certificate for both client and server. The server certificate must be created differently. If you do not, your client will not be able to connect. See the next section for details on that.
Here is how I created the server certificate.
Menu Item: S Please enter certificate owner's name or ID. Usual format is first initial-last name (jdoe) or hostname of server which will use this certificate. All lower case, numbers OK. Owner [latens.example.org]: bast.example.org File names will use bast.example.org. Please enter certificate owner's name or ID. Usual format is first initial-last name (jdoe) or hostname of server which will use this certificate. All lower case, numbers OK. Owner [bast.example.org]: Would you like to password protect the private key (y/n): n Generating a 4096 bit RSA private key ............................................................++ .......................................................................................................................++ writing new private key to 'bast.example.org.key' ----- ===> Serial Number = 07 Using configuration from /usr/local/etc/ssl-admin/openssl.conf Enter pass phrase for /usr/local/etc/ssl-admin/active/ca.key: Check that the request matches the signature Signature ok The Subject's Distinguished Name is as follows countryName :PRINTABLE:'US' stateOrProvinceName :PRINTABLE:'PA' localityName :PRINTABLE:'Pittsburgh' organizationName :PRINTABLE:'Data Center' commonName :PRINTABLE:'bast.example.org' emailAddress :IA5STRING:'admin@example.org' Certificate is to be certified until Jan 1 01:22:24 2023 GMT (3650 days) Write out database with 1 new entries Data Base Updated =========> Moving certificates and keys to /usr/local/etc/ssl-admin/active for production. Can I move signing request (bast.example.org.csr) to the csr directory for archiving? (y/n): y ===> bast.example.org.csr moved. ===================================================== # SSL-ADMIN # ===================================================== Please enter the menu option from the following list: 1) Update run-time options: Key Duration (days): 3650 Current Serial #: 08 Key Size (bits): 4096 Intermediate CA Signing: NO 2) Create new Certificate Request 3) Sign a Certificate Request 4) Perform a one-step request/sign 5) Revoke a Certificate 6) Renew/Re-sign a past Certificate Request 7) View current Certificate Revokation List 8) View index information for certificate. z) Zip files for end user. dh) Generate Diffie Hellman parameters. CA) Create new Self-Signed CA certificate. S) Create new Signed Server certificate. q) Quit ssl-admin Menu Item: z Please enter certificate owner's name or ID. Usual format is first initial-last name (jdoe) or hostname of server which will use this certificate. All lower case, numbers OK. Owner [bast.example.org]: =========> Creating .zip file for bast.example.org in /usr/local/etc/ssl-admin/packages =================> Moving bast.example.org.crt =================> Moving bast.example.org.key Is this certificate for an OpenVPN client install? (y/n): n =================> Zipping File updating: client.crt (deflated 46%) updating: client.key (deflated 24%) updating: ca.crt (deflated 32%) =================> Cleaning up files: client.crt, client.key. You may distribute /usr/local/etc/ssl-admin/packages/bast.example.org.zip to the end user.
Updating your server
Distributing the server zip file is pretty much the same as the client certificate. Follow the same steps as above. However, there is one more file you need to deploy. See crl.pem in the section below. However, for the main files, here is what I did:
$ su # cd /usr/local/etc/openvpn/keys unzip ~dvl/bast.example.org.zip Archive: /home/dan/bast.example.org.zip inflating: client.crt inflating: client.key inflating: ca.crt
NOTE that the configuration on the server is different. You do not want to deploy that file over to the server.
crl.pem
You’ll find this file in the prog subdirectory. On my client, that needs to go to /usr/local/etc/openvpn/keys. This is the Certificate Revocation List. This is the list of revoked certificates. You maintain that list using the 5) Revoke a Certificate option. When you use that menu item, be sure to redeploy that file.
Restarting the VPN
After you have deployed both the client and the server files, it is time to restart OpenVPN on both machines. My server started up just fine. But the client refused to connect. See below for the message.
Client canot connect
When I first started my client, I got these errors:
Jan 3 01:00:02 latens openvpn[72481]: TLS_ERROR: BIO read tls_read_plaintext error: error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed Jan 3 01:00:02 latens openvpn[72481]: TLS Error: TLS object -> incoming plaintext read error Jan 3 01:00:02 latens openvpn[72481]: TLS Error: TLS handshake failed
I spent a lot of time, checking the certificates, verifying them, etc. Eventually, it was suggested on the OpenVPN IRC channel that I bump up the verb setting on the client configuration file. I set it to 5, restarted OpenVPN, and then I saw these errors:
Jan 3 01:18:53 latens openvpn[73944]: TLS: Initial packet from 71.162.210.170:1194, sid=3cc2df32 1fa8a55b Jan 3 01:18:57 latens openvpn[73944]: VERIFY OK: depth=1, /C=US/ST=PA/L=Pittsburgh/O=Data_Center/CN=TheFreeBSDDiaryCertificateAuthority/emailAddress=admin@example.org Jan 3 01:18:57 latens openvpn[73944]: VERIFY nsCertType ERROR: /C=US/ST=PA/O=Data Center/CN=bast.example.org/emailAddress=admin@example.org, require nsCertType=SERVER Jan 3 01:18:57 latens openvpn[73944]: TLS_ERROR: BIO read tls_read_plaintext error: error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed Jan 3 01:18:57 latens openvpn[73944]: TLS Error: TLS object -> incoming plaintext read error Jan 3 01:18:57 latens openvpn[73944]: TLS Error: TLS handshake failed
Oh oh! There it is: require nsCertType=SERVER
DOH! Yes, then it was clear. Then I went back in and used the S) Create new Signed Server certificate. option. I revoked the original server certificate and then redeployed the files to the server. Restarting the server and all was well!
Cryptic Error Messages
If you encounter an error message similar to this when running ssl-admin, your $ENV{‘KEY_CRL_LOC’} setting in the ssl-admin.conf file is probably empty. Instead, set it to the default value: “URI:http://CRL_URI”.
Error Loading extension section v3_ca 23970:error:2206D06C:X509 V3 routines:X509V3_parse_list:invalid null name:/usr/src/secure/lib/libcrypto/../../../crypto/openssl/crypto/x509v3/v3_utl.c:326: 23970:error:22097069:X509 V3 routines:DO_EXT_NCONF:invalid extension string:/usr/src/secure/lib/libcrypto/../../../crypto/openssl/crypto/x509v3/v3_conf.c:139:name=crlDistributionPoints,section= 23970:error:22098080:X509 V3 routines:X509V3_EXT_nconf:error in extension:/usr/src/secure/lib/libcrypto/../../../crypto/openssl/crypto/x509v3/v3_conf.c:93:name=crlDistributionPoints, value= OpenSSL exited with errors. Please read above and address the problems indicated. at /usr/local/bin/ssl-admin line 195, <> line 4.
If you see these errors message, your country field is too long. It can only be two characters.
string is too long, it needs to be less than 2 bytes long string is too long, it needs to be less than 2 bytes long string is too long, it needs to be less than 2 bytes long string is too long, it needs to be less than 2 bytes long string is too long, it needs to be less than 2 bytes long string is too long, it needs to be less than 2 bytes long string is too long, it needs to be less than 2 bytes long string is too long, it needs to be less than 2 bytes long ...
Using it for more than OpenVPN
I will be using ssl-admin for more than just OpenVPN. I have a bunch of non-public certificates that I want to refresh. Specifically, the certificates I use for Bacula backups. I’ll start in on that process very soon now.