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