Cómo usar autenticación con tarjetas de Firma Digital de Costa Rica en sitios web

Esta guía explica cómo configurar un servidor web Apache con mod_ssl para autenticación cliente con TLS y la jerarquía de certificados para personas físicas o jurídicas, incluyendo comprobación de estado de revocación de los certificados (OCSP).

Existen muchos servidores HTTPS y terminadores TLS en general que permiten autenticación con certificado cliente. En esta guía se presenta mod_ssl de Apache HTTPd en particular.

Obtención e instalación de cadena de certificados de confianza

Para el caso presentado, se requiere se hace uso del comando openssl para convertir todos los certificados a formato PEM, ya que mod_ssl solamente trabaja con este formato en los certificados cliente. Para ello, se puede ejecutar:

wget https://www.firmadigital.go.cr/repositorio/CA%20RAIZ%20NACIONAL%20-%20COSTA%20RICA%20v2.crt

wget https://www.firmadigital.go.cr/repositorio/CA%20POLITICA%20PERSONA%20FISICA%20-%20COSTA%20RICA%20v2.crt

wget http://fdi.sinpe.fi.cr/repositorio/CA%20SINPE%20-%20PERSONA%20FISICA%20v2.crt

wget http://fdi.sinpe.fi.cr/repositorio/CA%20SINPE%20-%20PERSONA%20FISICA%20v2(1).crt

openssl x509 -inform der -in CA\ RAIZ\ NACIONAL\ -\ COSTA\ RICA\ v2.crt -outform pem -out CA\ RAIZ\ NACIONAL\ -\ COSTA\ RICA\ v2.pem

openssl x509 -inform der -in CA\ POLITICA\ PERSONA\ FISICA\ -\ COSTA\ RICA\ v2.crt -outform pem -out CA\ POLITICA\ PERSONA\ FISICA\ -\ COSTA\ RICA\ v2.pem

Subir al servidor los ficheros en una ruta que luego se le indicará a Apache HTTPd:

CA RAIZ NACIONAL - COSTA RICA v2.pem
CA POLITICA PERSONA FISICA - COSTA RICA v2.pem
CA SINPE - PERSONA FISICA v2.crt
CA SINPE - PERSONA FISICA v2(1).crt

Existen dos formas de suministrar a mod_ssl los certificados de la jerarquía de confianza. Combinarlos en un único fichero o bien renombrar o crear enlaces simbólicos cuyo nombre sea un hash. En esta guía se mostrará esta segunda opción. En el caso de los certificados con el mismo hash, se aumenta el consecutivo del número que hay final del nombre. Se pueden generar así:

ln -s CA\ RAIZ\ NACIONAL\ -\ COSTA\ RICA\ v2.pem $(openssl x509 -noout -hash -in CA\ RAIZ\ NACIONAL\ -\ COSTA\ RICA\ v2.pem).0

ln -s CA\ POLITICA\ PERSONA\ FISICA\ -\ COSTA\ RICA\ v2.pem $(openssl x509 -noout -hash -in CA\ POLITICA\ PERSONA\ FISICA\ -\ COSTA\ RICA\ v2.pem).0

ln -s CA\ SINPE\ -\ PERSONA\ FISICA\ v2.crt $(openssl x509 -noout -hash -in CA\ SINPE\ -\ PERSONA\ FISICA\ v2.crt).0

ln -s CA\ SINPE\ -\ PERSONA\ FISICA\ v2\(1\).crt $(openssl x509 -noout -hash -in CA\ SINPE\ -\ PERSONA\ FISICA\ v2\(1\).crt).1

Lo anterior creará los siguientes enlaces simbólicos:

e1f996fa.0
c07e7fb7.0
395f14c9.0
395f14c9.1

Al enlazar a los nombres originales, es un poco más fácil saber a qué certificado se refiere cada uno, ya que los nombres usados por mod_ssl no son amigables.

Configuración de Apache HTTPd y mod_ssl

