Apache SSL TLS Certificate Creation Script

Overview

Brief notes on how to create an Apache OpenSSL certificate using a bash script under Debian 10. A website that is not encrypted can become a threat to visitors, and often many providers block websites that are not SSL/TLS enabled. The audience is experienced Linux administrators.

Definitions

    * Root CA certificate = the main self-signed certificate from the Root certificate authority that signs all other certificates or intermediate certificates.
    * Intermediate CA certificate = a certificate created by an intermediate certificate authority (CA), signed by the Root CA.
    * CA Bundle certificate = the merge of Root CA certificate an the Intermadiate CA certificate, valid as a root certificate.
    * Certificate = the certificate received and signed by the Intermediate CA certificate.
    * Certificate Chain = the end certificate, along with the CA Bundle certificate.
    * The intermediate method has more security, so that intrusion of one intermediate certificate authority does not affect the entire root.

The Script

The OpenSSL script below is simple; the variables need to be modified inside. It creates the following (4) four files:

    * Raw private key.
    * RSA private key.
    * CSR, certificate signing request.
    * Self-signed certificate, for testing.

Creating the private key in at least two formats seems like a good idea. Always keep private keys truly private and secure.

#!/bin/bash
#
### Create self signed certificate for local SSL virtual hosts.
# by Ramses Soto-Navarro <ramses@sotosystems.com> 7/12/2010

f_syntax () {
echo "SYNTAX: $0 <virtualhost.name.org>"
exit 1
}

if [ $# -lt 1 ]; then f_syntax; fi

VHOST=$1

#########################
# MODIFY VARIABLES BELOW:
#########################

f_setvars () {
#### Modify only the variables below:
C=US
ST=FL
L="Winter Haven"
O="Example Company"
OU="Information Technology Department"
EMAIL="admin@example.com"
DAYS="3650"
OWNERS=root.root
#########################

# Do not modify anything below:
CN=$VHOST
RAWPRIVKEY=$VHOST.raw.privkey.pem
CSR=$VHOST.csr
RSAPRIVKEY=$VHOST.rsa.privkey.pem
CERT=$VHOST.self-signed.crt 
CONFIG=/dev/shm/sslconfig-$$.txt

cat > $CONFIG <<EOF
[ req ]
default_bits           = 2048
default_keyfile        = $RAWPRIVKEY.pem
distinguished_name     = req_distinguished_name
attributes             = req_attributes
prompt                 = no
output_password        = mypass
[ req_distinguished_name ]
C=$C
ST=$ST
L=$L
O=$O
OU=$OU
CN=$VHOST
emailAddress=$EMAIL
[ req_attributes ]
challengePassword              = $RANDOM challenge password
EOF
}

f_create-self-signed-cert () {
f_setvars
echo "*** Creating Raw Private Key $RAWPRIVKEY"
echo "*** Creating Certificate Signing Request $CSR"
openssl req -config $CONFIG -new -nodes -keyout $RAWPRIVKEY -out $CSR
echo "*** Converting Raw Private Key to RSA format"
openssl rsa -in $RAWPRIVKEY -out $RSAPRIVKEY
echo "*** Creating Self-sign Certificate $CERT"
openssl x509 -in $CSR -req -signkey $RSAPRIVKEY -days $DAYS -out $CERT 
chmod 0640 $VHOST*
#chown $OWNERS $VHOST*
echo "
---------------------------------------
Create the following entries in Apache:

SSLEngine on
SSLCertificateFile $PWD/$CERT
SSLCertificateKeyFile $PWD/$RSAPRIVKEY

"
rm $CONFIG
}

echo -en "Create self-signed certificate for $VHOST [y/n] "
read continue

case $continue in
        y|Y) f_create-self-signed-cert ;;
        n|N) exit 0 ;;
        *) f_syntax ;;
esac

Results

What running the script looks like and the result.

# mkdir -p /etc/ssl/www.example.com
# cd /etc/ssl/www.example.com
# create-cert.sh www.example.com
Create self-signed certificate for www.example.com [y/n] y
*** Creating Raw Private Key www.example.com.raw.privkey.pem
*** Creating Certificate Signing Request www.example.com.csr
Generating a RSA private key
........+++++
..............+++++
writing new private key to 'www.example.com.raw.privkey.pem'
-----
*** Converting Raw Private Key to RSA format
writing RSA key
*** Creating Self-sign Certificate www.example.com.self-signed.crt
Signature ok
subject=C = US, ST = FL, L = Winter Haven, O = Example Company, OU = Information Technology Department, CN = www.example.com, emailAddress = admin@example.com
Getting Private key

---------------------------------------
Create the following entries in Apache:

SSLEngine on
SSLCertificateFile /etc/ssl/www.example.com.self-signed.crt
SSLCertificateKeyFile /etc/ssl/www.example.com.rsa.privkey.pem

The files created:

# ls -lh
total 16K
-rw-r----- 1 root root 1.2K Sep 11 01:21 www.example.com.csr
-rw-r----- 1 root root 1.7K Sep 11 01:21 www.example.com.raw.privkey.pem
-rw-r----- 1 root root 1.7K Sep 11 01:21 www.example.com.rsa.privkey.pem
-rw-r----- 1 root root 1.4K Sep 11 01:21 www.example.com.self-signed.crt

Official Certificate Process

The self-signed certificate is fine for testing. However, for official certificate encryption you’ll need to do the following:

    * Subscribe to a certificate issuer.
    * Purchase a certificate validation.
    * Send the certificate signing request; the *,csr file above.
    * The CSR is basically a temporary key sent to the intermediate certificate authorities, so that they can create and sign your public certificate.
    * Wait for your certificate request to be processed; sometimes it takes a few hours, but it can take 24 hours or more.
    * You’ll receive an Email with the signed certificate or a link to download it.
    * File www_example_com.zip may extract to: www_example_com.crt and www_example_com.ca-bundle. Refer to the above definitions for clarification.

Check Certificate Validity

Check if the certificate returned is valid. Important matching areas to inspect: “Subject: CN=”, “Not After”, “Issuer”.

# openssl x509 -subject -noout -in www.example.com.crt

# openssl x509 -enddate -noout -in www.example.com.crt

# openssl x509 -issuer -noout -in www.example.com.crt

# openssl x509 -text -in www.example.com.crt | more

Configure Apache Virtual Host with SSL

Modify the Apache SSL configuration:

# vi /etc/apache2/sites-available/www.example.com-ssl.conf

<VirtualHost *:443>
	Header edit Set-Cookie ^(.*)$ $1;HttpOnly;Secure
        ServerAdmin "admin@example.com"
        ServerName "example.com:443"
        DocumentRoot "/var/www/www.example.com"

        <Directory "/var/www/www.example.com">
                Options Indexes FollowSymLinks MultiViews
                AllowOverride All
                Require all granted
        </Directory>

	SSLEngine on
	SSLCertificateFile /etc/ssl/www.example.com/www.example.com.crt
	SSLCertificateKeyFile /etc/ssl/www.example.com/ww.example.com.rsa.privkey.pem
	SSLCertificateChainFile /etc/ssl/www.example.com/www.example.com.ca-bundle
</VirtualHost>

Create the test file:

# mkdir -p /var/www/www.example.com
# echo "Hello World" >> /var/www/www.example.com/index.html

Restart Apache:

# systemctl restart apache2

Open the page in your browser and verify that the certificate is valid by clicking on the certificate lockpad next to or near the URL entry box.

Subject Alternative Certificate Script

Follow the logic:

# by Ramses Soto-Navarro <ramses@sotosystems.com>, 3/1/2023
# Create a self-signed certificate with subject alternative name
# in order to server URLs with the same domain suffix.
# Also create the private key, public key and CSR.
# Modify the variable below:

# === VARIABLES ===

export DOMAIN="example.com"
export DAYS=3650

cat > req.cnf <<EOF
[ req ]
prompt = no
default_bits = 4096
distinguished_name = req_distinguished_name
req_extensions = req_ext

[ req_distinguished_name ]
C=US
ST=FL
L=Bartow
O=Example LLC
OU=IT Dept
CN=$DOMAIN
emailAddress=info@$DOMAIN

[ req_ext ]
subjectAltName = @alt_names

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

# === Do not modify below ===

# Create priv key
f_privkey () {
echo -e "nn=== Generating private key $DOMAIN.priv.key ==="
openssl genrsa -out $DOMAIN.priv.key 2048

# Verify: openssl rsa -in privateKey.key -check
}

f_pubkey () {
echo -e "nn=== Generating public key $DOMAIN.pub.pem ==="
openssl rsa -in $DOMAIN.priv.key -pubout -out $DOMAIN.pub.pem

# Verify: cat $DOMAIN.pub.pem
}

# Create CSR
f_csr () {
echo -e "nn=== Creating CSR $DOMAIN.csr ==="
openssl req 
 -new 
 -key $DOMAIN.priv.key 
 -config req.cnf 
 -out $DOMAIN.csr

# Verify: openssl req -text -noout -verify -in $DOMAIN.csr
# Verify CSR subjectAltName: openssl req -in $DOMAIN.csr -text -noout | grep DNS
}

# Create self-signed cert
f_cert () {
echo -e "nn=== Generating Self-signed Certificate $DOMAIN.crt ==="
openssl x509 
 -signkey $DOMAIN.priv.key 
 -in $DOMAIN.csr 
 -req 
 -days 365 
 -extfile req.cnf 
 -extensions req_ext 
 -out $DOMAIN.crt

# Verify: openssl x509 -text -noout -in $DOMAIN.crt
}

f_privkey
f_pubkey
f_csr
f_cert

The End.