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 515