Creating a SSL certificate is a unavoidable step of the setup of a encrypted connexion (HTTP, IMAP, FTP, etc.). This guide describe how to generate a valid SSL / TLS certificate.

This howto is tested on:

  • Debian 5.0 Lenny
  • Debian 6.0 Squeeze
  • Debian 7.0 Wheezy
  • Debian 10.0 Buster

Prerequisites

This howto recommends:

Settings

Name the group owning the SSL certificates files (for assigning access to system users):

sslGroup="ssl-cert"

To allow a software starting without “root” permissions (for example, Exim 4), add the software user to the “sslGroup” group:

# ${cmdProxy} adduser Debian-exim "${sslGroup}"

Installation

Detect if sudo is available (“command” is used if not):

cmdProxy='command'
command type -f 'sudo' &>'/dev/null' && cmdProxy='sudo'

Environment preparation

Install the software’s requisites:

${cmdProxy} apt-get install openssl ssl-cert

Create the SSL certificates folders:

while read folder; do
  ${cmdProxy} mkdir --parent "/etc/ssl/${folder}"
done <<< "private
requests
roots
chains
certificates
authorities
configs"

Make sure the chosen group exists:

${cmdProxy} addgroup --system "${sslGroup}"

Adjust the private keys path permissions:

${cmdProxy} chown -R root:${sslGroup} '/etc/ssl/private'
${cmdProxy} chmod 750 '/etc/ssl/private'
${cmdProxy} chmod 440 '/etc/ssl/private/'*

Creating a self-signed certificate (for local networking)

Settings

Set the fully qualified domain name (aka. FQDN, for example: “sub.domain.com”) for which the certificate is created:

sslKeyName="$(command hostname --fqdn)"

Set the group owning the created SSL certificates files (for assigning access to system users):

sslGroup="ssl-cert"

Creation

Create a self-signed certificate:

sslConfigFile="$(command mktemp)"
command sed \
    -e "s/@HostName@/${sslKeyName}/" \
    -e "s|privkey.pem|/etc/ssl/private/${sslKeyName}.key|" \
    '/usr/share/ssl-cert/ssleay.cnf' > "${sslConfigFile}"
${cmdProxy} openssl req -config "${sslConfigFile}" -new -x509 -days 3650 \
    -nodes -out "/etc/ssl/certificates/${sslKeyName}.crt" -keyout "/etc/ssl/private/${sslKeyName}.key"
command rm "${sslConfigFile}"

Set the group owning the created SSL certificates files (for assigning access to system users):

${cmdProxy} chown root:${sslGroup} "/etc/ssl/private/${sslKeyName}.key"
${cmdProxy} chmod 440 "/etc/ssl/private/${sslKeyName}.key"

Self-signed certificates are useful to encrypt connections on a private network with local domains. For connection over the Internet, “Let’s encrypt” certificates are preferred.

Note: Debian provide a tool to create self-signed certificates, but it put the private key and the public key in the same file.

# ${cmdProxy} make-ssl-cert '/usr/share/ssl-cert/ssleay.cnf' '/etc/ssl/certificates/${sslKeyName}.crt'

Creating a certified (valid) SSL / TLS certifate (for Internet)

Settings

Set the fully qualified domain name (aka. FQDN, for example: “sub.domain.com”) for which the certificate is created:

sslKeyName="domain.com"

Note: In order to create a SSL certificated valid for all sub-domains of a domain name (also known as “Wildcard”), use “*” instead of the sub-domain par of the FQDN.

# sslKeyName="*.domain.com"

Set the group owning the created SSL certificates files (for assigning access to system users):

sslGroup="ssl-cert"

Identification settings

Certificate authorities needs to validate the customer identity before acceding to a certificate signing request. Load the identity settings, if available:

if [ -e '/etc/ssl/csr-informations' ]; then
    source '/etc/ssl/csr-informations'
    cat '/etc/ssl/csr-informations'
else
    echo "

