Create your own certification authority and your own self-signed certificates with a completed Subject Alternative Name (functional in Chrome 58+)

In this short article, we’ll show you how to generate your own certification authority and how to sign a self-signed certificate with this certification authority and with completed subjectAltName (Subject Alternative Name) to make it works in Chrome 58 or higher. The main reason for this is mostly for the development, when we want to establish a https connection locally and want it to be trusted. But we can generate this certificates also for intranet domains and, in the worst case, for public domains too.

Why should you ever do with your own certification authority and not just create your own self-signed certificates? The main advantage is that you only need to import this certificate authority to your system/browser (Firefox has its own certificate store), and then all signed certificates by this authority will be automatically trusted. I have to note here, that I’m not a security or linux expert, and I only have merge together guides I found in the one functional unit. It’s possible that something could be done more elegantly, or I will not use the correct terminology. Don’t be afraid to fix me in comments 🙂 This tutorial works at least on Debian Jessie and Stretch, but it’s quite probably, that it will run on multiple systems.

First, we generate a certification authority. We have two options, if we want or don’t want to have a private key protected by a password. This is a simplified tutorial from https://datacenteroverlords.com/2012/03/01/creating-your-own-ssl-certificate-authority/. If we don’t want to have a password protected private key, we will use this command:

sudo openssl genrsa -out /etc/ssl/private/rootCA-Development.key 2048

And if we want a password protected private key, add the -des3 switch as follows:

sudo openssl genrsa -des3 -out /etc/ssl/private/rootCA-Development.key 2048

The following procedure is the same for both options:

sudo chmod 600 /etc/ssl/private/rootCA-Development.key
sudo openssl req -x509 -new -nodes -key /etc/ssl/private/rootCA-Development.key -sha256 -days 3650 -subj "/C=CZ/ST=Prague/L=Prague/O=Development" -out /etc/ssl/certs/rootCA-Development.pem

Of course, you can adjust the parameters in -subj. Their meaning is C=country, ST=state, L=locality and O=organization. After that we need to import file /etc/ssl/certs/rootCA-Development.pem as trusted to the system or browser (here everyone has to google how to do it for their system/browser).

We just have to create a script that will generate the domain certificates. One or more domains can be entered in one certificate. A wildcard certificate is always generated, so it will also be valid for all subdomains. For this reason, we pass domains to the script without www. So we will create a script with the generate-certificate name:

sudo nano /usr/local/bin/generate-certificate

With content:

#!/bin/bash

###
# How to generate certificate authority:
#  -> without password:
#    sudo openssl genrsa -out /etc/ssl/private/rootCA-Development.key 2048
#  -> with password:
#    sudo openssl genrsa -des3 -out /etc/ssl/private/rootCA-Development.key 2048
#
#    sudo chmod 600 /etc/ssl/private/rootCA-Development.key 2048
#    sudo openssl req -x509 -new -nodes -key /etc/ssl/private/rootCA-Development.key -sha256 -days 3650 -subj "/C=CZ/ST=Prague/L=Prague/O=Development" -out /etc/ssl/certs/rootCA-Development.pem
###

if [ "$EUID" -ne 0 ]; then
  echo "Please run as root"
  exit 1
fi

if [ $# -eq 0 ]; then
  echo "Please specify domain(s)."
  echo "Usage: $0 <main domain> [another domain] [another domain] ..."
  exit 2
fi

ROOTCA="Development"

# -> for certificate authority with password uncomment the line below:
#read -p "Enter rootCA-${ROOTCA}.key password: " PASSWORD

DOMAIN=$1
CONF="/tmp/$DOMAIN.openssl.cnf"
PRIVATE_KEY="/etc/ssl/private/$DOMAIN.key"
CERTIFICATE_REQUEST="/etc/ssl/certs/$DOMAIN.crt.req"
CERTIFICATE="/etc/ssl/certs/$DOMAIN.crt"
ANOTHER_DOMAINS=""
ANOTHER_DOMAINS_INFO=""

ANOTHER_DOMAIN_INDEX=3
for ANOTHER_DOMAIN in ${@:2}
do
  ANOTHER_DOMAINS="${ANOTHER_DOMAINS}DNS.${ANOTHER_DOMAIN_INDEX} = ${ANOTHER_DOMAIN}"$'\n'
  ANOTHER_DOMAIN_INDEX=$((ANOTHER_DOMAIN_INDEX + 1))
  ANOTHER_DOMAINS="${ANOTHER_DOMAINS}DNS.${ANOTHER_DOMAIN_INDEX} = *.${ANOTHER_DOMAIN}"$'\n'
  ANOTHER_DOMAIN_INDEX=$((ANOTHER_DOMAIN_INDEX + 1))

  ANOTHER_DOMAINS_INFO="-> ${ANOTHER_DOMAIN}"$'\n'
done

cat > $CONF <<-EOF
[req]
default_bits = 2048
prompt = no
x509_extensions = v3_req
distinguished_name = dn

[dn]
C = CZ
ST = Prague
L = Prague
O = $ROOTCA
CN = *.$DOMAIN

[v3_req]
subjectAltName = @alt_names

[alt_names]
DNS.1 = $DOMAIN
DNS.2 = *.$DOMAIN
$ANOTHER_DOMAINS
EOF

openssl genrsa -out $PRIVATE_KEY 2048
chmod 600 $PRIVATE_KEY
openssl req -new -config $CONF -key $PRIVATE_KEY -out $CERTIFICATE_REQUEST

openssl x509 -req -in $CERTIFICATE_REQUEST -CA /etc/ssl/certs/rootCA-${ROOTCA}.pem -CAkey /etc/ssl/private/rootCA-${ROOTCA}.key \
  -CAcreateserial -out $CERTIFICATE -days 3650 -sha256 -extfile $CONF -extensions 'v3_req'
# -> for certificate authority with password uncomment the line below and remove this line and the one up
#  -CAcreateserial -out $CERTIFICATE -days 3650 -sha256 -extfile $CONF -extensions 'v3_req' -passin pass:$PASSWORD

rm $CERTIFICATE_REQUEST
rm $CONF

chmod 600 $PRIVATE_KEY

echo "Self signed certificate ${CERTIFICATE} and private key ${PRIVATE_KEY} for main domain ${DOMAIN} were generated with 10 years expiration time"

if [ -z "$ANOTHER_DOMAINS_INFO" ]; then
  echo "Another domains:"
  echo ${ANOTHER_DOMAINS_INFO}
fi

A we will set the script as executable:

sudo chmod a+x /usr/local/bin/generate-certificate

If we have generated a private key with a password-protected certificate authority, we must uncomment the line starting with #read -p ..., and for the openssl x509 ... command, we must uncomment the third line and delete the second one. The script then always asks for a password before generating the certificate. We can also adjust the certificate information in the [dn] section as we did with the certification authority.

At the end, we will show a simple example. We generate the certificate for domains domain1.com and domain2.org like this:

sudo generate-certificate domain1.com domain2.org

The generated certificate is then in files /etc/ssl/private/domain1.com.key (private key) and /etc/ssl/private/domain1.com.crt (certificate). We only need to use these files in nginx, Apache, or other software configuration. This certificate will apply to domains domain1.com, *.domain1.com, domain2.org and *.domain2.org.

Napsat komentář

Vaše emailová adresa nebude zveřejněna.