Pular para o conteúdo
ecdsa.com
← Todos os artigos

Cadeia de confiança DNSSEC: DS, DNSKEY, RRSIG e falhas

Um resolvedor validador confia em uma única chave, a da raiz, e segue ponteiros assinados até a resposta. Toda queda de DNSSEC é um elo quebrado nessa cadeia. Esta página percorre uma cadeia real com dig e delv e depois quebra uma de propósito em laboratório para mostrar como cada erro se manifesta.

Resposta curta. O DNSSEC liga as zonas com dois tipos de registro. Um registro DS na zona pai contém um hash da chave de assinatura de chaves da zona filha (DNSKEY, flags 257). Essa chave assina o conjunto DNSKEY da zona filha, e a chave de assinatura da zona (flags 256) assina os registros propriamente ditos com RRSIGs. Um resolvedor validador parte da chave da raiz em que confia e verifica cada elo até a resposta. Se qualquer elo falhar, ele retorna SERVFAIL em vez dos dados. Verifique uma cadeia com o delv (“fully validated”) ou com dig +dnssec (a flag ad), compare o DS da zona pai com o DNSKEY da zona filha usando o dnssec-dsfromkey e use +cd para ver se os dados estão lá, mas não passam na validação. A maioria das quedas vem de rollovers de chaves (a substituição planejada das chaves): um DS não atualizado depois de uma mudança de KSK, assinaturas que expiraram sem ser renovadas ou chaves trocadas mais rápido do que os caches expiram.

Os quatro registros

RegistroOnde ficaO que contém
DNSKEYNa própria zonaChaves públicas. O valor de flags 257 indica uma chave de assinatura de chaves (KSK, com o bit “SEP” ativado), e 256, uma chave de assinatura da zona (ZSK)
RRSIGAo lado de cada conjunto de registros assinadoUma assinatura feita por uma chave sobre um conjunto de registros (RRset), com o horário de início, o horário de expiração e a key tag da chave de assinatura
DSNa zona pai, na delegaçãoUm digest de um dos registros DNSKEY da zona filha: key tag, algoritmo, tipo de digest, digest
NSEC / NSEC3Na zonaProva assinada de que um nome ou tipo não existe

O modelo separa as chaves por função. A KSK assina apenas o RRset DNSKEY, e o hash dela fica na zona pai. Trocá-la exige envolver a zona pai (o registrador ou o registry). A ZSK assina todo o resto e pode ser trocada sem envolver a zona pai. Uma zona também pode usar uma única chave combinada (CSK) para as duas funções, que é o que faz default, a política dnssec-policy embutida no BIND (csk ... algorithm 13). As regras são as mesmas; a chave apenas tem flags 257 e assina tudo.

Percorrendo uma cadeia real com dig

www.isc.org, passo a passo, em 20 de outubro de 2026 (dig do BIND 9.20.10, consultas enviadas a 1.1.1.1). Primeiro, a raiz. O conjunto DNSKEY dela tem uma ZSK e duas KSKs:

dig . DNSKEY +multiline (resumido)
.			2158 IN	DNSKEY 256 3 8 (
) ; ZSK; alg = RSASHA256 ; key id = 8763
.			2158 IN	DNSKEY 257 3 8 (
) ; KSK; alg = RSASHA256 ; key id = 20326
.			2158 IN	DNSKEY 257 3 8 (
) ; KSK; alg = RSASHA256 ; key id = 38696

A chave 20326 é a KSK-2017, e a 38696 é a KSK-2024. O rollover da KSK da raiz aconteceu nove dias antes desta captura. Nas palavras da ICANN: “Em 11 de outubro de 2026, às 14:00 UTC, a KSK-2024 começou a assinar a zona raiz do DNS, conforme programado”. A assinatura sobre o conjunto DNSKEY da raiz confirma isso:

