Creando tu propia Autoridad Certificadora (CA)

En esta entrada os voy a explicar para qué sirve una autoridad certificadora y como podemos crear una propia. Como siempre sin mucho rollo y al grano. Que no se enfade nadie por las incorrecciones teóricas, pero no es el objetivo de esta entrada ser teóricamente correcto, sino 100% práctico.

Una autoridad certificadora (en adelante CA, de Certificate Authority) es una entidad emisora de certificados digitales. Y ¿para qué sirve un certificado digital? Básicamente para validar documentos y para cifrar comunicaciones. Esta segunda utilidad es la que vamos a ver en esta entrada.

Los certificados están compuestos por dos partes, una, la clave privada que sirve para cifrar lo que enviamos, y la clave pública que sirve para que otros cifren lo que nos quieren enviar. Muchas veces a la clave privada se la llama clave (o key en inglés) y a la clave pública, se la llama certificado (certificate en inglés). La clave privada no la deberemos desvelar jamás ya que cualquiera que la tuviera se podría hacer pasar por nosotros (por nuestro servidor web seguro, o incluso por nuestra CA).

¿Cómo sabemos que un certificado es válido? Fácil, porque alguien en quien confiamos nos dice que ese certificado es valido, es decir, alguien le ha puesto su firma indicándonos que es válido. Esa es la utilidad de la CA.

Cuando estamos navegando por Internet, y accedemos a cualquier página por HTTPS, quiere decir que esa web utiliza un certificado. ¿Como sabe nuestro navegador que ese certificado es válido? Pues porque cuando nos instalamos el navegador, también se instala una lista de certificados (en realidad son solo sus claves públicas) de autoridades certificadoras en las que se confía (Verisign, FNMT, Go Daddy, Entrust…).

Entonces tenemos el siguiente escenario: la autoridad certificadora (CA) crea un certificado (clave pública y clave privada) firmado por ella misma, y lo vende a una empresa para que lo use en su servidor web para cifrar las comunicaciones usando HTTPS.

Imaginaos ahora que queréis montar un servidor web seguro y queréis usar HTTPS, o compráis un certificado a una CA oficial pagando el dineral que valen u os creáis una propia… La misma situación la tenemos para montar un servidor de correo seguro, para montar uno MQTT con certificados, o simplemente para crear una VPN que use certificados. La única pega es que tendréis que instalar el certificado (la clave pública) de vuestra CA en todos los equipos que vayan a usar sus certificados, o cada vez que se haga uso os aparecerá el molesto mensaje de que se están usando certificados emitidos por una CA en la que no se confía.

En mi caso, tengo un servidor web, varios túneles VPN, un servidor MQTT y varios servidores SSH. Ya me estoy cansando de tantas contraseñas. Necesito una CA para emitir certificados para todos, que las comunicaciones se cifren, y que todo esté centralizado y sea fácil de administrar. Vamos a ello.

Estructura de directorios y fichero de configuración

Usaremos OpenSSL para crear toda la infraestructura de la autoridad, y todos los certificados, bajo Ubuntu.

Lo primero es crear la estructura de directorios adecuada y el archivo de configuración principal, para ello ejecutamos:

root@servidor:/# mkdir /etc/CA
root@servidor:/# cd /etc/CA
root@servidor:/etc/CA# mkdir certs crl csr ewcerts private
root@servidor:/etc/CA# chmod 700 private

creamos el archivo /etc/CA/openssl.cnf con el siguiente contenido:

# OpenSSL, fichero de configuracion para una CA raiz.

[ ca ]
default_ca = CA_default

[ CA_default ]
# Ubicaciones por defectos de ficheros y directorios.
dir               = /etc/CA
certs             = $dir/certs
crl_dir           = $dir/crl
new_certs_dir     = $dir/newcerts
database          = $dir/index.txt
serial            = $dir/serial
RANDFILE          = $dir/private/.rand

# La clave privada y el certificado raiz.
private_key       = $dir/private/ca.key.pem
certificate       = $dir/certs/ca.cert.pem

