DNSSEC10

Status: Final

Purpose

  • Verify that signed child-zone nameservers consistently provide NSEC or NSEC3 denial-of-existence material (including signatures and owner/type-shape checks) when querying for apex NSEC and NSEC3PARAM.

Preconditions And Inputs

  • Preconditions:
    • A zone.Zone object is available.
  • Required inputs:
  • Profile/config knobs that affect behavior:
    • net.ipv4 and net.ipv6: disabled transports are skipped with transport debug tags.
    • resolver.defaults.parallel: per-nameserver parallel execution fanout.

Algorithm And Decision Flow

  1. Emit TEST_CASE_START.
  2. Build child nameserver set from delegation+zone NS items, grouped by IP.
  3. For each unique nameserver IP (parallelized):
    • If transport is disabled, emit IPV4_DISABLED or IPV6_DISABLED for rrtypes DNSKEY, NSEC, and NSEC3PARAM, mark nameserver ignored, and skip.
    • Query DNSKEY (DNSSEC enabled); if response is absent/non-NOERROR/non-AA, mark ignored and skip.
    • If no apex DNSKEY records are returned, classify nameserver as without DNSKEY and skip remaining DS10 checks.
    • Otherwise classify nameserver as with DNSKEY and keep DNSKEY set for signature checks.
  4. Run NSEC query processing:
    • Response-shape failure => NSEC query response error set.
    • Non-empty answer with NSEC records => NSEC-in-answer path (multi-record, apex-owner checks).
    • Non-empty answer without NSEC => erroneous-answer set.
    • Empty answer with NSEC3 in authority => NSEC3-NODATA path (SOA presence/owner checks, NSEC3 owner/type-list checks, signature presence and verification checks).
    • Empty answer with NSEC in authority (no NSEC3) => NSEC-NODATA path for RFC 4470 / RFC 9824 white-lies / minimally covering NSEC / compact denial of existence implementations (SOA presence/owner checks, NSEC count/apex-owner checks, signature presence and verification checks; type-list validation is skipped because the synthesized bitmap intentionally excludes the queried type). Treated as NSEC evidence equivalent to NSEC-in-answer for consistency checks.
  5. Run NSEC3PARAM query processing:
    • Response-shape failure => NSEC3PARAM query response error set.
    • Non-empty answer with NSEC3PARAM => NSEC3PARAM-in-answer path (apex-owner check applied to every NSEC3PARAM RR in the RRset; multiple NSEC3PARAM RRs are permitted to accommodate parameter rollover).
    • Non-empty answer without NSEC3PARAM => erroneous-answer set.
    • Empty answer with NSEC in authority => NSEC-NODATA path (SOA presence/owner checks, NSEC owner/type-list checks, signature presence and verification checks).
  6. During NSEC/NSEC3 signature verification:
    • Track per-keytag conditions: no matching DNSKEY, expired, not-yet-valid, verify error.
    • Track successful verification per nameserver.
    • Track unsupported algorithm situations as DS10_ALGO_NOT_SUPPORTED_BY_ZM.
  7. Aggregate outcomes across nameservers and emit structural consistency tags:
    • DS10_ERR_MULT_*, DS10_INCONSISTENT_*, DS10_MIXED_NSEC_NSEC3, DS10_HAS_NSEC, DS10_HAS_NSEC3.
  8. Emit detailed content/signature tags for NSEC and NSEC3/NSEC3PARAM observations.
  9. Emit DNSSEC-presence summary tags:
    • DS10_ZONE_NO_DNSSEC when only no-DNSKEY responders were observed.
    • DS10_SERVER_NO_DNSSEC when mixed DNSKEY/no-DNSKEY responders were observed.
  10. Emit DS10_EXPECTED_NSEC_NSEC3_MISSING for nameservers with DNSKEY that produced neither expected NSEC nor expected NSEC3 evidence sets.
  11. Emit TEST_CASE_END.

Per-Nameserver DNSKEY Classification (step 3)