dig . DNSKEY +dnssec: a assinatura sobre o conjunto de chaves da raiz
.			1587 IN	RRSIG DNSKEY 8 0 172800 (
20261101000000 20261011000000 38696 .

É o único RRSIG sobre esse conjunto. A chave antiga continua publicada até a revogação planejada, mas não assina mais. Um resolvedor que confia apenas na KSK-2017, porque nunca recebeu a KSK-2024 pelas atualizações automáticas da RFC 5011 nem por uma atualização de software, não consegue mais validar nada.

Em seguida, cada delegação. O DS da zona pai identifica a KSK da zona filha pela key tag:

dig org. DS, dig org. DNSKEY, dig isc.org. DS, dig isc.org. DNSKEY (resumido)
org.			81000	IN	DS	26974 8 2 4FEDE294C53F438A158C41D39489CD78A86BEB0D8A0AEAFF14745C0D 16E1DE32
) ; ZSK; alg = RSASHA256 ; key id = 25488
) ; ZSK; alg = RSASHA256 ; key id = 11859
) ; ZSK; alg = RSASHA256 ; key id = 24060
) ; KSK; alg = RSASHA256 ; key id = 725
) ; KSK; alg = RSASHA256 ; key id = 26974
isc.org.		3600	IN	DS	7250 13 2 A30B3F78B6DDE9A4A9A2AD0C805518B4F49EC62E7D3F4531D33DE697 CDA01CB2
) ; ZSK; alg = ECDSAP256SHA256 ; key id = 27566
) ; KSK; alg = ECDSAP256SHA256 ; key id = 7250

O DS de org. na raiz aponta para a chave 26974, que org. publica como KSK. O DS de isc.org. em org. aponta para a chave 7250, a KSK de isc.org. Repare na mudança de algoritmo na descida: org. assina com RSA (algoritmo 8), e isc.org, com ECDSA P-256 (algoritmo 13). Cada zona escolhe o seu. Por fim, a resposta e a assinatura dela feita pela ZSK de isc.org, a 27566:

dig www.isc.org. A +dnssec +multiline
www.isc.org.		300 IN A 151.101.3.42
www.isc.org.		300 IN A 151.101.67.42
www.isc.org.		300 IN A 151.101.131.42
www.isc.org.		300 IN A 151.101.195.42
www.isc.org.		300 IN RRSIG A 13 3 300 (
				20261103074926 20261020065242 27566 isc.org.
				qz5Qb4BFyOw4PRXBJjeK61LrPSKo6G2Ma1aFwNwZ57x5
				bFIg/d3EoMHtXopLYU949QQtMjcQ8BWULk7a629tLA== )

Os campos do RRSIG são: tipo coberto A, algoritmo 13, 3 rótulos, TTL original 300, expiração 2026-11-03 07:49:26 UTC, início 2026-10-20 06:52:42 UTC, key tag 27566, signatário isc.org.. Um resolvedor validador que verifica tudo isso ativa a flag AD (authenticated data, dados autenticados):

dig www.isc.org A +dnssec @1.1.1.1
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 5, AUTHORITY: 0, ADDITIONAL: 1

O ad é uma afirmação do resolvedor e só merece tanta confiança quanto o caminho até ele. Para validar por conta própria, use o delv, que faz todo o percurso localmente a partir das âncoras de confiança da raiz embutidas nele. O +rtrace mostra as buscas:

delv @1.1.1.1 www.isc.org A +rtrace (BIND 9.20.10, resumido)
;; fetch: www.isc.org/A
;; fetch: isc.org/DNSKEY
;; fetch: isc.org/DS
;; fetch: org/DNSKEY
;; fetch: org/DS
;; fetch: ./DNSKEY
; fully validated

O dig +sigchase, que guias mais antigos recomendam, não existe mais: o dig 9.20 responde dig: +sigchase option no longer supported. Use o delv. Para fazer o mesmo percurso no navegador via DNS-over-HTTPS, o inspetor de DNSSEC busca cada elo, verifica cada RRSIG com código próprio e aponta o elo que quebra.

Algoritmos 8, 13 e 15

O número do algoritmo aparece nos registros DNSKEY, DS e RRSIG. A RFC 9904 (novembro de 2025) substituiu a RFC 8624 e transferiu as recomendações para o próprio registro da IANA; a RFC 9905, publicada junto com ela, proíbe assinar com os dois algoritmos SHA-1:

NúmeroAlgoritmoAssinaturaValidação
5, 7RSA/SHA-1Proibido (MUST NOT)Implementação obrigatória (MUST); os operadores de resolvedores o tratam como algoritmo sem suporte
8RSA/SHA-256Recomendado (RECOMMENDED), implementação obrigatória (MUST)Implementação obrigatória (MUST)
10RSA/SHA-512Não recomendado (NOT RECOMMENDED)Implementação obrigatória (MUST)
13ECDSA P-256/SHA-256Recomendado (RECOMMENDED), implementação obrigatória (MUST)Implementação obrigatória (MUST)
14ECDSA P-384/SHA-384Opcional (MAY)Recomendado (RECOMMENDED)
15Ed25519Recomendado (RECOMMENDED)Recomendado (RECOMMENDED)
16Ed448Opcional (MAY)Recomendado (RECOMMENDED)

