Пример #1
0
enum sec_status
nsec3_prove_nxornodata(struct module_env* env, struct val_env* ve,
	struct ub_packed_rrset_key** list, size_t num, 
	struct query_info* qinfo, struct key_entry_key* kkey, int* nodata)
{
	enum sec_status sec, secnx;
	rbtree_t ct;
	struct nsec3_filter flt;
	*nodata = 0;

	if(!list || num == 0 || !kkey || !key_entry_isgood(kkey))
		return sec_status_bogus; /* no valid NSEC3s, bogus */
	rbtree_init(&ct, &nsec3_hash_cmp); /* init names-to-hash cache */
	filter_init(&flt, list, num, qinfo); /* init RR iterator */
	if(!flt.zone)
		return sec_status_bogus; /* no RRs */
	if(nsec3_iteration_count_high(ve, &flt, kkey))
		return sec_status_insecure; /* iteration count too high */

	/* try nxdomain and nodata after another, while keeping the
	 * hash cache intact */

	secnx = nsec3_do_prove_nameerror(env, &flt, &ct, qinfo);
	if(secnx==sec_status_secure)
		return sec_status_secure;
	sec = nsec3_do_prove_nodata(env, &flt, &ct, qinfo);
	if(sec==sec_status_secure) {
		*nodata = 1;
	} else if(sec == sec_status_insecure) {
		*nodata = 1;
	} else if(secnx == sec_status_insecure) {
		sec = sec_status_insecure;
	}
	return sec;
}
Пример #2
0
enum sec_status
nsec3_prove_wildcard(struct module_env* env, struct val_env* ve,
        struct ub_packed_rrset_key** list, size_t num,
	struct query_info* qinfo, struct key_entry_key* kkey, uint8_t* wc)
{
	rbtree_t ct;
	struct nsec3_filter flt;
	struct ce_response ce;
	uint8_t* nc;
	size_t nc_len;
	size_t wclen;
	(void)dname_count_size_labels(wc, &wclen);

	if(!list || num == 0 || !kkey || !key_entry_isgood(kkey))
		return sec_status_bogus; /* no valid NSEC3s, bogus */
	rbtree_init(&ct, &nsec3_hash_cmp); /* init names-to-hash cache */
	filter_init(&flt, list, num, qinfo); /* init RR iterator */
	if(!flt.zone)
		return sec_status_bogus; /* no RRs */
	if(nsec3_iteration_count_high(ve, &flt, kkey))
		return sec_status_insecure; /* iteration count too high */

	/* We know what the (purported) closest encloser is by just 
	 * looking at the supposed generating wildcard. 
	 * The *. has already been removed from the wc name.
	 */
	memset(&ce, 0, sizeof(ce));
	ce.ce = wc;
	ce.ce_len = wclen;

	/* Now we still need to prove that the original data did not exist.
	 * Otherwise, we need to show that the next closer name is covered. */
	next_closer(qinfo->qname, qinfo->qname_len, ce.ce, &nc, &nc_len);
	if(!find_covering_nsec3(env, &flt, &ct, nc, nc_len, 
		&ce.nc_rrset, &ce.nc_rr)) {
		verbose(VERB_ALGO, "proveWildcard: did not find a covering "
			"NSEC3 that covered the next closer name.");
		return sec_status_bogus;
	}
	if(ce.nc_rrset && nsec3_has_optout(ce.nc_rrset, ce.nc_rr)) {
		verbose(VERB_ALGO, "proveWildcard: NSEC3 optout");
		return sec_status_insecure;
	}
	return sec_status_secure;
}
Пример #3
0
enum sec_status
nsec3_prove_nodata(struct module_env* env, struct val_env* ve,
	struct ub_packed_rrset_key** list, size_t num,
	struct query_info* qinfo, struct key_entry_key* kkey)
{
	rbtree_t ct;
	struct nsec3_filter flt;

