コード例 #1
0
ファイル: val_utils.c プロジェクト: RS-liuyang/rsdns
/** Get signer name from RRSIG */
static void
rrsig_get_signer(uint8_t* data, size_t len, uint8_t** sname, size_t* slen)
{
	/* RRSIG rdata is not allowed to be compressed, it is stored
	 * uncompressed in memory as well, so return a ptr to the name */
	if(len < 21) {
		/* too short RRSig:
		 * short, byte, byte, long, long, long, short, "." is
		 * 2	1	1	4	4  4	2	1 = 19
		 * 			and a skip of 18 bytes to the name.
		 * +2 for the rdatalen is 21 bytes len for root label */
		*sname = NULL;
		*slen = 0;
		return;
	}
	data += 20; /* skip the fixed size bits */
	len -= 20;
	*slen = dname_valid(data, len);
	if(!*slen) {
		/* bad dname in this rrsig. */
		*sname = NULL;
		return;
	}
	*sname = data;
}
コード例 #2
0
ファイル: unitdname.c プロジェクト: schvin/unbound
/** Test dname_valid */
static void
dname_test_valid(void)
{
	unit_show_func("util/data/dname.c", "dname_valid");
	unit_assert( dname_valid( 
			(uint8_t*)"\003www\007example\003com", 255) == 17);
	unit_assert( dname_valid((uint8_t*)"", 255) == 1);
	unit_assert( dname_valid( (uint8_t*)
		"\020a1cdef5555544444"
		"\020a2cdef5555544444"
		"\020a3cdef5555544444"
		"\020a4cdef5555544444"
		"\020a5cdef5555544444"
		"\020a6cdef5555544444"
		"\020a7cdef5555544444"
		"\020a8cdef5555544444"
		"\020a9cdef5555544444"
		"\020aAcdef5555544444"
		"\020aBcdef5555544444"
		"\020aCcdef5555544444"
		"\020aDcdef5555544444"
		"\020aEcdef5555544444"	/* 238 up to here */
		"\007aabbccd"		/* 246 up to here */
		"\007example\000"	/* 255 to here */
		, 255) == 255);
	unit_assert( dname_valid( (uint8_t*)
		"\020a1cdef5555544444"
		"\020a2cdef5555544444"
		"\020a3cdef5555544444"
		"\020a4cdef5555544444"
		"\020a5cdef5555544444"
		"\020a6cdef5555544444"
		"\020a7cdef5555544444"
		"\020a8cdef5555544444"
		"\020a9cdef5555544444"
		"\020aAcdef5555544444"
		"\020aBcdef5555544444"
		"\020aCcdef5555544444"
		"\020aDcdef5555544444"
		"\020aEcdef5555544444"	/* 238 up to here */
		"\007aabbccd"		/* 246 up to here */
		"\010exampleX\000"	/* 256 to here */
		, 4096) == 0);
}
コード例 #3
0
ファイル: val_utils.c プロジェクト: schvin/unbound
/** see if rrset has signer name as one of the rrsig signers */
static int
rrset_has_signer(struct ub_packed_rrset_key* rrset, uint8_t* name, size_t len)
{
	struct packed_rrset_data* d = (struct packed_rrset_data*)rrset->
		entry.data;
	size_t i;
	for(i = d->count; i< d->count+d->rrsig_count; i++) {
		if(d->rr_len[i] > 2+18+len) {
			/* at least rdatalen + signature + signame (+1 sig)*/
			if(!dname_valid(d->rr_data[i]+2+18, d->rr_len[i]-2-18))
				continue;
			if(query_dname_compare(name, d->rr_data[i]+2+18) == 0)
			{
				return 1;
			}
		}
	}
	return 0;
}
コード例 #4
0
ファイル: iter_delegpt.c プロジェクト: RS-liuyang/rsdns
int 
delegpt_rrset_add_ns(struct delegpt* dp, struct regional* region,
        struct ub_packed_rrset_key* ns_rrset, int lame)
{
	struct packed_rrset_data* nsdata = (struct packed_rrset_data*)
		ns_rrset->entry.data;
	size_t i;
	if(nsdata->security == sec_status_bogus)
		dp->bogus = 1;
	for(i=0; i<nsdata->count; i++) {
		if(nsdata->rr_len[i] < 2+1) continue; /* len + root label */
		if(dname_valid(nsdata->rr_data[i]+2, nsdata->rr_len[i]-2) !=
			(size_t)ldns_read_uint16(nsdata->rr_data[i]))
			continue; /* bad format */
		/* add rdata of NS (= wirefmt dname), skip rdatalen bytes */
		if(!delegpt_add_ns(dp, region, nsdata->rr_data[i]+2, lame))
			return 0;
	}
	return 1;
}
コード例 #5
0
/**
 * Check if right hand name in NSEC is within zone
 * @param rrset: the NSEC rrset
 * @param zonename: the zone name.
 * @return true if BAD.
 */