Para os digests de DS, use SHA-256 (tipo 2). O SHA-1 (tipo 1) é “MUST NOT” para delegações, embora os validadores ainda precisem oferecer suporte a ele. Das dez zonas que verificamos em 20 de outubro de 2026, com., net., nl., cloudflare.com, isc.org, ietf.org, nic.cz e sidn.nl assinam com o 13, enquanto org. e de. usam o 8, assim como a raiz. Assinar a mesma zona com cada algoritmo mostra por que o 13 é popular:

dnssec-keygen / dnssec-signzone 9.20.29: uma zona, três algoritmos
algorithm 8  RSASHA256         ZSK public key 260 bytes, RRSIG signature 256 bytes
algorithm 13 ECDSAP256SHA256   ZSK public key  64 bytes, RRSIG signature  64 bytes
algorithm 15 ED25519           ZSK public key  32 bytes, RRSIG signature  64 bytes

Assinaturas pequenas mantêm as respostas abaixo do limite de tamanho do UDP (1232 bytes é o buffer EDNS usual hoje), o que evita a fragmentação e a repetição da consulta por TCP. O algoritmo 15 tem as menores chaves, mas o suporte nos validadores é RECOMMENDED, e não MUST, então verifique os resolvedores do seu público-alvo antes de escolhê-lo.

Quebrando uma cadeia de propósito

Para ver as falhas sem quebrar um domínio real, o laboratório abaixo roda duas instâncias do BIND 9.20.29 no Debian 13. Uma é um servidor autoritativo para uma raiz privada ., para lab. e para shop.lab., todas assinadas com o algoritmo 13. A outra é um resolvedor validador cuja única âncora de confiança é o DS dessa raiz privada. As etapas de geração de chaves e de assinatura usam as ferramentas comuns do BIND:

Trecho do laboratório: chaves, assinatura e a âncora de confiança do resolvedor
keygen() { dnssec-keygen -q -K keys -a ECDSAP256SHA256 -L 3600 "$@"; }
for z in . lab shop.lab; do keygen -fKSK "$z" >/dev/null; keygen "$z" >/dev/null; done

# the parent includes the child's dsset file before signing
cat auth/db.lab.unsigned auth/dsset-shop.lab. > auth/db.lab
dnssec-signzone -q -S -K keys -d auth -o lab -f auth/db.lab.signed auth/db.lab

read -r _ _ _ tag alg dt d1 d2 < auth/dsset-.
echo "trust-anchors { . static-ds $tag $alg $dt \"$d1$d2\"; };" > anchors.conf

1. Tudo certo. O DS em lab. identifica a KSK de shop.lab., o resolvedor ativa o ad e o delv valida:

Laboratório, caso 1
DS in lab.: shop.lab. 48794 13 2
DNSKEY in shop.lab.: ZSK; alg = ECDSAP256SHA256 ; key id = 6251
DNSKEY in shop.lab.: KSK; alg = ECDSAP256SHA256 ; key id = 48794
$ dig @127.0.0.1 www.shop.lab A +dnssec
;; ->>HEADER<<- opcode: QUERY, status: NOERROR
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1
www.shop.lab.		5	IN	A	192.0.2.10
$ delv @127.0.0.2 -a anchors.conf www.shop.lab A
; fully validated
www.shop.lab.		5	IN	A	192.0.2.10

2. KSK substituída na zona filha, DS não atualizado na zona pai. É a queda clássica depois de uma mudança de hospedagem de DNS ou de um rollover automatizado da KSK que ninguém concluiu no registrador:

Laboratório, caso 2
DS in lab.: shop.lab. 48794 13 2
DNSKEY in shop.lab.: KSK; alg = ECDSAP256SHA256 ; key id = 11943
DNSKEY in shop.lab.: ZSK; alg = ECDSAP256SHA256 ; key id = 6251
$ dig @127.0.0.1 www.shop.lab A +dnssec
;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1
$ dig @127.0.0.1 www.shop.lab A +dnssec +cd
;; ->>HEADER<<- opcode: QUERY, status: NOERROR
;; flags: qr rd ra cd; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1
www.shop.lab.		5	IN	A	192.0.2.10
$ delv @127.0.0.2 -a anchors.conf www.shop.lab A
;; validating shop.lab/DNSKEY: no valid signature found (DS)
;; broken trust chain resolving 'www.shop.lab/A/IN': 127.0.0.2#53
;; resolution failed: broken trust chain