For each unique nameserver IP (parallel; fan-out = resolver.defaults.parallel):

   transport check (IPv4 / IPv6 via net.ipv4 / net.ipv6)
    +- disabled  -> emit IPV4_DISABLED / IPV6_DISABLED for DNSKEY,
    |               NSEC, NSEC3PARAM; mark ignored; stop
    +- enabled   -> query DNSKEY at apex (DNSSEC=on)
                     +- no Msg / RCODE != NOERROR / not AA  -> mark ignored; stop
                     +- answer has no apex DNSKEY records   -> "without DNSKEY"; stop
                     +- no records parse as *dns.DNSKEY     -> "without DNSKEY"; stop
                     +- apex DNSKEY records present         -> "with DNSKEY"
                                                                |
                                                                v
                                                       run NSEC      (see below)
                                                       run NSEC3PARAM (see below)

NSEC Query Processing (step 4)

query NSEC at apex (DNSSEC=on)
 |
 +- no Msg / RCODE != NOERROR / not AA       -> nsecResponseError
 |
 +- answer non-empty
 |   +- NSEC RRs in answer                   -> nsecInAnswer
 |   |    +- count > 1                       -> erroneousMultipleNSEC
 |   |    +- count == 1, owner != apex       -> nsecMismatchesApex
 |   +- no NSEC RRs in answer                -> nsecErroneousAnswer
 |
 +- empty answer, NSEC3 in authority         -> nsecNsec3Nodata  (NSEC3-NODATA)
 |   +- SOA missing                          -> nsec3NodataMissingSOA
 |   +- SOA owner != apex                    -> nsec3NodataWrongSOA
 |   +- NSEC3 RRs in authority:
 |        +- count > 1                       -> erroneousMultipleNSEC3
 |        +- count == 1, owner-hash != apex  -> nsec3MismatchesApex
 |        +- count == 1, bitmap fails check  -> nsec3IncorrectTypeList
 |        |     mandatory: SOA, NS, DNSKEY, NSEC3PARAM, RRSIG
 |        |     forbidden: NSEC, NSEC3
 |        +- RRSIG over the NSEC3 RRset:
 |             +- none present               -> nsec3MissingSignature
 |             +- per signature (keytag):    -> [signature check]  (see below)
 |
 +- empty answer, NSEC in authority          -> nsecNsecNodata  (RFC 4470 / 9824)
 |   +- SOA missing                          -> nsecNodataMissingSOA
 |   +- SOA owner != apex                    -> nsecNodataWrongSOA
 |   +- NSEC RRs in authority:
 |        +- count > 1                       -> erroneousMultipleNSEC
 |        +- count == 1, owner != apex       -> nsecMismatchesApex
 |        |     (type-list check skipped: synthesized bitmap may exclude
 |        |      the queried type and include normally-forbidden types)
 |        +- RRSIG over the NSEC RRset:
 |             +- none present               -> nsecMissingSignature
 |             +- per signature (keytag):    -> [signature check]  (see below)
 |
 +- empty answer, neither NSEC nor NSEC3     -> (no evidence; silent)


[signature check]  applied per RRSIG, keyed by sig.KeyTag:
   +- no DNSKEY with that keytag             -> *RRSIGNoDNSKEY[keytag]
   +- sig.Expiration < now                   -> *RRSIGExpired[keytag]
   +- sig.Inception  > now                   -> *RRSIGNotYetValid[keytag]
   +- verify succeeds against any DNSKEY     -> *RRSIGVerified  (sets per-NS flag)
   +- verify fails with dns.ErrAlg           -> algoNotSupportedByZM[keytag][algo]
   +- verify fails for any other reason      -> *RRSIGVerifyError[keytag]

NSEC3PARAM Query Processing (step 5)

