Saltar al contenido
ecdsa.com
← Todos los artículos

Certificate Transparency para programadores: SCT y alertas

Todo certificado TLS de confianza pública se publica en logs de solo adición antes de que los navegadores lo acepten. Eso hace visibles los certificados emitidos indebidamente y permite buscar en tu propio inventario de certificados. Aquí verás cómo encajan las piezas, qué exigen los navegadores y cómo vigilar tus dominios.

Respuesta breve. Certificate Transparency (CT, RFC 6962) obliga a las CA a enviar cada certificado TLS de confianza pública a logs públicos de solo adición. Cada log devuelve una promesa firmada de incluir el certificado, la SCT, y la CA incrusta las SCT en el certificado. Chrome, Safari y Firefox rechazan los certificados de confianza pública que no tienen suficientes SCT de suficientes logs independientes. Para ti, eso significa dos cosas. Cualquiera puede ver todos los certificados emitidos para tus dominios, a través de Cert Spotter, crt.sh o tu propio monitor. Y deberías vigilar esos logs, porque un certificado que no solicitaste es la primera señal de una toma de control del DNS, de una cuenta comprometida o de una CA que no actúa como debe.

Cómo funciona CT

Un log CT es un árbol de Merkle, la misma estructura de hashes de solo adición que usan Git y Bitcoin. Cualquiera puede descargarlo, comprobar que nunca se eliminan ni se modifican entradas y obtener una prueba breve de que un certificado concreto está incluido. La emisión con CT funciona así:

  1. La CA construye un precertificado: el contenido del certificado final más una extensión crítica de «veneno» (poison, OID 1.3.6.1.4.1.11129.2.4.3), para que no pueda usarse como certificado real.
  2. Envía el precertificado a varios logs. Cada log devuelve una marca de tiempo de certificado firmada (Signed Certificate Timestamp, SCT): una firma sobre la entrada y una marca de tiempo que promete incluirla dentro del plazo máximo de incorporación del log (Maximum Merge Delay, MMD).
  3. La CA emite el certificado final con las SCT incrustadas en una extensión X.509 (OID 1.3.6.1.4.1.11129.2.4.2).
  4. Los navegadores comprueban las firmas de las SCT con su lista de logs de confianza y las cuentan según su política.
  5. Los monitores leen los logs e informan de los certificados de los nombres que vigilan. Los auditores comprueban que los logs se mantienen coherentes y cumplen sus promesas.

En la mayoría de los casos se registran en los logs tanto el precertificado como el certificado final, y por eso las herramientas de búsqueda suelen mostrar cada certificado dos veces.

Las SCT de un certificado real

openssl x509 -text decodifica las SCT incrustadas. Este es el certificado que servía letsencrypt.org el 20 de octubre de 2026:

openssl x509 -noout -text (OpenSSL 3.5.7, abreviado)
subject=CN=letsencrypt.org
issuer=C=US, O=Let's Encrypt, CN=YE2
notBefore=Sep  4 14:34:32 2026 GMT
notAfter=Dec  3 14:34:31 2026 GMT
            CT Precertificate SCTs:
                Signed Certificate Timestamp:
                    Version   : v1 (0x0)
                    Log ID    : D8:09:55:3B:94:4F:7A:FF:C8:16:19:6F:94:4F:85:AB:
                                B0:F8:FC:5E:87:55:26:0F:15:D1:2E:72:BB:45:4B:14
                    Timestamp : Sep  4 15:33:02.377 2026 GMT
                    Extensions: none
                    Signature : ecdsa-with-SHA256
                                30:46:02:21:00:D0:2E:25:A4:9D:7F:C8:18:D6:7B:5E:...
                Signed Certificate Timestamp:
                    Version   : v1 (0x0)
                    Log ID    : 46:AF:86:3D:3B:3E:E5:9F:A5:77:DE:A8:24:5D:36:B0:
                                D9:ED:22:A2:23:F4:61:77:41:22:94:52:EE:95:50:5F
                    Timestamp : Sep  4 15:33:02.552 2026 GMT
                    Extensions: 00:00:05:00:24:DF:DB:0C
                    Signature : ecdsa-with-SHA256
                                30:44:02:20:31:2F:83:D6:42:65:26:0D:58:D7:DD:C3:...

El ID del log es el hash SHA-256 de la clave pública del log. Al buscar ambos ID en la lista de logs de Chrome (log_list.json, versión del 19 de octubre de 2026) se obtiene:

