Apache SSL certificado cliente, configurar Apache para permitir solo accesos SSL con certificado instalado en cliente

Vamos a configurar Apache (sobre un Ubuntu 12) para permitir el acceso de clientes que tengan un certificado SSL personal instalado, primero tenemos que crear algunas estructuras para poder más tarde trabajar con listas de revocación.

Lo primero es tener instalado openssl:

ubuntu@ip-10-112-31-82:~$ sudo aptitude install openssl

Crearemos una estructura de directorios que se ajuste a las rutas esperadas por el fichero de configuración openssl.cnf:

Source   
ubuntu@ip-10-112-31-82:~$ mkdir -p /vol/apache2_certs
ubuntu@ip-10-112-31-82:~$ cd /vol/apache2_certs/
ubuntu@ip-10-112-31-82:/vol/apache2_certs$ sudo cp /etc/ssl/openssl.cnf .

El fichero openssl.cnf define una estructura de directorios para poder trabajar entre otras cosas con listas de denegación de certificados, vamos a editarlo y moficicar la linea:

Source   
dir = ./demoCA

por:

Source   
dir = /vol/apache2_certs

Y para no tener sorpresas con la caducidad del certificado crl:

Source   
default_crl_days= 30

por

Source   
default_crl_days= 3650

En este fichero hay muchas referencias a la variable $dir si hacemos:

Source   
ubuntu@ip-10-112-31-82:/vol/apache2_certs$ cat openssl.cnf | grep '$dir'
certs = $dir/certs # Where the issued certs are kept
crl_dir = $dir/crl # Where the issued crl are kept
database = $dir/index.txt # database index file.
new_certs_dir = $dir/newcerts # default place for new certs.
certificate = $dir/cacert.pem # The CA certificate
serial = $dir/serial # The current serial number
crlnumber = $dir/crlnumber # the current crl number
crl = $dir/crl.pem # The current CRL
private_key = $dir/private/cakey.pem# The private key
RANDFILE = $dir/private/.rand # private random number file
serial = $dir/tsaserial # The current serial number (mandatory)
signer_cert = $dir/tsacert.pem # The TSA signing certificate
certs = $dir/cacert.pem # Certificate chain to include in reply
signer_key = $dir/private/tsakey.pem # The TSA private key (optional)

Algunas de las referencias son a directorios que deberíamos crear para que existan todos los destinos:

Source   
ubuntu@ip-10-112-31-82:/vol/apache2_certs$ sudo mkdir -p newcerts private
ubuntu@ip-10-112-31-82:/vol/apache2_certs$ ls -l
total 20
drwxr-xr-x 2 root root 4096 Apr 10 09:53 newcerts
-rw-r--r-- 1 root root 10845 Apr 10 09:51 openssl.cnf
drwxr-xr-x 2 root root 4096 Apr 10 09:53 private

Ahora vamos a generar los certificados necesarios manteniendo el nombre que espera encontrar el fichero de configuración openssl.cnf.

Creación de certificado, petición de firma y firma de entidad certificadora:

Source   
#creación key
ubuntu@ip-10-112-31-82:/vol/apache2_certs$ sudo openssl genrsa -out /vol/apache2_certs/private/cakey.pem 1024
Generating RSA private key, 1024 bit long modulus
..++++++
................++++++
e is 65537 (0x10001)
#petición de firma
ubuntu@ip-10-112-31-82:/vol/apache2_certs$ sudo openssl req -new -key /vol/apache2_certs/private/cakey.pem -out /vol/apache2_certs/private/cacsr.csr
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) [AU]:ES
State or Province Name (full name) [Some-State]:ANDALUCIA
Locality Name (eg, city) []:SEVILLA
Organization Name (eg, company) [Internet Widgits Pty Ltd]:ACME
Organizational Unit Name (eg, section) []:
Common Name (e.g. server FQDN or YOUR name) []:
Email Address []:
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
#firma
ubuntu@ip-10-112-31-82:/vol/apache2_certs$ sudo openssl x509 -req -days 3650 -in /vol/apache2_certs/private/cacsr.csr -signkey /vol/apache2_certs/private/cakey.pem -out /vol/apache2_certs/cacert.pem
Signature ok
subject=/C=ES/ST=ANDALUCIA/L=SEVILLA/O=ACME
Getting Private key

