Пример #1
0
/** parse a query line to a packet into buffer */
static int
qlist_parse_line(sldns_buffer* buf, char* p)
{
	char nm[1024], cl[1024], tp[1024], fl[1024];
	int r; 
	int rec = 1, edns = 0;
	struct query_info qinfo;
	nm[0] = 0; cl[0] = 0; tp[0] = 0; fl[0] = 0;
	r = sscanf(p, " %1023s %1023s %1023s %1023s", nm, cl, tp, fl);
	if(r != 3 && r != 4)
		return 0;
	/*printf("nm='%s', cl='%s', tp='%s', fl='%s'\n", nm, cl, tp, fl);*/
	if(strcmp(tp, "IN") == 0 || strcmp(tp, "CH") == 0) {
		qinfo.qtype = sldns_get_rr_type_by_name(cl);
		qinfo.qclass = sldns_get_rr_class_by_name(tp);
	} else {
		qinfo.qtype = sldns_get_rr_type_by_name(tp);
		qinfo.qclass = sldns_get_rr_class_by_name(cl);
	}
	if(fl[0] == '+') rec = 1;
	else if(fl[0] == '-') rec = 0;
	else if(fl[0] == 'E') edns = 1;
	if((fl[0] == '+' || fl[0] == '-') && fl[1] == 'E')
		edns = 1;
	qinfo.qname = sldns_str2wire_dname(nm, &qinfo.qname_len);
	if(!qinfo.qname)
		return 0;
	qinfo_query_encode(buf, &qinfo);
	sldns_buffer_write_u16_at(buf, 0, 0); /* zero ID */
	if(rec) LDNS_RD_SET(sldns_buffer_begin(buf));
	if(edns) {
		struct edns_data ed;
		memset(&ed, 0, sizeof(ed));
		ed.edns_present = 1;
		ed.udp_size = EDNS_ADVERTISED_SIZE;
		/* Set DO bit in all EDNS datagrams ... */
		ed.bits = EDNS_DO;
		attach_edns_record(buf, &ed);
	}
	free(qinfo.qname);
	return 1;
}
Пример #2
0
/**
 * Read a BIND9 like file with trust anchors in named.conf format.
 * @param anchors: anchor storage.
 * @param buffer: parsing buffer.
 * @param fname: string.
 * @return false on error.
 */
