Creating a self-signed SSL certificate


To Whom It May Concern: This page is blatantly kyped from its originating location strictly to make sure it doesn't disapear off the web. I have found that these instructions work, and don't care to have to deal with drudging through all the other howto's to find another that does. With the exception of this note, the entire document is "as found" with all accredations still in place.


Following is a step-by-step guide to creating a self-signed server certificate with openssl on linux. Solaris 2.10 issues are discussed briefly as well. Some of the finer points will vary based on your linux distribution, but this document will explain what goes on at each step. Making a self-signed certificate will cause the client browser to prompt with a message whether you want to trust the certificate signing authority (yourself). But it'll save you a few hundred dollars that would otherwise go to a recognized signing authority. The message "web site certified by an unknown authority... accept?" may be a business liability for general public usage (although it's easy enough for a client to accept the certificate permanently). In that case, you may find yourself spending the money to have a widely recognized signing authority do this instead: paying for name recognition. But if you're on a budget, have a special need or small audience, signing it yourself might make sense.

Note that these instructions create a Certificate Authority (CA). It's possible to one time self-sign a certificate without going through that trouble (no CA is involved). But making your own CA allows you to sign multiple server certificates using the same CA.

Note also that web browsers will prompt whether you want to trust your homemade Certificate Authority for a particular session, permanently, or whether to reject it. Permanently accepting the CA will cause it to be stored by your browser, and you'll not be continually prompted with the "accept?" prompt for server keys signed by it.

Before you start
You need Apache, openssl and mod_ssl. This document requires that they are all installed. Read their individual manuals on installation/compilation procedures, or go with a mainstream linux distro which will do all of the preliminary work for you.


Some idiosyncrasies between linux distros (and Solaris)
There may be some additional things to be aware of before you start working with the steps in this document. Checking this section first might save you some time.


(1) Generate your own Certificate Authority (CA).

su to root. Create a working directory (for example, mkdir certwork) that only root has access to. Go to that directory.

This is where you take the place of VeriSign, Thawte, etc. You'll first build the CA key, then build the certificate itself.

It's been noted that the Common Name (CN), Organization (O) and Organizational Unit (OU) of the CA and the Server certificates should not match. In this step, you'll provide the CA entries. In step 2, you'll provide the Server entries. In this example, I just added "CA" to the CA fields. Use whatever schema you want, just make sure the CA and Server entries do not correspond.

CA:
Common Name (CN): www.somesite.edu CA
Organization (O): Somesite CA
Organizational Unit (OU): Development CA

Server:
Common Name (CN): www.somesite.edu
Organization (O): Somesite
Organizational Unit (OU): Development

For Common Name, you can use the IP instead of the fully qualified domain name. But, again, make sure that something differentiates the entry of the CA's CN from the Server's CN.

openssl genrsa -des3 -out ca.key 4096
openssl req -new -x509 -days 365 -key ca.key -out ca.crt

(2) Generate a server key and request for signing (csr).