Ahora crearemos un certificado web para el servidor Apache, url ssl.acme.es, lo firmará la autoridad certificadora creada anteriormente:

Source   
#creación de clave
ubuntu@ip-10-112-31-82:/vol/apache2_certs$ sudo openssl genrsa -out /vol/apache2_certs/private/ssl.acme.es.key.pem 1024
Generating RSA private key, 1024 bit long modulus
.................................................++++++
....++++++
e is 65537 (0x10001)
#peticion de firma
ubuntu@ip-10-112-31-82:/vol/apache2_certs$ sudo openssl req -new -key /vol/apache2_certs/private/ssl.acme.es.key.pem -out /vol/apache2_certs/private/ssl.acme.es.csr
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) [AU]:ES
State or Province Name (full name) [Some-State]:ANDALUCIA
Locality Name (eg, city) []:SEVILLA
Organization Name (eg, company) [Internet Widgits Pty Ltd]:ACME
Organizational Unit Name (eg, section) []:
Common Name (e.g. server FQDN or YOUR name) []:ssl.acme.es
Email Address []:
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
#firma por la autoridad certificadora
ubuntu@ip-10-112-31-82:/vol/apache2_certs$ sudo openssl x509 -req -days 3650 -CA /vol/apache2_certs/cacert.pem -CAkey /vol/apache2_certs/private/cakey.pem -CAcreateserial -CAserial /vol/apache_cert/serial -in /vol/apache2_certs/private/ssl.acme.es.csr -out /vol/apache2_certs/ssl.acme.es.crt.pem
Signature ok
subject=/C=ES/ST=ANDALUCIA/L=SEVILLA/O=ACME/CN=ssl.acme.es
Getting CA Private Key

Ahora vamos a crear un certificado personal y su versión para navegador para instalar en el cliente, para más tarde configurar apache. Primero crearemos un directorio para tener los certificados personales localizados perfectamente:

Source   
ubuntu@ip-10-112-31-82:/vol/apache2_certs$ sudo mkdir /vol/apache2_certs/certs_people
#creamos clave
ubuntu@ip-10-112-31-82:/vol/apache2_certs$ sudo openssl genrsa -out /vol/apache2_certs/certs_people/55555555X.pem 1024
Generating RSA private key, 1024 bit long modulus
...................................++++++
...................................++++++
e is 65537 (0x10001)
#petición de firma
ubuntu@ip-10-112-31-82:/vol/apache2_certs$ sudo openssl req -new -key /vol/apache2_certs/certs_people/55555555X.pem -out /vol/apache2_certs/certs_people/55555555X.csr
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) [AU]:ES
State or Province Name (full name) [Some-State]:ANDALUCIA
Locality Name (eg, city) []:SEVILLA
Organization Name (eg, company) [Internet Widgits Pty Ltd]:ACME
Organizational Unit Name (eg, section) []:IT
Common Name (e.g. server FQDN or YOUR name) []:Jonh Doe
Email Address []:jdoe@acme.es
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
#Firma con la autoridad certificadora
ubuntu@ip-10-112-31-82:/vol/apache2_certs$ sudo openssl x509 -req -days 3650 -CA /vol/apache2_certs/cacert.pem -CAkey /vol/apache2_certs/private/cakey.pem -CAcreateserial -CAserial /vol/apache_cert/serial -in /vol/apache2_certs/certs_people/55555555X.csr -out /vol/apache2_certs/certs_people/55555555X.crt.pem
Signature ok
subject=/C=ES/ST=ANDALUCIA/L=SEVILLA/O=ACME/OU=IT/CN=Jonh Doe/emailAddress=jdoe@acme.es
Getting CA Private Key
Ahora convertimos el certificado personarl para que pueda ser importado en un navegador (nos pide un password "prueba" para que será demandado durante la importación):
[codesyntax lang="bash"]
ubuntu@ip-10-112-31-82:/vol/apache2_certs$ sudo sudo openssl pkcs12 -export -clcerts -in /vol/apache2_certs/certs_people/55555555X.crt.pem -inkey /vol/apache2_certs/certs_people/55555555X.pem -out /vol/apache2_certs/certs_people/55555555X.p12
Enter Export Password:
Verifying - Enter Export Password:

