Chapter 11 · Part IV · Trust & privacy

DNSSEC & the chain of trust

Plain DNS believes the first plausible answer it hears. DNSSEC lets the owner of a zone sign its records, so that a validating resolver can check with arithmetic, not faith, that an answer came from that owner and was not changed on the way. Each zone's key is vouched for by its parent, all the way up to one key at the root. This chapter assumes you know how names, servers and caches fit together; if not, start with networks · DHCP & DNS.

2010the year the root zone was signed; IANA's first root trust anchor (key tag 19036) is valid from 15 July 2010
2018 · 2026the two root key rollovers so far: KSK-2017 took over on 11 October 2018, and KSK-2024 began signing on 11 October 2026
0the NSEC3 iteration count RFC 9276 requires, with an empty salt: extra hashing costs everyone and protects almost nothing

Common mix-up: DNSSEC does not encrypt anything. A signed answer still crosses the network in plain text, readable by anyone on the path. DNSSEC is a tamper-evident seal, not an envelope; hiding your lookups is the job of encrypted DNS (Chapter 12). And the padlock in your browser is TLS, a separate system with separate keys.

The promise, exactly

What DNSSEC proves, and what it doesn't

A resolver that sends a question over UDP gets back a packet that could have come from anyone able to guess a few numbers in time. Chapter 13 covers how cache poisoning exploits that. The fix that removes the guessing game entirely is to make answers checkable: the zone's owner signs each set of records with a private key, publishes the matching public key, and any resolver can verify the signature. A forger can copy a signature, but cannot make a new one for different data.

RFC 4033, the overview of DNSSEC, lists exactly three things it provides. Data origin authentication: the records were published by whoever holds the zone's key. Data integrity: they were not altered after signing. Authenticated denial of existence: when the answer is "no such name" or "no such record type", that answer is signed too, so it cannot be forged either. RFC 9364, the current best-practice summary, points back to the same three.

Everything else is out of scope, and most DNSSEC confusion comes from expecting one of the missing items. The table is worth reading row by row.

QuestionDoes DNSSEC answer it?Why
Who published this?YesOnly the holder of the zone's private key can make a signature that verifies
Was it changed?Yes, detectedChanging one bit of a signed record makes its signature fail
Does it really not exist?YesNSEC and NSEC3 records sign the gaps between names
Can others see my lookups?NoNothing is encrypted; see Chapter 12
Will the site load?No promiseA broken signature makes the name fail on purpose (SERVFAIL)
Is the content honest?NoA signature proves who said it, not that it is true; a hijacked registrar account can publish signed nonsense
Is my laptop's copy safe?Only sometimesUsually the resolver validates, and the last hop to your device is unprotected
Go deeper: the last mile, and the DO, AD and CD bits

Most phones and laptops run a stub resolver: a small client that forwards every question to a recursive resolver and believes what comes back. In the usual deployment the recursive resolver does the validating. It sets the AD (Authentic Data) bit on answers it has proven secure. But the AD bit is just a bit in a packet, and anyone who can forge the answer can set it too. RFC 4035 (section 4.9.3) says a stub must not rely on validation done on its behalf unless it got the answer from a trusted resolver over a secure channel. That is one of the reasons encrypted DNS and local validation both matter.

Three flags matter here. DO (DNSSEC OK) lives in the EDNS part of a query and says "send me the signatures too"; without it a server leaves the RRSIG records out. AD in a reply means "I validated this". CD (Checking Disabled) in a query says "give me the data even if validation fails, I will check it myself"; it is also the switch every DNS engineer flips first when a name returns SERVFAIL, to see whether DNSSEC is the reason. RFC 6840 refined the rules: a resolver should only set AD in a reply when the query carried DO or AD. Where the bits sit in the header is Chapter 2's business.

The new vocabulary

Four records and two keys

DNSSEC adds no new servers and no new protocol messages. It adds record types, defined in RFC 4034, that travel in ordinary DNS answers.

  • DNSKEY holds a public key. It sits at the zone's apex, so the keys for example.test are the DNSKEY records at example.test. Each key has a key tag, a 16-bit checksum of the record used as a short nickname so a resolver can pick the right key quickly.
  • RRSIG is a signature over one RRset: all the records with the same name, class and type, signed together as a unit. It names the key that made it (by key tag and signer name), the algorithm, and a validity window, an inception and an expiration time. Outside that window the signature is worthless, which is what stops an attacker from replaying last year's answer forever.
  • DS (Delegation Signer) lives in the parent zone, next to the NS records of the delegation. It holds a hash of one of the child's DNSKEYs. This is the link in the chain: the parent signs the DS, and the DS pins the child's key.
  • NSEC and NSEC3 prove that something does not exist. They come later in this chapter.

