DNSSEC02
Status: Final
Purpose
- Verify that DS records found at the parent delegation match usable DNSKEYs in the child zone and that matching DNSKEYs can validate DNSKEY RRset signatures.
Preconditions And Inputs
- Preconditions:
- A
zone.Zoneobject is available.
- A
- Required inputs:
- Parent nameserver names/IPs from
ParentNameservers. - Child nameserver sets from
GlueNameserversandApexNameservers. - Parent DS responses and child DNSKEY/RRSIG responses.
- Parent nameserver names/IPs from
- Profile/config knobs that affect behavior:
net.ipv4andnet.ipv6: disabled transports are skipped with transport debug tags.resolver.defaults.parallel: parallel parent and child query execution fanout.
Algorithm And Decision Flow
- Emit
TEST_CASE_START. - Collect DS records from parent nameservers:
- Query each unique parent nameserver IP in parallel.
- If transport is disabled, emit
IPV4_DISABLEDorIPV6_DISABLEDfor rrtypeDSand skip. - Accept response only if DNSSEC response shape passes (
NOERROR,OPT,DO,AA) and at least one DS record matches child zone owner name. - Add unique DS RDATA values to DS record set.
- If DS record set is empty, emit
TEST_CASE_ENDand stop. - Build child nameserver set from the union of
GlueNameserversandApexNameservers(deduplicated byns.String()), then deduplicate by IP. - For each unique child nameserver IP (parallelized):
- If transport is disabled, emit
IPV4_DISABLEDorIPV6_DISABLEDfor rrtypeDNSKEYand skip. - Query DNSKEY with DNSSEC enabled.
- Require
NOERROR,OPT,DO,AA, the TC flag clear, and at least one DNSKEY at child apex; otherwise skip. A truncated answer is a partial RRset, whichever transport delivered it. - Mark nameserver as responding.
- For each DS record:
- Find DNSKEY candidates by keytag and select a matching candidate (digest-checked when digest type is supported).
- A keytag candidate whose DNSKEY algorithm differs from the DS algorithm field is never a match: add keytag/ns with both algorithm values to
DS02_DS_ALGO_DNSKEY_MISMATCHand skip the candidate. This applies on both the supported-digest and unsupported-digest branches (RFC 4034 section 5.2 requires the DS algorithm field to equal the DNSKEY algorithm). - If no DNSKEY by keytag exists, add keytag/ns to
DS02_NO_DNSKEY_FOR_DS. - If DNSKEY exists but DS digest check fails, add keytag/ns to
DS02_NO_MATCH_DS_DNSKEY. - If DNSKEY has no ZONE flag, add keytag/ns to
DS02_DNSKEY_NOT_FOR_ZONE_SIGNINGand stop processing that DS. - If DNSKEY has no SEP flag, add keytag/ns to
DS02_DNSKEY_NOT_SEP. - Track DNSKEY as DS-matching candidate for signature checks.
- For each DS-matching DNSKEY:
- Find DNSKEY-covering RRSIG by keytag and verify against DNSKEY.
- Missing/invalid match contributes
DS02_NO_MATCHING_DNSKEY_RRSIG. - Unsupported verification algorithm contributes
DS02_ALGO_NOT_SUPPORTED_BY_ZM. - Signature verification failure contributes
DS02_RRSIG_NOT_VALID_BY_DNSKEY. - Successful verification marks nameserver as having an RRSIG match for DS.
- If transport is disabled, emit
- Emit accumulated per-keytag findings (
DS02_*) with mergedaddresses. - Emit per-nameserver summary:
DS02_NO_VALID_DNSKEY_FOR_ANY_DSfor responding nameservers with no DS-matching DNSKEY.- Else
DS02_DNSKEY_NOT_SIGNED_BY_ANY_DSfor responding nameservers with DS-matching DNSKEY but no validating RRSIG from those keys.
- For each DS-linked DNSKEY keytag whose RRSIG validated, emit
DS02_MATCH_DS_DNSKEYwith that keytag and the IPs where it validated. A keytag that failed on every nameserver is never reported as a match. - Emit
TEST_CASE_END.
Parent DS Collection (steps 2-4)
Per-Child DNSKEY Match and RRSIG Verify (steps 5-8)
Emitted Tags (Possible Set)
| Tag | Emitted when |
|---|---|
DS02_ALGO_NOT_SUPPORTED_BY_ZM | DNSKEY RRSIG verification requires an unsupported algorithm for this build/runtime. |
DS02_DS_ALGO_DNSKEY_MISMATCH | A DNSKEY matches the DS keytag but the DS algorithm field differs from the DNSKEY algorithm; validating resolvers ignore such a DS record. |
DS02_MATCH_DS_DNSKEY | A DS-matching DNSKEY validates the DNSKEY RRset; emitted once per such keytag. |
DS02_DNSKEY_NOT_FOR_ZONE_SIGNING | DS-matching DNSKEY is found but lacks ZONE flag. |
DS02_DNSKEY_NOT_SEP | DS-matching DNSKEY is found but lacks SEP flag. |
DS02_DNSKEY_NOT_SIGNED_BY_ANY_DS | Nameserver has DS-matching DNSKEY(s), but no validating DNSKEY RRSIG from those keys. |
DS02_NO_DNSKEY_FOR_DS | No DNSKEY with matching keytag exists for DS record. |
DS02_NO_MATCHING_DNSKEY_RRSIG | No valid DNSKEY-covering RRSIG could be matched to a DS-matching DNSKEY. |
DS02_NO_MATCH_DS_DNSKEY | DNSKEY keytag match exists but DS digest/algorithm does not match DNSKEY data. |
DS02_NO_VALID_DNSKEY_FOR_ANY_DS | Responding child nameserver has no valid DS-matching DNSKEY for any DS. |
DS02_RRSIG_NOT_VALID_BY_DNSKEY | Candidate DNSKEY RRSIG was present but failed verification with matching DNSKEY. |
DS02_RSA_EXPONENT_UNSUPPORTED | Candidate DNSKEY RRSIG could not be checked only because the matching DS-linked DNSKEY is an RSA key whose public exponent exceeds what the local verifier supports (more than 64 bits). |
IPV4_DISABLED | IPv4 transport is disabled for a queried nameserver (DS or DNSKEY). |
IPV6_DISABLED | IPv6 transport is disabled for a queried nameserver (DS or DNSKEY). |
TEST_CASE_END | Testcase completion marker is emitted. |
TEST_CASE_START | Testcase start marker is emitted. |
Tag Arguments
| Tag | Argument key | Type | Meaning |
|---|---|---|---|
DS02_ALGO_NOT_SUPPORTED_BY_ZM | keytag | int | DNSKEY keytag associated with unsupported signature algorithm. |
DS02_ALGO_NOT_SUPPORTED_BY_ZM | algo_num | int | DNSSEC algorithm number that verification cannot process. |
DS02_ALGO_NOT_SUPPORTED_BY_ZM | algo_mnemo | string | DNSSEC algorithm mnemonic string. |
DS02_ALGO_NOT_SUPPORTED_BY_ZM | addresses | array<string> | Structured child nameserver IP list. |
DS02_DS_ALGO_DNSKEY_MISMATCH | keytag | int | DS keytag whose DS algorithm field disagrees with the DNSKEY algorithm. |
DS02_DS_ALGO_DNSKEY_MISMATCH | ds_key_algo_num | int | Algorithm field value from the DS RDATA. |
DS02_DS_ALGO_DNSKEY_MISMATCH | ds_key_algo_mnemo | string | DNSSEC algorithm mnemonic for the DS algorithm field value. |
DS02_DS_ALGO_DNSKEY_MISMATCH | algo_num | int | Algorithm of the keytag-matching DNSKEY record. |
DS02_DS_ALGO_DNSKEY_MISMATCH | algo_mnemo | string | DNSSEC algorithm mnemonic for the DNSKEY algorithm. |
DS02_DS_ALGO_DNSKEY_MISMATCH | addresses | array<string> | Structured child nameserver IP list. |
DS02_DNSKEY_NOT_FOR_ZONE_SIGNING | keytag | int | DS/DNSKEY keytag lacking ZONE bit. |
DS02_DNSKEY_NOT_FOR_ZONE_SIGNING | addresses | array<string> | Structured child nameserver IP list. |
DS02_DNSKEY_NOT_SEP | keytag | int | DS/DNSKEY keytag lacking SEP bit. |
DS02_DNSKEY_NOT_SEP | addresses | array<string> | Structured child nameserver IP list. |
DS02_DNSKEY_NOT_SIGNED_BY_ANY_DS | addresses | array<string> | Structured child nameserver IP list. |
DS02_MATCH_DS_DNSKEY | keytag | int | DS-matching DNSKEY keytag whose RRSIG over the DNSKEY RRset validates. |
DS02_MATCH_DS_DNSKEY | addresses | array<string> | Structured child nameserver IP list with DS-matching DNSKEY and valid RRSIG. |
DS02_NO_DNSKEY_FOR_DS | keytag | int | DS keytag for which no DNSKEY was found. |
DS02_NO_DNSKEY_FOR_DS | addresses | array<string> | Structured child nameserver IP list. |
DS02_NO_MATCHING_DNSKEY_RRSIG | keytag | int | DS-matching DNSKEY keytag lacking a validating DNSKEY RRSIG. |
DS02_NO_MATCHING_DNSKEY_RRSIG | addresses | array<string> | Structured child nameserver IP list. |
DS02_NO_MATCH_DS_DNSKEY | keytag | int | DS keytag whose DS digest/algorithm did not match DNSKEY data. |
DS02_NO_MATCH_DS_DNSKEY | addresses | array<string> | Structured child nameserver IP list. |
DS02_NO_VALID_DNSKEY_FOR_ANY_DS | addresses | array<string> | Structured child nameserver IP list. |
DS02_RRSIG_NOT_VALID_BY_DNSKEY | keytag | int | Keytag from DNSKEY RRSIG verification failure. |
DS02_RRSIG_NOT_VALID_BY_DNSKEY | addresses | array<string> | Structured child nameserver IP list. |
DS02_RSA_EXPONENT_UNSUPPORTED | keytag | int | DS-linked DNSKEY keytag whose RSA public exponent the local verifier cannot use. |
DS02_RSA_EXPONENT_UNSUPPORTED | addresses | array<string> | Structured child nameserver IP list. |
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 | rrtype | string | rrtype skipped (DS or 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 | rrtype | string | rrtype skipped (DS or DNSKEY). |
TEST_CASE_END | testcase | string | Testcase display name (DNSSEC02). |
TEST_CASE_START | testcase | string | Testcase display name (DNSSEC02). |
Severity Levels Per Tag
| Tag | Level | Notes |
|---|---|---|
DS02_ALGO_NOT_SUPPORTED_BY_ZM | NOTICE | Default from share/profile.json (test_levels.DNSSEC). |
DS02_DS_ALGO_DNSKEY_MISMATCH | ERROR | Default from share/profile.json (test_levels.DNSSEC). |
DS02_DNSKEY_NOT_FOR_ZONE_SIGNING | ERROR | Default from share/profile.json (test_levels.DNSSEC). |
DS02_DNSKEY_NOT_SEP | NOTICE | Default from share/profile.json (test_levels.DNSSEC). |
DS02_DNSKEY_NOT_SIGNED_BY_ANY_DS | ERROR | Default from share/profile.json (test_levels.DNSSEC). |
DS02_MATCH_DS_DNSKEY | INFO | Default from share/profile.json (test_levels.DNSSEC). |
DS02_NO_DNSKEY_FOR_DS | WARNING | Default from share/profile.json (test_levels.DNSSEC). |
DS02_NO_MATCHING_DNSKEY_RRSIG | ERROR | Default from share/profile.json (test_levels.DNSSEC). |
DS02_NO_MATCH_DS_DNSKEY | ERROR | Default from share/profile.json (test_levels.DNSSEC). |
DS02_NO_VALID_DNSKEY_FOR_ANY_DS | ERROR | Default from share/profile.json (test_levels.DNSSEC). |
DS02_RRSIG_NOT_VALID_BY_DNSKEY | ERROR | Default from share/profile.json (test_levels.DNSSEC). |
DS02_RSA_EXPONENT_UNSUPPORTED | NOTICE | Default from share/profile.json (test_levels.DNSSEC); carries zero score penalty (scoring TagPenalties). |
IPV4_DISABLED | DEBUG2 | Default from share/profile.json (test_levels.DNSSEC). |
IPV6_DISABLED | DEBUG2 | 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
- Differences (Upstream vs Gonemaster):
- Upstream: explicitly describes a dedicated undelegated DS input branch in testcase flow. Gonemaster:
DNSSEC02implementation uses parent DS discovery path directly and has no separate testcase-local undelegated DS branch. - Upstream: does not explicitly specify testcase boundary and per-query transport debug emissions in this testcase summary. Gonemaster: emits
TEST_CASE_START,TEST_CASE_END,IPV4_DISABLED, andIPV6_DISABLED. - Upstream: emits
DS02_MATCH_DS_DNSKEYonce for the zone, without naming a key. Gonemaster: emits it once per DS-linked keytag whose RRSIG validates and names that keytag, so a zone where one DS names a validating key and another names a key that signs nothing does not read as an all-clear. - Upstream: emits
DS02_NO_MATCHING_DNSKEY_RRSIGatWARNING. Gonemaster: emits it atERROR, because RFC 4035 section 2.2 requires the apex DNSKEY RRset to be signed by each algorithm in the parent DS RRset, and a validator that implements the referenced algorithm answers SERVFAIL for a zone that omits those signatures. SeeDIV-DS02-RRSIG-SEVERITY.
- Upstream: explicitly describes a dedicated undelegated DS input branch in testcase flow. Gonemaster:
- Potential upstream report:
yes
Edge Cases And Limitations
- If parent DS discovery yields no DS records, testcase stops after boundary tags and emits no DS02 findings.
- Child nameservers are deduplicated by IP before DNSKEY checks, so repeated names on one IP collapse into one probe context.
- A DNSKEY answer with the TC flag set is skipped, including one received over TCP after the transport fell back from a truncated UDP answer. The nameserver is not marked responding and contributes to no
DS02_*finding, so a missing RRSIG in a partial RRset is never reported asDS02_NO_MATCHING_DNSKEY_RRSIG. Connectivity05 reports the truncated TCP answer asCN05_TCP_ANSWER_TRUNCATED. DS02_NO_VALID_DNSKEY_FOR_ANY_DSandDS02_DNSKEY_NOT_SIGNED_BY_ANY_DSare mutually exclusive by implementation (else ifbranch).- A zone whose DS RRset names one key that signs the DNSKEY RRset and one that does not gets
DS02_NO_MATCHING_DNSKEY_RRSIGfor the second keytag andDS02_MATCH_DS_DNSKEYfor the first. The two findings name different keytags and both hold. - DS algorithm field mismatch: a DS whose algorithm field differs from the keytag-matching DNSKEY algorithm never counts as a match. A zone whose only DS has a mismatched algorithm therefore gets both
DS02_DS_ALGO_DNSKEY_MISMATCHand the summaryDS02_NO_VALID_DNSKEY_FOR_ANY_DS; a zone with an additional correct DS keepsDS02_MATCH_DS_DNSKEYalongside the mismatch tag. The keytag-fallback selection of the candidate for the ZONE/SEP flag checks is unaffected. - Large RSA public exponent handling: an RSA DNSKEY the DNS library refuses although RFC 3110 permits it (an exponent of more than 4 bytes or greater than 2^31-1, as with the
.lvKSK and its exponent of 2^32+1, or a leading zero byte in the exponent or modulus) is verified by gonemaster’s own RSA path instead, so its RRSIGs pass or fail like any other. Only when the exponent exceeds 64 bits, a ceiling most validators share, is the finding reclassified from theERRORDS02_RRSIG_NOT_VALID_BY_DNSKEYto theNOTICEDS02_RSA_EXPONENT_UNSUPPORTED. Such a key is treated as indeterminate rather than failed: it does not raiseDS02_NO_MATCHING_DNSKEY_RRSIG, and when it is the sole reason a nameserver has no validating DS-linked key,DS02_DNSKEY_NOT_SIGNED_BY_ANY_DSis suppressed.