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