skip to content

Authenticated Denial

Proving a name is absent without an online key: NSEC's next-name chain, NSEC3's salted hashes and opt-out, and the zone-walking trade-off. Interviewers use it as the non-obvious part of the design.

on this pageshow

questions

6

In a DNSSEC-signed zone, how does an NSEC record prove that a queried name or record type does not exist?

level: middleimportance: must knowfreq 30%

answer

  1. the header carries no signature
  2. keys sign before the zone loads
  3. owner name, then next name
  4. a span that covers the query
  5. the owner's type list

basics

~20 s

An NSEC record names the next existing name in canonical order and lists the types at its owner. A signed NSEC spanning the queried name proves the name absent; one at that name, lacking the type, proves no data.

solid answer

~50 s

The DNS header, including the `NXDOMAIN` code, is not signed, and DNSSEC was designed so a zone can be signed before it is loaded, with no key on the servers - so nobody can sign a fresh "no such name" for every possible query. Instead the signer sorts every owner name into canonical order and gives each name an `NSEC` record whose **Next Domain Name** is the following name and whose **Type Bit Maps** list the types present at the owner; each `NSEC` is signed like any other RRset. For a missing name, the server returns the `NSEC` whose owner sorts before the query and whose next name sorts after it, plus an `NSEC` showing no wildcard could have matched (sometimes the same record). For a missing type at an existing name, it returns that name's own `NSEC`, whose bitmap lacks the type.

go deeper

for a junior

Recall that DNSSEC can prove a name is missing, not only that an answer is genuine, and that it does so with signed NSEC records the zone publishes in advance.

for a middle

Explain the Next Domain Name and Type Bit Maps fields, how a covering span proves a name error, how the owner's bitmap proves no data, and why the wildcard must be ruled out too.

for a senior

Read a real negative response: name the NSEC covering the query, the one covering the wildcard, and say what truncation does to the proof and why the header's response code is never trusted.

for a principal

Weigh what pre-signed gaps buy - no key on the servers, spans resolvers can reuse - against what they publish, an ordered list of every name, and when that pushes a zone elsewhere.

## Why absence needs its own signed record DNSSEC signs **RRsets** - the records of one type at one name - with `RRSIG` records. It does not sign the DNS message header, so the response code (`NXDOMAIN`, "no such name") and the header flags can be forged by anyone on the path (RFC 7129, section 3; RFC 9824, section 8). A resolver therefore cannot trust "this name does not exist" just because the header says so. The obvious fix - sign a statement naming the missing query name - clashes with the way DNSSEC was designed. The protocol assumes **offline signing**: the zone is signed once, ahead of time, and the authoritative servers serve the result without holding the private key. The set of names that do *not* exist is infinite, so their denials cannot be pre-computed one by one. A single generic "denied" record would be worse: an attacker could replay it to deny any name at all (RFC 7129, section 3). The design that survived signs the **gaps** instead. A zone has finitely many existing names; between each pair of neighbours lies a gap that can be described, signed once, and handed out whenever a query falls inside it. ## What an NSEC record holds The `NSEC` record (type 47, RFC 4034 section 4) has two fields: - **Next Domain Name** - the next owner name in the zone, in **canonical order**, that has authoritative data or is a delegation point. The last `NSEC` points back to the zone apex, closing the chain into a loop. - **Type Bit Maps** - the record types present at the `NSEC`'s own owner name, encoded as window blocks of bits. **Canonical order** (RFC 4034 section 6.1) sorts names by their rightmost label first, then the next label, comparing each label as an unsigned octet string with uppercase folded to lowercase. It is not plain left-to-right string sorting: in RFC 4034's own example, `yljkjljk.a.example` sorts before `z.example`, because the comparison starts at the rightmost label. ## A worked chain Suppose `example.org` holds an apex, `api`, `mail` and `www`. Its signer would publish this chain (each record also gets an `RRSIG`): ```dns example.org. 3600 IN NSEC api.example.org. NS SOA RRSIG NSEC DNSKEY api.example.org. 3600 IN NSEC mail.example.org. A AAAA RRSIG NSEC mail.example.org. 3600 IN NSEC www.example.org. A RRSIG NSEC www.example.org. 3600 IN NSEC example.org. A AAAA RRSIG NSEC ``` | Query | Response | Proof in the authority section | |---|---|---| | `dev.example.org A` | name error (`NXDOMAIN`) | `api -> mail` covers `dev`; `apex -> api` covers `*.example.org` | | `mail.example.org AAAA` | no data (`NOERROR`, empty answer) | `mail`'s own `NSEC`, whose bitmap has no `AAAA` | | `www.example.org A` | the answer | no denial needed | ## How a resolver reads the two proofs For a **name error** (RFC 4035 sections 3.1.3.2 and 5.4) the resolver, after checking the signatures (a separate topic), works through: 1. Find an `NSEC` whose owner sorts strictly before the query name and whose Next Domain Name sorts strictly after it. Nothing exists in that span, so the exact name does not exist. 2. Work out where a wildcard could have matched - `*.example.org` here - and find an `NSEC` that covers that name too. Here the apex record does, because `*` sorts before any letter. 3. Accept the denial only when both hold. One record can prove both points; the server then sends it once. For a **no-data** answer the name exists, so wildcard expansion cannot apply and a single `NSEC` at the query name suffices: the type is absent if its bit is clear. RFC 5155 spells out the same test for `NSEC3` and adds that the `CNAME` bit must also be clear, since a `CNAME` would have been followed instead. ## Edges worth knowing - **Empty non-terminals** - names with no records but with children - have no `NSEC` of their own; a query for one is answered from a covering record (RFC 4035 section 3.1.3.2 notes this case). - If the denial records do not fit, the server sets the **TC** bit and the resolver must re-ask, because a partial proof proves nothing. - A validator **ignores the `NSEC` and `RRSIG` bits** in a bitmap: a validated `NSEC` already proves both exist (RFC 4035 section 5.4). - Because a validated span covers every name inside it, a resolver following RFC 8198 can answer later queries for other names in the same gap from its cache. - The price of signing gaps in cleartext is that the chain lists every name in order, which is why `NSEC3` and online-signed alternatives exist. The design point to remember: DNSSEC proves absence with **signed statements about which names exist next to each other**, prepared in advance, not with a signed refusal written for each question.

  • How can a validating resolver reuse one validated NSEC record for other missing names?
    RFC 8198 updated RFC 4035 so that a validating resolver SHOULD use a cached, validated `NSEC` to synthesise `NXDOMAIN` or no-data answers for any name falling in its span, until the effective TTL or the signatures expire. That cuts latency and load on the authoritative servers and blunts floods of random subdomains; the cost is that a name added inside the span stays invisible to that resolver until then.
  • When can a single NSEC record prove both that the name is absent and that no wildcard matched?
    When one span covers both names. In a zone whose apex `NSEC` points to `api.example.org`, a query for `aaa.example.org` falls between the apex and `api`, and so does `*.example.org`, because `*` sorts before letters. RFC 4035 says the server then includes that `NSEC` and its `RRSIG` only once.