query NSEC3PARAM at apex (DNSSEC=on)
 |
 +- no Msg / RCODE != NOERROR / not AA       -> nsec3paramResponseError
 |
 +- answer non-empty
 |   +- NSEC3PARAM RRs in answer             -> nsec3paramInAnswer
 |   |    +- for each RR, owner != apex      -> nsec3paramMismatchesApex
 |   |       (every RR is checked; multi-RR salt/iterations rollover allowed)
 |   +- no NSEC3PARAM RRs in answer          -> nsec3paramErroneousAnswer
 |
 +- empty answer, NSEC in authority          -> nsec3paramNsecNodata
 |   +- SOA missing                          -> nsecNodataMissingSOA
 |   +- SOA owner != apex                    -> nsecNodataWrongSOA
 |   +- NSEC RRs in authority:
 |        +- count > 1                       -> erroneousMultipleNSEC
 |        +- count == 1, owner != apex       -> nsecMismatchesApex
 |        +- count == 1, bitmap fails check  -> nsecIncorrectTypeList
 |        |     mandatory: SOA, NS, DNSKEY, NSEC, RRSIG
 |        |     forbidden: NSEC3PARAM, NSEC3
 |        +- RRSIG over the NSEC RRset:
 |             +- none present               -> nsecMissingSignature
 |             +- per signature (keytag):    -> [signature check] (see NSEC section)
 |
 +- empty answer, no NSEC in authority       -> (no evidence; silent)

Aggregation and Final Emission (steps 6-11)

After the per-nameserver phase, with:
    NSEC_set  = nsecInAnswer  union nsec3paramNsecNodata
    NSEC3_set = nsec3paramInAnswer union nsecNsec3Nodata
    (nsecInAnswer first absorbs nsecNsecNodata per RFC 4470 / 9824)

1. Consistency and presence (set algebra over evidence sets)
     nsecInAnswer  symdiff nsec3paramNsecNodata, minus opposite-kind set
                                                  -> DS10_INCONSISTENT_NSEC
     nsec3paramInAnswer symdiff nsecNsec3Nodata,  minus opposite-kind set
                                                  -> DS10_INCONSISTENT_NSEC3
     NSEC3_set intersect NSEC_set                 -> DS10_MIXED_NSEC_NSEC3
     NSEC_set  non-empty, NSEC3_set empty         -> DS10_HAS_NSEC
     NSEC3_set non-empty, NSEC_set  empty         -> DS10_HAS_NSEC3
     NSEC_set and NSEC3_set each have an exclusive member
                                                  -> DS10_INCONSISTENT_NSEC_NSEC3

2. Content and shape (one tag per non-empty per-NS list)
     DS10_ERR_MULT_NSEC, DS10_ERR_MULT_NSEC3,
     DS10_NONSTANDARD_NSEC_RESPONSE,
     DS10_NSEC_ERR_TYPE_LIST,   DS10_NSEC3_ERR_TYPE_LIST,
     DS10_NSEC_MISMATCHES_APEX, DS10_NSEC3_MISMATCHES_APEX,
     DS10_NSEC3PARAM_MISMATCHES_APEX,
     DS10_NSEC_NODATA_MISSING_SOA,  DS10_NSEC_NODATA_WRONG_SOA,
     DS10_NSEC3_NODATA_MISSING_SOA, DS10_NSEC3_NODATA_WRONG_SOA,
     DS10_NSEC_GIVES_ERR_ANSWER,    DS10_NSEC3PARAM_GIVES_ERR_ANSWER,
     DS10_NSEC_QUERY_RESPONSE_ERR,  DS10_NSEC3PARAM_QUERY_RESPONSE_ERR,
     DS10_NSEC_MISSING_SIGNATURE,   DS10_NSEC3_MISSING_SIGNATURE

3. Signature conditions
     One tag per (kind, keytag):
       DS10_{NSEC,NSEC3}_RRSIG_{NO_DNSKEY, EXPIRED, NOT_YET_VALID, VERIFY_ERROR}
     One tag per (keytag, algo):
       DS10_ALGO_NOT_SUPPORTED_BY_ZM
     DS10_{NSEC,NSEC3}_NO_VERIFIED_SIGNATURE =
       NSes appearing in any condition above, minus NSes with at least
       one verified signature for the same kind.

4. DNSKEY presence across nameservers
     withDNSKEY empty,     withoutDNSKEY non-empty -> DS10_ZONE_NO_DNSSEC
     withDNSKEY non-empty, withoutDNSKEY non-empty -> DS10_SERVER_NO_DNSSEC

5. Expected evidence
     missing = allNS minus (ignoredNS, withoutDNSKEY,
                            nsecInAnswer, nsec3paramNsecNodata,
                            nsec3paramInAnswer, nsecNsec3Nodata)
     missing non-empty -> DS10_EXPECTED_NSEC_NSEC3_MISSING

