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