Fracasos con el Certificado Digital de la FNMT




Hace mucho tiempo que disfruto de las ventajas que ofrece el certificado digital de persona física, emitido por la FNMT-RCM pero últimamente me he estado preguntando cuáles eran los límites de su capacidad de identificación y encriptación personales.

Después de mucho trastear con él puedo decir sin temor a equivocarme que el certificado de la FNMT es útil pero muy aburrido y no nos permite realizar tareas más complejas que otros certificados cumplen sin ningún problema.

Todos estos experimentos surgieron por casualidad, al descargarme un certificado de AWS para hacer un par de trabajos de cloud computing. Me di cuenta de que el certificado SSH tenía una extensión .pem, al igual que la versión desencriptada del de la FNMT (aunque originariamente se encuentra en .p12, hay que desencriptarlo para poder empezar a trabajar con él, ya que .p12 es un formato de tránsito, pensado para el transporte desde la autoridad certificadora (CA) hasta el titular (CN)).

Entonces vi factible la posibilidad de poder conectarme por SSH a un host remoto con mi certificado FNMT. Qué ingenuo fui. La justificación a que esto no funcione se hace muy evidente después de indagar en la completa y extensísima documentación de OpenSSL. Desgraciadamente, .pem es sólo un contenedor que puede albergar un amplio espectro de información criptográfica: certificados, claves públicas, privadas, fingerprints, hashes y exóticas mezclas de todos estos componentes, que hacen que el arduo trabajo de la criptografía se vuelva incluso más esotérico, si cabe.

Es necesario aclarar que a partir de un certificado SSL se puede obtener uno SSH pero esta conversión no tiene sentido. Partiendo del certificado de la FNMT, podemos extraer por un lado el certificado propiamente dicho, que no es sino la clave pública y por otro lado podemos obtener la clave privada para acabar fundiéndolas y reformateándolas como un .pem, esta vez sí, con todos los requisitos para que nuestro servidor SSH nos permita identificarnos. Todo esto debe ser considerado un fracaso porque la transformación que ha sufrido el certificado es tan radical que no se parece en nada al original por lo que su utilidad se queda reducida a la que nos aportaría uno creado de cero, sin que guardara ninguna relación con nuestro certificado digital.

TL;DR

Voy a describir el proceso por curiosidad morbosa. El primer paso es extraer las claves del paquete .p12 original:
openssl pkcs12 -in fnmt.p12 -out fnmtpriv.pem -nodes -nocerts
openssl pkcs12 -in fnmt.p12 -out fnmtpub.pem -nodes -nokeys
La clave privada, fnmtpriv.pem está en formato PKCS8, no soportado por SSH, así que lo transformamos, recortando todo el sobrante con el comando
openssl rsa -in fnmtpriv.pem -out id_rsa
En el caso de la clave pública, podríamos derivarla de la privada, pero prefiero obtenerla de la transformación del certificado original para que la derivación me sirva como operación de comprobación.
openssl x509 -in fnmtpub.pem -pubkey -noout > fnmt.pub
ssh-keygen -i -m PKCS8 -f fnmt.pub > id_rsa.pub
Con el primer comando, extraemos la clave pública del certificado que contiene más datos que no vamos a necesitar y con el segundo convertimos esa clave en una admitida por SSH. Como ya se ha comentado, el resultado de estas operaciones nada tiene que ver con el archivo original. Esto añadido a su complejidad, que implica la utilización de 4 programas y su poca utilidad, lo considero un fracaso.

Después de semejante fallo, se me ocurrió utilizar mi certificado en su estado original, esto es OpenSSL, para lo que todo el mundo utiliza mayoritariamente OpenSSL, crear conexiones seguras a servidores web mediante HTTPS. También fracasé. Esta vez, la culpa no fue del propio funcionamiento y naturaleza de los certificados, sino de una imposición directa de la FNMT, como averigüé después de perder incontables horas en esta vacua tarea. En principio, al no estar pensado para este tipo de requerimientos, tuve que reensamblar toda la cadena de certificados que nos permite desarrollar un modelo de chain of trust, es decir, encontrar al firmante de mi certificado digital (AC FNMT Usuarios), buscar el certificado desde el que se firmó y volver a repetir esa operación hasta el certificado raiz que se firma a sí mismo (AC RAIZ FNMT-RCM). Luego hay que concatenar todos esos certificados en lo que parece un árbol genealógico para que el navegador pueda rastrear la validez de cada certificado hasta llegar a uno en el que verdaderamente confíe. Al acabar todo este peregrinaje, no funcionaba porque es necesario que el common name (CN) del certificado de la FNMT coincida con el dominio de la web segura que queramos desarrollar. Obviamente, el CN de mi certificado digital es mi propio nombre, así que nada de esto podría funcionar y sin embargo se podría ampliar el concepto de chain of trust creando otro certificado con el correspondiente CN, firmado por el mío. Aquí es donde enlazo con el principio, cuando culpo a la FNMT, porque los certificados digitales que emite están configurados deliberadamente para que no se conviertan en autoridades certificadoras (AC) y puedan firmar otros certificados, dejando mi experimento inconcluso. En realidad, todo esto se puede resumir en la salida del siguiente comando, que nos revela que no podemos firmar otros.
openssl x509 -purpose -in fnmt.pem
Una vez conseguí reponerme del ridículo de fracasar no una sino dos veces, tome la decisión de utilizar el certificado de nuevo para una tarea sin demasiado sentido pero que iba a conseguir a toda costa, como premio de consolación por los errores pasados... pero tampoco puedo asegurar que haya tenido demasiado éxito en este nueva empresa. 