Ahora tenemos que crear un fichero de revocación de certificados (crl.pem), un fichero de índice (index.txt) y el fichero de numeración (crlnumber):

Source   
#creación de fichero índice
ubuntu@ip-10-112-31-82:/vol/apache2_certs$ sudo touch /vol/apache2_certs/index.txt
#tengo que crear el fichero crlnumber con 01 (un número en hexa):
ubuntu@ip-10-112-31-82:/vol/apache2_certs$ sudo vi /vol/apache2_certs/crlnumber
ubuntu@ip-10-112-31-82:/vol/apache2_certs$ cat /vol/apache2_certs/crlnumber
01
#creación fichero crl.pem
ubuntu@ip-10-112-31-82:/vol/apache2_certs$ sudo openssl ca -config /vol/apache2_certs/openssl.cnf -gencrl -out /vol/apache2_certs/crl.pem
Using configuration from /vol/apache2_certs/openssl.cnf

Recapitulando un poco ahora tenemos un árbol de directorios y ficheros:

Source   
ubuntu@ip-10-112-31-82:/vol/apache2_certs$ tree
.
├── cacert.pem
├── certs_people
│   ├── 55555555X.crt.pem
│   ├── 55555555X.csr
│   ├── 55555555X.p12
│   └── 55555555X.pem
├── crlnumber
├── crlnumber.old
├── crl.pem
├── index.txt
├── newcerts
├── openssl.cnf
├── private
│   ├── cacsr.csr
│   ├── cakey.pem
│   ├── ssl.acme.es.csr
│   └── ssl.acme.es.key.pem
└── ssl.acme.es.crt.pem
3 directories, 15 files

