Encryption and trust
DNSSEC and encrypted DNS
Signed DNS answers, and DNS carried over an encrypted connection to a resolver you chose.
DNSSEC lets a resolver check that answers were signed by the zone's owner, so forged answers are detected.
A validating resolver marks answers that check out with the ad flag, answers a provably unsigned zone without
it (insecure), and refuses one that should be signed and is not, or does not match (bogus) with SERVFAIL.
It signs, it does not hide: answers still cross the network in the clear. DoH/DoT encrypt and authenticate the
path to the resolver, hiding lookups from the local network. Neither replaces TLS for the connection that follows.
How DNSSEC works, step by step
In the DNSSEC lab the root, lab and example.lab are signed, legacy.lab is
not, and the laptop (10.0.1.10) uses a validating resolver, validator (10.0.1.11). DNSSEC is defined in
RFC 4033 to 4035:
- The owner signs the zone with
dnssec-signzone. Every record set (all records of one name and type) gets an RRSIG, made with the zone-signing key (ZSK, DNSKEY flags 256). The key-signing key (KSK, flags 257) signs the DNSKEY set. Signatures carry a validity window, 30 days here, so the zone must be signed again before it ends. - The zone proves what does not exist. Signing adds an NSEC chain: each record names the next name in the zone and the types present, signed. "No such name" and "no such type" become signed statements.
- The parent vouches for the key.
labpublishes a DS forexample.lab, the SHA-256 digest of its KSK, and signs it. The links up to the root form the chain of trust. - The resolver asks for the proof. It sets the DO bit (DNSSEC OK) in the EDNS0 header and gets the RRSIGs with the records. It fetches each zone's DNSKEY set and the parent's DS, and checks every link from its trust anchor, the root's key, down to the answer.
- It gives a verdict. Secure: the answer goes out with the
adflag. Insecure: the parent proved with a signed NSEC that the child has no DS, so an unsigned answer is fine, withoutad. Bogus: something that must be signed is not, or does not match, and the client gets SERVFAIL with an Extended DNS Error (RFC 8914).
DNSSEC signs, it does not encrypt. DNS over TLS (RFC 7858, TCP port 853) and DNS over HTTPS (RFC 8484, port
443, path /dns-query) encrypt the hop from a client to its resolver; the
zones and encrypted DNS lab asks the same name both ways.
What it looks like on a Linux machine
The validator runs unbound. +dnssec asks for the signatures, +multi splits them over lines:
$ dig +dnssec +multi +noall +answer www.example.lab
www.example.lab. 60 IN A 10.0.2.14
www.example.lab. 60 IN RRSIG A 13 3 60 (
20261109171951 20261010171951 25648 example.lab.
xRH3/d/tCLba9elW6gv8YWoYntOtkA7MkhCH1TB01URi
JIgu4+PeMC4rIMb7/6XPWAEFGJ6SZVk9ONWKphPrMA== )
Type covered, algorithm 13 (ECDSA P-256 with SHA-256), 3 labels, original TTL 60, expiry, inception, key tag,
signer. A plain query shows flags: qr rd ra ad;. Then the lab changes www in the signed zone file to the
attacker's 10.0.2.15 without re-signing:
$ dig www.example.lab
;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL, id: 9313
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1
; EDE: 6 (DNSSEC Bogus): (validation failure <www.example.lab. A IN>: signature crypto failed from 10.0.2.12)
$ dig +noall +comments +answer +cd www.example.lab
;; flags: qr rd ra cd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
www.example.lab. 60 IN A 10.0.2.15
+cd (checking disabled) shows the bogus data for debugging. The second resolver, plainResolver, does not
validate and hands out 10.0.2.15. delv www.example.lab checks the chain on the laptop itself and prints
; fully validated, ; unsigned answer for www.legacy.lab, or the reason it failed.
What goes wrong, and how you see it
The signatures expire. Nobody re-signs, the validity window ends, and every name in the zone turns
SERVFAIL at once, with EDE: 7 (Signature Expired). Let the name server sign on a schedule (BIND's
dnssec-policy) instead of by hand.
A key changed, the DS did not. A new KSK without a new DS in the parent breaks the chain: EDE: 6 (DNSSEC Bogus), "no keys have a DS". Compute the DS with dnssec-dsfromkey -2, publish it in the parent, then retire the
old key.
A forged answer arrives. Something on the path answers for the signed zone without signatures. The validator
refuses it: EDE: 10 (RRSIGs Missing). This is DNSSEC doing its job.
The trust anchor is wrong. Every signed name fails, and so do unsigned ones, because proving a zone is unsigned
also needs a signature from above. Check grep trust-anchor /etc/unbound/unbound.conf against the root's real DS.
The clock is wrong. Signatures carry absolute times, so a validator with a bad clock finds valid ones expired or not yet valid. Check NTP before blaming the zone.
Questions people ask
Does DNSSEC encrypt DNS? No. Queries and answers still cross the network in the clear. DNSSEC proves an answer came unchanged from the zone's owner; DoT and DoH hide it from the path.
Does DNSSEC stop DNS spoofing? Between a validating resolver and the authoritative servers, yes: a forged or altered answer for a signed zone is refused. Between the laptop and its resolver it does not, unless the laptop validates itself or uses an encrypted link. See DNS spoofing and the DNS spoofing lab.
What does SERVFAIL mean on a signed domain? Often a validation failure. Run the query again with +cd: if an
answer appears, the data is bogus, and the EDE line says why.