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