Debido a que algunos navegadores no son compatibles con autenticación con certificado cliente usando TLS 1.3 y HTTP/2, así como debido a que mod_ssl es poco intuitivo, conviene indicar que el parámetro de configuración SSLProtocol puede estar definido globalmente, es decir, fuera de un VirtualHost, y tiene prioridad sobre ellos. Si se quiere configurar un valor predeterminado pero sobrescribible por otros VirtualHost en particular, entonces el primer VirtualHost será el predeterminado.

Debido a la limitación en ciertos navegadores, si se utiliza TLS 1.3 en el primer VirtualHost para uso predeterminado, tener un VirtualHost separado para la autenticación con TLS 1.2. Aunque Firefox soporta autenticación cliente con TLS 1.3 y HTTP/2, no es el caso de otros navegadores que pueden motrar errores, por lo que se sugiere lo siguiente para el caso del VirtualHost

<VirtualHost *:443>
    # En caso de usar HTTP/2 (h2) se puede bajar a HTTP/1.1
    Protocols http/1.1
    # En caso de SSLProtocol en el primer VirtualHost con TLS 1.3
    SSLProtocol -TLSv1.3
    ServerName auth.example.org
    DocumentRoot /var/www/auth.example.org
    # No hay OCSP en toda la jerarquía en excepto en la hoja
    SSLOCSPEnable leaf
    # Ruta a los certificados (puede ser cualquier ubicación del sistema)
    SSLCACertificatePath /var/www/auth.example.org/certificados
    # 3 es suficiente para la jerarquía nacional
    SSLVerifyDepth 3
    # Para acceder a datos desde un script
    SSLOptions +StdEnvVars +ExportCertData
    # En caso de querer controlar resultado de validación desde script
    SSLVerifyClient optional
    # (...)
</VirtualHost>

En esa ruta un script puede leer los encabezados que mod_ssl devuelve a lo interno. En el caso de PHP se pueden leer en el arreglo superglobal $_SERVER:

<?php
echo '<!doctype html>
<html lang=es-cr>
<meta name=viewport content="width=device-width,initial-scale=1.0">
<meta charset=utf-8>
<title>Prueba de autenticación con certificado cliente TLS</title>
<h1>Prueba de autenticación con certificado cliente TLS</h1>';
if ($_SERVER['SSL_CLIENT_VERIFY'] === 'NONE') exit('<p>No se seleccionó ningún certificado.');
if ($_SERVER['SSL_CLIENT_VERIFY'] === 'SUCCESS') {
	echo '<p>Hola, ', ucwords(strtolower(htmlspecialchars($_SERVER['SSL_CLIENT_S_DN_G']))), ":\n";
	echo '<p>Con toda certeza, tu nombre completo es ', htmlspecialchars($_SERVER['SSL_CLIENT_S_DN_G']), ' ', htmlspecialchars($_SERVER['SSL_CLIENT_S_DN_S']), ".\n";
	parse_str(str_replace(',', '&', htmlspecialchars($_SERVER['SSL_CLIENT_S_DN'])), $dn);
	echo '<p>Identificación: ', $dn['serialNumber'];
	echo '<p>Tu certificado vencerá dentro de ', htmlspecialchars($_SERVER['SSL_CLIENT_V_REMAIN']), " días.\n";
	echo '<p>Fecha de emisión: ', htmlspecialchars($_SERVER['SSL_CLIENT_V_START']), ".\n";
	echo '<p>Fecha de expiración: ', htmlspecialchars($_SERVER['SSL_CLIENT_V_END']), ".\n";
} else echo '<p>Parece que falló la autenticación.';

Queda a discreción del usuario el manejo de la autenticación al gusto, teniendo en cuenta el valor SUCCESS en SSL_VERIFY_CLIENT y lo que considere realizar en base a los datos como el serialNumber.

Existen muchas alternativas, como mod_gnutls en el mismo Apache HTTPd, o en otros servidores como nginx, lighttpd, haproxy, hitch, etc. donde también es posible configurar autenticación con certificado cliente, así como el tratamiento desde otros lenguajes de programación de la información de autenticación.

Se puede encontrar una demostración en https://autenticacion.fran.cr/.

Deja un comentario

Tu dirección de correo electrónico no será publicada.