static int sanitize_nsec_is_overreach(struct rrset_parse* rrset,
                                      uint8_t* zonename)
{
    struct rr_parse* rr;
    uint8_t* rhs;
    size_t len;
    log_assert(rrset->type == LDNS_RR_TYPE_NSEC);
    for(rr = rrset->rr_first; rr; rr = rr->next) {
        rhs = rr->ttl_data+4+2;
        len = ldns_read_uint16(rr->ttl_data+4);
        if(!dname_valid(rhs, len)) {
            /* malformed domain name in rdata */
            return 1;
        }
        if(!dname_subdomain_c(rhs, zonename)) {
            /* overreaching */
            return 1;
        }
    }
    /* all NSEC RRs OK */
    return 0;
}
コード例 #6
0
ファイル: packed_rrset.c プロジェクト: 2asoft/freebsd
void 
get_cname_target(struct ub_packed_rrset_key* rrset, uint8_t** dname, 
	size_t* dname_len)
{
	struct packed_rrset_data* d;
	size_t len;
	if(ntohs(rrset->rk.type) != LDNS_RR_TYPE_CNAME && 
		ntohs(rrset->rk.type) != LDNS_RR_TYPE_DNAME)
		return;
	d = (struct packed_rrset_data*)rrset->entry.data;
	if(d->count < 1)
		return;
	if(d->rr_len[0] < 3) /* at least rdatalen + 0byte root label */
		return;
	len = sldns_read_uint16(d->rr_data[0]);
	if(len != d->rr_len[0] - sizeof(uint16_t))
		return;
	if(dname_valid(d->rr_data[0]+sizeof(uint16_t), len) != len)
		return;
	*dname = d->rr_data[0]+sizeof(uint16_t);
	*dname_len = len;
}
コード例 #7
0
ファイル: val_neg.c プロジェクト: stasic/debian-unbound
/**
 * Remove NSEC records between start and end points.
 * By walking the tree, the tree is sorted canonically.
 * @param neg: negative cache.
 * @param zone: the zone
 * @param el: element to start walking at.
 * @param nsec: the nsec record with the end point
 */
static void wipeout(struct val_neg_cache* neg, struct val_neg_zone* zone, 
	struct val_neg_data* el, struct ub_packed_rrset_key* nsec)
{
	struct packed_rrset_data* d = (struct packed_rrset_data*)nsec->
		entry.data;
	uint8_t* end;
	size_t end_len;
	int end_labs, m;
	rbnode_t* walk, *next;
	struct val_neg_data* cur;
	uint8_t buf[257];
	/* get endpoint */
	if(!d || d->count == 0 || d->rr_len[0] < 2+1)
		return;
	if(ntohs(nsec->rk.type) == LDNS_RR_TYPE_NSEC) {
		end = d->rr_data[0]+2;
		end_len = dname_valid(end, d->rr_len[0]-2);
		end_labs = dname_count_labels(end);
	} else {
		/* NSEC3 */
		if(!nsec3_get_nextowner_b32(nsec, 0, buf, sizeof(buf)))
			return;
		end = buf;
		end_labs = dname_count_size_labels(end, &end_len);
	}

