xref: /dragonfly/contrib/ldns/drill/dnssec.c (revision 650094e1)
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 */
15 ldns_rr_list *
16 get_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 
34 void
35 drill_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 
67 void
68 drill_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  */
96 ldns_pkt_type
97 get_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 
153 ldns_status
154 ldns_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*/
241 ldns_rr *
242 ldns_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, *hashed_sname;
249 
250 	size_t nsec_i;
251 	ldns_rr *nsec;
252 	ldns_rr *result = NULL;
253 
254 	ldns_status status;
255 
256 	const ldns_rr_descriptor *descriptor;
257 
258 	ldns_rdf *zone_name;
259 
260 	if (verbosity >= 4) {
261 		printf(";; finding exact match for ");
262 		descriptor = ldns_rr_descript(qtype);
263 		if (descriptor && descriptor->_name) {
264 			printf("%s ", descriptor->_name);
265 		} else {
266 			printf("TYPE%d ", qtype);
267 		}
268 		ldns_rdf_print(stdout, qname);
269 		printf("\n");
270 	}
271 
272 	if (!qname || !nsec3s || ldns_rr_list_rr_count(nsec3s) < 1) {
273 		if (verbosity >= 4) {
274 			printf("no qname, nsec3s or list empty\n");
275 		}
276 		return NULL;
277 	}
278 
279 	nsec = ldns_rr_list_rr(nsec3s, 0);
280 	algorithm = ldns_nsec3_algorithm(nsec);
281 	salt_length = ldns_nsec3_salt_length(nsec);
282 	salt = ldns_nsec3_salt_data(nsec);
283 	iterations = ldns_nsec3_iterations(nsec);
284 
285 	sname = ldns_rdf_clone(qname);
286 
287 	if (verbosity >= 4) {
288 		printf(";; owner name hashes to: ");
289 	}
290 	hashed_sname = ldns_nsec3_hash_name(sname, algorithm, iterations, salt_length, salt);
291 
292 	zone_name = ldns_dname_left_chop(ldns_rr_owner(nsec));
293 	status = ldns_dname_cat(hashed_sname, zone_name);
294 
295 	if (verbosity >= 4) {
296 		ldns_rdf_print(stdout, hashed_sname);
297 		printf("\n");
298 	}
299 
300 	for (nsec_i = 0; nsec_i < ldns_rr_list_rr_count(nsec3s); nsec_i++) {
301 		nsec = ldns_rr_list_rr(nsec3s, nsec_i);
302 
303 		/* check values of iterations etc! */
304 
305 		/* exact match? */
306 		if (ldns_dname_compare(ldns_rr_owner(nsec), hashed_sname) == 0) {
307 			result = nsec;
308 			goto done;
309 		}
310 
311 	}
312 
313 done:
314 	ldns_rdf_deep_free(zone_name);
315 	ldns_rdf_deep_free(sname);
316 	ldns_rdf_deep_free(hashed_sname);
317 	LDNS_FREE(salt);
318 
319 	if (verbosity >= 4) {
320 		if (result) {
321 			printf(";; Found.\n");
322 		} else {
323 			printf(";; Not foud.\n");
324 		}
325 	}
326 	return result;
327 }
328 
329 /*return the owner name of the closest encloser for name from the list of rrs */
330 /* this is NOT the hash, but the original name! */
331 ldns_rdf *
332 ldns_nsec3_closest_encloser(ldns_rdf *qname, ldns_rr_type qtype, ldns_rr_list *nsec3s)
333 {
334 	/* remember parameters, they must match */
335 	uint8_t algorithm;
336 	uint32_t iterations;
337 	uint8_t salt_length;
338 	uint8_t *salt;
339 
340 	ldns_rdf *sname, *hashed_sname, *tmp;
341 	ldns_rr *ce;
342 	bool flag;
343 
344 	bool exact_match_found;
345 	bool in_range_found;
346 
347 	ldns_status status;
348 	ldns_rdf *zone_name;
349 
350 	size_t nsec_i;
351 	ldns_rr *nsec;
352 	ldns_rdf *result = NULL;
353 
354 	if (!qname || !nsec3s || ldns_rr_list_rr_count(nsec3s) < 1) {
355 		return NULL;
356 	}
357 
358 	if (verbosity >= 4) {
359 		printf(";; finding closest encloser for type %d ", qtype);
360 		ldns_rdf_print(stdout, qname);
361 		printf("\n");
362 	}
363 
364 	nsec = ldns_rr_list_rr(nsec3s, 0);
365 	algorithm = ldns_nsec3_algorithm(nsec);
366 	salt_length = ldns_nsec3_salt_length(nsec);
367 	salt = ldns_nsec3_salt_data(nsec);
368 	iterations = ldns_nsec3_iterations(nsec);
369 
370 	sname = ldns_rdf_clone(qname);
371 
372 	ce = NULL;
373 	flag = false;
374 
375 	zone_name = ldns_dname_left_chop(ldns_rr_owner(nsec));
376 
377 	/* algorithm from nsec3-07 8.3 */
378 	while (ldns_dname_label_count(sname) > 0) {
379 		exact_match_found = false;
380 		in_range_found = false;
381 
382 		if (verbosity >= 3) {
383 			printf(";; ");
384 			ldns_rdf_print(stdout, sname);
385 			printf(" hashes to: ");
386 		}
387 		hashed_sname = ldns_nsec3_hash_name(sname, algorithm, iterations, salt_length, salt);
388 
389 		status = ldns_dname_cat(hashed_sname, zone_name);
390 
391 		if (verbosity >= 3) {
392 			ldns_rdf_print(stdout, hashed_sname);
393 			printf("\n");
394 		}
395 
396 		for (nsec_i = 0; nsec_i < ldns_rr_list_rr_count(nsec3s); nsec_i++) {
397 			nsec = ldns_rr_list_rr(nsec3s, nsec_i);
398 
399 			/* check values of iterations etc! */
400 
401 			/* exact match? */
402 			if (ldns_dname_compare(ldns_rr_owner(nsec), hashed_sname) == 0) {
403 				if (verbosity >= 4) {
404 					printf(";; exact match found\n");
405 				}
406 			 	exact_match_found = true;
407 			} else if (ldns_nsec_covers_name(nsec, hashed_sname)) {
408 				if (verbosity >= 4) {
409 					printf(";; in range of an nsec\n");
410 				}
411 				in_range_found = true;
412 			}
413 
414 		}
415 		if (!exact_match_found && in_range_found) {
416 			flag = true;
417 		} else if (exact_match_found && flag) {
418 			result = ldns_rdf_clone(sname);
419 		} else if (exact_match_found && !flag) {
420 			// error!
421 			if (verbosity >= 4) {
422 				printf(";; the closest encloser is the same name (ie. this is an exact match, ie there is no closest encloser)\n");
423 			}
424 			ldns_rdf_deep_free(hashed_sname);
425 			goto done;
426 		} else {
427 			flag = false;
428 		}
429 
430 		ldns_rdf_deep_free(hashed_sname);
431 		tmp = sname;
432 		sname = ldns_dname_left_chop(sname);
433 		ldns_rdf_deep_free(tmp);
434 	}
435 
436 	done:
437 	LDNS_FREE(salt);
438 	ldns_rdf_deep_free(zone_name);
439 	ldns_rdf_deep_free(sname);
440 
441 	if (!result) {
442 		if (verbosity >= 4) {
443 			printf(";; no closest encloser found\n");
444 		}
445 	}
446 
447 	/* todo checks from end of 6.2. here or in caller? */
448 	return result;
449 }
450 
451 
452 /* special case were there was a wildcard expansion match, the exact match must be disproven */
453 ldns_status
454 ldns_verify_denial_wildcard(ldns_pkt *pkt, ldns_rdf *name, ldns_rr_type type, ldns_rr_list **nsec_rrs, ldns_rr_list **nsec_rr_sigs)
455 {
456 	ldns_rdf *nsec3_ce = NULL;
457 	ldns_rr *nsec3_ex = NULL;
458 	ldns_rdf *wildcard_name = NULL;
459 	ldns_rdf *nsec3_wc_ce = NULL;
460 	ldns_rr *nsec3_wc_ex = NULL;
461 	ldns_rdf *chopped_dname = NULL;
462 	ldns_rr_list *nsecs;
463 	ldns_status result = LDNS_STATUS_ERR;
464 
465 	nsecs = ldns_pkt_rr_list_by_type(pkt, LDNS_RR_TYPE_NSEC3, LDNS_SECTION_ANY_NOQUESTION);
466 	if (nsecs) {
467 		wildcard_name = ldns_dname_new_frm_str("*");
468 		chopped_dname = ldns_dname_left_chop(name);
469 		result = ldns_dname_cat(wildcard_name, chopped_dname);
470 		ldns_rdf_deep_free(chopped_dname);
471 
472 		nsec3_ex = ldns_nsec3_exact_match(name, type, nsecs);
473 		nsec3_ce = ldns_nsec3_closest_encloser(name, type, nsecs);
474 		nsec3_wc_ce = ldns_nsec3_closest_encloser(wildcard_name, type, nsecs);
475 		nsec3_wc_ex = ldns_nsec3_exact_match(wildcard_name, type, nsecs);
476 
477 		if (nsec3_ex) {
478 			if (verbosity >= 3) {
479 				printf(";; Error, exact match for for name found, but should not exist (draft -07 section 8.8)\n");
480 			}
481 			result = LDNS_STATUS_NSEC3_ERR;
482 		} else if (!nsec3_ce) {
483 			if (verbosity >= 3) {
484 				printf(";; Error, closest encloser for exact match missing in wildcard response (draft -07 section 8.8)\n");
485 			}
486 			result = LDNS_STATUS_NSEC3_ERR;
487 /*
488 		} else if (!nsec3_wc_ex) {
489 			printf(";; Error, no wildcard nsec3 match: ");
490 			ldns_rdf_print(stdout, wildcard_name);
491 			printf(" (draft -07 section 8.8)\n");
492 			result = LDNS_STATUS_NSEC3_ERR;
493 */
494 /*		} else if (!nsec */
495 		} else {
496 			if (verbosity >= 3) {
497 				printf(";; wilcard expansion proven\n");
498 			}
499 			result = LDNS_STATUS_OK;
500 		}
501 	} else {
502 		if (verbosity >= 3) {
503 			printf(";; Error: no NSEC or NSEC3 records in answer\n");
504 		}
505 		result = LDNS_STATUS_CRYPTO_NO_RRSIG;
506 	}
507 
508 	if (nsecs && nsec_rrs && nsec_rr_sigs) {
509 		(void) get_dnssec_rr(pkt, ldns_rr_owner(ldns_rr_list_rr(nsecs, 0)), LDNS_RR_TYPE_NSEC3, nsec_rrs, nsec_rr_sigs);
510 	}
511 	return result;
512 }
513 
514 
515