This step creates an unsigned server key, and a request that you want it signed (the .csr file) by a Certificate Authority (the one you just created in Step #2.)

Think carefully when inputting a Common Name (CN) as you generate the .csr file below. This should match the DNS name, or the IP address you specify in the httpd.conf or ssl.conf (if this portion is separated outside of httpd.conf) for your server. If they don't match, client browsers will get a "domain mismatch" message when going to your https web server. If you're doing this for home use, and you don't have a static IP or DNS name, you might not even want worry about the message (but you sure will need to worry if this is a production/public server). For example, you could match it to an internal and static IP you use behind your router, so that you'll never get the "domain mismatch" message if you're accessing the computer on your home LAN, but will always get that message when accessing it elsewhere. Your call -- is your IP stable, do you want to repeat these steps every time your IP changes, do you have a DNS name, do you mainly use it inside your home or LAN, or outside?

openssl genrsa -des3 -out server.key 4096
openssl req -new -key server.key -out server.csr

(3) Sign the certificate signing request (csr) with the self-created certificate authority (CA) that you made earlier.

Note that I use 365 days here. After a year you'll need to do this again.

Note also that I set the serial number of the signed server certificate to "01". Each time you do this, especially if you do this before a previously-signed certificate expires, you'll need to change the serial key to something else -- otherwise everyone who's visited your site with a cached version of your certificate will get a warning message to the effect that your certificate signing authority has screwed up -- they've signed a new key/request, but kept the old serial number.

The command below does a number of things. It takes your signing request (csr) and makes a one-year valid signed server certificate (crt) out of it. In doing so, we need to tell it which certificate authority (ca) to use, which ca key to use, and which server key to sign. We set the serial number to 01, and output the signed key in the file named server.crt. If you do this again after people have visited your site and trusted your CA (storing it in their browser), you might want to use 02 for the next serial number, and so on.

openssl x509 -req -days 365 -in server.csr -CA ca.crt -CAkey ca.key -set_serial 01 -out server.crt

Note that for earlier versions of openssl you may not have the "-set_serial" flag available. In this case, openssl needs to read the serial number from a file called, by default, ca.srl. So if you run the long command string above and get an error like this:

ca.srl: No such file or directory
23526:error:02001002:system library:fopen:No such file or directory:bss_file.c:245:fopen('ca.srl','r')
23526:error:20074002:BIO routines:FILE_CTRL:system lib:bss_file.c:247:

Then you need to create a little file named (by default) ca.srl. Put in whatever value you want for the new serial number. For example:

echo "01" >ca.srl

Then issue this command instead of the previous. This one lacks the -set_serial flag and instead reads it from your ca.srl file:

openssl x509 -req -days 365 -in server.csr -CA ca.crt -CAkey ca.key -out server.crt

To examine the components if you're curious:

openssl rsa -noout -text -in server.key
openssl req -noout -text -in server.csr
openssl rsa -noout -text -in ca.key
openssl x509 -noout -text -in ca.crt

(4) Make a server.key which doesn't cause apache to prompt for a password.

Here we create an insecure version of the server.key. The insecure one will be used for when Apache starts, and will not require a password with every restart of the web server. But keep in mind that while this means you don't have to type in a password when restarting Apache (or worse -- coding it somewhere in plaintext), it does mean that anyone obtaining this insecure key will be able to decrypt your transmissions. Guard it for permissions VERY carefully.

openssl rsa -in server.key -out server.key.insecure
mv server.key server.key.secure
mv server.key.insecure server.key

(5) Copy the files into position.

They're useless unless Apache knows their location. Your httpd.conf or ssl.conf (if the SSL portion has been separated as in Red Hat distros) may also need to be tweaked, so that these directory locations are properly referenced by Apache.

Note that Red Hat distros have a slightly different default directory location from the SuSE example given here. For example: /etc/httpd/conf/ssl.crt/. Check before you copy, and make backups if necessary.

cp server.key /etc/httpd/ssl.key
cp server.crt /etc/httpd/ssl.crt
cp server.csr /etc/httpd/ssl.csr

That's basically it for this step. If you've never configured httpd.conf or ssl.conf (if there is one), you might read the next set of instructions.

(6) Tweak httpd.conf or ssl.conf (in Red Hat) as needed.

This section is going to be specific to your *nix distro and so no single set of procedures will suffice. Implementations between distros, and Apache 1.3.x and 2.x can vary substantially. If you're doing this for Ubuntu or openSuSE 9.3 you should follow the instructions in those documents (referenced early in this document.) The steps below apply loosely toward Red Hat 9 and SuSE 8.2 under Apache 1.3.x.

In Red Hat 9 and later distros you'll need to examine both /etc/httpd/conf/httpd.conf and /etc/httpd/conf.d/ssl.conf. You'll need to make sure you've got at least the following lines properly configured. Note that they don't generally appear next to one another, so you may need to hunt around a bit.

ServerName xxx.xxx.xxx.xxx

(Note: You should use the same server name or IP as the Common Name (CN) you picked while generating the server csr in one of the earlier steps. This will prevent client browsers from generating a message like "domain mismatch" when you first visit the site.)

Red Hat and SuSE at this point should already be loading the ssl module, have the engine turned on, and be listening to 443. But you should double-check and examine the next settings detailed below as well.

Red Hat 9+
LoadModule ssl_module modules/mod_ssl.so

SuSE 8.x
You might see something like this: Include /etc/httpd/suse_loadmodule.conf
And in suse_loadmodule.conf you might see this: LoadModule ssl_module /usr/lib/apache/libssl.so

Listen xxx.xxx.xxx.xxx:443
(Note: Replace the x's with your IP or DNS name. You can listen to a different port, although 443 is standard for https.)

SSLEngine on

SSLCertificateFile /etc/httpd/ssl.crt/server.crt
SSLCertificateKeyFile /etc/httpd/ssl.key/server.key

(Note: Of course you can select different directory locations for the .crt and .key files. Just make sure you reference the proper location where you placed them in an earlier step, and that you manage their permissions very carefully.)

Most likely some other various tweaks. For example, you might want to create a separate directory from which to serve ssl web pages. What's nice about this is that you'll never inadvertently serve a sensitive page through port 80 so long as you develop in two separate places. Perhaps /var/www/html for basic port 80 stuff, and /var/www-ssl/html for port 443 or SSL delivered pages, or under /srv/... as typical under some SuSE distros. An example from Red Hat:

<VirtualHost _default_:443>
# General setup for the virtual host; inherited from global configuration.
DocumentRoot "/var/www-ssl/html"

(Note: Since Red Hat and other distros out-of-box may not have a /var/www-ssl or /var/www-ssl/html directory, you'll need to mkdir to create them as needed.)

(7) Restart apache.

If you are running apache prior to 2.x, then you should substitute 'apache2' with just 'apache' below. With Red Hat it'll be named 'httpd.'

cd /etc/init.d
./apache2 restart

Done -- test it out.


The views and opinions expressed in this page are strictly those of the page author.
The contents of this page have not been reviewed or approved by the University of Minnesota.