validator.c revision 1.13
1/* $NetBSD: validator.c,v 1.13 2023/06/26 22:03:00 christos Exp $ */ 2 3/* 4 * Copyright (C) Internet Systems Consortium, Inc. ("ISC") 5 * 6 * SPDX-License-Identifier: MPL-2.0 7 * 8 * This Source Code Form is subject to the terms of the Mozilla Public 9 * License, v. 2.0. If a copy of the MPL was not distributed with this 10 * file, you can obtain one at https://mozilla.org/MPL/2.0/. 11 * 12 * See the COPYRIGHT file distributed with this work for additional 13 * information regarding copyright ownership. 14 */ 15 16#include <inttypes.h> 17#include <stdbool.h> 18 19#include <isc/base32.h> 20#include <isc/md.h> 21#include <isc/mem.h> 22#include <isc/print.h> 23#include <isc/string.h> 24#include <isc/task.h> 25#include <isc/util.h> 26 27#include <dns/client.h> 28#include <dns/db.h> 29#include <dns/dnssec.h> 30#include <dns/ds.h> 31#include <dns/events.h> 32#include <dns/keytable.h> 33#include <dns/keyvalues.h> 34#include <dns/log.h> 35#include <dns/message.h> 36#include <dns/ncache.h> 37#include <dns/nsec.h> 38#include <dns/nsec3.h> 39#include <dns/rdata.h> 40#include <dns/rdataset.h> 41#include <dns/rdatatype.h> 42#include <dns/resolver.h> 43#include <dns/result.h> 44#include <dns/validator.h> 45#include <dns/view.h> 46 47/*! \file 48 * \brief 49 * Basic processing sequences: 50 * 51 * \li When called with rdataset and sigrdataset: 52 * validator_start -> validate_answer -> proveunsecure 53 * validator_start -> validate_answer -> validate_nx (if secure wildcard) 54 * 55 * \li When called with rdataset but no sigrdataset: 56 * validator_start -> proveunsecure 57 * 58 * \li When called with no rdataset or sigrdataset: 59 * validator_start -> validate_nx-> proveunsecure 60 * 61 * validator_start: determine what type of validation to do. 62 * validate_answer: attempt to perform a positive validation. 63 * proveunsecure: attempt to prove the answer comes from an unsecure zone. 64 * validate_nx: attempt to prove a negative response. 65 */ 66 67#define VALIDATOR_MAGIC ISC_MAGIC('V', 'a', 'l', '?') 68#define VALID_VALIDATOR(v) ISC_MAGIC_VALID(v, VALIDATOR_MAGIC) 69 70#define VALATTR_SHUTDOWN 0x0001 /*%< Shutting down. */ 71#define VALATTR_CANCELED 0x0002 /*%< Canceled. */ 72#define VALATTR_TRIEDVERIFY \ 73 0x0004 /*%< We have found a key and \ 74 * have attempted a verify. */ 75#define VALATTR_INSECURITY 0x0010 /*%< Attempting proveunsecure. */ 76 77/*! 78 * NSEC proofs to be looked for. 79 */ 80#define VALATTR_NEEDNOQNAME 0x00000100 81#define VALATTR_NEEDNOWILDCARD 0x00000200 82#define VALATTR_NEEDNODATA 0x00000400 83 84/*! 85 * NSEC proofs that have been found. 86 */ 87#define VALATTR_FOUNDNOQNAME 0x00001000 88#define VALATTR_FOUNDNOWILDCARD 0x00002000 89#define VALATTR_FOUNDNODATA 0x00004000 90#define VALATTR_FOUNDCLOSEST 0x00008000 91#define VALATTR_FOUNDOPTOUT 0x00010000 92#define VALATTR_FOUNDUNKNOWN 0x00020000 93 94#define NEEDNODATA(val) ((val->attributes & VALATTR_NEEDNODATA) != 0) 95#define NEEDNOQNAME(val) ((val->attributes & VALATTR_NEEDNOQNAME) != 0) 96#define NEEDNOWILDCARD(val) ((val->attributes & VALATTR_NEEDNOWILDCARD) != 0) 97#define FOUNDNODATA(val) ((val->attributes & VALATTR_FOUNDNODATA) != 0) 98#define FOUNDNOQNAME(val) ((val->attributes & VALATTR_FOUNDNOQNAME) != 0) 99#define FOUNDNOWILDCARD(val) ((val->attributes & VALATTR_FOUNDNOWILDCARD) != 0) 100#define FOUNDCLOSEST(val) ((val->attributes & VALATTR_FOUNDCLOSEST) != 0) 101#define FOUNDOPTOUT(val) ((val->attributes & VALATTR_FOUNDOPTOUT) != 0) 102 103#define SHUTDOWN(v) (((v)->attributes & VALATTR_SHUTDOWN) != 0) 104#define CANCELED(v) (((v)->attributes & VALATTR_CANCELED) != 0) 105 106#define NEGATIVE(r) (((r)->attributes & DNS_RDATASETATTR_NEGATIVE) != 0) 107#define NXDOMAIN(r) (((r)->attributes & DNS_RDATASETATTR_NXDOMAIN) != 0) 108 109static void 110destroy(dns_validator_t *val); 111 112static isc_result_t 113select_signing_key(dns_validator_t *val, dns_rdataset_t *rdataset); 114 115static isc_result_t 116validate_answer(dns_validator_t *val, bool resume); 117 118static isc_result_t 119validate_dnskey(dns_validator_t *val); 120 121static isc_result_t 122validate_nx(dns_validator_t *val, bool resume); 123 124static isc_result_t 125proveunsecure(dns_validator_t *val, bool have_ds, bool resume); 126 127static void 128validator_logv(dns_validator_t *val, isc_logcategory_t *category, 129 isc_logmodule_t *module, int level, const char *fmt, va_list ap) 130 ISC_FORMAT_PRINTF(5, 0); 131 132static void 133validator_log(void *val, int level, const char *fmt, ...) 134 ISC_FORMAT_PRINTF(3, 4); 135 136static void 137validator_logcreate(dns_validator_t *val, dns_name_t *name, 138 dns_rdatatype_t type, const char *caller, 139 const char *operation); 140 141/*% 142 * Ensure the validator's rdatasets are marked as expired. 143 */ 144static void 145expire_rdatasets(dns_validator_t *val) { 146 if (dns_rdataset_isassociated(&val->frdataset)) { 147 dns_rdataset_expire(&val->frdataset); 148 } 149 if (dns_rdataset_isassociated(&val->fsigrdataset)) { 150 dns_rdataset_expire(&val->fsigrdataset); 151 } 152} 153 154/*% 155 * Ensure the validator's rdatasets are disassociated. 156 */ 157static void 158disassociate_rdatasets(dns_validator_t *val) { 159 if (dns_rdataset_isassociated(&val->fdsset)) { 160 dns_rdataset_disassociate(&val->fdsset); 161 } 162 if (dns_rdataset_isassociated(&val->frdataset)) { 163 dns_rdataset_disassociate(&val->frdataset); 164 } 165 if (dns_rdataset_isassociated(&val->fsigrdataset)) { 166 dns_rdataset_disassociate(&val->fsigrdataset); 167 } 168} 169 170/*% 171 * Mark the rdatasets in val->event with trust level "answer", 172 * indicating that they did not validate, but could be cached as insecure. 173 * 174 * If we are validating a name that is marked as "must be secure", log a 175 * warning and return DNS_R_MUSTBESECURE instead. 176 */ 177static isc_result_t 178markanswer(dns_validator_t *val, const char *where, const char *mbstext) { 179 if (val->mustbesecure && mbstext != NULL) { 180 validator_log(val, ISC_LOG_WARNING, 181 "must be secure failure, %s", mbstext); 182 return (DNS_R_MUSTBESECURE); 183 } 184 185 validator_log(val, ISC_LOG_DEBUG(3), "marking as answer (%s)", where); 186 if (val->event->rdataset != NULL) { 187 dns_rdataset_settrust(val->event->rdataset, dns_trust_answer); 188 } 189 if (val->event->sigrdataset != NULL) { 190 dns_rdataset_settrust(val->event->sigrdataset, 191 dns_trust_answer); 192 } 193 194 return (ISC_R_SUCCESS); 195} 196 197/*% 198 * Mark the RRsets in val->event with trust level secure. 199 */ 200static void 201marksecure(dns_validatorevent_t *event) { 202 dns_rdataset_settrust(event->rdataset, dns_trust_secure); 203 if (event->sigrdataset != NULL) { 204 dns_rdataset_settrust(event->sigrdataset, dns_trust_secure); 205 } 206 event->secure = true; 207} 208 209/* 210 * Validator 'val' is finished; send the completion event to the task 211 * that called dns_validator_create(), with result `result`. 212 */ 213static void 214validator_done(dns_validator_t *val, isc_result_t result) { 215 isc_task_t *task; 216 217 if (val->event == NULL) { 218 return; 219 } 220 221 /* 222 * Caller must be holding the lock. 223 */ 224 225 val->event->result = result; 226 task = val->event->ev_sender; 227 val->event->ev_sender = val; 228 val->event->ev_type = DNS_EVENT_VALIDATORDONE; 229 val->event->ev_action = val->action; 230 val->event->ev_arg = val->arg; 231 isc_task_sendanddetach(&task, (isc_event_t **)(void *)&val->event); 232} 233 234/* 235 * Called when deciding whether to destroy validator 'val'. 236 */ 237static bool 238exit_check(dns_validator_t *val) { 239 /* 240 * Caller must be holding the lock. 241 */ 242 if (!SHUTDOWN(val)) { 243 return (false); 244 } 245 246 INSIST(val->event == NULL); 247 248 if (val->fetch != NULL || val->subvalidator != NULL) { 249 return (false); 250 } 251 252 return (true); 253} 254 255/*% 256 * Look in the NSEC record returned from a DS query to see if there is 257 * a NS RRset at this name. If it is found we are at a delegation point. 258 */ 259static bool 260isdelegation(dns_name_t *name, dns_rdataset_t *rdataset, 261 isc_result_t dbresult) { 262 dns_fixedname_t fixed; 263 dns_label_t hashlabel; 264 dns_name_t nsec3name; 265 dns_rdata_nsec3_t nsec3; 266 dns_rdata_t rdata = DNS_RDATA_INIT; 267 dns_rdataset_t set; 268 int order; 269 int scope; 270 bool found; 271 isc_buffer_t buffer; 272 isc_result_t result; 273 unsigned char hash[NSEC3_MAX_HASH_LENGTH]; 274 unsigned char owner[NSEC3_MAX_HASH_LENGTH]; 275 unsigned int length; 276 277 REQUIRE(dbresult == DNS_R_NXRRSET || dbresult == DNS_R_NCACHENXRRSET); 278 279 dns_rdataset_init(&set); 280 if (dbresult == DNS_R_NXRRSET) { 281 dns_rdataset_clone(rdataset, &set); 282 } else { 283 result = dns_ncache_getrdataset(rdataset, name, 284 dns_rdatatype_nsec, &set); 285 if (result == ISC_R_NOTFOUND) { 286 goto trynsec3; 287 } 288 if (result != ISC_R_SUCCESS) { 289 return (false); 290 } 291 } 292 293 INSIST(set.type == dns_rdatatype_nsec); 294 295 found = false; 296 result = dns_rdataset_first(&set); 297 if (result == ISC_R_SUCCESS) { 298 dns_rdataset_current(&set, &rdata); 299 found = dns_nsec_typepresent(&rdata, dns_rdatatype_ns); 300 dns_rdata_reset(&rdata); 301 } 302 dns_rdataset_disassociate(&set); 303 return (found); 304 305trynsec3: 306 /* 307 * Iterate over the ncache entry. 308 */ 309 found = false; 310 dns_name_init(&nsec3name, NULL); 311 dns_fixedname_init(&fixed); 312 dns_name_downcase(name, dns_fixedname_name(&fixed), NULL); 313 name = dns_fixedname_name(&fixed); 314 for (result = dns_rdataset_first(rdataset); result == ISC_R_SUCCESS; 315 result = dns_rdataset_next(rdataset)) 316 { 317 dns_ncache_current(rdataset, &nsec3name, &set); 318 if (set.type != dns_rdatatype_nsec3) { 319 dns_rdataset_disassociate(&set); 320 continue; 321 } 322 dns_name_getlabel(&nsec3name, 0, &hashlabel); 323 isc_region_consume(&hashlabel, 1); 324 isc_buffer_init(&buffer, owner, sizeof(owner)); 325 result = isc_base32hexnp_decoderegion(&hashlabel, &buffer); 326 if (result != ISC_R_SUCCESS) { 327 dns_rdataset_disassociate(&set); 328 continue; 329 } 330 for (result = dns_rdataset_first(&set); result == ISC_R_SUCCESS; 331 result = dns_rdataset_next(&set)) 332 { 333 dns_rdata_reset(&rdata); 334 dns_rdataset_current(&set, &rdata); 335 (void)dns_rdata_tostruct(&rdata, &nsec3, NULL); 336 if (nsec3.hash != 1) { 337 continue; 338 } 339 length = isc_iterated_hash( 340 hash, nsec3.hash, nsec3.iterations, nsec3.salt, 341 nsec3.salt_length, name->ndata, name->length); 342 if (length != isc_buffer_usedlength(&buffer)) { 343 continue; 344 } 345 order = memcmp(hash, owner, length); 346 if (order == 0) { 347 found = dns_nsec3_typepresent(&rdata, 348 dns_rdatatype_ns); 349 dns_rdataset_disassociate(&set); 350 return (found); 351 } 352 if ((nsec3.flags & DNS_NSEC3FLAG_OPTOUT) == 0) { 353 continue; 354 } 355 /* 356 * Does this optout span cover the name? 357 */ 358 scope = memcmp(owner, nsec3.next, nsec3.next_length); 359 if ((scope < 0 && order > 0 && 360 memcmp(hash, nsec3.next, length) < 0) || 361 (scope >= 0 && 362 (order > 0 || 363 memcmp(hash, nsec3.next, length) < 0))) 364 { 365 dns_rdataset_disassociate(&set); 366 return (true); 367 } 368 } 369 dns_rdataset_disassociate(&set); 370 } 371 return (found); 372} 373 374/*% 375 * We have been asked to look for a key. 376 * If found, resume the validation process. 377 * If not found, fail the validation process. 378 */ 379static void 380fetch_callback_dnskey(isc_task_t *task, isc_event_t *event) { 381 dns_fetchevent_t *devent; 382 dns_validator_t *val; 383 dns_rdataset_t *rdataset; 384 bool want_destroy; 385 isc_result_t result; 386 isc_result_t eresult; 387 isc_result_t saved_result; 388 dns_fetch_t *fetch; 389 390 UNUSED(task); 391 INSIST(event->ev_type == DNS_EVENT_FETCHDONE); 392 devent = (dns_fetchevent_t *)event; 393 val = devent->ev_arg; 394 rdataset = &val->frdataset; 395 eresult = devent->result; 396 397 /* Free resources which are not of interest. */ 398 if (devent->node != NULL) { 399 dns_db_detachnode(devent->db, &devent->node); 400 } 401 if (devent->db != NULL) { 402 dns_db_detach(&devent->db); 403 } 404 if (dns_rdataset_isassociated(&val->fsigrdataset)) { 405 dns_rdataset_disassociate(&val->fsigrdataset); 406 } 407 isc_event_free(&event); 408 409 INSIST(val->event != NULL); 410 411 validator_log(val, ISC_LOG_DEBUG(3), "in fetch_callback_dnskey"); 412 LOCK(&val->lock); 413 fetch = val->fetch; 414 val->fetch = NULL; 415 if (CANCELED(val)) { 416 validator_done(val, ISC_R_CANCELED); 417 } else if (eresult == ISC_R_SUCCESS || eresult == DNS_R_NCACHENXRRSET) { 418 /* 419 * We have an answer to our DNSKEY query. Either the DNSKEY 420 * RRset or a NODATA response. 421 */ 422 validator_log(val, ISC_LOG_DEBUG(3), "%s with trust %s", 423 eresult == ISC_R_SUCCESS ? "keyset" 424 : "NCACHENXRRSET", 425 dns_trust_totext(rdataset->trust)); 426 /* 427 * Only extract the dst key if the keyset exists and is secure. 428 */ 429 if (eresult == ISC_R_SUCCESS && 430 rdataset->trust >= dns_trust_secure) 431 { 432 result = select_signing_key(val, rdataset); 433 if (result == ISC_R_SUCCESS) { 434 val->keyset = &val->frdataset; 435 } 436 } 437 result = validate_answer(val, true); 438 if (result == DNS_R_NOVALIDSIG && 439 (val->attributes & VALATTR_TRIEDVERIFY) == 0) 440 { 441 saved_result = result; 442 validator_log(val, ISC_LOG_DEBUG(3), 443 "falling back to insecurity proof"); 444 result = proveunsecure(val, false, false); 445 if (result == DNS_R_NOTINSECURE) { 446 result = saved_result; 447 } 448 } 449 if (result != DNS_R_WAIT) { 450 validator_done(val, result); 451 } 452 } else { 453 validator_log(val, ISC_LOG_DEBUG(3), 454 "fetch_callback_dnskey: got %s", 455 isc_result_totext(eresult)); 456 if (eresult == ISC_R_CANCELED) { 457 validator_done(val, eresult); 458 } else { 459 validator_done(val, DNS_R_BROKENCHAIN); 460 } 461 } 462 463 want_destroy = exit_check(val); 464 UNLOCK(&val->lock); 465 466 if (fetch != NULL) { 467 dns_resolver_destroyfetch(&fetch); 468 } 469 470 if (want_destroy) { 471 destroy(val); 472 } 473} 474 475/*% 476 * We have been asked to look for a DS. This may be part of 477 * walking a trust chain, or an insecurity proof. 478 */ 479static void 480fetch_callback_ds(isc_task_t *task, isc_event_t *event) { 481 dns_fetchevent_t *devent; 482 dns_validator_t *val; 483 dns_rdataset_t *rdataset; 484 bool want_destroy, trustchain; 485 isc_result_t result; 486 isc_result_t eresult; 487 dns_fetch_t *fetch; 488 489 UNUSED(task); 490 INSIST(event->ev_type == DNS_EVENT_FETCHDONE); 491 devent = (dns_fetchevent_t *)event; 492 val = devent->ev_arg; 493 rdataset = &val->frdataset; 494 eresult = devent->result; 495 496 /* 497 * Set 'trustchain' to true if we're walking a chain of 498 * trust; false if we're attempting to prove insecurity. 499 */ 500 trustchain = ((val->attributes & VALATTR_INSECURITY) == 0); 501 502 /* Free resources which are not of interest. */ 503 if (devent->node != NULL) { 504 dns_db_detachnode(devent->db, &devent->node); 505 } 506 if (devent->db != NULL) { 507 dns_db_detach(&devent->db); 508 } 509 if (dns_rdataset_isassociated(&val->fsigrdataset)) { 510 dns_rdataset_disassociate(&val->fsigrdataset); 511 } 512 513 INSIST(val->event != NULL); 514 515 validator_log(val, ISC_LOG_DEBUG(3), "in fetch_callback_ds"); 516 LOCK(&val->lock); 517 fetch = val->fetch; 518 val->fetch = NULL; 519 520 if (CANCELED(val)) { 521 validator_done(val, ISC_R_CANCELED); 522 goto done; 523 } 524 525 switch (eresult) { 526 case DNS_R_NXDOMAIN: 527 case DNS_R_NCACHENXDOMAIN: 528 /* 529 * These results only make sense if we're attempting 530 * an insecurity proof, not when walking a chain of trust. 531 */ 532 if (trustchain) { 533 goto unexpected; 534 } 535 536 FALLTHROUGH; 537 case ISC_R_SUCCESS: 538 if (trustchain) { 539 /* 540 * We looked for a DS record as part of 541 * following a key chain upwards; resume following 542 * the chain. 543 */ 544 validator_log(val, ISC_LOG_DEBUG(3), 545 "dsset with trust %s", 546 dns_trust_totext(rdataset->trust)); 547 val->dsset = &val->frdataset; 548 result = validate_dnskey(val); 549 if (result != DNS_R_WAIT) { 550 validator_done(val, result); 551 } 552 } else { 553 /* 554 * There is a DS which may or may not be a zone cut. 555 * In either case we are still in a secure zone, 556 * so keep looking for the break in the chain 557 * of trust. 558 */ 559 result = proveunsecure(val, (eresult == ISC_R_SUCCESS), 560 true); 561 if (result != DNS_R_WAIT) { 562 validator_done(val, result); 563 } 564 } 565 break; 566 case DNS_R_CNAME: 567 case DNS_R_NXRRSET: 568 case DNS_R_NCACHENXRRSET: 569 case DNS_R_SERVFAIL: /* RFC 1034 parent? */ 570 if (trustchain) { 571 /* 572 * Failed to find a DS while following the 573 * chain of trust; now we need to prove insecurity. 574 */ 575 validator_log(val, ISC_LOG_DEBUG(3), 576 "falling back to insecurity proof (%s)", 577 dns_result_totext(eresult)); 578 result = proveunsecure(val, false, false); 579 if (result != DNS_R_WAIT) { 580 validator_done(val, result); 581 } 582 } else if (eresult == DNS_R_SERVFAIL) { 583 goto unexpected; 584 } else if (eresult != DNS_R_CNAME && 585 isdelegation(dns_fixedname_name(&devent->foundname), 586 &val->frdataset, eresult)) 587 { 588 /* 589 * Failed to find a DS while trying to prove 590 * insecurity. If this is a zone cut, that 591 * means we're insecure. 592 */ 593 result = markanswer(val, "fetch_callback_ds", 594 "no DS and this is a delegation"); 595 validator_done(val, result); 596 } else { 597 /* 598 * Not a zone cut, so we have to keep looking for 599 * the break point in the chain of trust. 600 */ 601 result = proveunsecure(val, false, true); 602 if (result != DNS_R_WAIT) { 603 validator_done(val, result); 604 } 605 } 606 break; 607 608 default: 609 unexpected: 610 validator_log(val, ISC_LOG_DEBUG(3), 611 "fetch_callback_ds: got %s", 612 isc_result_totext(eresult)); 613 if (eresult == ISC_R_CANCELED) { 614 validator_done(val, eresult); 615 } else { 616 validator_done(val, DNS_R_BROKENCHAIN); 617 } 618 } 619done: 620 621 isc_event_free(&event); 622 want_destroy = exit_check(val); 623 UNLOCK(&val->lock); 624 625 if (fetch != NULL) { 626 dns_resolver_destroyfetch(&fetch); 627 } 628 629 if (want_destroy) { 630 destroy(val); 631 } 632} 633 634/*% 635 * Callback from when a DNSKEY RRset has been validated. 636 * 637 * Resumes the stalled validation process. 638 */ 639static void 640validator_callback_dnskey(isc_task_t *task, isc_event_t *event) { 641 dns_validatorevent_t *devent; 642 dns_validator_t *val; 643 bool want_destroy; 644 isc_result_t result; 645 isc_result_t eresult; 646 isc_result_t saved_result; 647 648 UNUSED(task); 649 INSIST(event->ev_type == DNS_EVENT_VALIDATORDONE); 650 651 devent = (dns_validatorevent_t *)event; 652 val = devent->ev_arg; 653 eresult = devent->result; 654 655 isc_event_free(&event); 656 dns_validator_destroy(&val->subvalidator); 657 658 INSIST(val->event != NULL); 659 660 validator_log(val, ISC_LOG_DEBUG(3), "in validator_callback_dnskey"); 661 LOCK(&val->lock); 662 if (CANCELED(val)) { 663 validator_done(val, ISC_R_CANCELED); 664 } else if (eresult == ISC_R_SUCCESS) { 665 validator_log(val, ISC_LOG_DEBUG(3), "keyset with trust %s", 666 dns_trust_totext(val->frdataset.trust)); 667 /* 668 * Only extract the dst key if the keyset is secure. 669 */ 670 if (val->frdataset.trust >= dns_trust_secure) { 671 (void)select_signing_key(val, &val->frdataset); 672 } 673 result = validate_answer(val, true); 674 if (result == DNS_R_NOVALIDSIG && 675 (val->attributes & VALATTR_TRIEDVERIFY) == 0) 676 { 677 saved_result = result; 678 validator_log(val, ISC_LOG_DEBUG(3), 679 "falling back to insecurity proof"); 680 result = proveunsecure(val, false, false); 681 if (result == DNS_R_NOTINSECURE) { 682 result = saved_result; 683 } 684 } 685 if (result != DNS_R_WAIT) { 686 validator_done(val, result); 687 } 688 } else { 689 if (eresult != DNS_R_BROKENCHAIN) { 690 expire_rdatasets(val); 691 } 692 validator_log(val, ISC_LOG_DEBUG(3), 693 "validator_callback_dnskey: got %s", 694 isc_result_totext(eresult)); 695 validator_done(val, DNS_R_BROKENCHAIN); 696 } 697 698 want_destroy = exit_check(val); 699 UNLOCK(&val->lock); 700 if (want_destroy) { 701 destroy(val); 702 } 703} 704 705/*% 706 * Callback when the DS record has been validated. 707 * 708 * Resumes validation of the zone key or the unsecure zone proof. 709 */ 710static void 711validator_callback_ds(isc_task_t *task, isc_event_t *event) { 712 dns_validatorevent_t *devent; 713 dns_validator_t *val; 714 bool want_destroy; 715 isc_result_t result; 716 isc_result_t eresult; 717 718 UNUSED(task); 719 INSIST(event->ev_type == DNS_EVENT_VALIDATORDONE); 720 721 devent = (dns_validatorevent_t *)event; 722 val = devent->ev_arg; 723 eresult = devent->result; 724 725 isc_event_free(&event); 726 dns_validator_destroy(&val->subvalidator); 727 728 INSIST(val->event != NULL); 729 730 validator_log(val, ISC_LOG_DEBUG(3), "in validator_callback_ds"); 731 LOCK(&val->lock); 732 if (CANCELED(val)) { 733 validator_done(val, ISC_R_CANCELED); 734 } else if (eresult == ISC_R_SUCCESS) { 735 bool have_dsset; 736 dns_name_t *name; 737 validator_log(val, ISC_LOG_DEBUG(3), "%s with trust %s", 738 val->frdataset.type == dns_rdatatype_ds ? "dsset" 739 : "ds " 740 "non-" 741 "existe" 742 "nce", 743 dns_trust_totext(val->frdataset.trust)); 744 have_dsset = (val->frdataset.type == dns_rdatatype_ds); 745 name = dns_fixedname_name(&val->fname); 746 if ((val->attributes & VALATTR_INSECURITY) != 0 && 747 val->frdataset.covers == dns_rdatatype_ds && 748 NEGATIVE(&val->frdataset) && 749 isdelegation(name, &val->frdataset, DNS_R_NCACHENXRRSET)) 750 { 751 result = markanswer(val, "validator_callback_ds", 752 "no DS and this is a delegation"); 753 } else if ((val->attributes & VALATTR_INSECURITY) != 0) { 754 result = proveunsecure(val, have_dsset, true); 755 } else { 756 result = validate_dnskey(val); 757 } 758 if (result != DNS_R_WAIT) { 759 validator_done(val, result); 760 } 761 } else { 762 if (eresult != DNS_R_BROKENCHAIN) { 763 expire_rdatasets(val); 764 } 765 validator_log(val, ISC_LOG_DEBUG(3), 766 "validator_callback_ds: got %s", 767 isc_result_totext(eresult)); 768 validator_done(val, DNS_R_BROKENCHAIN); 769 } 770 771 want_destroy = exit_check(val); 772 UNLOCK(&val->lock); 773 if (want_destroy) { 774 destroy(val); 775 } 776} 777 778/*% 779 * Callback when the CNAME record has been validated. 780 * 781 * Resumes validation of the unsecure zone proof. 782 */ 783static void 784validator_callback_cname(isc_task_t *task, isc_event_t *event) { 785 dns_validatorevent_t *devent; 786 dns_validator_t *val; 787 bool want_destroy; 788 isc_result_t result; 789 isc_result_t eresult; 790 791 UNUSED(task); 792 INSIST(event->ev_type == DNS_EVENT_VALIDATORDONE); 793 794 devent = (dns_validatorevent_t *)event; 795 val = devent->ev_arg; 796 eresult = devent->result; 797 798 isc_event_free(&event); 799 dns_validator_destroy(&val->subvalidator); 800 801 INSIST(val->event != NULL); 802 INSIST((val->attributes & VALATTR_INSECURITY) != 0); 803 804 validator_log(val, ISC_LOG_DEBUG(3), "in validator_callback_cname"); 805 LOCK(&val->lock); 806 if (CANCELED(val)) { 807 validator_done(val, ISC_R_CANCELED); 808 } else if (eresult == ISC_R_SUCCESS) { 809 validator_log(val, ISC_LOG_DEBUG(3), "cname with trust %s", 810 dns_trust_totext(val->frdataset.trust)); 811 result = proveunsecure(val, false, true); 812 if (result != DNS_R_WAIT) { 813 validator_done(val, result); 814 } 815 } else { 816 if (eresult != DNS_R_BROKENCHAIN) { 817 expire_rdatasets(val); 818 } 819 validator_log(val, ISC_LOG_DEBUG(3), 820 "validator_callback_cname: got %s", 821 isc_result_totext(eresult)); 822 validator_done(val, DNS_R_BROKENCHAIN); 823 } 824 825 want_destroy = exit_check(val); 826 UNLOCK(&val->lock); 827 if (want_destroy) { 828 destroy(val); 829 } 830} 831 832/*% 833 * Callback for when NSEC records have been validated. 834 * 835 * Looks for NOQNAME, NODATA and OPTOUT proofs. 836 * 837 * Resumes the negative response validation by calling validate_nx(). 838 */ 839static void 840validator_callback_nsec(isc_task_t *task, isc_event_t *event) { 841 dns_validatorevent_t *devent; 842 dns_validator_t *val; 843 dns_rdataset_t *rdataset; 844 bool want_destroy; 845 isc_result_t result; 846 bool exists, data; 847 848 UNUSED(task); 849 INSIST(event->ev_type == DNS_EVENT_VALIDATORDONE); 850 851 devent = (dns_validatorevent_t *)event; 852 rdataset = devent->rdataset; 853 val = devent->ev_arg; 854 result = devent->result; 855 dns_validator_destroy(&val->subvalidator); 856 857 INSIST(val->event != NULL); 858 859 validator_log(val, ISC_LOG_DEBUG(3), "in validator_callback_nsec"); 860 LOCK(&val->lock); 861 if (CANCELED(val)) { 862 validator_done(val, ISC_R_CANCELED); 863 } else if (result != ISC_R_SUCCESS) { 864 validator_log(val, ISC_LOG_DEBUG(3), 865 "validator_callback_nsec: got %s", 866 isc_result_totext(result)); 867 if (result == DNS_R_BROKENCHAIN) { 868 val->authfail++; 869 } 870 if (result == ISC_R_CANCELED) { 871 validator_done(val, result); 872 } else { 873 result = validate_nx(val, true); 874 if (result != DNS_R_WAIT) { 875 validator_done(val, result); 876 } 877 } 878 } else { 879 dns_name_t **proofs = val->event->proofs; 880 dns_name_t *wild = dns_fixedname_name(&val->wild); 881 882 if (rdataset->type == dns_rdatatype_nsec && 883 rdataset->trust == dns_trust_secure && 884 (NEEDNODATA(val) || NEEDNOQNAME(val)) && 885 !FOUNDNODATA(val) && !FOUNDNOQNAME(val) && 886 dns_nsec_noexistnodata(val->event->type, val->event->name, 887 devent->name, rdataset, &exists, 888 &data, wild, validator_log, 889 val) == ISC_R_SUCCESS) 890 { 891 if (exists && !data) { 892 val->attributes |= VALATTR_FOUNDNODATA; 893 if (NEEDNODATA(val)) { 894 proofs[DNS_VALIDATOR_NODATAPROOF] = 895 devent->name; 896 } 897 } 898 if (!exists) { 899 dns_name_t *closest; 900 unsigned int clabels; 901 902 val->attributes |= VALATTR_FOUNDNOQNAME; 903 904 closest = dns_fixedname_name(&val->closest); 905 clabels = dns_name_countlabels(closest); 906 /* 907 * If we are validating a wildcard response 908 * clabels will not be zero. We then need 909 * to check if the generated wildcard from 910 * dns_nsec_noexistnodata is consistent with 911 * the wildcard used to generate the response. 912 */ 913 if (clabels == 0 || 914 dns_name_countlabels(wild) == clabels + 1) 915 { 916 val->attributes |= VALATTR_FOUNDCLOSEST; 917 } 918 /* 919 * The NSEC noqname proof also contains 920 * the closest encloser. 921 */ 922 if (NEEDNOQNAME(val)) { 923 proofs[DNS_VALIDATOR_NOQNAMEPROOF] = 924 devent->name; 925 } 926 } 927 } 928 929 result = validate_nx(val, true); 930 if (result != DNS_R_WAIT) { 931 validator_done(val, result); 932 } 933 } 934 935 want_destroy = exit_check(val); 936 UNLOCK(&val->lock); 937 if (want_destroy) { 938 destroy(val); 939 } 940 941 /* 942 * Free stuff from the event. 943 */ 944 isc_event_free(&event); 945} 946 947/*% 948 * Looks for the requested name and type in the view (zones and cache). 949 * 950 * Returns: 951 * \li ISC_R_SUCCESS 952 * \li ISC_R_NOTFOUND 953 * \li DNS_R_NCACHENXDOMAIN 954 * \li DNS_R_NCACHENXRRSET 955 * \li DNS_R_NXRRSET 956 * \li DNS_R_NXDOMAIN 957 * \li DNS_R_BROKENCHAIN 958 */ 959static isc_result_t 960view_find(dns_validator_t *val, dns_name_t *name, dns_rdatatype_t type) { 961 dns_fixedname_t fixedname; 962 dns_name_t *foundname; 963 isc_result_t result; 964 unsigned int options; 965 isc_time_t now; 966 char namebuf[DNS_NAME_FORMATSIZE]; 967 char typebuf[DNS_RDATATYPE_FORMATSIZE]; 968 969 disassociate_rdatasets(val); 970 971 if (isc_time_now(&now) == ISC_R_SUCCESS && 972 dns_resolver_getbadcache(val->view->resolver, name, type, &now)) 973 { 974 dns_name_format(name, namebuf, sizeof(namebuf)); 975 dns_rdatatype_format(type, typebuf, sizeof(typebuf)); 976 validator_log(val, ISC_LOG_INFO, "bad cache hit (%s/%s)", 977 namebuf, typebuf); 978 return (DNS_R_BROKENCHAIN); 979 } 980 981 options = DNS_DBFIND_PENDINGOK; 982 foundname = dns_fixedname_initname(&fixedname); 983 result = dns_view_find(val->view, name, type, 0, options, false, false, 984 NULL, NULL, foundname, &val->frdataset, 985 &val->fsigrdataset); 986 987 if (result == DNS_R_NXDOMAIN) { 988 goto notfound; 989 } else if (result != ISC_R_SUCCESS && result != DNS_R_NCACHENXDOMAIN && 990 result != DNS_R_NCACHENXRRSET && result != DNS_R_EMPTYNAME && 991 result != DNS_R_NXRRSET && result != ISC_R_NOTFOUND) 992 { 993 result = ISC_R_NOTFOUND; 994 goto notfound; 995 } 996 997 return (result); 998 999notfound: 1000 disassociate_rdatasets(val); 1001 1002 return (result); 1003} 1004 1005/*% 1006 * Checks to make sure we are not going to loop. As we use a SHARED fetch 1007 * the validation process will stall if looping was to occur. 1008 */ 1009static bool 1010check_deadlock(dns_validator_t *val, dns_name_t *name, dns_rdatatype_t type, 1011 dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset) { 1012 dns_validator_t *parent; 1013 1014 for (parent = val; parent != NULL; parent = parent->parent) { 1015 if (parent->event != NULL && parent->event->type == type && 1016 dns_name_equal(parent->event->name, name) && 1017 /* 1018 * As NSEC3 records are meta data you sometimes 1019 * need to prove a NSEC3 record which says that 1020 * itself doesn't exist. 1021 */ 1022 (parent->event->type != dns_rdatatype_nsec3 || 1023 rdataset == NULL || sigrdataset == NULL || 1024 parent->event->message == NULL || 1025 parent->event->rdataset != NULL || 1026 parent->event->sigrdataset != NULL)) 1027 { 1028 validator_log(val, ISC_LOG_DEBUG(3), 1029 "continuing validation would lead to " 1030 "deadlock: aborting validation"); 1031 return (true); 1032 } 1033 } 1034 return (false); 1035} 1036 1037/*% 1038 * Start a fetch for the requested name and type. 1039 */ 1040static isc_result_t 1041create_fetch(dns_validator_t *val, dns_name_t *name, dns_rdatatype_t type, 1042 isc_taskaction_t callback, const char *caller) { 1043 unsigned int fopts = 0; 1044 1045 disassociate_rdatasets(val); 1046 1047 if (check_deadlock(val, name, type, NULL, NULL)) { 1048 validator_log(val, ISC_LOG_DEBUG(3), 1049 "deadlock found (create_fetch)"); 1050 return (DNS_R_NOVALIDSIG); 1051 } 1052 1053 if ((val->options & DNS_VALIDATOR_NOCDFLAG) != 0) { 1054 fopts |= DNS_FETCHOPT_NOCDFLAG; 1055 } 1056 1057 if ((val->options & DNS_VALIDATOR_NONTA) != 0) { 1058 fopts |= DNS_FETCHOPT_NONTA; 1059 } 1060 1061 validator_logcreate(val, name, type, caller, "fetch"); 1062 return (dns_resolver_createfetch( 1063 val->view->resolver, name, type, NULL, NULL, NULL, NULL, 0, 1064 fopts, 0, NULL, val->event->ev_sender, callback, val, 1065 &val->frdataset, &val->fsigrdataset, &val->fetch)); 1066} 1067 1068/*% 1069 * Start a subvalidation process. 1070 */ 1071static isc_result_t 1072create_validator(dns_validator_t *val, dns_name_t *name, dns_rdatatype_t type, 1073 dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset, 1074 isc_taskaction_t action, const char *caller) { 1075 isc_result_t result; 1076 unsigned int vopts = 0; 1077 dns_rdataset_t *sig = NULL; 1078 1079 if (sigrdataset != NULL && dns_rdataset_isassociated(sigrdataset)) { 1080 sig = sigrdataset; 1081 } 1082 1083 if (check_deadlock(val, name, type, rdataset, sig)) { 1084 validator_log(val, ISC_LOG_DEBUG(3), 1085 "deadlock found (create_validator)"); 1086 return (DNS_R_NOVALIDSIG); 1087 } 1088 1089 /* OK to clear other options, but preserve NOCDFLAG and NONTA. */ 1090 vopts |= (val->options & 1091 (DNS_VALIDATOR_NOCDFLAG | DNS_VALIDATOR_NONTA)); 1092 1093 validator_logcreate(val, name, type, caller, "validator"); 1094 result = dns_validator_create(val->view, name, type, rdataset, sig, 1095 NULL, vopts, val->task, action, val, 1096 &val->subvalidator); 1097 if (result == ISC_R_SUCCESS) { 1098 val->subvalidator->parent = val; 1099 val->subvalidator->depth = val->depth + 1; 1100 } 1101 return (result); 1102} 1103 1104/*% 1105 * Try to find a key that could have signed val->siginfo among those in 1106 * 'rdataset'. If found, build a dst_key_t for it and point val->key at 1107 * it. 1108 * 1109 * If val->key is already non-NULL, locate it in the rdataset and then 1110 * search past it for the *next* key that could have signed 'siginfo', then 1111 * set val->key to that. 1112 * 1113 * Returns ISC_R_SUCCESS if a possible matching key has been found, 1114 * ISC_R_NOTFOUND if not. Any other value indicates error. 1115 */ 1116static isc_result_t 1117select_signing_key(dns_validator_t *val, dns_rdataset_t *rdataset) { 1118 isc_result_t result; 1119 dns_rdata_rrsig_t *siginfo = val->siginfo; 1120 isc_buffer_t b; 1121 dns_rdata_t rdata = DNS_RDATA_INIT; 1122 dst_key_t *oldkey = val->key; 1123 bool foundold; 1124 1125 if (oldkey == NULL) { 1126 foundold = true; 1127 } else { 1128 foundold = false; 1129 val->key = NULL; 1130 } 1131 1132 result = dns_rdataset_first(rdataset); 1133 if (result != ISC_R_SUCCESS) { 1134 goto failure; 1135 } 1136 do { 1137 dns_rdataset_current(rdataset, &rdata); 1138 1139 isc_buffer_init(&b, rdata.data, rdata.length); 1140 isc_buffer_add(&b, rdata.length); 1141 INSIST(val->key == NULL); 1142 result = dst_key_fromdns(&siginfo->signer, rdata.rdclass, &b, 1143 val->view->mctx, &val->key); 1144 if (result == ISC_R_SUCCESS) { 1145 if (siginfo->algorithm == 1146 (dns_secalg_t)dst_key_alg(val->key) && 1147 siginfo->keyid == 1148 (dns_keytag_t)dst_key_id(val->key) && 1149 dst_key_iszonekey(val->key)) 1150 { 1151 if (foundold) { 1152 /* 1153 * This is the key we're looking for. 1154 */ 1155 return (ISC_R_SUCCESS); 1156 } else if (dst_key_compare(oldkey, val->key)) { 1157 foundold = true; 1158 dst_key_free(&oldkey); 1159 } 1160 } 1161 dst_key_free(&val->key); 1162 } 1163 dns_rdata_reset(&rdata); 1164 result = dns_rdataset_next(rdataset); 1165 } while (result == ISC_R_SUCCESS); 1166 1167 if (result == ISC_R_NOMORE) { 1168 result = ISC_R_NOTFOUND; 1169 } 1170 1171failure: 1172 if (oldkey != NULL) { 1173 dst_key_free(&oldkey); 1174 } 1175 1176 return (result); 1177} 1178 1179/*% 1180 * Get the key that generated the signature in val->siginfo. 1181 */ 1182static isc_result_t 1183seek_dnskey(dns_validator_t *val) { 1184 isc_result_t result; 1185 dns_rdata_rrsig_t *siginfo = val->siginfo; 1186 unsigned int nlabels; 1187 int order; 1188 dns_namereln_t namereln; 1189 1190 /* 1191 * Is the signer name appropriate for this signature? 1192 * 1193 * The signer name must be at the same level as the owner name 1194 * or closer to the DNS root. 1195 */ 1196 namereln = dns_name_fullcompare(val->event->name, &siginfo->signer, 1197 &order, &nlabels); 1198 if (namereln != dns_namereln_subdomain && 1199 namereln != dns_namereln_equal) 1200 { 1201 return (DNS_R_CONTINUE); 1202 } 1203 1204 if (namereln == dns_namereln_equal) { 1205 /* 1206 * If this is a self-signed keyset, it must not be a zone key 1207 * (since seek_dnskey is not called from validate_dnskey). 1208 */ 1209 if (val->event->rdataset->type == dns_rdatatype_dnskey) { 1210 return (DNS_R_CONTINUE); 1211 } 1212 1213 /* 1214 * Records appearing in the parent zone at delegation 1215 * points cannot be self-signed. 1216 */ 1217 if (dns_rdatatype_atparent(val->event->rdataset->type)) { 1218 return (DNS_R_CONTINUE); 1219 } 1220 } else { 1221 /* 1222 * SOA and NS RRsets can only be signed by a key with 1223 * the same name. 1224 */ 1225 if (val->event->rdataset->type == dns_rdatatype_soa || 1226 val->event->rdataset->type == dns_rdatatype_ns) 1227 { 1228 const char *type; 1229 1230 if (val->event->rdataset->type == dns_rdatatype_soa) { 1231 type = "SOA"; 1232 } else { 1233 type = "NS"; 1234 } 1235 validator_log(val, ISC_LOG_DEBUG(3), 1236 "%s signer mismatch", type); 1237 return (DNS_R_CONTINUE); 1238 } 1239 } 1240 1241 /* 1242 * Do we know about this key? 1243 */ 1244 result = view_find(val, &siginfo->signer, dns_rdatatype_dnskey); 1245 switch (result) { 1246 case ISC_R_SUCCESS: 1247 /* 1248 * We have an rrset for the given keyname. 1249 */ 1250 val->keyset = &val->frdataset; 1251 if ((DNS_TRUST_PENDING(val->frdataset.trust) || 1252 DNS_TRUST_ANSWER(val->frdataset.trust)) && 1253 dns_rdataset_isassociated(&val->fsigrdataset)) 1254 { 1255 /* 1256 * We know the key but haven't validated it yet or 1257 * we have a key of trust answer but a DS 1258 * record for the zone may have been added. 1259 */ 1260 result = create_validator( 1261 val, &siginfo->signer, dns_rdatatype_dnskey, 1262 &val->frdataset, &val->fsigrdataset, 1263 validator_callback_dnskey, "seek_dnskey"); 1264 if (result != ISC_R_SUCCESS) { 1265 return (result); 1266 } 1267 return (DNS_R_WAIT); 1268 } else if (DNS_TRUST_PENDING(val->frdataset.trust)) { 1269 /* 1270 * Having a pending key with no signature means that 1271 * something is broken. 1272 */ 1273 result = DNS_R_CONTINUE; 1274 } else if (val->frdataset.trust < dns_trust_secure) { 1275 /* 1276 * The key is legitimately insecure. There's no 1277 * point in even attempting verification. 1278 */ 1279 val->key = NULL; 1280 result = ISC_R_SUCCESS; 1281 } else { 1282 /* 1283 * See if we've got the key used in the signature. 1284 */ 1285 validator_log(val, ISC_LOG_DEBUG(3), 1286 "keyset with trust %s", 1287 dns_trust_totext(val->frdataset.trust)); 1288 result = select_signing_key(val, val->keyset); 1289 if (result != ISC_R_SUCCESS) { 1290 /* 1291 * Either the key we're looking for is not 1292 * in the rrset, or something bad happened. 1293 * Give up. 1294 */ 1295 result = DNS_R_CONTINUE; 1296 } 1297 } 1298 break; 1299 1300 case ISC_R_NOTFOUND: 1301 /* 1302 * We don't know anything about this key. 1303 */ 1304 result = create_fetch(val, &siginfo->signer, 1305 dns_rdatatype_dnskey, 1306 fetch_callback_dnskey, "seek_dnskey"); 1307 if (result != ISC_R_SUCCESS) { 1308 return (result); 1309 } 1310 return (DNS_R_WAIT); 1311 1312 case DNS_R_NCACHENXDOMAIN: 1313 case DNS_R_NCACHENXRRSET: 1314 case DNS_R_EMPTYNAME: 1315 case DNS_R_NXDOMAIN: 1316 case DNS_R_NXRRSET: 1317 /* 1318 * This key doesn't exist. 1319 */ 1320 result = DNS_R_CONTINUE; 1321 break; 1322 1323 case DNS_R_BROKENCHAIN: 1324 return (result); 1325 1326 default: 1327 break; 1328 } 1329 1330 if (dns_rdataset_isassociated(&val->frdataset) && 1331 val->keyset != &val->frdataset) 1332 { 1333 dns_rdataset_disassociate(&val->frdataset); 1334 } 1335 if (dns_rdataset_isassociated(&val->fsigrdataset)) { 1336 dns_rdataset_disassociate(&val->fsigrdataset); 1337 } 1338 1339 return (result); 1340} 1341 1342/* 1343 * Compute the tag for a key represented in a DNSKEY rdata. 1344 */ 1345static dns_keytag_t 1346compute_keytag(dns_rdata_t *rdata) { 1347 isc_region_t r; 1348 1349 dns_rdata_toregion(rdata, &r); 1350 return (dst_region_computeid(&r)); 1351} 1352 1353/*% 1354 * Is the DNSKEY rrset in val->event->rdataset self-signed? 1355 */ 1356static bool 1357selfsigned_dnskey(dns_validator_t *val) { 1358 dns_rdataset_t *rdataset = val->event->rdataset; 1359 dns_rdataset_t *sigrdataset = val->event->sigrdataset; 1360 dns_name_t *name = val->event->name; 1361 isc_result_t result; 1362 isc_mem_t *mctx = val->view->mctx; 1363 bool answer = false; 1364 1365 if (rdataset->type != dns_rdatatype_dnskey) { 1366 return (false); 1367 } 1368 1369 for (result = dns_rdataset_first(rdataset); result == ISC_R_SUCCESS; 1370 result = dns_rdataset_next(rdataset)) 1371 { 1372 dns_rdata_t keyrdata = DNS_RDATA_INIT; 1373 dns_rdata_t sigrdata = DNS_RDATA_INIT; 1374 dns_rdata_dnskey_t key; 1375 dns_rdata_rrsig_t sig; 1376 dns_keytag_t keytag; 1377 1378 dns_rdata_reset(&keyrdata); 1379 dns_rdataset_current(rdataset, &keyrdata); 1380 result = dns_rdata_tostruct(&keyrdata, &key, NULL); 1381 RUNTIME_CHECK(result == ISC_R_SUCCESS); 1382 keytag = compute_keytag(&keyrdata); 1383 1384 for (result = dns_rdataset_first(sigrdataset); 1385 result == ISC_R_SUCCESS; 1386 result = dns_rdataset_next(sigrdataset)) 1387 { 1388 dst_key_t *dstkey = NULL; 1389 1390 dns_rdata_reset(&sigrdata); 1391 dns_rdataset_current(sigrdataset, &sigrdata); 1392 result = dns_rdata_tostruct(&sigrdata, &sig, NULL); 1393 RUNTIME_CHECK(result == ISC_R_SUCCESS); 1394 1395 if (sig.algorithm != key.algorithm || 1396 sig.keyid != keytag || 1397 !dns_name_equal(name, &sig.signer)) 1398 { 1399 continue; 1400 } 1401 1402 /* 1403 * If the REVOKE bit is not set we have a 1404 * theoretically self signed DNSKEY RRset. 1405 * This will be verified later. 1406 */ 1407 if ((key.flags & DNS_KEYFLAG_REVOKE) == 0) { 1408 answer = true; 1409 continue; 1410 } 1411 1412 result = dns_dnssec_keyfromrdata(name, &keyrdata, mctx, 1413 &dstkey); 1414 if (result != ISC_R_SUCCESS) { 1415 continue; 1416 } 1417 1418 /* 1419 * If this RRset is pending and it is trusted, 1420 * see if it was self signed by this DNSKEY. 1421 */ 1422 if (DNS_TRUST_PENDING(rdataset->trust) && 1423 dns_view_istrusted(val->view, name, &key)) 1424 { 1425 result = dns_dnssec_verify( 1426 name, rdataset, dstkey, true, 1427 val->view->maxbits, mctx, &sigrdata, 1428 NULL); 1429 if (result == ISC_R_SUCCESS) { 1430 /* 1431 * The key with the REVOKE flag has 1432 * self signed the RRset so it is no 1433 * good. 1434 */ 1435 dns_view_untrust(val->view, name, &key); 1436 } 1437 } else if (rdataset->trust >= dns_trust_secure) { 1438 /* 1439 * We trust this RRset so if the key is 1440 * marked revoked remove it. 1441 */ 1442 dns_view_untrust(val->view, name, &key); 1443 } 1444 1445 dst_key_free(&dstkey); 1446 } 1447 } 1448 1449 return (answer); 1450} 1451 1452/*% 1453 * Attempt to verify the rdataset using the given key and rdata (RRSIG). 1454 * The signature was good and from a wildcard record and the QNAME does 1455 * not match the wildcard we need to look for a NOQNAME proof. 1456 * 1457 * Returns: 1458 * \li ISC_R_SUCCESS if the verification succeeds. 1459 * \li Others if the verification fails. 1460 */ 1461static isc_result_t 1462verify(dns_validator_t *val, dst_key_t *key, dns_rdata_t *rdata, 1463 uint16_t keyid) { 1464 isc_result_t result; 1465 dns_fixedname_t fixed; 1466 bool ignore = false; 1467 dns_name_t *wild; 1468 1469 val->attributes |= VALATTR_TRIEDVERIFY; 1470 wild = dns_fixedname_initname(&fixed); 1471again: 1472 result = dns_dnssec_verify(val->event->name, val->event->rdataset, key, 1473 ignore, val->view->maxbits, val->view->mctx, 1474 rdata, wild); 1475 if ((result == DNS_R_SIGEXPIRED || result == DNS_R_SIGFUTURE) && 1476 val->view->acceptexpired) 1477 { 1478 ignore = true; 1479 goto again; 1480 } 1481 1482 if (ignore && (result == ISC_R_SUCCESS || result == DNS_R_FROMWILDCARD)) 1483 { 1484 validator_log(val, ISC_LOG_INFO, 1485 "accepted expired %sRRSIG (keyid=%u)", 1486 (result == DNS_R_FROMWILDCARD) ? "wildcard " : "", 1487 keyid); 1488 } else if (result == DNS_R_SIGEXPIRED || result == DNS_R_SIGFUTURE) { 1489 validator_log(val, ISC_LOG_INFO, 1490 "verify failed due to bad signature (keyid=%u): " 1491 "%s", 1492 keyid, isc_result_totext(result)); 1493 } else { 1494 validator_log(val, ISC_LOG_DEBUG(3), 1495 "verify rdataset (keyid=%u): %s", keyid, 1496 isc_result_totext(result)); 1497 } 1498 if (result == DNS_R_FROMWILDCARD) { 1499 if (!dns_name_equal(val->event->name, wild)) { 1500 dns_name_t *closest; 1501 unsigned int labels; 1502 1503 /* 1504 * Compute the closest encloser in case we need it 1505 * for the NSEC3 NOQNAME proof. 1506 */ 1507 closest = dns_fixedname_name(&val->closest); 1508 dns_name_copynf(wild, closest); 1509 labels = dns_name_countlabels(closest) - 1; 1510 dns_name_getlabelsequence(closest, 1, labels, closest); 1511 val->attributes |= VALATTR_NEEDNOQNAME; 1512 } 1513 result = ISC_R_SUCCESS; 1514 } 1515 return (result); 1516} 1517 1518/*% 1519 * Attempts positive response validation of a normal RRset. 1520 * 1521 * Returns: 1522 * \li ISC_R_SUCCESS Validation completed successfully 1523 * \li DNS_R_WAIT Validation has started but is waiting 1524 * for an event. 1525 * \li Other return codes are possible and all indicate failure. 1526 */ 1527static isc_result_t 1528validate_answer(dns_validator_t *val, bool resume) { 1529 isc_result_t result, vresult = DNS_R_NOVALIDSIG; 1530 dns_validatorevent_t *event; 1531 dns_rdata_t rdata = DNS_RDATA_INIT; 1532 1533 /* 1534 * Caller must be holding the validator lock. 1535 */ 1536 1537 event = val->event; 1538 1539 if (resume) { 1540 /* 1541 * We already have a sigrdataset. 1542 */ 1543 result = ISC_R_SUCCESS; 1544 validator_log(val, ISC_LOG_DEBUG(3), "resuming validate"); 1545 } else { 1546 result = dns_rdataset_first(event->sigrdataset); 1547 } 1548 1549 for (; result == ISC_R_SUCCESS; 1550 result = dns_rdataset_next(event->sigrdataset)) 1551 { 1552 dns_rdata_reset(&rdata); 1553 dns_rdataset_current(event->sigrdataset, &rdata); 1554 if (val->siginfo == NULL) { 1555 val->siginfo = isc_mem_get(val->view->mctx, 1556 sizeof(*val->siginfo)); 1557 } 1558 result = dns_rdata_tostruct(&rdata, val->siginfo, NULL); 1559 if (result != ISC_R_SUCCESS) { 1560 return (result); 1561 } 1562 1563 /* 1564 * At this point we could check that the signature algorithm 1565 * was known and "sufficiently good". 1566 */ 1567 if (!dns_resolver_algorithm_supported(val->view->resolver, 1568 event->name, 1569 val->siginfo->algorithm)) 1570 { 1571 resume = false; 1572 continue; 1573 } 1574 1575 if (!resume) { 1576 result = seek_dnskey(val); 1577 if (result == DNS_R_CONTINUE) { 1578 continue; /* Try the next SIG RR. */ 1579 } 1580 if (result != ISC_R_SUCCESS) { 1581 return (result); 1582 } 1583 } 1584 1585 /* 1586 * There isn't a secure DNSKEY for this signature so move 1587 * onto the next RRSIG. 1588 */ 1589 if (val->key == NULL) { 1590 resume = false; 1591 continue; 1592 } 1593 1594 do { 1595 isc_result_t tresult; 1596 vresult = verify(val, val->key, &rdata, 1597 val->siginfo->keyid); 1598 if (vresult == ISC_R_SUCCESS) { 1599 break; 1600 } 1601 1602 tresult = select_signing_key(val, val->keyset); 1603 if (tresult != ISC_R_SUCCESS) { 1604 break; 1605 } 1606 } while (1); 1607 if (vresult != ISC_R_SUCCESS) { 1608 validator_log(val, ISC_LOG_DEBUG(3), 1609 "failed to verify rdataset"); 1610 } else { 1611 dns_rdataset_trimttl(event->rdataset, 1612 event->sigrdataset, val->siginfo, 1613 val->start, 1614 val->view->acceptexpired); 1615 } 1616 1617 if (val->key != NULL) { 1618 dst_key_free(&val->key); 1619 } 1620 if (val->keyset != NULL) { 1621 dns_rdataset_disassociate(val->keyset); 1622 val->keyset = NULL; 1623 } 1624 val->key = NULL; 1625 if (NEEDNOQNAME(val)) { 1626 if (val->event->message == NULL) { 1627 validator_log(val, ISC_LOG_DEBUG(3), 1628 "no message available " 1629 "for noqname proof"); 1630 return (DNS_R_NOVALIDSIG); 1631 } 1632 validator_log(val, ISC_LOG_DEBUG(3), 1633 "looking for noqname proof"); 1634 return (validate_nx(val, false)); 1635 } else if (vresult == ISC_R_SUCCESS) { 1636 marksecure(event); 1637 validator_log(val, ISC_LOG_DEBUG(3), 1638 "marking as secure, " 1639 "noqname proof not needed"); 1640 return (ISC_R_SUCCESS); 1641 } else { 1642 validator_log(val, ISC_LOG_DEBUG(3), 1643 "verify failure: %s", 1644 isc_result_totext(result)); 1645 resume = false; 1646 } 1647 } 1648 if (result != ISC_R_NOMORE) { 1649 validator_log(val, ISC_LOG_DEBUG(3), 1650 "failed to iterate signatures: %s", 1651 isc_result_totext(result)); 1652 return (result); 1653 } 1654 1655 validator_log(val, ISC_LOG_INFO, "no valid signature found"); 1656 return (vresult); 1657} 1658 1659/*% 1660 * Check whether this DNSKEY (keyrdata) signed the DNSKEY RRset 1661 * (val->event->rdataset). 1662 */ 1663static isc_result_t 1664check_signer(dns_validator_t *val, dns_rdata_t *keyrdata, uint16_t keyid, 1665 dns_secalg_t algorithm) { 1666 dns_rdata_rrsig_t sig; 1667 dst_key_t *dstkey = NULL; 1668 isc_result_t result; 1669 1670 for (result = dns_rdataset_first(val->event->sigrdataset); 1671 result == ISC_R_SUCCESS; 1672 result = dns_rdataset_next(val->event->sigrdataset)) 1673 { 1674 dns_rdata_t rdata = DNS_RDATA_INIT; 1675 1676 dns_rdataset_current(val->event->sigrdataset, &rdata); 1677 result = dns_rdata_tostruct(&rdata, &sig, NULL); 1678 RUNTIME_CHECK(result == ISC_R_SUCCESS); 1679 if (keyid != sig.keyid || algorithm != sig.algorithm) { 1680 continue; 1681 } 1682 if (dstkey == NULL) { 1683 result = dns_dnssec_keyfromrdata( 1684 val->event->name, keyrdata, val->view->mctx, 1685 &dstkey); 1686 if (result != ISC_R_SUCCESS) { 1687 /* 1688 * This really shouldn't happen, but... 1689 */ 1690 continue; 1691 } 1692 } 1693 result = verify(val, dstkey, &rdata, sig.keyid); 1694 if (result == ISC_R_SUCCESS) { 1695 break; 1696 } 1697 } 1698 1699 if (dstkey != NULL) { 1700 dst_key_free(&dstkey); 1701 } 1702 1703 return (result); 1704} 1705 1706/* 1707 * get_dsset() is called to look up a DS RRset corresponding to the name 1708 * of a DNSKEY record, either in the cache or, if necessary, by starting a 1709 * fetch. This is done in the context of validating a zone key to build a 1710 * trust chain. 1711 * 1712 * Returns: 1713 * \li ISC_R_COMPLETE a DS has not been found; the caller should 1714 * stop trying to validate the zone key and 1715 * return the result code in '*resp'. 1716 * \li DNS_R_CONTINUE a DS has been found and the caller may 1717 * continue the zone key validation. 1718 */ 1719static isc_result_t 1720get_dsset(dns_validator_t *val, dns_name_t *tname, isc_result_t *resp) { 1721 isc_result_t result; 1722 1723 result = view_find(val, tname, dns_rdatatype_ds); 1724 switch (result) { 1725 case ISC_R_SUCCESS: 1726 /* 1727 * We have a DS RRset. 1728 */ 1729 val->dsset = &val->frdataset; 1730 if ((DNS_TRUST_PENDING(val->frdataset.trust) || 1731 DNS_TRUST_ANSWER(val->frdataset.trust)) && 1732 dns_rdataset_isassociated(&val->fsigrdataset)) 1733 { 1734 /* 1735 * ... which is signed but not yet validated. 1736 */ 1737 result = create_validator( 1738 val, tname, dns_rdatatype_ds, &val->frdataset, 1739 &val->fsigrdataset, validator_callback_ds, 1740 "validate_dnskey"); 1741 *resp = DNS_R_WAIT; 1742 if (result != ISC_R_SUCCESS) { 1743 *resp = result; 1744 } 1745 return (ISC_R_COMPLETE); 1746 } else if (DNS_TRUST_PENDING(val->frdataset.trust)) { 1747 /* 1748 * There should never be an unsigned DS. 1749 */ 1750 disassociate_rdatasets(val); 1751 validator_log(val, ISC_LOG_DEBUG(2), 1752 "unsigned DS record"); 1753 *resp = DNS_R_NOVALIDSIG; 1754 return (ISC_R_COMPLETE); 1755 } 1756 break; 1757 1758 case ISC_R_NOTFOUND: 1759 /* 1760 * We don't have the DS. Find it. 1761 */ 1762 result = create_fetch(val, tname, dns_rdatatype_ds, 1763 fetch_callback_ds, "validate_dnskey"); 1764 *resp = DNS_R_WAIT; 1765 if (result != ISC_R_SUCCESS) { 1766 *resp = result; 1767 } 1768 return (ISC_R_COMPLETE); 1769 1770 case DNS_R_NCACHENXDOMAIN: 1771 case DNS_R_NCACHENXRRSET: 1772 case DNS_R_EMPTYNAME: 1773 case DNS_R_NXDOMAIN: 1774 case DNS_R_NXRRSET: 1775 case DNS_R_CNAME: 1776 /* 1777 * The DS does not exist. 1778 */ 1779 disassociate_rdatasets(val); 1780 validator_log(val, ISC_LOG_DEBUG(2), "no DS record"); 1781 *resp = DNS_R_NOVALIDSIG; 1782 return (ISC_R_COMPLETE); 1783 1784 case DNS_R_BROKENCHAIN: 1785 *resp = result; 1786 return (ISC_R_COMPLETE); 1787 1788 default: 1789 break; 1790 } 1791 1792 return (DNS_R_CONTINUE); 1793} 1794 1795/*% 1796 * Attempts positive response validation of an RRset containing zone keys 1797 * (i.e. a DNSKEY rrset). 1798 * 1799 * Caller must be holding the validator lock. 1800 * 1801 * Returns: 1802 * \li ISC_R_SUCCESS Validation completed successfully 1803 * \li DNS_R_WAIT Validation has started but is waiting 1804 * for an event. 1805 * \li Other return codes are possible and all indicate failure. 1806 */ 1807static isc_result_t 1808validate_dnskey(dns_validator_t *val) { 1809 isc_result_t result; 1810 dns_rdata_t dsrdata = DNS_RDATA_INIT; 1811 dns_rdata_t keyrdata = DNS_RDATA_INIT; 1812 dns_keynode_t *keynode = NULL; 1813 dns_rdata_ds_t ds; 1814 bool supported_algorithm; 1815 char digest_types[256]; 1816 1817 /* 1818 * If we don't already have a DS RRset, check to see if there's 1819 * a DS style trust anchor configured for this key. 1820 */ 1821 if (val->dsset == NULL) { 1822 result = dns_keytable_find(val->keytable, val->event->name, 1823 &keynode); 1824 if (result == ISC_R_SUCCESS) { 1825 if (dns_keynode_dsset(keynode, &val->fdsset)) { 1826 val->dsset = &val->fdsset; 1827 } 1828 dns_keytable_detachkeynode(val->keytable, &keynode); 1829 } 1830 } 1831 1832 /* 1833 * No trust anchor for this name, so we look up the DS at the parent. 1834 */ 1835 if (val->dsset == NULL) { 1836 isc_result_t tresult = ISC_R_SUCCESS; 1837 1838 /* 1839 * If this is the root name and there was no trust anchor, 1840 * we can give up now, since there's no DS at the root. 1841 */ 1842 if (dns_name_equal(val->event->name, dns_rootname)) { 1843 if ((val->attributes & VALATTR_TRIEDVERIFY) != 0) { 1844 validator_log(val, ISC_LOG_DEBUG(3), 1845 "root key failed to validate"); 1846 } else { 1847 validator_log(val, ISC_LOG_DEBUG(3), 1848 "no trusted root key"); 1849 } 1850 result = DNS_R_NOVALIDSIG; 1851 goto cleanup; 1852 } 1853 1854 /* 1855 * Look up the DS RRset for this name. 1856 */ 1857 result = get_dsset(val, val->event->name, &tresult); 1858 if (result == ISC_R_COMPLETE) { 1859 result = tresult; 1860 goto cleanup; 1861 } 1862 } 1863 1864 /* 1865 * We have a DS set. 1866 */ 1867 INSIST(val->dsset != NULL); 1868 1869 if (val->dsset->trust < dns_trust_secure) { 1870 result = markanswer(val, "validate_dnskey (2)", "insecure DS"); 1871 goto cleanup; 1872 } 1873 1874 /* 1875 * Look through the DS record and find the keys that can sign the 1876 * key set and the matching signature. For each such key, attempt 1877 * verification. 1878 */ 1879 1880 supported_algorithm = false; 1881 1882 /* 1883 * If DNS_DSDIGEST_SHA256 or DNS_DSDIGEST_SHA384 is present we 1884 * are required to prefer it over DNS_DSDIGEST_SHA1. This in 1885 * practice means that we need to ignore DNS_DSDIGEST_SHA1 if a 1886 * DNS_DSDIGEST_SHA256 or DNS_DSDIGEST_SHA384 is present. 1887 */ 1888 memset(digest_types, 1, sizeof(digest_types)); 1889 for (result = dns_rdataset_first(val->dsset); result == ISC_R_SUCCESS; 1890 result = dns_rdataset_next(val->dsset)) 1891 { 1892 dns_rdata_reset(&dsrdata); 1893 dns_rdataset_current(val->dsset, &dsrdata); 1894 result = dns_rdata_tostruct(&dsrdata, &ds, NULL); 1895 RUNTIME_CHECK(result == ISC_R_SUCCESS); 1896 1897 if (!dns_resolver_ds_digest_supported(val->view->resolver, 1898 val->event->name, 1899 ds.digest_type)) 1900 { 1901 continue; 1902 } 1903 1904 if (!dns_resolver_algorithm_supported(val->view->resolver, 1905 val->event->name, 1906 ds.algorithm)) 1907 { 1908 continue; 1909 } 1910 1911 if ((ds.digest_type == DNS_DSDIGEST_SHA256 && 1912 ds.length == ISC_SHA256_DIGESTLENGTH) || 1913 (ds.digest_type == DNS_DSDIGEST_SHA384 && 1914 ds.length == ISC_SHA384_DIGESTLENGTH)) 1915 { 1916 digest_types[DNS_DSDIGEST_SHA1] = 0; 1917 break; 1918 } 1919 } 1920 1921 for (result = dns_rdataset_first(val->dsset); result == ISC_R_SUCCESS; 1922 result = dns_rdataset_next(val->dsset)) 1923 { 1924 dns_rdata_reset(&dsrdata); 1925 dns_rdataset_current(val->dsset, &dsrdata); 1926 result = dns_rdata_tostruct(&dsrdata, &ds, NULL); 1927 RUNTIME_CHECK(result == ISC_R_SUCCESS); 1928 1929 if (digest_types[ds.digest_type] == 0) { 1930 continue; 1931 } 1932 1933 if (!dns_resolver_ds_digest_supported(val->view->resolver, 1934 val->event->name, 1935 ds.digest_type)) 1936 { 1937 continue; 1938 } 1939 1940 if (!dns_resolver_algorithm_supported(val->view->resolver, 1941 val->event->name, 1942 ds.algorithm)) 1943 { 1944 continue; 1945 } 1946 1947 supported_algorithm = true; 1948 1949 /* 1950 * Find the DNSKEY matching the DS... 1951 */ 1952 result = dns_dnssec_matchdskey(val->event->name, &dsrdata, 1953 val->event->rdataset, &keyrdata); 1954 if (result != ISC_R_SUCCESS) { 1955 validator_log(val, ISC_LOG_DEBUG(3), 1956 "no DNSKEY matching DS"); 1957 continue; 1958 } 1959 1960 /* 1961 * ... and check that it signed the DNSKEY RRset. 1962 */ 1963 result = check_signer(val, &keyrdata, ds.key_tag, ds.algorithm); 1964 if (result == ISC_R_SUCCESS) { 1965 break; 1966 } 1967 validator_log(val, ISC_LOG_DEBUG(3), 1968 "no RRSIG matching DS key"); 1969 } 1970 1971 if (result == ISC_R_SUCCESS) { 1972 marksecure(val->event); 1973 validator_log(val, ISC_LOG_DEBUG(3), "marking as secure (DS)"); 1974 } else if (result == ISC_R_NOMORE && !supported_algorithm) { 1975 validator_log(val, ISC_LOG_DEBUG(3), 1976 "no supported algorithm/digest (DS)"); 1977 result = markanswer(val, "validate_dnskey (3)", 1978 "no supported algorithm/digest (DS)"); 1979 } else { 1980 validator_log(val, ISC_LOG_INFO, 1981 "no valid signature found (DS)"); 1982 result = DNS_R_NOVALIDSIG; 1983 } 1984 1985cleanup: 1986 if (val->dsset == &val->fdsset) { 1987 val->dsset = NULL; 1988 dns_rdataset_disassociate(&val->fdsset); 1989 } 1990 1991 return (result); 1992} 1993 1994/*% 1995 * val_rdataset_first and val_rdataset_next provide iteration methods 1996 * that hide whether we are iterating across the AUTHORITY section of 1997 * a message, or a negative cache rdataset. 1998 */ 1999static isc_result_t 2000val_rdataset_first(dns_validator_t *val, dns_name_t **namep, 2001 dns_rdataset_t **rdatasetp) { 2002 dns_message_t *message = val->event->message; 2003 isc_result_t result; 2004 2005 REQUIRE(rdatasetp != NULL); 2006 REQUIRE(namep != NULL); 2007 if (message == NULL) { 2008 REQUIRE(*rdatasetp != NULL); 2009 REQUIRE(*namep != NULL); 2010 } else { 2011 REQUIRE(*rdatasetp == NULL); 2012 REQUIRE(*namep == NULL); 2013 } 2014 2015 if (message != NULL) { 2016 result = dns_message_firstname(message, DNS_SECTION_AUTHORITY); 2017 if (result != ISC_R_SUCCESS) { 2018 return (result); 2019 } 2020 dns_message_currentname(message, DNS_SECTION_AUTHORITY, namep); 2021 *rdatasetp = ISC_LIST_HEAD((*namep)->list); 2022 INSIST(*rdatasetp != NULL); 2023 } else { 2024 result = dns_rdataset_first(val->event->rdataset); 2025 if (result == ISC_R_SUCCESS) { 2026 dns_ncache_current(val->event->rdataset, *namep, 2027 *rdatasetp); 2028 } 2029 } 2030 return (result); 2031} 2032 2033static isc_result_t 2034val_rdataset_next(dns_validator_t *val, dns_name_t **namep, 2035 dns_rdataset_t **rdatasetp) { 2036 dns_message_t *message = val->event->message; 2037 isc_result_t result = ISC_R_SUCCESS; 2038 2039 REQUIRE(rdatasetp != NULL && *rdatasetp != NULL); 2040 REQUIRE(namep != NULL && *namep != NULL); 2041 2042 if (message != NULL) { 2043 dns_rdataset_t *rdataset = *rdatasetp; 2044 rdataset = ISC_LIST_NEXT(rdataset, link); 2045 if (rdataset == NULL) { 2046 *namep = NULL; 2047 result = dns_message_nextname(message, 2048 DNS_SECTION_AUTHORITY); 2049 if (result == ISC_R_SUCCESS) { 2050 dns_message_currentname( 2051 message, DNS_SECTION_AUTHORITY, namep); 2052 rdataset = ISC_LIST_HEAD((*namep)->list); 2053 INSIST(rdataset != NULL); 2054 } 2055 } 2056 *rdatasetp = rdataset; 2057 } else { 2058 dns_rdataset_disassociate(*rdatasetp); 2059 result = dns_rdataset_next(val->event->rdataset); 2060 if (result == ISC_R_SUCCESS) { 2061 dns_ncache_current(val->event->rdataset, *namep, 2062 *rdatasetp); 2063 } 2064 } 2065 return (result); 2066} 2067 2068/*% 2069 * Look for NODATA at the wildcard and NOWILDCARD proofs in the 2070 * previously validated NSEC records. As these proofs are mutually 2071 * exclusive we stop when one is found. 2072 * 2073 * Returns 2074 * \li ISC_R_SUCCESS 2075 */ 2076static isc_result_t 2077checkwildcard(dns_validator_t *val, dns_rdatatype_t type, 2078 dns_name_t *zonename) { 2079 dns_name_t *name, *wild, tname; 2080 isc_result_t result; 2081 bool exists, data; 2082 char namebuf[DNS_NAME_FORMATSIZE]; 2083 dns_rdataset_t *rdataset, trdataset; 2084 2085 dns_name_init(&tname, NULL); 2086 dns_rdataset_init(&trdataset); 2087 wild = dns_fixedname_name(&val->wild); 2088 2089 if (dns_name_countlabels(wild) == 0) { 2090 validator_log(val, ISC_LOG_DEBUG(3), 2091 "in checkwildcard: no wildcard to check"); 2092 return (ISC_R_SUCCESS); 2093 } 2094 2095 dns_name_format(wild, namebuf, sizeof(namebuf)); 2096 validator_log(val, ISC_LOG_DEBUG(3), "in checkwildcard: %s", namebuf); 2097 2098 if (val->event->message == NULL) { 2099 name = &tname; 2100 rdataset = &trdataset; 2101 } else { 2102 name = NULL; 2103 rdataset = NULL; 2104 } 2105 2106 for (result = val_rdataset_first(val, &name, &rdataset); 2107 result == ISC_R_SUCCESS; 2108 result = val_rdataset_next(val, &name, &rdataset)) 2109 { 2110 if (rdataset->type != type || 2111 rdataset->trust != dns_trust_secure) 2112 { 2113 continue; 2114 } 2115 2116 if (rdataset->type == dns_rdatatype_nsec && 2117 (NEEDNODATA(val) || NEEDNOWILDCARD(val)) && 2118 !FOUNDNODATA(val) && !FOUNDNOWILDCARD(val) && 2119 dns_nsec_noexistnodata(val->event->type, wild, name, 2120 rdataset, &exists, &data, NULL, 2121 validator_log, val) == ISC_R_SUCCESS) 2122 { 2123 dns_name_t **proofs = val->event->proofs; 2124 if (exists && !data) { 2125 val->attributes |= VALATTR_FOUNDNODATA; 2126 } 2127 if (exists && !data && NEEDNODATA(val)) { 2128 proofs[DNS_VALIDATOR_NODATAPROOF] = name; 2129 } 2130 if (!exists) { 2131 val->attributes |= VALATTR_FOUNDNOWILDCARD; 2132 } 2133 if (!exists && NEEDNOQNAME(val)) { 2134 proofs[DNS_VALIDATOR_NOWILDCARDPROOF] = name; 2135 } 2136 if (dns_rdataset_isassociated(&trdataset)) { 2137 dns_rdataset_disassociate(&trdataset); 2138 } 2139 return (ISC_R_SUCCESS); 2140 } 2141 2142 if (rdataset->type == dns_rdatatype_nsec3 && 2143 (NEEDNODATA(val) || NEEDNOWILDCARD(val)) && 2144 !FOUNDNODATA(val) && !FOUNDNOWILDCARD(val) && 2145 dns_nsec3_noexistnodata( 2146 val->event->type, wild, name, rdataset, zonename, 2147 &exists, &data, NULL, NULL, NULL, NULL, NULL, NULL, 2148 validator_log, val) == ISC_R_SUCCESS) 2149 { 2150 dns_name_t **proofs = val->event->proofs; 2151 if (exists && !data) { 2152 val->attributes |= VALATTR_FOUNDNODATA; 2153 } 2154 if (exists && !data && NEEDNODATA(val)) { 2155 proofs[DNS_VALIDATOR_NODATAPROOF] = name; 2156 } 2157 if (!exists) { 2158 val->attributes |= VALATTR_FOUNDNOWILDCARD; 2159 } 2160 if (!exists && NEEDNOQNAME(val)) { 2161 proofs[DNS_VALIDATOR_NOWILDCARDPROOF] = name; 2162 } 2163 if (dns_rdataset_isassociated(&trdataset)) { 2164 dns_rdataset_disassociate(&trdataset); 2165 } 2166 return (ISC_R_SUCCESS); 2167 } 2168 } 2169 if (result == ISC_R_NOMORE) { 2170 result = ISC_R_SUCCESS; 2171 } 2172 if (dns_rdataset_isassociated(&trdataset)) { 2173 dns_rdataset_disassociate(&trdataset); 2174 } 2175 return (result); 2176} 2177 2178/* 2179 * Look for the needed proofs for a negative or wildcard response 2180 * from a zone using NSEC3, and set flags in the validator as they 2181 * are found. 2182 */ 2183static isc_result_t 2184findnsec3proofs(dns_validator_t *val) { 2185 dns_name_t *name, tname; 2186 isc_result_t result; 2187 bool exists, data, optout, unknown; 2188 bool setclosest, setnearest, *setclosestp; 2189 dns_fixedname_t fclosest, fnearest, fzonename; 2190 dns_name_t *closest, *nearest, *zonename, *closestp; 2191 dns_name_t **proofs = val->event->proofs; 2192 dns_rdataset_t *rdataset, trdataset; 2193 2194 dns_name_init(&tname, NULL); 2195 dns_rdataset_init(&trdataset); 2196 closest = dns_fixedname_initname(&fclosest); 2197 nearest = dns_fixedname_initname(&fnearest); 2198 zonename = dns_fixedname_initname(&fzonename); 2199 2200 if (val->event->message == NULL) { 2201 name = &tname; 2202 rdataset = &trdataset; 2203 } else { 2204 name = NULL; 2205 rdataset = NULL; 2206 } 2207 2208 for (result = val_rdataset_first(val, &name, &rdataset); 2209 result == ISC_R_SUCCESS; 2210 result = val_rdataset_next(val, &name, &rdataset)) 2211 { 2212 if (rdataset->type != dns_rdatatype_nsec3 || 2213 rdataset->trust != dns_trust_secure) 2214 { 2215 continue; 2216 } 2217 2218 result = dns_nsec3_noexistnodata( 2219 val->event->type, val->event->name, name, rdataset, 2220 zonename, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 2221 NULL, validator_log, val); 2222 if (result != ISC_R_IGNORE && result != ISC_R_SUCCESS) { 2223 if (dns_rdataset_isassociated(&trdataset)) { 2224 dns_rdataset_disassociate(&trdataset); 2225 } 2226 return (result); 2227 } 2228 } 2229 if (result != ISC_R_NOMORE) { 2230 result = ISC_R_SUCCESS; 2231 } 2232 POST(result); 2233 2234 if (dns_name_countlabels(zonename) == 0) { 2235 return (ISC_R_SUCCESS); 2236 } 2237 2238 /* 2239 * If the val->closest is set then we want to use it otherwise 2240 * we need to discover it. 2241 */ 2242 if (dns_name_countlabels(dns_fixedname_name(&val->closest)) != 0) { 2243 char namebuf[DNS_NAME_FORMATSIZE]; 2244 2245 dns_name_format(dns_fixedname_name(&val->closest), namebuf, 2246 sizeof(namebuf)); 2247 validator_log(val, ISC_LOG_DEBUG(3), 2248 "closest encloser from wildcard signature '%s'", 2249 namebuf); 2250 dns_name_copynf(dns_fixedname_name(&val->closest), closest); 2251 closestp = NULL; 2252 setclosestp = NULL; 2253 } else { 2254 closestp = closest; 2255 setclosestp = &setclosest; 2256 } 2257 2258 for (result = val_rdataset_first(val, &name, &rdataset); 2259 result == ISC_R_SUCCESS; 2260 result = val_rdataset_next(val, &name, &rdataset)) 2261 { 2262 if (rdataset->type != dns_rdatatype_nsec3 || 2263 rdataset->trust != dns_trust_secure) 2264 { 2265 continue; 2266 } 2267 2268 /* 2269 * We process all NSEC3 records to find the closest 2270 * encloser and nearest name to the closest encloser. 2271 */ 2272 setclosest = setnearest = false; 2273 optout = false; 2274 unknown = false; 2275 result = dns_nsec3_noexistnodata( 2276 val->event->type, val->event->name, name, rdataset, 2277 zonename, &exists, &data, &optout, &unknown, 2278 setclosestp, &setnearest, closestp, nearest, 2279 validator_log, val); 2280 if (unknown) { 2281 val->attributes |= VALATTR_FOUNDUNKNOWN; 2282 } 2283 if (result == DNS_R_NSEC3ITERRANGE) { 2284 /* 2285 * We don't really know which NSEC3 record provides 2286 * which proof. Just populate them. 2287 */ 2288 if (NEEDNOQNAME(val) && 2289 proofs[DNS_VALIDATOR_NOQNAMEPROOF] == NULL) 2290 { 2291 proofs[DNS_VALIDATOR_NOQNAMEPROOF] = name; 2292 } else if (setclosest) { 2293 proofs[DNS_VALIDATOR_CLOSESTENCLOSER] = name; 2294 } else if (NEEDNODATA(val) && 2295 proofs[DNS_VALIDATOR_NODATAPROOF] == NULL) 2296 { 2297 proofs[DNS_VALIDATOR_NODATAPROOF] = name; 2298 } else if (NEEDNOWILDCARD(val) && 2299 proofs[DNS_VALIDATOR_NOWILDCARDPROOF] == 2300 NULL) 2301 { 2302 proofs[DNS_VALIDATOR_NOWILDCARDPROOF] = name; 2303 } 2304 return (result); 2305 } 2306 if (result != ISC_R_SUCCESS) { 2307 continue; 2308 } 2309 if (setclosest) { 2310 proofs[DNS_VALIDATOR_CLOSESTENCLOSER] = name; 2311 } 2312 if (exists && !data && NEEDNODATA(val)) { 2313 val->attributes |= VALATTR_FOUNDNODATA; 2314 proofs[DNS_VALIDATOR_NODATAPROOF] = name; 2315 } 2316 if (!exists && setnearest) { 2317 val->attributes |= VALATTR_FOUNDNOQNAME; 2318 proofs[DNS_VALIDATOR_NOQNAMEPROOF] = name; 2319 if (optout) { 2320 val->attributes |= VALATTR_FOUNDOPTOUT; 2321 } 2322 } 2323 } 2324 if (result == ISC_R_NOMORE) { 2325 result = ISC_R_SUCCESS; 2326 } 2327 2328 /* 2329 * To know we have a valid noqname and optout proofs we need to also 2330 * have a valid closest encloser. Otherwise we could still be looking 2331 * at proofs from the parent zone. 2332 */ 2333 if (dns_name_countlabels(closest) > 0 && 2334 dns_name_countlabels(nearest) == 2335 dns_name_countlabels(closest) + 1 && 2336 dns_name_issubdomain(nearest, closest)) 2337 { 2338 val->attributes |= VALATTR_FOUNDCLOSEST; 2339 result = dns_name_concatenate(dns_wildcardname, closest, 2340 dns_fixedname_name(&val->wild), 2341 NULL); 2342 RUNTIME_CHECK(result == ISC_R_SUCCESS); 2343 } else { 2344 val->attributes &= ~VALATTR_FOUNDNOQNAME; 2345 val->attributes &= ~VALATTR_FOUNDOPTOUT; 2346 proofs[DNS_VALIDATOR_NOQNAMEPROOF] = NULL; 2347 } 2348 2349 /* 2350 * Do we need to check for the wildcard? 2351 */ 2352 if (FOUNDNOQNAME(val) && FOUNDCLOSEST(val) && 2353 ((NEEDNODATA(val) && !FOUNDNODATA(val)) || NEEDNOWILDCARD(val))) 2354 { 2355 result = checkwildcard(val, dns_rdatatype_nsec3, zonename); 2356 if (result != ISC_R_SUCCESS) { 2357 return (result); 2358 } 2359 } 2360 return (result); 2361} 2362 2363/* 2364 * Start a validator for negative response data. 2365 * 2366 * Returns: 2367 * \li DNS_R_CONTINUE Validation skipped, continue 2368 * \li DNS_R_WAIT Validation is in progress 2369 * 2370 * \li Other return codes indicate failure. 2371 */ 2372static isc_result_t 2373validate_neg_rrset(dns_validator_t *val, dns_name_t *name, 2374 dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset) { 2375 isc_result_t result; 2376 2377 /* 2378 * If a signed zone is missing the zone key, bad 2379 * things could happen. A query for data in the zone 2380 * would lead to a query for the zone key, which 2381 * would return a negative answer, which would contain 2382 * an SOA and an NSEC signed by the missing key, which 2383 * would trigger another query for the DNSKEY (since 2384 * the first one is still in progress), and go into an 2385 * infinite loop. Avoid that. 2386 */ 2387 if (val->event->type == dns_rdatatype_dnskey && 2388 rdataset->type == dns_rdatatype_nsec && 2389 dns_name_equal(name, val->event->name)) 2390 { 2391 dns_rdata_t nsec = DNS_RDATA_INIT; 2392 2393 result = dns_rdataset_first(rdataset); 2394 if (result != ISC_R_SUCCESS) { 2395 return (result); 2396 } 2397 dns_rdataset_current(rdataset, &nsec); 2398 if (dns_nsec_typepresent(&nsec, dns_rdatatype_soa)) { 2399 return (DNS_R_CONTINUE); 2400 } 2401 } 2402 2403 val->currentset = rdataset; 2404 result = create_validator(val, name, rdataset->type, rdataset, 2405 sigrdataset, validator_callback_nsec, 2406 "validate_neg_rrset"); 2407 if (result != ISC_R_SUCCESS) { 2408 return (result); 2409 } 2410 2411 val->authcount++; 2412 return (DNS_R_WAIT); 2413} 2414 2415/*% 2416 * Validate the authority section records. 2417 */ 2418static isc_result_t 2419validate_authority(dns_validator_t *val, bool resume) { 2420 dns_name_t *name; 2421 dns_message_t *message = val->event->message; 2422 isc_result_t result; 2423 2424 if (!resume) { 2425 result = dns_message_firstname(message, DNS_SECTION_AUTHORITY); 2426 } else { 2427 result = ISC_R_SUCCESS; 2428 } 2429 2430 for (; result == ISC_R_SUCCESS; 2431 result = dns_message_nextname(message, DNS_SECTION_AUTHORITY)) 2432 { 2433 dns_rdataset_t *rdataset = NULL, *sigrdataset = NULL; 2434 2435 name = NULL; 2436 dns_message_currentname(message, DNS_SECTION_AUTHORITY, &name); 2437 if (resume) { 2438 rdataset = ISC_LIST_NEXT(val->currentset, link); 2439 val->currentset = NULL; 2440 resume = false; 2441 } else { 2442 rdataset = ISC_LIST_HEAD(name->list); 2443 } 2444 2445 for (; rdataset != NULL; 2446 rdataset = ISC_LIST_NEXT(rdataset, link)) 2447 { 2448 if (rdataset->type == dns_rdatatype_rrsig) { 2449 continue; 2450 } 2451 2452 for (sigrdataset = ISC_LIST_HEAD(name->list); 2453 sigrdataset != NULL; 2454 sigrdataset = ISC_LIST_NEXT(sigrdataset, link)) 2455 { 2456 if (sigrdataset->type == dns_rdatatype_rrsig && 2457 sigrdataset->covers == rdataset->type) 2458 { 2459 break; 2460 } 2461 } 2462 2463 result = validate_neg_rrset(val, name, rdataset, 2464 sigrdataset); 2465 if (result != DNS_R_CONTINUE) { 2466 return (result); 2467 } 2468 } 2469 } 2470 if (result == ISC_R_NOMORE) { 2471 result = ISC_R_SUCCESS; 2472 } 2473 return (result); 2474} 2475 2476/*% 2477 * Validate negative cache elements. 2478 */ 2479static isc_result_t 2480validate_ncache(dns_validator_t *val, bool resume) { 2481 dns_name_t *name; 2482 isc_result_t result; 2483 2484 if (!resume) { 2485 result = dns_rdataset_first(val->event->rdataset); 2486 } else { 2487 result = dns_rdataset_next(val->event->rdataset); 2488 } 2489 2490 for (; result == ISC_R_SUCCESS; 2491 result = dns_rdataset_next(val->event->rdataset)) 2492 { 2493 dns_rdataset_t *rdataset, *sigrdataset = NULL; 2494 2495 disassociate_rdatasets(val); 2496 2497 name = dns_fixedname_initname(&val->fname); 2498 rdataset = &val->frdataset; 2499 dns_ncache_current(val->event->rdataset, name, rdataset); 2500 2501 if (val->frdataset.type == dns_rdatatype_rrsig) { 2502 continue; 2503 } 2504 2505 result = dns_ncache_getsigrdataset(val->event->rdataset, name, 2506 rdataset->type, 2507 &val->fsigrdataset); 2508 if (result == ISC_R_SUCCESS) { 2509 sigrdataset = &val->fsigrdataset; 2510 } 2511 2512 result = validate_neg_rrset(val, name, rdataset, sigrdataset); 2513 if (result == DNS_R_CONTINUE) { 2514 continue; 2515 } 2516 2517 return (result); 2518 } 2519 if (result == ISC_R_NOMORE) { 2520 result = ISC_R_SUCCESS; 2521 } 2522 2523 return (result); 2524} 2525 2526/*% 2527 * Prove a negative answer is good or that there is a NOQNAME when the 2528 * answer is from a wildcard. 2529 * 2530 * Loop through the authority section looking for NODATA, NOWILDCARD 2531 * and NOQNAME proofs in the NSEC records by calling 2532 * validator_callback_nsec(). 2533 * 2534 * If the required proofs are found we are done. 2535 * 2536 * If the proofs are not found attempt to prove this is an unsecure 2537 * response. 2538 */ 2539static isc_result_t 2540validate_nx(dns_validator_t *val, bool resume) { 2541 isc_result_t result; 2542 2543 if (resume) { 2544 validator_log(val, ISC_LOG_DEBUG(3), "resuming validate_nx"); 2545 } 2546 2547 if (val->event->message == NULL) { 2548 result = validate_ncache(val, resume); 2549 } else { 2550 result = validate_authority(val, resume); 2551 } 2552 2553 if (result != ISC_R_SUCCESS) { 2554 return (result); 2555 } 2556 2557 /* 2558 * Do we only need to check for NOQNAME? To get here we must have 2559 * had a secure wildcard answer. 2560 */ 2561 if (!NEEDNODATA(val) && !NEEDNOWILDCARD(val) && NEEDNOQNAME(val)) { 2562 if (!FOUNDNOQNAME(val)) { 2563 result = findnsec3proofs(val); 2564 if (result == DNS_R_NSEC3ITERRANGE) { 2565 validator_log(val, ISC_LOG_DEBUG(3), 2566 "too many iterations"); 2567 markanswer(val, "validate_nx (3)", NULL); 2568 return (ISC_R_SUCCESS); 2569 } 2570 } 2571 2572 if (FOUNDNOQNAME(val) && FOUNDCLOSEST(val) && !FOUNDOPTOUT(val)) 2573 { 2574 validator_log(val, ISC_LOG_DEBUG(3), 2575 "marking as secure, noqname proof found"); 2576 marksecure(val->event); 2577 return (ISC_R_SUCCESS); 2578 } else if (FOUNDOPTOUT(val) && 2579 dns_name_countlabels( 2580 dns_fixedname_name(&val->wild)) != 0) 2581 { 2582 validator_log(val, ISC_LOG_DEBUG(3), 2583 "optout proof found"); 2584 val->event->optout = true; 2585 markanswer(val, "validate_nx (1)", NULL); 2586 return (ISC_R_SUCCESS); 2587 } else if ((val->attributes & VALATTR_FOUNDUNKNOWN) != 0) { 2588 validator_log(val, ISC_LOG_DEBUG(3), 2589 "unknown NSEC3 hash algorithm found"); 2590 markanswer(val, "validate_nx (2)", NULL); 2591 return (ISC_R_SUCCESS); 2592 } 2593 2594 validator_log(val, ISC_LOG_DEBUG(3), "noqname proof not found"); 2595 return (DNS_R_NOVALIDNSEC); 2596 } 2597 2598 if (!FOUNDNOQNAME(val) && !FOUNDNODATA(val)) { 2599 result = findnsec3proofs(val); 2600 if (result == DNS_R_NSEC3ITERRANGE) { 2601 validator_log(val, ISC_LOG_DEBUG(3), 2602 "too many iterations"); 2603 markanswer(val, "validate_nx (4)", NULL); 2604 return (ISC_R_SUCCESS); 2605 } 2606 } 2607 2608 /* 2609 * Do we need to check for the wildcard? 2610 */ 2611 if (FOUNDNOQNAME(val) && FOUNDCLOSEST(val) && 2612 ((NEEDNODATA(val) && !FOUNDNODATA(val)) || NEEDNOWILDCARD(val))) 2613 { 2614 result = checkwildcard(val, dns_rdatatype_nsec, NULL); 2615 if (result != ISC_R_SUCCESS) { 2616 return (result); 2617 } 2618 } 2619 2620 if ((NEEDNODATA(val) && (FOUNDNODATA(val) || FOUNDOPTOUT(val))) || 2621 (NEEDNOQNAME(val) && FOUNDNOQNAME(val) && NEEDNOWILDCARD(val) && 2622 FOUNDNOWILDCARD(val) && FOUNDCLOSEST(val))) 2623 { 2624 if ((val->attributes & VALATTR_FOUNDOPTOUT) != 0) { 2625 val->event->optout = true; 2626 } 2627 validator_log(val, ISC_LOG_DEBUG(3), 2628 "nonexistence proof(s) found"); 2629 if (val->event->message == NULL) { 2630 marksecure(val->event); 2631 } else { 2632 val->event->secure = true; 2633 } 2634 return (ISC_R_SUCCESS); 2635 } 2636 2637 if (val->authfail != 0 && val->authcount == val->authfail) { 2638 return (DNS_R_BROKENCHAIN); 2639 } 2640 2641 validator_log(val, ISC_LOG_DEBUG(3), "nonexistence proof(s) not found"); 2642 return (proveunsecure(val, false, false)); 2643} 2644 2645/*% 2646 * Check that DS rdataset has at least one record with 2647 * a supported algorithm and digest. 2648 */ 2649static bool 2650check_ds_algs(dns_validator_t *val, dns_name_t *name, 2651 dns_rdataset_t *rdataset) { 2652 dns_rdata_t dsrdata = DNS_RDATA_INIT; 2653 dns_rdata_ds_t ds; 2654 isc_result_t result; 2655 2656 for (result = dns_rdataset_first(rdataset); result == ISC_R_SUCCESS; 2657 result = dns_rdataset_next(rdataset)) 2658 { 2659 dns_rdataset_current(rdataset, &dsrdata); 2660 result = dns_rdata_tostruct(&dsrdata, &ds, NULL); 2661 RUNTIME_CHECK(result == ISC_R_SUCCESS); 2662 2663 if (dns_resolver_ds_digest_supported(val->view->resolver, name, 2664 ds.digest_type) && 2665 dns_resolver_algorithm_supported(val->view->resolver, name, 2666 ds.algorithm)) 2667 { 2668 dns_rdata_reset(&dsrdata); 2669 return (true); 2670 } 2671 dns_rdata_reset(&dsrdata); 2672 } 2673 return (false); 2674} 2675 2676/*% 2677 * seek_ds is called to look up DS rrsets at the label of val->event->name 2678 * indicated by val->labels. This is done while building an insecurity 2679 * proof, and so it will attempt validation of NXDOMAIN, NXRRSET or CNAME 2680 * responses. 2681 * 2682 * Returns: 2683 * \li ISC_R_COMPLETE a result has been determined and copied 2684 * into `*resp`; ISC_R_SUCCESS indicates that 2685 * the name has been proven insecure and any 2686 * other result indicates failure. 2687 * \li DNS_R_CONTINUE result is indeterminate; caller should 2688 * continue walking down labels. 2689 */ 2690static isc_result_t 2691seek_ds(dns_validator_t *val, isc_result_t *resp) { 2692 isc_result_t result; 2693 char namebuf[DNS_NAME_FORMATSIZE]; 2694 dns_fixedname_t fixedfound; 2695 dns_name_t *found = dns_fixedname_initname(&fixedfound); 2696 dns_name_t *tname = dns_fixedname_initname(&val->fname); 2697 2698 if (val->labels == dns_name_countlabels(val->event->name)) { 2699 dns_name_copynf(val->event->name, tname); 2700 } else { 2701 dns_name_split(val->event->name, val->labels, NULL, tname); 2702 } 2703 2704 dns_name_format(tname, namebuf, sizeof(namebuf)); 2705 validator_log(val, ISC_LOG_DEBUG(3), "checking existence of DS at '%s'", 2706 namebuf); 2707 2708 result = view_find(val, tname, dns_rdatatype_ds); 2709 switch (result) { 2710 case ISC_R_SUCCESS: 2711 /* 2712 * There is a DS here. If it's already been 2713 * validated, continue walking down labels. 2714 */ 2715 if (val->frdataset.trust >= dns_trust_secure) { 2716 if (!check_ds_algs(val, tname, &val->frdataset)) { 2717 validator_log(val, ISC_LOG_DEBUG(3), 2718 "no supported algorithm/" 2719 "digest (%s/DS)", 2720 namebuf); 2721 *resp = markanswer(val, "proveunsecure (5)", 2722 "no supported " 2723 "algorithm/digest (DS)"); 2724 return (ISC_R_COMPLETE); 2725 } 2726 2727 break; 2728 } 2729 2730 /* 2731 * Otherwise, try to validate it now. 2732 */ 2733 if (dns_rdataset_isassociated(&val->fsigrdataset)) { 2734 result = create_validator( 2735 val, tname, dns_rdatatype_ds, &val->frdataset, 2736 &val->fsigrdataset, validator_callback_ds, 2737 "proveunsecure"); 2738 *resp = DNS_R_WAIT; 2739 if (result != ISC_R_SUCCESS) { 2740 *resp = result; 2741 } 2742 } else { 2743 /* 2744 * There should never be an unsigned DS. 2745 */ 2746 validator_log(val, ISC_LOG_DEBUG(3), 2747 "unsigned DS record"); 2748 *resp = DNS_R_NOVALIDSIG; 2749 } 2750 2751 return (ISC_R_COMPLETE); 2752 2753 case ISC_R_NOTFOUND: 2754 /* 2755 * We don't know anything about the DS. Find it. 2756 */ 2757 *resp = DNS_R_WAIT; 2758 result = create_fetch(val, tname, dns_rdatatype_ds, 2759 fetch_callback_ds, "proveunsecure"); 2760 if (result != ISC_R_SUCCESS) { 2761 *resp = result; 2762 } 2763 return (ISC_R_COMPLETE); 2764 2765 case DNS_R_NXRRSET: 2766 case DNS_R_NCACHENXRRSET: 2767 /* 2768 * There is no DS. If this is a delegation, 2769 * we may be done. 2770 * 2771 * If we have "trust == answer" then this namespace 2772 * has switched from insecure to should be secure. 2773 */ 2774 if (DNS_TRUST_PENDING(val->frdataset.trust) || 2775 DNS_TRUST_ANSWER(val->frdataset.trust)) 2776 { 2777 result = create_validator( 2778 val, tname, dns_rdatatype_ds, &val->frdataset, 2779 &val->fsigrdataset, validator_callback_ds, 2780 "proveunsecure"); 2781 *resp = DNS_R_WAIT; 2782 if (result != ISC_R_SUCCESS) { 2783 *resp = result; 2784 } 2785 return (ISC_R_COMPLETE); 2786 } 2787 2788 /* 2789 * Zones using NSEC3 don't return a NSEC RRset so 2790 * we need to use dns_view_findzonecut2 to find 2791 * the zone cut. 2792 */ 2793 if (result == DNS_R_NXRRSET && 2794 !dns_rdataset_isassociated(&val->frdataset) && 2795 dns_view_findzonecut(val->view, tname, found, NULL, 0, 0, 2796 false, false, NULL, 2797 NULL) == ISC_R_SUCCESS && 2798 dns_name_equal(tname, found)) 2799 { 2800 *resp = markanswer(val, "proveunsecure (3)", 2801 "no DS at zone cut"); 2802 return (ISC_R_COMPLETE); 2803 } 2804 2805 if (val->frdataset.trust < dns_trust_secure) { 2806 /* 2807 * This shouldn't happen, since the negative 2808 * response should have been validated. Since 2809 * there's no way of validating existing 2810 * negative response blobs, give up. 2811 */ 2812 validator_log(val, ISC_LOG_WARNING, 2813 "can't validate existing " 2814 "negative responses (no DS)"); 2815 *resp = DNS_R_MUSTBESECURE; 2816 return (ISC_R_COMPLETE); 2817 } 2818 2819 if (isdelegation(tname, &val->frdataset, result)) { 2820 *resp = markanswer(val, "proveunsecure (4)", 2821 "this is a delegation"); 2822 return (ISC_R_COMPLETE); 2823 } 2824 2825 break; 2826 2827 case DNS_R_NXDOMAIN: 2828 case DNS_R_NCACHENXDOMAIN: 2829 /* 2830 * This is not a zone cut. Assuming things are 2831 * as expected, continue. 2832 */ 2833 if (!dns_rdataset_isassociated(&val->frdataset)) { 2834 /* 2835 * There should be an NSEC here, since we 2836 * are still in a secure zone. 2837 */ 2838 *resp = DNS_R_NOVALIDNSEC; 2839 return (ISC_R_COMPLETE); 2840 } else if (DNS_TRUST_PENDING(val->frdataset.trust) || 2841 DNS_TRUST_ANSWER(val->frdataset.trust)) 2842 { 2843 /* 2844 * If we have "trust == answer" then this 2845 * namespace has switched from insecure to 2846 * should be secure. 2847 */ 2848 *resp = DNS_R_WAIT; 2849 result = create_validator( 2850 val, tname, dns_rdatatype_ds, &val->frdataset, 2851 &val->fsigrdataset, validator_callback_ds, 2852 "proveunsecure"); 2853 if (result != ISC_R_SUCCESS) { 2854 *resp = result; 2855 } 2856 return (ISC_R_COMPLETE); 2857 } else if (val->frdataset.trust < dns_trust_secure) { 2858 /* 2859 * This shouldn't happen, since the negative 2860 * response should have been validated. Since 2861 * there's no way of validating existing 2862 * negative response blobs, give up. 2863 */ 2864 validator_log(val, ISC_LOG_WARNING, 2865 "can't validate existing " 2866 "negative responses " 2867 "(not a zone cut)"); 2868 *resp = DNS_R_NOVALIDSIG; 2869 return (ISC_R_COMPLETE); 2870 } 2871 2872 break; 2873 2874 case DNS_R_CNAME: 2875 if (DNS_TRUST_PENDING(val->frdataset.trust) || 2876 DNS_TRUST_ANSWER(val->frdataset.trust)) 2877 { 2878 result = create_validator( 2879 val, tname, dns_rdatatype_cname, 2880 &val->frdataset, &val->fsigrdataset, 2881 validator_callback_cname, 2882 "proveunsecure " 2883 "(cname)"); 2884 *resp = DNS_R_WAIT; 2885 if (result != ISC_R_SUCCESS) { 2886 *resp = result; 2887 } 2888 return (ISC_R_COMPLETE); 2889 } 2890 2891 break; 2892 2893 default: 2894 *resp = result; 2895 return (ISC_R_COMPLETE); 2896 } 2897 2898 /* 2899 * No definite answer yet; continue walking down labels. 2900 */ 2901 return (DNS_R_CONTINUE); 2902} 2903 2904/*% 2905 * proveunsecure walks down, label by label, from the closest enclosing 2906 * trust anchor to the name that is being validated, looking for an 2907 * endpoint in the chain of trust. That occurs when we can prove that 2908 * a DS record does not exist at a delegation point, or that a DS exists 2909 * at a delegation point but we don't support its algorithm/digest. If 2910 * no such endpoint is found, then the response should have been secure. 2911 * 2912 * Returns: 2913 * \li ISC_R_SUCCESS val->event->name is in an unsecure zone 2914 * \li DNS_R_WAIT validation is in progress. 2915 * \li DNS_R_MUSTBESECURE val->event->name is supposed to be secure 2916 * (policy) but we proved that it is unsecure. 2917 * \li DNS_R_NOVALIDSIG 2918 * \li DNS_R_NOVALIDNSEC 2919 * \li DNS_R_NOTINSECURE 2920 * \li DNS_R_BROKENCHAIN 2921 */ 2922static isc_result_t 2923proveunsecure(dns_validator_t *val, bool have_ds, bool resume) { 2924 isc_result_t result; 2925 char namebuf[DNS_NAME_FORMATSIZE]; 2926 dns_fixedname_t fixedsecroot; 2927 dns_name_t *secroot = dns_fixedname_initname(&fixedsecroot); 2928 unsigned int labels; 2929 2930 /* 2931 * We're attempting to prove insecurity. 2932 */ 2933 val->attributes |= VALATTR_INSECURITY; 2934 2935 dns_name_copynf(val->event->name, secroot); 2936 2937 /* 2938 * If this is a response to a DS query, we need to look in 2939 * the parent zone for the trust anchor. 2940 */ 2941 labels = dns_name_countlabels(secroot); 2942 if (val->event->type == dns_rdatatype_ds && labels > 1U) { 2943 dns_name_getlabelsequence(secroot, 1, labels - 1, secroot); 2944 } 2945 2946 result = dns_keytable_finddeepestmatch(val->keytable, secroot, secroot); 2947 if (result == ISC_R_NOTFOUND) { 2948 validator_log(val, ISC_LOG_DEBUG(3), "not beneath secure root"); 2949 return (markanswer(val, "proveunsecure (1)", 2950 "not beneath secure root")); 2951 } else if (result != ISC_R_SUCCESS) { 2952 return (result); 2953 } 2954 2955 if (!resume) { 2956 /* 2957 * We are looking for interruptions in the chain of trust. 2958 * That can only happen *below* the trust anchor, so we 2959 * start looking at the next label down. 2960 */ 2961 val->labels = dns_name_countlabels(secroot) + 1; 2962 } else { 2963 validator_log(val, ISC_LOG_DEBUG(3), "resuming proveunsecure"); 2964 2965 /* 2966 * If we have a DS rdataset and it is secure, check whether 2967 * it has a supported algorithm combination. If not, this is 2968 * an insecure delegation as far as this resolver is concerned. 2969 */ 2970 if (have_ds && val->frdataset.trust >= dns_trust_secure && 2971 !check_ds_algs(val, dns_fixedname_name(&val->fname), 2972 &val->frdataset)) 2973 { 2974 dns_name_format(dns_fixedname_name(&val->fname), 2975 namebuf, sizeof(namebuf)); 2976 validator_log(val, ISC_LOG_DEBUG(3), 2977 "no supported algorithm/digest (%s/DS)", 2978 namebuf); 2979 result = markanswer(val, "proveunsecure (2)", namebuf); 2980 goto out; 2981 } 2982 val->labels++; 2983 } 2984 2985 /* 2986 * Walk down through each of the remaining labels in the name, 2987 * looking for DS records. 2988 */ 2989 while (val->labels <= dns_name_countlabels(val->event->name)) { 2990 isc_result_t tresult; 2991 2992 result = seek_ds(val, &tresult); 2993 if (result == ISC_R_COMPLETE) { 2994 result = tresult; 2995 goto out; 2996 } 2997 2998 INSIST(result == DNS_R_CONTINUE); 2999 val->labels++; 3000 } 3001 3002 /* Couldn't complete insecurity proof. */ 3003 validator_log(val, ISC_LOG_DEBUG(3), "insecurity proof failed: %s", 3004 isc_result_totext(result)); 3005 return (DNS_R_NOTINSECURE); 3006 3007out: 3008 if (result != DNS_R_WAIT) { 3009 disassociate_rdatasets(val); 3010 } 3011 return (result); 3012} 3013 3014/*% 3015 * Start the validation process. 3016 * 3017 * Attempt to validate the answer based on the category it appears to 3018 * fall in. 3019 * \li 1. secure positive answer. 3020 * \li 2. unsecure positive answer. 3021 * \li 3. a negative answer (secure or unsecure). 3022 * 3023 * Note an answer that appears to be a secure positive answer may actually 3024 * be an unsecure positive answer. 3025 */ 3026static void 3027validator_start(isc_task_t *task, isc_event_t *event) { 3028 dns_validator_t *val; 3029 dns_validatorevent_t *vevent; 3030 bool want_destroy = false; 3031 isc_result_t result = ISC_R_FAILURE; 3032 3033 UNUSED(task); 3034 REQUIRE(event->ev_type == DNS_EVENT_VALIDATORSTART); 3035 vevent = (dns_validatorevent_t *)event; 3036 val = vevent->validator; 3037 3038 /* If the validator has been canceled, val->event == NULL */ 3039 if (val->event == NULL) { 3040 return; 3041 } 3042 3043 validator_log(val, ISC_LOG_DEBUG(3), "starting"); 3044 3045 LOCK(&val->lock); 3046 3047 if (val->event->rdataset != NULL && val->event->sigrdataset != NULL) { 3048 isc_result_t saved_result; 3049 3050 /* 3051 * This looks like a simple validation. We say "looks like" 3052 * because it might end up requiring an insecurity proof. 3053 */ 3054 validator_log(val, ISC_LOG_DEBUG(3), 3055 "attempting positive response validation"); 3056 3057 INSIST(dns_rdataset_isassociated(val->event->rdataset)); 3058 INSIST(dns_rdataset_isassociated(val->event->sigrdataset)); 3059 if (selfsigned_dnskey(val)) { 3060 result = validate_dnskey(val); 3061 } else { 3062 result = validate_answer(val, false); 3063 } 3064 if (result == DNS_R_NOVALIDSIG && 3065 (val->attributes & VALATTR_TRIEDVERIFY) == 0) 3066 { 3067 saved_result = result; 3068 validator_log(val, ISC_LOG_DEBUG(3), 3069 "falling back to insecurity proof"); 3070 result = proveunsecure(val, false, false); 3071 if (result == DNS_R_NOTINSECURE) { 3072 result = saved_result; 3073 } 3074 } 3075 } else if (val->event->rdataset != NULL && 3076 val->event->rdataset->type != 0) 3077 { 3078 /* 3079 * This is either an unsecure subdomain or a response 3080 * from a broken server. 3081 */ 3082 INSIST(dns_rdataset_isassociated(val->event->rdataset)); 3083 validator_log(val, ISC_LOG_DEBUG(3), 3084 "attempting insecurity proof"); 3085 3086 result = proveunsecure(val, false, false); 3087 if (result == DNS_R_NOTINSECURE) { 3088 validator_log(val, ISC_LOG_INFO, 3089 "got insecure response; " 3090 "parent indicates it should be secure"); 3091 } 3092 } else if ((val->event->rdataset == NULL && 3093 val->event->sigrdataset == NULL)) 3094 { 3095 /* 3096 * This is a validation of a negative response. 3097 */ 3098 validator_log(val, ISC_LOG_DEBUG(3), 3099 "attempting negative response validation " 3100 "from message"); 3101 3102 if (val->event->message->rcode == dns_rcode_nxdomain) { 3103 val->attributes |= VALATTR_NEEDNOQNAME; 3104 val->attributes |= VALATTR_NEEDNOWILDCARD; 3105 } else { 3106 val->attributes |= VALATTR_NEEDNODATA; 3107 } 3108 3109 result = validate_nx(val, false); 3110 } else if ((val->event->rdataset != NULL && 3111 NEGATIVE(val->event->rdataset))) 3112 { 3113 /* 3114 * This is a delayed validation of a negative cache entry. 3115 */ 3116 validator_log(val, ISC_LOG_DEBUG(3), 3117 "attempting negative response validation " 3118 "from cache"); 3119 3120 if (NXDOMAIN(val->event->rdataset)) { 3121 val->attributes |= VALATTR_NEEDNOQNAME; 3122 val->attributes |= VALATTR_NEEDNOWILDCARD; 3123 } else { 3124 val->attributes |= VALATTR_NEEDNODATA; 3125 } 3126 3127 result = validate_nx(val, false); 3128 } else { 3129 UNREACHABLE(); 3130 } 3131 3132 if (result != DNS_R_WAIT) { 3133 want_destroy = exit_check(val); 3134 validator_done(val, result); 3135 } 3136 3137 UNLOCK(&val->lock); 3138 if (want_destroy) { 3139 destroy(val); 3140 } 3141} 3142 3143isc_result_t 3144dns_validator_create(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type, 3145 dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset, 3146 dns_message_t *message, unsigned int options, 3147 isc_task_t *task, isc_taskaction_t action, void *arg, 3148 dns_validator_t **validatorp) { 3149 isc_result_t result = ISC_R_FAILURE; 3150 dns_validator_t *val; 3151 isc_task_t *tclone = NULL; 3152 dns_validatorevent_t *event; 3153 3154 REQUIRE(name != NULL); 3155 REQUIRE(rdataset != NULL || 3156 (rdataset == NULL && sigrdataset == NULL && message != NULL)); 3157 REQUIRE(validatorp != NULL && *validatorp == NULL); 3158 3159 event = (dns_validatorevent_t *)isc_event_allocate( 3160 view->mctx, task, DNS_EVENT_VALIDATORSTART, validator_start, 3161 NULL, sizeof(dns_validatorevent_t)); 3162 3163 isc_task_attach(task, &tclone); 3164 event->result = ISC_R_FAILURE; 3165 event->name = name; 3166 event->type = type; 3167 event->rdataset = rdataset; 3168 event->sigrdataset = sigrdataset; 3169 event->message = message; 3170 memset(event->proofs, 0, sizeof(event->proofs)); 3171 event->optout = false; 3172 event->secure = false; 3173 3174 val = isc_mem_get(view->mctx, sizeof(*val)); 3175 *val = (dns_validator_t){ .event = event, 3176 .options = options, 3177 .task = task, 3178 .action = action, 3179 .arg = arg }; 3180 3181 dns_view_weakattach(view, &val->view); 3182 isc_mutex_init(&val->lock); 3183 3184 result = dns_view_getsecroots(val->view, &val->keytable); 3185 if (result != ISC_R_SUCCESS) { 3186 goto cleanup; 3187 } 3188 3189 val->mustbesecure = dns_resolver_getmustbesecure(view->resolver, name); 3190 dns_rdataset_init(&val->fdsset); 3191 dns_rdataset_init(&val->frdataset); 3192 dns_rdataset_init(&val->fsigrdataset); 3193 dns_fixedname_init(&val->wild); 3194 dns_fixedname_init(&val->closest); 3195 isc_stdtime_get(&val->start); 3196 ISC_LINK_INIT(val, link); 3197 val->magic = VALIDATOR_MAGIC; 3198 3199 event->validator = val; 3200 3201 if ((options & DNS_VALIDATOR_DEFER) == 0) { 3202 isc_task_send(task, ISC_EVENT_PTR(&event)); 3203 } 3204 3205 *validatorp = val; 3206 3207 return (ISC_R_SUCCESS); 3208 3209cleanup: 3210 isc_mutex_destroy(&val->lock); 3211 3212 isc_task_detach(&tclone); 3213 isc_event_free(ISC_EVENT_PTR(&event)); 3214 3215 dns_view_weakdetach(&val->view); 3216 isc_mem_put(view->mctx, val, sizeof(*val)); 3217 3218 return (result); 3219} 3220 3221void 3222dns_validator_send(dns_validator_t *validator) { 3223 isc_event_t *event; 3224 REQUIRE(VALID_VALIDATOR(validator)); 3225 3226 LOCK(&validator->lock); 3227 3228 INSIST((validator->options & DNS_VALIDATOR_DEFER) != 0); 3229 event = (isc_event_t *)validator->event; 3230 validator->options &= ~DNS_VALIDATOR_DEFER; 3231 UNLOCK(&validator->lock); 3232 3233 isc_task_send(validator->task, ISC_EVENT_PTR(&event)); 3234} 3235 3236void 3237dns_validator_cancel(dns_validator_t *validator) { 3238 dns_fetch_t *fetch = NULL; 3239 3240 REQUIRE(VALID_VALIDATOR(validator)); 3241 3242 LOCK(&validator->lock); 3243 3244 validator_log(validator, ISC_LOG_DEBUG(3), "dns_validator_cancel"); 3245 3246 if ((validator->attributes & VALATTR_CANCELED) == 0) { 3247 validator->attributes |= VALATTR_CANCELED; 3248 if (validator->event != NULL) { 3249 fetch = validator->fetch; 3250 validator->fetch = NULL; 3251 3252 if (validator->subvalidator != NULL) { 3253 dns_validator_cancel(validator->subvalidator); 3254 } 3255 if ((validator->options & DNS_VALIDATOR_DEFER) != 0) { 3256 validator->options &= ~DNS_VALIDATOR_DEFER; 3257 validator_done(validator, ISC_R_CANCELED); 3258 } 3259 } 3260 } 3261 UNLOCK(&validator->lock); 3262 3263 /* Need to cancel and destroy the fetch outside validator lock */ 3264 if (fetch != NULL) { 3265 dns_resolver_cancelfetch(fetch); 3266 dns_resolver_destroyfetch(&fetch); 3267 } 3268} 3269 3270static void 3271destroy(dns_validator_t *val) { 3272 isc_mem_t *mctx; 3273 3274 REQUIRE(SHUTDOWN(val)); 3275 REQUIRE(val->event == NULL); 3276 REQUIRE(val->fetch == NULL); 3277 3278 val->magic = 0; 3279 if (val->key != NULL) { 3280 dst_key_free(&val->key); 3281 } 3282 if (val->keytable != NULL) { 3283 dns_keytable_detach(&val->keytable); 3284 } 3285 if (val->subvalidator != NULL) { 3286 dns_validator_destroy(&val->subvalidator); 3287 } 3288 disassociate_rdatasets(val); 3289 mctx = val->view->mctx; 3290 if (val->siginfo != NULL) { 3291 isc_mem_put(mctx, val->siginfo, sizeof(*val->siginfo)); 3292 } 3293 isc_mutex_destroy(&val->lock); 3294 dns_view_weakdetach(&val->view); 3295 isc_mem_put(mctx, val, sizeof(*val)); 3296} 3297 3298void 3299dns_validator_destroy(dns_validator_t **validatorp) { 3300 dns_validator_t *val; 3301 bool want_destroy = false; 3302 3303 REQUIRE(validatorp != NULL); 3304 val = *validatorp; 3305 *validatorp = NULL; 3306 REQUIRE(VALID_VALIDATOR(val)); 3307 3308 LOCK(&val->lock); 3309 3310 val->attributes |= VALATTR_SHUTDOWN; 3311 validator_log(val, ISC_LOG_DEBUG(4), "dns_validator_destroy"); 3312 3313 want_destroy = exit_check(val); 3314 UNLOCK(&val->lock); 3315 if (want_destroy) { 3316 destroy(val); 3317 } 3318} 3319 3320static void 3321validator_logv(dns_validator_t *val, isc_logcategory_t *category, 3322 isc_logmodule_t *module, int level, const char *fmt, 3323 va_list ap) { 3324 char msgbuf[2048]; 3325 static const char spaces[] = " *"; 3326 int depth = val->depth * 2; 3327 const char *viewname, *sep1, *sep2; 3328 3329 vsnprintf(msgbuf, sizeof(msgbuf), fmt, ap); 3330 3331 if ((unsigned int)depth >= sizeof spaces) { 3332 depth = sizeof spaces - 1; 3333 } 3334 3335 /* 3336 * Log the view name unless it's: 3337 * * "_default/IN" (which means there's only one view 3338 * configured in the server), or 3339 * * "_dnsclient/IN" (which means this is being called 3340 * from an application using dns/client.c). 3341 */ 3342 if (val->view->rdclass == dns_rdataclass_in && 3343 (strcmp(val->view->name, "_default") == 0 || 3344 strcmp(val->view->name, DNS_CLIENTVIEW_NAME) == 0)) 3345 { 3346 sep1 = viewname = sep2 = ""; 3347 } else { 3348 sep1 = "view "; 3349 viewname = val->view->name; 3350 sep2 = ": "; 3351 } 3352 3353 if (val->event != NULL && val->event->name != NULL) { 3354 char namebuf[DNS_NAME_FORMATSIZE]; 3355 char typebuf[DNS_RDATATYPE_FORMATSIZE]; 3356 3357 dns_name_format(val->event->name, namebuf, sizeof(namebuf)); 3358 dns_rdatatype_format(val->event->type, typebuf, 3359 sizeof(typebuf)); 3360 isc_log_write(dns_lctx, category, module, level, 3361 "%s%s%s%.*svalidating %s/%s: %s", sep1, viewname, 3362 sep2, depth, spaces, namebuf, typebuf, msgbuf); 3363 } else { 3364 isc_log_write(dns_lctx, category, module, level, 3365 "%s%s%s%.*svalidator @%p: %s", sep1, viewname, 3366 sep2, depth, spaces, val, msgbuf); 3367 } 3368} 3369 3370static void 3371validator_log(void *val, int level, const char *fmt, ...) { 3372 va_list ap; 3373 3374 if (!isc_log_wouldlog(dns_lctx, level)) { 3375 return; 3376 } 3377 3378 va_start(ap, fmt); 3379 3380 validator_logv(val, DNS_LOGCATEGORY_DNSSEC, DNS_LOGMODULE_VALIDATOR, 3381 level, fmt, ap); 3382 va_end(ap); 3383} 3384 3385static void 3386validator_logcreate(dns_validator_t *val, dns_name_t *name, 3387 dns_rdatatype_t type, const char *caller, 3388 const char *operation) { 3389 char namestr[DNS_NAME_FORMATSIZE]; 3390 char typestr[DNS_RDATATYPE_FORMATSIZE]; 3391 3392 dns_name_format(name, namestr, sizeof(namestr)); 3393 dns_rdatatype_format(type, typestr, sizeof(typestr)); 3394 validator_log(val, ISC_LOG_DEBUG(9), "%s: creating %s for %s %s", 3395 caller, operation, namestr, typestr); 3396} 3397