* @param type Type to be checked.
* @return 0 or error code.
*/
-static int maches_name_and_type(int *flags, const knot_rrset_t *nsec3,
+static int matches_name_and_type(int *flags, const knot_rrset_t *nsec3,
const knot_dname_t *name, uint16_t type)
{
assert(flags && nsec3 && name);
}
flags = 0;
- int ret = maches_name_and_type(&flags, rrset, sname, stype);
+ int ret = matches_name_and_type(&flags, rrset, sname, stype);
if (ret != 0) {
return ret;
}
}
flags = 0;
- int ret = maches_name_and_type(&flags, rrset, wildcard, stype);
+ int ret = matches_name_and_type(&flags, rrset, wildcard, stype);
if (ret != 0) {
return ret;
}
return kr_error(ENOENT);
}
-int kr_nsec3_no_data(const knot_pkt_t *pkt, knot_section_t section_id,
- const knot_dname_t *sname, uint16_t stype)
+
+int kr_nsec3_no_data_ds(const knot_pkt_t *pkt, knot_section_t section_id,
+ const knot_dname_t *sname)
{
/* DS record may be also matched by an existing NSEC3 RR. */
- int ret = no_data_response_no_ds(pkt, section_id, sname, stype);
+ int ret = no_data_response_no_ds(pkt, section_id, sname, KNOT_RRTYPE_DS);
if (ret == 0) {
- /* Satisfies RFC5155 8.5 and 8.6, first paragraph. */
+ /* Satisfies RFC5155 8.6, first paragraph. */
return ret;
}
}
assert(encloser_name && covering_next_nsec3);
- if ((stype == KNOT_RRTYPE_DS) && has_optout(covering_next_nsec3)) {
- /* Satisfies RFC5155 8.6, second paragraph. */
- return 0;
+ if (!has_optout(covering_next_nsec3)) {
+ ret = DNSSEC_NOT_FOUND;
+ }
+
+ /* Satisfies RFC5155 8.6, second paragraph. */
+ return ret;
+}
+
+
+int kr_nsec3_no_data_no_ds(const knot_pkt_t *pkt, knot_section_t section_id,
+ const knot_dname_t *sname, uint16_t stype)
+{
+ int ret = no_data_response_no_ds(pkt, section_id, sname, stype);
+ if (ret == 0) {
+ /* Satisfies RFC5155 8.5, first paragraph. */
+ return ret;
+ }
+
+ /* Check RFC5155 8.7. */
+ /* Find closest provable encloser. */
+ const knot_dname_t *encloser_name = NULL;
+ const knot_rrset_t *covering_next_nsec3 = NULL;
+ ret = closest_encloser_proof(pkt, section_id, sname, &encloser_name,
+ NULL, &covering_next_nsec3);
+ if (ret != 0) {
+ return ret;
}
- return matches_closest_encloser_wildcard(pkt, section_id,
+ assert(encloser_name && covering_next_nsec3);
+ ret = matches_closest_encloser_wildcard(pkt, section_id,
encloser_name, stype);
+ if (ret == 0) {
+ /* Satisfies RFC5155 8.7 */
+ return ret;
+ }
+
+ if (has_optout(covering_next_nsec3)) {
+ /*
+ * Satisfies RFC5155 ERRATA 3441 8.5
+ * (No Data Responses, QTYPE is not DS)
+ * - empty nonterminal derived from unsecure delegation.
+ * Moreover, ENT may be wilcard.
+ * Hence it covers "wilcard nodata response" case.
+ * It is not an error, but
+ * denial of existance can not be proven.
+ * Set error code to proceed unsecure.
+ */
+ ret = DNSSEC_NOT_FOUND;
+ }
+
+ return ret;
}
+
const knot_dname_t *sname, int trim_to_next);
/**
- * Authenticated denial of existence according to RFC5155 8.5, 8.6 and 8.7.
+ * Authenticated denial of existence according to RFC5155 8.5 and 8.7.
* @note No RRSIGs are validated.
* @param pkt Packet structure to be processed.
* @param section_id Packet section to be processed.
* @param sname Queried domain name.
* @param stype Queried type.
* @return 0 or error code.
+ * @retval DNSSEC_NOT_FOUND denial of existence can't be proven due to opt-out.
*/
-int kr_nsec3_no_data(const knot_pkt_t *pkt, knot_section_t section_id,
+int kr_nsec3_no_data_no_ds(const knot_pkt_t *pkt, knot_section_t section_id,
const knot_dname_t *sname, uint16_t stype);
+/**
+ * Authenticated denial of existence according to RFC5155 8.6
+ * @note No RRSIGs are validated.
+ * @param pkt Packet structure to be processed.
+ * @param section_id Packet section to be processed.
+ * @param sname Queried domain name.
+ * @return 0 or error code.
+ */
+int kr_nsec3_no_data_ds(const knot_pkt_t *pkt, knot_section_t section_id,
+ const knot_dname_t *sname);
#include <libknot/packet/wire.h>
#include <libknot/rrtype/rdname.h>
#include <libknot/rrtype/rrsig.h>
+#include <dnssec/error.h>
#include "lib/dnssec/nsec.h"
#include "lib/dnssec/nsec3.h"
if (!has_nsec3) {
ret = kr_nsec_existence_denial(answer, KNOT_AUTHORITY, proved_name, KNOT_RRTYPE_DS);
} else {
- ret = kr_nsec3_no_data(answer, KNOT_AUTHORITY, proved_name, KNOT_RRTYPE_DS);
+ ret = kr_nsec3_no_data_ds(answer, KNOT_AUTHORITY, proved_name);
}
if (ret != 0) {
DEBUG_MSG(qry, "<= bogus proof of DS non-existence\n");
if (!has_nsec3) {
ret = kr_nsec_existence_denial(pkt, KNOT_AUTHORITY, knot_pkt_qname(pkt), knot_pkt_qtype(pkt));
} else {
- ret = kr_nsec3_no_data(pkt, KNOT_AUTHORITY, knot_pkt_qname(pkt), knot_pkt_qtype(pkt));
+ ret = kr_nsec3_no_data_no_ds(pkt, KNOT_AUTHORITY, knot_pkt_qname(pkt), knot_pkt_qtype(pkt));
}
if (ret != 0) {
- DEBUG_MSG(qry, "<= bad NODATA proof\n");
- qry->flags |= QUERY_DNSSEC_BOGUS;
- return KNOT_STATE_FAIL;
+ if (has_nsec3 && (ret == DNSSEC_NOT_FOUND)) {
+ DEBUG_MSG(qry, "<= can't prove NODATA due to optout, going insecure\n");
+ qry->flags &= ~QUERY_DNSSEC_WANT;
+ qry->flags |= QUERY_DNSSEC_INSECURE;
+ } else {
+ DEBUG_MSG(qry, "<= bad NODATA proof\n");
+ qry->flags |= QUERY_DNSSEC_BOGUS;
+ return KNOT_STATE_FAIL;
+ }
}
}
}