]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/ldns/drill/dnssec.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.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                 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
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
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
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
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         
184         if (verbosity >= 5) {
185                 printf("VERIFY DENIAL FROM:\n");
186                 ldns_pkt_print(stdout, pkt);
187         }
188
189         result = LDNS_STATUS_CRYPTO_NO_RRSIG;
190         /* Try to see if there are NSECS in the packet */
191         nsecs = ldns_pkt_rr_list_by_type(pkt, LDNS_RR_TYPE_NSEC, LDNS_SECTION_ANY_NOQUESTION);
192         if (nsecs) {
193                 for (nsec_i = 0; nsec_i < ldns_rr_list_rr_count(nsecs); nsec_i++) {
194                         /* there are four options:
195                          * - name equals ownername and is covered by the type bitmap
196                          * - name equals ownername but is not covered by the type bitmap
197                          * - name falls within nsec coverage but is not equal to the owner name
198                          * - name falls outside of nsec coverage
199                          */
200                         if (ldns_dname_compare(ldns_rr_owner(ldns_rr_list_rr(nsecs, nsec_i)), name) == 0) {
201                                 /*
202                                 printf("CHECKING NSEC:\n");
203                                 ldns_rr_print(stdout, ldns_rr_list_rr(nsecs, nsec_i));
204                                 printf("DAWASEM\n");
205                                 */
206                                 if (ldns_nsec_bitmap_covers_type(
207                                            ldns_nsec_get_bitmap(ldns_rr_list_rr(nsecs,
208                                                                                                         nsec_i)),
209                                            type)) {
210                                         /* Error, according to the nsec this rrset is signed */
211                                         result = LDNS_STATUS_CRYPTO_NO_RRSIG;
212                                 } else {
213                                         /* ok nsec denies existence */
214                                         if (verbosity >= 3) {
215                                                 printf(";; Existence of data set with this type denied by NSEC\n");
216                                         }
217                                                 /*printf(";; Verifiably insecure.\n");*/
218                                                 if (nsec_rrs && nsec_rr_sigs) {
219                                                         (void) get_dnssec_rr(pkt, ldns_rr_owner(ldns_rr_list_rr(nsecs, nsec_i)), LDNS_RR_TYPE_NSEC, nsec_rrs, nsec_rr_sigs);
220                                                 }
221                                                 ldns_rr_list_deep_free(nsecs);
222                                                 return LDNS_STATUS_OK;
223                                 }
224                         } else if (ldns_nsec_covers_name(ldns_rr_list_rr(nsecs, nsec_i), name)) {
225                                 if (verbosity >= 3) {
226                                         printf(";; Existence of data set with this name denied by NSEC\n");
227                                 }
228                                 if (nsec_rrs && nsec_rr_sigs) {
229                                         (void) get_dnssec_rr(pkt, ldns_rr_owner(ldns_rr_list_rr(nsecs, nsec_i)), LDNS_RR_TYPE_NSEC, nsec_rrs, nsec_rr_sigs);
230                                 }
231                                 ldns_rr_list_deep_free(nsecs);
232                                 return LDNS_STATUS_OK;
233                         } else {
234                                 /* nsec has nothing to do with this data */
235                         }
236                 }
237                 ldns_rr_list_deep_free(nsecs);
238         } else if( (nsecs = ldns_pkt_rr_list_by_type(pkt, LDNS_RR_TYPE_NSEC3, LDNS_SECTION_ANY_NOQUESTION)) ) {
239                 ldns_rr_list* sigs = ldns_pkt_rr_list_by_type(pkt, LDNS_RR_TYPE_RRSIG, LDNS_SECTION_ANY_NOQUESTION);
240                 ldns_rr* q = ldns_rr_new();
241                 ldns_rr* match = NULL;
242
243                 if(!sigs) {
244                         if (q) {
245                                 ldns_rr_free(q);
246                         }
247                         ldns_rr_list_deep_free(nsecs);
248                         return LDNS_STATUS_MEM_ERR;
249                 }
250                 if(!q) {
251                         ldns_rr_list_deep_free(nsecs);
252                         ldns_rr_list_deep_free(sigs);
253                         return LDNS_STATUS_MEM_ERR;
254                 }
255                 ldns_rr_set_question(q, 1);
256                 ldns_rr_set_ttl(q, 0);
257                 ldns_rr_set_owner(q, ldns_rdf_clone(name));
258                 if(!ldns_rr_owner(q)) {
259                         ldns_rr_free(q);
260                         ldns_rr_list_deep_free(sigs);
261                         ldns_rr_list_deep_free(nsecs);
262                         return LDNS_STATUS_MEM_ERR;
263                 }
264                 ldns_rr_set_type(q, type);
265                 
266                 /* result = ldns_dnssec_verify_denial_nsec3(q, nsecs, sigs, ldns_pkt_get_rcode(pkt), type, ldns_pkt_ancount(pkt) == 0); */
267                 result = ldns_dnssec_verify_denial_nsec3_match(q, nsecs, sigs, ldns_pkt_get_rcode(pkt), type, ldns_pkt_ancount(pkt) == 0, &match);
268                 if (result == LDNS_STATUS_OK && match && nsec_rrs && nsec_rr_sigs) {
269                         (void) get_dnssec_rr(pkt, ldns_rr_owner(match), LDNS_RR_TYPE_NSEC3, nsec_rrs, nsec_rr_sigs);
270                 }
271                 ldns_rr_free(q);
272                 ldns_rr_list_deep_free(nsecs);
273                 ldns_rr_list_deep_free(sigs);
274         }
275         return result;
276 #else
277         (void)pkt;
278         (void)name;
279         (void)type;
280         (void)nsec_rrs;
281         (void)nsec_rr_sigs;
282         return LDNS_STATUS_ERR;
283 #endif /* HAVE_SSL */
284 }
285
286 /* NSEC3 draft -07 */
287 /*return hash name match*/
288 ldns_rr *
289 ldns_nsec3_exact_match(ldns_rdf *qname, ldns_rr_type qtype, ldns_rr_list *nsec3s) {
290         uint8_t algorithm;
291         uint32_t iterations;
292         uint8_t salt_length;
293         uint8_t *salt;
294         
295         ldns_rdf *sname = NULL, *hashed_sname = NULL;
296         
297         size_t nsec_i;
298         ldns_rr *nsec;
299         ldns_rr *result = NULL;
300         
301         const ldns_rr_descriptor *descriptor;
302         
303         ldns_rdf *zone_name = NULL;
304         
305         if (verbosity >= 4) {
306                 printf(";; finding exact match for ");
307                 descriptor = ldns_rr_descript(qtype);
308                 if (descriptor && descriptor->_name) {
309                         printf("%s ", descriptor->_name);
310                 } else {
311                         printf("TYPE%d ", qtype);
312                 }
313                 ldns_rdf_print(stdout, qname);
314                 printf("\n");
315         }
316         
317         if (!qname || !nsec3s || ldns_rr_list_rr_count(nsec3s) < 1) {
318                 if (verbosity >= 4) {
319                         printf("no qname, nsec3s or list empty\n");
320                 }
321                 return NULL;
322         }
323
324         nsec = ldns_rr_list_rr(nsec3s, 0);
325         algorithm = ldns_nsec3_algorithm(nsec);
326         salt_length = ldns_nsec3_salt_length(nsec);
327         salt = ldns_nsec3_salt_data(nsec);
328         iterations = ldns_nsec3_iterations(nsec);
329         if (salt == NULL) {
330                 goto done;
331         }
332
333         sname = ldns_rdf_clone(qname);
334         if (sname == NULL) {
335                 goto done;
336         }
337         if (verbosity >= 4) {
338                 printf(";; owner name hashes to: ");
339         }
340         hashed_sname = ldns_nsec3_hash_name(sname, algorithm, iterations, salt_length, salt);
341         if (hashed_sname == NULL) {
342                 goto done;
343         }
344         zone_name = ldns_dname_left_chop(ldns_rr_owner(nsec));
345         if (zone_name == NULL) {
346                 goto done;
347         }
348         if (ldns_dname_cat(hashed_sname, zone_name) != LDNS_STATUS_OK) {
349                 goto done;
350         };
351         
352         if (verbosity >= 4) {
353                 ldns_rdf_print(stdout, hashed_sname);
354                 printf("\n");
355         }
356
357         for (nsec_i = 0; nsec_i < ldns_rr_list_rr_count(nsec3s); nsec_i++) {
358                 nsec = ldns_rr_list_rr(nsec3s, nsec_i);
359                 
360                 /* check values of iterations etc! */
361                 
362                 /* exact match? */
363                 if (ldns_dname_compare(ldns_rr_owner(nsec), hashed_sname) == 0) {
364                         result = nsec;
365                         goto done;
366                 }
367                 
368         }
369
370 done:
371         ldns_rdf_deep_free(zone_name);
372         ldns_rdf_deep_free(sname);
373         ldns_rdf_deep_free(hashed_sname);
374         LDNS_FREE(salt);
375         
376         if (verbosity >= 4) {
377                 if (result) {
378                         printf(";; Found.\n");
379                 } else {
380                         printf(";; Not foud.\n");
381                 }
382         }
383         return result;
384 }
385
386 /*return the owner name of the closest encloser for name from the list of rrs */
387 /* this is NOT the hash, but the original name! */
388 ldns_rdf *
389 ldns_nsec3_closest_encloser(ldns_rdf *qname, ldns_rr_type qtype, ldns_rr_list *nsec3s)
390 {
391         /* remember parameters, they must match */
392         uint8_t algorithm;
393         uint32_t iterations;
394         uint8_t salt_length;
395         uint8_t *salt;
396
397         ldns_rdf *sname = NULL, *hashed_sname = NULL, *tmp;
398         bool flag;
399         
400         bool exact_match_found;
401         bool in_range_found;
402         
403         ldns_rdf *zone_name = NULL;
404         
405         size_t nsec_i;
406         ldns_rr *nsec;
407         ldns_rdf *result = NULL;
408         
409         if (!qname || !nsec3s || ldns_rr_list_rr_count(nsec3s) < 1) {
410                 return NULL;
411         }
412
413         if (verbosity >= 4) {
414                 printf(";; finding closest encloser for type %d ", qtype);
415                 ldns_rdf_print(stdout, qname);
416                 printf("\n");
417         }
418
419         nsec = ldns_rr_list_rr(nsec3s, 0);
420         algorithm = ldns_nsec3_algorithm(nsec);
421         salt_length = ldns_nsec3_salt_length(nsec);
422         salt = ldns_nsec3_salt_data(nsec);
423         iterations = ldns_nsec3_iterations(nsec);
424         if (salt == NULL) {
425                 goto done;
426         }
427
428         sname = ldns_rdf_clone(qname);
429         if (sname == NULL) {
430                 goto done;
431         }
432
433         flag = false;
434         
435         zone_name = ldns_dname_left_chop(ldns_rr_owner(nsec));
436         if (zone_name == NULL) {
437                 goto done;
438         }
439
440         /* algorithm from nsec3-07 8.3 */
441         while (ldns_dname_label_count(sname) > 0) {
442                 exact_match_found = false;
443                 in_range_found = false;
444                 
445                 if (verbosity >= 3) {
446                         printf(";; ");
447                         ldns_rdf_print(stdout, sname);
448                         printf(" hashes to: ");
449                 }
450                 hashed_sname = ldns_nsec3_hash_name(sname, algorithm, iterations, salt_length, salt);
451                 if (hashed_sname == NULL) {
452                         goto done;
453                 }
454
455                 if (ldns_dname_cat(hashed_sname, zone_name) != LDNS_STATUS_OK){
456                         goto done;
457                 }
458
459                 if (verbosity >= 3) {
460                         ldns_rdf_print(stdout, hashed_sname);
461                         printf("\n");
462                 }
463
464                 for (nsec_i = 0; nsec_i < ldns_rr_list_rr_count(nsec3s); nsec_i++) {
465                         nsec = ldns_rr_list_rr(nsec3s, nsec_i);
466                         
467                         /* check values of iterations etc! */
468                         
469                         /* exact match? */
470                         if (ldns_dname_compare(ldns_rr_owner(nsec), hashed_sname) == 0) {
471                                 if (verbosity >= 4) {
472                                         printf(";; exact match found\n");
473                                 }
474                                 exact_match_found = true;
475                         } else if (ldns_nsec_covers_name(nsec, hashed_sname)) {
476                                 if (verbosity >= 4) {
477                                         printf(";; in range of an nsec\n");
478                                 }
479                                 in_range_found = true;
480                         }
481                         
482                 }
483                 if (!exact_match_found && in_range_found) {
484                         flag = true;
485                 } else if (exact_match_found && flag) {
486                         result = ldns_rdf_clone(sname);
487                 } else if (exact_match_found && !flag) {
488                         // error!
489                         if (verbosity >= 4) {
490                                 printf(";; the closest encloser is the same name (ie. this is an exact match, ie there is no closest encloser)\n");
491                         }
492                         ldns_rdf_deep_free(hashed_sname);
493                         goto done;
494                 } else {
495                         flag = false;
496                 }
497                 
498                 ldns_rdf_deep_free(hashed_sname);
499                 tmp = sname;
500                 sname = ldns_dname_left_chop(sname);
501                 ldns_rdf_deep_free(tmp);
502                 if (sname == NULL) {
503                         goto done;
504                 }
505         }
506
507 done:
508         LDNS_FREE(salt);
509         ldns_rdf_deep_free(zone_name);
510         ldns_rdf_deep_free(sname);
511
512         if (!result) {
513                 if (verbosity >= 4) {
514                         printf(";; no closest encloser found\n");
515                 }
516         }
517         
518         /* todo checks from end of 6.2. here or in caller? */
519         return result;
520 }