Most zones use two keys with different jobs. The key-signing key (KSK) signs only the DNSKEY RRset; its hash is what goes up to the parent as the DS. The zone-signing key (ZSK) signs everything else. The split exists for convenience, not cryptography: you can change the ZSK as often as you like without talking to the parent, because the parent only knows about the KSK. A KSK has flag value 257 (the "secure entry point" bit set); a ZSK has 256. Some operators use one key for both jobs, a combined signing key, and that is perfectly valid.

Here is what a signed answer looks like. The data is simulated, on the reserved name example.test, but the format is exactly what dig +dnssec prints.

; dig +dnssec www.example.test A   (simulated answer)
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 2
; EDNS: version: 0, flags: do; udp: 1232
www.example.test.  3600 IN A      192.0.2.10
www.example.test.  3600 IN RRSIG  A 13 3 3600 20261029120000 20261022110000 41522 example.test. kD9w3x…
; RRSIG fields: type covered (A), algorithm (13), labels (3), original TTL,
; expiration, inception, key tag (41522), signer name, then the signature
Go deeper: what exactly gets signed

A signature has to be over bytes, and two servers must produce the same bytes for the same records, or verification would fail at random. RFC 4034 section 6 defines a canonical form: names in lowercase, uncompressed, the TTL replaced by the "original TTL" stored in the RRSIG (so a cache counting the TTL down does not break the signature), and the records of an RRset sorted by their data bytes.

The signed blob is the RRSIG's own fields (type covered, algorithm, labels, original TTL, expiration, inception, key tag, signer name) followed by every record of the RRset in canonical form. The signature field is then appended. The validator in Instrument 1 builds exactly these bytes, signs them with ECDSA P-256 (algorithm 13, RFC 6605) through your browser's WebCrypto, and verifies them the same way a resolver would.

The key tag algorithm (RFC 4034, Appendix B) is a simple checksum over the DNSKEY's data. It is not unique: two keys can collide, so a validator must try every key with a matching tag rather than trusting the tag as an identity.

Following the signatures upward

The chain of trust

A signature is only as good as your confidence in the public key that checks it. If a resolver fetched example.test's DNSKEY over the same unprotected channel as everything else, a forger could just send their own key with their own signatures. DNSSEC solves this by asking the parent. Validating www.example.test goes like this:

  1. The resolver starts from a key it already trusts: the trust anchor, a copy of the root's KSK (or its hash) built into the resolver's configuration.
  2. It fetches the root's DNSKEY RRset, finds the key that matches the anchor, and checks the RRSIG that key made over the whole set. Now the root's ZSK is trusted too.
  3. It fetches the DS record for test. from the root, checks the root ZSK's signature on it, and so learns a hash of test.'s KSK.
  4. It fetches test.'s DNSKEY RRset, hashes the KSK, compares it with the DS, and checks the KSK's signature over the set.
  5. Same again one level down: the DS for example.test, then example.test's DNSKEY RRset.
  6. Finally it checks the RRSIG on the A record with example.test's ZSK.

Every link is either a hash comparison (DS against DNSKEY) or a signature check (RRSIG against DNSKEY). Break any one and the chain stops there. That is the whole design.

DS digest = SHA-256( owner name ‖ DNSKEY RDATA )
The parent stores a hash of the child's key-signing key, computed over the child's name in wire format followed by the DNSKEY's flags, protocol, algorithm and public key. Digest type 2 (SHA-256) is what operators should publish today.

The root zone was signed in July 2010, and its key has been replaced twice since. The first root KSK rollover, from the 2010 key to KSK-2017 (key tag 20326), happened on 11 October 2018, after a one-year delay while ICANN studied how many resolvers still had only the old anchor. The second, to KSK-2024 (key tag 38696), happened on 11 October 2026, eleven days before this chapter was written. A resolver that never learns the new anchor stops validating anything at all, so rollovers at the root are planned years ahead.