	/* sanity check, both owner and end must be below the zone apex */
	if(!dname_subdomain_c(el->name, zone->name) || 
		!dname_subdomain_c(end, zone->name))
		return;

	/* detect end of zone NSEC ; wipe until the end of zone */
	if(query_dname_compare(end, zone->name) == 0) {
		end = NULL;
	}

	walk = rbtree_next(&el->node);
	while(walk && walk != RBTREE_NULL) {
		cur = (struct val_neg_data*)walk;
		/* sanity check: must be larger than start */
		if(dname_canon_lab_cmp(cur->name, cur->labs, 
			el->name, el->labs, &m) <= 0) {
			/* r == 0 skip original record. */
			/* r < 0  too small! */
			walk = rbtree_next(walk);
			continue;
		}
		/* stop at endpoint, also data at empty nonterminals must be
		 * removed (no NSECs there) so everything between 
		 * start and end */
		if(end && dname_canon_lab_cmp(cur->name, cur->labs,
			end, end_labs, &m) >= 0) {
			break;
		}
		/* this element has to be deleted, but we cannot do it
		 * now, because we are walking the tree still ... */
		/* get the next element: */
		next = rbtree_next(walk);
		/* now delete the original element, this may trigger
		 * rbtree rebalances, but really, the next element is
		 * the one we need.
		 * But it may trigger delete of other data and the
		 * entire zone. However, if that happens, this is done
		 * by deleting the *parents* of the element for deletion,
		 * and maybe also the entire zone if it is empty. 
		 * But parents are smaller in canonical compare, thus,
		 * if a larger element exists, then it is not a parent,
		 * it cannot get deleted, the zone cannot get empty.
		 * If the next==NULL, then zone can be empty. */
		if(cur->in_use)
			neg_delete_data(neg, cur);
		walk = next;
	}
}
コード例 #8
0
ファイル: val_sigcrypt.c プロジェクト: 2trill2spill/freebsd
/**
 * Canonicalize Rdata in buffer.
 * @param buf: buffer at position just after the rdata.
 * @param rrset: rrset with type.
 * @param len: length of the rdata (including rdatalen uint16).
 */