ID del log (base64)LogOperadorTipoEstado
2AlVO5RPev/IFhlvlE+Fq7D4/F6HVSYPFdEucrtFSxQ=Xenon2026h2GoogleRFC 6962, MMD de 24 hutilizable
Rq+GPTs+5Z+ld96oJF02sNntIqIj9GF3QSKUUu6VUF8=Tuscolo2026h2Geomysstatic-ct-api, MMD de 60 sutilizable

Dos logs de dos operadores distintos: el mínimo para un certificado de 90 días. La extensión de la segunda SCT no es ruido. Los logs que siguen la static-ct-api incluyen en la SCT la posición de la entrada en el log: tipo de extensión 0 (leaf_index), longitud 5 y un índice de 40 bits, aquí 618.650.380. Un monitor puede obtener esa entrada directamente en lugar de buscarla.

El decodificador de SCT hace esta búsqueda por ti. Muestra el nombre de cada log, su estado en las listas de Chrome y de Apple, y si el conjunto cumple la política de cada navegador. El decodificador de certificados muestra la extensión de las SCT junto con el resto del certificado.

Las SCT pueden llegar al navegador de tres formas:

  • Incrustadas en el certificado, como arriba. Es lo que hacen casi todas las CA, y no requiere nada por tu parte.
  • En la extensión TLS signed_certificate_timestamp. El servidor envía las SCT que obtiene por su cuenta. Pocos servidores lo admiten.
  • Grapadas en una respuesta OCSP. Chrome solo las aceptaba «en versiones anteriores a la versión 148», y como Let's Encrypt y otros están retirando OCSP, esta vía está desapareciendo (consulta OCSP y CRL en 2026).

Qué exigen los navegadores

Los tres grandes motores exigen CT para los certificados de las CA de sus programas públicos de raíces.

ChromeApple (Safari, iOS, macOS)Firefox
SCT incrustadas, vida útil ≤ 180 días2 de logs distintos22 de logs distintos
SCT incrustadas, vida útil mayor3 de logs distintos3 (181–398 días)3 de logs distintos
Diversidad de operadoresAl menos 2 operadores de logs distintosSe cuentan como máximo 1 (≤ 180 días) o 2 (vida útil mayor) SCT por operadorAl menos 2 operadores de logs distintos
Otras condicionesAl menos una SCT incrustada de un log que esté actualmente en estado Qualified, Usable o ReadOnlyAl menos una SCT incrustada de un log aprobado actualmente. Al menos una SCT de un log RFC 6962Al menos una SCT de un log admisible actualmente. La lista de logs procede de la de Chromium
SCT por TLS u OCSP2 de logs de confianza actualmente, 2 operadores. OCSP solo antes de Chrome 1482 de logs aprobados actualmente, una de ellas entregada por TLS u OCSP2 de logs admisibles, 2 operadores
Error si no se cumpleNET::ERR_CERTIFICATE_TRANSPARENCY_REQUIREDLa conexión fallaMOZILLA_PKIX_ERROR_INSUFFICIENT_CERTIFICATE_TRANSPARENCY

Fuentes: la política CT de Chrome, la política CT de Apple (abril de 2025) y la página sobre CT de Mozilla. Según MDN, Firefox exige CT en escritorio desde la versión 135 (febrero de 2025) y en Android desde la versión 145 (noviembre de 2025). La preferencia security.pki.certificate_transparency.mode muestra el modo: 2 significa que CT se exige.

Dos consecuencias prácticas:

  • Los navegadores dejan de exigir CT si su lista de logs es demasiado antigua. Chrome solo exige CT mientras su lista de logs más reciente tenga menos de 70 días, y la lista de Firefox caduca a las 10 semanas. Un equipo que lleva meses sin actualizarse no exige CT en absoluto, así que no lo uses para probar fallos de CT.
  • Las CA privadas están exentas. Las notas para empresas de Chrome dicen que CT «solo se aplica a las CA de confianza pública». Los certificados de una raíz que instalas tú mismo no necesitan SCT, y de todos modos los logs no los aceptan.

Los logs en sí

La lista de logs de Chrome del 19 de octubre de 2026 contiene 21 logs RFC 6962 utilizables, más 2 de solo lectura y 3 retirados. También incluye 22 logs static-ct-api utilizables y 37 en estado qualified. Once operadores gestionan logs utilizables o en estado qualified: Cloudflare, DigiCert, Geomys, GoDaddy, Google, HARICA, IPng Networks, Let's Encrypt, Microsec, Sectigo y TrustAsia. Los logs se dividen en fragmentos por tiempo. Un log llamado 2026h2 solo acepta certificados que caducan en el segundo semestre de 2026, lo que mantiene acotado el tamaño de cada log y permite retirarlo una vez caducados sus certificados.