O DS ainda diz 48794; a zona agora tem a KSK 11943. O +cd (checking disabled, verificação desativada) retorna os dados, o que prova que a zona está no ar e só a validação falha. É o jeito mais rápido de distinguir uma falha de DNSSEC de uma indisponibilidade.

3. Assinaturas expiradas. O DS foi corrigido, mas a zona foi assinada uma vez e nunca mais reassinada. Aqui o laboratório a assina com início há dez dias e expiração há uma hora:

Laboratório, caso 3
RRSIG inception 20261010131152 expiration 20261020121152
$ dig @127.0.0.1 www.shop.lab A +dnssec
;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1
; EDE: 7 (Signature Expired): (shop.lab/DNSKEY)
$ delv @127.0.0.2 -a anchors.conf www.shop.lab A
;; validating shop.lab/DNSKEY: no valid signature found (DS)
;; broken trust chain resolving 'www.shop.lab/A/IN': 127.0.0.2#53
;; resolution failed: broken trust chain

O BIND anexa um erro de DNS estendido (Extended DNS Error, RFC 8914) que indica a causa: EDE: 7 (Signature Expired). A assinatura estática com dnssec-signzone gera, por padrão, assinaturas de 30 dias (a primeira assinatura do laboratório produziu início 20261020120639 e expiração 20261119120639), então uma tarefa do cron que parou de reassinar causa exatamente isso um mês depois. Em vez disso, deixe o servidor DNS assinar e reassinar automaticamente: a dnssec-policy no BIND, cujo padrão renova assinaturas de 14 dias a cada 5 dias, ou o equivalente no Knot ou no PowerDNS.

4. ZSK trocada de uma só vez. A zona substitui a ZSK e reassina tudo com a nova chave imediatamente. Um resolvedor que guardou em cache o conjunto DNSKEY antigo (TTL 3600) recebe um registro A assinado por uma chave que ele não tem:

Laboratório, caso 4
$ dig @127.0.0.1 www.shop.lab A +dnssec
;; ->>HEADER<<- opcode: QUERY, status: NOERROR
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1
www.shop.lab.		5	IN	A	192.0.2.10
resolver cache: DNSKEY flags 256 TTL 3600
resolver cache: DNSKEY flags 257 TTL 3600
(6 s later: the A record's 5 s TTL has expired, the cached DNSKEY set's 3600 s TTL has not)
$ dig @127.0.0.1 www.shop.lab A +dnssec
;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1
(resolver restarted, cache empty)
$ dig @127.0.0.1 www.shop.lab A +dnssec
;; ->>HEADER<<- opcode: QUERY, status: NOERROR
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1
www.shop.lab.		5	IN	A	192.0.2.10

A zona em si é válida: um resolvedor com o cache vazio a valida. Mas todo resolvedor que guardou em cache o conjunto de chaves antigo falha até essa entrada do cache expirar. A queda é intermitente e depende do resolvedor — o tipo mais difícil de depurar.

Rollovers que não quebram nada

A RFC 6781 descreve as sequências seguras. A regra por trás de todas elas é que todo resolvedor precisa conseguir validar com qualquer mistura de registros antigos e novos que tenha em cache.

  • ZSK, pré-publicação (pre-publish). Adicione a nova ZSK ao conjunto DNSKEY enquanto a antiga ainda assina. Espere pelo menos o TTL do DNSKEY, para que todo cache tenha as duas chaves. Passe a assinar com a nova chave. Espere o maior TTL dos dados assinados, para que as assinaturas antigas saiam dos caches. Depois remova a chave antiga.
  • KSK, assinatura dupla (double-signature). Adicione a nova KSK e assine o conjunto DNSKEY com as duas. Envie o novo DS para a zona pai. Espere até que a zona pai o publique e o DS antigo expire nos caches (o TTL do DS, muitas vezes uma hora ou um dia). Só então remova a KSK antiga.
  • Rollover de algoritmo (por exemplo, de 8 para 13). As novas chaves do novo algoritmo precisam assinar tudo antes de o novo DS aparecer, e o algoritmo antigo precisa continuar assinando até o DS antigo sumir. A RFC 6781 §4.1.4 traz a sequência completa.
  • Automatize o lado da zona pai. Os registros CDS e CDNSKEY (RFC 8078) permitem que uma zona pai que ofereça suporte a eles obtenha o novo DS a partir da zona filha. Sem isso, a etapa do DS é manual no registrador, e é nela que os rollovers empacam.
  • Troca de provedor de DNS. Faça uma migração coordenada com vários signatários (multi-signer) ou remova primeiro o DS no registrador, espere o TTL dele e reative o DNSSEC com a chave do novo provedor. Mover os registros NS enquanto o DS antigo continua lá é o caso 2 em produção.