static int
anchor_read_bind_file(struct val_anchors* anchors, sldns_buffer* buffer,
	const char* fname)
{
	int line_nr = 1;
	FILE* in = fopen(fname, "r");
	int rdlen = 0;
	if(!in) {
		log_err("error opening file %s: %s", fname, strerror(errno));
		return 0;
	}
	verbose(VERB_QUERY, "reading in bind-compat-mode: '%s'", fname);
	/* scan for  trusted-keys  keyword, ignore everything else */
	sldns_buffer_clear(buffer);
	while((rdlen=readkeyword_bindfile(in, buffer, &line_nr, 1)) != 0) {
		if(rdlen != 12 || strncmp((char*)sldns_buffer_begin(buffer),
			"trusted-keys", 12) != 0) {
			sldns_buffer_clear(buffer);
			/* ignore everything but trusted-keys */
			continue;
		}
		if(!skip_to_special(in, buffer, &line_nr, '{')) {
			log_err("error in trusted key: \"%s\"", fname);
			fclose(in);
			return 0;
		}
		/* process contents */
		if(!process_bind_contents(anchors, buffer, &line_nr, in)) {
			log_err("error in trusted key: \"%s\"", fname);
			fclose(in);
			return 0;
		}
		if(!skip_to_special(in, buffer, &line_nr, ';')) {
			log_err("error in trusted key: \"%s\"", fname);
			fclose(in);
			return 0;
		}
		sldns_buffer_clear(buffer);
	}
	fclose(in);
	return 1;
}
Пример #3
0
/** test query_dname_tolower */
static void
dname_test_qdtl(sldns_buffer* buff)
{
	unit_show_func("util/data/dname.c", "query_dname_tolower");
	sldns_buffer_write_at(buff, 0, "\012abCDeaBCde\003cOm\000", 16);
	query_dname_tolower(sldns_buffer_begin(buff));
	unit_assert( memcmp(sldns_buffer_begin(buff), 
		"\012abcdeabcde\003com\000", 16) == 0);

	sldns_buffer_write_at(buff, 0, "\001+\012abC{e-ZYXe\003NET\000", 18);
	query_dname_tolower(sldns_buffer_begin(buff));
	unit_assert( memcmp(sldns_buffer_begin(buff), 
		"\001+\012abc{e-zyxe\003net\000", 18) == 0);

	sldns_buffer_write_at(buff, 0, "\000", 1);
	query_dname_tolower(sldns_buffer_begin(buff));
	unit_assert( memcmp(sldns_buffer_begin(buff), "\000", 1) == 0);

	sldns_buffer_write_at(buff, 0, "\002NL\000", 4);
	query_dname_tolower(sldns_buffer_begin(buff));
	unit_assert( memcmp(sldns_buffer_begin(buff), "\002nl\000", 4) == 0);
}
Пример #4
0
int 
query_info_parse(struct query_info* m, sldns_buffer* query)
{
	uint8_t* q = sldns_buffer_begin(query);
	/* minimum size: header + \0 + qtype + qclass */
	if(sldns_buffer_limit(query) < LDNS_HEADER_SIZE + 5)
		return 0;
	if(LDNS_OPCODE_WIRE(q) != LDNS_PACKET_QUERY || 
		LDNS_QDCOUNT(q) != 1 || sldns_buffer_position(query) != 0)
		return 0;
	sldns_buffer_skip(query, LDNS_HEADER_SIZE);
	m->qname = sldns_buffer_current(query);
	if((m->qname_len = query_dname_len(query)) == 0)
		return 0; /* parse error */
	if(sldns_buffer_remaining(query) < 4)
		return 0; /* need qtype, qclass */
	m->qtype = sldns_buffer_read_u16(query);
	m->qclass = sldns_buffer_read_u16(query);
	return 1;
}
Пример #5
0
/** get entry from ringbuffer */
static int
ring_pop(struct ringbuf* r, sldns_buffer* pkt, struct timeval* tv, 
	struct proxy** p)
{
	/* time -- proxy* -- 16bitlen -- message */
	uint16_t len;
	uint8_t* where = NULL;
	size_t done;
	if(r->low == r->high)
		return 0;
	where = r->buf + r->low;
	memmove(tv, where, sizeof(*tv));
	memmove(p, where+sizeof(*tv), sizeof(*p));
	memmove(&len, where+sizeof(*tv)+sizeof(*p), sizeof(len));
	memmove(sldns_buffer_begin(pkt), 
		where+sizeof(*tv)+sizeof(*p)+sizeof(len), len);
	sldns_buffer_set_limit(pkt, (size_t)len);
	done = sizeof(*tv)+sizeof(*p)+sizeof(len)+len;
	/* move lowmark */
	if(r->low < r->high) {
		/* used part in middle */
		log_assert(r->high - r->low >= done);
		r->low += done;
	} else {
		/* unused part in middle */
		log_assert(r->size - r->low >= done);
		r->low += done;
		if(r->size - r->low > sizeof(*tv)+sizeof(*p)) {
			/* see if it is zeroed; means end of buffer */
			struct proxy* pz;
			memmove(&pz, r->buf+r->low+sizeof(*tv), sizeof(pz));
			if(pz == NULL)
				r->low = 0;
		} else r->low = 0;
	}
	if(r->low == r->high) {
		r->low = 0; /* reset if empty */
		r->high = 0;
	}
	return 1;
}
Пример #6
0
struct trust_anchor*
anchor_store_str(struct val_anchors* anchors, sldns_buffer* buffer,
	const char* str)
{
	struct trust_anchor* ta;
	uint8_t* rr = sldns_buffer_begin(buffer);
	size_t len = sldns_buffer_capacity(buffer), dname_len = 0;
	int status = sldns_str2wire_rr_buf(str, rr, &len, &dname_len,
		0, NULL, 0, NULL, 0);
	if(status != 0) {
		log_err("error parsing trust anchor %s: at %d: %s", 
			str, LDNS_WIREPARSE_OFFSET(status),
			sldns_get_errorstr_parse(status));
		return NULL;
	}
	if(!(ta=anchor_store_new_rr(anchors, rr, len, dname_len))) {
		log_err("out of memory");
		return NULL;
	}
	return ta;
}
Пример #7
0
/** recv new waiting packets */
static void
service_recv(int s, struct ringbuf* ring, sldns_buffer* pkt, 
	fd_set* rorig, int* max, struct proxy** proxies,
	struct sockaddr_storage* srv_addr, socklen_t srv_len, 
	struct timeval* now, struct timeval* delay, struct timeval* reuse)
{
	int i;
	struct sockaddr_storage from;
	socklen_t from_len;
	ssize_t len;
	struct proxy* p;
	for(i=0; i<TRIES_PER_SELECT; i++) {
		from_len = (socklen_t)sizeof(from);
		len = recvfrom(s, (void*)sldns_buffer_begin(pkt),
			sldns_buffer_capacity(pkt), 0,
			(struct sockaddr*)&from, &from_len);
		if(len < 0) {
#ifndef USE_WINSOCK
			if(errno == EAGAIN || errno == EINTR)
				return;
			fatal_exit("recvfrom: %s", strerror(errno));
#else
			if(WSAGetLastError() == WSAEWOULDBLOCK || 
				WSAGetLastError() == WSAEINPROGRESS)
				return;
			fatal_exit("recvfrom: %s", 
				wsa_strerror(WSAGetLastError()));
#endif
		}
		sldns_buffer_set_limit(pkt, (size_t)len);
		/* find its proxy element */
		p = find_create_proxy(&from, from_len, rorig, max, proxies,
			addr_is_ip6(srv_addr, srv_len), now, reuse);
		if(!p) fatal_exit("error: cannot find or create proxy");
		p->lastuse = *now;
		ring_add(ring, pkt, now, delay, p);
		p->numwait++;
		log_addr(1, "recv from client", &p->addr, p->addr_len);
	}
}
Пример #8
0
/** add result to the bg worker result queue */
static void
add_bg_result(struct libworker* w, struct ctx_query* q, sldns_buffer* pkt, 
	int err, char* reason)
{
	uint8_t* msg = NULL;
	uint32_t len = 0;

	/* serialize and delete unneeded q */
	if(w->is_bg_thread) {
		lock_basic_lock(&w->ctx->cfglock);
		if(reason)
			q->res->why_bogus = strdup(reason);
		if(pkt) {
			q->msg_len = sldns_buffer_remaining(pkt);
			q->msg = memdup(sldns_buffer_begin(pkt), q->msg_len);
			if(!q->msg)
				msg = context_serialize_answer(q, UB_NOMEM, 
				NULL, &len);
			else	msg = context_serialize_answer(q, err, 
				NULL, &len);
		} else msg = context_serialize_answer(q, err, NULL, &len);
		lock_basic_unlock(&w->ctx->cfglock);
	} else {
		if(reason)
			q->res->why_bogus = strdup(reason);
		msg = context_serialize_answer(q, err, pkt, &len);
		(void)rbtree_delete(&w->ctx->queries, q->node.key);
		w->ctx->num_async--;
		context_query_delete(q);
	}

	if(!msg) {
		log_err("out of memory for async answer");
		return;
	}
	if(!tube_queue_item(w->ctx->rr_pipe, msg, len)) {
		log_err("out of memory for async answer");
		return;
	}
}
Пример #9
0
void 
log_dns_msg(const char* str, struct query_info* qinfo, struct reply_info* rep)
{
	/* not particularly fast but flexible, make wireformat and print */
	sldns_buffer* buf = sldns_buffer_new(65535);
	struct regional* region = regional_create();
	if(!reply_info_encode(qinfo, rep, 0, rep->flags, buf, 0, 
		region, 65535, 1)) {
		log_info("%s: log_dns_msg: out of memory", str);
	} else {
		char* s = sldns_wire2str_pkt(sldns_buffer_begin(buf),
			sldns_buffer_limit(buf));
		if(!s) {
			log_info("%s: log_dns_msg: ldns tostr failed", str);
		} else {
			log_info("%s %s", str, s);
		}
		free(s);
	}
	sldns_buffer_free(buf);
	regional_destroy(region);
}
Пример #10
0
void server_stats_insquery(struct ub_server_stats* stats, struct comm_point* c,
	uint16_t qtype, uint16_t qclass, struct edns_data* edns,
	struct comm_reply* repinfo)
{
	uint16_t flags = sldns_buffer_read_u16_at(c->buffer, 2);
	if(qtype < UB_STATS_QTYPE_NUM)
		stats->qtype[qtype]++;
	else	stats->qtype_big++;
	if(qclass < UB_STATS_QCLASS_NUM)
		stats->qclass[qclass]++;
	else	stats->qclass_big++;
	stats->qopcode[ LDNS_OPCODE_WIRE(sldns_buffer_begin(c->buffer)) ]++;
	if(c->type != comm_udp)
		stats->qtcp++;
	if(repinfo && addr_is_ip6(&repinfo->addr, repinfo->addrlen))
		stats->qipv6++;
	if( (flags&BIT_QR) )
		stats->qbit_QR++;
	if( (flags&BIT_AA) )
		stats->qbit_AA++;
	if( (flags&BIT_TC) )
		stats->qbit_TC++;
	if( (flags&BIT_RD) )
		stats->qbit_RD++;
	if( (flags&BIT_RA) )
		stats->qbit_RA++;
	if( (flags&BIT_Z) )
		stats->qbit_Z++;
	if( (flags&BIT_AD) )
		stats->qbit_AD++;
	if( (flags&BIT_CD) )
		stats->qbit_CD++;
	if(edns->edns_present) {
		stats->qEDNS++;
		if( (edns->bits & EDNS_DO) )
			stats->qEDNS_DO++;
	}
}
Пример #11
0
/** get additional name from rrset RR, return false if no name present */
static int
get_additional_name(struct rrset_parse* rrset, struct rr_parse* rr, 
	uint8_t** nm, size_t* nmlen, sldns_buffer* pkt) 
{
	size_t offset = 0;
	size_t len, oldpos;
	switch(rrset->type) {
		case LDNS_RR_TYPE_MB:
		case LDNS_RR_TYPE_MD:
		case LDNS_RR_TYPE_MF:
		case LDNS_RR_TYPE_NS:
			offset = 0;
			break;
		case LDNS_RR_TYPE_MX:
		case LDNS_RR_TYPE_KX:
			offset = 2;
			break;
		case LDNS_RR_TYPE_SRV:
			offset = 6;
			break;
		case LDNS_RR_TYPE_NAPTR:
			/* TODO: NAPTR not supported, glue stripped off */
			return 0;
		default:
			return 0;
	}
	len = sldns_read_uint16(rr->ttl_data+sizeof(uint32_t));
	if(len < offset+1)
		return 0; /* rdata field too small */
	*nm = rr->ttl_data+sizeof(uint32_t)+sizeof(uint16_t)+offset;
	oldpos = sldns_buffer_position(pkt);
	sldns_buffer_set_position(pkt, (size_t)(*nm - sldns_buffer_begin(pkt)));
	*nmlen = pkt_dname_len(pkt);
	sldns_buffer_set_position(pkt, oldpos);
	if(*nmlen == 0)
		return 0;
	return 1;
}
Пример #12
0
void 
comm_point_send_reply(struct comm_reply* repinfo)
{
	struct replay_answer* ans = (struct replay_answer*)calloc(1,
		sizeof(struct replay_answer));
	struct replay_runtime* runtime = (struct replay_runtime*)repinfo->c->ev;
	log_info("testbound: comm_point_send_reply fake");
	/* dump it into the todo list */
	log_assert(ans);
	memcpy(&ans->repinfo, repinfo, sizeof(struct comm_reply));
	ans->next = NULL;
	if(runtime->answer_last)
		runtime->answer_last->next = ans;
	else 	runtime->answer_list = ans;
	runtime->answer_last = ans;

	/* try to parse packet */
	ans->pkt = memdup(sldns_buffer_begin(ans->repinfo.c->buffer),
		sldns_buffer_limit(ans->repinfo.c->buffer));
	ans->pkt_len = sldns_buffer_limit(ans->repinfo.c->buffer);
	if(!ans->pkt) fatal_exit("out of memory");
	log_pkt("reply pkt: ", ans->pkt, ans->pkt_len);
}
Пример #13
0
/**
 * Fill buffer with reply from the entry.
 */