	if(!list || num == 0 || !kkey || !key_entry_isgood(kkey))
		return sec_status_bogus; /* no valid NSEC3s, bogus */
	rbtree_init(&ct, &nsec3_hash_cmp); /* init names-to-hash cache */
	filter_init(&flt, list, num, qinfo); /* init RR iterator */
	if(!flt.zone)
		return sec_status_bogus; /* no RRs */
	if(nsec3_iteration_count_high(ve, &flt, kkey))
		return sec_status_insecure; /* iteration count too high */
	return nsec3_do_prove_nodata(env, &flt, &ct, qinfo);
}
Пример #4
0
int 
iter_indicates_dnssec(struct module_env* env, struct delegpt* dp,
        struct dns_msg* msg, uint16_t dclass)
{
	struct trust_anchor* a;
	/* information not available, !env->anchors can be common */
	if(!env || !env->anchors || !dp || !dp->name)
		return 0;
	/* a trust anchor exists with this name, RRSIGs expected */
	if((a=anchor_find(env->anchors, dp->name, dp->namelabs, dp->namelen,
		dclass))) {
		lock_basic_unlock(&a->lock);
		return 1;
	}
	/* see if DS rrset was given, in AUTH section */
	if(msg && msg->rep &&
		reply_find_rrset_section_ns(msg->rep, dp->name, dp->namelen,
		LDNS_RR_TYPE_DS, dclass))
		return 1;
	/* look in key cache */
	if(env->key_cache) {
		struct key_entry_key* kk = key_cache_obtain(env->key_cache,
			dp->name, dp->namelen, dclass, env->scratch, *env->now);
		if(kk) {
			if(query_dname_compare(kk->name, dp->name) == 0) {
			  if(key_entry_isgood(kk) || key_entry_isbad(kk)) {
				regional_free_all(env->scratch);
				return 1;
			  } else if(key_entry_isnull(kk)) {
				regional_free_all(env->scratch);
				return 0;
			  }
			}
			regional_free_all(env->scratch);
		}
	}
	return 0;
}
Пример #5
0
enum sec_status
nsec3_prove_nods(struct module_env* env, struct val_env* ve,
	struct ub_packed_rrset_key** list, size_t num,
	struct query_info* qinfo, struct key_entry_key* kkey, char** reason)
{
	rbtree_t ct;
	struct nsec3_filter flt;
	struct ce_response ce;
	struct ub_packed_rrset_key* rrset;
	int rr;
	log_assert(qinfo->qtype == LDNS_RR_TYPE_DS);

	if(!list || num == 0 || !kkey || !key_entry_isgood(kkey)) {
		*reason = "no valid NSEC3s";
		return sec_status_bogus; /* no valid NSEC3s, bogus */
	}
	if(!list_is_secure(env, ve, list, num, kkey, reason))
		return sec_status_bogus; /* not all NSEC3 records secure */
	rbtree_init(&ct, &nsec3_hash_cmp); /* init names-to-hash cache */
	filter_init(&flt, list, num, qinfo); /* init RR iterator */
	if(!flt.zone) {
		*reason = "no NSEC3 records";
		return sec_status_bogus; /* no RRs */
	}
	if(nsec3_iteration_count_high(ve, &flt, kkey))
		return sec_status_insecure; /* iteration count too high */

	/* Look for a matching NSEC3 to qname -- this is the normal 
	 * NODATA case. */
	if(find_matching_nsec3(env, &flt, &ct, qinfo->qname, qinfo->qname_len, 
		&rrset, &rr)) {
		/* If the matching NSEC3 has the SOA bit set, it is from 
		 * the wrong zone (the child instead of the parent). If 
		 * it has the DS bit set, then we were lied to. */
		if(nsec3_has_type(rrset, rr, LDNS_RR_TYPE_SOA) && 
			qinfo->qname_len != 1) {
			verbose(VERB_ALGO, "nsec3 provenods: NSEC3 is from"
				" child zone, bogus");
			*reason = "NSEC3 from child zone";
			return sec_status_bogus;
		} else if(nsec3_has_type(rrset, rr, LDNS_RR_TYPE_DS)) {
			verbose(VERB_ALGO, "nsec3 provenods: NSEC3 has qtype"
				" DS, bogus");
			*reason = "NSEC3 has DS in bitmap";
			return sec_status_bogus;
		}
		/* If the NSEC3 RR doesn't have the NS bit set, then 
		 * this wasn't a delegation point. */
		if(!nsec3_has_type(rrset, rr, LDNS_RR_TYPE_NS))
			return sec_status_indeterminate;
		/* Otherwise, this proves no DS. */
		return sec_status_secure;
	}

	/* Otherwise, we are probably in the opt-out case. */
	if(nsec3_prove_closest_encloser(env, &flt, &ct, qinfo, 1, &ce)
		!= sec_status_secure) {
		/* an insecure delegation *above* the qname does not prove
		 * anything about this qname exactly, and bogus is bogus */
		verbose(VERB_ALGO, "nsec3 provenods: did not match qname, "
		          "nor found a proven closest encloser.");
		*reason = "no NSEC3 closest encloser";
		return sec_status_bogus;
	}

	/* robust extra check */
	if(!ce.nc_rrset) {
		verbose(VERB_ALGO, "nsec3 nods proof: no next closer nsec3");
		*reason = "no NSEC3 next closer";
		return sec_status_bogus;
	}

	/* we had the closest encloser proof, then we need to check that the
	 * covering NSEC3 was opt-out -- the proveClosestEncloser step already
	 * checked to see if the closest encloser was a delegation or DNAME.
	 */
	log_assert(ce.nc_rrset);
	if(!nsec3_has_optout(ce.nc_rrset, ce.nc_rr)) {
		verbose(VERB_ALGO, "nsec3 provenods: covering NSEC3 was not "
			"opt-out in an opt-out DS NOERROR/NODATA case.");
		*reason = "covering NSEC3 was not opt-out in an opt-out "
			"DS NOERROR/NODATA case";
		return sec_status_bogus;
	}
	/* RFC5155 section 9.2: if nc has optout then no AD flag set */
	return sec_status_insecure;
}