This cheat sheet helps to set up web server with TLS authentication. We'll use our own certificate authority.

As a prerequisite You have to own the server and the domain, pointed to this server.

Prepare easy-rsa

We need to create several cipher keys. OpenSSL can do it for us, but it's not the easiest tool. Much simpler way is to use easy-rsa. It comes with openvpn in Debian-8. Make a local copy and apply some changes:

cp -r /usr/share/doc/openvpn/examples/easy-rsa/2.0 /etc/.keys-infrastructure

edit vars:

+++ /usr/share/doc/openvpn/examples/easy-rsa/2.0/vars   2011-07-01 12:31:26.000000000 +0400
@@ -26,8 +26,7 @@
 # This variable should point to
 # the openssl.cnf file included
 # with easy-rsa.
-#export KEY_CONFIG=`$EASY_RSA/whichopensslcnf $EASY_RSA`
-export KEY_CONFIG=$EASY_RSA/openssl-1.0.0.cnf
+export KEY_CONFIG=`$EASY_RSA/whichopensslcnf $EASY_RSA`

 # Edit this variable to point to
 # your soon-to-be-created key
@@ -51,13 +50,13 @@
 # down TLS negotiation performance
 # as well as the one-time DH parms
 # generation process.
-export KEY_SIZE=4096
+export KEY_SIZE=1024

 # In how many days should the root CA key expire?
 export CA_EXPIRE=3650

 # In how many days should certificates expire?
-export KEY_EXPIRE=365
+export KEY_EXPIRE=3650

 # These are the default values for fields
 # which will be placed in the certificate.
@@ -65,11 +64,11 @@
 export KEY_COUNTRY="US"
 export KEY_PROVINCE="CA"
 export KEY_CITY="SanFrancisco"
-export KEY_ORG="ACME"
-export KEY_EMAIL="info@example.com"
-export KEY_ALTNAME="example.com"
+export KEY_ORG="Fort-Funston"
+export KEY_EMAIL="me@myhost.mydomain"
+export KEY_EMAIL=mail@host.domain
 export KEY_CN=changeme
 export KEY_NAME=changeme
-export KEY_OU=IT Department
+export KEY_OU=changeme
 export PKCS11_MODULE_PATH=changeme
-export PKCS11_PIN=7266
+export PKCS11_PIN=1234

edit openssl-1.0.0.cnf

--- openssl-1.0.0.cnf   2016-10-11 09:56:47.895473062 +0300
+++ /usr/share/doc/openvpn/examples/easy-rsa/2.0/openssl-1.0.0.cnf      2011-07-01 12:31:26.000000000 +0400
@@ -182,7 +182,7 @@
 # keyUsage = nonRepudiation, digitalSignature, keyEncipherment

 # This will be displayed in Netscape's comment listbox.
-nsComment                      = "ACME certfication"
+nsComment                      = "Easy-RSA Generated Certificate"

 # PKIX recommendations harmless if included in all certificates.
 subjectKeyIdentifier=hash
@@ -193,10 +193,10 @@

 # This stuff is for subjectAltName and issuerAltname.
 # Import the email address.
-subjectAltName = "DNS.1:example.com,DNS.2:*.example.com"
+# subjectAltName=email:copy

 # Copy subject details
-issuerAltName=issuer:copy
+# issuerAltName=issuer:copy

 #nsCaRevocationUrl             = http://www.domain.dom/ca-crl.pem
 #nsBaseUrl
@@ -210,8 +210,7 @@
 # JY ADDED -- Make a cert with nsCertType set to "server"
 basicConstraints=CA:FALSE
 nsCertType                     = server
-nsComment                      = "ACME certification"
-subjectAltName="DNS.1:example.com,DNS.2:*.example.com"
+nsComment                      = "Easy-RSA Generated Server Certificate"
 subjectKeyIdentifier=hash
 authorityKeyIdentifier=keyid,issuer:always
 extendedKeyUsage=serverAuth
@@ -251,9 +250,9 @@
 # nsCertType = sslCA, emailCA

 # Include email address in subject alt name: another PKIX recommendation
-subjectAltName="DNS.1:example.com,DNS.2:*.example.com"
+# subjectAltName=email:copy
 # Copy issuer details