static void
fill_buffer_with_reply(sldns_buffer* buffer, struct entry* entry, uint8_t* q,
	size_t qlen)
{
	uint8_t* c;
	size_t clen;
	log_assert(entry && entry->reply_list);
	sldns_buffer_clear(buffer);
	if(entry->reply_list->reply_from_hex) {
		c = sldns_buffer_begin(entry->reply_list->reply_from_hex);
		clen = sldns_buffer_limit(entry->reply_list->reply_from_hex);
		if(!c) fatal_exit("out of memory");
	} else {
		c = entry->reply_list->reply_pkt;
		clen = entry->reply_list->reply_len;
	}
	if(c) {
		if(q) adjust_packet(entry, &c, &clen, q, qlen);
		sldns_buffer_write(buffer, c, clen);
		if(q) free(c);
	}
	sldns_buffer_flip(buffer);
}
Пример #14
0
/** fillup fg results */
static void
libworker_fillup_fg(struct ctx_query* q, int rcode, sldns_buffer* buf, 
	enum sec_status s, char* why_bogus)
{
	if(why_bogus)
		q->res->why_bogus = strdup(why_bogus);
	if(rcode != 0) {
		q->res->rcode = rcode;
		q->msg_security = s;
		return;
	}

	q->res->rcode = LDNS_RCODE_SERVFAIL;
	q->msg_security = 0;
	q->msg = memdup(sldns_buffer_begin(buf), sldns_buffer_limit(buf));
	q->msg_len = sldns_buffer_limit(buf);
	if(!q->msg) {
		return; /* the error is in the rcode */
	}

	/* canonname and results */
	q->msg_security = s;
	libworker_enter_result(q->res, buf, q->w->env->scratch, s);
}
Пример #15
0
/**
 * Check a canonical sig+rrset and signature against a dnskey
 * @param buf: buffer with data to verify, the first rrsig part and the
 *	canonicalized rrset.
 * @param algo: DNSKEY algorithm.
 * @param sigblock: signature rdata field from RRSIG
 * @param sigblock_len: length of sigblock data.
 * @param key: public key data from DNSKEY RR.
 * @param keylen: length of keydata.
 * @param reason: bogus reason in more detail.
 * @return secure if verification succeeded, bogus on crypto failure,
 *	unchecked on format errors and alloc failures.
 */
enum sec_status
verify_canonrrset(sldns_buffer* buf, int algo, unsigned char* sigblock, 
	unsigned int sigblock_len, unsigned char* key, unsigned int keylen,
	char** reason)
{
	/* uses libNSS */
	/* large enough for the different hashes */
	unsigned char hash[HASH_LENGTH_MAX];
	unsigned char hash2[HASH_LENGTH_MAX*2];
	HASH_HashType htype = 0;
	SECKEYPublicKey* pubkey = NULL;
	SECItem secsig = {siBuffer, sigblock, sigblock_len};
	SECItem sechash = {siBuffer, hash, 0};
	SECStatus res;
	unsigned char* prefix = NULL; /* prefix for hash, RFC3110, RFC5702 */
	size_t prefixlen = 0;
	int err;

	if(!nss_setup_key_digest(algo, &pubkey, &htype, key, keylen,
		&prefix, &prefixlen)) {
		verbose(VERB_QUERY, "verify: failed to setup key");
		*reason = "use of key for crypto failed";
		SECKEY_DestroyPublicKey(pubkey);
		return sec_status_bogus;
	}

#if defined(USE_DSA) && defined(USE_SHA1)
	/* need to convert DSA, ECDSA signatures? */
	if((algo == LDNS_DSA || algo == LDNS_DSA_NSEC3)) {
		if(sigblock_len == 1+2*SHA1_LENGTH) {
			secsig.data ++;
			secsig.len --;
		} else {
			SECItem* p = DSAU_DecodeDerSig(&secsig);
			if(!p) {
				verbose(VERB_QUERY, "verify: failed DER decode");
				*reason = "signature DER decode failed";
				SECKEY_DestroyPublicKey(pubkey);
				return sec_status_bogus;
			}
			if(SECITEM_CopyItem(pubkey->arena, &secsig, p)) {
				log_err("alloc failure in DER decode");
				SECKEY_DestroyPublicKey(pubkey);
				SECITEM_FreeItem(p, PR_TRUE);
				return sec_status_unchecked;
			}
			SECITEM_FreeItem(p, PR_TRUE);
		}
	}
#endif /* USE_DSA */

	/* do the signature cryptography work */
	/* hash the data */
	sechash.len = HASH_ResultLen(htype);
	if(sechash.len > sizeof(hash)) {
		verbose(VERB_QUERY, "verify: hash too large for buffer");
		SECKEY_DestroyPublicKey(pubkey);
		return sec_status_unchecked;
	}
	if(HASH_HashBuf(htype, hash, (unsigned char*)sldns_buffer_begin(buf),
		(unsigned int)sldns_buffer_limit(buf)) != SECSuccess) {
		verbose(VERB_QUERY, "verify: HASH_HashBuf failed");
		SECKEY_DestroyPublicKey(pubkey);
		return sec_status_unchecked;
	}
	if(prefix) {
		int hashlen = sechash.len;
		if(prefixlen+hashlen > sizeof(hash2)) {
			verbose(VERB_QUERY, "verify: hashprefix too large");
			SECKEY_DestroyPublicKey(pubkey);
			return sec_status_unchecked;
		}
		sechash.data = hash2;
		sechash.len = prefixlen+hashlen;
		memcpy(sechash.data, prefix, prefixlen);
		memmove(sechash.data+prefixlen, hash, hashlen);
	}

	/* verify the signature */
	res = PK11_Verify(pubkey, &secsig, &sechash, NULL /*wincx*/);
	SECKEY_DestroyPublicKey(pubkey);

	if(res == SECSuccess) {
		return sec_status_secure;
	}
	err = PORT_GetError();
	if(err != SEC_ERROR_BAD_SIGNATURE) {
		/* failed to verify */
		verbose(VERB_QUERY, "verify: PK11_Verify failed: %s",
			PORT_ErrorToString(err));
		/* if it is not supported, like ECC is removed, we get,
		 * SEC_ERROR_NO_MODULE */
		if(err == SEC_ERROR_NO_MODULE)
			return sec_status_unchecked;
		/* but other errors are commonly returned
		 * for a bad signature from NSS.  Thus we return bogus,
		 * not unchecked */
		*reason = "signature crypto failed";
		return sec_status_bogus;
	}
	verbose(VERB_QUERY, "verify: signature mismatch: %s",
		PORT_ErrorToString(err));
	*reason = "signature crypto failed";
	return sec_status_bogus;
}
Пример #16
0
/** load a msg entry */
static int
load_msg(SSL* ssl, sldns_buffer* buf, struct worker* worker)
{
	struct regional* region = worker->scratchpad;
	struct query_info qinf;
	struct reply_info rep;
	char* s = (char*)sldns_buffer_begin(buf);
	unsigned int flags, qdcount, security, an, ns, ar;
	long long ttl;
	size_t i;
	int go_on = 1;

	regional_free_all(region);

	if(strncmp(s, "msg ", 4) != 0) {
		log_warn("error expected msg but got %s", s);
		return 0;
	}
	s += 4;
	s = load_qinfo(s, &qinf, region);
	if(!s) {
		return 0;
	}

	/* read remainder of line */
	if(sscanf(s, " %u %u " ARG_LL "d %u %u %u %u", &flags, &qdcount, &ttl, 
		&security, &an, &ns, &ar) != 7) {
		log_warn("error cannot parse numbers: %s", s);
		return 0;
	}
	rep.flags = (uint16_t)flags;
	rep.qdcount = (uint16_t)qdcount;
	rep.ttl = (time_t)ttl;
	rep.prefetch_ttl = PREFETCH_TTL_CALC(rep.ttl);
	rep.security = (enum sec_status)security;
	if(an > RR_COUNT_MAX || ns > RR_COUNT_MAX || ar > RR_COUNT_MAX) {
		log_warn("error too many rrsets");
		return 0; /* protect against integer overflow in alloc */
	}
	rep.an_numrrsets = (size_t)an;
	rep.ns_numrrsets = (size_t)ns;
	rep.ar_numrrsets = (size_t)ar;
	rep.rrset_count = (size_t)an+(size_t)ns+(size_t)ar;
	rep.rrsets = (struct ub_packed_rrset_key**)regional_alloc_zero(
		region, sizeof(struct ub_packed_rrset_key*)*rep.rrset_count);

	/* fill repinfo with references */
	for(i=0; i<rep.rrset_count; i++) {
		if(!load_ref(ssl, buf, worker, region, &rep.rrsets[i], 
			&go_on)) {
			return 0;
		}
	}

	if(!go_on) 
		return 1; /* skip this one, not all references satisfied */

	if(!dns_cache_store(&worker->env, &qinf, &rep, 0, 0, 0, NULL, flags)) {
		log_warn("error out of memory");
		return 0;
	}
	return 1;
}
Пример #17
0
/** load an rrset entry */
static int
load_rrset(SSL* ssl, sldns_buffer* buf, struct worker* worker)
{
	char* s = (char*)sldns_buffer_begin(buf);
	struct regional* region = worker->scratchpad;
	struct ub_packed_rrset_key* rk;
	struct packed_rrset_data* d;
	unsigned int rr_count, rrsig_count, trust, security;
	long long ttl;
	unsigned int i;
	int go_on = 1;
	regional_free_all(region);

	rk = (struct ub_packed_rrset_key*)regional_alloc_zero(region, 
		sizeof(*rk));
	d = (struct packed_rrset_data*)regional_alloc_zero(region, sizeof(*d));
	if(!rk || !d) {
		log_warn("error out of memory");
		return 0;
	}

	if(strncmp(s, ";rrset", 6) != 0) {
		log_warn("error expected ';rrset' but got %s", s);
		return 0;
	}
	s += 6;
	if(strncmp(s, " nsec_apex", 10) == 0) {
		s += 10;
		rk->rk.flags |= PACKED_RRSET_NSEC_AT_APEX;
	}
	if(sscanf(s, " " ARG_LL "d %u %u %u %u", &ttl, &rr_count, &rrsig_count,
		&trust, &security) != 5) {
		log_warn("error bad rrset spec %s", s);
		return 0;
	}
	if(rr_count == 0 && rrsig_count == 0) {
		log_warn("bad rrset without contents");
		return 0;
	}
	if(rr_count > RR_COUNT_MAX || rrsig_count > RR_COUNT_MAX) {
		log_warn("bad rrset with too many rrs");
		return 0;
	}
	d->count = (size_t)rr_count;
	d->rrsig_count = (size_t)rrsig_count;
	d->security = (enum sec_status)security;
	d->trust = (enum rrset_trust)trust;
	d->ttl = (time_t)ttl + *worker->env.now;

	d->rr_len = regional_alloc_zero(region, 
		sizeof(size_t)*(d->count+d->rrsig_count));
	d->rr_ttl = regional_alloc_zero(region, 
		sizeof(time_t)*(d->count+d->rrsig_count));
	d->rr_data = regional_alloc_zero(region, 
		sizeof(uint8_t*)*(d->count+d->rrsig_count));
	if(!d->rr_len || !d->rr_ttl || !d->rr_data) {
		log_warn("error out of memory");
		return 0;
	}
	
	/* read the rr's themselves */
	for(i=0; i<rr_count; i++) {
		if(!load_rr(ssl, buf, region, rk, d, i, 0, 
			&go_on, *worker->env.now)) {
			log_warn("could not read rr %u", i);
			return 0;
		}
	}
	for(i=0; i<rrsig_count; i++) {
		if(!load_rr(ssl, buf, region, rk, d, i+rr_count, 1, 
			&go_on, *worker->env.now)) {
			log_warn("could not read rrsig %u", i);
			return 0;
		}
	}
	if(!go_on) {
		/* skip this entry */
		return 1;
	}

	return move_into_cache(rk, d, worker);
}
Пример #18
0
/** check fixed text on line */
static int
read_fixed(SSL* ssl, sldns_buffer* buf, const char* str)
{
	if(!ssl_read_buf(ssl, buf)) return 0;
	return (strcmp((char*)sldns_buffer_begin(buf), str) == 0);
}
Пример #19
0
/** read a line from ssl into buffer */
static int
ssl_read_buf(SSL* ssl, sldns_buffer* buf)
{
	return ssl_read_line(ssl, (char*)sldns_buffer_begin(buf), 
		sldns_buffer_capacity(buf));
}
Пример #20
0
int 
worker_handle_request(struct comm_point* c, void* arg, int error,
	struct comm_reply* repinfo)
{
	struct worker* worker = (struct worker*)arg;
	int ret;
	hashvalue_t h;
	struct lruhash_entry* e;
	struct query_info qinfo;
	struct edns_data edns;
	enum acl_access acl;
	int rc = 0;

