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