6. Emit TEST_CASE_END.

Emitted Tags (Possible Set)

TagEmitted when
DS10_ALGO_NOT_SUPPORTED_BY_ZMSignature verification required an unsupported algorithm.
DS10_ERR_MULT_NSECMore than one NSEC record was observed where one was expected.
DS10_ERR_MULT_NSEC3More than one NSEC3 record was observed where one was expected.
DS10_EXPECTED_NSEC_NSEC3_MISSINGNameserver had DNSKEY support but did not provide expected NSEC/NSEC3 evidence.
DS10_HAS_NSECZone behavior is consistently NSEC-only for observed nameservers.
DS10_HAS_NSEC3Zone behavior is consistently NSEC3-only for observed nameservers.
DS10_INCONSISTENT_NSECNSEC evidence is inconsistent across nameservers.
DS10_INCONSISTENT_NSEC3NSEC3 evidence is inconsistent across nameservers.
DS10_INCONSISTENT_NSEC_NSEC3At least one nameserver uses NSEC-only and at least one uses NSEC3-only, with no nameserver exhibiting both simultaneously.
DS10_MIXED_NSEC_NSEC3At least one nameserver shows both NSEC and NSEC3 behavior.
DS10_NONSTANDARD_NSEC_RESPONSENSEC query returned NSEC in the authority section instead of the answer section (RFC 4470 white-lies / RFC 9824 compact denial).
DS10_NSEC3PARAM_GIVES_ERR_ANSWERNSEC3PARAM query had unexpected non-empty answer content.
DS10_NSEC3PARAM_MISMATCHES_APEXNSEC3PARAM owner name did not match zone apex.
DS10_NSEC3PARAM_QUERY_RESPONSE_ERRNSEC3PARAM query had no usable authoritative NOERROR response.
DS10_NSEC3_ERR_TYPE_LISTNSEC3 type bitmap failed mandatory/forbidden checks.
DS10_NSEC3_MISMATCHES_APEXNSEC3 owner hash/name did not match expected apex semantics.
DS10_NSEC3_MISSING_SIGNATURENSEC3 RRset had no matching RRSIG coverage.
DS10_NSEC3_NODATA_MISSING_SOANSEC3 NODATA authority response lacked SOA.
DS10_NSEC3_NODATA_WRONG_SOANSEC3 NODATA authority response had SOA with wrong owner.
DS10_NSEC3_NO_VERIFIED_SIGNATURENSEC3 signatures existed but none verified for affected nameservers.
DS10_NSEC3_RRSIG_EXPIREDNSEC3 RRSIG expired for given keytag.
DS10_NSEC3_RRSIG_NOT_YET_VALIDNSEC3 RRSIG not yet valid for given keytag.
DS10_NSEC3_RRSIG_NO_DNSKEYNSEC3 RRSIG keytag had no matching DNSKEY.
DS10_NSEC3_RRSIG_VERIFY_ERRORNSEC3 RRSIG verification failed for given keytag.
DS10_NSEC_ERR_TYPE_LISTNSEC type bitmap failed mandatory/forbidden checks.
DS10_NSEC_GIVES_ERR_ANSWERNSEC query had unexpected non-empty answer content.
DS10_NSEC_MISMATCHES_APEXNSEC owner name did not match zone apex.
DS10_NSEC_MISSING_SIGNATURENSEC RRset had no matching RRSIG coverage.
DS10_NSEC_NODATA_MISSING_SOANSEC NODATA authority response lacked SOA.
DS10_NSEC_NODATA_WRONG_SOANSEC NODATA authority response had SOA with wrong owner.
DS10_NSEC_NO_VERIFIED_SIGNATURENSEC signatures existed but none verified for affected nameservers.
DS10_NSEC_QUERY_RESPONSE_ERRNSEC query had no usable authoritative NOERROR response.
DS10_NSEC_RRSIG_EXPIREDNSEC RRSIG expired for given keytag.
DS10_NSEC_RRSIG_NOT_YET_VALIDNSEC RRSIG not yet valid for given keytag.
DS10_NSEC_RRSIG_NO_DNSKEYNSEC RRSIG keytag had no matching DNSKEY.
DS10_NSEC_RRSIG_VERIFY_ERRORNSEC RRSIG verification failed for given keytag.
DS10_SERVER_NO_DNSSECAt least one nameserver returned a usable DNSKEY and at least one nameserver returned no usable DNSKEY.
DS10_ZONE_NO_DNSSECNo nameserver returned usable DNSKEY while at least one returned no DNSKEY.
IPV4_DISABLEDIPv4 transport is disabled for a queried nameserver/rrtype.
IPV6_DISABLEDIPv6 transport is disabled for a queried nameserver/rrtype.
TEST_CASE_ENDTestcase completion marker is emitted.
TEST_CASE_STARTTestcase start marker is emitted.