	if(error != NETEVENT_NOERROR) {
		/* some bad tcp query DNS formats give these error calls */
		verbose(VERB_ALGO, "handle request called with err=%d", error);
		return 0;
	}
#ifdef USE_DNSTAP
	if(worker->dtenv.log_client_query_messages)
		dt_msg_send_client_query(&worker->dtenv, &repinfo->addr, c->type,
			c->buffer);
#endif
	acl = acl_list_lookup(worker->daemon->acl, &repinfo->addr, 
		repinfo->addrlen);
	if((ret=deny_refuse_all(c, acl, worker, repinfo)) != -1)
	{
		if(ret == 1)
			goto send_reply;
		return ret;
	}
	if((ret=worker_check_request(c->buffer, worker)) != 0) {
		verbose(VERB_ALGO, "worker check request: bad query.");
		log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen);
		if(ret != -1) {
			LDNS_QR_SET(sldns_buffer_begin(c->buffer));
			LDNS_RCODE_SET(sldns_buffer_begin(c->buffer), ret);
			return 1;
		}
		comm_point_drop_reply(repinfo);
		return 0;
	}
	worker->stats.num_queries++;
	/* see if query is in the cache */
	if(!query_info_parse(&qinfo, c->buffer)) {
		verbose(VERB_ALGO, "worker parse request: formerror.");
		log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen);
		if(worker_err_ratelimit(worker, LDNS_RCODE_FORMERR) == -1) {
			comm_point_drop_reply(repinfo);
			return 0;
		}
		sldns_buffer_rewind(c->buffer);
		LDNS_QR_SET(sldns_buffer_begin(c->buffer));
		LDNS_RCODE_SET(sldns_buffer_begin(c->buffer), 
			LDNS_RCODE_FORMERR);
		server_stats_insrcode(&worker->stats, c->buffer);
		goto send_reply;
	}
	if(worker->env.cfg->log_queries) {
		char ip[128];
		addr_to_str(&repinfo->addr, repinfo->addrlen, ip, sizeof(ip));
		log_nametypeclass(0, ip, qinfo.qname, qinfo.qtype, qinfo.qclass);
	}
	if(qinfo.qtype == LDNS_RR_TYPE_AXFR || 
		qinfo.qtype == LDNS_RR_TYPE_IXFR) {
		verbose(VERB_ALGO, "worker request: refused zone transfer.");
		log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen);
		sldns_buffer_rewind(c->buffer);
		LDNS_QR_SET(sldns_buffer_begin(c->buffer));
		LDNS_RCODE_SET(sldns_buffer_begin(c->buffer), 
			LDNS_RCODE_REFUSED);
		if(worker->stats.extended) {
			worker->stats.qtype[qinfo.qtype]++;
			server_stats_insrcode(&worker->stats, c->buffer);
		}
		goto send_reply;
	}
	if((ret=parse_edns_from_pkt(c->buffer, &edns, worker->scratchpad)) != 0) {
		struct edns_data reply_edns;
		verbose(VERB_ALGO, "worker parse edns: formerror.");
		log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen);
		memset(&reply_edns, 0, sizeof(reply_edns));
		reply_edns.edns_present = 1;
		reply_edns.udp_size = EDNS_ADVERTISED_SIZE;
		LDNS_RCODE_SET(sldns_buffer_begin(c->buffer), ret);
		error_encode(c->buffer, ret, &qinfo,
			*(uint16_t*)(void *)sldns_buffer_begin(c->buffer),
			sldns_buffer_read_u16_at(c->buffer, 2), &reply_edns);
		regional_free_all(worker->scratchpad);
		server_stats_insrcode(&worker->stats, c->buffer);
		goto send_reply;
	}
	if(edns.edns_present && edns.edns_version != 0) {
		edns.ext_rcode = (uint8_t)(EDNS_RCODE_BADVERS>>4);
		edns.edns_version = EDNS_ADVERTISED_VERSION;
		edns.udp_size = EDNS_ADVERTISED_SIZE;
		edns.bits &= EDNS_DO;
		edns.opt_list = NULL;
		verbose(VERB_ALGO, "query with bad edns version.");
		log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen);
		error_encode(c->buffer, EDNS_RCODE_BADVERS&0xf, &qinfo,
			*(uint16_t*)(void *)sldns_buffer_begin(c->buffer),
			sldns_buffer_read_u16_at(c->buffer, 2), NULL);
		attach_edns_record(c->buffer, &edns);
		regional_free_all(worker->scratchpad);
		goto send_reply;
	}
