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