dnssec.c revision 238104
1/*
2 * dnssec.c
3 * Some DNSSEC helper function are defined here
4 * and tracing is done
5 * (c) 2005 NLnet Labs
6 *
7 * See the file LICENSE for the license
8 *
9 */
10
11#include "drill.h"
12#include <ldns/ldns.h>
13
14/* get rr_type from a server from a server */
15ldns_rr_list *
16get_rr(ldns_resolver *res, ldns_rdf *zname, ldns_rr_type t, ldns_rr_class c)
17{
18	/* query, retrieve, extract and return */
19	ldns_pkt *p;
20	ldns_rr_list *found;
21
22	p = ldns_pkt_new();
23	found = NULL;
24
25	if (ldns_resolver_send(&p, res, zname, t, c, 0) != LDNS_STATUS_OK) {
26		/* oops */
27		return NULL;
28	} else {
29		found = ldns_pkt_rr_list_by_type(p, t, LDNS_SECTION_ANY_NOQUESTION);
30	}
31	return found;
32}
33
34void
35drill_pkt_print(FILE *fd, ldns_resolver *r, ldns_pkt *p)
36{
37	ldns_rr_list *new_nss;
38	ldns_rr_list *hostnames;
39
40	if (verbosity < 5) {
41		return;
42	}
43
44	hostnames = ldns_get_rr_list_name_by_addr(r, ldns_pkt_answerfrom(p), 0, 0);
45
46	new_nss = ldns_pkt_rr_list_by_type(p,
47			LDNS_RR_TYPE_NS, LDNS_SECTION_ANSWER);
48	ldns_rr_list_print(fd, new_nss);
49
50	/* new_nss can be empty.... */
51
52	fprintf(fd, ";; Received %d bytes from %s#%d(",
53			(int) ldns_pkt_size(p),
54			ldns_rdf2str(ldns_pkt_answerfrom(p)),
55			(int) ldns_resolver_port(r));
56	/* if we can resolve this print it, other print the ip again */
57	if (hostnames) {
58		ldns_rdf_print(fd,
59				ldns_rr_rdf(ldns_rr_list_rr(hostnames, 0), 0));
60		ldns_rr_list_deep_free(hostnames);
61	} else {
62		fprintf(fd, "%s", ldns_rdf2str(ldns_pkt_answerfrom(p)));
63	}
64	fprintf(fd, ") in %u ms\n\n", (unsigned int)ldns_pkt_querytime(p));
65}
66
67void
68drill_pkt_print_footer(FILE *fd, ldns_resolver *r, ldns_pkt *p)
69{
70	ldns_rr_list *hostnames;
71
72	if (verbosity < 5) {
73		return;
74	}
75
76	hostnames = ldns_get_rr_list_name_by_addr(r, ldns_pkt_answerfrom(p), 0, 0);
77
78	fprintf(fd, ";; Received %d bytes from %s#%d(",
79			(int) ldns_pkt_size(p),
80			ldns_rdf2str(ldns_pkt_answerfrom(p)),
81			(int) ldns_resolver_port(r));
82	/* if we can resolve this print it, other print the ip again */
83	if (hostnames) {
84		ldns_rdf_print(fd,
85				ldns_rr_rdf(ldns_rr_list_rr(hostnames, 0), 0));
86		ldns_rr_list_deep_free(hostnames);
87	} else {
88		fprintf(fd, "%s", ldns_rdf2str(ldns_pkt_answerfrom(p)));
89	}
90	fprintf(fd, ") in %u ms\n\n", (unsigned int)ldns_pkt_querytime(p));
91}
92/*
93 * generic function to get some RRset from a nameserver
94 * and possible some signatures too (that would be the day...)
95 */
96ldns_pkt_type
97get_dnssec_rr(ldns_pkt *p, ldns_rdf *name, ldns_rr_type t,
98	ldns_rr_list **rrlist, ldns_rr_list **sig)
99{
100	ldns_pkt_type pt = LDNS_PACKET_UNKNOWN;
101	ldns_rr_list *rr = NULL;
102	ldns_rr_list *sigs = NULL;
103	size_t i;
104
105	if (!p) {
106		if (rrlist) {
107			*rrlist = NULL;
108		}
109		return LDNS_PACKET_UNKNOWN;
110	}
111
112	pt = ldns_pkt_reply_type(p);
113	if (name) {
114		rr = ldns_pkt_rr_list_by_name_and_type(p, name, t, LDNS_SECTION_ANSWER);
115		if (!rr) {
116			rr = ldns_pkt_rr_list_by_name_and_type(p, name, t, LDNS_SECTION_AUTHORITY);
117		}
118		sigs = ldns_pkt_rr_list_by_name_and_type(p, name, LDNS_RR_TYPE_RRSIG,
119				LDNS_SECTION_ANSWER);
120		if (!sigs) {
121		sigs = ldns_pkt_rr_list_by_name_and_type(p, name, LDNS_RR_TYPE_RRSIG,
122				LDNS_SECTION_AUTHORITY);
123		}
124	} else {
125               /* A DS-referral - get the DS records if they are there */
126               rr = ldns_pkt_rr_list_by_type(p, t, LDNS_SECTION_AUTHORITY);
127               sigs = ldns_pkt_rr_list_by_type(p, LDNS_RR_TYPE_RRSIG,
128                               LDNS_SECTION_AUTHORITY);
129	}
130	if (sig) {
131		*sig = ldns_rr_list_new();
132		for (i = 0; i < ldns_rr_list_rr_count(sigs); i++) {
133			/* only add the sigs that cover this type */
134			if (ldns_rdf2rr_type(ldns_rr_rrsig_typecovered(ldns_rr_list_rr(sigs, i))) ==
135			    t) {
136			 	ldns_rr_list_push_rr(*sig, ldns_rr_clone(ldns_rr_list_rr(sigs, i)));
137			}
138		}
139	}
140	ldns_rr_list_deep_free(sigs);
141	if (rrlist) {
142		*rrlist = rr;
143	}
144
145	if (pt == LDNS_PACKET_NXDOMAIN || pt == LDNS_PACKET_NODATA) {
146		return pt;
147	} else {
148		return LDNS_PACKET_ANSWER;
149	}
150}
151
152
153ldns_status
154ldns_verify_denial(ldns_pkt *pkt, ldns_rdf *name, ldns_rr_type type, ldns_rr_list **nsec_rrs, ldns_rr_list **nsec_rr_sigs)
155{
156	uint16_t nsec_i;
157
158	ldns_rr_list *nsecs;
159	ldns_status result;
160
161	if (verbosity >= 5) {
162		printf("VERIFY DENIAL FROM:\n");
163		ldns_pkt_print(stdout, pkt);
164	}
165
166	result = LDNS_STATUS_CRYPTO_NO_RRSIG;
167	/* Try to see if there are NSECS in the packet */
168	nsecs = ldns_pkt_rr_list_by_type(pkt, LDNS_RR_TYPE_NSEC, LDNS_SECTION_ANY_NOQUESTION);
169	if (nsecs) {
170		for (nsec_i = 0; nsec_i < ldns_rr_list_rr_count(nsecs); nsec_i++) {
171			/* there are four options:
172			 * - name equals ownername and is covered by the type bitmap
173			 * - name equals ownername but is not covered by the type bitmap
174			 * - name falls within nsec coverage but is not equal to the owner name
175			 * - name falls outside of nsec coverage
176			 */
177			if (ldns_dname_compare(ldns_rr_owner(ldns_rr_list_rr(nsecs, nsec_i)), name) == 0) {
178				/*
179				printf("CHECKING NSEC:\n");
180				ldns_rr_print(stdout, ldns_rr_list_rr(nsecs, nsec_i));
181				printf("DAWASEM\n");
182				*/
183				if (ldns_nsec_bitmap_covers_type(
184					   ldns_nsec_get_bitmap(ldns_rr_list_rr(nsecs,
185													nsec_i)),
186					   type)) {
187					/* Error, according to the nsec this rrset is signed */
188					result = LDNS_STATUS_CRYPTO_NO_RRSIG;
189				} else {
190					/* ok nsec denies existence */
191					if (verbosity >= 3) {
192						printf(";; Existence of data set with this type denied by NSEC\n");
193					}
194						/*printf(";; Verifiably insecure.\n");*/
195						if (nsec_rrs && nsec_rr_sigs) {
196							(void) get_dnssec_rr(pkt, ldns_rr_owner(ldns_rr_list_rr(nsecs, nsec_i)), LDNS_RR_TYPE_NSEC, nsec_rrs, nsec_rr_sigs);
197						}
198						ldns_rr_list_deep_free(nsecs);
199						return LDNS_STATUS_OK;
200				}
201			} else if (ldns_nsec_covers_name(ldns_rr_list_rr(nsecs, nsec_i), name)) {
202				if (verbosity >= 3) {
203					printf(";; Existence of data set with this name denied by NSEC\n");
204				}
205				if (nsec_rrs && nsec_rr_sigs) {
206					(void) get_dnssec_rr(pkt, ldns_rr_owner(ldns_rr_list_rr(nsecs, nsec_i)), LDNS_RR_TYPE_NSEC, nsec_rrs, nsec_rr_sigs);
207				}
208				ldns_rr_list_deep_free(nsecs);
209				return LDNS_STATUS_OK;
210			} else {
211				/* nsec has nothing to do with this data */
212			}
213		}
214		ldns_rr_list_deep_free(nsecs);
215	} else if( (nsecs = ldns_pkt_rr_list_by_type(pkt, LDNS_RR_TYPE_NSEC3, LDNS_SECTION_ANY_NOQUESTION)) ) {
216                ldns_rr_list* sigs = ldns_pkt_rr_list_by_type(pkt, LDNS_RR_TYPE_RRSIG, LDNS_SECTION_ANY_NOQUESTION);
217                ldns_rr* q = ldns_rr_new();
218		ldns_rr* match = NULL;
219                if(!sigs) return LDNS_STATUS_MEM_ERR;
220                if(!q) return LDNS_STATUS_MEM_ERR;
221                ldns_rr_set_question(q, 1);
222                ldns_rr_set_ttl(q, 0);
223                ldns_rr_set_owner(q, ldns_rdf_clone(name));
224                if(!ldns_rr_owner(q)) return LDNS_STATUS_MEM_ERR;
225                ldns_rr_set_type(q, type);
226
227                /* result = ldns_dnssec_verify_denial_nsec3(q, nsecs, sigs, ldns_pkt_get_rcode(pkt), type, ldns_pkt_ancount(pkt) == 0); */
228                result = ldns_dnssec_verify_denial_nsec3_match(q, nsecs, sigs, ldns_pkt_get_rcode(pkt), type, ldns_pkt_ancount(pkt) == 0, &match);
229		if (result == LDNS_STATUS_OK && match && nsec_rrs && nsec_rr_sigs) {
230			(void) get_dnssec_rr(pkt, ldns_rr_owner(match), LDNS_RR_TYPE_NSEC3, nsec_rrs, nsec_rr_sigs);
231		}
232                ldns_rr_free(q);
233		ldns_rr_list_deep_free(nsecs);
234		ldns_rr_list_deep_free(sigs);
235        }
236	return result;
237}
238
239/* NSEC3 draft -07 */
240/*return hash name match*/
241ldns_rr *
242ldns_nsec3_exact_match(ldns_rdf *qname, ldns_rr_type qtype, ldns_rr_list *nsec3s) {
243	uint8_t algorithm;
244	uint32_t iterations;
245	uint8_t salt_length;
246	uint8_t *salt;
247
248	ldns_rdf *sname = NULL, *hashed_sname = NULL;
249
250	size_t nsec_i;
251	ldns_rr *nsec;
252	ldns_rr *result = NULL;
253
254	const ldns_rr_descriptor *descriptor;
255
256	ldns_rdf *zone_name = NULL;
257
258	if (verbosity >= 4) {
259		printf(";; finding exact match for ");
260		descriptor = ldns_rr_descript(qtype);
261		if (descriptor && descriptor->_name) {
262			printf("%s ", descriptor->_name);
263		} else {
264			printf("TYPE%d ", qtype);
265		}
266		ldns_rdf_print(stdout, qname);
267		printf("\n");
268	}
269
270	if (!qname || !nsec3s || ldns_rr_list_rr_count(nsec3s) < 1) {
271		if (verbosity >= 4) {
272			printf("no qname, nsec3s or list empty\n");
273		}
274		return NULL;
275	}
276
277	nsec = ldns_rr_list_rr(nsec3s, 0);
278	algorithm = ldns_nsec3_algorithm(nsec);
279	salt_length = ldns_nsec3_salt_length(nsec);
280	salt = ldns_nsec3_salt_data(nsec);
281	iterations = ldns_nsec3_iterations(nsec);
282	if (salt == NULL) {
283		goto done;
284	}
285
286	sname = ldns_rdf_clone(qname);
287	if (sname == NULL) {
288		goto done;
289	}
290	if (verbosity >= 4) {
291		printf(";; owner name hashes to: ");
292	}
293	hashed_sname = ldns_nsec3_hash_name(sname, algorithm, iterations, salt_length, salt);
294	if (hashed_sname == NULL) {
295		goto done;
296	}
297	zone_name = ldns_dname_left_chop(ldns_rr_owner(nsec));
298	if (zone_name == NULL) {
299		goto done;
300	}
301	if (ldns_dname_cat(hashed_sname, zone_name) != LDNS_STATUS_OK) {
302		goto done;
303	};
304
305	if (verbosity >= 4) {
306		ldns_rdf_print(stdout, hashed_sname);
307		printf("\n");
308	}
309
310	for (nsec_i = 0; nsec_i < ldns_rr_list_rr_count(nsec3s); nsec_i++) {
311		nsec = ldns_rr_list_rr(nsec3s, nsec_i);
312
313		/* check values of iterations etc! */
314
315		/* exact match? */
316		if (ldns_dname_compare(ldns_rr_owner(nsec), hashed_sname) == 0) {
317			result = nsec;
318			goto done;
319		}
320
321	}
322
323done:
324	ldns_rdf_deep_free(zone_name);
325	ldns_rdf_deep_free(sname);
326	ldns_rdf_deep_free(hashed_sname);
327	LDNS_FREE(salt);
328
329	if (verbosity >= 4) {
330		if (result) {
331			printf(";; Found.\n");
332		} else {
333			printf(";; Not foud.\n");
334		}
335	}
336	return result;
337}
338
339/*return the owner name of the closest encloser for name from the list of rrs */
340/* this is NOT the hash, but the original name! */
341ldns_rdf *
342ldns_nsec3_closest_encloser(ldns_rdf *qname, ldns_rr_type qtype, ldns_rr_list *nsec3s)
343{
344	/* remember parameters, they must match */
345	uint8_t algorithm;
346	uint32_t iterations;
347	uint8_t salt_length;
348	uint8_t *salt;
349
350	ldns_rdf *sname = NULL, *hashed_sname = NULL, *tmp;
351	bool flag;
352
353	bool exact_match_found;
354	bool in_range_found;
355
356	ldns_rdf *zone_name = NULL;
357
358	size_t nsec_i;
359	ldns_rr *nsec;
360	ldns_rdf *result = NULL;
361
362	if (!qname || !nsec3s || ldns_rr_list_rr_count(nsec3s) < 1) {
363		return NULL;
364	}
365
366	if (verbosity >= 4) {
367		printf(";; finding closest encloser for type %d ", qtype);
368		ldns_rdf_print(stdout, qname);
369		printf("\n");
370	}
371
372	nsec = ldns_rr_list_rr(nsec3s, 0);
373	algorithm = ldns_nsec3_algorithm(nsec);
374	salt_length = ldns_nsec3_salt_length(nsec);
375	salt = ldns_nsec3_salt_data(nsec);
376	iterations = ldns_nsec3_iterations(nsec);
377	if (salt == NULL) {
378		goto done;
379	}
380
381	sname = ldns_rdf_clone(qname);
382	if (sname == NULL) {
383		goto done;
384	}
385
386	flag = false;
387
388	zone_name = ldns_dname_left_chop(ldns_rr_owner(nsec));
389	if (zone_name == NULL) {
390		goto done;
391	}
392
393	/* algorithm from nsec3-07 8.3 */
394	while (ldns_dname_label_count(sname) > 0) {
395		exact_match_found = false;
396		in_range_found = false;
397
398		if (verbosity >= 3) {
399			printf(";; ");
400			ldns_rdf_print(stdout, sname);
401			printf(" hashes to: ");
402		}
403		hashed_sname = ldns_nsec3_hash_name(sname, algorithm, iterations, salt_length, salt);
404		if (hashed_sname == NULL) {
405			goto done;
406		}
407
408		if (ldns_dname_cat(hashed_sname, zone_name) != LDNS_STATUS_OK){
409			goto done;
410		}
411
412		if (verbosity >= 3) {
413			ldns_rdf_print(stdout, hashed_sname);
414			printf("\n");
415		}
416
417		for (nsec_i = 0; nsec_i < ldns_rr_list_rr_count(nsec3s); nsec_i++) {
418			nsec = ldns_rr_list_rr(nsec3s, nsec_i);
419
420			/* check values of iterations etc! */
421
422			/* exact match? */
423			if (ldns_dname_compare(ldns_rr_owner(nsec), hashed_sname) == 0) {
424				if (verbosity >= 4) {
425					printf(";; exact match found\n");
426				}
427			 	exact_match_found = true;
428			} else if (ldns_nsec_covers_name(nsec, hashed_sname)) {
429				if (verbosity >= 4) {
430					printf(";; in range of an nsec\n");
431				}
432				in_range_found = true;
433			}
434
435		}
436		if (!exact_match_found && in_range_found) {
437			flag = true;
438		} else if (exact_match_found && flag) {
439			result = ldns_rdf_clone(sname);
440		} else if (exact_match_found && !flag) {
441			// error!
442			if (verbosity >= 4) {
443				printf(";; the closest encloser is the same name (ie. this is an exact match, ie there is no closest encloser)\n");
444			}
445			ldns_rdf_deep_free(hashed_sname);
446			goto done;
447		} else {
448			flag = false;
449		}
450
451		ldns_rdf_deep_free(hashed_sname);
452		tmp = sname;
453		sname = ldns_dname_left_chop(sname);
454		ldns_rdf_deep_free(tmp);
455		if (sname == NULL) {
456			goto done;
457		}
458	}
459
460done:
461	LDNS_FREE(salt);
462	ldns_rdf_deep_free(zone_name);
463	ldns_rdf_deep_free(sname);
464
465	if (!result) {
466		if (verbosity >= 4) {
467			printf(";; no closest encloser found\n");
468		}
469	}
470
471	/* todo checks from end of 6.2. here or in caller? */
472	return result;
473}
474