Tag Arguments

TagArgument keyTypeMeaning
DS10_ALGO_NOT_SUPPORTED_BY_ZMkeytag, algo_num, algo_mnemo, addressesint, int, string, stringUnsupported algorithm details and semicolon-delimited nameserver identity/IP list from verification path.
DS10_ERR_MULT_NSECserversarray<object>Structured nameserver identities ({ns,address} object).
DS10_ERR_MULT_NSEC3serversarray<object>Structured nameserver identities ({ns,address} object).
DS10_EXPECTED_NSEC_NSEC3_MISSINGserversarray<object>Structured nameserver identities ({ns,address} object).
DS10_HAS_NSECserversarray<object>Structured nameserver identities ({ns,address} object).
DS10_HAS_NSEC3serversarray<object>Structured nameserver identities ({ns,address} object).
DS10_INCONSISTENT_NSECserversarray<object>Structured nameserver identities ({ns,address} object).
DS10_INCONSISTENT_NSEC3serversarray<object>Structured nameserver identities ({ns,address} object).
DS10_INCONSISTENT_NSEC_NSEC3serversarray<object>Structured nameserver identities ({ns,address} object).
DS10_MIXED_NSEC_NSEC3serversarray<object>Structured nameserver identities ({ns,address} object).
DS10_NONSTANDARD_NSEC_RESPONSEserversarray<object>Structured nameserver identities ({ns,address} object) that placed the NSEC RR in the authority section.
DS10_NSEC3PARAM_GIVES_ERR_ANSWERserversarray<object>Structured nameserver identities ({ns,address} object).
DS10_NSEC3PARAM_MISMATCHES_APEXserversarray<object>Structured nameserver identities ({ns,address} object).
DS10_NSEC3PARAM_QUERY_RESPONSE_ERRserversarray<object>Structured nameserver identities ({ns,address} object).
DS10_NSEC3_ERR_TYPE_LISTserversarray<object>Structured nameserver identities ({ns,address} object).
DS10_NSEC3_MISMATCHES_APEXserversarray<object>Structured nameserver identities ({ns,address} object).
DS10_NSEC3_MISSING_SIGNATUREserversarray<object>Structured nameserver identities ({ns,address} object).
DS10_NSEC3_NODATA_MISSING_SOAserversarray<object>Structured nameserver identities ({ns,address} object).
DS10_NSEC3_NODATA_WRONG_SOAdomain, serversstring, stringWrong SOA owner domain and affected nameserver identities (name/ip).
DS10_NSEC3_NO_VERIFIED_SIGNATUREserversarray<object>Structured nameserver identities ({ns,address} object) lacking any verified NSEC3 signature.
DS10_NSEC3_RRSIG_EXPIREDkeytag, serversint, stringKeytag and affected nameserver identities (name/ip).
DS10_NSEC3_RRSIG_NOT_YET_VALIDkeytag, serversint, stringKeytag and affected nameserver identities (name/ip).
DS10_NSEC3_RRSIG_NO_DNSKEYkeytag, serversint, stringKeytag and affected nameserver identities (name/ip).
DS10_NSEC3_RRSIG_VERIFY_ERRORkeytag, serversint, stringKeytag and affected nameserver identities (name/ip).
DS10_NSEC_ERR_TYPE_LISTserversarray<object>Structured nameserver identities ({ns,address} object).
DS10_NSEC_GIVES_ERR_ANSWERserversarray<object>Structured nameserver identities ({ns,address} object).
DS10_NSEC_MISMATCHES_APEXserversarray<object>Structured nameserver identities ({ns,address} object).
DS10_NSEC_MISSING_SIGNATUREserversarray<object>Structured nameserver identities ({ns,address} object).
DS10_NSEC_NODATA_MISSING_SOAserversarray<object>Structured nameserver identities ({ns,address} object).
DS10_NSEC_NODATA_WRONG_SOAdomain, serversstring, stringWrong SOA owner domain and affected nameserver identities (name/ip).
DS10_NSEC_NO_VERIFIED_SIGNATUREserversarray<object>Structured nameserver identities ({ns,address} object) lacking any verified NSEC signature.
DS10_NSEC_QUERY_RESPONSE_ERRserversarray<object>Structured nameserver identities ({ns,address} object).
DS10_NSEC_RRSIG_EXPIREDkeytag, serversint, stringKeytag and affected nameserver identities (name/ip).
DS10_NSEC_RRSIG_NOT_YET_VALIDkeytag, serversint, stringKeytag and affected nameserver identities (name/ip).
DS10_NSEC_RRSIG_NO_DNSKEYkeytag, serversint, stringKeytag and affected nameserver identities (name/ip).
DS10_NSEC_RRSIG_VERIFY_ERRORkeytag, serversint, stringKeytag and affected nameserver identities (name/ip).
DS10_SERVER_NO_DNSSECserversarray<object>Structured nameserver identities ({ns,address} object) without DNSKEY among mixed responders.
DS10_ZONE_NO_DNSSECserversarray<object>Structured nameserver identities ({ns,address} object) without DNSKEY when zone appears unsigned.
IPV4_DISABLEDns, rrtypestring, stringDisabled nameserver identity (name/ip) and skipped rrtype (DNSKEY, NSEC, NSEC3PARAM).
IPV6_DISABLEDns, rrtypestring, stringDisabled nameserver identity (name/ip) and skipped rrtype (DNSKEY, NSEC, NSEC3PARAM).
TEST_CASE_ENDtestcasestringTestcase display name (DNSSEC10).
TEST_CASE_STARTtestcasestringTestcase display name (DNSSEC10).

