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