#####################
Error: No identity informations available."
fi

If the previous command-line diplay an error, or if the loaded settings does not fit your identity, update the identity settings:

Set the code of your country:

SSL_COUNTRY="fr"

Set the name of your province:

SSL_PROVINCE="Ile-de-France"

Set the name of your city:

SSL_CITY="Paris"

Set your e-mail address:

SSL_EMAIL="user@some-domain.com"

Save the settings in a configuration file for future use:

${cmdProxy} tee '/etc/ssl/csr-informations' \
<<< "# SSL CSR informations.
SSL_COUNTRY=\"${SSL_COUNTRY}\"
SSL_PROVINCE=\"${SSL_PROVINCE}\"
SSL_CITY=\"${SSL_CITY}\"
SSL_EMAIL=\"${SSL_EMAIL}\""

Generation of the private key

Generate a RSA private key with a 2048 bits length:

${cmdProxy} openssl genrsa -out "/etc/ssl/private/${sslKeyName}.key" 2048

Set the private key access permissions:

${cmdProxy} chown root:${sslGroup} "/etc/ssl/private/${sslKeyName}.key"
${cmdProxy} chmod 440 "/etc/ssl/private/${sslKeyName}.key"

Creation of a Certificate Signing Request (CSR)

The Certificate Signing Request is sent to a certificate authority to ask it to validate (sign) the generate SSL certificate. Any error in its creation will result in the certificate authority rejecting the request. For more informations, see Certificate signing request (en) on Wikipedia.

Create the CSR:

${cmdProxy} openssl req -new \
    -key "/etc/ssl/private/${sslKeyName}.key" \
    -out "/etc/ssl/requests/${sslKeyName}.csr" \
    <<< "${SSL_COUNTRY}
${SSL_PROVINCE}
${SSL_CITY}
${sslKeyName}

${sslKeyName}
${SSL_EMAIL}

"

Show the CSR contents:

command cat "/etc/ssl/requests/${sslKeyName}.csr"

The CSR contents should look like this:

-----BEGIN CERTIFICATE REQUEST-----
MIIC3DCCAcQCADKZgZYOEzAJBgNVBAYAXODfRYwFAYDVQQIEw1JKJDfZGUtRnJh
 ..... .... ....
N4QtCKIq9ZsP+FjK+h5f7Q==
-----END CERTIFICATE REQUEST-----

Obtaining the public key

The certified public key is obtained from a commercial certificate authority. The certificate authority validate the identity used to generate the CSR before issuing the certified public key.

Once the domain accepted by the certificate authority, request the signing of the certificate by sending the CSR to the authority (by sending the CSR file, or copy/pasting the content of the file in a web form):

command cat "/etc/ssl/requests/${sslKeyName}.csr"

Once the public key obtained, copy/paste it in the “sslCert” Shell variable:

sslCert="-----BEGIN CERTIFICATE-----
MIIHJzCCBg+gAwIBAgIDBNzOMXAXCDRTSIKDOWQBBQUAAGEOMMQscZfGLDVQQGEwJJ
 .... .... .....
H5LYbXPAq3DpOzs=
-----END CERTIFICATE-----"

Create the public key file:

echo "${sslCert}" > "/etc/ssl/certificates/${sslKeyName}.crt"

Make sure to download the root and chains certificates for your chosen certificate authority.

For example:

# ${cmdProxy} wget "https://www.certificate-authority.com/certs/ca.crt" \
        --output-document="/etc/ssl/roots/certificate-authority-root.ca"
# ${cmdProxy} wget "https://www.certificate-authority.com/certs/sca.server1.crt" \
        --output-document="/etc/ssl/chains/certificate-authority.class1.server.ca.pem"

Create a symbolic link to the correct intermediate certificate of the chosen certificate authority. For example:

# ${cmdProxy} ln -s "/etc/ssl/chains/certificate-authority.class1.server.ca.pem" "/etc/ssl/chains/${sslKeyName}.ca"

