Create a SSL / TLS certificate on Debian
The creation of a SSL certificate is a major step when setting up a encrypted connection. Whether to implement HTTPS, to encrypt your IMAP server or FTP server, this guide helps you generate a valid SSL certificate.
This howto is tested on:
- Debian 5.0 Lenny
- Debian 6.0 Squeeze
- Debian 7.0 Wheezy
Prerequisites
This howto recommends:
- setting up SSL / TLS certificates expirations alerts, as described in Setup an email alert on SSL / TLS certificate expiration.
Environment preparation
Install the needed software:
command apt-get install openssl ssl-cert
Create the folders that will contain the certificate:
command mkdir --parent '/etc/ssl/private'
command mkdir --parent '/etc/ssl/requests'
command mkdir --parent '/etc/ssl/roots'
command mkdir --parent '/etc/ssl/chains'
command mkdir --parent '/etc/ssl/certificates'
command mkdir --parent '/etc/ssl/authorities'
command mkdir --parent '/etc/ssl/configs'
Make sure that the system group "ssl-cert" exists:
command addgroup --system 'ssl-cert'
Adjust the permissions on the private keys folder:
command chown -R root:ssl-cert '/etc/ssl/private'
command chmod 710 '/etc/ssl/private'
command chmod 440 '/etc/ssl/private/'*
Creation of a self-signed SSL / TLS certificate (for local networking)
Parameters
Provide the fully qualified host name (sub-domain.domain) of the generated certificate:
SSL_KEY_NAME="$(command hostname --fqdn)"
Creation of the self-signed certificate
Create a self-signed certificate:
CONF_FILE="$(command mktemp)"
command sed \
-e "s/@HostName@/${SSL_KEY_NAME}/" \
-e "s|privkey.pem|/etc/ssl/private/${SSL_KEY_NAME}.pem|" \
'/usr/share/ssl-cert/ssleay.cnf' > "${CONF_FILE}"
command openssl req -config "${CONF_FILE}" -new -x509 -days 3650 \
-nodes -out "/etc/ssl/certificates/${SSL_KEY_NAME}.crt" -keyout "/etc/ssl/private/${SSL_KEY_NAME}.key"
command rm "${CONF_FILE}"
Protect the private key:
command chown root:ssl-cert "/etc/ssl/private/${SSL_KEY_NAME}.key"
command chmod 440 "/etc/ssl/private/${SSL_KEY_NAME}.key"
This method can be used to create a non-valid SSL certificate for a web site. The use of self-signed certificates trigger the display of error messages in web browsers.
Note : Debian provide a tool to create self-signed certificates, but it does not allow to separate private key from public key.
# command make-ssl-cert '/usr/share/ssl-cert/ssleay.cnf' '/etc/ssl/certificates/${SSL_KEY_NAME}.crt'
Creating a valid SSL / TLS certificate (for Internet)
Parameters
Provide the complete domain name (sub-domain included) which for you want to generate a certificate (free with StartSSL authority):
SSL_KEY_NAME="www.domain.com"
Note: To obtain a SSL certificate that match all of a domain sub-domains (also known as Wildcard certificate), replace the sub-domain part by a star ("*") (wildcard certificate cost: US $ 59.90 with StartSSL authority):
SSL_KEY_NAME="*.domain.com"
Personal informations
Some personal data are needed to create a SSL certificate. Load this informations if possible:
if [ -e '/etc/ssl/csr-informations' ]; then
source '/etc/ssl/csr-informations'
cat '/etc/ssl/csr-informations'
else
echo "
#####################
Error: No SSL informations available."
fi
If the command above display an error, or if the loaded data does not fit, update the data:
Provide your country code (edit the bold value):
SSL_COUNTRY="us"
Provide your state / province (edit the bold value):
SSL_PROVINCE="Florida"
Provide your city (edit the bold value):
SSL_CITY="Miami"
Provide your e-mail address (edit the bold value):
SSL_EMAIL="user@some-domain.com"
Save this informations in a configuration file for future use:
echo "# SSL CSR informations.
SSL_COUNTRY=\"${SSL_COUNTRY}\"
SSL_PROVINCE=\"${SSL_PROVINCE}\"
SSL_CITY=\"${SSL_CITY}\"
SSL_EMAIL=\"${SSL_EMAIL}\"" \
> '/etc/ssl/csr-informations'
Creating the private key
Generate the RSA private key with a 2048 bits length:
command openssl genrsa -out "/etc/ssl/private/${SSL_KEY_NAME}.key" 2048
Protect the private key access:
command chown root:ssl-cert "/etc/ssl/private/${SSL_KEY_NAME}.key"
command chmod 440 "/etc/ssl/private/${SSL_KEY_NAME}.key"
Creating the Certificate Signing Request (CSR)
The Certificate Signing Request is to be sent to the certification authority in order to obtain the signed (aka. checked) SSL certificate. It is important to make no mistake when creating it: invalid requests are rejected. For more information, read the Wikipedia article: Certificate signing request.
Generate the CSR:
command openssl req -new \
-key "/etc/ssl/private/${SSL_KEY_NAME}.key" \
-out "/etc/ssl/requests/${SSL_KEY_NAME}.csr" \
<<< "${SSL_COUNTRY}
${SSL_PROVINCE}
${SSL_CITY}
${SSL_KEY_NAME}
${SSL_KEY_NAME}
${SSL_EMAIL}
"
Display the CSR contents:
cat "/etc/ssl/requests/${SSL_KEY_NAME}.csr"
The displayed contents must look like:
-----BEGIN CERTIFICATE REQUEST-----
MIIC3DCCAcQCADKZgZYOEzAJBgNVBAYAXODfRYwFAYDVQQIEw1JKJDfZGUtRnJh
..... .... ....
N4QtCKIq9ZsP+FjK+h5f7Q==
-----END CERTIFICATE REQUEST-----
Obtaining the public key
The public key is obtained from a certification authority. If you have no preference, you can use the StartSSL certification authority.
Once registered, and after your domain name has been validated by the authority, request the validation of the CSR displayed by:
cat "/etc/ssl/requests/${SSL_KEY_NAME}.csr"
For the StartSSL certification authority, the validation process is available in your account "Certificate Wizard" tab.
Once the public key obtained, copy/paste it in the Shell variable SSL_CERT (replace the bold value with your public key):
SSL_CERT="-----BEGIN CERTIFICATE-----
MIIHJzCCBg+gAwIBAgIDBNzOMXAXCDRTSIKDOWQBBQUAAGEOMMQscZfGLDVQQGEwJJ
.... .... .....
H5LYbXPAq3DpOzs=
-----END CERTIFICATE-----"
Create the public key file:
echo "${SSL_CERT}" > "/etc/ssl/certificates/${SSL_KEY_NAME}.crt"
If you choose to use the StartSSL certification authority, download the authority root and intermediate certificate:
command wget "http://www.startssl.com/certs/ca.pem" \
--output-document="/etc/ssl/roots/startssl-root.ca"
command wget "http://www.startssl.com/certs/sub.class1.server.ca.pem" \
--output-document="/etc/ssl/chains/startssl-sub.class1.server.ca.pem"
command wget "http://www.startssl.com/certs/sub.class2.server.ca.pem" \
--output-document="/etc/ssl/chains/startssl-sub.class2.server.ca.pem"
command wget "http://www.startssl.com/certs/sub.class3.server.ca.pem" \
--output-document="/etc/ssl/chains/startssl-sub.class3.server.ca.pem"
If you choose to use the StartSSL certification authority, install the root certificate of this authority:
command ln -s "/etc/ssl/roots/startssl-root.ca" "/etc/ssl/roots/${SSL_KEY_NAME}-root.ca"
If you choose to use the StartSSL certification authority, install the intermediate certificate of this authority:
if [ "${SSL_KEY_NAME}" = "$(echo "${SSL_KEY_NAME}" | command tr '*' '.')" ]; then
command ln -s "/etc/ssl/chains/startssl-sub.class1.server.ca.pem" "/etc/ssl/chains/${SSL_KEY_NAME}.ca"
else
command ln -s "/etc/ssl/chains/startssl-sub.class2.server.ca.pem" "/etc/ssl/chains/${SSL_KEY_NAME}.ca"
fi
Create a file containing the public, intermediate and root certificates for software that does not have the needed configuration options:
command cp "/etc/ssl/certificates/${SSL_KEY_NAME}.crt" "/etc/ssl/certificates/${SSL_KEY_NAME}.crt+chain+root"
test -e "/etc/ssl/chains/${SSL_KEY_NAME}.ca" \
&& command cat "/etc/ssl/chains/${SSL_KEY_NAME}.ca" >> "/etc/ssl/certificates/${SSL_KEY_NAME}.crt+chain+root"
test -e "/etc/ssl/roots/${SSL_KEY_NAME}-root.ca" \
&& command cat "/etc/ssl/roots/${SSL_KEY_NAME}-root.ca" >> "/etc/ssl/certificates/${SSL_KEY_NAME}.crt+chain+root"
The SSL certificate is now available to be used by your HTTP, IMAP, FTP, etc. servers. Get the names of its key and certificates files:
echo "Private key : \"/etc/ssl/private/${SSL_KEY_NAME}.key\"
Root certificate : \"/etc/ssl/roots/${SSL_KEY_NAME}-root.ca\"
Intermediate certificate : \"/etc/ssl/chains/${SSL_KEY_NAME}.ca\"
Public key : \"/etc/ssl/certificates/${SSL_KEY_NAME}.crt\""
Creating a local certification authority
Parameters
Provide the complete domain name (sub-domain included) which for you want to generate a certification authority:
SSL_CA_NAME="$(command hostname --fqdn)"
Creating a certification authority
Create the authority configuration file:
command mkdir --parent "/etc/ssl/authorities/${SSL_CA_NAME}"
CONF_FILE="/etc/ssl/authorities/${SSL_CA_NAME}/${SSL_CA_NAME}.conf"
command sed \
-e "s/@HostName@/${SSL_CA_NAME}/" \
-e "s|privkey.pem|/etc/ssl/private/${SSL_CA_NAME}.cakey|" \
'/usr/share/ssl-cert/ssleay.cnf' > "${CONF_FILE}"
command echo "[ ca ]
default_ca = CA_${SSL_CA_NAME}
[ CA_${SSL_CA_NAME} ]
dir = /etc/ssl
serial = \$dir/authorities/${SSL_CA_NAME}/serial
database = \$dir/authorities/${SSL_CA_NAME}/index.txt
new_certs_dir = \$dir/certificates
certificate = \$dir/authorities/${SSL_CA_NAME}.ca
private_key = \$dir/private/${SSL_CA_NAME}.cakey
default_days = 365
default_md = md5
preserve = no
email_in_dn = no
nameopt = default_ca
certopt = default_ca
policy = policy_anything
[ policy_match ]
countryName = match
stateOrProvinceName = match
organizationName = match
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[ policy_anything ]
countryName = optional
stateOrProvinceName = optional
localityName = optional
organizationName = optional
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[ v3_ca ]
basicConstraints = CA:TRUE
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer:always
[ v3_req ]
basicConstraints = CA:FALSE
subjectKeyIdentifier = hash" \
>> "${CONF_FILE}"
Create the local certification authority:
command openssl req -config "${CONF_FILE}" -new -x509 -extensions v3_ca -days 3650 \
-nodes -out "/etc/ssl/authorities/${SSL_CA_NAME}.ca" -keyout "/etc/ssl/private/${SSL_CA_NAME}.cakey"
Protect the private key:
command chown root:ssl-cert "/etc/ssl/private/${SSL_CA_NAME}.cakey"
command chmod 440 "/etc/ssl/private/${SSL_CA_NAME}.cakey"
Create the authority index and serial files:
command touch "/etc/ssl/authorities/${SSL_CA_NAME}/index.txt"
command echo '01' > "/etc/ssl/authorities/${SSL_CA_NAME}/serial"
This authority is used to sign certificates localy created. It has almost no value, other than allow clients with its public key installed to validate local certificates signed by it.
Obtaining a certificate public key by validating a CSR
Note: the CSR creation process is described higher in this page.
Sign a public certificate by accepting the Certificate Signing Request with the local authority:
echo 'y
y' > '/tmp/ca.input'
CONF_FILE="/etc/ssl/authorities/${SSL_CA_NAME}/${SSL_CA_NAME}.conf"
command openssl ca -config "${CONF_FILE}" -days 3650 \
-out "/etc/ssl/certificates/${SSL_KEY_NAME}.crt" \
-in "/etc/ssl/requests/${SSL_KEY_NAME}.csr" \
< '/tmp/ca.input'
command rm '/tmp/ca.input'
Allowing the use of SSL / TLS certificates
If the server software does not start with root user permissions (it is the case for Exim 4), add the server user to the "ssl-cert" group. For example, to enable the use of SSL / TLS certificates by Exim 4:
command adduser Debian-exim ssl-cert
References
These books can help you:
Thanks
- Thanks to CACert (en) for VhostTaskForce (en).
- Thanks to author and translators of Guide pratique des certificats SSL (fr).
- Thanks to Matthieu Vogelweith (fr) for Serveur Web Apache - SSL - PHP (fr).
- Thanks to Documentation technique : Debian (fr) for Création d’un Certificate Signing Request (CSR) (fr).
- Thanks to Artisan Numérique (fr) for Créer sa propre (mini) PKI (fr).