Nadie utiliza PGP, el mecanismo para firmar o encriptar correos electrónicos. Tengo un par de claves desde hace años y sólo las he utilizado una vez, para un correo interno de Canonical, que me lo exigía. Tampoco conozco a nadie que lo haya usado nunca y en internet el pesimismo sobre PGP es unánime. Si este es el panorama para el protocolo más utilizado, imaginaos por un momento la situación de su hermano tonto, el standard incluso menos utilizado, S/MIME, cuya única ventaja es que es compatible con el certificado de la FNMT. Al final he conseguido mandar un un email firmado con mi certificado pero considero a esto una victoria pírrica por múltiples motivos. El primero y quizás más importante es que el propio concepto de S/MIME es defectuoso. Es una complicación innecesaria que no aporta demasiada seguridad extra si tenemos en cuenta que no encripta de punto a punto como en el caso de PGP sino a través de una autoridad certificadora. Es por esto que solo se usa en entornos corporativos, para que los jefes tengan acceso al contenido de los emails de sus trabajadores. Es un concepto poco ético y técnicamente peligroso porque crea un innecesario single point of failure. Si ha esto le añadimos que su uso se hace en el marco de VPNs o se tiene acceso a clientes mail web por TLS, la seguridad que aporta es redundante e innecesaria pero es que además es terriblemente difícil. Cuando empecé este ultimo experimento, pensé ingenuamente que sería el más sencillo y ha resultado ser el más complejo. Infinitamente más que utilizar PGP, por si alguien se lo está preguntando aunque también he de reconocer que lo he hecho todo de forma manual para poder utilizarlo directamente con Gmail, sin acudir a clientes que seguramente faciliten muchísimo toda la operativa (thunderbird, pero no me apetecía usarlo).

TL;DR

Una vez conoces el proceso, no es demasiado largo. El problema es enlazar todas las partes de la documentación para enterarse de todos los pasos. Afortunadamente, ese arduo trabajo de documentación ya lo he hecho yo y os lo dejo todo a punto para empezar a usar (pero no lo uses, en serio).

El proceso de firma a un mensaje situado en la misma carpeta y denominado email.txt no tiene complicación:
openssl smime -sign -signer fnmt.pem -in email.txt
donde fnmt.pem es nuestro certificado, descomprimido de su original paquete de transporte .p12, del que ya he hablado anteriormente. A este comando le podemos agregar las típicas flags de -from y -to para completar las cabeceras del email.

La complicación viene del lado del receptor, que quiera comprobar la integridad del mensaje, así como su autoría. Para ello habrá que añadir a la carpeta de certificados (/usr/lib/ssl/certs) el FNMTClase2CA.pem. Hasta ahí, todo normal, aunque no funcionaría porque OpenSSL no puede leerlo a no ser que el certificado lleve como nombre su hash y la extensión .0. Pocas veces he encontrado absurdeces esotéricas e incomprensibles como esta en Linux. Lo más aconsejable es crear un link simbólico al certificado para que este no tenga que perder su nombre entre tanto numero. Con el siguiente comando se hace sin complicaciones.
sudo ln -s FNMTClase2CA.pem `openssl x509 -hash -noout 
-in FNMTClase2CA.pem`.0
sudo ln -s AC_FNMT_Usuarios.pem `openssl x509 -hash -noout 
-in AC_FNMT_Usuarios.pem`.0
sudo ln -s AC_Raiz_FNMT-RCM_SHA256.pem `openssl x509 -hash -noout 
-in AC_Raiz_FNMT-RCM_SHA256.pem`.0
Finalmente, solo hace falta verificar el email mediante
openssl smime -verify -in email.txt 
Por si no fuera poco, toda esta tarea tiene un punto débil que hace que sea totalmente insegura y desaconsejable. Por la forma en la que funciona OpenSSL, esta verificación es puramente matemática, es decir, se asegura el origen, o lo que es lo mismo, se asegura de que el mensaje está firmado por un certificado procedente de una autoridad certificadora, pero todo esto es stateless, no tiene en cuenta la posible revocación del certificado por el usuario. Esto habría que hacerlo mirando las listas de revocación de certificados del servidor de la autoridad certificadora, mediante peticiones de OCSP. Aparte de la complejidad que esto supone, estas peticiones no se realizan por canales seguros por lo que nadie está libre de poder sufrir ataques MitM que arruinen toda la verificación. S/MIME es así, una auténtica mierda, un callejón sin salida dentro de un callejón sin salida dentro de otro callejón sin salida que forman una espiral autodestructiva que me ha llegado a desquiciar.

La moraleja de esta historia de miedo es que el certificado digital solo se puede usar dentro de los limitados y aburridos márgenes que establece la Administración y con las herramientas que esta ofrece, algo que cualquiera se habría imaginado, pero yo tenía que ser el tonto útil que se asegurase de esta gran evidencia. Al menos he aprendido un par de cosas útiles.

Fuente: man {ca, genrsa, ocsp, openssl, pkcs7, pkcs12, rsa, smime, ssh, ssh-keygen, ssl, verify, x509}