Pasaron casi 5 años y llegó el día menos pensado: mi script para verificar periódicamente la validez de los certificados en mi servidor me avisó que el certificado de mi CA autofirmada está por expirar. Y ahora, ¿quién podrá defendernos?

Este artículo explica cómo renovar el certificado de una CA autofirmada sin alterar el funcionamiento de los certificados válidos emitidos con anterioridad.



En el artículo Cómo crear tu propia autoridad certificante (CA) expliqué detalladamente cómo crear una CA para emitir certificados SSL. Estos certificados sirven para implementar SSL/TLS en sistemas de desarrollo/testing, o en sistemas en producción internos, pero no sirven para sistemas de acceso público, pues no son de confianza. Es decir, los certificados no están firmados por una autoridad certificante de confianza, sino que están firmados por nuestra propia CA. Si se necesita un certificado de confianza, será necesario comprar uno a una autoridad certificante de confianza, o generar uno gratuito desde StartSSL o Let's Encrypt.

Sin embargo, estos certificados son perfectamente válidos para proveer seguridad en comunicaciones privadas, donde no se necesita confianza pues ambos extremos disponen del certificado de nuestra CA. Este es el caso y por ello han pasado ya casi 5 años de mi CA en funcionamiento. El día que creé mi CA fui lo suficientemente iluso para pensar que era una solución provisoria (y como toda solución provisoria es para siempre), por ello generé el certificado de la CA con una validez de (sólo) 5 años. De hecho pensé que en 5 años estaría muerto, o al menos trabajando en otra empresa, y que iba a ser problema del próximo SysAdmin. Pero aquí estoy, insoportablemente vivo.

La cuestión ahora es que debo generar un certificado nuevo para la CA, pero que no altere el funcionamiento de los certificados en funcionamiento actualmente. Para ello debo generar un nuevo certificado a partir del mismo par de claves (pública y privada) del certificado actual.

Manos a la obra

Cambiar al directorio donde se encuentra montada la CA:

root@debian7# cd /ca/

El certificado actual de la CA corresponde con el archivo certs/linuxito-ca.crt:

root@debian7# date
Tue Dec 13 07:57:28 ART 2016
root@debian7# openssl x509 -enddate -noout -in certs/linuxito-ca.crt
notAfter=Jan  2 11:53:57 2017 GMT

Se observa que quedan unos pocos días para que el mismo expire (vence el 2 de enero de 2017). Ah, por cierto, hoy es martes 13 de diciembre de 2016, lindo día para ponerse a hacer estas cositas y romper todo (martes 13, no te cases ni te embarques, ni toques una línea de configuración de ningún servicio).

El certificado de la CA permite verificar la validez de un certificado emitido por la misma, por ejemplo del certificado certs/apache-server-2016.crt:

root@debian7# openssl verify -CAfile certs/linuxito-ca.crt certs/apache-server-2016.crt
certs/apache-server-2016.crt: OK

El nuevo certificado para la CA deberá validar correctamente este certificado. Para ello se deberá mantener la misma clave pública (por ende también la misma clave privada). El módulo de la clave pública actual es:

root@debian7# openssl x509 -modulus -noout -in certs/linuxito-ca.crt 
Modulus=B78F1EE08F0EB7196BFDEFD034DB7524DA5754B025F8162C6F32F80301EEF6B4D1BD16FF48B39DFDCAB92D3E5897046F22FBEA2492C50A493CCE5D4EB667074C0426E059170C98ABCEB4A02BE4FEDD1573D4F9251E1A49691AB498768C87406BFF7178D63FF64CB6D55AA3834CB3A31F37A5966998F5F50D990F01B1B2B72C71

Cabe recordar que la emisión de certificados (firma y generación de .crt) se realiza con la clave privada de la CA. Mientras que la verificación de validez de un certificado se realiza con la clave pública. Lo que se necesita entonces, es un certificado nuevo para la CA, pero que mantenga la misma clave pública y sea firmado con la clave privada correspondiente.

Se debe entonces generar un nuevo certificado (openssl x509) a partir de los datos del certificado actual (-in certs/linuxito-ca.crt) y firmarlo con la clave privada correspondiente (-signkey private/linuxito-ca.key):

root@debian7# openssl x509 -in certs/linuxito-ca.crt -days 36500 -out certs/linuxito-ca-2016.crt -signkey private/linuxito-ca.key
Getting Private key
Enter pass phrase for private/linuxito-ca.key:

El nuevo certificado corresponde con el archivo certs/linuxito-ca-2016.crt, y esta vez es firmado por 100 años (-days 36500). Espero no vivir tanto como para tener que renovarlo nuevamente.

Luego de ingresar la contraseña de la clave privada (passphrase, más vale no haberla perdido...) el certificado se genera correctamente:

root@debian7# ll certs/linuxito-ca*
-rw-r--r-- 1 root root 1.4K Dec 13 08:06 certs/linuxito-ca-2016.crt
-rw-r--r-- 1 root root 1.4K Jan  4  2012 certs/linuxito-ca.crt

El mismo es válido hasta el 19 de noviembre de 2116:

root@debian7# openssl x509 -enddate -noout -in certs/linuxito-ca-2016.crt 
notAfter=Nov 19 11:06:11 2116 GMT

Ahora lo importante, veamos si el módulo de la clave pública no ha cambiado:

root@debian7# openssl x509 -modulus -noout -in certs/linuxito-ca-2016.crt 
Modulus=B78F1EE08F0EB7196BFDEFD034DB7524DA5754B025F8162C6F32F80301EEF6B4D1BD16FF48B39DFDCAB92D3E5897046F22FBEA2492C50A493CCE5D4EB667074C0426E059170C98ABCEB4A02BE4FEDD1573D4F9251E1A49691AB498768C87406BFF7178D63FF64CB6D55AA3834CB3A31F37A5966998F5F50D990F01B1B2B72C71

A simple vista sí, pero mejor asegurarse:

root@debian7# openssl x509 -modulus -noout -in certs/linuxito-ca.crt > modulus.txt
root@debian7# openssl x509 -modulus -noout -in certs/linuxito-ca-2016.crt > modulus-2016.txt
root@debian7# diff modulus.txt modulus-2016.txt 
root@debian7#

Evidentemente las claves públicas son idénticas.

La prueba final consiste en verificar cualquier certificado emitido anteriormente con el nuevo certificado de la CA:

root@debian7# openssl verify -CAfile certs/linuxito-ca-2016.crt certs/apache-server-2016.crt 
certs/apache-server-2016.crt: OK

Debe funcionar pues el nuevo certificado posee la misma clave pública.

Habiendo verificado que el nuevo certificado para mi CA funciona correctamente para los certificados emitidos anteriormente (es decir, firmados con la calve privada correspondiente con el certificado anterior), es posible reconfigurar todos los servicios que utilizan certificados emitidos por esta CA (Apache, MySQL, etc.) para que validen con el nuevo certificado de la CA.

Pero antes es recomendable copiar la clave privada para que se corresponda con el nuevo nombre del certificado de la CA (para evitar que sea borrada accidentalmente):

root@debian7# cp -a private/linuxito-ca.key private/linuxito-ca-2016.key

Además, es necesario modificar la configuración de la CA para que emita los nuevos certificados (firme) utilizando esta nueva clave copiada:

root@debian7# grep 2016 openssl.my.cnf 
certificate     = $dir/certs/linuxito-ca-2016.crt      # The CA certificate
private_key     = $dir/private/linuxito-ca-2016.key    # The private key

Eso es todo, espero que les haya gustado.

Referencias

man openssl
man ca
man x509


Tal vez pueda interesarte


Compartí este artículo