addWildcardNXRRSETProof(finder, db_context.rrset);
}
} else if (db_context.isNSEC3Signed() && !db_context.isWildcard()) {
- if (*qtype_ == RRType::DS()) {
- // RFC 5155, Section 7.2.4. Add either NSEC3 for the qname or
- // closest (provable) encloser proof in case of optout.
- addClosestEncloserProof(finder, *qname_, true);
- } else {
- // RFC 5155, Section 7.2.3. Just add NSEC3 for the qname.
- addNSEC3ForName(finder, *qname_, true);
- }
+ // Section 7.2.3 and 7.2.4 of RFC 5155 with clarification by errata
+ // http://www.rfc-editor.org/errata_search.php?rfc=5155&eid=3441
+ // In the end, these two cases are basically the same: if the qname is
+ // equal to or derived from insecure delegation covered by an Opt-Out
+ // NSEC3 RR, include the closest provable encloser proof; otherwise we
+ // have a matching NSEC3, so we include it.
+ //
+ // Note: This implementation does not check in the former case whether
+ // the NSEC3 for the next closer has Opt-Out bit on; this must be the
+ // case as long as the zone is correctly signed, and if it's broken
+ // we'd just return what we are given and have the validator detect it.
+ addClosestEncloserProof(finder, *qname_, true);
} else if (db_context.isNSEC3Signed() && db_context.isWildcard()) {
// Case for RFC 5155 Section 7.2.5: add closest encloser proof for the
// qname, construct the matched wildcard name and add NSEC3 for it.
NULL, mock_finder->getOrigin());
}
-// Check the exception is correctly raised when the NSEC3 thing isn't in the
-// zone
-TEST_P(QueryTest, nxrrsetMissingNSEC3) {
+TEST_P(QueryTest, nxrrsetDerivedFromOptOutNSEC3) {
// In this test we emulate the situation where an empty non-terminal name
// is derived from insecure delegation and covered by an opt-out NSEC3.
- // In the actual test data the covering NSEC3 doesn't have the opt-out
- // bit set, but the implementation doesn't check it.
+ // In the actual test data the covering NSEC3 really has the opt-out
+ // bit set, although the implementation doesn't check it anyway.
enableNSEC3(rrsets_to_add_);
- EXPECT_THROW(query.process(*list_, Name("empty.example.com"),
- RRType::TXT(), response, true),
- Query::BadNSEC3);
+ query.process(*list_, Name("empty.example.com"), RRType::TXT(), response,
+ true);
+
+ // The closest provable encloser is the origin name (example.com.), and
+ // the next closer is the empty name itself, which is expected to be
+ // covered by an opt-out NSEC3 RR. The response should contain these 2
+ // NSEC3s.
+ responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 6, 0, NULL,
+ (string(soa_minttl_txt) +
+ string("example.com. 0 IN RRSIG ") +
+ getCommonRRSIGText("SOA") + "\n" +
+ string(nsec3_apex_txt) + "\n" +
+ nsec3_hash_.calculate(Name("example.com.")) +
+ ".example.com. 3600 IN RRSIG " +
+ getCommonRRSIGText("NSEC3") + "\n" +
+ string(nsec3_www_txt) + "\n" +
+ nsec3_hash_.calculate(Name("www.example.com.")) +
+ ".example.com. 3600 IN RRSIG " +
+ getCommonRRSIGText("NSEC3") + "\n").c_str(),
+ NULL, mock_finder->getOrigin());
}
TEST_P(QueryTest, nxrrsetWithNSEC3_ds_exact) {