Severity Levels Per Tag

TagLevelNotes
DS10_ALGO_NOT_SUPPORTED_BY_ZMNOTICEDefault from share/profile.json (test_levels.DNSSEC).
DS10_ERR_MULT_NSECERRORDefault from share/profile.json (test_levels.DNSSEC).
DS10_ERR_MULT_NSEC3ERRORDefault from share/profile.json (test_levels.DNSSEC).
DS10_EXPECTED_NSEC_NSEC3_MISSINGERRORDefault from share/profile.json (test_levels.DNSSEC).
DS10_HAS_NSECINFODefault from share/profile.json (test_levels.DNSSEC).
DS10_HAS_NSEC3INFODefault from share/profile.json (test_levels.DNSSEC).
DS10_INCONSISTENT_NSECERRORDefault from share/profile.json (test_levels.DNSSEC).
DS10_INCONSISTENT_NSEC3ERRORDefault from share/profile.json (test_levels.DNSSEC).
DS10_INCONSISTENT_NSEC_NSEC3ERRORDefault from share/profile.json (test_levels.DNSSEC).
DS10_MIXED_NSEC_NSEC3ERRORDefault from share/profile.json (test_levels.DNSSEC).
DS10_NONSTANDARD_NSEC_RESPONSENOTICEDefault from share/profile.json (test_levels.DNSSEC).
DS10_NSEC3PARAM_GIVES_ERR_ANSWERERRORDefault from share/profile.json (test_levels.DNSSEC).
DS10_NSEC3PARAM_MISMATCHES_APEXERRORDefault from share/profile.json (test_levels.DNSSEC).
DS10_NSEC3PARAM_QUERY_RESPONSE_ERRERRORDefault from share/profile.json (test_levels.DNSSEC).
DS10_NSEC3_ERR_TYPE_LISTERRORDefault from share/profile.json (test_levels.DNSSEC).
DS10_NSEC3_MISMATCHES_APEXERRORDefault from share/profile.json (test_levels.DNSSEC).
DS10_NSEC3_MISSING_SIGNATUREERRORDefault from share/profile.json (test_levels.DNSSEC).
DS10_NSEC3_NODATA_MISSING_SOAERRORDefault from share/profile.json (test_levels.DNSSEC).
DS10_NSEC3_NODATA_WRONG_SOAERRORDefault from share/profile.json (test_levels.DNSSEC).
DS10_NSEC3_NO_VERIFIED_SIGNATUREERRORDefault from share/profile.json (test_levels.DNSSEC).
DS10_NSEC3_RRSIG_EXPIREDERRORDefault from share/profile.json (test_levels.DNSSEC).
DS10_NSEC3_RRSIG_NOT_YET_VALIDERRORDefault from share/profile.json (test_levels.DNSSEC).
DS10_NSEC3_RRSIG_NO_DNSKEYWARNINGDefault from share/profile.json (test_levels.DNSSEC).
DS10_NSEC3_RRSIG_VERIFY_ERRORERRORDefault from share/profile.json (test_levels.DNSSEC).
DS10_NSEC_ERR_TYPE_LISTERRORDefault from share/profile.json (test_levels.DNSSEC).
DS10_NSEC_GIVES_ERR_ANSWERERRORDefault from share/profile.json (test_levels.DNSSEC).
DS10_NSEC_MISMATCHES_APEXERRORDefault from share/profile.json (test_levels.DNSSEC).
DS10_NSEC_MISSING_SIGNATUREERRORDefault from share/profile.json (test_levels.DNSSEC).
DS10_NSEC_NODATA_MISSING_SOAERRORDefault from share/profile.json (test_levels.DNSSEC).
DS10_NSEC_NODATA_WRONG_SOAERRORDefault from share/profile.json (test_levels.DNSSEC).
DS10_NSEC_NO_VERIFIED_SIGNATUREERRORDefault from share/profile.json (test_levels.DNSSEC).
DS10_NSEC_QUERY_RESPONSE_ERRERRORDefault from share/profile.json (test_levels.DNSSEC).
DS10_NSEC_RRSIG_EXPIREDERRORDefault from share/profile.json (test_levels.DNSSEC).
DS10_NSEC_RRSIG_NOT_YET_VALIDERRORDefault from share/profile.json (test_levels.DNSSEC).
DS10_NSEC_RRSIG_NO_DNSKEYWARNINGDefault from share/profile.json (test_levels.DNSSEC).
DS10_NSEC_RRSIG_VERIFY_ERRORERRORDefault from share/profile.json (test_levels.DNSSEC).
DS10_SERVER_NO_DNSSECERRORDefault from share/profile.json (test_levels.DNSSEC).
DS10_ZONE_NO_DNSSECNOTICEDefault from share/profile.json (test_levels.DNSSEC).
IPV4_DISABLEDDEBUGDefault from share/profile.json (test_levels.DNSSEC).
IPV6_DISABLEDDEBUGDefault from share/profile.json (test_levels.DNSSEC).
TEST_CASE_ENDDEBUGDefault from share/profile.json (test_levels.DNSSEC).
TEST_CASE_STARTDEBUGDefault from share/profile.json (test_levels.DNSSEC).