Ambos tipos de logs aceptan envíos a través de los mismos endpoints de RFC 6962 (add-chain, add-pre-chain). Se diferencian en cómo los leen los monitores. Un log RFC 6962 responde a llamadas dinámicas a la API:

GET https://ct.googleapis.com/logs/eu1/xenon2026h2/ct/v1/get-sth (20 de octubre de 2026)
{"tree_size":2980148930,"timestamp":1792499093002,"sha256_root_hash":"wr3F5apMl2E7wQHqbAA1yKsqaZbAzBXTT8WTAeRAy8M=","tree_head_signature":"BAMARzBFAiEAsC3Pr7fsPwy0vchrMDIXka7HxrZANu5tcXclDCUqqSYCIGJ64SaIT0tjM5hCGfycNGPfu6FP8q8RvW14Q4SoyvVU"}

Son casi tres mil millones de entradas en un solo fragmento semestral. Un log static-ct-api (un log «tiled») publica la cabeza firmada de su árbol (signed tree head) como un checkpoint en texto plano, y sus entradas como teselas (tiles) inmutables de 256 entradas que las CDN pueden almacenar en caché:

GET https://tuscolo2026h2.skylight.geomys.org/checkpoint (20 de octubre de 2026, firmas acortadas)
tuscolo2026h2.sunlight.geomys.org
1007870339
aRhh7dPjYarH0itUM1LD+XJw7CW41z1+9tSnf3AizuY=

— tuscolo2026h2.sunlight.geomys.org W+DWDWi4dqCfFx8da0IS4+jwHKVL6ETEHGQCHn5y8rKflUhLRtLHQ3c6...
— grease.invalid Aui1jDc8Y7Uve7seHd/Pg1p+wHSUmw0+MTNyEKEAAbHaE5bY3Gi/MUZ3zBuk+NxUyhJL...
— tuscolo2026h2.sunlight.geomys.org 7BiSLwAAAaFZRnbMBAMARzBFAiA++3wWdtsK2H8l3IxZh6H/OQml...

Las primeras líneas son el origen, el tamaño del árbol y el hash raíz. Las líneas que empiezan por «—» son firmas. Observa que la URL de monitorización (skylight) es distinta de la URL de envío (sunlight). Ambas figuran en la lista de logs.

Dos servicios públicos de búsqueda cubren prácticamente todos los logs.

API de Cert Spotter (SSLMate). El endpoint de emisiones enumera los certificados no caducados de un dominio. Funciona sin clave para un número limitado de consultas por hora. Para uso en producción, SSLMate pide que te registres para obtener una clave. Estos son los certificados de ecdsa.com:

Cert Spotter: certificados no caducados de un dominio y sus subdominios
curl -s "https://api.certspotter.com/v1/issuances?domain=ecdsa.com&include_subdomains=true&expand=dns_names&expand=issuer"
Primer elemento de la respuesta (20 de octubre de 2026)
{
  "id": "16609031524",
  "tbs_sha256": "8c6f1f0bef5434da2012d5f29eab13f00bcec659f17832c07872ff600f61ecf5",
  "cert_sha256": "1396447e3454a081fe4e48dc1d5de18b7e3cf857ec1d7ff3c987d091c9024b04",
  "dns_names": [
    "ecdsa.com"
  ],
  "pubkey_sha256": "9a1fa381dad4630b83cf3a1a1a7a3da7f04577db8a41933dd9bac49dabfa8c29",
  "issuer": {
    "friendly_name": "Let's Encrypt",
    "pubkey_sha256": "2e8307068b6db620e4a39d068b5dee5d6ef5788cbb2c0b6d23ead84fcc17178c",
    "name": "C=US, O=Let's Encrypt, CN=YR1"
  },
  "not_before": "2026-08-19T14:52:58Z",
  "not_after": "2026-11-17T14:52:57Z",
  "revoked": false
}

En resumen, la respuesta contenía cinco emisiones:

Las cinco emisiones, una por línea
16609031524 2026-08-19 2026-11-17 Let's Encrypt ecdsa.com
16609045002 2026-08-19 2026-11-17 Let's Encrypt ecdsa.com,www.ecdsa.com
17525925247 2026-10-01 2026-12-30 Let's Encrypt *.ecdsa.com,ecdsa.com
17875915585 2026-10-19 2027-01-17 Let's Encrypt ecdsa.com,www.ecdsa.com
17878726033 2026-10-20 2027-01-18 Let's Encrypt ecdsa.com