Es decir tenemos:
-Una autoridad certificadora (ficheros cakey.pem, cacsr.csr y cacert.pem(
-Un certficado web para ssl.acme.es (ficheros ssl.acme.es.key.pem, ssl.acme.es.csr y ssl.acme.es.crt.pem), firmado por la autoridad certificadora.
-Un certificado personal para Jonh Doe (ficheros 55555555X.*), firmado por la autoridad certificadora.
-Ficheros necesarios para revocación de certificados (ficheros crlnumber, crlnumber.old, crl.pem y index.txt

Ahora pasamos a configurar Apache para que solo permita accesos SSL a navegadores con un certificado personal instalado (el de Jonh Doe).

Nos vamos al directorio de configuración de apache creamos un virtual host a partir del default-ssl:

Source   
ubuntu@ip-10-112-31-82:/etc/apache2/sites-enabled$ ls
000-default
#Si existe un virtual host default-ssl hay que dehabilitarlo
ubuntu@ip-10-112-31-82:/etc/apache2/sites-enabled$ sudo a2dissite default-ssl
#copiamos configuración base
ubuntu@ip-10-112-31-82:/etc/apache2/sites-enabled$ cd ../sites-available/
ubuntu@ip-10-112-31-82:/etc/apache2/sites-available$ sudo cp default-ssl ssl.acme.es

Editamos el fichero ssl.acme.es y tenemos que buscar y modificar las entradas:

Source   
SSLCertificateFile /vol/apache2_certs/ssl.acme.es.crt.pem
SSLCertificateKeyFile /vol/apache2_certs/private/ssl.acme.es.key.pem
SSLCACertificateFile /vol/apache2_certs/cacert.pem
SSLCARevocationFile /vol/apache2_certs/crl.pem
SSLVerifyClient require
SSLVerifyDepth 10

Activamos el virtual host y reiniciamos Apache:

Source   
ubuntu@ip-10-112-31-82:/etc/apache2/sites-available$ sudo a2ensite ssl.acme.es
Enabling site ssl.acme.es.
To activate the new configuration, you need to run:
service apache2 reload
ubuntu@ip-10-112-31-82:/etc/apache2/sites-available$ sudo /etc/init.d/apache2 restart
* Restarting web server apache2 ... waiting [ OK ]

Una vez instalado el certificado 55555555X.p12 podemos intentar acceder al https://ssl.acme.es. Durante el acceso confirmará el certifica a usar.

Es posible que aparezca un mensaje en el navegadro indicando que no es un sitio de confianza (y esas cosas tan poco tranquilizadoras), como este montaje está pensado para un entorno donde se distribuyen los certificados personales no es problema la importación de la autoridad certificadora en el navegador. Solo hay que importar el archivo cacert.pem.

Ahora vamos a revocar el certificado personal de Jonh Doe, recrear el fichero de revocación crl.pem y reload de apache:

Source   
#revocar certificado
ubuntu@ip-10-112-31-82:/vol/apache2_certs$ sudo openssl ca -config /vol/apache2_certs/openssl.cnf -revoke /vol/apache2_certs/certs_people/55555555X.crt.pem
Using configuration from /vol/apache2_certs/openssl.cnf
Adding Entry with serial number 8BE88F0198C75DDE to DB for /C=ES/ST=ANDALUCIA/L=SEVILLA/O=ACME/OU=IT/CN=Jonh Doe/emailAddress=jdoe@acme.es
Revoking Certificate 8BE88F0198C75DDE.
Data Base Updated
#regeneración del fichero crl.pem
ubuntu@ip-10-112-31-82:/vol/apache2_certs$ sudo openssl ca -config /vol/apache2_certs/openssl.cnf -gencrl -out /vol/apache2_certs/crl.pem
Using configuration from /vol/apache2_certs/openssl.cnf
#reload apache
ubuntu@ip-10-112-31-82:/vol/apache2_certs$ sudo /etc/init.d/apache2 reload
* Reloading web server config apache2 [ OK ]

Podemos ver los certificados revocados con:

Source   
ubuntu@ip-10-112-31-82:/vol/apache2_certs$ sudo openssl crl -text -noout -in /vol/apache2_certs/crl.pem
Certificate Revocation List (CRL):
Version 2 (0x1)
Signature Algorithm: sha1WithRSAEncryption
Issuer: /C=ES/ST=ANDALUCIA/L=SEVILLA/O=ACME
Last Update: Apr 10 12:26:52 2013 GMT
Next Update: May 10 12:26:52 2013 GMT
CRL extensions:
X509v3 CRL Number:
2
Revoked Certificates:
Serial Number: 8BE88F0198C75DDE
Revocation Date: Apr 10 12:24:33 2013 GMT
Signature Algorithm: sha1WithRSAEncryption
0d:6b:f6:db:52:52:fa:1e:dc:19:73:73:fc:41:71:43:8e:4e:
...
3d:5d

Donde el serial number 8BE88F0198C75DDE conincide con la información del certificado de Jonh Doe:

Source   
ubuntu@ip-10-112-31-82:/vol/apache2_certs/certs_people$ sudo openssl x509 -text -noout -in /vol/apache2_certs/certs_people/55555555X.crt.pem
Certificate:
Data:
Version: 1 (0x0)
Serial Number: 10081465002889797086 (0x8be88f0198c75dde)
Signature Algorithm: sha1WithRSAEncryption
Issuer: C=ES, ST=ANDALUCIA, L=SEVILLA, O=ACME
Validity
Not Before: Apr 10 11:09:19 2013 GMT
Not After : Apr 8 11:09:19 2023 GMT
Subject: C=ES, ST=ANDALUCIA, L=SEVILLA, O=ACME, OU=IT, CN=Jonh Doe/emailAddress=jdoe@acme.es
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (1024 bit)
Modulus:
00:c1:59:9b:97:33:c8:61:51:b8:22:bd:4a:37:64:
...
1a:30:6b:84:72:6e:25:07:83
Exponent: 65537 (0x10001)
Signature Algorithm: sha1WithRSAEncryption
29:35:98:08:02:fb:fd:86:f9:1b:15:26:26:bb:31:7d:f6:1f:
...
8c:84

Si se quiere volver a activar el uso de un certificado personal, simplemente hay que:
-Eliminar la entrada del certificado del fichero index.txt
-Regenerar el fichero crl.pem
-Hacer un reload de Apache

Y con esto se puede montar un sistema muy pero que muy seguro de acceso y revocación a servicios web.

2 thoughts on “Apache SSL certificado cliente, configurar Apache para permitir solo accesos SSL con certificado instalado en cliente

  1. Pingback: Autenticación de WebService por Certificado SSL – Linux Trucupei Blog

Deja un comentario