From 6703a067ec757f415da10b62140f74e673a06ba0 Mon Sep 17 00:00:00 2001 From: Grigorii Demidov Date: Fri, 17 Mar 2017 09:20:17 +0100 Subject: [PATCH] layer/validate: clear AD if closest encloser proof has optouted NSEC3 --- lib/cache.h | 5 +++++ lib/dnssec/nsec3.c | 51 ++++++++++++++++++++++++++++++-------------- lib/layer/pktcache.c | 6 ++++++ lib/layer/validate.c | 11 ++++++++-- lib/resolve.c | 3 ++- lib/rplan.h | 1 + tests/deckard | 2 +- 7 files changed, 59 insertions(+), 20 deletions(-) diff --git a/lib/cache.h b/lib/cache.h index b237602c9..b9f8f84b7 100644 --- a/lib/cache.h +++ b/lib/cache.h @@ -54,6 +54,11 @@ enum kr_cache_flag { KR_CACHE_FLAG_WCARD_PROOF = 1, /* Entry contains either packet with wildcard * answer either record for which wildcard * expansion proof is needed */ + KR_CACHE_FLAG_OPTOUT = 2, /* Entry contains secured packet containing a + * closest encloser proof in which the NSEC3 RR + * that covers the "next closer" name + * has the Opt-Out bit set + */ }; diff --git a/lib/dnssec/nsec3.c b/lib/dnssec/nsec3.c index f7c7a32ec..c8585fa44 100644 --- a/lib/dnssec/nsec3.c +++ b/lib/dnssec/nsec3.c @@ -360,17 +360,20 @@ static int prepend_asterisk(uint8_t *tgt, size_t maxlen, const knot_dname_t *nam /** * Closest encloser proof (RFC5155 7.2.1). * @note No RRSIGs are validated. - * @param pkt Packet structure to be processed. - * @param section_id Packet section to be processed. - * @param sname Name to be checked. - * @param encloser_name Returned matching encloser name, if found. - * @param matching_ecloser_nsec3 Pointer to matching encloser NSEC RRSet. - * @param covering_next_nsec3 Pointer to covering next closer NSEC3 RRSet. - * @return 0 or error code. + * @param pkt Packet structure to be processed. + * @param section_id Packet section to be processed. + * @param sname Name to be checked. + * @param encloser_name Returned matching encloser name, if found. + * @param matching_encloser_nsec3 Pointer to matching encloser NSEC RRSet. + * @param covering_next_nsec3 Pointer to covering next closer NSEC3 RRSet. + * @return 0 or error code. */ -static int closest_encloser_proof(const knot_pkt_t *pkt, knot_section_t section_id, - const knot_dname_t *sname, const knot_dname_t **encloser_name, - const knot_rrset_t **matching_ecloser_nsec3, const knot_rrset_t **covering_next_nsec3) +static int closest_encloser_proof(const knot_pkt_t *pkt, + knot_section_t section_id, + const knot_dname_t *sname, + const knot_dname_t **encloser_name, + const knot_rrset_t **matching_encloser_nsec3, + const knot_rrset_t **covering_next_nsec3) { const knot_pktsection_t *sec = knot_pkt_section(pkt, section_id); if (!sec || !sname) { @@ -427,8 +430,8 @@ static int closest_encloser_proof(const knot_pkt_t *pkt, knot_section_t section_ if (encloser_name && next_closer[0]) { *encloser_name = knot_wire_next_label(next_closer, NULL); } - if (matching_ecloser_nsec3) { - *matching_ecloser_nsec3 = matching; + if (matching_encloser_nsec3) { + *matching_encloser_nsec3 = matching; } if (covering_next_nsec3) { *covering_next_nsec3 = covering; @@ -444,7 +447,10 @@ static int closest_encloser_proof(const knot_pkt_t *pkt, knot_section_t section_ * @param pkt Packet structure to be processed. * @param section_id Packet section to be processed. * @param encloser Closest (provable) encloser domain name. - * @return 0 or error code. + * @return 0 or error code: + * DNSSEC_OUT_OF_RANGE - NSEC3 RR (that covers a wildcard) + * has been found, but has opt-out flag set; + * otherwise - error. */ static int covers_closest_encloser_wildcard(const knot_pkt_t *pkt, knot_section_t section_id, const knot_dname_t *encloser) @@ -474,7 +480,8 @@ static int covers_closest_encloser_wildcard(const knot_pkt_t *pkt, knot_section_ return ret; } if (flags & FLG_NAME_COVERED) { - return kr_ok(); + return has_optout(rrset) ? + kr_error(DNSSEC_OUT_OF_RANGE) : kr_ok(); } } @@ -485,11 +492,23 @@ int kr_nsec3_name_error_response_check(const knot_pkt_t *pkt, knot_section_t sec const knot_dname_t *sname) { const knot_dname_t *encloser = NULL; - int ret = closest_encloser_proof(pkt, section_id, sname, &encloser, NULL, NULL); + const knot_rrset_t *covering_next_nsec3 = NULL; + int ret = closest_encloser_proof(pkt, section_id, sname, + &encloser, NULL, &covering_next_nsec3); + if (ret != 0) { + return ret; + } + ret = covers_closest_encloser_wildcard(pkt, section_id, encloser); if (ret != 0) { + /* OK, but NSEC3 for wildcard at encloser has opt-out; + * or error */ return ret; } - return covers_closest_encloser_wildcard(pkt, section_id, encloser); + /* Closest encloser proof is OK and + * NSEC3 for wildcard has been found and optout flag is not set. + * Now check if NSEC3 that covers next closer name has opt-out. */ + return has_optout(covering_next_nsec3) ? + kr_error(DNSSEC_OUT_OF_RANGE) : kr_ok(); } /** diff --git a/lib/layer/pktcache.c b/lib/layer/pktcache.c index 861e47cba..942f61382 100644 --- a/lib/layer/pktcache.c +++ b/lib/layer/pktcache.c @@ -128,6 +128,9 @@ static int pktcache_peek(kr_layer_t *ctx, knot_pkt_t *pkt) if (flags & KR_CACHE_FLAG_WCARD_PROOF) { qry->flags |= QUERY_DNSSEC_WEXPAND; } + if (flags & KR_CACHE_FLAG_OPTOUT) { + qry->flags |= QUERY_DNSSEC_OPTOUT; + } pkt->parsed = pkt->size; knot_wire_set_qr(pkt->wire); knot_wire_set_aa(pkt->wire); @@ -229,6 +232,9 @@ static int pktcache_stash(kr_layer_t *ctx, knot_pkt_t *pkt) if (qry->flags & QUERY_DNSSEC_WEXPAND) { header.flags |= KR_CACHE_FLAG_WCARD_PROOF; } + if (qry->flags & QUERY_DNSSEC_OPTOUT) { + header.flags |= KR_CACHE_FLAG_OPTOUT; + } /* Check if we can replace (allow current or better rank, SECURE is always accepted). */ struct kr_cache *cache = &ctx->req->ctx->cache; diff --git a/lib/layer/validate.c b/lib/layer/validate.c index bdff94a3a..ae66e5486 100644 --- a/lib/layer/validate.c +++ b/lib/layer/validate.c @@ -641,7 +641,14 @@ static int validate(kr_layer_t *ctx, knot_pkt_t *pkt) } else { ret = kr_nsec3_name_error_response_check(pkt, KNOT_AUTHORITY, qry->sname); } - if (ret != 0) { + if (has_nsec3 && (ret == kr_error(DNSSEC_OUT_OF_RANGE))) { + /* NXDOMAIN proof is OK, + * but NSEC3 that covers next closer name + * (or wildcard at next closer name) has opt-out flag. + * RFC5155 9.2; AD flag can not be set */ + qry->flags |= QUERY_DNSSEC_OPTOUT; + VERBOSE_MSG(qry, "<= can't prove NXDOMAIN due to optout, going insecure\n"); + } else if (ret != 0) { VERBOSE_MSG(qry, "<= bad NXDOMAIN proof\n"); qry->flags |= QUERY_DNSSEC_BOGUS; return KR_STATE_FAIL; @@ -665,7 +672,7 @@ static int validate(kr_layer_t *ctx, knot_pkt_t *pkt) if (ret != 0) { if (has_nsec3 && (ret == kr_error(DNSSEC_OUT_OF_RANGE))) { VERBOSE_MSG(qry, "<= can't prove NODATA due to optout, going insecure\n"); - qry->flags |= QUERY_DNSSEC_NODS; + qry->flags |= QUERY_DNSSEC_OPTOUT; /* Could not return from here, * we must continue, validate NSEC\NSEC3 and * call update_parent_keys() to mark diff --git a/lib/resolve.c b/lib/resolve.c index 591d22f12..c6496f763 100644 --- a/lib/resolve.c +++ b/lib/resolve.c @@ -537,7 +537,8 @@ static int answer_finalize(struct kr_request *request, int state) struct kr_query *last = array_tail(rplan->resolved); /* Do not set AD for RRSIG query, as we can't validate it. */ const bool secure = (last->flags & QUERY_DNSSEC_WANT) && - !(last->flags & QUERY_DNSSEC_INSECURE); + !(last->flags & QUERY_DNSSEC_INSECURE) && + !(last->flags & QUERY_DNSSEC_OPTOUT); if (!(last->flags & QUERY_STUB) /* Never set AD if forwarding. */ && has_ad && secure && knot_pkt_qtype(answer) != KNOT_RRTYPE_RRSIG) { diff --git a/lib/rplan.h b/lib/rplan.h index 6a70835eb..4f7628963 100644 --- a/lib/rplan.h +++ b/lib/rplan.h @@ -54,6 +54,7 @@ X(TRACE, 1 << 25) /**< Log answer with kr_verbose_log(), unless -DNDEBUG. */ \ X(NO_0X20, 1 << 26) /**< Disable query case randomization . */ \ X(DNSSEC_NODS, 1 << 27) /**< DS non-existance is proven */ \ + X(DNSSEC_OPTOUT, 1 << 28) /**< Closest encloser proof has optout */ \ /* 1 << 31 Used by ../modules/dns64/dns64.lua */ /** Query flags */ diff --git a/tests/deckard b/tests/deckard index b7453577c..b96ef5cd5 160000 --- a/tests/deckard +++ b/tests/deckard @@ -1 +1 @@ -Subproject commit b7453577c57cb837261ca6e21098b8a44a9e8b3d +Subproject commit b96ef5cd589ddb71eefb89e09fee1087a49edf35 -- 2.47.2