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