-issuerAltName=issuer:copy
+# issuerAltName=issuer:copy

 # DER hex encoding of an extension: beware experts only!
 # obj=DER:02:03

pkitool:

+++ /usr/share/doc/openvpn/examples/easy-rsa/2.0/pkitool        2011-04-27 13:52:59.000000000 +0400
@@ -322,7 +322,7 @@

     # Build root CA
     if [ $DO_ROOT -eq 1 ]; then
-       $OPENSSL req $BATCH -days $CA_EXPIRE $NODES_REQ -new -newkey rsa:$KEY_SIZE -sha256 \
+       $OPENSSL req $BATCH -days $CA_EXPIRE $NODES_REQ -new -newkey rsa:$KEY_SIZE -sha1 \
            -x509 -keyout "$CA.key" -out "$CA.crt" -config "$KEY_CONFIG" && \
            chmod 0600 "$CA.key"
     else        
@@ -347,7 +347,7 @@
                echo "Generating key pair on PKCS#11 token..."
                $PKCS11TOOL --module "$PKCS11_MODULE_PATH" --keypairgen \
                        --login --pin "$PKCS11_PIN" \
-                       --key-type rsa:4096 \
+                       --key-type rsa:1024 \
                        --slot "$PKCS11_SLOT" --id "$PKCS11_ID" --label "$PKCS11_LABEL" || exit 1
                PKCS11_ARGS="-engine pkcs11 -keyform engine -key $PKCS11_SLOT:$PKCS11_ID"
        fi
@@ -356,7 +356,7 @@
        ( [ $DO_REQ -eq 0 ] || $OPENSSL req $BATCH -days $KEY_EXPIRE $NODES_REQ -new -newkey rsa:$KEY_SIZE \
                -keyout "$FN.key" -out "$FN.csr" $REQ_EXT -config "$KEY_CONFIG" $PKCS11_ARGS ) && \
            ( [ $DO_CA -eq 0 ]  || $OPENSSL ca $BATCH -days $KEY_EXPIRE -out "$FN.crt" \
-               -in "$FN.csr" $CA_EXT -md sha256 -config "$KEY_CONFIG" ) && \
+               -in "$FN.csr" $CA_EXT -md sha1 -config "$KEY_CONFIG" ) && \
            ( [ $DO_P12 -eq 0 ] || $OPENSSL pkcs12 -export -inkey "$FN.key" \
                -in "$FN.crt" -certfile "$CA.crt" -out "$FN.p12" $NODES_P12 ) && \
            ( [ $DO_CA -eq 0 -o $DO_P11 -eq 1 ]  || chmod 0600 "$FN.key" ) && \

Creating key infrastructure

First thing to do is to build certificate authority. It can sign other certificates and validate them.

