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