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