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