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