static void
canonicalize_rdata(sldns_buffer* buf, struct ub_packed_rrset_key* rrset,
	size_t len)
{
	uint8_t* datstart = sldns_buffer_current(buf)-len+2;
	switch(ntohs(rrset->rk.type)) {
		case LDNS_RR_TYPE_NXT: 
		case LDNS_RR_TYPE_NS:
		case LDNS_RR_TYPE_MD:
		case LDNS_RR_TYPE_MF:
		case LDNS_RR_TYPE_CNAME:
		case LDNS_RR_TYPE_MB:
		case LDNS_RR_TYPE_MG:
		case LDNS_RR_TYPE_MR:
		case LDNS_RR_TYPE_PTR:
		case LDNS_RR_TYPE_DNAME:
			/* type only has a single argument, the name */
			query_dname_tolower(datstart);
			return;
		case LDNS_RR_TYPE_MINFO:
		case LDNS_RR_TYPE_RP:
		case LDNS_RR_TYPE_SOA:
			/* two names after another */
			query_dname_tolower(datstart);
			query_dname_tolower(datstart + 
				dname_valid(datstart, len-2));
			return;
		case LDNS_RR_TYPE_RT:
		case LDNS_RR_TYPE_AFSDB:
		case LDNS_RR_TYPE_KX:
		case LDNS_RR_TYPE_MX:
			/* skip fixed part */
			if(len < 2+2+1) /* rdlen, skiplen, 1byteroot */
				return;
			datstart += 2;
			query_dname_tolower(datstart);
			return;
		case LDNS_RR_TYPE_SIG:
		/* downcase the RRSIG, compat with BIND (kept it from SIG) */
		case LDNS_RR_TYPE_RRSIG:
			/* skip fixed part */
			if(len < 2+18+1)
				return;
			datstart += 18;
			query_dname_tolower(datstart);
			return;
		case LDNS_RR_TYPE_PX:
			/* skip, then two names after another */
			if(len < 2+2+1) 
				return;
			datstart += 2;
			query_dname_tolower(datstart);
			query_dname_tolower(datstart + 
				dname_valid(datstart, len-2-2));
			return;
		case LDNS_RR_TYPE_NAPTR:
			if(len < 2+4)
				return;
			len -= 2+4;
			datstart += 4;
			if(len < (size_t)datstart[0]+1) /* skip text field */
				return;
			len -= (size_t)datstart[0]+1;
			datstart += (size_t)datstart[0]+1;
			if(len < (size_t)datstart[0]+1) /* skip text field */
				return;
			len -= (size_t)datstart[0]+1;
			datstart += (size_t)datstart[0]+1;
			if(len < (size_t)datstart[0]+1) /* skip text field */
				return;
			len -= (size_t)datstart[0]+1;
			datstart += (size_t)datstart[0]+1;
			if(len < 1)	/* check name is at least 1 byte*/
				return;
			query_dname_tolower(datstart);
			return;
		case LDNS_RR_TYPE_SRV:
			/* skip fixed part */
			if(len < 2+6+1)
				return;
			datstart += 6;
			query_dname_tolower(datstart);
			return;

		/* do not canonicalize NSEC rdata name, compat with 
		 * from bind 9.4 signer, where it does not do so */
		case LDNS_RR_TYPE_NSEC: /* type starts with the name */
		case LDNS_RR_TYPE_HINFO: /* not downcased */
		/* A6 not supported */
		default:	
			/* nothing to do for unknown types */
			return;
	}
}
コード例 #9
0
ファイル: val_sigcrypt.c プロジェクト: 2trill2spill/freebsd
/**
 * Compare two RRs in the same RRset and determine their relative
 * canonical order.
 * @param rrset: the rrset in which to perform compares.
 * @param i: first RR to compare
 * @param j: first RR to compare
 * @return 0 if RR i== RR j, -1 if <, +1 if >.
 */