A printed, stamped page of a phone directory that shows 'Adams' followed directly by 'Baker' proves there is no 'Allen' - nobody has to write and sign a fresh letter for each enquiry, because the gap was certified when the page was printed.

saying these in an interview costs you the question

  • The NXDOMAIN response code is signed, so it is the proof that the name is missing.
  • In base DNSSEC the server signs a fresh denial for each missing name at query time.
  • An NSEC record lists the names that do not exist in the zone.
  • One NSEC covering the query name always suffices for NXDOMAIN; wildcards need no proof.
  • The Next Domain Name is simply the next name in plain alphabetical string order.
open as a page

Why does DNSSEC's NSEC record let anyone list every name in a signed zone, and what does NSEC3 change about it?

level: middleimportance: must knowfreq 25%

basics

~20 s

Each NSEC names the next existing name, so following the chain from the apex lists the whole zone. NSEC3 hashes owner names with SHA-1, so the chain shows hashes, not names, though guessable names still fall to offline dictionary attacks.

open as a page

A DNSSEC zone signed with NSEC3PARAM 1 0 100 AABBCCDD gets insecure or SERVFAIL negative answers from some validating resolvers; why, and what does RFC 9276 say to set?

level: seniorimportance: should knowfreq 12%

basics

~20 s

Every extra NSEC3 iteration adds hashing to each negative answer for servers and validators, so resolvers may treat counts above 0 as insecure or fail them. RFC 9276 requires 0 extra iterations and advises an empty salt: 1 0 0 -.

open as a page

For a DNSSEC hosting platform signing many customer zones, how do you choose between precomputed NSEC3, RFC 4470 minimally covering NSEC and RFC 9824 compact denial?

level: principalimportance: should knowfreq 6%

basics

~20 s

Precomputed NSEC3 keeps keys off the servers and lets resolvers reuse spans, but leaks guessable names. Minimally covering NSEC and compact denial stop enumeration but need online keys and leave no reusable spans; compact denial also turns NXDOMAIN into NOERROR.

open as a page

A DNSSEC registry zone with millions of mostly unsigned delegations uses NSEC3 opt-out; what does an opt-out record stop proving, and when is that acceptable?

level: seniorimportance: nice to knowfreq 9%

basics

~20 s

An opt-out NSEC3 record's span may hold unsigned delegations without asserting whether they exist, so they change without re-signing. Inside such spans unsigned delegations can be inserted or deleted undetected; signed names stay protected. Use it only in huge, sparsely signed zones.

open as a page

Why must a DNSSEC denial of a name also rule out a wildcard, and why can NSEC3 need three records where NSEC needs two?

level: seniorimportance: nice to knowfreq 8%

basics

~20 s

A missing name might still match a wildcard, so a denial must rule one out. NSEC's cleartext names show which ancestor exists; NSEC3's hashes hide it, so NSEC3 must match the closest encloser and cover the next closer name and the wildcard.

open as a page