root@debian:/etc/.keys-infrastructure# ./build-ca
Generating a 4096 bit RSA private key
...................................................................++
....................++
writing new private key to 'ca.key'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [US]:
State or Province Name (full name) [CA]:
Locality Name (eg, city) [SanFrancisco]:
Organization Name (eg, company) [ACME]:
Organizational Unit Name (eg, section) [IT]:IT Department
Common Name (eg, your name or your server's hostname) [changeme]:exmaple.com
Name [changeme]:ca
Email Address [info@example.com]:

Next we'll build and sign key and certificate for our server.

root@debian:/etc/.keys-infrastructure# ./build-key-server my-nginx
Generating a 4096 bit RSA private key
...........................++
.................
writing new private key to 'my-nginx.key'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [US]:
State or Province Name (full name) [CA]:
Locality Name (eg, city) [SanFrancisco]:
Organization Name (eg, company) [ACME]:
Organizational Unit Name (eg, section) [IT]:IT Department
Common Name (eg, your name or your server's hostname) [nginx]:example.com
Name [changeme]:nginx
Email Address [info@example.com]:

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
Using configuration from /etc/.keys-infrastructure/openssl-1.0.0.cnf
Check that the request matches the signature
Signature ok
The Subject's Distinguished Name is as follows
countryName           :PRINTABLE:'US'
stateOrProvinceName   :PRINTABLE:'CA'
localityName          :PRINTABLE:'SanFrancisco'
organizationName      :PRINTABLE:'ACME'
organizationalUnitName:PRINTABLE:'IT Department'
commonName            :PRINTABLE:'exmaple.com'
name                  :PRINTABLE:'nginx'
emailAddress          :IA5STRING:'info@exmaple.com'
Certificate is to be certified until Oct 11 07:00:59 2017 GMT (365 days)
Sign the certificate? [y/n]:y


1 out of 1 certificate requests certified, commit? [y/n]y
Write out database with 1 new entries
Data Base Updated

Managing clients

When client connects to our server, she must provide signed certificate. To be able to encrypt data, she also must have private key. Let's create it

root@debian:/etc/.keys-infrastructure# ./build-key alice
Generating a 4096 bit RSA private key
....................................
......++
writing new private key to 'alice.key'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [US]:
State or Province Name (full name) [CA]:
Locality Name (eg, city) [SanFrancisco]:
Organization Name (eg, company) [ACME]:
Organizational Unit Name (eg, section) [IT]:IT Department
Common Name (eg, your name or your server's hostname) [alice]:
Name [changeme]:alice
Email Address [info@example.com]:alice@example.com

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
Using configuration from /etc/.keys-infrastructure/openssl-1.0.0.cnf
Check that the request matches the signature
Signature ok
The Subject's Distinguished Name is as follows
countryName           :PRINTABLE:'US'
stateOrProvinceName   :PRINTABLE:'CA'
localityName          :PRINTABLE:'SanFrancisco'
organizationName      :PRINTABLE:'ACME'
organizationalUnitName:PRINTABLE:'IT Department'
commonName            :PRINTABLE:'alice'
name                  :PRINTABLE:'alice'
emailAddress          :IA5STRING:'alice@example.com'
Certificate is to be certified until Oct 11 07:02:12 2017 GMT (365 days)
Sign the certificate? [y/n]:y

1 out of 1 certificate requests certified, commit? [y/n]y
Write out database with 1 new entries
Data Base Updated

Sometimes cilent need p12 certificate with private key in it. You can get it with the following command:

openssl pkcs12 -export -in alice.crt -inkey alice.key -out alice.p12 -CAfile ca.crt -caname ACME

We would call revoke-full if we decided to restrict Alice access to the server. This command will update crl.pem file, containing revoke certificates.

root@debian:/etc/.keys-infrastructure# ./revoke-full unwanted
Using configuration from /etc/.keys-infrastructure/openssl-1.0.0.cnf
Revoking Certificate 02.
Data Base Updated
Using configuration from /etc/.keys-infrastructure/openssl-1.0.0.cnf
alice.crt: C = US, ST = CA, L = SanFrancisco, O = ACME, OU = IT Department, CN = alice, name = alice, emailAddress = alice@example.com
error 23 at 0 depth lookup:certificate revoked

Note the "error 23" in the last line. It is normal - it indicates that a certificate verification of the revoked certificate failed.

Setting up nginx server

Nginx server configuration section:

server {
    listen 127.0.0.1:443;
    server_name localhost;

    ssl on;
    ssl_certificate /etc/ssl/nginx/nginx.crt;
    ssl_certificate_key /etc/ssl/nginx/nginx.key;
    ssl_client_certificate /etc/ssl/nginx/ca.crt;
    ssl_crl /etc/ssl/nginx/crl.pem;
    ssl_verify_client on;

    access_log /var/log/nginx/localhost.ssl_access_log main;
    error_log /var/log/nginx/localhost.ssl_error_log info;

    location / {
        root /var/www/localhost/htdocs;
    }
}

Client examples

Browser

Alice need to import ca.crt in the Certificate Authorities section and allow it to identify cites. In Personal section she need to import her p12 certificate.

Curl

We need to add private key into Alice's certificate. We can just concatenate it:

cp alice.crt alice.pem
cat alice.key >> alice.pem
curl --cacert ca.crt -E alice.pem https://example.com

Python

It's very easy with help of Requests library.

rs = requests.get('https://example.com', verify='/path/to/ca.crt', cert=('/path/to/alice.crt', '/path/to/alice.key')

Comments

comments powered by Disqus