static int
canonical_compare(struct ub_packed_rrset_key* rrset, size_t i, size_t j)
{
	struct packed_rrset_data* d = (struct packed_rrset_data*)
		rrset->entry.data;
	const sldns_rr_descriptor* desc;
	uint16_t type = ntohs(rrset->rk.type);
	size_t minlen;
	int c;

	if(i==j)
		return 0;

	switch(type) {
		/* These RR types have only a name as RDATA. 
		 * This name has to be canonicalized.*/
		case LDNS_RR_TYPE_NS:
		case LDNS_RR_TYPE_MD:
		case LDNS_RR_TYPE_MF:
		case LDNS_RR_TYPE_CNAME:
		case LDNS_RR_TYPE_MB:
		case LDNS_RR_TYPE_MG:
		case LDNS_RR_TYPE_MR:
		case LDNS_RR_TYPE_PTR:
		case LDNS_RR_TYPE_DNAME:
			/* the wireread function has already checked these
			 * dname's for correctness, and this double checks */
			if(!dname_valid(d->rr_data[i]+2, d->rr_len[i]-2) ||
				!dname_valid(d->rr_data[j]+2, d->rr_len[j]-2))
				return 0;
			return query_dname_compare(d->rr_data[i]+2,
				d->rr_data[j]+2);

		/* These RR types have STR and fixed size rdata fields
		 * before one or more name fields that need canonicalizing,
		 * and after that a byte-for byte remainder can be compared.
		 */
		/* type starts with the name; remainder is binary compared */
		case LDNS_RR_TYPE_NXT: 
		/* use rdata field formats */
		case LDNS_RR_TYPE_MINFO:
		case LDNS_RR_TYPE_RP:
		case LDNS_RR_TYPE_SOA:
		case LDNS_RR_TYPE_RT:
		case LDNS_RR_TYPE_AFSDB:
		case LDNS_RR_TYPE_KX:
		case LDNS_RR_TYPE_MX:
		case LDNS_RR_TYPE_SIG:
		/* RRSIG signer name has to be downcased */
		case LDNS_RR_TYPE_RRSIG:
		case LDNS_RR_TYPE_PX:
		case LDNS_RR_TYPE_NAPTR:
		case LDNS_RR_TYPE_SRV:
			desc = sldns_rr_descript(type);
			log_assert(desc);
			/* this holds for the types that need canonicalizing */
			log_assert(desc->_minimum == desc->_maximum);
			return canonical_compare_byfield(d, desc, i, j);

		case LDNS_RR_TYPE_HINFO: /* no longer downcased */
		case LDNS_RR_TYPE_NSEC: 
	default:
		/* For unknown RR types, or types not listed above,
		 * no canonicalization is needed, do binary compare */
		/* byte for byte compare, equal means shortest first*/
		minlen = d->rr_len[i]-2;
		if(minlen > d->rr_len[j]-2)
			minlen = d->rr_len[j]-2;
		c = memcmp(d->rr_data[i]+2, d->rr_data[j]+2, minlen);
		if(c!=0)
			return c;
		/* rdata equal, shortest is first */
		if(d->rr_len[i] < d->rr_len[j])
			return -1;
		if(d->rr_len[i] > d->rr_len[j])
			return 1;
		/* rdata equal, length equal */
		break;
	}
	return 0;
}
コード例 #10
0
ファイル: val_sigcrypt.c プロジェクト: 2trill2spill/freebsd
enum sec_status 
dnskey_verify_rrset_sig(struct regional* region, sldns_buffer* buf, 
	struct val_env* ve, time_t now,
        struct ub_packed_rrset_key* rrset, struct ub_packed_rrset_key* dnskey,
        size_t dnskey_idx, size_t sig_idx,
	struct rbtree_t** sortree, int* buf_canon, char** reason)
{
	enum sec_status sec;
	uint8_t* sig;		/* RRSIG rdata */
	size_t siglen;
	size_t rrnum = rrset_get_count(rrset);
	uint8_t* signer;	/* rrsig signer name */
	size_t signer_len;
	unsigned char* sigblock; /* signature rdata field */
	unsigned int sigblock_len;
	uint16_t ktag;		/* DNSKEY key tag */
	unsigned char* key;	/* public key rdata field */
	unsigned int keylen;
	rrset_get_rdata(rrset, rrnum + sig_idx, &sig, &siglen);
	/* min length of rdatalen, fixed rrsig, root signer, 1 byte sig */
	if(siglen < 2+20) {
		verbose(VERB_QUERY, "verify: signature too short");
		*reason = "signature too short";
		return sec_status_bogus;
	}

	if(!(dnskey_get_flags(dnskey, dnskey_idx) & DNSKEY_BIT_ZSK)) {
		verbose(VERB_QUERY, "verify: dnskey without ZSK flag");
		*reason = "dnskey without ZSK flag";
		return sec_status_bogus; 
	}

	if(dnskey_get_protocol(dnskey, dnskey_idx) != LDNS_DNSSEC_KEYPROTO) { 
		/* RFC 4034 says DNSKEY PROTOCOL MUST be 3 */
		verbose(VERB_QUERY, "verify: dnskey has wrong key protocol");
		*reason = "dnskey has wrong protocolnumber";
		return sec_status_bogus;
	}