# Para las listas de certificados revocados
crlnumber         = $dir/crlnumber
crl               = $dir/crl/ca.crl.pem
crl_extensions    = crl_ext
default_crl_days  = 30

default_md        = sha256

name_opt          = ca_default
cert_opt          = ca_default
default_days      = 3750
preserve          = no
policy            = policy_strict

[ policy_strict ]
# The root CA should only sign intermediate certificates that match.
# See the POLICY FORMAT section of `man ca`.
countryName             = match
stateOrProvinceName     = match
organizationName        = match
organizationalUnitName  = optional
commonName              = supplied
emailAddress            = optional

[ policy_loose ]
# Allow the intermediate CA to sign a more diverse range of certificates.
# See the POLICY FORMAT section of the `ca` man page.
countryName             = optional
stateOrProvinceName     = optional
localityName            = optional
organizationName        = optional
organizationalUnitName  = optional
commonName              = supplied
emailAddress            = optional

[ req ]
# Opciones por defecto para 'openssl req'
default_bits        = 2048
distinguished_name  = req_distinguished_name
string_mask         = utf8only

default_md          = sha256

x509_extensions     = v3_ca

[ req_distinguished_name ]
# See <https://en.wikipedia.org/wiki/Certificate_signing_request>.
countryName                     = Country Name (2 letter code)
stateOrProvinceName             = State or Province Name
localityName                    = Locality Name
0.organizationName              = Organization Name
organizationalUnitName          = Organizational Unit Name
commonName                      = Common Name
emailAddress                    = Email Address

# Algunos valores por defecto
countryName_default             = ES
stateOrProvinceName_default     = Spain
localityName_default            =
0.organizationName_default      = Mi Organizacion
organizationalUnitName_default  =
emailAddress_default            =

[ v3_ca ]
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = critical, CA:true
keyUsage = critical, digitalSignature, cRLSign, keyCertSign

[ usr_cert ]
# Extensiones para los certificados de clientes
basicConstraints = CA:FALSE
nsCertType = client, email
nsComment = "Client Certificate"
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer
keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment
extendedKeyUsage = clientAuth, emailProtection

[ server_cert ]
# Extensiones para los certificados de servidor
basicConstraints = CA:FALSE
nsCertType = server
nsComment = "Server Certificate"
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer:always
keyUsage = critical, digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth

[ crl_ext ]
# Extensiones para CRLs (Listas de revocacion de certificados)
authorityKeyIdentifier=keyid:always

[ ocsp ]
# Extension for OCSP signing certificates (`man ocsp`).
basicConstraints = CA:FALSE
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer
keyUsage = critical, digitalSignature
extendedKeyUsage = critical, OCSPSigning

 

En la sección  [req_distinguished_name] podemos encontrar algunos parámetros por defecto interesantes como son: countryName_default, stateOrProvinceName_default y 0.organizationName_default, que deberíamos ajustar con nuestros valores personalizados.

Las secciones [v3_ca], [v3_intermediate_ca], [usr_cert], [server_cert] y [ocsp] definen los valores por defecto de los distintos tipos de certificados que vamos a poder crear más adelante.

Creación de la clave privada y el certificado raíz de la CA

Ahora podemos crear la pareja de claves. Primero la clave privada de la CA:

root@servidor:/# cd /etc/CA
root@servidor:/etc/CA# openssl genrsa -aes256 -out private/ca.key.pem 4096
Generating RSA private key, 4096 bit long modulus
........................................................................................................++
.................................++
e is 65537 (0x10001)
Enter pass phrase for private/ca.key.pem: miclavesecreta
Verifying - Enter pass phrase for private/ca.key.pem: miclavesecreta

root@servidor:/etc/CA# chmod 400 private/ca.key.pem

Ahora podemos crear el certificado raíz (clave pública) de la CA usando la clave privada anterior:

root@servidor:/etc/CA# openssl req -config openssl.cnf  -key private/ca.key.pem -new -x509 -days 3650 -sha256 -extensions v3_ca -out certs/ca.cert.pem
Enter pass phrase for private/ca.key.pem: miclavesecreta
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) [ES]:
State or Province Name [Spain]:
Locality Name []:
Organization Name [Mi Organizacion]:
Organizational Unit Name []:
Common Name []:Certificado CA
Email Address []:
root@servidor:/etc/CA# chmod 444 certs/ca.cert.pem

Podemos verificar el certificado recien creado con el comando:

root@servidor:/etc/CA# openssl x509 -noout -text -in certs/ca.cert.pem

A partir de este momento ya podemos crear certificados para nuestros servidores (MQTT, SSH, HTTPS, …) y para autenticar clientes (moviles, clientes VPN, …).

 

Asegurando nuestro servidor web Apache2

Como primer ejemplo vamos a crear un par de claves privada y publica (key & certificate) para usar con Apache2 y permitir el trafico HTTPS usando nuestra flamante CA. Primero creamos la clave privada:

root@servidor:/etc/CA# openssl genrsa -out private/webserver.key.pem 2048
Generating RSA private key, 2048 bit long modulus
............................................+++
.................................................+++
e is 65537 (0x10001)

El segundo paso es crear la petición formal de certificado:

root@servidor:/etc/CA# openssl req -config openssl.cnf -key private/webserver.key.pem -new -sha256 -out csr/webserver.csr.pem
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) [ES]:
State or Province Name [Spain]:
Locality Name []:
Organization Name [Mi Organizacion]:
Organizational Unit Name []:
Common Name []:servidor web
Email Address []:

Finalmente, nuestra CA firma la petición de certificado anterior y se genera el certificado del servidor web, válido 5 años (1825 días):

root@servidor:/etc/CA# openssl ca -config openssl.cnf -extensions server_cert -days 1825 -notext -md sha256 -in csr/webserver.csr.pem -out certs/webserver.cert.pem
Using configuration from openssl.cnf
Enter pass phrase for /etc/CA/private/ca.key.pem:
Check that the request matches the signature
Signature ok
     Certificate Details:
          Serial Number: 4096 (0x1000)
          Validity
               Not Before: Oct 21 11:53:45 2015 GMT
               Not After : Oct 19 11:53:45 2020 GMT
          Subject:
               countryName = ES
               stateOrProvinceName = Spain
               organizationName = Mi Organizacion
               commonName = servidor web
          X509v3 extensions:
               X509v3 Basic Constraints:
                    CA:FALSE
               Netscape Cert Type:
                    SSL Server
               Netscape Comment:
                    Server Certificate
               X509v3 Subject Key Identifier:
                    42:F9:B4:10:62:19:4D:10:7D:6E:54:B7:57:7A:59:A4:C6:11:EF:F5
               X509v3 Authority Key Identifier:
                    keyid:F8:FA:06:AD:9C:AF:C4:10:F4:17:34:D0:BE:FC:87:01:70:8F:6E:37
                    DirName:/C=ES/ST=Spain/O=Mi Organizacion/CN=Certificado CA
                    serial:A8:57:70:1D:D9:C5:D4:1B

               X509v3 Key Usage: critical
                    Digital Signature, Key Encipherment
               X509v3 Extended Key Usage:
                    TLS Web Server Authentication
Certificate is to be certified until Oct 19 11:53:45 2020 GMT (1825 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

root@servidor:/etc/CA# chmod 444 certs/webserver.cert.pem

Una ves que ya tenemos la clave privada, la publica y el certificado de la CA tenemos que ir a nuestro archivo donde se define el virtualhost del servidor y añadir las directivas:

SSLEngine on
SSLCertificateFile /etc/CA/certs/webserver.cert.pem
SSLCertificateKeyFile /etc/CA/private/webserver.key.pem
SSLCertificateChainFile /etc/CA/certs/ca.cert.pem

Asegurando Mosquitto (MQTT)

De la misma forma podemos asegurar nuestro servidor mosquitto (MQTT):

root@servidor:/etc/CA# openssl genrsa -out private/mosquitto_jdomo.key.pem 2048
Generating RSA private key, 2048 bit long modulus
.............................................+++
...............+++
e is 65537 (0x10001)

root@servidor:/etc/CA# openssl req -config openssl.cnf -key private/mosquitto_jdomo.key.pem -new -sha256 -out csr/mosquitto_jdomo.csr.pem
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) [ES]:
State or Province Name [Spain]:
Locality Name []:
Organization Name [Mi Organizacion]:
Organizational Unit Name []:
Common Name []:servidor mqtt jdomo
Email Address []:

root@servidor:/etc/CA# openssl ca -config openssl.cnf -extensions server_cert -days 1825 -notext -md sha256 -in csr/mosquitto_jdomo.csr.pem -out certs/mosquitto_jdomo.cert.pem
Using configuration from openssl.cnf
Enter pass phrase for /etc/CA/private/ca.key.pem:
Check that the request matches the signature
Signature ok
Certificate Details:
Serial Number: 4101 (0x1005)
Validity
Not Before: Nov 24 08:51:43 2015 GMT
Not After : Nov 22 08:51:43 2020 GMT
Subject:
countryName               = ES
stateOrProvinceName       = Spain
organizationName          = Mi Organizacion
commonName                = servidor mqtt jdomo
X509v3 extensions:
X509v3 Basic Constraints:
CA:FALSE
Netscape Cert Type:
SSL Server
Netscape Comment:
Server Certificate
X509v3 Subject Key Identifier:
4A:93:B2:A7:07:9F:74:EE:C3:38:F6:D7:E1:79:72:DC:A6:F9:FA:8F
X509v3 Authority Key Identifier:
keyid:F8:FA:06:AD:9C:AF:C4:10:F4:17:34:D0:BE:FC:87:01:70:8F:6E:37
DirName:/C=ES/ST=Spain/O=Mi Organizacion/CN=Certificado CA
serial:A8:57:70:1D:D9:C5:D4:1B

X509v3 Key Usage: critical
Digital Signature, Key Encipherment
X509v3 Extended Key Usage:
TLS Web Server Authentication
Certificate is to be certified until Nov 22 08:51:43 2020 GMT (1825 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

root@sanvi:/etc/CA# chmod 444 certs/mosquitto_jdomo.cert.pem

Una vez que tenemos los ficheros generados, los copiamos al servidor junto con el certificado de la CA y modificamos el fichero de configuración de mosquitto para espeficarle las nuevas rutas de los tresarchivos:

...
cafile /etc/mosquitto/miCA/ca.cert.pem
certfile /etc/mosquitto/miCA/mosquitto_jdomo.cert.pem
keyfile /etc/mosquitto/miCA/mosquitto_jdomo.key.pem
...

Certificados de usuario

Si lo que queremos es autenticar algún usuario mediante un certificado, por ejemplo, que nuestro servidor web requiera que el usuario que accede se identifique mediante certificado, el procecimiento es exactamente el mismo que para crear los certificados de servidor, pero cambiando en el comando openssl la parte -extensions server_cert por -extensions usr_cert.

Si lo que vamos a hacer es instalar el certificado de usuario en un navegador, necesitaremos el fichero P12 o PFX, que no es más que la clave privada, la pública y el certificado del servidor todo en uno. Para generarlo usamos el siguiente comando:

openssl pkcs12 -export -out jose.pfx -inkey private/jose.key.pem -in certs/jose.cert.pem -certfile certs/jose.cert.pem
Enter Export Password: 1234
Verifying - Enter Export Password: 1234

El comando anterior nos pide una clave de exportación (‘1234‘), que mas tarde nos pedirá el navegador para realizar la importación.

A partir de ahora cada vez que necesitemos un certificado, iremos a nuestro servidor que tenga la CA configurada, emitiremos uno nuevo, lo llevamos donde corresponda y listo.

Espero que os sirva para tener más organizado vuestro sistema 🙂

6 comentarios

Añadir un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.