DNSSEC20 (dnssec20)
Status: Draft
Purpose
- Verify that the NSEC or NSEC3 type bitmap at the zone apex accurately reflects the RR types actually present in the zone. An incomplete (subset) bitmap enables cache poisoning via RFC 8198 aggressive negative caching and replay attacks (see Petr Špaček, ISC, 2021-11-30, “Type Bitmap: Subset - Broken”).
Preconditions And Inputs
- Preconditions:
- A
zone.Zoneobject is available.
- A
- Required inputs:
- Child nameserver name/IP items from
methodsv2.GetDelNSNamesAndIPsandmethodsv2.GetZoneNSNamesAndIPs. - DNSKEY query response (DNSSEC enabled) to confirm zone is signed. In a full test run, this response is cached from earlier test cases (e.g., DNSSEC10); when running standalone, the query is made directly.
- NSEC or NSEC3PARAM query response to obtain the apex type bitmap. Also typically cached from DNSSEC10.
- Query responses for probed RR types: A, AAAA, MX, TXT. Typically cached from earlier test cases (Basic, Zone, Connectivity).
- Child nameserver name/IP items from
- Profile/config knobs that affect behavior:
net.ipv4andnet.ipv6: disabled transports are skipped with transport debug tags.resolver.defaults.parallel: per-nameserver parallel execution fanout.
Algorithm And Decision Flow
- Emit
TEST_CASE_START. - Build nameserver set from delegation+zone NS items, grouped by IP.
- For each unique nameserver IP (parallelized):
- If transport is disabled, emit
IPV4_DISABLEDorIPV6_DISABLEDfor rrtypeDNSKEYand skip. - Query child apex
DNSKEYwith DNSSEC enabled. - If response is absent, non-
NOERROR, or non-AA, classify nameserver asno_dnssecand skip. - If no apex DNSKEY records are present, classify nameserver as
no_dnssecand skip. - Query
NSEC(DNSSEC enabled) to obtain the apex type bitmap:- If NSEC record for the apex is present in the answer section, extract its type bitmap (NSEC zone).
- Else if NSEC3 record matching the apex hash is present in the authority section, extract its type bitmap (NSEC3 zone).
- If no bitmap obtained from the NSEC query, try
NSEC3PARAMquery and look for an NSEC record in the authority section (NODATA response). - If no bitmap could be obtained, classify nameserver as
no_bitmapand skip. - For each probed type (A, AAAA, MX, TXT):
- Query the apex for that type with DNSSEC enabled.
- If the response is
NOERRORwith at least one matching RR for the apex name in the answer section, the type exists. - If the type exists but is NOT present in the type bitmap, record a bitmap mismatch for that type.
- If transport is disabled, emit
- Aggregate results across nameservers:
- For each probed type with mismatches, emit
DS20_NSEC_BITMAP_MISMATCHES_RRTYPE(NSEC zones) orDS20_NSEC3_BITMAP_MISMATCHES_RRTYPE(NSEC3 zones) with mergedservers. - If all nameservers with DNSSEC show correct bitmaps, emit
DS20_BITMAP_OK. - If nameservers had DNSSEC but no bitmap could be obtained, emit
DS20_NO_BITMAP. - If no nameserver had DNSSEC (and no other findings), emit
DS20_NO_DNSSEC.
- For each probed type with mismatches, emit
- Emit
TEST_CASE_END.
Emitted Tags (Possible Set)
| Tag | Emitted when |
|---|---|
DS20_BITMAP_OK | All probed types present in the zone are correctly represented in the NSEC/NSEC3 type bitmap on all responding nameservers. |
DS20_NO_BITMAP | Nameserver has DNSKEY but no NSEC/NSEC3 bitmap could be obtained for the apex. |
DS20_NO_DNSSEC | No nameserver returned a usable DNSKEY; bitmap check skipped. |
DS20_NSEC3_BITMAP_MISMATCHES_RRTYPE | An existing RR type at the apex is missing from the NSEC3 type bitmap. Enables cache poisoning via RFC 8198. |
DS20_NSEC_BITMAP_MISMATCHES_RRTYPE | An existing RR type at the apex is missing from the NSEC type bitmap. Enables cache poisoning via RFC 8198. |
IPV4_DISABLED | IPv4 transport is disabled for a queried nameserver (DNSKEY). |
IPV6_DISABLED | IPv6 transport is disabled for a queried nameserver (DNSKEY). |
TEST_CASE_END | Testcase completion marker is emitted. |
TEST_CASE_START | Testcase start marker is emitted. |
Tag Arguments
| Tag | Argument key | Type | Meaning |
|---|---|---|---|
DS20_BITMAP_OK | servers | array<object> | Structured nameserver identities ({ns,address} object) with correct bitmaps. |
DS20_NO_BITMAP | servers | array<object> | Structured nameserver identities ({ns,address} object) where no bitmap was obtained. |
DS20_NO_DNSSEC | servers | array<object> | Structured nameserver identities ({ns,address} object) without DNSKEY. |
DS20_NSEC3_BITMAP_MISMATCHES_RRTYPE | query_type | string | RR type name missing from the NSEC3 bitmap (e.g., A, AAAA). |
DS20_NSEC3_BITMAP_MISMATCHES_RRTYPE | servers | array<object> | Structured nameserver identities ({ns,address} object) exhibiting the mismatch. |
DS20_NSEC_BITMAP_MISMATCHES_RRTYPE | query_type | string | RR type name missing from the NSEC bitmap (e.g., A, AAAA). |
DS20_NSEC_BITMAP_MISMATCHES_RRTYPE | servers | array<object> | Structured nameserver identities ({ns,address} object) exhibiting the mismatch. |
IPV4_DISABLED | ns | string | Nameserver identity (ns name only; use address for IP) skipped on IPv4. |
IPV4_DISABLED | address | string | Nameserver IP address for the same endpoint. |
IPV4_DISABLED | query_type | string | rrtype skipped (DNSKEY). |
IPV6_DISABLED | ns | string | Nameserver identity (ns name only; use address for IP) skipped on IPv6. |
IPV6_DISABLED | address | string | Nameserver IP address for the same endpoint. |
IPV6_DISABLED | query_type | string | rrtype skipped (DNSKEY). |
TEST_CASE_END | testcase | string | Testcase display name (DNSSEC20). |
TEST_CASE_START | testcase | string | Testcase display name (DNSSEC20). |
Severity Levels Per Tag
| Tag | Level | Notes |
|---|---|---|
DS20_BITMAP_OK | INFO | Default from share/profile.json (test_levels.DNSSEC). |
DS20_NO_BITMAP | WARNING | Default from share/profile.json (test_levels.DNSSEC). |
DS20_NO_DNSSEC | NOTICE | Default from share/profile.json (test_levels.DNSSEC). |
DS20_NSEC3_BITMAP_MISMATCHES_RRTYPE | ERROR | Default from share/profile.json (test_levels.DNSSEC). |
DS20_NSEC_BITMAP_MISMATCHES_RRTYPE | ERROR | Default from share/profile.json (test_levels.DNSSEC). |
IPV4_DISABLED | DEBUG | Default from share/profile.json (test_levels.DNSSEC). |
IPV6_DISABLED | DEBUG | Default from share/profile.json (test_levels.DNSSEC). |
TEST_CASE_END | DEBUG | Default from share/profile.json (test_levels.DNSSEC). |
TEST_CASE_START | DEBUG | Default from share/profile.json (test_levels.DNSSEC). |
Differences From Upstream
- Upstream reference: No upstream Zonemaster equivalent. DNSSEC20 is a new testcase unique to Gonemaster.
- Differences (Upstream vs Gonemaster):
- Upstream: no testcase verifies NSEC/NSEC3 type bitmap accuracy against actual RR types present. DNSSEC10 checks structural correctness of the bitmap (mandatory/forbidden types) but not completeness against observed data. Gonemaster: implements dynamic bitmap accuracy verification by probing common apex RR types and comparing against the bitmap.
- Potential upstream report:
no
Edge Cases And Limitations
- Nameserver evaluation is deduplicated by IP; multiple names mapped to one IP are merged into one query outcome and expanded in
servers. - Nameservers with non-
NOERRORor non-AADNSKEY responses are treated asno_dnssecand can only contribute toDS20_NO_DNSSEC. - The set of probed types (A, AAAA, MX, TXT) is intentionally limited to common apex types. DNSKEY, SOA, NS, RRSIG, and NSEC/NSEC3 are already validated structurally by DNSSEC10 and are not re-checked here.
- Super-set bitmaps (types listed in the bitmap but not actually present) are not flagged - only subset bitmaps (existing types missing from the bitmap) are checked, as these are the security-relevant case per the ISC presentation.
- For NSEC3 zones, the NSEC3 record must have an owner hash matching the apex for the bitmap to be used; non-matching NSEC3 records are ignored.
- All queries in DNSSEC20 benefit from the per-nameserver query cache. In a full test run (after DNSSEC10, Basic, Zone, etc.), most queries are cache hits with zero network overhead.
Evidence In Gonemaster
- Code paths:
engine/test/dnssec/dnssec.go(DNSSEC20 testcase function)
- Related tests:
engine/test/dnssec/dnssec_test.go(TestDNSSEC20BitmapOK, TestDNSSEC20NSECSubsetBitmap, TestDNSSEC20NSEC3SubsetBitmap, TestDNSSEC20NoDNSSEC)
- References:
- RFC 4034 (NSEC type bitmap format)
- RFC 5155 (NSEC3 type bitmap format)
- RFC 8198 (Aggressive Use of DNSSEC-Validated Cache)
- Petr Špaček, “NSEC* type bitmap discrepancies”, OARC 35, 2021-11-30