Пример #21
0
struct serviced_query* outnet_serviced_query(struct outside_network* outnet,
        uint8_t* qname, size_t qnamelen, uint16_t qtype, uint16_t qclass,
	uint16_t flags, int dnssec, int ATTR_UNUSED(want_dnssec),
	int ATTR_UNUSED(tcp_upstream), int ATTR_UNUSED(ssl_upstream),
	struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* zone,
	size_t zonelen, comm_point_callback_t* callback, void* callback_arg,
	sldns_buffer* ATTR_UNUSED(buff))
{
	struct replay_runtime* runtime = (struct replay_runtime*)outnet->base;
	struct fake_pending* pend = (struct fake_pending*)calloc(1,
		sizeof(struct fake_pending));
	char z[256];
	log_assert(pend);
	log_nametypeclass(VERB_OPS, "pending serviced query", 
		qname, qtype, qclass);
	dname_str(zone, z);
	verbose(VERB_OPS, "pending serviced query zone %s flags%s%s%s%s", 
		z, (flags&BIT_RD)?" RD":"", (flags&BIT_CD)?" CD":"",
		(flags&~(BIT_RD|BIT_CD))?" MORE":"", (dnssec)?" DO":"");

	/* create packet with EDNS */
	pend->buffer = sldns_buffer_new(512);
	log_assert(pend->buffer);
	sldns_buffer_write_u16(pend->buffer, 0); /* id */
	sldns_buffer_write_u16(pend->buffer, flags);
	sldns_buffer_write_u16(pend->buffer, 1); /* qdcount */
	sldns_buffer_write_u16(pend->buffer, 0); /* ancount */
	sldns_buffer_write_u16(pend->buffer, 0); /* nscount */
	sldns_buffer_write_u16(pend->buffer, 0); /* arcount */
	sldns_buffer_write(pend->buffer, qname, qnamelen);
	sldns_buffer_write_u16(pend->buffer, qtype);
	sldns_buffer_write_u16(pend->buffer, qclass);
	sldns_buffer_flip(pend->buffer);
	if(1) {
		/* add edns */
		struct edns_data edns;
		edns.edns_present = 1;
		edns.ext_rcode = 0;
		edns.edns_version = EDNS_ADVERTISED_VERSION;
		edns.udp_size = EDNS_ADVERTISED_SIZE;
		edns.bits = 0;
		if(dnssec)
			edns.bits = EDNS_DO;
		attach_edns_record(pend->buffer, &edns);
	}
	memcpy(&pend->addr, addr, addrlen);
	pend->addrlen = addrlen;
	pend->zone = memdup(zone, zonelen);
	pend->zonelen = zonelen;
	pend->qtype = (int)qtype;
	log_assert(pend->zone);
	pend->callback = callback;
	pend->cb_arg = callback_arg;
	pend->timeout = UDP_AUTH_QUERY_TIMEOUT;
	pend->transport = transport_udp; /* pretend UDP */
	pend->pkt = NULL;
	pend->runtime = runtime;
	pend->serviced = 1;
	pend->pkt_len = sldns_buffer_limit(pend->buffer);
	pend->pkt = memdup(sldns_buffer_begin(pend->buffer), pend->pkt_len);
	if(!pend->pkt) fatal_exit("out of memory");
	/*log_pkt("pending serviced query: ", pend->pkt, pend->pkt_len);*/

	/* see if it matches the current moment */
	if(runtime->now && runtime->now->evt_type == repevt_back_query &&
		(runtime->now->addrlen == 0 || sockaddr_cmp(
			&runtime->now->addr, runtime->now->addrlen,
			&pend->addr, pend->addrlen) == 0) &&
		find_match(runtime->now->match, pend->pkt, pend->pkt_len,
			pend->transport)) {
		log_info("testbound: matched pending to event. "
			"advance time between events.");
		log_info("testbound: do STEP %d %s", runtime->now->time_step,
			repevt_string(runtime->now->evt_type));
		advance_moment(runtime);
		/* still create the pending, because we need it to callback */
	} 
	log_info("testbound: created fake pending");
	/* add to list */
	pend->next = runtime->pending_list;
	runtime->pending_list = pend;
	return (struct serviced_query*)pend;
}
Пример #22
0
/** see if buffers contain the same packet */
static int
test_buffers(sldns_buffer* pkt, sldns_buffer* out)
{
	/* check binary same */
	if(sldns_buffer_limit(pkt) == sldns_buffer_limit(out) &&
		memcmp(sldns_buffer_begin(pkt), sldns_buffer_begin(out),
			sldns_buffer_limit(pkt)) == 0) {
		if(vbmp) printf("binary the same (length=%u)\n",
				(unsigned)sldns_buffer_limit(pkt));
		return 1;
	}

	if(vbmp) {
		size_t sz = 16;
		size_t count;
		size_t lim = sldns_buffer_limit(out);
		if(sldns_buffer_limit(pkt) < lim)
			lim = sldns_buffer_limit(pkt);
		for(count=0; count<lim; count+=sz) {
			size_t rem = sz;
			if(lim-count < sz) rem = lim-count;
			if(memcmp(sldns_buffer_at(pkt, count), 
				sldns_buffer_at(out, count), rem) == 0) {
				log_info("same %d %d", (int)count, (int)rem);
				log_hex("same: ", sldns_buffer_at(pkt, count),
					rem);
			} else {
				log_info("diff %d %d", (int)count, (int)rem);
				log_hex("difp: ", sldns_buffer_at(pkt, count),
					rem);
				log_hex("difo: ", sldns_buffer_at(out, count),
					rem);
			}
		}
	}

	/* check if it 'means the same' */
	if(vbmp) {
		char* s1, *s2;
		log_buf(0, "orig in hex", pkt);
		log_buf(0, "unbound out in hex", out);
		printf("\npacket from unbound (%d):\n", 
			(int)sldns_buffer_limit(out));
		s1 = sldns_wire2str_pkt(sldns_buffer_begin(out),
			sldns_buffer_limit(out));
		printf("%s\n", s1?s1:"null");
		free(s1);

		printf("\npacket original (%d):\n", 
			(int)sldns_buffer_limit(pkt));
		s2 = sldns_wire2str_pkt(sldns_buffer_begin(pkt),
			sldns_buffer_limit(pkt));
		printf("%s\n", s2?s2:"null");
		free(s2);
		printf("\n");
	}
	/* if it had two EDNS sections, skip comparison */
	if(1) {
		char* s = sldns_wire2str_pkt(sldns_buffer_begin(pkt),
			sldns_buffer_limit(pkt));
		char* e1 = strstr(s, "; EDNS:");
		if(e1 && strstr(e1+4, "; EDNS:")) {
			free(s);
			return 0;
		}
		free(s);
	}
	/* compare packets */
	unit_assert(match_all(sldns_buffer_begin(pkt), sldns_buffer_limit(pkt),
		sldns_buffer_begin(out), sldns_buffer_limit(out), 1,
		matches_nolocation));
	return 0;
}
Пример #23
0
/** test a packet */
static void
testpkt(sldns_buffer* pkt, struct alloc_cache* alloc, sldns_buffer* out, 
	const char* hex)
{
	struct query_info qi;
	struct reply_info* rep = 0;
	int ret;
	uint16_t id;
	uint16_t flags;
	uint32_t timenow = 0;
	struct regional* region = regional_create();
	struct edns_data edns;

	hex_to_buf(pkt, hex);
	memmove(&id, sldns_buffer_begin(pkt), sizeof(id));
	if(sldns_buffer_limit(pkt) < 2)
		flags = 0;
	else	memmove(&flags, sldns_buffer_at(pkt, 2), sizeof(flags));
	flags = ntohs(flags);
	ret = reply_info_parse(pkt, alloc, &qi, &rep, region, &edns);
	if(ret != 0) {
		char rbuf[16];
		sldns_wire2str_rcode_buf(ret, rbuf, sizeof(rbuf));
		if(vbmp) printf("parse code %d: %s\n", ret, rbuf);
		if(ret == LDNS_RCODE_FORMERR) {
			unit_assert(!check_formerr_gone);
			checkformerr(pkt);
		}
		unit_assert(ret != LDNS_RCODE_SERVFAIL);
	} else if(!check_formerr_gone) {
		const size_t lim = 512;
		ret = reply_info_encode(&qi, rep, id, flags, out, timenow,
			region, 65535, (int)(edns.bits & EDNS_DO) );
		unit_assert(ret != 0); /* udp packets should fit */
		attach_edns_record(out, &edns);
		if(vbmp) printf("inlen %u outlen %u\n", 
			(unsigned)sldns_buffer_limit(pkt),
			(unsigned)sldns_buffer_limit(out));
		if(!check_nosameness)
			test_buffers(pkt, out);
		if(check_rrsigs)
			check_the_rrsigs(&qi, rep);

		if(sldns_buffer_limit(out) > lim) {
			ret = reply_info_encode(&qi, rep, id, flags, out, 
				timenow, region, 
				lim - calc_edns_field_size(&edns),
				(int)(edns.bits & EDNS_DO));
			unit_assert(ret != 0); /* should fit, but with TC */
			attach_edns_record(out, &edns);
			if( LDNS_QDCOUNT(sldns_buffer_begin(out)) !=
				LDNS_QDCOUNT(sldns_buffer_begin(pkt)) ||
				LDNS_ANCOUNT(sldns_buffer_begin(out)) !=
				LDNS_ANCOUNT(sldns_buffer_begin(pkt)) ||
				LDNS_NSCOUNT(sldns_buffer_begin(out)) !=
				LDNS_NSCOUNT(sldns_buffer_begin(pkt)))
				unit_assert(
				LDNS_TC_WIRE(sldns_buffer_begin(out)));
				/* must set TC bit if shortened */
			unit_assert(sldns_buffer_limit(out) <= lim);
		}
	} 

	query_info_clear(&qi);
	reply_info_parsedelete(rep, alloc);
	regional_destroy(region);
}
Пример #24
0
static char *
_verify_nettle_ecdsa(sldns_buffer* buf, unsigned int digest_size, unsigned char* sigblock,
	unsigned int sigblock_len, unsigned char* key, unsigned int keylen)
{
	int res = 0;
	struct ecc_point pubkey;
	struct dsa_signature signature;

	/* Always matched strength, as per RFC 6605 sec. 1 */
	if (sigblock_len != 2*digest_size || keylen != 2*digest_size) {
		return "wrong ECDSA signature length";
	}

	/* Parse ECDSA signature as per RFC 6605 sec. 4 */
	nettle_dsa_signature_init(&signature);
	switch (digest_size) {
		case SHA256_DIGEST_SIZE:
		{
			uint8_t digest[SHA256_DIGEST_SIZE];
			mpz_t x, y;
			nettle_ecc_point_init(&pubkey, &nettle_secp_256r1);
			nettle_mpz_init_set_str_256_u(x, SHA256_DIGEST_SIZE, key);
			nettle_mpz_init_set_str_256_u(y, SHA256_DIGEST_SIZE, key+SHA256_DIGEST_SIZE);
			nettle_mpz_set_str_256_u(signature.r, SHA256_DIGEST_SIZE, sigblock);
			nettle_mpz_set_str_256_u(signature.s, SHA256_DIGEST_SIZE, sigblock+SHA256_DIGEST_SIZE);
			res = _digest_nettle(SHA256_DIGEST_SIZE, (unsigned char*)sldns_buffer_begin(buf),
						(unsigned int)sldns_buffer_limit(buf), (unsigned char*)digest);
			res &= nettle_ecc_point_set(&pubkey, x, y);
			res &= nettle_ecdsa_verify (&pubkey, SHA256_DIGEST_SIZE, digest, &signature);
			mpz_clear(x);
			mpz_clear(y);
			break;
		}
		case SHA384_DIGEST_SIZE:
		{
			uint8_t digest[SHA384_DIGEST_SIZE];
			mpz_t x, y;
			nettle_ecc_point_init(&pubkey, &nettle_secp_384r1);
			nettle_mpz_init_set_str_256_u(x, SHA384_DIGEST_SIZE, key);
			nettle_mpz_init_set_str_256_u(y, SHA384_DIGEST_SIZE, key+SHA384_DIGEST_SIZE);
			nettle_mpz_set_str_256_u(signature.r, SHA384_DIGEST_SIZE, sigblock);
			nettle_mpz_set_str_256_u(signature.s, SHA384_DIGEST_SIZE, sigblock+SHA384_DIGEST_SIZE);
			res = _digest_nettle(SHA384_DIGEST_SIZE, (unsigned char*)sldns_buffer_begin(buf),
						(unsigned int)sldns_buffer_limit(buf), (unsigned char*)digest);
			res &= nettle_ecc_point_set(&pubkey, x, y);
			res &= nettle_ecdsa_verify (&pubkey, SHA384_DIGEST_SIZE, digest, &signature);
			mpz_clear(x);
			mpz_clear(y);
			nettle_ecc_point_clear(&pubkey);
			break;
		}
		default:
			return "unknown ECDSA algorithm";
	}

	/* Clear and return */
	nettle_dsa_signature_clear(&signature);
	if (!res)
		return "ECDSA signature verification failed";
	else
		return NULL;
}
Пример #25
0
static char *
_verify_nettle_dsa(sldns_buffer* buf, unsigned char* sigblock,
	unsigned int sigblock_len, unsigned char* key, unsigned int keylen)
{
	uint8_t digest[SHA1_DIGEST_SIZE];
	uint8_t key_t_value;
	int res = 0;
	size_t offset;
	struct dsa_public_key pubkey;
	struct dsa_signature signature;
	unsigned int expected_len;

	/* Extract DSA signature from the record */
	nettle_dsa_signature_init(&signature);
	/* Signature length: 41 bytes - RFC 2536 sec. 3 */
	if(sigblock_len == 41) {
		if(key[0] != sigblock[0])
			return "invalid T value in DSA signature or pubkey";
		nettle_mpz_set_str_256_u(signature.r, 20, sigblock+1);
		nettle_mpz_set_str_256_u(signature.s, 20, sigblock+1+20);
	} else {
		/* DER encoded, decode the ASN1 notated R and S bignums */
		/* SEQUENCE { r INTEGER, s INTEGER } */
		struct asn1_der_iterator i, seq;
		if(asn1_der_iterator_first(&i, sigblock_len,
			(uint8_t*)sigblock) != ASN1_ITERATOR_CONSTRUCTED
			|| i.type != ASN1_SEQUENCE)
			return "malformed DER encoded DSA signature";
		/* decode this element of i using the seq iterator */
		if(asn1_der_decode_constructed(&i, &seq) !=
			ASN1_ITERATOR_PRIMITIVE || seq.type != ASN1_INTEGER)
			return "malformed DER encoded DSA signature";
		if(!asn1_der_get_bignum(&seq, signature.r, 20*8))
			return "malformed DER encoded DSA signature";
		if(asn1_der_iterator_next(&seq) != ASN1_ITERATOR_PRIMITIVE
			|| seq.type != ASN1_INTEGER)
			return "malformed DER encoded DSA signature";
		if(!asn1_der_get_bignum(&seq, signature.s, 20*8))
			return "malformed DER encoded DSA signature";
		if(asn1_der_iterator_next(&i) != ASN1_ITERATOR_END)
			return "malformed DER encoded DSA signature";
	}

	/* Validate T values constraints - RFC 2536 sec. 2 & sec. 3 */
	key_t_value = key[0];
	if (key_t_value > 8) {
		return "invalid T value in DSA pubkey";
	}

	/* Pubkey minimum length: 21 bytes - RFC 2536 sec. 2 */
	if (keylen < 21) {
		return "DSA pubkey too short";
	}

	expected_len =   1 +		/* T */
		        20 +		/* Q */
		       (64 + key_t_value*8) +	/* P */
		       (64 + key_t_value*8) +	/* G */
		       (64 + key_t_value*8);	/* Y */
	if (keylen != expected_len ) {
		return "invalid DSA pubkey length";
	}

	/* Extract DSA pubkey from the record */
	nettle_dsa_public_key_init(&pubkey);
	offset = 1;
	nettle_mpz_set_str_256_u(pubkey.q, 20, key+offset);
	offset += 20;
	nettle_mpz_set_str_256_u(pubkey.p, (64 + key_t_value*8), key+offset);
	offset += (64 + key_t_value*8);
	nettle_mpz_set_str_256_u(pubkey.g, (64 + key_t_value*8), key+offset);
	offset += (64 + key_t_value*8);
	nettle_mpz_set_str_256_u(pubkey.y, (64 + key_t_value*8), key+offset);

	/* Digest content of "buf" and verify its DSA signature in "sigblock"*/
	res = _digest_nettle(SHA1_DIGEST_SIZE, (unsigned char*)sldns_buffer_begin(buf),
						(unsigned int)sldns_buffer_limit(buf), (unsigned char*)digest);
	res &= dsa_sha1_verify_digest(&pubkey, digest, &signature);

	/* Clear and return */
	nettle_dsa_signature_clear(&signature);
	nettle_dsa_public_key_clear(&pubkey);
	if (!res)
		return "DSA signature verification failed";
	else
		return NULL;
}
Пример #26
0
/** check request sanity.
 * @param pkt: the wire packet to examine for sanity.
 * @param worker: parameters for checking.
 * @return error code, 0 OK, or -1 discard.
*/
static int 
worker_check_request(sldns_buffer* pkt, struct worker* worker)
{
	if(sldns_buffer_limit(pkt) < LDNS_HEADER_SIZE) {
		verbose(VERB_QUERY, "request too short, discarded");
		return -1;
	}
	if(sldns_buffer_limit(pkt) > NORMAL_UDP_SIZE && 
		worker->daemon->cfg->harden_large_queries) {
		verbose(VERB_QUERY, "request too large, discarded");
		return -1;
	}
	if(LDNS_QR_WIRE(sldns_buffer_begin(pkt))) {
		verbose(VERB_QUERY, "request has QR bit on, discarded");
		return -1;
	}
	if(LDNS_TC_WIRE(sldns_buffer_begin(pkt))) {
		LDNS_TC_CLR(sldns_buffer_begin(pkt));
		verbose(VERB_QUERY, "request bad, has TC bit on");
		return worker_err_ratelimit(worker, LDNS_RCODE_FORMERR);
	}
	if(LDNS_OPCODE_WIRE(sldns_buffer_begin(pkt)) != LDNS_PACKET_QUERY) {
		verbose(VERB_QUERY, "request unknown opcode %d", 
			LDNS_OPCODE_WIRE(sldns_buffer_begin(pkt)));
		return worker_err_ratelimit(worker, LDNS_RCODE_NOTIMPL);
	}
	if(LDNS_QDCOUNT(sldns_buffer_begin(pkt)) != 1) {
		verbose(VERB_QUERY, "request wrong nr qd=%d", 
			LDNS_QDCOUNT(sldns_buffer_begin(pkt)));
		return worker_err_ratelimit(worker, LDNS_RCODE_FORMERR);
	}
	if(LDNS_ANCOUNT(sldns_buffer_begin(pkt)) != 0) {
		verbose(VERB_QUERY, "request wrong nr an=%d", 
			LDNS_ANCOUNT(sldns_buffer_begin(pkt)));
		return worker_err_ratelimit(worker, LDNS_RCODE_FORMERR);
	}
	if(LDNS_NSCOUNT(sldns_buffer_begin(pkt)) != 0) {
		verbose(VERB_QUERY, "request wrong nr ns=%d", 
			LDNS_NSCOUNT(sldns_buffer_begin(pkt)));
		return worker_err_ratelimit(worker, LDNS_RCODE_FORMERR);
	}
	if(LDNS_ARCOUNT(sldns_buffer_begin(pkt)) > 1) {
		verbose(VERB_QUERY, "request wrong nr ar=%d", 
			LDNS_ARCOUNT(sldns_buffer_begin(pkt)));
		return worker_err_ratelimit(worker, LDNS_RCODE_FORMERR);
	}
	return 0;
}
Пример #27
0
static char *
_verify_nettle_rsa(sldns_buffer* buf, unsigned int digest_size, char* sigblock,
	unsigned int sigblock_len, uint8_t* key, unsigned int keylen)
{
	uint16_t exp_len = 0;
	size_t exp_offset = 0, mod_offset = 0;
	struct rsa_public_key pubkey;
	mpz_t signature;
	int res = 0;

	/* RSA pubkey parsing as per RFC 3110 sec. 2 */
	if( keylen <= 1) {
		return "null RSA key";
	}
	if (key[0] != 0) {
		/* 1-byte length */
		exp_len = key[0];
		exp_offset = 1;
	} else {
		/* 1-byte NUL + 2-bytes exponent length */
		if (keylen < 3) {
			return "incorrect RSA key length";
		}
		exp_len = READ_UINT16(key+1);
		if (exp_len == 0)
			return "null RSA exponent length";
		exp_offset = 3;
	}
	/* Check that we are not over-running input length */
	if (keylen < exp_offset + exp_len + 1) {
		return "RSA key content shorter than expected";
	}
	mod_offset = exp_offset + exp_len;
	nettle_rsa_public_key_init(&pubkey);
	pubkey.size = keylen - mod_offset;
	nettle_mpz_set_str_256_u(pubkey.e, exp_len, &key[exp_offset]);
	nettle_mpz_set_str_256_u(pubkey.n, pubkey.size, &key[mod_offset]);

	/* Digest content of "buf" and verify its RSA signature in "sigblock"*/
	nettle_mpz_init_set_str_256_u(signature, sigblock_len, (uint8_t*)sigblock);
	switch (digest_size) {
		case SHA1_DIGEST_SIZE:
		{
			uint8_t digest[SHA1_DIGEST_SIZE];
			res = _digest_nettle(SHA1_DIGEST_SIZE, (unsigned char*)sldns_buffer_begin(buf),
						(unsigned int)sldns_buffer_limit(buf), (unsigned char*)digest);
			res &= rsa_sha1_verify_digest(&pubkey, digest, signature);
			break;
		}
		case SHA256_DIGEST_SIZE:
		{
			uint8_t digest[SHA256_DIGEST_SIZE];
			res = _digest_nettle(SHA256_DIGEST_SIZE, (unsigned char*)sldns_buffer_begin(buf),
						(unsigned int)sldns_buffer_limit(buf), (unsigned char*)digest);
			res &= rsa_sha256_verify_digest(&pubkey, digest, signature);
			break;
		}
		case SHA512_DIGEST_SIZE:
		{
			uint8_t digest[SHA512_DIGEST_SIZE];
			res = _digest_nettle(SHA512_DIGEST_SIZE, (unsigned char*)sldns_buffer_begin(buf),
						(unsigned int)sldns_buffer_limit(buf), (unsigned char*)digest);
			res &= rsa_sha512_verify_digest(&pubkey, digest, signature);
			break;
		}
		default:
			break;
	}

	/* Clear and return */
	nettle_rsa_public_key_clear(&pubkey);
	mpz_clear(signature);
	if (!res) {
		return "RSA signature verification failed";
	} else {
		return NULL;
	}
}
Пример #28
0
void log_buf(enum verbosity_value level, const char* msg, sldns_buffer* buf)
{
	if(verbosity < level)
		return;
	log_hex_f(level, msg, sldns_buffer_begin(buf), sldns_buffer_limit(buf));
}
Пример #29
0
/**
 * Check a canonical sig+rrset and signature against a dnskey
 * @param buf: buffer with data to verify, the first rrsig part and the
 *	canonicalized rrset.
 * @param algo: DNSKEY algorithm.
 * @param sigblock: signature rdata field from RRSIG
 * @param sigblock_len: length of sigblock data.
 * @param key: public key data from DNSKEY RR.
 * @param keylen: length of keydata.
 * @param reason: bogus reason in more detail.
 * @return secure if verification succeeded, bogus on crypto failure,
 *	unchecked on format errors and alloc failures.
 */
