Tuesday, March 03, 2015

Creating a HTTPS client authentication based web server with CRL.

Ok.

I am in need of a web server that uses HTTPS client certificate authentication.

I think this should keep those without the client cert off my https! :P

Lets start

Lets create a directory to store every thing

Lets echo a number for our CRLNumber file ( CRL number is for the next number for the next cert )
echo 1000 > crlnumber

Lets touch an index. ( A database of all the certs in there )
touch index.txt

Lets create an openssl.cnf file. This will be the config file passed in to all the commands.
===== Start ===== 
dir = /xxx

[ ca ]
default_ca      = CA_default

[ CA_default ]
serial = $dir/crlnumber
new_certs_dir = $dir/certs
database = $dir/index.txt
policy = policy_match
default_days = 365
default_md = md5
default_crl_days = 1

[ policy_match ]
countryName = match
stateOrProvinceName = match
organizationName = match
organizationalUnitName = optional
commonName = supplied
emailAddress = optional

[ usr_cert ]
# These extensions are added when 'ca' signs a request.
basicConstraints=CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
nsComment = "OpenSSL Generated Certificate"
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid,issuer

[ v3_ca ]
# Extensions for a typical CA
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid:always,issuer
basicConstraints = CA:true
keyUsage = cRLSign, keyCertSign

[ req ]
distinguished_name      = req_distinguished_name
string_mask = utf8only


[ req_distinguished_name ]
countryName                     = Country Name (2 letter code)
countryName_default             = SG
countryName_min                 = 2
countryName_max                 = 2

stateOrProvinceName             = State or Province Name (full name)
stateOrProvinceName_default     = Singapore

localityName                    = Locality Name (eg, city)
localityName_default            = Singapore

0.organizationName              = Organization Name (eg, company)
0.organizationName_default      = XXX

# we can do this but it is not needed normally :-)
#1.organizationName             = Second Organization Name (eg, company)
#1.organizationName_default     = World Wide Web Pty Ltd

organizationalUnitName          = Organizational Unit Name (eg, section)
#organizationalUnitName_default =

commonName                      = Common Name (e.g. server FQDN or YOUR name)
commonName_max                  = 64

emailAddress                    = Email Address
emailAddress_max                = 64

# SET-ex3                       = SET extension number 3

===== Start ===== 

Lets create a CA ( Remember the password )
openssl genrsa -aes256 -out ca.key.pem 4096

Lets create the cert out of the key!
openssl req -new -x509 -days 3650 -key ca.key.pem -sha256 -extensions v3_ca -out ca.cert.pem

Ok, the CA seems to be fixed now.

Lets create our apache web server key and cert
openssl genrsa -out server.key.pem 4096

Create a CSR out of it
openssl req -sha256 -new -key server.key.pem -out server.csr.pem

Lets sign it
openssl ca -keyfile ca.key.pem -cert ca.cert.pem -extensions usr_cert -notext -md sha256 -in server.csr.pem -out server.cert.pem -config openssl.cnf

Lets fix Apache
SSLEngine on
SSLCertificateFile    /xxx/server.cert.pem
SSLCertificateKeyFile /xxx/server.key.pem
SSLCACertificateFile /xxx/ca.cert.pem

Now your apache should be HTTPS enabled.
Though you should get a cert not trusted sign.

Lets move on to allow our clients to login...
SSLCARevocationFile /xxx/crl.pem
SSLVerifyClient require
SSLVerifyDepth  1

==== Create user script
#!/bin/bash

echo "Creating Private Key for $1"
openssl genrsa -out $1.key.pem 4096

echo "Creating CSR for $1"
openssl req -new -key $1.key.pem -out $1.csr.pem -config openssl.cnf

echo "Signing CSR from CA Key"
openssl ca -keyfile ca.key.pem -cert ca.cert.pem -extensions usr_cert -notext -md sha1 -in $1.csr.pem -out $1.cert.pem -config openssl.cnf

echo "Creating P12 keys"
openssl pkcs12 -export -clcerts -in $1.cert.pem -inkey $1.key.pem -out $1.p12
==== Create user script

==== revokeUser.sh
#!/bin/bash

echo "Revoke user: $1"
openssl ca -keyfile ca.key.pem -cert ca.cert.pem -revoke $1.cert.pem -config openssl.cnf
clear
echo "Generating new CRL"
openssl ca -keyfile ca.key.pem -cert ca.cert.pem -gencrl -out crl.pem -config openssl.cnf

/etc/init.d/apache2 restart

==== revokeUser.sh

To create the user ./createUser.sh nameofuser
To revoke ./revokeUser.sh nameofuser