Self-signed SSL certificate generation

From Smith family
Server setup
← Previous Next →
NTP MDA (Dovecot)

Eclectica has a good guide to setting up SSL certificates. Basically, I followed the instructions given there, except that I didn't rebuild the /etc/ssl/openssl.cnf file, as described at Eclectica.

Initial configuration

  • Install OpenSSL, installed as part of the SSH server package:
root@server:~# apt-get install openssh-server
  • I did all the creation work in /etc/ssl/domain, so create the directory structure:
root@server:~# cd /etc/ssl
root@server:/etc/ssl# mkdir -p domain/private domain/certs domain/newcerts
  • Create a couple of files for the database of keys
root@server:~# echo '01' > domain/serial
root@server:~# touch domain/index.txt
  • Create a list of key revocations
root@server:~# echo '01' > domain/crlnumber
  • Create the /etc/ssl/openssl.cnf file as shown below.

Create the root certifiate

root@server:/etc/ssl# openssl req -new -x509 -extensions v3_ca \
  -keyout domain/private/cakey.pem -out domain/cacert.pem \
  -days 3650 -config ./openssl.cnf
Using configuration from ./openssl.cnf
Generating a 1024 bit RSA private key
.......++++++
..........................++++++
writing new private key to 'domain/private/cakey.pem'
Enter PEM pass phrase:demo
Verifying password - Enter PEM pass phrase:demo
-----
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.
-----
Organization Name (company) [The Sample Company]:<enter>
Organizational Unit Name (department, division) []:CA Division
Email Address []:ca@sample.com
Locality Name (city, district) [Your Town]:<enter>
State or Province Name (full name) [Your State]:<enter>
Country Name (2 letter code) [UK]:<enter>
Common Name (hostname, IP, or your name) []:My Root CA
  • Carefully note the passphrase used to generate this root CA. This generates a private key in domain/private/cakey.pem and a root CA certificate in domain/cacert.pem . It is the latter that can be distributed.

Create a certificate signing request

Now to create a certificate signing request for all of the systems that need them. For the server, that's the MTA, the IMAP server, and the Squirrelmail web mail server.

root@server:/etc/ssl# openssl req -new -nodes \
   -out domain/squirrelmail-req.pem \
   -keyout domain/private/squirrelmail-key.pem -config ./openssl.cnf
...
Organizational Unit Name (department, division) []:Webmail Server
Email Address []:postmaster@sample.com
Common Name (hostname, IP, or your name) []:squirrelmail.domain.tld
...

Change the name squirrelmail-req.pem for the purpose needed. Make sure that the common name given is the fully-qualified domain name of the machine that will use the certificate.

Each CSR will create a pair of files: a private key squirrelmail-key.pem and a signing request squirrelmail-req.pem

Sign the request

root@server:/etc/ssl# openssl ca -out domain/certs/squirrelmail-cert.pem \
   -config ./openssl.cnf -infiles domain/squirrelmail-req.pem 
Using configuration from ./openssl.cnf
Enter PEM pass phrase:demo
Check that the request matches the signature
Signature ok
The Subjects Distinguished Name is as follows
organizationName      :PRINTABLE:'The Sample Company'
organizationalUnitName:PRINTABLE:'Webmail Server'
emailAddress          :IA5STRING:'postmaster@sample.com'
localityName          :PRINTABLE:'Your Town'
stateOrProvinceName   :PRINTABLE:'Your State'
countryName           :PRINTABLE:'UK'
commonName            :PRINTABLE:'squirrelmail.domain.tld'
Certificate is to be certified until Dec  8 04:37:38 2002 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

This creates the signed certificate in squrrelmail-cert.pem and a copy in newcerts/<serial>.pem.

Installing certificates

This is detailed in the information for the particular applications. One wrinkle is that the certificate for Apache needs to be modified so that Apache doesn't request the passphrase every time it starts.

 root@server:/etc/ssl# openssl rsa -in domain/private/squirrelmail-key.pem \
   -out domain/private/squirrelmail-key.insecure.pem

Full details on setting up Apache are in the Web server setup notes. Read more on generating SSL keys for Apache and more notes for Apache + SSL.

Revoking a certificate

When certificates expire or become compromised, they can be revoked.

  • Revoke a certificate with the command:
root@server:/etc/ssl# openssl ca -revoke domain/certs/squirrelmail-cert.pem 
  • Once you've done all the revocations you need to, generate the certificate revocation list (CRL):
root@server:/etc/ssl# openssl ca -gencrl -out domain/root.crl
  • You can check the contents of the revocation list with:
root@server:/etc/ssl# openssl ca -gencrl -out domain/root.crl
  • Copy the new CRL to the correct directory on the wweb server:
root@server:/etc/ssl# cp domain/root.crl /var/www/domain.tld/root.crl

You can then generate new certificates to replace the revoked ones.

Viewing the contents of a certificate

root@server:/etc/ssl# openssl x509 -in domain/certs/squirrelmail-cert.pem -text

Contents of /etc/ssl/openssl.cnf

Note the change to the dir entry in the [ CA_default ] section.

#
# OpenSSL example configuration file.
# This is mostly being used for generation of certificate requests.
#
HOME                    = .
RANDFILE                = $ENV::HOME/.rnd

oid_section             = new_oids

####################################################################
[ ca ]
default_ca      = CA_default            # The default ca section

####################################################################
[ CA_default ]

dir             = ./domain               # Where everything is kept
certs           = $dir/certs            # Where the issued certs are kept
crl_dir         = $dir/crl              # Where the issued crl are kept
database        = $dir/index.txt        # database index file.
new_certs_dir   = $dir/newcerts         # default place for new certs. 

certificate     = $dir/cacert.pem       # The CA certificate
serial          = $dir/serial           # The current serial number
crlnumber       = $dir/crlnumber        # the current crl number
                                        # must be commented out to leave a V1 CRL
crl             = $dir/root.crl         # The current CRL
private_key     = $dir/private/cakey.pem# The private key
RANDFILE        = $dir/private/.rand    # private random number file

x509_extensions = usr_cert              # The extentions to add to the cert

name_opt        = ca_default            # Subject Name options
cert_opt        = ca_default            # Certificate field options

crl_extensions        = crl_ext

default_days    = 3650                  # how long to certify for
default_crl_days= 30                    # how long before next CRL
default_md      = sha1                  # which md to use.
preserve        = no                    # keep passed DN ordering

policy          = policy_match 

# For the CA policy
[ policy_match ]
countryName             = match
stateOrProvinceName     = match
organizationName        = match
organizationalUnitName  = optional
commonName              = supplied
emailAddress            = optional 

# For the 'anything' policy
[ policy_anything ]
countryName             = optional
stateOrProvinceName     = optional
localityName            = optional
organizationName        = optional
organizationalUnitName  = optional
commonName              = supplied
emailAddress            = optional

####################################################################
[ req ]
default_bits            = 1024
default_keyfile         = privkey.pem
distinguished_name      = req_distinguished_name
attributes              = req_attributes
x509_extensions = v3_ca # The extentions to add to the self signed cert 

string_mask = nombstr

req_extensions = v3_req # The extensions to add to a certificate request 

[ req_distinguished_name ]
countryName                     = Country Name (2 letter code)
countryName_default             = UK
countryName_min                 = 2
countryName_max                 = 2 

stateOrProvinceName             = State or Province Name (full name)
stateOrProvinceName_default     = Your State 

localityName                    = Locality Name (eg, city)
localityName_default            = Your Town

0.organizationName              = Organization Name (eg, company)
0.organizationName_default      = Your Org Name

organizationalUnitName          = Organizational Unit Name (eg, section)

commonName                      = Common Name (eg, YOUR name)
commonName_default              = Domain
commonName_max                  = 64 

emailAddress                    = Email Address
emailAddress_default            = webmaster@domain.tld
emailAddress_max                = 64

[ req_attributes ]
challengePassword               = A challenge password
challengePassword_min           = 4
challengePassword_max           = 20

unstructuredName                = An optional company name

[ usr_cert ] 

# These extensions are added when 'ca' signs a request.

basicConstraints=CA:FALSE 

nsComment                       = "OpenSSL Generated Certificate"

subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid,issuer

keyUsage = digitalSignature,keyEncipherment
extendedKeyUsage = serverAuth
crlDistributionPoints = URI:http://domain.tld/root.crl
subjectAltName  = @alt_names

[alt_names]
DNS.1 = domain.tld
DNS.2 = *.domain.tld

[ v3_req ]

basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment 

[ v3_ca ]

subjectKeyIdentifier=hash

authorityKeyIdentifier=keyid:always,issuer:always

basicConstraints = CA:true 

[ crl_ext ]

authorityKeyIdentifier=keyid:always,issuer:always

[ proxy_cert_ext ]

basicConstraints=CA:FALSE 

nsComment                       = "OpenSSL Generated Certificate" 

subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid,issuer:always

proxyCertInfo=critical,language:id-ppl-anyLanguage,pathlen:3,policy:foo