SSL/TLS-certificates for lazy people

In a nutshell, the SSL/TLS certificate (SSL: Secure Sockets Layer, TLS: Transport Layer Security) is a unique digital signature for the secure connection between the client and the server.
 
Creating SSL certificate can be divided into the following steps:

  • create a personal key (Private Key);
  • create a query to retrieve the certificate (Certificate Signing Request);
  • creating a self-signed (Self-Signed Certificate).


To create the certificates I have written a small shell-script:

#!/bin/sh
#--------------------------------------------------------------------------
# certroutine.sh: script for creating SSL Certificates
# $Revision: 1.00 (CentOS Edition by Wakko Warner) $
# $Comment: Any comments please send to wakko@acmelabs.spb.ru $
#--------------------------------------------------------------------------

#################
# User Settings #
#################
# Country Name (2 letter code)
  C_="RU"
# State or Province Name (full name)
  ST_="North-West"
# Locality Name (eg, city)
  L_="Saint-Petersburg"
# Organizational Name (eg, company)
  O_=""
# Organizational Unit Name (eg, section)
  OU_=""
# Common Name (eg, YOUR name, domain or host name, don't add *. for wildcards)
  CN_=""
# Email Address
  EM_=""
# Subject Alternative Names (enter * for wildcard certificate)
  SAN_=""

[ "$C" == "" ] && C="$C_"; [ "$ST" == "" ] && ST="$ST_"; [ "$L" == "" ] && L="$L_"
[ "$O" == "" ] && O="$O_"; [ "$OU" == "" ] && OU="$OU_"; [ "$CN" == "" ] && CN="$CN_"
[ "$EM" == "" ] && EM="$EM_"; [ "$SAN" == "" ] && SAN="$SAN_"
if [ "$CN" == "" ]; then
	echo "This script allows you to create:"
	echo "  o public/private key pairs"
	echo "  o SSL certificate signing requests (CSRs)"
	echo "  o self-signed SSL certificates"
	echo
	echo "Edit settings in the script before beginning!"
	exit 0
fi

OPENSSL=/usr/bin/openssl
UTF8=`locale -c LC_CTYPE -k | grep -q charmap.*UTF-8 && echo -utf8`
KEYLEN=2048
TYPE=rsa:${KEYLEN}
[ "$SERIAL" == "" ] && SERIAL=0
[ "$DAYS" == "" ] && DAYS=365

TLSROOT=/etc/pki/tls
KEY=${TLSROOT}/private/$CN.key
CSR=${TLSROOT}/certs/$CN.csr
CRT=${TLSROOT}/certs/$CN.crt
PEM=${TLSROOT}/certs/$CN.pem
if [ "$SAN" == "*" ]; then
	CN="*.$CN"
	SAN=""
fi

createconfig() {
	CNF=`/bin/mktemp /tmp/openssl.XXXXXX`
	CONFIG="-batch -config $CNF"
	cat <<EOF >$CNF
[req]
default_bits			= $KEYLEN
default_md			= sha256
distinguished_name		= req_distinguished_name
req_extensions			= v3_req

[req_distinguished_name]
countryName			= Country Name (2 letter code)
countryName_default		= $C
stateOrProvinceName		= State or Province Name (full name)
stateOrProvinceName_default	= $ST
localityName			= Locality Name (eg, city)
localityName_default		= $L
organizationName		= Organizational Name (eg, company)
organizationName_default	= $O
organizationalUnitName		= Organizational Unit Name (eg, section)
organizationalUnitName_default	= $OU
commonName			= Common Name (eg, YOUR name)
commonName_default		= $CN
commonName_max			= 64
emailAddress			= Email Address
emailAddress_default		= $EM

[v3_ca]
basicConstraints		= CA:TRUE
subjectKeyIdentifier		= hash
authorityKeyIdentifier		= keyid:always,issuer:always

[v3_req]
basicConstraints		= CA:FALSE
keyUsage			= nonRepudiation, digitalSignature, keyEncipherment
EOF
	if [ ! "$SAN" == "" ]; then
		echo "subjectAltName			= @alt_names" >>$CNF
		echo "" >>$CNF
		echo "[alt_names]" >>$CNF
		i=0
		for AN in $SAN
		do
			((i++))
			echo "DNS.$i				= $AN" >>$CNF
		done
	fi
}

