Creating a self-signed SSL certificate
Following is a step-by-step guide to creating a self-signed server
certificate with openssl on linux. Solaris 2.10 issues are touched on briefly
as well.
Making a self-signed certificate will cause the client web browser to prompt with a
message whether to trust the certificate signing authority (yourself) permanently
(store it in the browser), temporarily for that session, or to reject it. The message
"web site certified by an unknown authority... accept?" may be a business liability for
general public usage, although it's simple enough for the client to accept the CA permanently.
Self-signing and/or building a CA will save the periodic expense of paying a recognized signing authority.
This is purely for name recognition -- they've paid the major browser producers to have their
CA pre-loaded into them. So 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 one's own CA allows the signing of multiple server certificates
using the same CA.
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.
-
Ubuntu (verified with versions 5.04 - 8.04)
Please refer to my separate document here: selfsign_ubuntu.html.
-
Red Hat based distros
If you're running a Red Hat 9, Fedora, Enterprise or similar Red Hat distro, I suggest
skipping this document unless you want to do use openssl directly, not taking advantage of
the handy scripts provided with the distro. Check out Red Hat's instructions. I've gone
through them a number of times -- they're written clearly and they work:
http://www.redhat.com/docs/manuals/linux/RHL-9-Manual/custom-guide/ch-httpd-secure-server.html.
I've noticed that Fedora Core 2 (and probably 3-4) will actually
auto-configure a demo (Snake Oil type) self-signed certificate once you
complete a basic installation which includes Apache, openssl, and mod_ssl.
Just go to your newly installed box and type https://xxx.xxx.xxx.xxx where
the x's are your IP address. Red Hat's httpd server (based on Apache) will set up the
httpd.conf and ssl.conf files as needed. But you'll still probably want to build your own
certificate, using either the steps in the Red Hat link above, or the the manual procedures
in this document.
-
Red Hat Enterprise AS 3
These steps have been tested and confirmed with Red Hat AS 3.
-
openSuSE 9.3
Please refer to my separate document here: selfsign_opensuse.html.
-
Sun Solaris 2.10
The steps have also been verified to work with Sun Solaris 2.10, but you'll need to
download openssl and recompile a fresh copy -- there's
something non-standard in the out-of-box Sun implementation. You may encounter
a number of arcane (and unhelpful) low-level errors. Rather than going down that
dark and winding path, a system administrator colleague downloaded a recent source for
openssl, recompiled, and these steps worked without a hitch.
I've had feedback that Sun's Java implementation may have problems handling
a key modulus over 2048. So you may need to downgrade the step below which has
an example using 4096. Unfortunately, I don't have exact details on this
error or which version of the JDK/SDK/JRE (or the litany of other acronyms) is the culprit.
That's Sun's problem.
Some steps in this document require priviledged access, and you'll want to
limit access to the certs to all but the root user. So you may
as well su to root and create a working directory that only root has read/write access
to (for example: mkdir certwork, chmod 600 certwork). Go to that directory. In this step you'll
take the place of VeriSign, Thawte, etc. You'll first build the CA key, then build the
certificate itself.
The Common Name (CN) of the CA and the Server certificates should not match or
else a naming collision will occur and you'll get errors later on. In this step, you'll provide the
CA entries. In Step #2 below, you'll provide the Server entries. In this example, I just added "CA" to the CA's
CN field, to distinguish it from the Server's CN field. Use whatever schema you want, just make sure the
CA and Server entries are not identical.
CA:
Common Name (CN): www.somesite.edu CA
Organization (O): Somesite
Organizational Unit (OU): Development
Server:
Common Name (CN): www.somesite.edu
Organization (O): Somesite
Organizational Unit (OU): Development
If you don't have a fully qualified domain name, you should use the IP that you'll be using
to access your SSL site for Common Name (CN). 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
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 #1 above.)
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
Note that 365 days is used 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 browser 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. There are a couple ways to rectify that. crl's
(certificate revocation list) is one method, but beyond the scope of the document. Another
method is for all clients which have stored the CA certificate to go into their settings and
delete the old one manually. But for the purposes of this document, we'll just avoid the
problem. (If you're a sysadmin of a production system and your server.key is compromised,
you'll certainly need to worry.)
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. You might create
some scheme to make the serial number more "official" in appearance or makeup but keep in
mind that it is fully exposed to the public in their web browsers, so it offers no additional
security in itself.
openssl x509 -req -days 365 -in server.csr -CA ca.crt -CAkey ca.key -set_serial 01 -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
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
More experienced system administrators out there can add more insight
on this topic, but it appears that "chmod 600" is the minimal effective
access that root retains on linux. By this, I mean that root retains
read and write access to all files (but not executable rights,
unless explicitly specified), regardless of their chmod settings.
Execute rights are unnecessary for these files. Thus, I typically run SSL
by chown'ing these files to root, and chmod'ing them to all zeros..
"chmod 000 {filename}". Root should still retain read/write access to
them.
If you're running BSD, Solaris, etc. you might want to test this behavior.
(Being less familiar with them, I cannot say for certain.) As root do
something like this: "touch testme.txt" and then "chmod 000 testme.txt".
Open the file with your editor of choice. If you can see the (initially
empty) file, make changes and save it, then you've got mimimal
effective chmod 600 rights for root.
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) will also need to be tweaked, so that these directory
locations are properly referenced by Apache (refer to the next step below).
Locations vary based on distro and Apache version. You can place them in
a non-standard position (so long as you properly reference them in step #6 below),
but if you're doing this the first time you may not want to do anything terribly
idiosyncratic at this point. Once in position, you should be able to su to root
(Ubuntu: sudo su) and chmod 600 them. This will lock everyone out except root.
With Ubuntu/Debian distros you may want to place them in /etc/apache2/ssl/.
I've noted that earlier versions of Ubuntu (pre 7.x) may already have the ssl
directory in place. If not, you may need to create it. Explore your system
a bit.
For Red Hat 9/Fedora/AS distros, you'll probably want to use the
/etc/httpd/conf/ssl.crt and /etc/httpd/conf/ssl.key directories.
For SuSE, it may be /etc/apache2/ssl.crt and /etc/apache2/ssl.key.
Check before you copy, and make backups if necessary. The following
example is aimed at Ubuntu/Apache 2.x configurations.
cp server.key /etc/apache2/ssl
cp server.crt /etc/apache2/ssl
The steps below apply loosely toward Red Hat 9 and related distros running
Apache 1.3.x. If you're doing this for Ubuntu or openSuSE you should follow the instructions
in those documents: selfsign_ubuntu.html or
selfsign_opensuse.html. This section is specific to
your distro so no single set of procedures will suffice. Implementations can and do vary
between distros, and Apache 1.3.x and 2.x. You'll be doing some minor fiddling around,
but once you get the basics it'll become straightforward for your environment.
Essentially you need to make sure your server name is configured, listening to the correct port,
the ssl module is loaded and the engine is on, the locations of the server.crt and
server.key files are properly referenced, and there's an existing document root (the path
location) of your SSL site. There's more you can do, but this is the bare minimum. 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'll need to hunt around a bit.
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 web browsers from generating a message like "domain mismatch" whenever
they visit the site. Replace the x's below with your IP or DNS name.
ServerName xxx.xxx.xxx.xxx:443
You can listen to a different port, although 443 is standard for https.
Replace the x's below with your IP or DNS name.
Listen xxx.xxx.xxx.xxx:443
Red Hat 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.
LoadModule ssl_module modules/mod_ssl.so
Make sure the engine is on and referencing the server.crt and server.key files
you moved into place at an earlier step. Of course it's possible to select
different directory locations for the .crt and .key files. Always make sure you
manage their permissions very carefully.
SSLEngine on
SSLCertificateFile /etc/httpd/ssl.crt/server.crt
SSLCertificateKeyFile /etc/httpd/ssl.key/server.key
Most likely some other various tweaks. For example, you'll probably want to create a
separate directory from which to serve ssl web pages (DocumentRoot). Perhaps /var/www/html
for port 80 material, and /var/www-ssl/html for SSL delivered pages. Create those directories if they
don't exist, and place a basic index.html SSL web page in it for testing purposes.
You'll then need to reference the DocumentRoot for the SSL portion of your website.
<VirtualHost _default_:443>
DocumentRoot "/var/www-ssl/html"
cd /etc/init.d
./httpd restart
Done -- test it out.