030aa3bb73f529a2829256d5ca1fadb134f90783
[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         } 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