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