Differences From Upstream

  • Differences (Upstream vs Gonemaster):
    • Upstream: summary for DS10_INCONSISTENT_NSEC_NSEC3 describes two separate lists (ns_list_nsec, ns_list_nsec3). Gonemaster: emits a single combined servers argument.
    • Upstream: most DS10 tags are documented with servers. Gonemaster: DS10_ALGO_NOT_SUPPORTED_BY_ZM uses addresses while other DS10 tags use servers.
    • 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, and IPV6_DISABLED.
    • NSEC-in-authority NODATA responses (RFC 4470 white-lies / minimally covering NSEC / RFC 9824 compact denial of existence, as used by e.g. AWS Route 53, Cloudflare, NS1): both upstream (since engine v9.0.0, see “Resolved upstream issues” below) and gonemaster treat NSEC-in-authority on the NSEC query as NSEC evidence equivalent to NSEC-in-answer and emit DS10_NONSTANDARD_NSEC_RESPONSE (NOTICE) rather than a false DS10_INCONSISTENT_NSEC. One difference remains: upstream performs NSEC type-list validation on the synthesized NSEC record (and may emit DS10_NSEC_INCORRECT_TYPE_LIST), while gonemaster deliberately skips that check because an RFC 4470 / RFC 9824 synthesized bitmap intentionally excludes the queried type and may carry NSEC3PARAM/NSEC3. All other checks (SOA, count, apex owner, signature) match.
    • DS10_ERR_MULT_NSEC3PARAM is not emitted (the tag has been removed). RFC 5155 does not constrain the cardinality of the apex NSEC3PARAM RRset and a zone may legitimately publish more than one NSEC3PARAM RR during a parameter (salt/iterations) rollover. Gonemaster follows the upstream removal: the apex-owner check (DS10_NSEC3PARAM_MISMATCHES_APEX) is applied to every NSEC3PARAM RR in the answer instead of only the first. Apex-hash verification for the NSEC3 chain itself uses each NSEC3 record’s own salt/iterations, so a multi-chain rollover is already validated correctly without a cardinality check.
  • Resolved upstream issues:
    • The NSEC-in-authority gap (false DS10_INCONSISTENT_NSEC for RFC 4470 / RFC 9824 on-line signers, zonemaster/zonemaster#1424 ) is resolved upstream in engine v9.0.0 / Zonemaster v2026.1 (spec update #1478, implementation #1523/#1539): upstream now adds a NODATA-with-NSEC-in-authority branch and emits DS10_NONSTANDARD_NSEC_RESPONSE. Gonemaster had already implemented this branch and tag ahead of the release.
  • Potential upstream report:
    • no – the gap is now handled on both sides; only the type-list-validation difference noted above remains, and that is an intentional gonemaster choice rather than an upstream defect.

Implementation Notes

The following behaviors are implementation choices, not mandated by RFC 4034/4035/5155/4470/9824:

  • Reference time source: RRSIG validity checks use wall-clock time (time.Now().UTC()) as the reference “now”. RFC 4034 requires checking whether signatures are currently valid; using wall-clock time rather than packet timestamps (as dnssec04 does) is an implementation choice appropriate for aggregate multi-nameserver analysis where a single consistent reference point is preferred.
  • Deduplication by IP: The nameserver set is built by IP address; delegation and zone NS entries sharing the same IP are merged. First-seen nameserver identity string (name/ip) is used in output arguments. The protocol does not specify how to handle NS records for the same IP from different sources.
  • servers vs addresses argument name: Most DS10 tags use servers (nameserver identity strings) while DS10_ALGO_NOT_SUPPORTED_BY_ZM uses addresses (raw IPs from the signature verification path). This asymmetry is an implementation-defined output format.
  • RFC 4470 / RFC 9824 white-lies NSEC handling: When the NSEC query returns a NODATA response with NSEC in the authority section (rather than NSEC in the answer section), this is recognized as NSEC evidence from an on-line signing / minimally covering NSEC (RFC 4470) or compact denial of existence (RFC 9824) implementation. RFC 9824 Section 7.2 explicitly permits dynamically generated NSEC records for owner names that don’t exist or are ENTs, relaxing the RFC 4035 constraint. The synthesized NSEC record’s type bitmap intentionally excludes the queried type (NSEC) and may include normally-forbidden types (NSEC3PARAM), so type-list validation is skipped for this record. All other checks (SOA, count, apex owner, signature) are performed normally. For consistency purposes this evidence is treated identically to NSEC-in-answer.

Edge Cases And Limitations

  • Nameserver processing is deduplicated by IP; all DS10 output tags except DS10_ALGO_NOT_SUPPORTED_BY_ZM report servers as nameserver identity strings (name/ip) rather than raw IPs.
  • DS10_NSEC_NO_VERIFIED_SIGNATURE and DS10_NSEC3_NO_VERIFIED_SIGNATURE are suppressed per nameserver when at least one signature verifies for that nameserver.
  • Signature validity checks use testcase wall-clock time (time.Now().UTC()), not packet capture timestamps.