Respuesta breve. Desde marzo de 2024, el CA/Browser Forum exige a las CA que publiquen CRL y hace opcional OCSP. Let's Encrypt eliminó las URL de OCSP de sus certificados en mayo de 2025 y apagó sus respondedores en agosto de 2025. Los navegadores ya no preguntan a las CA por cada certificado. Firefox consulta un filtro CRLite local, Chrome consulta el CRLSet que recibe por actualización y Apple usa su propia lista agregada. La mayoría de las bibliotecas y herramientas de línea de comandos (Java, .NET, Go, Python, Node.js, curl) no comprueban la revocación en absoluto por defecto. Todas aceptaron un certificado revocado de Let's Encrypt en nuestras pruebas. Si tu cliente debe rechazar certificados revocados, activa de forma explícita la comprobación de CRL y prepárate para certificados con una vida útil corta. Lo segundo es, de todos modos, hacia donde va el sector.
Por qué había que replantear la revocación
Un certificado puede revocarse antes de caducar, normalmente porque su clave se filtró o porque se emitió por error. Las dos formas clásicas de comunicarlo a los clientes eran:
- CRL (lista de revocación de certificados, RFC 5280): la CA publica una lista firmada de números de serie revocados. El certificado apunta a ella en su extensión CRL Distribution Points.
- OCSP (RFC 6960): el cliente pregunta al respondedor de la CA por un certificado concreto y recibe una respuesta firmada con el estado «good», «revoked» o «unknown». La URL está en la extensión Authority Information Access.
Ambas tenían problemas en la web. Las CRL podían ser grandes. OCSP revelaba a la CA cada sitio que visitaba el usuario, añadía latencia, y los navegadores tenían que hacer «soft-fail» (seguir adelante sin respuesta) cuando el respondedor no estaba accesible. Un atacante capaz de bloquear la solicitud OCSP deja la comprobación sin efecto. El grapado OCSP (OCSP stapling) resolvió el problema de privacidad haciendo que el servidor obtuviera la respuesta y la adjuntara, pero nunca llegó a ser universal. Must-Staple, un indicador del certificado que exige una respuesta grapada, apenas llegó a admitirse en los navegadores.
Qué dicen las normas ahora
La votación SC-063 («Hacer OCSP opcional, exigir CRL e incentivar la automatización», en vigor desde el 15 de marzo de 2024) cambió los Baseline Requirements (BR):
- Las CRL son obligatorias. Una CA debe publicar una CRL completa o fragmentada en las 24 horas siguientes a la emisión de su primer certificado. Debe actualizar la CRL al menos cada 7 días si todos sus certificados incluyen una URL de OCSP, y cada 4 días en caso contrario, además de en las 24 horas siguientes a revocar un certificado (§4.9.7). Para los certificados de suscriptor,
nextUpdatepuede ser como máximo 10 días posterior athisUpdate(§7.2). - OCSP es opcional. Si un certificado tiene una URL de OCSP, el respondedor está obligado a contestar, y sus respuestas deben tener una validez de entre 8 horas y 10 días (§4.9.9). Un certificado sin URL de OCSP debe incluir un CRL Distribution Point (§7.1.2.11.2).
- Los certificados de corta duración no necesitan información de revocación. Un «Short-lived Subscriber Certificate» (certificado de suscriptor de corta duración) es válido como máximo 7 días si se emite a partir del 15 de marzo de 2026 (10 días si se emite antes de esa fecha). La CA puede admitir su revocación, y el CRL Distribution Point es opcional.
- Plazos de revocación. 24 horas para el compromiso de la clave y casos similares, 5 días para el resto (§4.9.1.1).
Después, Let's Encrypt abandonó OCSP por completo, «principalmente porque representa un riesgo considerable para la privacidad en Internet»:
- 30 de enero de 2025: fallan las nuevas solicitudes de Must-Staple.
- 7 de mayo de 2025: se eliminan las URL de OCSP de los certificados nuevos, que pasan a incluir URL de CRL.
- 6 de agosto de 2025: se apagan los respondedores OCSP.
Qué incluyen hoy los certificados
Al revisar unos cuantos sitios el 20 de octubre de 2026 en busca de una URL de OCSP, una URL de CRL y una respuesta OCSP grapada, el panorama es variado:
letsencrypt.org Let's Encrypt OCSP=- CRL=http://ye2.c.lencr.org/96.crl
staple: OCSP response: no response sent
www.google.com Google Trust Services OCSP=- CRL=http://c.pki.goog/we2/xuzt3PU9F_w.crl
staple: OCSP response: no response sent
github.com Sectigo Limited OCSP=http://ocsp.sectigo.com CRL=-
staple: OCSP response: no response sent
www.digicert.com DigiCert Inc OCSP=http://ocsp.digicert.com CRL=http://crl3.digicert.com/DigiCertEVRSACAG2.crl
staple: OCSP Response Status: successful (0x0)
www.microsoft.com Microsoft Corporation OCSP=http://oneocsp.microsoft.com/ocsp CRL=http://www.microsoft.com/pkiops/crl/partition/Microsoft%20TLS%20G2%20RSA%20CA%20OCSP%2004_Partition00093.crl
staple: OCSP Response Status: successful (0x0)
www.amazon.com Amazon OCSP=http://ocsp.r2m04.amazontrust.com CRL=http://crl.r2m04.amazontrust.com/r2m04.crl
staple: OCSP Response Status: successful (0x0)
Let's Encrypt y Google Trust Services emiten certificados solo con CRL. El certificado de GitHub, emitido por Sectigo, es el caso inverso, solo con OCSP, algo que los BR permiten. Un cliente que solo admite uno de los dos métodos no puede comprobarlos todos.
Las CRL no son pequeñas, pero sí manejables:
http://yr1.c.lencr.org/46.crl 192226 bytes 5094 entries Oct 20 12:26:45 2026 GMT -> Oct 29 12:26:44 2026 GMT
http://c.pki.goog/we2/xuzt3PU9F_w.crl 87562 bytes 2456 entries Oct 20 11:12:29 2026 GMT -> Oct 30 10:12:28 2026 GMT
http://crl3.digicert.com/DigiCertEVRSACAG2.crl 635286 bytes 17091 entries Oct 20 06:24:08 2026 GMT -> Oct 27 06:24:08 2026 GMT
Let's Encrypt fragmenta sus CRL: cada certificado apunta a uno de muchos archivos numerados, y la extensión Issuing Distribution Point de la CRL indica ese fragmento. El decodificador de CRL lee cualquiera de estos archivos, comprueba su firma con el certificado del emisor y te dice si un certificado concreto figura en él.
Cómo comprueban la revocación los navegadores
Ninguno de los principales navegadores envía ya una solicitud OCSP para un certificado normal:
- Firefox: CRLite. Firefox descarga una codificación comprimida de todos los certificados revocados que aparecen en los logs CT, la actualiza cada 12 horas y la consulta localmente. Son unos 300 kB de datos al día de media, según Mozilla. Está activado para todos los usuarios de escritorio desde Firefox 137. Firefox 142 dejó de usar OCSP para los certificados de validación de dominio, y Firefox para Android adoptó CRLite en la versión 145.
- Chrome: CRLSets. Chrome distribuye una lista construida a partir de las CRL de las CA, pero solo con «un subconjunto de los certificados identificados como revocados», y «Chrome no realiza, por lo general, comprobaciones en línea (es decir, OCSP y CRL)» (Chromium). En nuestra prueba, Chromium 156 cargó
https://revoked-isrgrootx1.letsencrypt.org/con HTTP 200. - Apple: una lista agregada. Apple recopila datos de revocación de las CA y los distribuye a los dispositivos. En diciembre de 2025, el soporte técnico para desarrolladores de Apple explicó que los certificados «solo acaban en la lista “negra” de Apple» cuando se revocan por motivos como el compromiso de la clave, y que para los certificados de Let's Encrypt no hay una comprobación OCSP secundaria. Por eso, Safari puede seguir aceptando un certificado revocado por un motivo ordinario.
Qué significa esto en la práctica: para los navegadores, revocar un certificado no es un interruptor de emergencia rápido. Firefox recoge las revocaciones con las actualizaciones de CRLite cada 12 horas. Puede que Chrome y Safari nunca lleguen a bloquear un certificado revocado por un motivo ordinario. El límite real para una clave filtrada es la vida útil restante del certificado, y ese es uno de los motivos del paso a los certificados de 47 días.
Qué comprueban por defecto las bibliotecas y las herramientas
Todos los clientes siguientes se conectaron a https://revoked-isrgrootx1.letsencrypt.org/ (revocado el 7 de octubre de 2026) y a https://valid-isrgrootx1.letsencrypt.org/ el 20 de octubre de 2026. El certificado revocado tiene una URL de CRL y ninguna URL de OCSP.
| Cliente | Por defecto, en el sitio revocado | Comprobación de revocación que funcionó |
|---|---|---|
| Java 25 (JSSE) | HTTP 200 | -Dcom.sun.net.ssl.checkRevocation=true -Dcom.sun.security.enableCRLDP=true |
.NET 10 HttpClient | HTTP 200 | SslOptions.CertificateRevocationCheckMode = X509RevocationMode.Online |
Go 1.27 crypto/tls | 200 OK | Comprobación propia en tls.Config.VerifyConnection |
Python 3.13 ssl | handshake ok | VERIFY_CRL_CHECK_LEAF más la CRL cargada en el contexto |
Node.js 24 tls | handshake ok | Opción crl con una CRL por elemento del array, para cada nivel de la cadena |
| curl 8.14 (OpenSSL) | HTTP 200 | --crlfile con las CRL de cada nivel de la cadena |
| Chromium 156 | HTTP 200 | Ninguna (solo CRLSet) |
A continuación, los detalles de cada cliente.
Java
JSSE no comprueba la revocación salvo que com.sun.net.ssl.checkRevocation sea true. Incluso entonces usa solo OCSP, a menos que también se activen los CRL Distribution Points, y por eso un certificado de Let's Encrypt falla como desconocido y no como revocado:
--- 1. default
HTTP 200
--- 2. -Dcom.sun.net.ssl.checkRevocation=true
javax.net.ssl.SSLHandshakeException: (certificate_unknown) PKIX path validation failed: java.security.cert.CertPathValidatorException: Could not determine revocation status
--- 3. checkRevocation + -Dcom.sun.security.enableCRLDP=true (revoked site)
javax.net.ssl.SSLHandshakeException: (certificate_revoked) PKIX path validation failed: java.security.cert.CertPathValidatorException: Certificate has been revoked, reason: UNSPECIFIED, revocation date: Wed Oct 07 18:37:19 UTC 2026, authority: CN=YR1, O=Let's Encrypt, C=US, extension OIDs: []
--- 4. same, valid site
HTTP 200
Con la comprobación activada, el validador PKIX rechaza el certificado cuando no puede determinar su estado. Es lo seguro, pero entonces una caída del servidor de CRL se convierte en tu caída. java.security.cert.PKIXRevocationChecker te permite elegir el orden de OCSP y CRL y las opciones de soft-fail para cada conexión.
.NET
HttpClient con SocketsHttpHandler no comprueba la revocación por defecto. Si se configura el modo Online, .NET obtiene por sí mismo la CRL o la respuesta OCSP. En Linux lo hace mediante su propia implementación sobre OpenSSL:
var handler = new SocketsHttpHandler();
handler.SslOptions.CertificateRevocationCheckMode = X509RevocationMode.Online;
using var client = new HttpClient(handler);
https://revoked-isrgrootx1.letsencrypt.org/ revocation=default -> 200
https://revoked-isrgrootx1.letsencrypt.org/ revocation=Online -> The remote certificate is invalid because of errors in the certificate chain: Revoked
https://valid-isrgrootx1.letsencrypt.org/ revocation=default -> 200
https://valid-isrgrootx1.letsencrypt.org/ revocation=Online -> 200
Go
crypto/tls verifica la cadena y el nombre, y nunca comprueba la revocación. Si la necesitas, comprueba tú mismo la CRL después de la verificación. x509.ParseRevocationList y CheckSignatureFrom se encargan de la parte difícil:
func checkCRL(cs tls.ConnectionState) error {
chain := cs.VerifiedChains[0]
leaf, issuer := chain[0], chain[1]
if len(leaf.CRLDistributionPoints) == 0 {
return errors.New("certificate has no CRL distribution point")
}
resp, err := http.Get(leaf.CRLDistributionPoints[0])
if err != nil {
return err
}
defer resp.Body.Close()
der, err := io.ReadAll(io.LimitReader(resp.Body, 64<<20))
if err != nil {
return err
}
crl, err := x509.ParseRevocationList(der)
if err != nil {
return err
}
if err := crl.CheckSignatureFrom(issuer); err != nil {
return fmt.Errorf("CRL signature: %w", err)
}
if time.Now().After(crl.NextUpdate) {
return errors.New("CRL is past its nextUpdate")
}
for _, entry := range crl.RevokedCertificateEntries {
if entry.SerialNumber.Cmp(leaf.SerialNumber) == 0 {
return fmt.Errorf("certificate %X revoked at %s", leaf.SerialNumber, entry.RevocationTime.UTC())
}
}
return nil
}
// client := &http.Client{Transport: &http.Transport{TLSClientConfig: &tls.Config{VerifyConnection: checkCRL}}}
https://revoked-isrgrootx1.letsencrypt.org/ -> 200 OK
https://revoked-isrgrootx1.letsencrypt.org/ -> Get "https://revoked-isrgrootx1.letsencrypt.org/": certificate 67E51010C975E496C8EB800F3EF1BAB3F2B revoked at 2026-10-07 18:37:19 +0000 UTC
https://valid-isrgrootx1.letsencrypt.org/ -> 200 OK
https://valid-isrgrootx1.letsencrypt.org/ -> 200 OK
El ejemplo comprueba solo el certificado hoja y descarga la CRL en cada handshake. En producción, guarda cada CRL en caché hasta su NextUpdate y decide qué ocurre cuando el servidor de CRL no está disponible.
Python, Node.js y curl
Los tres usan la comprobación de CRL de OpenSSL y esperan que les proporciones las CRL. Nunca las descargan:
python 3.13.5 default: handshake ok, TLSv1.3
python 3.13.5 VERIFY_CRL_CHECK_LEAF: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: certificate revoked (_ssl.c:1029)
node v24.22.0 default: handshake ok
node v24.22.0 crl: UNABLE_TO_GET_CRL unable to get certificate CRL
ssl.VERIFY_CRL_CHECK_LEAF de Python comprueba solo el certificado hoja, así que basta con cargar la CRL de la hoja con ctx.load_verify_locations(cafile=...). Node.js y curl comprueban todos los certificados de la cadena, así que una CRL solo para la hoja produce UNABLE_TO_GET_CRL (Node) o unable to get certificate CRL (curl) incluso en un sitio válido. Dales la CRL de cada certificado de la cadena. En Node.js 24, pásalas como un array con una CRL por elemento, cada una como texto PEM. Un único buffer con tres CRL concatenadas siguió fallando con UNABLE_TO_GET_CRL en nuestra prueba:
revoked-isrgrootx1.letsencrypt.org (one buffer): UNABLE_TO_GET_CRL unable to get certificate CRL
revoked-isrgrootx1.letsencrypt.org (array): CERT_REVOKED certificate revoked
valid-isrgrootx1.letsencrypt.org (one buffer): UNABLE_TO_GET_CRL unable to get certificate CRL
valid-isrgrootx1.letsencrypt.org (array): handshake ok
Las dos opciones de curl se comportan de forma distinta. --cert-status exige una respuesta OCSP grapada, así que falla en todos los servidores que no la grapan, incluidos todos los sitios de Let's Encrypt. --crlfile funciona con un archivo que contenga las CRL de toda la cadena:
$ curl -s -o /dev/null -w "HTTP %{http_code}\n" https://revoked-isrgrootx1.letsencrypt.org/
HTTP 200
$ curl -sS -o /dev/null --cert-status https://revoked-isrgrootx1.letsencrypt.org/
curl: (91) No OCSP response received
$ curl -sS -o /dev/null --crlfile revoked-chain-crls.pem https://revoked-isrgrootx1.letsencrypt.org/
curl: (60) SSL certificate problem: certificate revoked
$ curl -s -o /dev/null -w "HTTP %{http_code}\n" --crlfile valid-chain-crls.pem https://valid-isrgrootx1.letsencrypt.org/
HTTP 200
$ curl -sS -o /dev/null --crlfile leaf-crl-only.pem https://valid-isrgrootx1.letsencrypt.org/
curl: (60) SSL certificate problem: unable to get certificate CRL
Este script recopila la CRL de cada certificado que envía un servidor:
#!/bin/bash
host="$1"; out="$2"
dir=$(mktemp -d)
openssl s_client -connect "$host:443" -servername "$host" -showcerts </dev/null 2>/dev/null \
| awk -v d="$dir" '/BEGIN CERTIFICATE/{n++} n>0{print > (d "/cert" n ".pem")}'
: > "$out"
for cert in "$dir"/cert*.pem; do
url=$(openssl x509 -in "$cert" -noout -ext crlDistributionPoints 2>/dev/null | grep -o 'http[^ ]*' | head -1)
[ -n "$url" ] && curl -s "$url" | openssl crl -inform DER >> "$out"
done
rm -r "$dir"
echo "$host: $(grep -c 'BEGIN X509 CRL' "$out") CRLs"
Cómo comprobar un certificado a mano
Con OpenSSL puedes ver dónde se publica el estado de un certificado y comprobarlo directamente. Mira primero las extensiones:
$ openssl x509 -in leaf.pem -noout -ext crlDistributionPoints,authorityInfoAccess
Authority Information Access:
CA Issuers - URI:http://yr1.i.lencr.org/
X509v3 CRL Distribution Points:
Full Name:
URI:http://yr1.c.lencr.org/44.crl
Después descarga la CRL y verifica el certificado con ella. -untrusted aporta los certificados intermedios que envió el servidor:
$ curl -s -o crl.der http://yr1.c.lencr.org/44.crl
$ openssl crl -inform DER -in crl.der -out crl.pem
$ openssl verify -crl_check -CRLfile crl.pem -untrusted chain.pem leaf.pem
CN=revoked-isrgrootx1.letsencrypt.org
error 23 at 0 depth lookup: certificate revoked
error leaf.pem: verification failed
$ openssl crl -in crl.pem -noout -text | grep -A1 "Serial Number: 067E51010C975E496C8EB800F3EF1BAB3F2B"
Serial Number: 067E51010C975E496C8EB800F3EF1BAB3F2B
Revocation Date: Oct 7 18:37:19 2026 GMT
Si la CA todavía mantiene OCSP, pregunta directamente al respondedor o mira la respuesta grapada:
$ openssl ocsp -issuer issuer.pem -cert leaf.pem -url http://ocsp.digicert.com -resp_text -noverify
OCSP Response Status: successful (0x0)
Cert Status: good
This Update: Oct 19 22:09:00 2026 GMT
Next Update: Oct 26 21:09:00 2026 GMT
leaf.pem: good
This Update: Oct 19 22:09:00 2026 GMT
Next Update: Oct 26 21:09:00 2026 GMT
$ openssl s_client -connect www.digicert.com:443 -servername www.digicert.com -status </dev/null
OCSP Response Status: successful (0x0)
Cert Status: good
-noverify omite la comprobación de la firma de la respuesta, lo que sirve para un vistazo rápido, pero no para tomar una decisión. El decodificador de OCSP analiza solicitudes y respuestas, verifica la firma y la autoridad del respondedor, y puede consultar un respondedor por ti.
Qué hacer en tu servicio
- Decide si de verdad necesitas comprobar la revocación. Para las llamadas salientes a API públicas, el modelo de los navegadores (vidas útiles cortas, CT, respuesta de las CA ante incidentes) suele bastar. Para las conexiones de alto valor, como los callbacks de pago, el mTLS entre organizaciones o la firma de código y de documentos, comprueba la revocación de forma explícita.
- Admite primero las CRL. Las CA públicas están obligadas a publicarlas, y algunas ya no mantienen OCSP. Un cliente que solo usa OCSP no podrá decidir sobre los certificados de Let's Encrypt y Google Trust Services.
- Guarda las CRL en caché y actualízalas a su ritmo. Descarga cada CRL una vez, consérvala hasta
nextUpdatey actualízala en segundo plano, para que un handshake TLS nunca tenga que esperar una descarga. - Elige fail-open o fail-closed a conciencia. Con fail-closed, un problema en la CDN de una CA se convierte en tu caída. Con fail-open, la comprobación pasa a ser opcional para cualquiera que pueda bloquear la descarga de la CRL. Registra los dos casos en el log.
- Elimina las dependencias de Must-Staple y del grapado OCSP. Let's Encrypt rechaza las solicitudes de Must-Staple, y el grapado solo sirve con las CA que todavía mantienen OCSP.
- En una PKI privada, el diseño es tuyo. Publica CRL con un
nextUpdatecorto, o emite certificados de corta duración y prescinde de la revocación, como ahora permiten los BR para los certificados de 7 días o menos.
Fuentes
- CA/Browser Forum, Baseline Requirements v2.3.1: §4.9.1.1 (plazos de revocación), §4.9.7 (frecuencia de las CRL), §4.9.9 (OCSP), §7.1.2.11.2 (puntos de distribución de CRL), §7.2 (perfil de CRL), definición de Short-lived Subscriber Certificate. Votación SC-063.
- RFC 5280 (CRL) y RFC 6960 (OCSP).
- Let's Encrypt, Ending OCSP Support in 2025.
- Mozilla, CRLite: Fast, private, and comprehensive certificate revocation checking in Firefox (agosto de 2025), y las notas de la versión 145 de Firefox para Android.
- Chromium, CRLSets.
- Apple Developer Forums, hilo 808875 (diciembre de 2025).
Las pruebas se hicieron el 20 de octubre de 2026 en node:24.22.0-trixie (OpenSSL 3.5.7, curl 8.14.1, Node.js 24.22.0, Python 3.13.5), eclipse-temurin:25.0.4.1_1-jdk-noble, golang:1.27.3-trixie, mcr.microsoft.com/dotnet/sdk:10.0.402-noble y mcr.microsoft.com/playwright:v1.64.1-noble (Chromium 156).