xref: /dragonfly/contrib/ldns/drill/dnssec.c (revision 7733acb50455a11cc2ee36edd926ff0fa3361e9a)
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