Los resultados llegan en el orden en que SSLMate los descubrió. Para paginar, pasa el último id como after=. Un array vacío llega con un encabezado Retry-After, lo que permite usar el endpoint como un feed de sondeo periódico. Fíjate en lo que permite hacer el campo pubkey_sha256. Al compararlo con las claves de tus servidores, sabes qué certificados están desplegados de verdad y cuáles se emitieron y nunca se usaron.

crt.sh (Sectigo) tiene una interfaz web y una salida JSON (https://crt.sh/?q=example.com&output=json). Es gratuito y abarca un historial muy largo, incluidos los certificados caducados. También es un servicio compartido con mucha carga. Las cuatro consultas JSON que hicimos el 20 de octubre de 2026 devolvieron 502 Bad Gateway. Trátalo como una comodidad, no como una dependencia de tu monitorización.

La herramienta de historial de CT muestra los certificados de un dominio a lo largo del tiempo, con el emisor, la validez y los nombres de cada uno.

Monitorización de tus dominios

La búsqueda responde a «¿qué existe?». La monitorización responde a «¿qué hay de nuevo?» y te avisa a los pocos minutos u horas de la emisión. Opciones:

  • Un monitor alojado. El servicio alojado Cert Spotter de SSLMate y los paneles de varias CA envían correos electrónicos o webhooks cuando aparecen certificados nuevos para tus dominios.
  • certspotter, de código abierto (v0.25.0, septiembre de 2026), lee los logs por sí mismo. Enumeras los nombres en ~/.certspotter/watchlist (un punto inicial abarca todos los subdominios, por ejemplo .example.com), y por cada coincidencia te envía un correo o ejecuta los scripts de ~/.certspotter/hooks.d. Desde la v0.24 también incluye certspotter-authorize, que marca los certificados esperados para que solo los inesperados generen alertas.
  • La API de búsqueda como feed. Consulta periódicamente el endpoint de emisiones de Cert Spotter con after= y compara cada certificado nuevo con los emitidos por tu automatización.

Qué debe generar una alerta:

  1. Un emisor que no usas. Compáralo con tus registros CAA. Un certificado de una CA que tu CAA prohíbe es un incidente de la CA y debe notificarse a la CA.
  2. Nombres que no reconoces, sobre todo subdominios olvidados. Un certificado para old-campaign.example.com puede significar que alguien tomó el control de un registro DNS huérfano.
  3. Una clave pública que no generaste tú para un nombre que gestiona tu automatización.
  4. Certificados comodín, si tu política no los usa.

Con los certificados de 47 días, la emisión legítima se vuelve frecuente. Sin certspotter-authorize ni una comparación con los registros de tu cliente ACME, la fatiga de alertas hará que ignores el único certificado que importa.

CT y nombres privados

Todo lo que contiene un certificado de confianza pública se publica: cada nombre de la lista SAN, para siempre. Los nombres de host internos como jenkins.corp.example.com o staging-payments.example.com se hacen públicos en cuanto obtienes un certificado público para ellos, y cualquiera que lea los logs los ve, incluidos quienes rastrean en busca de objetivos. Opciones, según las notas para empresas de Chrome y la práctica habitual:

  • Usa una CA privada para los nombres internos. CT no se aplica y no se publica nada.
  • Usa un certificado comodín (*.corp.example.com) cuando un certificado público sea inevitable. Revela la zona, pero no cada host.
  • No cuentes con pedir a una CA pública que no lo registre en los logs. Entonces el certificado fallaría en todos los navegadores que exigen CT.

Errores frecuentes

  • Creer que una SCT demuestra la inclusión. Una SCT es una promesa de incluir la entrada dentro del MMD. Los auditores y los monitores comprueban que los logs la cumplen.
  • Contar duplicados. Las entradas del precertificado y del certificado de una misma emisión aparecen como dos filas en la mayoría de las herramientas de búsqueda. Comparten emisor y número de serie, así que elimina duplicados por ese par antes de contar certificados.
  • Esperar información de revocación en CT. Un certificado revocado permanece en el log para siempre. La revocación es un sistema aparte.
  • Usar un navegador antiguo para probar la exigencia de CT. La exigencia de CT se desactiva sola cuando la lista de logs del navegador está desactualizada.
  • Monitorizar con un único servicio gratuito. crt.sh sufre caídas. Usa una segunda fuente o tu propio monitor.

Fuentes

La salida de los comandos se generó el 20 de octubre de 2026 con OpenSSL 3.5.7 y curl 8.14.1 en node:24.22.0-trixie.