usage() {
	echo "This script allows you to create:"
	echo "  o public/private key pairs"
	echo "  o SSL certificate signing requests (CSRs)"
	echo "  o self-signed SSL certificates"
	echo
	echo Usage:
	echo "  To create a KEY file, run \"$0 genkey\";"
	echo "  To create a CSR file, run \"$0 gencsr\";"
	echo "  To create a CRT file, run \"$0 gencrt\";"
	echo "  To create a PEM file, run \"$0 genpem\";"
	echo "  To verify a CSR file, run \"$0 verifycsr\";"
	echo "  To verify a CRT file, run \"$0 verifycrt\"."
	echo
	echo "${TLSROOT}/private/ is output directory for key files"
	echo "${TLSROOT}/certs/ is output directory for CSR, CRT and PEM files"
	echo
	echo "To create a test certificate with serial number other than zero, add SERIAL=num"
	echo "You can also specify key length with KEYLEN=n and expiration in days with DAYS=n"
	echo "Also you can specify C=, ST=, L=, O=, OU=, CN=, EM=, SAN=..."
	echo
	echo Examples:
	echo "  CN=www.example.com $0 genkey"
	echo "  CN=www.example.com SAN=\"mail.example.com blog.example.com\" $0 gencsr"
	echo "  CN=www.example.com SAN=\"mail.example.com blog.example.com\" $0 gencrt"
	return 0
}

genkey() {
	umask 77
	$OPENSSL genrsa $KEYLEN -sha256 -nodes >$KEY
	return 0
}

gencsr() {
	umask 77
	[ ! -f $KEY ] && genkey
	createconfig
	$OPENSSL req $UTF8 -new -key $KEY -out $CSR $CONFIG
	rm -f $CNF
	return 0
}

verifycsr() {
	$OPENSSL req -in $CSR -text -verify -noout
	return 0
}

gencrt() {
	umask 77
	[ ! -f $KEY ] && genkey
	createconfig
	$OPENSSL req $UTF8 -new -key $KEY -x509 -days $DAYS -out $CRT $CONFIG -set_serial $SERIAL
	rm -f $CNF
	CRTHASH=`openssl x509 -hash -noout -in $CRT`.0
	rm -f ${TLSROOT}/certs/$CRTHASH
	ln -s $CN.crt ${TLSROOT}/certs/$CRTHASH
	return 0
}

verifycrt() {
	$OPENSSL verify $CRT
	return 0
}

genpem() {
	umask 77
	PEM1=`/bin/mktemp /tmp/openssl.XXXXXX`
	PEM2=`/bin/mktemp /tmp/openssl.XXXXXX`
	createconfig
	$OPENSSL req $UTF8 -newkey $TYPE -keyout $PEM1 -nodes -x509 -days $DAYS -out $PEM2 \
		$CONFIG -set_serial $SERIAL
	rm -f $CNF
	cat $PEM1 >  $PEM
	echo ""   >> $PEM
	cat $PEM2 >> $PEM
	rm -f $PEM1 $PEM2
	return 0
}

case $1 in
	genkey | gencsr | gencrt | genpem | verifycsr | verifycrt)
		$1
		exit $?
	;;
	*)
		usage
		exit $?
	;;
esac

At the top of the script, you can fill in the default values:

# Country Name (2 letter code)
  C_="RU"
# State or Province Name (full name)
  ST_="North-West"
# Locality Name (eg, city)
  L_="Saint-Petersburg"
# Organizational Name (eg, company)
  O_="Example Organization"
# Organizational Unit Name (eg, section)
  OU_=""
# Common Name (eg, YOUR name, domain or host name, don't add *. for wildcards)
  CN_="www.example.com"
# Email Address
  EM_="hostmaster@example.com"