	/* verify as many fields in rrsig as possible */
	signer = sig+2+18;
	signer_len = dname_valid(signer, siglen-2-18);
	if(!signer_len) {
		verbose(VERB_QUERY, "verify: malformed signer name");
		*reason = "signer name malformed";
		return sec_status_bogus; /* signer name invalid */
	}
	if(!dname_subdomain_c(rrset->rk.dname, signer)) {
		verbose(VERB_QUERY, "verify: signer name is off-tree");
		*reason = "signer name off-tree";
		return sec_status_bogus; /* signer name offtree */
	}
	sigblock = (unsigned char*)signer+signer_len;
	if(siglen < 2+18+signer_len+1) {
		verbose(VERB_QUERY, "verify: too short, no signature data");
		*reason = "signature too short, no signature data";
		return sec_status_bogus; /* sig rdf is < 1 byte */
	}
	sigblock_len = (unsigned int)(siglen - 2 - 18 - signer_len);

	/* verify key dname == sig signer name */
	if(query_dname_compare(signer, dnskey->rk.dname) != 0) {
		verbose(VERB_QUERY, "verify: wrong key for rrsig");
		log_nametypeclass(VERB_QUERY, "RRSIG signername is", 
			signer, 0, 0);
		log_nametypeclass(VERB_QUERY, "the key name is", 
			dnskey->rk.dname, 0, 0);
		*reason = "signer name mismatches key name";
		return sec_status_bogus;
	}

	/* verify covered type */
	/* memcmp works because type is in network format for rrset */
	if(memcmp(sig+2, &rrset->rk.type, 2) != 0) {
		verbose(VERB_QUERY, "verify: wrong type covered");
		*reason = "signature covers wrong type";
		return sec_status_bogus;
	}
	/* verify keytag and sig algo (possibly again) */
	if((int)sig[2+2] != dnskey_get_algo(dnskey, dnskey_idx)) {
		verbose(VERB_QUERY, "verify: wrong algorithm");
		*reason = "signature has wrong algorithm";
		return sec_status_bogus;
	}
	ktag = htons(dnskey_calc_keytag(dnskey, dnskey_idx));
	if(memcmp(sig+2+16, &ktag, 2) != 0) {
		verbose(VERB_QUERY, "verify: wrong keytag");
		*reason = "signature has wrong keytag";
		return sec_status_bogus;
	}

	/* verify labels is in a valid range */
	if((int)sig[2+3] > dname_signame_label_count(rrset->rk.dname)) {
		verbose(VERB_QUERY, "verify: labelcount out of range");
		*reason = "signature labelcount out of range";
		return sec_status_bogus;
	}

	/* original ttl, always ok */

	if(!*buf_canon) {
		/* create rrset canonical format in buffer, ready for 
		 * signature */
		if(!rrset_canonical(region, buf, rrset, sig+2, 
			18 + signer_len, sortree)) {
			log_err("verify: failed due to alloc error");
			return sec_status_unchecked;
		}
		*buf_canon = 1;
	}

	/* check that dnskey is available */
	dnskey_get_pubkey(dnskey, dnskey_idx, &key, &keylen);
	if(!key) {
		verbose(VERB_QUERY, "verify: short DNSKEY RR");
		return sec_status_unchecked;
	}

	/* verify */
	sec = verify_canonrrset(buf, (int)sig[2+2],
		sigblock, sigblock_len, key, keylen, reason);
	
	if(sec == sec_status_secure) {
		/* check if TTL is too high - reduce if so */
		adjust_ttl(ve, now, rrset, sig+2+4, sig+2+8, sig+2+12);

		/* verify inception, expiration dates 
		 * Do this last so that if you ignore expired-sigs the
		 * rest is sure to be OK. */
		if(!check_dates(ve, now, sig+2+8, sig+2+12, reason)) {
			return sec_status_bogus;
		}
	}

	return sec;
}