validator.c revision 1.14
1/* $NetBSD: validator.c,v 1.14 2024/02/13 15:27:20 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, start searching from the next position in 1110 * 'rdataset' to find 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 no_rdata = false; 1124 1125 if (oldkey == NULL) { 1126 result = dns_rdataset_first(rdataset); 1127 } else { 1128 dst_key_free(&oldkey); 1129 val->key = NULL; 1130 result = dns_rdataset_next(rdataset); 1131 } 1132 if (result != ISC_R_SUCCESS) { 1133 goto done; 1134 } 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_ex(&siginfo->signer, rdata.rdclass, &b, 1143 val->view->mctx, no_rdata, 1144 &val->key); 1145 if (result == ISC_R_SUCCESS) { 1146 if (siginfo->algorithm == 1147 (dns_secalg_t)dst_key_alg(val->key) && 1148 siginfo->keyid == 1149 (dns_keytag_t)dst_key_id(val->key) && 1150 (dst_key_flags(val->key) & DNS_KEYFLAG_REVOKE) == 1151 0 && 1152 dst_key_iszonekey(val->key)) 1153 { 1154 if (no_rdata) { 1155 /* Retry with full key */ 1156 dns_rdata_reset(&rdata); 1157 dst_key_free(&val->key); 1158 no_rdata = false; 1159 continue; 1160 } 1161 /* This is the key we're looking for. */ 1162 goto done; 1163 } 1164 dst_key_free(&val->key); 1165 } 1166 dns_rdata_reset(&rdata); 1167 result = dns_rdataset_next(rdataset); 1168 no_rdata = true; 1169 } while (result == ISC_R_SUCCESS); 1170 1171done: 1172 if (result == ISC_R_NOMORE) { 1173 result = ISC_R_NOTFOUND; 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 vresult = verify(val, val->key, &rdata, val->siginfo->keyid); 1595 if (vresult != ISC_R_SUCCESS) { 1596 val->failed = true; 1597 validator_log(val, ISC_LOG_DEBUG(3), 1598 "failed to verify rdataset"); 1599 } else { 1600 dns_rdataset_trimttl(event->rdataset, 1601 event->sigrdataset, val->siginfo, 1602 val->start, 1603 val->view->acceptexpired); 1604 } 1605 1606 if (val->key != NULL) { 1607 dst_key_free(&val->key); 1608 } 1609 if (val->keyset != NULL) { 1610 dns_rdataset_disassociate(val->keyset); 1611 val->keyset = NULL; 1612 } 1613 val->key = NULL; 1614 if (NEEDNOQNAME(val)) { 1615 if (val->event->message == NULL) { 1616 validator_log(val, ISC_LOG_DEBUG(3), 1617 "no message available " 1618 "for noqname proof"); 1619 return (DNS_R_NOVALIDSIG); 1620 } 1621 validator_log(val, ISC_LOG_DEBUG(3), 1622 "looking for noqname proof"); 1623 return (validate_nx(val, false)); 1624 } else if (vresult == ISC_R_SUCCESS) { 1625 marksecure(event); 1626 validator_log(val, ISC_LOG_DEBUG(3), 1627 "marking as secure, " 1628 "noqname proof not needed"); 1629 return (ISC_R_SUCCESS); 1630 } else { 1631 validator_log(val, ISC_LOG_DEBUG(3), 1632 "verify failure: %s", 1633 isc_result_totext(vresult)); 1634 resume = false; 1635 } 1636 if (val->failed) { 1637 result = ISC_R_NOMORE; 1638 break; 1639 } 1640 } 1641 if (result != ISC_R_NOMORE) { 1642 validator_log(val, ISC_LOG_DEBUG(3), 1643 "failed to iterate signatures: %s", 1644 isc_result_totext(result)); 1645 return (result); 1646 } 1647 1648 validator_log(val, ISC_LOG_INFO, "no valid signature found"); 1649 return (vresult); 1650} 1651 1652/*% 1653 * Check whether this DNSKEY (keyrdata) signed the DNSKEY RRset 1654 * (val->event->rdataset). 1655 */ 1656static isc_result_t 1657check_signer(dns_validator_t *val, dns_rdata_t *keyrdata, uint16_t keyid, 1658 dns_secalg_t algorithm) { 1659 dns_rdata_rrsig_t sig; 1660 dst_key_t *dstkey = NULL; 1661 isc_result_t result; 1662 1663 for (result = dns_rdataset_first(val->event->sigrdataset); 1664 result == ISC_R_SUCCESS; 1665 result = dns_rdataset_next(val->event->sigrdataset)) 1666 { 1667 dns_rdata_t rdata = DNS_RDATA_INIT; 1668 1669 dns_rdataset_current(val->event->sigrdataset, &rdata); 1670 result = dns_rdata_tostruct(&rdata, &sig, NULL); 1671 RUNTIME_CHECK(result == ISC_R_SUCCESS); 1672 if (keyid != sig.keyid || algorithm != sig.algorithm) { 1673 continue; 1674 } 1675 if (dstkey == NULL) { 1676 result = dns_dnssec_keyfromrdata( 1677 val->event->name, keyrdata, val->view->mctx, 1678 &dstkey); 1679 if (result != ISC_R_SUCCESS) { 1680 /* 1681 * This really shouldn't happen, but... 1682 */ 1683 continue; 1684 } 1685 } 1686 result = verify(val, dstkey, &rdata, sig.keyid); 1687 if (result == ISC_R_SUCCESS) { 1688 break; 1689 } 1690 } 1691 1692 if (dstkey != NULL) { 1693 dst_key_free(&dstkey); 1694 } 1695 1696 return (result); 1697} 1698 1699/* 1700 * get_dsset() is called to look up a DS RRset corresponding to the name 1701 * of a DNSKEY record, either in the cache or, if necessary, by starting a 1702 * fetch. This is done in the context of validating a zone key to build a 1703 * trust chain. 1704 * 1705 * Returns: 1706 * \li ISC_R_COMPLETE a DS has not been found; the caller should 1707 * stop trying to validate the zone key and 1708 * return the result code in '*resp'. 1709 * \li DNS_R_CONTINUE a DS has been found and the caller may 1710 * continue the zone key validation. 1711 */ 1712static isc_result_t 1713get_dsset(dns_validator_t *val, dns_name_t *tname, isc_result_t *resp) { 1714 isc_result_t result; 1715 1716 result = view_find(val, tname, dns_rdatatype_ds); 1717 switch (result) { 1718 case ISC_R_SUCCESS: 1719 /* 1720 * We have a DS RRset. 1721 */ 1722 val->dsset = &val->frdataset; 1723 if ((DNS_TRUST_PENDING(val->frdataset.trust) || 1724 DNS_TRUST_ANSWER(val->frdataset.trust)) && 1725 dns_rdataset_isassociated(&val->fsigrdataset)) 1726 { 1727 /* 1728 * ... which is signed but not yet validated. 1729 */ 1730 result = create_validator( 1731 val, tname, dns_rdatatype_ds, &val->frdataset, 1732 &val->fsigrdataset, validator_callback_ds, 1733 "validate_dnskey"); 1734 *resp = DNS_R_WAIT; 1735 if (result != ISC_R_SUCCESS) { 1736 *resp = result; 1737 } 1738 return (ISC_R_COMPLETE); 1739 } else if (DNS_TRUST_PENDING(val->frdataset.trust)) { 1740 /* 1741 * There should never be an unsigned DS. 1742 */ 1743 disassociate_rdatasets(val); 1744 validator_log(val, ISC_LOG_DEBUG(2), 1745 "unsigned DS record"); 1746 *resp = DNS_R_NOVALIDSIG; 1747 return (ISC_R_COMPLETE); 1748 } 1749 break; 1750 1751 case ISC_R_NOTFOUND: 1752 /* 1753 * We don't have the DS. Find it. 1754 */ 1755 result = create_fetch(val, tname, dns_rdatatype_ds, 1756 fetch_callback_ds, "validate_dnskey"); 1757 *resp = DNS_R_WAIT; 1758 if (result != ISC_R_SUCCESS) { 1759 *resp = result; 1760 } 1761 return (ISC_R_COMPLETE); 1762 1763 case DNS_R_NCACHENXDOMAIN: 1764 case DNS_R_NCACHENXRRSET: 1765 case DNS_R_EMPTYNAME: 1766 case DNS_R_NXDOMAIN: 1767 case DNS_R_NXRRSET: 1768 case DNS_R_CNAME: 1769 /* 1770 * The DS does not exist. 1771 */ 1772 disassociate_rdatasets(val); 1773 validator_log(val, ISC_LOG_DEBUG(2), "no DS record"); 1774 *resp = DNS_R_NOVALIDSIG; 1775 return (ISC_R_COMPLETE); 1776 1777 case DNS_R_BROKENCHAIN: 1778 *resp = result; 1779 return (ISC_R_COMPLETE); 1780 1781 default: 1782 break; 1783 } 1784 1785 return (DNS_R_CONTINUE); 1786} 1787 1788/*% 1789 * Attempts positive response validation of an RRset containing zone keys 1790 * (i.e. a DNSKEY rrset). 1791 * 1792 * Caller must be holding the validator lock. 1793 * 1794 * Returns: 1795 * \li ISC_R_SUCCESS Validation completed successfully 1796 * \li DNS_R_WAIT Validation has started but is waiting 1797 * for an event. 1798 * \li Other return codes are possible and all indicate failure. 1799 */ 1800static isc_result_t 1801validate_dnskey(dns_validator_t *val) { 1802 isc_result_t result; 1803 dns_rdata_t dsrdata = DNS_RDATA_INIT; 1804 dns_rdata_t keyrdata = DNS_RDATA_INIT; 1805 dns_keynode_t *keynode = NULL; 1806 dns_rdata_ds_t ds; 1807 bool supported_algorithm; 1808 char digest_types[256]; 1809 1810 /* 1811 * If we don't already have a DS RRset, check to see if there's 1812 * a DS style trust anchor configured for this key. 1813 */ 1814 if (val->dsset == NULL) { 1815 result = dns_keytable_find(val->keytable, val->event->name, 1816 &keynode); 1817 if (result == ISC_R_SUCCESS) { 1818 if (dns_keynode_dsset(keynode, &val->fdsset)) { 1819 val->dsset = &val->fdsset; 1820 } 1821 dns_keytable_detachkeynode(val->keytable, &keynode); 1822 } 1823 } 1824 1825 /* 1826 * No trust anchor for this name, so we look up the DS at the parent. 1827 */ 1828 if (val->dsset == NULL) { 1829 isc_result_t tresult = ISC_R_SUCCESS; 1830 1831 /* 1832 * If this is the root name and there was no trust anchor, 1833 * we can give up now, since there's no DS at the root. 1834 */ 1835 if (dns_name_equal(val->event->name, dns_rootname)) { 1836 if ((val->attributes & VALATTR_TRIEDVERIFY) != 0) { 1837 validator_log(val, ISC_LOG_DEBUG(3), 1838 "root key failed to validate"); 1839 } else { 1840 validator_log(val, ISC_LOG_DEBUG(3), 1841 "no trusted root key"); 1842 } 1843 result = DNS_R_NOVALIDSIG; 1844 goto cleanup; 1845 } 1846 1847 /* 1848 * Look up the DS RRset for this name. 1849 */ 1850 result = get_dsset(val, val->event->name, &tresult); 1851 if (result == ISC_R_COMPLETE) { 1852 result = tresult; 1853 goto cleanup; 1854 } 1855 } 1856 1857 /* 1858 * We have a DS set. 1859 */ 1860 INSIST(val->dsset != NULL); 1861 1862 if (val->dsset->trust < dns_trust_secure) { 1863 result = markanswer(val, "validate_dnskey (2)", "insecure DS"); 1864 goto cleanup; 1865 } 1866 1867 /* 1868 * Look through the DS record and find the keys that can sign the 1869 * key set and the matching signature. For each such key, attempt 1870 * verification. 1871 */ 1872 1873 supported_algorithm = false; 1874 1875 /* 1876 * If DNS_DSDIGEST_SHA256 or DNS_DSDIGEST_SHA384 is present we 1877 * are required to prefer it over DNS_DSDIGEST_SHA1. This in 1878 * practice means that we need to ignore DNS_DSDIGEST_SHA1 if a 1879 * DNS_DSDIGEST_SHA256 or DNS_DSDIGEST_SHA384 is present. 1880 */ 1881 memset(digest_types, 1, sizeof(digest_types)); 1882 for (result = dns_rdataset_first(val->dsset); result == ISC_R_SUCCESS; 1883 result = dns_rdataset_next(val->dsset)) 1884 { 1885 dns_rdata_reset(&dsrdata); 1886 dns_rdataset_current(val->dsset, &dsrdata); 1887 result = dns_rdata_tostruct(&dsrdata, &ds, NULL); 1888 RUNTIME_CHECK(result == ISC_R_SUCCESS); 1889 1890 if (!dns_resolver_ds_digest_supported(val->view->resolver, 1891 val->event->name, 1892 ds.digest_type)) 1893 { 1894 continue; 1895 } 1896 1897 if (!dns_resolver_algorithm_supported(val->view->resolver, 1898 val->event->name, 1899 ds.algorithm)) 1900 { 1901 continue; 1902 } 1903 1904 if ((ds.digest_type == DNS_DSDIGEST_SHA256 && 1905 ds.length == ISC_SHA256_DIGESTLENGTH) || 1906 (ds.digest_type == DNS_DSDIGEST_SHA384 && 1907 ds.length == ISC_SHA384_DIGESTLENGTH)) 1908 { 1909 digest_types[DNS_DSDIGEST_SHA1] = 0; 1910 break; 1911 } 1912 } 1913 1914 for (result = dns_rdataset_first(val->dsset); result == ISC_R_SUCCESS; 1915 result = dns_rdataset_next(val->dsset)) 1916 { 1917 dns_rdata_reset(&dsrdata); 1918 dns_rdataset_current(val->dsset, &dsrdata); 1919 result = dns_rdata_tostruct(&dsrdata, &ds, NULL); 1920 RUNTIME_CHECK(result == ISC_R_SUCCESS); 1921 1922 if (digest_types[ds.digest_type] == 0) { 1923 continue; 1924 } 1925 1926 if (!dns_resolver_ds_digest_supported(val->view->resolver, 1927 val->event->name, 1928 ds.digest_type)) 1929 { 1930 continue; 1931 } 1932 1933 if (!dns_resolver_algorithm_supported(val->view->resolver, 1934 val->event->name, 1935 ds.algorithm)) 1936 { 1937 continue; 1938 } 1939 1940 supported_algorithm = true; 1941 1942 /* 1943 * Find the DNSKEY matching the DS... 1944 */ 1945 result = dns_dnssec_matchdskey(val->event->name, &dsrdata, 1946 val->event->rdataset, &keyrdata); 1947 if (result != ISC_R_SUCCESS) { 1948 validator_log(val, ISC_LOG_DEBUG(3), 1949 "no DNSKEY matching DS"); 1950 continue; 1951 } 1952 1953 /* 1954 * ... and check that it signed the DNSKEY RRset. 1955 */ 1956 result = check_signer(val, &keyrdata, ds.key_tag, ds.algorithm); 1957 if (result == ISC_R_SUCCESS) { 1958 break; 1959 } 1960 validator_log(val, ISC_LOG_DEBUG(3), 1961 "no RRSIG matching DS key"); 1962 } 1963 1964 if (result == ISC_R_SUCCESS) { 1965 marksecure(val->event); 1966 validator_log(val, ISC_LOG_DEBUG(3), "marking as secure (DS)"); 1967 } else if (result == ISC_R_NOMORE && !supported_algorithm) { 1968 validator_log(val, ISC_LOG_DEBUG(3), 1969 "no supported algorithm/digest (DS)"); 1970 result = markanswer(val, "validate_dnskey (3)", 1971 "no supported algorithm/digest (DS)"); 1972 } else { 1973 validator_log(val, ISC_LOG_INFO, 1974 "no valid signature found (DS)"); 1975 result = DNS_R_NOVALIDSIG; 1976 } 1977 1978cleanup: 1979 if (val->dsset == &val->fdsset) { 1980 val->dsset = NULL; 1981 dns_rdataset_disassociate(&val->fdsset); 1982 } 1983 1984 return (result); 1985} 1986 1987/*% 1988 * val_rdataset_first and val_rdataset_next provide iteration methods 1989 * that hide whether we are iterating across the AUTHORITY section of 1990 * a message, or a negative cache rdataset. 1991 */ 1992static isc_result_t 1993val_rdataset_first(dns_validator_t *val, dns_name_t **namep, 1994 dns_rdataset_t **rdatasetp) { 1995 dns_message_t *message = val->event->message; 1996 isc_result_t result; 1997 1998 REQUIRE(rdatasetp != NULL); 1999 REQUIRE(namep != NULL); 2000 if (message == NULL) { 2001 REQUIRE(*rdatasetp != NULL); 2002 REQUIRE(*namep != NULL); 2003 } else { 2004 REQUIRE(*rdatasetp == NULL); 2005 REQUIRE(*namep == NULL); 2006 } 2007 2008 if (message != NULL) { 2009 result = dns_message_firstname(message, DNS_SECTION_AUTHORITY); 2010 if (result != ISC_R_SUCCESS) { 2011 return (result); 2012 } 2013 dns_message_currentname(message, DNS_SECTION_AUTHORITY, namep); 2014 *rdatasetp = ISC_LIST_HEAD((*namep)->list); 2015 INSIST(*rdatasetp != NULL); 2016 } else { 2017 result = dns_rdataset_first(val->event->rdataset); 2018 if (result == ISC_R_SUCCESS) { 2019 dns_ncache_current(val->event->rdataset, *namep, 2020 *rdatasetp); 2021 } 2022 } 2023 return (result); 2024} 2025 2026static isc_result_t 2027val_rdataset_next(dns_validator_t *val, dns_name_t **namep, 2028 dns_rdataset_t **rdatasetp) { 2029 dns_message_t *message = val->event->message; 2030 isc_result_t result = ISC_R_SUCCESS; 2031 2032 REQUIRE(rdatasetp != NULL && *rdatasetp != NULL); 2033 REQUIRE(namep != NULL && *namep != NULL); 2034 2035 if (message != NULL) { 2036 dns_rdataset_t *rdataset = *rdatasetp; 2037 rdataset = ISC_LIST_NEXT(rdataset, link); 2038 if (rdataset == NULL) { 2039 *namep = NULL; 2040 result = dns_message_nextname(message, 2041 DNS_SECTION_AUTHORITY); 2042 if (result == ISC_R_SUCCESS) { 2043 dns_message_currentname( 2044 message, DNS_SECTION_AUTHORITY, namep); 2045 rdataset = ISC_LIST_HEAD((*namep)->list); 2046 INSIST(rdataset != NULL); 2047 } 2048 } 2049 *rdatasetp = rdataset; 2050 } else { 2051 dns_rdataset_disassociate(*rdatasetp); 2052 result = dns_rdataset_next(val->event->rdataset); 2053 if (result == ISC_R_SUCCESS) { 2054 dns_ncache_current(val->event->rdataset, *namep, 2055 *rdatasetp); 2056 } 2057 } 2058 return (result); 2059} 2060 2061/*% 2062 * Look for NODATA at the wildcard and NOWILDCARD proofs in the 2063 * previously validated NSEC records. As these proofs are mutually 2064 * exclusive we stop when one is found. 2065 * 2066 * Returns 2067 * \li ISC_R_SUCCESS 2068 */ 2069static isc_result_t 2070checkwildcard(dns_validator_t *val, dns_rdatatype_t type, 2071 dns_name_t *zonename) { 2072 dns_name_t *name, *wild, tname; 2073 isc_result_t result; 2074 bool exists, data; 2075 char namebuf[DNS_NAME_FORMATSIZE]; 2076 dns_rdataset_t *rdataset, trdataset; 2077 2078 dns_name_init(&tname, NULL); 2079 dns_rdataset_init(&trdataset); 2080 wild = dns_fixedname_name(&val->wild); 2081 2082 if (dns_name_countlabels(wild) == 0) { 2083 validator_log(val, ISC_LOG_DEBUG(3), 2084 "in checkwildcard: no wildcard to check"); 2085 return (ISC_R_SUCCESS); 2086 } 2087 2088 dns_name_format(wild, namebuf, sizeof(namebuf)); 2089 validator_log(val, ISC_LOG_DEBUG(3), "in checkwildcard: %s", namebuf); 2090 2091 if (val->event->message == NULL) { 2092 name = &tname; 2093 rdataset = &trdataset; 2094 } else { 2095 name = NULL; 2096 rdataset = NULL; 2097 } 2098 2099 for (result = val_rdataset_first(val, &name, &rdataset); 2100 result == ISC_R_SUCCESS; 2101 result = val_rdataset_next(val, &name, &rdataset)) 2102 { 2103 if (rdataset->type != type || 2104 rdataset->trust != dns_trust_secure) 2105 { 2106 continue; 2107 } 2108 2109 if (rdataset->type == dns_rdatatype_nsec && 2110 (NEEDNODATA(val) || NEEDNOWILDCARD(val)) && 2111 !FOUNDNODATA(val) && !FOUNDNOWILDCARD(val) && 2112 dns_nsec_noexistnodata(val->event->type, wild, name, 2113 rdataset, &exists, &data, NULL, 2114 validator_log, val) == ISC_R_SUCCESS) 2115 { 2116 dns_name_t **proofs = val->event->proofs; 2117 if (exists && !data) { 2118 val->attributes |= VALATTR_FOUNDNODATA; 2119 } 2120 if (exists && !data && NEEDNODATA(val)) { 2121 proofs[DNS_VALIDATOR_NODATAPROOF] = name; 2122 } 2123 if (!exists) { 2124 val->attributes |= VALATTR_FOUNDNOWILDCARD; 2125 } 2126 if (!exists && NEEDNOQNAME(val)) { 2127 proofs[DNS_VALIDATOR_NOWILDCARDPROOF] = name; 2128 } 2129 if (dns_rdataset_isassociated(&trdataset)) { 2130 dns_rdataset_disassociate(&trdataset); 2131 } 2132 return (ISC_R_SUCCESS); 2133 } 2134 2135 if (rdataset->type == dns_rdatatype_nsec3 && 2136 (NEEDNODATA(val) || NEEDNOWILDCARD(val)) && 2137 !FOUNDNODATA(val) && !FOUNDNOWILDCARD(val) && 2138 dns_nsec3_noexistnodata( 2139 val->event->type, wild, name, rdataset, zonename, 2140 &exists, &data, NULL, NULL, NULL, NULL, NULL, NULL, 2141 validator_log, val) == ISC_R_SUCCESS) 2142 { 2143 dns_name_t **proofs = val->event->proofs; 2144 if (exists && !data) { 2145 val->attributes |= VALATTR_FOUNDNODATA; 2146 } 2147 if (exists && !data && NEEDNODATA(val)) { 2148 proofs[DNS_VALIDATOR_NODATAPROOF] = name; 2149 } 2150 if (!exists) { 2151 val->attributes |= VALATTR_FOUNDNOWILDCARD; 2152 } 2153 if (!exists && NEEDNOQNAME(val)) { 2154 proofs[DNS_VALIDATOR_NOWILDCARDPROOF] = name; 2155 } 2156 if (dns_rdataset_isassociated(&trdataset)) { 2157 dns_rdataset_disassociate(&trdataset); 2158 } 2159 return (ISC_R_SUCCESS); 2160 } 2161 } 2162 if (result == ISC_R_NOMORE) { 2163 result = ISC_R_SUCCESS; 2164 } 2165 if (dns_rdataset_isassociated(&trdataset)) { 2166 dns_rdataset_disassociate(&trdataset); 2167 } 2168 return (result); 2169} 2170 2171/* 2172 * Look for the needed proofs for a negative or wildcard response 2173 * from a zone using NSEC3, and set flags in the validator as they 2174 * are found. 2175 */ 2176static isc_result_t 2177findnsec3proofs(dns_validator_t *val) { 2178 dns_name_t *name, tname; 2179 isc_result_t result; 2180 bool exists, data, optout, unknown; 2181 bool setclosest, setnearest, *setclosestp; 2182 dns_fixedname_t fclosest, fnearest, fzonename; 2183 dns_name_t *closest, *nearest, *zonename, *closestp; 2184 dns_name_t **proofs = val->event->proofs; 2185 dns_rdataset_t *rdataset, trdataset; 2186 2187 dns_name_init(&tname, NULL); 2188 dns_rdataset_init(&trdataset); 2189 closest = dns_fixedname_initname(&fclosest); 2190 nearest = dns_fixedname_initname(&fnearest); 2191 zonename = dns_fixedname_initname(&fzonename); 2192 2193 if (val->event->message == NULL) { 2194 name = &tname; 2195 rdataset = &trdataset; 2196 } else { 2197 name = NULL; 2198 rdataset = NULL; 2199 } 2200 2201 for (result = val_rdataset_first(val, &name, &rdataset); 2202 result == ISC_R_SUCCESS; 2203 result = val_rdataset_next(val, &name, &rdataset)) 2204 { 2205 if (rdataset->type != dns_rdatatype_nsec3 || 2206 rdataset->trust != dns_trust_secure) 2207 { 2208 continue; 2209 } 2210 2211 result = dns_nsec3_noexistnodata( 2212 val->event->type, val->event->name, name, rdataset, 2213 zonename, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 2214 NULL, validator_log, val); 2215 if (result != ISC_R_IGNORE && result != ISC_R_SUCCESS) { 2216 if (dns_rdataset_isassociated(&trdataset)) { 2217 dns_rdataset_disassociate(&trdataset); 2218 } 2219 return (result); 2220 } 2221 } 2222 if (result != ISC_R_NOMORE) { 2223 result = ISC_R_SUCCESS; 2224 } 2225 POST(result); 2226 2227 if (dns_name_countlabels(zonename) == 0) { 2228 return (ISC_R_SUCCESS); 2229 } 2230 2231 /* 2232 * If the val->closest is set then we want to use it otherwise 2233 * we need to discover it. 2234 */ 2235 if (dns_name_countlabels(dns_fixedname_name(&val->closest)) != 0) { 2236 char namebuf[DNS_NAME_FORMATSIZE]; 2237 2238 dns_name_format(dns_fixedname_name(&val->closest), namebuf, 2239 sizeof(namebuf)); 2240 validator_log(val, ISC_LOG_DEBUG(3), 2241 "closest encloser from wildcard signature '%s'", 2242 namebuf); 2243 dns_name_copynf(dns_fixedname_name(&val->closest), closest); 2244 closestp = NULL; 2245 setclosestp = NULL; 2246 } else { 2247 closestp = closest; 2248 setclosestp = &setclosest; 2249 } 2250 2251 for (result = val_rdataset_first(val, &name, &rdataset); 2252 result == ISC_R_SUCCESS; 2253 result = val_rdataset_next(val, &name, &rdataset)) 2254 { 2255 if (rdataset->type != dns_rdatatype_nsec3 || 2256 rdataset->trust != dns_trust_secure) 2257 { 2258 continue; 2259 } 2260 2261 /* 2262 * We process all NSEC3 records to find the closest 2263 * encloser and nearest name to the closest encloser. 2264 */ 2265 setclosest = setnearest = false; 2266 optout = false; 2267 unknown = false; 2268 result = dns_nsec3_noexistnodata( 2269 val->event->type, val->event->name, name, rdataset, 2270 zonename, &exists, &data, &optout, &unknown, 2271 setclosestp, &setnearest, closestp, nearest, 2272 validator_log, val); 2273 if (unknown) { 2274 val->attributes |= VALATTR_FOUNDUNKNOWN; 2275 } 2276 if (result == DNS_R_NSEC3ITERRANGE) { 2277 /* 2278 * We don't really know which NSEC3 record provides 2279 * which proof. Just populate them. 2280 */ 2281 if (NEEDNOQNAME(val) && 2282 proofs[DNS_VALIDATOR_NOQNAMEPROOF] == NULL) 2283 { 2284 proofs[DNS_VALIDATOR_NOQNAMEPROOF] = name; 2285 } else if (setclosest) { 2286 proofs[DNS_VALIDATOR_CLOSESTENCLOSER] = name; 2287 } else if (NEEDNODATA(val) && 2288 proofs[DNS_VALIDATOR_NODATAPROOF] == NULL) 2289 { 2290 proofs[DNS_VALIDATOR_NODATAPROOF] = name; 2291 } else if (NEEDNOWILDCARD(val) && 2292 proofs[DNS_VALIDATOR_NOWILDCARDPROOF] == 2293 NULL) 2294 { 2295 proofs[DNS_VALIDATOR_NOWILDCARDPROOF] = name; 2296 } 2297 return (result); 2298 } 2299 if (result != ISC_R_SUCCESS) { 2300 continue; 2301 } 2302 if (setclosest) { 2303 proofs[DNS_VALIDATOR_CLOSESTENCLOSER] = name; 2304 } 2305 if (exists && !data && NEEDNODATA(val)) { 2306 val->attributes |= VALATTR_FOUNDNODATA; 2307 proofs[DNS_VALIDATOR_NODATAPROOF] = name; 2308 } 2309 if (!exists && setnearest) { 2310 val->attributes |= VALATTR_FOUNDNOQNAME; 2311 proofs[DNS_VALIDATOR_NOQNAMEPROOF] = name; 2312 if (optout) { 2313 val->attributes |= VALATTR_FOUNDOPTOUT; 2314 } 2315 } 2316 } 2317 if (result == ISC_R_NOMORE) { 2318 result = ISC_R_SUCCESS; 2319 } 2320 2321 /* 2322 * To know we have a valid noqname and optout proofs we need to also 2323 * have a valid closest encloser. Otherwise we could still be looking 2324 * at proofs from the parent zone. 2325 */ 2326 if (dns_name_countlabels(closest) > 0 && 2327 dns_name_countlabels(nearest) == 2328 dns_name_countlabels(closest) + 1 && 2329 dns_name_issubdomain(nearest, closest)) 2330 { 2331 val->attributes |= VALATTR_FOUNDCLOSEST; 2332 result = dns_name_concatenate(dns_wildcardname, closest, 2333 dns_fixedname_name(&val->wild), 2334 NULL); 2335 RUNTIME_CHECK(result == ISC_R_SUCCESS); 2336 } else { 2337 val->attributes &= ~VALATTR_FOUNDNOQNAME; 2338 val->attributes &= ~VALATTR_FOUNDOPTOUT; 2339 proofs[DNS_VALIDATOR_NOQNAMEPROOF] = NULL; 2340 } 2341 2342 /* 2343 * Do we need to check for the wildcard? 2344 */ 2345 if (FOUNDNOQNAME(val) && FOUNDCLOSEST(val) && 2346 ((NEEDNODATA(val) && !FOUNDNODATA(val)) || NEEDNOWILDCARD(val))) 2347 { 2348 result = checkwildcard(val, dns_rdatatype_nsec3, zonename); 2349 if (result != ISC_R_SUCCESS) { 2350 return (result); 2351 } 2352 } 2353 return (result); 2354} 2355 2356/* 2357 * Start a validator for negative response data. 2358 * 2359 * Returns: 2360 * \li DNS_R_CONTINUE Validation skipped, continue 2361 * \li DNS_R_WAIT Validation is in progress 2362 * 2363 * \li Other return codes indicate failure. 2364 */ 2365static isc_result_t 2366validate_neg_rrset(dns_validator_t *val, dns_name_t *name, 2367 dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset) { 2368 isc_result_t result; 2369 2370 /* 2371 * If a signed zone is missing the zone key, bad 2372 * things could happen. A query for data in the zone 2373 * would lead to a query for the zone key, which 2374 * would return a negative answer, which would contain 2375 * an SOA and an NSEC signed by the missing key, which 2376 * would trigger another query for the DNSKEY (since 2377 * the first one is still in progress), and go into an 2378 * infinite loop. Avoid that. 2379 */ 2380 if (val->event->type == dns_rdatatype_dnskey && 2381 rdataset->type == dns_rdatatype_nsec && 2382 dns_name_equal(name, val->event->name)) 2383 { 2384 dns_rdata_t nsec = DNS_RDATA_INIT; 2385 2386 result = dns_rdataset_first(rdataset); 2387 if (result != ISC_R_SUCCESS) { 2388 return (result); 2389 } 2390 dns_rdataset_current(rdataset, &nsec); 2391 if (dns_nsec_typepresent(&nsec, dns_rdatatype_soa)) { 2392 return (DNS_R_CONTINUE); 2393 } 2394 } 2395 2396 val->currentset = rdataset; 2397 result = create_validator(val, name, rdataset->type, rdataset, 2398 sigrdataset, validator_callback_nsec, 2399 "validate_neg_rrset"); 2400 if (result != ISC_R_SUCCESS) { 2401 return (result); 2402 } 2403 2404 val->authcount++; 2405 return (DNS_R_WAIT); 2406} 2407 2408/*% 2409 * Validate the authority section records. 2410 */ 2411static isc_result_t 2412validate_authority(dns_validator_t *val, bool resume) { 2413 dns_name_t *name; 2414 dns_message_t *message = val->event->message; 2415 isc_result_t result; 2416 2417 if (!resume) { 2418 result = dns_message_firstname(message, DNS_SECTION_AUTHORITY); 2419 } else { 2420 result = ISC_R_SUCCESS; 2421 } 2422 2423 for (; result == ISC_R_SUCCESS; 2424 result = dns_message_nextname(message, DNS_SECTION_AUTHORITY)) 2425 { 2426 dns_rdataset_t *rdataset = NULL, *sigrdataset = NULL; 2427 2428 name = NULL; 2429 dns_message_currentname(message, DNS_SECTION_AUTHORITY, &name); 2430 if (resume) { 2431 rdataset = ISC_LIST_NEXT(val->currentset, link); 2432 val->currentset = NULL; 2433 resume = false; 2434 } else { 2435 rdataset = ISC_LIST_HEAD(name->list); 2436 } 2437 2438 for (; rdataset != NULL; 2439 rdataset = ISC_LIST_NEXT(rdataset, link)) 2440 { 2441 if (rdataset->type == dns_rdatatype_rrsig) { 2442 continue; 2443 } 2444 2445 for (sigrdataset = ISC_LIST_HEAD(name->list); 2446 sigrdataset != NULL; 2447 sigrdataset = ISC_LIST_NEXT(sigrdataset, link)) 2448 { 2449 if (sigrdataset->type == dns_rdatatype_rrsig && 2450 sigrdataset->covers == rdataset->type) 2451 { 2452 break; 2453 } 2454 } 2455 2456 result = validate_neg_rrset(val, name, rdataset, 2457 sigrdataset); 2458 if (result != DNS_R_CONTINUE) { 2459 return (result); 2460 } 2461 } 2462 } 2463 if (result == ISC_R_NOMORE) { 2464 result = ISC_R_SUCCESS; 2465 } 2466 return (result); 2467} 2468 2469/*% 2470 * Validate negative cache elements. 2471 */ 2472static isc_result_t 2473validate_ncache(dns_validator_t *val, bool resume) { 2474 dns_name_t *name; 2475 isc_result_t result; 2476 2477 if (!resume) { 2478 result = dns_rdataset_first(val->event->rdataset); 2479 } else { 2480 result = dns_rdataset_next(val->event->rdataset); 2481 } 2482 2483 for (; result == ISC_R_SUCCESS; 2484 result = dns_rdataset_next(val->event->rdataset)) 2485 { 2486 dns_rdataset_t *rdataset, *sigrdataset = NULL; 2487 2488 disassociate_rdatasets(val); 2489 2490 name = dns_fixedname_initname(&val->fname); 2491 rdataset = &val->frdataset; 2492 dns_ncache_current(val->event->rdataset, name, rdataset); 2493 2494 if (val->frdataset.type == dns_rdatatype_rrsig) { 2495 continue; 2496 } 2497 2498 result = dns_ncache_getsigrdataset(val->event->rdataset, name, 2499 rdataset->type, 2500 &val->fsigrdataset); 2501 if (result == ISC_R_SUCCESS) { 2502 sigrdataset = &val->fsigrdataset; 2503 } 2504 2505 result = validate_neg_rrset(val, name, rdataset, sigrdataset); 2506 if (result == DNS_R_CONTINUE) { 2507 continue; 2508 } 2509 2510 return (result); 2511 } 2512 if (result == ISC_R_NOMORE) { 2513 result = ISC_R_SUCCESS; 2514 } 2515 2516 return (result); 2517} 2518 2519/*% 2520 * Prove a negative answer is good or that there is a NOQNAME when the 2521 * answer is from a wildcard. 2522 * 2523 * Loop through the authority section looking for NODATA, NOWILDCARD 2524 * and NOQNAME proofs in the NSEC records by calling 2525 * validator_callback_nsec(). 2526 * 2527 * If the required proofs are found we are done. 2528 * 2529 * If the proofs are not found attempt to prove this is an unsecure 2530 * response. 2531 */ 2532static isc_result_t 2533validate_nx(dns_validator_t *val, bool resume) { 2534 isc_result_t result; 2535 2536 if (resume) { 2537 validator_log(val, ISC_LOG_DEBUG(3), "resuming validate_nx"); 2538 } 2539 2540 if (val->event->message == NULL) { 2541 result = validate_ncache(val, resume); 2542 } else { 2543 result = validate_authority(val, resume); 2544 } 2545 2546 if (result != ISC_R_SUCCESS) { 2547 return (result); 2548 } 2549 2550 /* 2551 * Do we only need to check for NOQNAME? To get here we must have 2552 * had a secure wildcard answer. 2553 */ 2554 if (!NEEDNODATA(val) && !NEEDNOWILDCARD(val) && NEEDNOQNAME(val)) { 2555 if (!FOUNDNOQNAME(val)) { 2556 result = findnsec3proofs(val); 2557 if (result == DNS_R_NSEC3ITERRANGE) { 2558 validator_log(val, ISC_LOG_DEBUG(3), 2559 "too many iterations"); 2560 markanswer(val, "validate_nx (3)", NULL); 2561 return (ISC_R_SUCCESS); 2562 } 2563 } 2564 2565 if (FOUNDNOQNAME(val) && FOUNDCLOSEST(val) && !FOUNDOPTOUT(val)) 2566 { 2567 validator_log(val, ISC_LOG_DEBUG(3), 2568 "marking as secure, noqname proof found"); 2569 marksecure(val->event); 2570 return (ISC_R_SUCCESS); 2571 } else if (FOUNDOPTOUT(val) && 2572 dns_name_countlabels( 2573 dns_fixedname_name(&val->wild)) != 0) 2574 { 2575 validator_log(val, ISC_LOG_DEBUG(3), 2576 "optout proof found"); 2577 val->event->optout = true; 2578 markanswer(val, "validate_nx (1)", NULL); 2579 return (ISC_R_SUCCESS); 2580 } else if ((val->attributes & VALATTR_FOUNDUNKNOWN) != 0) { 2581 validator_log(val, ISC_LOG_DEBUG(3), 2582 "unknown NSEC3 hash algorithm found"); 2583 markanswer(val, "validate_nx (2)", NULL); 2584 return (ISC_R_SUCCESS); 2585 } 2586 2587 validator_log(val, ISC_LOG_DEBUG(3), "noqname proof not found"); 2588 return (DNS_R_NOVALIDNSEC); 2589 } 2590 2591 if (!FOUNDNOQNAME(val) && !FOUNDNODATA(val)) { 2592 result = findnsec3proofs(val); 2593 if (result == DNS_R_NSEC3ITERRANGE) { 2594 validator_log(val, ISC_LOG_DEBUG(3), 2595 "too many iterations"); 2596 markanswer(val, "validate_nx (4)", NULL); 2597 return (ISC_R_SUCCESS); 2598 } 2599 } 2600 2601 /* 2602 * Do we need to check for the wildcard? 2603 */ 2604 if (FOUNDNOQNAME(val) && FOUNDCLOSEST(val) && 2605 ((NEEDNODATA(val) && !FOUNDNODATA(val)) || NEEDNOWILDCARD(val))) 2606 { 2607 result = checkwildcard(val, dns_rdatatype_nsec, NULL); 2608 if (result != ISC_R_SUCCESS) { 2609 return (result); 2610 } 2611 } 2612 2613 if ((NEEDNODATA(val) && (FOUNDNODATA(val) || FOUNDOPTOUT(val))) || 2614 (NEEDNOQNAME(val) && FOUNDNOQNAME(val) && NEEDNOWILDCARD(val) && 2615 FOUNDNOWILDCARD(val) && FOUNDCLOSEST(val))) 2616 { 2617 if ((val->attributes & VALATTR_FOUNDOPTOUT) != 0) { 2618 val->event->optout = true; 2619 } 2620 validator_log(val, ISC_LOG_DEBUG(3), 2621 "nonexistence proof(s) found"); 2622 if (val->event->message == NULL) { 2623 marksecure(val->event); 2624 } else { 2625 val->event->secure = true; 2626 } 2627 return (ISC_R_SUCCESS); 2628 } 2629 2630 if (val->authfail != 0 && val->authcount == val->authfail) { 2631 return (DNS_R_BROKENCHAIN); 2632 } 2633 2634 validator_log(val, ISC_LOG_DEBUG(3), "nonexistence proof(s) not found"); 2635 return (proveunsecure(val, false, false)); 2636} 2637 2638/*% 2639 * Check that DS rdataset has at least one record with 2640 * a supported algorithm and digest. 2641 */ 2642static bool 2643check_ds_algs(dns_validator_t *val, dns_name_t *name, 2644 dns_rdataset_t *rdataset) { 2645 dns_rdata_t dsrdata = DNS_RDATA_INIT; 2646 dns_rdata_ds_t ds; 2647 isc_result_t result; 2648 2649 for (result = dns_rdataset_first(rdataset); result == ISC_R_SUCCESS; 2650 result = dns_rdataset_next(rdataset)) 2651 { 2652 dns_rdataset_current(rdataset, &dsrdata); 2653 result = dns_rdata_tostruct(&dsrdata, &ds, NULL); 2654 RUNTIME_CHECK(result == ISC_R_SUCCESS); 2655 2656 if (dns_resolver_ds_digest_supported(val->view->resolver, name, 2657 ds.digest_type) && 2658 dns_resolver_algorithm_supported(val->view->resolver, name, 2659 ds.algorithm)) 2660 { 2661 dns_rdata_reset(&dsrdata); 2662 return (true); 2663 } 2664 dns_rdata_reset(&dsrdata); 2665 } 2666 return (false); 2667} 2668 2669/*% 2670 * seek_ds is called to look up DS rrsets at the label of val->event->name 2671 * indicated by val->labels. This is done while building an insecurity 2672 * proof, and so it will attempt validation of NXDOMAIN, NXRRSET or CNAME 2673 * responses. 2674 * 2675 * Returns: 2676 * \li ISC_R_COMPLETE a result has been determined and copied 2677 * into `*resp`; ISC_R_SUCCESS indicates that 2678 * the name has been proven insecure and any 2679 * other result indicates failure. 2680 * \li DNS_R_CONTINUE result is indeterminate; caller should 2681 * continue walking down labels. 2682 */ 2683static isc_result_t 2684seek_ds(dns_validator_t *val, isc_result_t *resp) { 2685 isc_result_t result; 2686 char namebuf[DNS_NAME_FORMATSIZE]; 2687 dns_fixedname_t fixedfound; 2688 dns_name_t *found = dns_fixedname_initname(&fixedfound); 2689 dns_name_t *tname = dns_fixedname_initname(&val->fname); 2690 2691 if (val->labels == dns_name_countlabels(val->event->name)) { 2692 dns_name_copynf(val->event->name, tname); 2693 } else { 2694 dns_name_split(val->event->name, val->labels, NULL, tname); 2695 } 2696 2697 dns_name_format(tname, namebuf, sizeof(namebuf)); 2698 validator_log(val, ISC_LOG_DEBUG(3), "checking existence of DS at '%s'", 2699 namebuf); 2700 2701 result = view_find(val, tname, dns_rdatatype_ds); 2702 switch (result) { 2703 case ISC_R_SUCCESS: 2704 /* 2705 * There is a DS here. If it's already been 2706 * validated, continue walking down labels. 2707 */ 2708 if (val->frdataset.trust >= dns_trust_secure) { 2709 if (!check_ds_algs(val, tname, &val->frdataset)) { 2710 validator_log(val, ISC_LOG_DEBUG(3), 2711 "no supported algorithm/" 2712 "digest (%s/DS)", 2713 namebuf); 2714 *resp = markanswer(val, "proveunsecure (5)", 2715 "no supported " 2716 "algorithm/digest (DS)"); 2717 return (ISC_R_COMPLETE); 2718 } 2719 2720 break; 2721 } 2722 2723 /* 2724 * Otherwise, try to validate it now. 2725 */ 2726 if (dns_rdataset_isassociated(&val->fsigrdataset)) { 2727 result = create_validator( 2728 val, tname, dns_rdatatype_ds, &val->frdataset, 2729 &val->fsigrdataset, validator_callback_ds, 2730 "proveunsecure"); 2731 *resp = DNS_R_WAIT; 2732 if (result != ISC_R_SUCCESS) { 2733 *resp = result; 2734 } 2735 } else { 2736 /* 2737 * There should never be an unsigned DS. 2738 */ 2739 validator_log(val, ISC_LOG_DEBUG(3), 2740 "unsigned DS record"); 2741 *resp = DNS_R_NOVALIDSIG; 2742 } 2743 2744 return (ISC_R_COMPLETE); 2745 2746 case ISC_R_NOTFOUND: 2747 /* 2748 * We don't know anything about the DS. Find it. 2749 */ 2750 *resp = DNS_R_WAIT; 2751 result = create_fetch(val, tname, dns_rdatatype_ds, 2752 fetch_callback_ds, "proveunsecure"); 2753 if (result != ISC_R_SUCCESS) { 2754 *resp = result; 2755 } 2756 return (ISC_R_COMPLETE); 2757 2758 case DNS_R_NXRRSET: 2759 case DNS_R_NCACHENXRRSET: 2760 /* 2761 * There is no DS. If this is a delegation, 2762 * we may be done. 2763 * 2764 * If we have "trust == answer" then this namespace 2765 * has switched from insecure to should be secure. 2766 */ 2767 if (DNS_TRUST_PENDING(val->frdataset.trust) || 2768 DNS_TRUST_ANSWER(val->frdataset.trust)) 2769 { 2770 result = create_validator( 2771 val, tname, dns_rdatatype_ds, &val->frdataset, 2772 &val->fsigrdataset, validator_callback_ds, 2773 "proveunsecure"); 2774 *resp = DNS_R_WAIT; 2775 if (result != ISC_R_SUCCESS) { 2776 *resp = result; 2777 } 2778 return (ISC_R_COMPLETE); 2779 } 2780 2781 /* 2782 * Zones using NSEC3 don't return a NSEC RRset so 2783 * we need to use dns_view_findzonecut2 to find 2784 * the zone cut. 2785 */ 2786 if (result == DNS_R_NXRRSET && 2787 !dns_rdataset_isassociated(&val->frdataset) && 2788 dns_view_findzonecut(val->view, tname, found, NULL, 0, 0, 2789 false, false, NULL, 2790 NULL) == ISC_R_SUCCESS && 2791 dns_name_equal(tname, found)) 2792 { 2793 *resp = markanswer(val, "proveunsecure (3)", 2794 "no DS at zone cut"); 2795 return (ISC_R_COMPLETE); 2796 } 2797 2798 if (val->frdataset.trust < dns_trust_secure) { 2799 /* 2800 * This shouldn't happen, since the negative 2801 * response should have been validated. Since 2802 * there's no way of validating existing 2803 * negative response blobs, give up. 2804 */ 2805 validator_log(val, ISC_LOG_WARNING, 2806 "can't validate existing " 2807 "negative responses (no DS)"); 2808 *resp = DNS_R_MUSTBESECURE; 2809 return (ISC_R_COMPLETE); 2810 } 2811 2812 if (isdelegation(tname, &val->frdataset, result)) { 2813 *resp = markanswer(val, "proveunsecure (4)", 2814 "this is a delegation"); 2815 return (ISC_R_COMPLETE); 2816 } 2817 2818 break; 2819 2820 case DNS_R_NXDOMAIN: 2821 case DNS_R_NCACHENXDOMAIN: 2822 /* 2823 * This is not a zone cut. Assuming things are 2824 * as expected, continue. 2825 */ 2826 if (!dns_rdataset_isassociated(&val->frdataset)) { 2827 /* 2828 * There should be an NSEC here, since we 2829 * are still in a secure zone. 2830 */ 2831 *resp = DNS_R_NOVALIDNSEC; 2832 return (ISC_R_COMPLETE); 2833 } else if (DNS_TRUST_PENDING(val->frdataset.trust) || 2834 DNS_TRUST_ANSWER(val->frdataset.trust)) 2835 { 2836 /* 2837 * If we have "trust == answer" then this 2838 * namespace has switched from insecure to 2839 * should be secure. 2840 */ 2841 *resp = DNS_R_WAIT; 2842 result = create_validator( 2843 val, tname, dns_rdatatype_ds, &val->frdataset, 2844 &val->fsigrdataset, validator_callback_ds, 2845 "proveunsecure"); 2846 if (result != ISC_R_SUCCESS) { 2847 *resp = result; 2848 } 2849 return (ISC_R_COMPLETE); 2850 } else if (val->frdataset.trust < dns_trust_secure) { 2851 /* 2852 * This shouldn't happen, since the negative 2853 * response should have been validated. Since 2854 * there's no way of validating existing 2855 * negative response blobs, give up. 2856 */ 2857 validator_log(val, ISC_LOG_WARNING, 2858 "can't validate existing " 2859 "negative responses " 2860 "(not a zone cut)"); 2861 *resp = DNS_R_NOVALIDSIG; 2862 return (ISC_R_COMPLETE); 2863 } 2864 2865 break; 2866 2867 case DNS_R_CNAME: 2868 if (DNS_TRUST_PENDING(val->frdataset.trust) || 2869 DNS_TRUST_ANSWER(val->frdataset.trust)) 2870 { 2871 result = create_validator( 2872 val, tname, dns_rdatatype_cname, 2873 &val->frdataset, &val->fsigrdataset, 2874 validator_callback_cname, 2875 "proveunsecure " 2876 "(cname)"); 2877 *resp = DNS_R_WAIT; 2878 if (result != ISC_R_SUCCESS) { 2879 *resp = result; 2880 } 2881 return (ISC_R_COMPLETE); 2882 } 2883 2884 break; 2885 2886 default: 2887 *resp = result; 2888 return (ISC_R_COMPLETE); 2889 } 2890 2891 /* 2892 * No definite answer yet; continue walking down labels. 2893 */ 2894 return (DNS_R_CONTINUE); 2895} 2896 2897/*% 2898 * proveunsecure walks down, label by label, from the closest enclosing 2899 * trust anchor to the name that is being validated, looking for an 2900 * endpoint in the chain of trust. That occurs when we can prove that 2901 * a DS record does not exist at a delegation point, or that a DS exists 2902 * at a delegation point but we don't support its algorithm/digest. If 2903 * no such endpoint is found, then the response should have been secure. 2904 * 2905 * Returns: 2906 * \li ISC_R_SUCCESS val->event->name is in an unsecure zone 2907 * \li DNS_R_WAIT validation is in progress. 2908 * \li DNS_R_MUSTBESECURE val->event->name is supposed to be secure 2909 * (policy) but we proved that it is unsecure. 2910 * \li DNS_R_NOVALIDSIG 2911 * \li DNS_R_NOVALIDNSEC 2912 * \li DNS_R_NOTINSECURE 2913 * \li DNS_R_BROKENCHAIN 2914 */ 2915static isc_result_t 2916proveunsecure(dns_validator_t *val, bool have_ds, bool resume) { 2917 isc_result_t result; 2918 char namebuf[DNS_NAME_FORMATSIZE]; 2919 dns_fixedname_t fixedsecroot; 2920 dns_name_t *secroot = dns_fixedname_initname(&fixedsecroot); 2921 unsigned int labels; 2922 2923 /* 2924 * We're attempting to prove insecurity. 2925 */ 2926 val->attributes |= VALATTR_INSECURITY; 2927 2928 dns_name_copynf(val->event->name, secroot); 2929 2930 /* 2931 * If this is a response to a DS query, we need to look in 2932 * the parent zone for the trust anchor. 2933 */ 2934 labels = dns_name_countlabels(secroot); 2935 if (val->event->type == dns_rdatatype_ds && labels > 1U) { 2936 dns_name_getlabelsequence(secroot, 1, labels - 1, secroot); 2937 } 2938 2939 result = dns_keytable_finddeepestmatch(val->keytable, secroot, secroot); 2940 if (result == ISC_R_NOTFOUND) { 2941 validator_log(val, ISC_LOG_DEBUG(3), "not beneath secure root"); 2942 return (markanswer(val, "proveunsecure (1)", 2943 "not beneath secure root")); 2944 } else if (result != ISC_R_SUCCESS) { 2945 return (result); 2946 } 2947 2948 if (!resume) { 2949 /* 2950 * We are looking for interruptions in the chain of trust. 2951 * That can only happen *below* the trust anchor, so we 2952 * start looking at the next label down. 2953 */ 2954 val->labels = dns_name_countlabels(secroot) + 1; 2955 } else { 2956 validator_log(val, ISC_LOG_DEBUG(3), "resuming proveunsecure"); 2957 2958 /* 2959 * If we have a DS rdataset and it is secure, check whether 2960 * it has a supported algorithm combination. If not, this is 2961 * an insecure delegation as far as this resolver is concerned. 2962 */ 2963 if (have_ds && val->frdataset.trust >= dns_trust_secure && 2964 !check_ds_algs(val, dns_fixedname_name(&val->fname), 2965 &val->frdataset)) 2966 { 2967 dns_name_format(dns_fixedname_name(&val->fname), 2968 namebuf, sizeof(namebuf)); 2969 validator_log(val, ISC_LOG_DEBUG(3), 2970 "no supported algorithm/digest (%s/DS)", 2971 namebuf); 2972 result = markanswer(val, "proveunsecure (2)", namebuf); 2973 goto out; 2974 } 2975 val->labels++; 2976 } 2977 2978 /* 2979 * Walk down through each of the remaining labels in the name, 2980 * looking for DS records. 2981 */ 2982 while (val->labels <= dns_name_countlabels(val->event->name)) { 2983 isc_result_t tresult; 2984 2985 result = seek_ds(val, &tresult); 2986 if (result == ISC_R_COMPLETE) { 2987 result = tresult; 2988 goto out; 2989 } 2990 2991 INSIST(result == DNS_R_CONTINUE); 2992 val->labels++; 2993 } 2994 2995 /* Couldn't complete insecurity proof. */ 2996 validator_log(val, ISC_LOG_DEBUG(3), "insecurity proof failed: %s", 2997 isc_result_totext(result)); 2998 return (DNS_R_NOTINSECURE); 2999 3000out: 3001 if (result != DNS_R_WAIT) { 3002 disassociate_rdatasets(val); 3003 } 3004 return (result); 3005} 3006 3007/*% 3008 * Start the validation process. 3009 * 3010 * Attempt to validate the answer based on the category it appears to 3011 * fall in. 3012 * \li 1. secure positive answer. 3013 * \li 2. unsecure positive answer. 3014 * \li 3. a negative answer (secure or unsecure). 3015 * 3016 * Note an answer that appears to be a secure positive answer may actually 3017 * be an unsecure positive answer. 3018 */ 3019static void 3020validator_start(isc_task_t *task, isc_event_t *event) { 3021 dns_validator_t *val; 3022 dns_validatorevent_t *vevent; 3023 bool want_destroy = false; 3024 isc_result_t result = ISC_R_FAILURE; 3025 3026 UNUSED(task); 3027 REQUIRE(event->ev_type == DNS_EVENT_VALIDATORSTART); 3028 vevent = (dns_validatorevent_t *)event; 3029 val = vevent->validator; 3030 3031 /* If the validator has been canceled, val->event == NULL */ 3032 if (val->event == NULL) { 3033 return; 3034 } 3035 3036 validator_log(val, ISC_LOG_DEBUG(3), "starting"); 3037 3038 LOCK(&val->lock); 3039 3040 if (val->event->rdataset != NULL && val->event->sigrdataset != NULL) { 3041 isc_result_t saved_result; 3042 3043 /* 3044 * This looks like a simple validation. We say "looks like" 3045 * because it might end up requiring an insecurity proof. 3046 */ 3047 validator_log(val, ISC_LOG_DEBUG(3), 3048 "attempting positive response validation"); 3049 3050 INSIST(dns_rdataset_isassociated(val->event->rdataset)); 3051 INSIST(dns_rdataset_isassociated(val->event->sigrdataset)); 3052 if (selfsigned_dnskey(val)) { 3053 result = validate_dnskey(val); 3054 } else { 3055 result = validate_answer(val, false); 3056 } 3057 if (result == DNS_R_NOVALIDSIG && 3058 (val->attributes & VALATTR_TRIEDVERIFY) == 0) 3059 { 3060 saved_result = result; 3061 validator_log(val, ISC_LOG_DEBUG(3), 3062 "falling back to insecurity proof"); 3063 result = proveunsecure(val, false, false); 3064 if (result == DNS_R_NOTINSECURE) { 3065 result = saved_result; 3066 } 3067 } 3068 } else if (val->event->rdataset != NULL && 3069 val->event->rdataset->type != 0) 3070 { 3071 /* 3072 * This is either an unsecure subdomain or a response 3073 * from a broken server. 3074 */ 3075 INSIST(dns_rdataset_isassociated(val->event->rdataset)); 3076 validator_log(val, ISC_LOG_DEBUG(3), 3077 "attempting insecurity proof"); 3078 3079 result = proveunsecure(val, false, false); 3080 if (result == DNS_R_NOTINSECURE) { 3081 validator_log(val, ISC_LOG_INFO, 3082 "got insecure response; " 3083 "parent indicates it should be secure"); 3084 } 3085 } else if ((val->event->rdataset == NULL && 3086 val->event->sigrdataset == NULL)) 3087 { 3088 /* 3089 * This is a validation of a negative response. 3090 */ 3091 validator_log(val, ISC_LOG_DEBUG(3), 3092 "attempting negative response validation " 3093 "from message"); 3094 3095 if (val->event->message->rcode == dns_rcode_nxdomain) { 3096 val->attributes |= VALATTR_NEEDNOQNAME; 3097 val->attributes |= VALATTR_NEEDNOWILDCARD; 3098 } else { 3099 val->attributes |= VALATTR_NEEDNODATA; 3100 } 3101 3102 result = validate_nx(val, false); 3103 } else if ((val->event->rdataset != NULL && 3104 NEGATIVE(val->event->rdataset))) 3105 { 3106 /* 3107 * This is a delayed validation of a negative cache entry. 3108 */ 3109 validator_log(val, ISC_LOG_DEBUG(3), 3110 "attempting negative response validation " 3111 "from cache"); 3112 3113 if (NXDOMAIN(val->event->rdataset)) { 3114 val->attributes |= VALATTR_NEEDNOQNAME; 3115 val->attributes |= VALATTR_NEEDNOWILDCARD; 3116 } else { 3117 val->attributes |= VALATTR_NEEDNODATA; 3118 } 3119 3120 result = validate_nx(val, false); 3121 } else { 3122 UNREACHABLE(); 3123 } 3124 3125 if (result != DNS_R_WAIT) { 3126 want_destroy = exit_check(val); 3127 validator_done(val, result); 3128 } 3129 3130 UNLOCK(&val->lock); 3131 if (want_destroy) { 3132 destroy(val); 3133 } 3134} 3135 3136isc_result_t 3137dns_validator_create(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type, 3138 dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset, 3139 dns_message_t *message, unsigned int options, 3140 isc_task_t *task, isc_taskaction_t action, void *arg, 3141 dns_validator_t **validatorp) { 3142 isc_result_t result = ISC_R_FAILURE; 3143 dns_validator_t *val; 3144 isc_task_t *tclone = NULL; 3145 dns_validatorevent_t *event; 3146 3147 REQUIRE(name != NULL); 3148 REQUIRE(rdataset != NULL || 3149 (rdataset == NULL && sigrdataset == NULL && message != NULL)); 3150 REQUIRE(validatorp != NULL && *validatorp == NULL); 3151 3152 event = (dns_validatorevent_t *)isc_event_allocate( 3153 view->mctx, task, DNS_EVENT_VALIDATORSTART, validator_start, 3154 NULL, sizeof(dns_validatorevent_t)); 3155 3156 isc_task_attach(task, &tclone); 3157 event->result = ISC_R_FAILURE; 3158 event->name = name; 3159 event->type = type; 3160 event->rdataset = rdataset; 3161 event->sigrdataset = sigrdataset; 3162 event->message = message; 3163 memset(event->proofs, 0, sizeof(event->proofs)); 3164 event->optout = false; 3165 event->secure = false; 3166 3167 val = isc_mem_get(view->mctx, sizeof(*val)); 3168 *val = (dns_validator_t){ .event = event, 3169 .options = options, 3170 .task = task, 3171 .action = action, 3172 .arg = arg }; 3173 3174 dns_view_weakattach(view, &val->view); 3175 isc_mutex_init(&val->lock); 3176 3177 result = dns_view_getsecroots(val->view, &val->keytable); 3178 if (result != ISC_R_SUCCESS) { 3179 goto cleanup; 3180 } 3181 3182 val->mustbesecure = dns_resolver_getmustbesecure(view->resolver, name); 3183 dns_rdataset_init(&val->fdsset); 3184 dns_rdataset_init(&val->frdataset); 3185 dns_rdataset_init(&val->fsigrdataset); 3186 dns_fixedname_init(&val->wild); 3187 dns_fixedname_init(&val->closest); 3188 isc_stdtime_get(&val->start); 3189 ISC_LINK_INIT(val, link); 3190 val->magic = VALIDATOR_MAGIC; 3191 3192 event->validator = val; 3193 3194 if ((options & DNS_VALIDATOR_DEFER) == 0) { 3195 isc_task_send(task, ISC_EVENT_PTR(&event)); 3196 } 3197 3198 *validatorp = val; 3199 3200 return (ISC_R_SUCCESS); 3201 3202cleanup: 3203 isc_mutex_destroy(&val->lock); 3204 3205 isc_task_detach(&tclone); 3206 isc_event_free(ISC_EVENT_PTR(&event)); 3207 3208 dns_view_weakdetach(&val->view); 3209 isc_mem_put(view->mctx, val, sizeof(*val)); 3210 3211 return (result); 3212} 3213 3214void 3215dns_validator_send(dns_validator_t *validator) { 3216 isc_event_t *event; 3217 REQUIRE(VALID_VALIDATOR(validator)); 3218 3219 LOCK(&validator->lock); 3220 3221 INSIST((validator->options & DNS_VALIDATOR_DEFER) != 0); 3222 event = (isc_event_t *)validator->event; 3223 validator->options &= ~DNS_VALIDATOR_DEFER; 3224 UNLOCK(&validator->lock); 3225 3226 isc_task_send(validator->task, ISC_EVENT_PTR(&event)); 3227} 3228 3229void 3230dns_validator_cancel(dns_validator_t *validator) { 3231 dns_fetch_t *fetch = NULL; 3232 3233 REQUIRE(VALID_VALIDATOR(validator)); 3234 3235 LOCK(&validator->lock); 3236 3237 validator_log(validator, ISC_LOG_DEBUG(3), "dns_validator_cancel"); 3238 3239 if ((validator->attributes & VALATTR_CANCELED) == 0) { 3240 validator->attributes |= VALATTR_CANCELED; 3241 if (validator->event != NULL) { 3242 fetch = validator->fetch; 3243 validator->fetch = NULL; 3244 3245 if (validator->subvalidator != NULL) { 3246 dns_validator_cancel(validator->subvalidator); 3247 } 3248 if ((validator->options & DNS_VALIDATOR_DEFER) != 0) { 3249 validator->options &= ~DNS_VALIDATOR_DEFER; 3250 validator_done(validator, ISC_R_CANCELED); 3251 } 3252 } 3253 } 3254 UNLOCK(&validator->lock); 3255 3256 /* Need to cancel and destroy the fetch outside validator lock */ 3257 if (fetch != NULL) { 3258 dns_resolver_cancelfetch(fetch); 3259 dns_resolver_destroyfetch(&fetch); 3260 } 3261} 3262 3263static void 3264destroy(dns_validator_t *val) { 3265 isc_mem_t *mctx; 3266 3267 REQUIRE(SHUTDOWN(val)); 3268 REQUIRE(val->event == NULL); 3269 REQUIRE(val->fetch == NULL); 3270 3271 val->magic = 0; 3272 if (val->key != NULL) { 3273 dst_key_free(&val->key); 3274 } 3275 if (val->keytable != NULL) { 3276 dns_keytable_detach(&val->keytable); 3277 } 3278 if (val->subvalidator != NULL) { 3279 dns_validator_destroy(&val->subvalidator); 3280 } 3281 disassociate_rdatasets(val); 3282 mctx = val->view->mctx; 3283 if (val->siginfo != NULL) { 3284 isc_mem_put(mctx, val->siginfo, sizeof(*val->siginfo)); 3285 } 3286 isc_mutex_destroy(&val->lock); 3287 dns_view_weakdetach(&val->view); 3288 isc_mem_put(mctx, val, sizeof(*val)); 3289} 3290 3291void 3292dns_validator_destroy(dns_validator_t **validatorp) { 3293 dns_validator_t *val; 3294 bool want_destroy = false; 3295 3296 REQUIRE(validatorp != NULL); 3297 val = *validatorp; 3298 *validatorp = NULL; 3299 REQUIRE(VALID_VALIDATOR(val)); 3300 3301 LOCK(&val->lock); 3302 3303 val->attributes |= VALATTR_SHUTDOWN; 3304 validator_log(val, ISC_LOG_DEBUG(4), "dns_validator_destroy"); 3305 3306 want_destroy = exit_check(val); 3307 UNLOCK(&val->lock); 3308 if (want_destroy) { 3309 destroy(val); 3310 } 3311} 3312 3313static void 3314validator_logv(dns_validator_t *val, isc_logcategory_t *category, 3315 isc_logmodule_t *module, int level, const char *fmt, 3316 va_list ap) { 3317 char msgbuf[2048]; 3318 static const char spaces[] = " *"; 3319 int depth = val->depth * 2; 3320 const char *viewname, *sep1, *sep2; 3321 3322 vsnprintf(msgbuf, sizeof(msgbuf), fmt, ap); 3323 3324 if ((unsigned int)depth >= sizeof spaces) { 3325 depth = sizeof spaces - 1; 3326 } 3327 3328 /* 3329 * Log the view name unless it's: 3330 * * "_default/IN" (which means there's only one view 3331 * configured in the server), or 3332 * * "_dnsclient/IN" (which means this is being called 3333 * from an application using dns/client.c). 3334 */ 3335 if (val->view->rdclass == dns_rdataclass_in && 3336 (strcmp(val->view->name, "_default") == 0 || 3337 strcmp(val->view->name, DNS_CLIENTVIEW_NAME) == 0)) 3338 { 3339 sep1 = viewname = sep2 = ""; 3340 } else { 3341 sep1 = "view "; 3342 viewname = val->view->name; 3343 sep2 = ": "; 3344 } 3345 3346 if (val->event != NULL && val->event->name != NULL) { 3347 char namebuf[DNS_NAME_FORMATSIZE]; 3348 char typebuf[DNS_RDATATYPE_FORMATSIZE]; 3349 3350 dns_name_format(val->event->name, namebuf, sizeof(namebuf)); 3351 dns_rdatatype_format(val->event->type, typebuf, 3352 sizeof(typebuf)); 3353 isc_log_write(dns_lctx, category, module, level, 3354 "%s%s%s%.*svalidating %s/%s: %s", sep1, viewname, 3355 sep2, depth, spaces, namebuf, typebuf, msgbuf); 3356 } else { 3357 isc_log_write(dns_lctx, category, module, level, 3358 "%s%s%s%.*svalidator @%p: %s", sep1, viewname, 3359 sep2, depth, spaces, val, msgbuf); 3360 } 3361} 3362 3363static void 3364validator_log(void *val, int level, const char *fmt, ...) { 3365 va_list ap; 3366 3367 if (!isc_log_wouldlog(dns_lctx, level)) { 3368 return; 3369 } 3370 3371 va_start(ap, fmt); 3372 3373 validator_logv(val, DNS_LOGCATEGORY_DNSSEC, DNS_LOGMODULE_VALIDATOR, 3374 level, fmt, ap); 3375 va_end(ap); 3376} 3377 3378static void 3379validator_logcreate(dns_validator_t *val, dns_name_t *name, 3380 dns_rdatatype_t type, const char *caller, 3381 const char *operation) { 3382 char namestr[DNS_NAME_FORMATSIZE]; 3383 char typestr[DNS_RDATATYPE_FORMATSIZE]; 3384 3385 dns_name_format(name, namestr, sizeof(namestr)); 3386 dns_rdatatype_format(type, typestr, sizeof(typestr)); 3387 validator_log(val, ISC_LOG_DEBUG(9), "%s: creating %s for %s %s", 3388 caller, operation, namestr, typestr); 3389} 3390