Create a file containing the public, intermediate and root certificates for use by software allowing only one public certificate file:

${cmdProxy} cp "/etc/ssl/certificates/${sslKeyName}.crt" 
test -e "/etc/ssl/chains/${sslKeyName}.ca" \
    && ${cmdProxy} tee -a "/etc/ssl/certificates/${sslKeyName}.crt+chain+root" < "/etc/ssl/chains/${sslKeyName}.ca"
test -e "/etc/ssl/roots/${sslKeyName}-root.ca" \
    && ${cmdProxy} tee -a "/etc/ssl/certificates/${sslKeyName}.crt+chain+root" < "/etc/ssl/roots/${sslKeyName}-root.ca"

The certificate can now be used with HTTP, IMAP, SMTP, FTP, etc. servers. Obtain the certificates files path with:

echo "Private key :        \"/etc/ssl/private/${sslKeyName}.key\"
Root certificate :         \"/etc/ssl/roots/${sslKeyName}-root.ca\"
Intermediate certificate : \"/etc/ssl/chains/${sslKeyName}.ca\"
Public key :               \"/etc/ssl/certificates/${sslKeyName}.crt\""

Creating a local certificate authority

Settings

Set the fully qualified domain name (aka. FQDN, for example: “sub.domain.com”) of the certificate authority :

sslCaName="$(command hostname --fqdn)"

Set the group owning the created SSL certificates files (for assigning access to system users):

sslGroup="ssl-cert"

Creation of a certificate authority

Create the authority configuration file:

${cmdProxy} mkdir --parent "/etc/ssl/authorities/${sslCaName}"
confFile="/etc/ssl/authorities/${sslCaName}/${sslCaName}.conf"
${cmdProxy} sed \
    -e "s/@HostName@/${sslCaName}/" \
    -e "s|privkey.pem|/etc/ssl/private/${sslCaName}.cakey|" \
    '/usr/share/ssl-cert/ssleay.cnf' > "${confFile}"
${cmdProxy} tee -a "${confFile}" \
   <<< "[ ca ]
default_ca = CA_${sslCaName}
[ CA_${sslCaName} ]
dir = /etc/ssl
serial = \$dir/authorities/${sslCaName}/serial
database = \$dir/authorities/${sslCaName}/index.txt
new_certs_dir = \$dir/certificates
certificate = \$dir/authorities/${sslCaName}.ca
private_key = \$dir/private/${sslCaName}.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"

Create the local certificate authority:

${cmdProxy} openssl req -config "${confFile}" -new -x509 -extensions v3_ca -days 3650 \
    -nodes -out "/etc/ssl/authorities/${sslCaName}.ca" -keyout "/etc/ssl/private/${sslCaName}.cakey"

Protect the certificate authority private key:

${cmdProxy} chown root:${sslGroup} "/etc/ssl/private/${sslCaName}.cakey"
${cmdProxy} chmod 440 "/etc/ssl/private/${sslCaName}.cakey"

Create the needed files:

${cmdProxy} touch "/etc/ssl/authorities/${sslCaName}/index.txt"
${cmdProxy} tee "/etc/ssl/authorities/${sslCaName}/serial" <<< '01'

This authority can sign local certificates. It allow the validation of localy signed certificates by clients possessing the local certificate authority public key. It can be of use on a local network with a local domain non visible on Internet.

Validation of a CSR

The creation of a CSR is described in this article: Creating a certified (valid) SSL / TLS certifate (for Internet)

Accept the CSR with the local certificate authority and create the public key for the CSR:

confFile="/etc/ssl/authorities/${sslCaName}/${sslCaName}.conf"
${cmdProxy} openssl ca -config "${confFile}" -days 3650 \
    -out "/etc/ssl/certificates/${sslKeyName}.crt" \
    -in "/etc/ssl/requests/${sslKeyName}.csr" \
  <<< 'y
y'

Bibliography

Thanks

Categories: HTTP

0 Comments

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.