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