# Subject Alternative Names (enter * for wildcard certificate)
  SAN_="mail.example.com"

Then to create the key and self-signed certificate, you will need to perform:

$ ./certroutine.sh genkey
Generating RSA private key, 2048 bit long modulus
............................................+++
.....................................+++
e is 65537 (0x10001)
$ ./certroutine.sh gencrt
$ ./certroutine.sh verifycrt
/etc/pki/tls/certs/www.example.com.crt: OK

The first command creates a private key /etc/pki/tls/private/www.example.com.key, the second command creates a self-signed certificate /etc/pki/tls/certs/www.example.com.crt, and a third team will check the validity of this certificate.
Note: Regardless of the script, if any certificate is written something like:

/etc/pki/tls/certs/www.example.com.crt: C = RU, ST = North-West, L = Saint-Petersburg, O = ACME Networks, CN = www.example.com, emailAddress = admin@acmenet.ru
error 18 at 0 depth lookup:self signed certificate
OK

Это означает, что для этого сертификата, в папке /etc/pki/tls/certs отсутствует необходимая информация для проверки. Необходимо убедиться, что в этой папке присутствует проверяемый сертификат, а так же присутствуем симлинк с хэшем вместо имени, на проверяемый сертификат. Если симлинка нет – его необходимо создать:
This means that the certificate in the folder /etc/pki/tls/certs is missing information required for validation. You must make sure that this folder is present the certificate being validated, as well as present a symlink with a hash instead of the name on the certificate being validated. If where is no special symlink – you need to create:

$ cd /etc/pki/tls/certs
$ ln -s $CRT `openssl x509 -hash -noout -in $CRT`.0

Where $CRT is the file name of the certificate.
 
If you plan to sign the certificate in «an adult way», on the side, you need to create a private key and request to obtain a certificate:

$ ./certroutine.sh genkey
Generating RSA private key, 2048 bit long modulus
............................................+++
.....................................+++
e is 65537 (0x10001)
$ ./certroutine.sh gencsr
$ ./certroutine.sh verifycsr
verify OK
Certificate Request:
    Data:
        Version: 0 (0x0)
        Subject: C=RU, ST=North-West, L=Saint-Petersburg, O=ACME Networks, CN=www.example.com/emailAddress=admin@acmenet.ru
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (2048 bit)
                Modulus:
                    [...]
                Exponent: 65537 (0x10001)
        Attributes:
        Requested Extensions:
            X509v3 Basic Constraints: 
                CA:FALSE
            X509v3 Key Usage: 
                Digital Signature, Non Repudiation, Key Encipherment
    Signature Algorithm: sha256WithRSAEncryption
         [...]
$ cat /etc/pki/tls/certs/www.example.com.csr
-----BEGIN CERTIFICATE REQUEST-----
[...]
-----END CERTIFICATE REQUEST-----

The contents of the csr file, you must send in a company that will certify your certificate.
 
Also, you can use a script like this:

$ CN="www.example.com" ./certroutine.sh genkey
$ C="RU" ST="North-West" L="Saint-Petersburg" O="Example Org" CN="www.example.com" \
	EM="hostmaster@example.com" SAN="mail.example.com" ./certroutine.sh gencsr
$ C="RU" ST="North-West" L="Saint-Petersburg" O="Example Org" CN="www.example.com" \
	EM="hostmaster@example.com" SAN="mail.example.com" ./certroutine.sh gencrt

 
If you use a free certificate from StartSSL, do the following:

$ cd /etc/pki/tls/certs
$ wget https://www.startssl.com/certs/sub.class1.server.ca.pem
$ ln -s sub.class1.server.ca.pem `openssl x509 -hash -noout -in sub.class1.server.ca.pem`.0

Otherwise verification certificate will receive an error:

$ openssl verify mail.example.com.crt 
mail.example.com.crt: C = RU, CN = mail.example.com, emailAddress = hostmaster@example.com
error 20 at 0 depth lookup:unable to get local issuer certificate

Leave a Reply