enum sec_status
verify_canonrrset(sldns_buffer* buf, int algo, unsigned char* sigblock, 
	unsigned int sigblock_len, unsigned char* key, unsigned int keylen,
	char** reason)
{
	const EVP_MD *digest_type;
	EVP_MD_CTX* ctx;
	int res, dofree = 0, docrypto_free = 0;
	EVP_PKEY *evp_key = NULL;

#ifndef USE_DSA
	if((algo == LDNS_DSA || algo == LDNS_DSA_NSEC3) &&(fake_dsa||fake_sha1))
		return sec_status_secure;
#endif
#ifndef USE_SHA1
	if(fake_sha1 && (algo == LDNS_DSA || algo == LDNS_DSA_NSEC3 || algo == LDNS_RSASHA1 || algo == LDNS_RSASHA1_NSEC3))
		return sec_status_secure;
#endif
	
	if(!setup_key_digest(algo, &evp_key, &digest_type, key, keylen)) {
		verbose(VERB_QUERY, "verify: failed to setup key");
		*reason = "use of key for crypto failed";
		EVP_PKEY_free(evp_key);
		return sec_status_bogus;
	}
#ifdef USE_DSA
	/* if it is a DSA signature in bind format, convert to DER format */
	if((algo == LDNS_DSA || algo == LDNS_DSA_NSEC3) && 
		sigblock_len == 1+2*SHA_DIGEST_LENGTH) {
		if(!setup_dsa_sig(&sigblock, &sigblock_len)) {
			verbose(VERB_QUERY, "verify: failed to setup DSA sig");
			*reason = "use of key for DSA crypto failed";
			EVP_PKEY_free(evp_key);
			return sec_status_bogus;
		}
		docrypto_free = 1;
	}
#endif
#if defined(USE_ECDSA) && defined(USE_DSA)
	else 
#endif
#ifdef USE_ECDSA
	if(algo == LDNS_ECDSAP256SHA256 || algo == LDNS_ECDSAP384SHA384) {
		/* EVP uses ASN prefix on sig, which is not in the wire data */
		if(!setup_ecdsa_sig(&sigblock, &sigblock_len)) {
			verbose(VERB_QUERY, "verify: failed to setup ECDSA sig");
			*reason = "use of signature for ECDSA crypto failed";
			EVP_PKEY_free(evp_key);
			return sec_status_bogus;
		}
		dofree = 1;
	}
#endif /* USE_ECDSA */

	/* do the signature cryptography work */
#ifdef HAVE_EVP_MD_CTX_NEW
	ctx = EVP_MD_CTX_new();
#else
	ctx = (EVP_MD_CTX*)malloc(sizeof(*ctx));
	if(ctx) EVP_MD_CTX_init(ctx);
#endif
	if(!ctx) {
		log_err("EVP_MD_CTX_new: malloc failure");
		EVP_PKEY_free(evp_key);
		if(dofree) free(sigblock);
		else if(docrypto_free) OPENSSL_free(sigblock);
		return sec_status_unchecked;
	}
#ifndef HAVE_EVP_DIGESTVERIFY
	if(EVP_DigestInit(ctx, digest_type) == 0) {
		verbose(VERB_QUERY, "verify: EVP_DigestInit failed");
#ifdef HAVE_EVP_MD_CTX_NEW
		EVP_MD_CTX_destroy(ctx);
#else
		EVP_MD_CTX_cleanup(ctx);
		free(ctx);
#endif
		EVP_PKEY_free(evp_key);
		if(dofree) free(sigblock);
		else if(docrypto_free) OPENSSL_free(sigblock);
		return sec_status_unchecked;
	}
	if(EVP_DigestUpdate(ctx, (unsigned char*)sldns_buffer_begin(buf), 
		(unsigned int)sldns_buffer_limit(buf)) == 0) {
		verbose(VERB_QUERY, "verify: EVP_DigestUpdate failed");
#ifdef HAVE_EVP_MD_CTX_NEW
		EVP_MD_CTX_destroy(ctx);
#else
		EVP_MD_CTX_cleanup(ctx);
		free(ctx);
#endif
		EVP_PKEY_free(evp_key);
		if(dofree) free(sigblock);
		else if(docrypto_free) OPENSSL_free(sigblock);
		return sec_status_unchecked;
	}

	res = EVP_VerifyFinal(ctx, sigblock, sigblock_len, evp_key);
#else /* HAVE_EVP_DIGESTVERIFY */
	if(EVP_DigestVerifyInit(ctx, NULL, digest_type, NULL, evp_key) == 0) {
		verbose(VERB_QUERY, "verify: EVP_DigestVerifyInit failed");
#ifdef HAVE_EVP_MD_CTX_NEW
		EVP_MD_CTX_destroy(ctx);
#else
		EVP_MD_CTX_cleanup(ctx);
		free(ctx);
#endif
		EVP_PKEY_free(evp_key);
		if(dofree) free(sigblock);
		else if(docrypto_free) OPENSSL_free(sigblock);
		return sec_status_unchecked;
	}
	res = EVP_DigestVerify(ctx, sigblock, sigblock_len,
		(unsigned char*)sldns_buffer_begin(buf),
		sldns_buffer_limit(buf));
#endif
#ifdef HAVE_EVP_MD_CTX_NEW
	EVP_MD_CTX_destroy(ctx);
#else
	EVP_MD_CTX_cleanup(ctx);
	free(ctx);
#endif
	EVP_PKEY_free(evp_key);

	if(dofree) free(sigblock);
	else if(docrypto_free) OPENSSL_free(sigblock);

	if(res == 1) {
		return sec_status_secure;
	} else if(res == 0) {
		verbose(VERB_QUERY, "verify: signature mismatch");
		*reason = "signature crypto failed";
		return sec_status_bogus;
	}

	log_crypto_error("verify:", ERR_get_error());
	return sec_status_unchecked;
}
Пример #30
0
/** 
 * read contents of trusted-keys{ ... ; clauses and insert keys into storage.
 * @param anchors: where to store keys
 * @param buf: buffer to use
 * @param line: line number in file
 * @param in: file to read from.
 * @return 0 on error.
 */