Most resolvers learn new anchors automatically with RFC 5011. When the root publishes a new KSK in its DNSKEY set, signed by the old one, a resolver following RFC 5011 notices it, waits out an "add hold-down" of at least 30 days while it keeps seeing the new key, and only then trusts it. The waiting is the safety: someone who briefly stole the old key could not slip in a new anchor without the change being visible for a month.

Worked example: check the real root anchor yourself. Below is the public key of the root's current KSK, KSK-2024, exactly as IANA publishes it in root-anchors.xml. The button builds the DNSKEY data (flags 257, protocol 3, algorithm 8), prefixes the root's name (a single zero byte), hashes it with SHA-256 in your browser and computes the key tag. Compare the result with IANA's published digest.

; press the button
Instrument 1

Break the chain

Three simulated zones, ., test. and example.test., each with its own KSK and ZSK, generated fresh in your browser when the page loaded. Every RRSIG below is a real ECDSA P-256 signature over the canonical bytes, and every DS is a real SHA-256 digest. The validator walks the chain the way a resolver does. Change the trust anchor, swap the DS, tamper with the answer in transit or move the clock past the signatures' expiration, and watch which link fails and why. None of this touches the network.

Generating keys…
Resolver's trust anchor
DS for example.test. published in test.
Resolver returns–
Extended error–
Links checked–
Signatures–
    
          

    Simulated zones on reserved names; times are simulated, starting 22 October 2026 12:00 UTC. The leaf zone's signatures expire after 7 days, test.'s after 20, the root's after 13.

    Four verdicts

    Secure, insecure, bogus

    RFC 4033 gives every answer a validating resolver handles one of four states, and the difference between them is the most practical thing in this chapter.

    StateMeaningWhat the client sees
    SecureAn unbroken chain of signatures and DS links from a trust anchor to this dataThe answer, with the AD bit set
    InsecureThe chain proves, with a signed denial, that some delegation on the way has no DS: the zone is simply unsignedThe answer, without AD. Most of the DNS is in this state
    BogusThere should be a valid chain, and there isn't: a bad signature, an expired one, a DS that matches no key, missing RRSIGsSERVFAIL. The data is withheld
    IndeterminateNo trust anchor covers this name, so there is nothing to check againstThe answer, without AD

    "Insecure" sounds alarming but is ordinary: it means "provably unsigned", and the resolver treats the answer like plain DNS. "Bogus" is the alarm. A validating resolver refuses to hand out bogus data, because it cannot tell an attack from a mistake, and handing out data that might be forged would defeat the point. So a DNSSEC mistake looks, to a user, exactly like an outage: the site "doesn't exist", while friends on a non-validating network load it fine.

    Two tools make this less mysterious. Extended DNS Errors (RFC 8914) let a resolver attach a reason code to the SERVFAIL: 6 is "DNSSEC Bogus", 7 "Signature Expired", 8 "Signature Not Yet Valid", 9 "DNSKEY Missing" (a DS exists, but no matching key), 10 "RRSIGs Missing". And the CD bit lets you ask the same resolver to skip validation. If +cd makes the answer appear, the problem is the signatures, not the servers.

    ; dig www.example.test A   (simulated: the zone's signatures expired)
    ;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL, id: 4243
    ; EDE: 7 (Signature Expired)
    
    ; dig +cd www.example.test A   (same resolver, checking disabled)
    ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 4244
    www.example.test.  3600 IN A  192.0.2.10
    Go deeper: the time window and clock skew

    Signature validity is checked against the resolver's own clock. A resolver whose clock is days wrong sees good signatures as expired or not yet valid; this is a real cause of "DNSSEC broke everything" on small devices that boot without a correct time. Signers therefore backdate the inception by an hour or so to absorb skew, and re-sign well before expiration: a common habit is to sign for a few weeks and refresh at the halfway point.

    Most DNSSEC outages in the wild are not attacks at all. They are signatures that were allowed to expire because the signing job stopped, or DS records that no longer match the zone's keys. Both show up instantly in public checkers such as DNSViz and the Verisign DNSSEC Analyzer, which draw the same chain as Instrument 1 for real zones.

    Signing a gap

    Proving a negative

    Signing records that exist is easy. Signing "this name does not exist" is harder, because there are infinitely many names that don't exist and the signer cannot sign each one in advance, and a server that signs on demand has to keep its private key online. DNSSEC's answer is to sort the zone's names and sign the gaps between them.

    Sort every name in the zone in canonical order (RFC 4034 section 6.1: compare labels from the right, as lowercase bytes). Then give each name an NSEC record that says "the next name after me is X, and I hold these record types". If you ask for cat.example.test and the zone has blog and then mail, the signed NSEC at blog saying "next is mail" proves nothing lies between them. Its type list also proves "no such type" answers: the NSEC at mail listing only A proves there is no AAAA there. The resolver also needs one more NSEC proving no wildcard (*.example.test) could have produced an answer.

    NSEC has a side effect: anyone can follow the chain of "next" pointers and list every name in your zone. This zone walking takes one query per name. For many zones that doesn't matter (the names are in certificates and search engines anyway), but some registries consider their list of customers confidential.

    NSEC3 (RFC 5155) replaces each name with a hash of it before sorting. The chain now runs between hashes, so walking it gives you a list of hashes, not names. But hashes of short, common names can be guessed offline: hash www, mail, vpn and a few thousand more and see which match. NSEC3 originally allowed extra hash iterations and a salt to slow that guessing down. In practice the extra work fell mostly on resolvers and authoritative servers, an attacker with a graphics card shrugged it off, and RFC 9276 now says: iterations 0, no salt, and use plain NSEC unless you have a reason not to.

    Go deeper: aggressive negative caching and offline signing

    Because an NSEC record proves a whole range is empty, a resolver that has validated one can answer other questions in that range itself, without asking the authoritative server again. RFC 8198 allows exactly this "aggressive use" of the cache. It cuts the load from junk queries for random names, and it improves privacy a little, since fewer questions leave the resolver.

    The sorted chain also lets the zone be signed offline, once, with the private key kept away from the servers. Some large operators prefer the opposite trade, signing on the fly with "minimally covering" records (RFC 4470) or the "black lies" style of answer, which avoid zone walking at the cost of keeping keys on every server.

    NSEC3 has an opt-out flag, meant for huge zones like a top-level domain where most delegations are unsigned: unsigned delegations can be skipped from the chain. RFC 9276 says not to use it for small zones.

    Instrument 2

    Explore the gaps

    A simulated zone, example.test, with nine names. Ask for any name and type, and the explorer finds the records a signed server would send to prove the answer, using real canonical ordering for NSEC and real NSEC3 hashing (SHA-1 over the name in wire format, then the salt, repeated for each extra iteration, written in base32hex). Then walk the zone, and try guessing its names offline.

    Answer–
    Proof records–
    Closest encloser–
    SHA-1 per name–
    
          

    Changing keys without going dark

    Key rollovers

    Keys get replaced: on a schedule, after a staff change, when moving to a better algorithm, or when moving to a new DNS provider. The difficulty is caching. At any moment, resolvers around the world hold copies of your DNSKEY set, your signatures and your parent's DS, each fetched at a different time and each expiring on its own TTL. A rollover is safe only if every combination a resolver could be holding still validates. RFC 6781 describes the standard methods and RFC 7583 works out their timing in detail.

    • ZSK pre-publish. Add the new ZSK to the DNSKEY set, but keep signing with the old one. Wait at least the DNSKEY TTL, so every resolver's cached key set includes the new key. Switch the signatures to the new key. Wait at least the longest TTL of the signed data, so old signatures have aged out of caches. Then remove the old key.
    • Double signature. Sign everything with both keys for a while. Fewer steps, twice the signatures in every answer; it is the usual choice for KSKs, where only the DNSKEY set is affected.
    • KSK double-DS. Put the new key's DS in the parent next to the old one. Wait the DS TTL. Swap the KSK in your DNSKEY set. Wait the DNSKEY TTL. Remove the old DS.

    Talking to the parent used to mean a web form at your registrar. RFC 7344 added CDS and CDNSKEY: records the child publishes in its own signed zone saying "this is what my DS should be". A parent that supports them polls the child and updates the DS itself, which makes KSK rollovers routine. RFC 8078 extends the idea to turning DNSSEC on or off.

    The classic outage is changing DNS provider while the zone is signed. The new provider signs with its own keys, the DS at the parent still points at the old provider's KSK, and from the moment resolvers fetch the new keys every validating resolver returns SERVFAIL. The safe way is either to remove the DS first and wait out its TTL (going briefly insecure), or to have the two providers cooperate and publish each other's keys, the multi-signer model of RFC 8901. Instrument 3 shows both.

    Instrument 3

    Plan a rollover

    Pick a procedure, set the TTLs, and choose how long to wait between steps. The planner works out, hour by hour, whether some resolver somewhere could hold a combination of cached records that no longer validates, and marks those hours as bogus. It assumes the worst case: some resolver fetched each record at the worst possible moment. Real plans also add a margin for propagation to secondary servers and for the parent's own publishing delay.

    Verdict–
    Bogus hours–
    Insecure hours–
    Safe minimum waits–

    Which maths to use

    Algorithms, and DANE

    Each DNSKEY names its algorithm by number. For years the guidance lived in RFC 8624. In November 2025 RFC 9904 obsoleted it and moved the official recommendations into IANA's registries, so they can change without a new RFC; RFC 9905, published alongside it, deprecated SHA-1-based signing. The values below are the ones RFC 9904 placed in the registry, as updated by RFC 9905.

    AlgorithmNumberUse for signingNotes
    ECDSAP256SHA25613RecommendedSmall keys and signatures; the most common choice for new zones, and what Instrument 1 uses
    ED2551915RecommendedModern, fast, deterministic signatures
    RSASHA2568RecommendedThe root zone's algorithm; large signatures
    ECDSAP384SHA384, ED44814, 16MayValidators are recommended to support them
    RSASHA1, RSASHA1-NSEC3-SHA15, 7Must notRFC 9904 listed them as not recommended; RFC 9905 raised that to must not. Resolver operators must treat them as unsupported, so zones still using them become insecure
    RSAMD5, DSA1, 3, 6Must notRetired

    For DS records, digest type 2 (SHA-256) is the one to publish; SHA-1 (type 1) must not be used for new DS records. NSEC3's own hash is still SHA-1, which is acceptable there because it only obscures names; it is not a signature.

    Once names can be trusted, other things can hang off them. DANE (RFC 6698) publishes a hash of a server's TLS certificate or key in a signed TLSA record, at a name like _25._tcp.mail.example.test. A client that validates DNSSEC can then check a server's certificate against what the domain owner published, rather than (or as well as) trusting any of the hundreds of certificate authorities. It has found its main home in mail transport between servers; web browsers never adopted it.

    Go deeper: turning DNSSEC on, safely

    Most of the work is done by your DNS host's signer, but the order of steps matters. Sign the zone first and check it with DNSViz while nothing points at the keys yet; at this stage a mistake costs nothing, because without a DS the zone is merely insecure. Then publish the DS at the registrar (or let CDS do it), and check again. Monitor signature expiration as you would a TLS certificate. Before any provider change, plan the DS.

    NIST SP 800-81-2, the US government's guide to secure DNS deployment, covers the same lifecycle in more depth, including key storage and rollover scheduling.

    Cheat sheet

    Terms from this chapter

    DNSSEC
    Extensions that let a zone sign its records so resolvers can verify origin, integrity and non-existence. Signs; never encrypts.
    DNSKEY
    A record at a zone's apex holding one of its public keys.
    RRSIG
    A signature over one RRset, with the signer, key tag, algorithm and a validity window (inception to expiration).
    DS
    Delegation Signer: a hash of a child zone's key, published and signed in the parent. The link in the chain.
    KSK / ZSK
    Key-signing key (signs the DNSKEY set; its DS goes to the parent) and zone-signing key (signs everything else).
    Key tag
    A 16-bit checksum of a DNSKEY used as its short nickname. Not unique.
    Trust anchor
    A key a validator trusts without proof, normally the root KSK. Kept current with RFC 5011.
    Chain of trust
    The alternating DS hashes and RRSIG signatures that link a trust anchor to an answer.
    Bogus
    Validation state of data that should verify and does not. The resolver answers SERVFAIL.
    NSEC / NSEC3
    Signed records naming the next name (or hash) in the zone, proving the gap between is empty.
    Zone walking
    Listing every name in an NSEC-signed zone by following its next-name pointers.
    CDS / CDNSKEY
    Records a child publishes to tell its parent what its DS should be, so DS updates can be automated.
    DANE / TLSA
    Publishing a hash of a TLS certificate or key in signed DNS, so clients can check it without relying only on certificate authorities.
    Where this comes from

    Sources