A dnssec-policy do BIND e os gerenciadores de chaves do Knot e do PowerDNS implementam esses tempos para você. A falha comum não está na ferramenta, mas na etapa da zona pai: um DS que precisa ser colado no formulário web de um registrador.

Como diagnosticar um SERVFAIL

  1. É DNSSEC? dig name +cd retorna dados enquanto dig name dá SERVFAIL → falha de validação. Procure uma linha EDE: 6 (DNSSEC Bogus), 7 (Signature Expired), 8 (Signature Not Yet Valid), 9 (DNSKEY Missing), 10 (RRSIGs Missing).
  2. Qual elo? Rode delv name +rtrace e leia a primeira etapa que falha.
  3. DS versus DNSKEY: calcule o DS a partir das chaves da zona filha e compare-o com o da zona pai:
DS na zona pai vs. DS calculado a partir do DNSKEY da zona filha (bind9-utils 9.20.29)
$ dig +short DS isc.org @1.1.1.1
7250 13 2 A30B3F78B6DDE9A4A9A2AD0C805518B4F49EC62E7D3F4531D33DE697 CDA01CB2
$ dig +cd +noall +answer DNSKEY isc.org @1.1.1.1 | dnssec-dsfromkey -2 -f - isc.org
isc.org. IN DS 7250 13 2 A30B3F78B6DDE9A4A9A2AD0C805518B4F49EC62E7D3F4531D33DE697CDA01CB2
$ dig +short DS dnssec-failed.org @1.1.1.1
42069 13 2 62726F6B656E20636861696E206F662074727573742073656E642068 656C7021
$ dig +cd +noall +answer DNSKEY dnssec-failed.org @1.1.1.1 | dnssec-dsfromkey -2 -f - dnssec-failed.org
dnssec-failed.org. IN DS 50719 13 2 D602C971A02AF89B7661B99D6DD1B9E2EC876617631D04F633902A42CD4D6BBD

O isc.org confere. O dnssec-failed.org é um domínio de teste quebrado de propósito, servido pelos servidores de nomes da Comcast (dns101.comcast.net e outros). O DS dele identifica a chave 42069, que não existe, e o digest é o texto ASCII de “broken chain of trust send help!”. Por isso os resolvedores públicos o rejeitam:

dig @1.1.1.1 dnssec-failed.org A
;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL, id: 59477
; EDE: 9 (DNSKEY Missing): (no SEP matching the DS found for dnssec-failed.org.)
  1. Horários das assinaturas: compare o início e a expiração do RRSIG com a hora UTC atual. Um signatário ou um validador com o relógio errado leva a erros “not yet valid” (ainda não válida) ou “expired” (expirada).
  2. Falhas que dependem do resolvedor depois de uma mudança de chave apontam para o cache (caso 4). Verifique os TTLs dos conjuntos DNSKEY e DS e o horário da mudança.

O que o DNSSEC possibilita

Uma cadeia de confiança que funciona é a base para registros que precisam de autenticidade, e não só de disponibilidade. O DANE/TLSA fixa chaves TLS no DNS e é usado no SMTP entre servidores de e-mail. O gerador de registros TLSA cria esses registros. Os registros CAA são verificados pelas CAs, e desde 15 de março de 2026 os Baseline Requirements do CA/Browser Forum exigem a validação DNSSEC das consultas CAA quando a zona é assinada. Por isso, uma cadeia quebrada também pode bloquear a emissão de certificados.

Fontes

As consultas reais foram feitas em 20 de outubro de 2026 no nicolaka/netshoot:v0.14 (dig e delv do BIND 9.20.10). O laboratório e o dnssec-dsfromkey rodaram no debian:trixie-20261005-slim, com o BIND 9.20.29 do Debian.