static int
process_bind_contents(struct val_anchors* anchors, sldns_buffer* buf, 
	int* line, FILE* in)
{
	/* loop over contents, collate strings before ; */
	/* contents is (numbered): 0   1    2  3 4   5  6 7 8    */
	/*                           name. 257 3 5 base64 base64 */
	/* quoted value:           0 "111"  0  0 0   0  0 0 0    */
	/* comments value:         1 "000"  1  1  1 "0  0 0 0"  1 */
	int contnum = 0;
	int quoted = 0;
	int comments = 1;
	int rdlen;
	char* str = 0;
	sldns_buffer_clear(buf);
	while((rdlen=readkeyword_bindfile(in, buf, line, comments))) {
		if(rdlen == 1 && sldns_buffer_position(buf) == 1
			&& isspace((unsigned char)*sldns_buffer_begin(buf))) {
			/* starting whitespace is removed */
			sldns_buffer_clear(buf);
			continue;
		} else if(rdlen == 1 && sldns_buffer_current(buf)[-1] == '"') {
			/* remove " from the string */
			if(contnum == 0) {
				quoted = 1;
				comments = 0;
			}
			sldns_buffer_skip(buf, -1);
			if(contnum > 0 && quoted) {
				if(sldns_buffer_remaining(buf) < 8+1) {
					log_err("line %d, too long", *line);
					return 0;
				}
				sldns_buffer_write(buf, " DNSKEY ", 8);
				quoted = 0;
				comments = 1;
			} else if(contnum > 0)
				comments = !comments;
			continue;
		} else if(rdlen == 1 && sldns_buffer_current(buf)[-1] == ';') {

			if(contnum < 5) {
				sldns_buffer_write_u8(buf, 0);
				log_err("line %d, bad key", *line);
				return 0;
			}
			sldns_buffer_skip(buf, -1);
			sldns_buffer_write_u8(buf, 0);
			str = strdup((char*)sldns_buffer_begin(buf));
			if(!str) {
				log_err("line %d, allocation failure", *line);
				return 0;
			}
			if(!anchor_store_str(anchors, buf, str)) {
				log_err("line %d, bad key", *line);
				free(str);
				return 0;
			}
			free(str);
			sldns_buffer_clear(buf);
			contnum = 0;
			quoted = 0;
			comments = 1;
			continue;
		} else if(rdlen == 1 && sldns_buffer_current(buf)[-1] == '}') {
			if(contnum > 0) {
				sldns_buffer_write_u8(buf, 0);
				log_err("line %d, bad key before }", *line);
				return 0;
			}
			return 1;
		} else if(rdlen == 1 && 
			isspace((unsigned char)sldns_buffer_current(buf)[-1])) {
			/* leave whitespace here */
		} else {
			/* not space or whatnot, so actual content */
			contnum ++;
			if(contnum == 1 && !quoted) {
				if(sldns_buffer_remaining(buf) < 8+1) {
					log_err("line %d, too long", *line);
					return 0;
				}	
				sldns_buffer_write(buf, " DNSKEY ", 8);
			}
		}
	}

	log_err("line %d, EOF before }", *line);
	return 0;
}