1 1.18 christos /* $NetBSD: dnssec.c,v 1.19 2026/01/29 18:37:48 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.12 christos * SPDX-License-Identifier: MPL-2.0 7 1.12 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.7 christos * file, you can obtain one at https://mozilla.org/MPL/2.0/. 11 1.1 christos * 12 1.1 christos * See the COPYRIGHT file distributed with this work for additional 13 1.1 christos * information regarding copyright ownership. 14 1.1 christos */ 15 1.1 christos 16 1.1 christos /*! \file */ 17 1.1 christos 18 1.11 christos #include <ctype.h> 19 1.3 christos #include <inttypes.h> 20 1.3 christos #include <stdbool.h> 21 1.1 christos #include <stdlib.h> 22 1.1 christos 23 1.1 christos #include <isc/buffer.h> 24 1.1 christos #include <isc/dir.h> 25 1.1 christos #include <isc/mem.h> 26 1.14 christos #include <isc/result.h> 27 1.1 christos #include <isc/serial.h> 28 1.1 christos #include <isc/string.h> 29 1.1 christos #include <isc/util.h> 30 1.1 christos 31 1.1 christos #include <dns/db.h> 32 1.1 christos #include <dns/diff.h> 33 1.1 christos #include <dns/dnssec.h> 34 1.1 christos #include <dns/fixedname.h> 35 1.6 christos #include <dns/kasp.h> 36 1.1 christos #include <dns/keyvalues.h> 37 1.1 christos #include <dns/log.h> 38 1.1 christos #include <dns/message.h> 39 1.1 christos #include <dns/rdata.h> 40 1.1 christos #include <dns/rdatalist.h> 41 1.1 christos #include <dns/rdataset.h> 42 1.1 christos #include <dns/rdatastruct.h> 43 1.1 christos #include <dns/stats.h> 44 1.6 christos #include <dns/tsig.h> /* for DNS_TSIG_FUDGE */ 45 1.1 christos 46 1.14 christos isc_stats_t *dns_dnssec_stats; 47 1.1 christos 48 1.3 christos #define is_response(msg) ((msg->flags & DNS_MESSAGEFLAG_QR) != 0) 49 1.1 christos 50 1.6 christos #define TYPE_SIGN 0 51 1.1 christos #define TYPE_VERIFY 1 52 1.1 christos 53 1.1 christos static isc_result_t 54 1.1 christos digest_callback(void *arg, isc_region_t *data); 55 1.1 christos 56 1.1 christos static int 57 1.1 christos rdata_compare_wrapper(const void *rdata1, const void *rdata2); 58 1.1 christos 59 1.1 christos static isc_result_t 60 1.1 christos rdataset_to_sortedarray(dns_rdataset_t *set, isc_mem_t *mctx, 61 1.1 christos dns_rdata_t **rdata, int *nrdata); 62 1.1 christos 63 1.1 christos static isc_result_t 64 1.1 christos digest_callback(void *arg, isc_region_t *data) { 65 1.1 christos dst_context_t *ctx = arg; 66 1.1 christos 67 1.16 christos return dst_context_adddata(ctx, data); 68 1.1 christos } 69 1.1 christos 70 1.12 christos static void 71 1.1 christos inc_stat(isc_statscounter_t counter) { 72 1.6 christos if (dns_dnssec_stats != NULL) { 73 1.1 christos isc_stats_increment(dns_dnssec_stats, counter); 74 1.6 christos } 75 1.1 christos } 76 1.1 christos 77 1.1 christos /* 78 1.1 christos * Make qsort happy. 79 1.1 christos */ 80 1.1 christos static int 81 1.1 christos rdata_compare_wrapper(const void *rdata1, const void *rdata2) { 82 1.16 christos return dns_rdata_compare((const dns_rdata_t *)rdata1, 83 1.16 christos (const dns_rdata_t *)rdata2); 84 1.1 christos } 85 1.1 christos 86 1.1 christos /* 87 1.1 christos * Sort the rdataset into an array. 88 1.1 christos */ 89 1.1 christos static isc_result_t 90 1.1 christos rdataset_to_sortedarray(dns_rdataset_t *set, isc_mem_t *mctx, 91 1.6 christos dns_rdata_t **rdata, int *nrdata) { 92 1.1 christos isc_result_t ret; 93 1.1 christos int i = 0, n; 94 1.1 christos dns_rdata_t *data; 95 1.1 christos dns_rdataset_t rdataset; 96 1.1 christos 97 1.1 christos n = dns_rdataset_count(set); 98 1.1 christos 99 1.16 christos data = isc_mem_cget(mctx, n, sizeof(dns_rdata_t)); 100 1.1 christos 101 1.1 christos dns_rdataset_init(&rdataset); 102 1.1 christos dns_rdataset_clone(set, &rdataset); 103 1.1 christos ret = dns_rdataset_first(&rdataset); 104 1.1 christos if (ret != ISC_R_SUCCESS) { 105 1.1 christos dns_rdataset_disassociate(&rdataset); 106 1.16 christos isc_mem_cput(mctx, data, n, sizeof(dns_rdata_t)); 107 1.16 christos return ret; 108 1.1 christos } 109 1.1 christos 110 1.1 christos /* 111 1.1 christos * Put them in the array. 112 1.1 christos */ 113 1.1 christos do { 114 1.1 christos dns_rdata_init(&data[i]); 115 1.1 christos dns_rdataset_current(&rdataset, &data[i++]); 116 1.1 christos } while (dns_rdataset_next(&rdataset) == ISC_R_SUCCESS); 117 1.1 christos 118 1.1 christos /* 119 1.1 christos * Sort the array. 120 1.1 christos */ 121 1.1 christos qsort(data, n, sizeof(dns_rdata_t), rdata_compare_wrapper); 122 1.1 christos *rdata = data; 123 1.1 christos *nrdata = n; 124 1.1 christos dns_rdataset_disassociate(&rdataset); 125 1.16 christos return ISC_R_SUCCESS; 126 1.1 christos } 127 1.1 christos 128 1.1 christos isc_result_t 129 1.1 christos dns_dnssec_keyfromrdata(const dns_name_t *name, const dns_rdata_t *rdata, 130 1.6 christos isc_mem_t *mctx, dst_key_t **key) { 131 1.1 christos isc_buffer_t b; 132 1.1 christos isc_region_t r; 133 1.1 christos 134 1.1 christos INSIST(name != NULL); 135 1.1 christos INSIST(rdata != NULL); 136 1.1 christos INSIST(mctx != NULL); 137 1.1 christos INSIST(key != NULL); 138 1.1 christos INSIST(*key == NULL); 139 1.1 christos REQUIRE(rdata->type == dns_rdatatype_key || 140 1.1 christos rdata->type == dns_rdatatype_dnskey); 141 1.1 christos 142 1.1 christos dns_rdata_toregion(rdata, &r); 143 1.1 christos isc_buffer_init(&b, r.base, r.length); 144 1.1 christos isc_buffer_add(&b, r.length); 145 1.16 christos return dst_key_fromdns(name, rdata->rdclass, &b, mctx, key); 146 1.1 christos } 147 1.1 christos 148 1.1 christos static isc_result_t 149 1.3 christos digest_sig(dst_context_t *ctx, bool downcase, dns_rdata_t *sigrdata, 150 1.6 christos dns_rdata_rrsig_t *rrsig) { 151 1.1 christos isc_region_t r; 152 1.1 christos isc_result_t ret; 153 1.1 christos dns_fixedname_t fname; 154 1.1 christos 155 1.1 christos dns_rdata_toregion(sigrdata, &r); 156 1.1 christos INSIST(r.length >= 19); 157 1.1 christos 158 1.1 christos r.length = 18; 159 1.1 christos ret = dst_context_adddata(ctx, &r); 160 1.6 christos if (ret != ISC_R_SUCCESS) { 161 1.16 christos return ret; 162 1.6 christos } 163 1.1 christos if (downcase) { 164 1.1 christos dns_fixedname_init(&fname); 165 1.1 christos 166 1.1 christos RUNTIME_CHECK(dns_name_downcase(&rrsig->signer, 167 1.1 christos dns_fixedname_name(&fname), 168 1.1 christos NULL) == ISC_R_SUCCESS); 169 1.1 christos dns_name_toregion(dns_fixedname_name(&fname), &r); 170 1.6 christos } else { 171 1.1 christos dns_name_toregion(&rrsig->signer, &r); 172 1.6 christos } 173 1.1 christos 174 1.16 christos return dst_context_adddata(ctx, &r); 175 1.1 christos } 176 1.1 christos 177 1.1 christos isc_result_t 178 1.1 christos dns_dnssec_sign(const dns_name_t *name, dns_rdataset_t *set, dst_key_t *key, 179 1.1 christos isc_stdtime_t *inception, isc_stdtime_t *expire, 180 1.6 christos isc_mem_t *mctx, isc_buffer_t *buffer, dns_rdata_t *sigrdata) { 181 1.1 christos dns_rdata_rrsig_t sig; 182 1.1 christos dns_rdata_t tmpsigrdata; 183 1.1 christos dns_rdata_t *rdatas; 184 1.1 christos int nrdatas, i; 185 1.1 christos isc_buffer_t sigbuf, envbuf; 186 1.1 christos isc_region_t r; 187 1.1 christos dst_context_t *ctx = NULL; 188 1.1 christos isc_result_t ret; 189 1.1 christos isc_buffer_t *databuf = NULL; 190 1.1 christos char data[256 + 8]; 191 1.1 christos unsigned int sigsize; 192 1.1 christos dns_fixedname_t fnewname; 193 1.1 christos dns_fixedname_t fsigner; 194 1.1 christos 195 1.1 christos REQUIRE(name != NULL); 196 1.1 christos REQUIRE(dns_name_countlabels(name) <= 255); 197 1.1 christos REQUIRE(set != NULL); 198 1.1 christos REQUIRE(key != NULL); 199 1.1 christos REQUIRE(inception != NULL); 200 1.1 christos REQUIRE(expire != NULL); 201 1.1 christos REQUIRE(mctx != NULL); 202 1.1 christos REQUIRE(sigrdata != NULL); 203 1.1 christos 204 1.6 christos if (*inception >= *expire) { 205 1.16 christos return DNS_R_INVALIDTIME; 206 1.6 christos } 207 1.1 christos 208 1.1 christos sig.mctx = mctx; 209 1.1 christos sig.common.rdclass = set->rdclass; 210 1.1 christos sig.common.rdtype = dns_rdatatype_rrsig; 211 1.1 christos ISC_LINK_INIT(&sig.common, link); 212 1.1 christos 213 1.1 christos /* 214 1.1 christos * Downcase signer. 215 1.1 christos */ 216 1.1 christos dns_name_init(&sig.signer, NULL); 217 1.1 christos dns_fixedname_init(&fsigner); 218 1.1 christos RUNTIME_CHECK(dns_name_downcase(dst_key_name(key), 219 1.6 christos dns_fixedname_name(&fsigner), 220 1.6 christos NULL) == ISC_R_SUCCESS); 221 1.1 christos dns_name_clone(dns_fixedname_name(&fsigner), &sig.signer); 222 1.1 christos 223 1.1 christos sig.covered = set->type; 224 1.1 christos sig.algorithm = dst_key_alg(key); 225 1.1 christos sig.labels = dns_name_countlabels(name) - 1; 226 1.6 christos if (dns_name_iswildcard(name)) { 227 1.1 christos sig.labels--; 228 1.6 christos } 229 1.1 christos sig.originalttl = set->ttl; 230 1.1 christos sig.timesigned = *inception; 231 1.1 christos sig.timeexpire = *expire; 232 1.1 christos sig.keyid = dst_key_id(key); 233 1.1 christos ret = dst_key_sigsize(key, &sigsize); 234 1.6 christos if (ret != ISC_R_SUCCESS) { 235 1.16 christos return ret; 236 1.6 christos } 237 1.1 christos sig.siglen = sigsize; 238 1.1 christos /* 239 1.1 christos * The actual contents of sig.signature are not important yet, since 240 1.1 christos * they're not used in digest_sig(). 241 1.1 christos */ 242 1.1 christos sig.signature = isc_mem_get(mctx, sig.siglen); 243 1.1 christos 244 1.6 christos isc_buffer_allocate(mctx, &databuf, sigsize + 256 + 18); 245 1.1 christos 246 1.1 christos dns_rdata_init(&tmpsigrdata); 247 1.1 christos ret = dns_rdata_fromstruct(&tmpsigrdata, sig.common.rdclass, 248 1.1 christos sig.common.rdtype, &sig, databuf); 249 1.6 christos if (ret != ISC_R_SUCCESS) { 250 1.1 christos goto cleanup_databuf; 251 1.6 christos } 252 1.1 christos 253 1.6 christos ret = dst_context_create(key, mctx, DNS_LOGCATEGORY_DNSSEC, true, 0, 254 1.6 christos &ctx); 255 1.6 christos if (ret != ISC_R_SUCCESS) { 256 1.1 christos goto cleanup_databuf; 257 1.6 christos } 258 1.1 christos 259 1.1 christos /* 260 1.1 christos * Digest the SIG rdata. 261 1.1 christos */ 262 1.3 christos ret = digest_sig(ctx, false, &tmpsigrdata, &sig); 263 1.6 christos if (ret != ISC_R_SUCCESS) { 264 1.1 christos goto cleanup_context; 265 1.6 christos } 266 1.1 christos 267 1.1 christos dns_fixedname_init(&fnewname); 268 1.1 christos RUNTIME_CHECK(dns_name_downcase(name, dns_fixedname_name(&fnewname), 269 1.1 christos NULL) == ISC_R_SUCCESS); 270 1.1 christos dns_name_toregion(dns_fixedname_name(&fnewname), &r); 271 1.1 christos 272 1.1 christos /* 273 1.1 christos * Create an envelope for each rdata: <name|type|class|ttl>. 274 1.1 christos */ 275 1.1 christos isc_buffer_init(&envbuf, data, sizeof(data)); 276 1.1 christos memmove(data, r.base, r.length); 277 1.1 christos isc_buffer_add(&envbuf, r.length); 278 1.1 christos isc_buffer_putuint16(&envbuf, set->type); 279 1.1 christos isc_buffer_putuint16(&envbuf, set->rdclass); 280 1.1 christos isc_buffer_putuint32(&envbuf, set->ttl); 281 1.1 christos 282 1.1 christos ret = rdataset_to_sortedarray(set, mctx, &rdatas, &nrdatas); 283 1.6 christos if (ret != ISC_R_SUCCESS) { 284 1.1 christos goto cleanup_context; 285 1.6 christos } 286 1.1 christos isc_buffer_usedregion(&envbuf, &r); 287 1.1 christos 288 1.1 christos for (i = 0; i < nrdatas; i++) { 289 1.3 christos uint16_t len; 290 1.1 christos isc_buffer_t lenbuf; 291 1.1 christos isc_region_t lenr; 292 1.1 christos 293 1.1 christos /* 294 1.1 christos * Skip duplicates. 295 1.1 christos */ 296 1.6 christos if (i > 0 && dns_rdata_compare(&rdatas[i], &rdatas[i - 1]) == 0) 297 1.6 christos { 298 1.6 christos continue; 299 1.6 christos } 300 1.1 christos 301 1.1 christos /* 302 1.1 christos * Digest the envelope. 303 1.1 christos */ 304 1.1 christos ret = dst_context_adddata(ctx, &r); 305 1.6 christos if (ret != ISC_R_SUCCESS) { 306 1.1 christos goto cleanup_array; 307 1.6 christos } 308 1.1 christos 309 1.1 christos /* 310 1.1 christos * Digest the length of the rdata. 311 1.1 christos */ 312 1.1 christos isc_buffer_init(&lenbuf, &len, sizeof(len)); 313 1.3 christos isc_buffer_putuint16(&lenbuf, (uint16_t)rdatas[i].length); 314 1.1 christos isc_buffer_usedregion(&lenbuf, &lenr); 315 1.1 christos ret = dst_context_adddata(ctx, &lenr); 316 1.6 christos if (ret != ISC_R_SUCCESS) { 317 1.1 christos goto cleanup_array; 318 1.6 christos } 319 1.1 christos 320 1.1 christos /* 321 1.1 christos * Digest the rdata. 322 1.1 christos */ 323 1.1 christos ret = dns_rdata_digest(&rdatas[i], digest_callback, ctx); 324 1.6 christos if (ret != ISC_R_SUCCESS) { 325 1.1 christos goto cleanup_array; 326 1.6 christos } 327 1.1 christos } 328 1.1 christos 329 1.1 christos isc_buffer_init(&sigbuf, sig.signature, sig.siglen); 330 1.1 christos ret = dst_context_sign(ctx, &sigbuf); 331 1.6 christos if (ret != ISC_R_SUCCESS) { 332 1.1 christos goto cleanup_array; 333 1.6 christos } 334 1.1 christos isc_buffer_usedregion(&sigbuf, &r); 335 1.1 christos if (r.length != sig.siglen) { 336 1.1 christos ret = ISC_R_NOSPACE; 337 1.1 christos goto cleanup_array; 338 1.1 christos } 339 1.1 christos 340 1.1 christos ret = dns_rdata_fromstruct(sigrdata, sig.common.rdclass, 341 1.9 rillig sig.common.rdtype, &sig, buffer); 342 1.1 christos 343 1.1 christos cleanup_array: 344 1.16 christos isc_mem_cput(mctx, rdatas, nrdatas, sizeof(dns_rdata_t)); 345 1.1 christos cleanup_context: 346 1.1 christos dst_context_destroy(&ctx); 347 1.1 christos cleanup_databuf: 348 1.1 christos isc_buffer_free(&databuf); 349 1.1 christos isc_mem_put(mctx, sig.signature, sig.siglen); 350 1.1 christos 351 1.16 christos return ret; 352 1.1 christos } 353 1.1 christos 354 1.1 christos isc_result_t 355 1.3 christos dns_dnssec_verify(const dns_name_t *name, dns_rdataset_t *set, dst_key_t *key, 356 1.6 christos bool ignoretime, unsigned int maxbits, isc_mem_t *mctx, 357 1.6 christos dns_rdata_t *sigrdata, dns_name_t *wild) { 358 1.1 christos dns_rdata_rrsig_t sig; 359 1.1 christos dns_fixedname_t fnewname; 360 1.1 christos isc_region_t r; 361 1.1 christos isc_buffer_t envbuf; 362 1.1 christos dns_rdata_t *rdatas; 363 1.1 christos int nrdatas, i; 364 1.1 christos isc_stdtime_t now; 365 1.1 christos isc_result_t ret; 366 1.1 christos unsigned char data[300]; 367 1.1 christos dst_context_t *ctx = NULL; 368 1.1 christos int labels = 0; 369 1.3 christos bool downcase = false; 370 1.1 christos 371 1.1 christos REQUIRE(name != NULL); 372 1.1 christos REQUIRE(set != NULL); 373 1.1 christos REQUIRE(key != NULL); 374 1.1 christos REQUIRE(mctx != NULL); 375 1.1 christos REQUIRE(sigrdata != NULL && sigrdata->type == dns_rdatatype_rrsig); 376 1.1 christos 377 1.1 christos ret = dns_rdata_tostruct(sigrdata, &sig, NULL); 378 1.6 christos if (ret != ISC_R_SUCCESS) { 379 1.16 christos return ret; 380 1.6 christos } 381 1.1 christos 382 1.6 christos if (set->type != sig.covered) { 383 1.16 christos return DNS_R_SIGINVALID; 384 1.6 christos } 385 1.1 christos 386 1.1 christos if (isc_serial_lt(sig.timeexpire, sig.timesigned)) { 387 1.1 christos inc_stat(dns_dnssecstats_fail); 388 1.16 christos return DNS_R_SIGINVALID; 389 1.1 christos } 390 1.1 christos 391 1.1 christos if (!ignoretime) { 392 1.16 christos now = isc_stdtime_now(); 393 1.1 christos 394 1.1 christos /* 395 1.1 christos * Is SIG temporally valid? 396 1.1 christos */ 397 1.3 christos if (isc_serial_lt((uint32_t)now, sig.timesigned)) { 398 1.1 christos inc_stat(dns_dnssecstats_fail); 399 1.16 christos return DNS_R_SIGFUTURE; 400 1.3 christos } else if (isc_serial_lt(sig.timeexpire, (uint32_t)now)) { 401 1.1 christos inc_stat(dns_dnssecstats_fail); 402 1.16 christos return DNS_R_SIGEXPIRED; 403 1.1 christos } 404 1.1 christos } 405 1.1 christos 406 1.1 christos /* 407 1.19 christos * NS, SOA and DNSKEY records are signed by their owner. 408 1.1 christos * DS records are signed by the parent. 409 1.1 christos */ 410 1.1 christos switch (set->type) { 411 1.1 christos case dns_rdatatype_ns: 412 1.1 christos case dns_rdatatype_soa: 413 1.1 christos case dns_rdatatype_dnskey: 414 1.1 christos if (!dns_name_equal(name, &sig.signer)) { 415 1.1 christos inc_stat(dns_dnssecstats_fail); 416 1.16 christos return DNS_R_SIGINVALID; 417 1.1 christos } 418 1.1 christos break; 419 1.1 christos case dns_rdatatype_ds: 420 1.1 christos if (dns_name_equal(name, &sig.signer)) { 421 1.1 christos inc_stat(dns_dnssecstats_fail); 422 1.16 christos return DNS_R_SIGINVALID; 423 1.1 christos } 424 1.12 christos FALLTHROUGH; 425 1.1 christos default: 426 1.1 christos if (!dns_name_issubdomain(name, &sig.signer)) { 427 1.1 christos inc_stat(dns_dnssecstats_fail); 428 1.16 christos return DNS_R_SIGINVALID; 429 1.1 christos } 430 1.1 christos break; 431 1.1 christos } 432 1.1 christos 433 1.6 christos again: 434 1.6 christos ret = dst_context_create(key, mctx, DNS_LOGCATEGORY_DNSSEC, false, 435 1.6 christos maxbits, &ctx); 436 1.6 christos if (ret != ISC_R_SUCCESS) { 437 1.1 christos goto cleanup_struct; 438 1.6 christos } 439 1.1 christos 440 1.1 christos /* 441 1.1 christos * Digest the SIG rdata (not including the signature). 442 1.1 christos */ 443 1.1 christos ret = digest_sig(ctx, downcase, sigrdata, &sig); 444 1.6 christos if (ret != ISC_R_SUCCESS) { 445 1.1 christos goto cleanup_context; 446 1.6 christos } 447 1.1 christos 448 1.1 christos /* 449 1.1 christos * If the name is an expanded wildcard, use the wildcard name. 450 1.1 christos */ 451 1.1 christos dns_fixedname_init(&fnewname); 452 1.1 christos labels = dns_name_countlabels(name) - 1; 453 1.1 christos RUNTIME_CHECK(dns_name_downcase(name, dns_fixedname_name(&fnewname), 454 1.1 christos NULL) == ISC_R_SUCCESS); 455 1.6 christos if (labels - sig.labels > 0) { 456 1.1 christos dns_name_split(dns_fixedname_name(&fnewname), sig.labels + 1, 457 1.1 christos NULL, dns_fixedname_name(&fnewname)); 458 1.6 christos } 459 1.1 christos 460 1.1 christos dns_name_toregion(dns_fixedname_name(&fnewname), &r); 461 1.1 christos 462 1.1 christos /* 463 1.1 christos * Create an envelope for each rdata: <name|type|class|ttl>. 464 1.1 christos */ 465 1.1 christos isc_buffer_init(&envbuf, data, sizeof(data)); 466 1.1 christos if (labels - sig.labels > 0) { 467 1.1 christos isc_buffer_putuint8(&envbuf, 1); 468 1.1 christos isc_buffer_putuint8(&envbuf, '*'); 469 1.1 christos memmove(data + 2, r.base, r.length); 470 1.6 christos } else { 471 1.6 christos memmove(data, r.base, r.length); 472 1.1 christos } 473 1.1 christos isc_buffer_add(&envbuf, r.length); 474 1.1 christos isc_buffer_putuint16(&envbuf, set->type); 475 1.1 christos isc_buffer_putuint16(&envbuf, set->rdclass); 476 1.1 christos isc_buffer_putuint32(&envbuf, sig.originalttl); 477 1.1 christos 478 1.1 christos ret = rdataset_to_sortedarray(set, mctx, &rdatas, &nrdatas); 479 1.6 christos if (ret != ISC_R_SUCCESS) { 480 1.1 christos goto cleanup_context; 481 1.6 christos } 482 1.1 christos 483 1.1 christos isc_buffer_usedregion(&envbuf, &r); 484 1.1 christos 485 1.1 christos for (i = 0; i < nrdatas; i++) { 486 1.3 christos uint16_t len; 487 1.1 christos isc_buffer_t lenbuf; 488 1.1 christos isc_region_t lenr; 489 1.1 christos 490 1.1 christos /* 491 1.1 christos * Skip duplicates. 492 1.1 christos */ 493 1.6 christos if (i > 0 && dns_rdata_compare(&rdatas[i], &rdatas[i - 1]) == 0) 494 1.6 christos { 495 1.6 christos continue; 496 1.6 christos } 497 1.1 christos 498 1.1 christos /* 499 1.1 christos * Digest the envelope. 500 1.1 christos */ 501 1.1 christos ret = dst_context_adddata(ctx, &r); 502 1.6 christos if (ret != ISC_R_SUCCESS) { 503 1.1 christos goto cleanup_array; 504 1.6 christos } 505 1.1 christos 506 1.1 christos /* 507 1.1 christos * Digest the rdata length. 508 1.1 christos */ 509 1.1 christos isc_buffer_init(&lenbuf, &len, sizeof(len)); 510 1.3 christos isc_buffer_putuint16(&lenbuf, (uint16_t)rdatas[i].length); 511 1.1 christos isc_buffer_usedregion(&lenbuf, &lenr); 512 1.1 christos 513 1.1 christos /* 514 1.1 christos * Digest the rdata. 515 1.1 christos */ 516 1.1 christos ret = dst_context_adddata(ctx, &lenr); 517 1.6 christos if (ret != ISC_R_SUCCESS) { 518 1.1 christos goto cleanup_array; 519 1.6 christos } 520 1.1 christos ret = dns_rdata_digest(&rdatas[i], digest_callback, ctx); 521 1.6 christos if (ret != ISC_R_SUCCESS) { 522 1.1 christos goto cleanup_array; 523 1.6 christos } 524 1.1 christos } 525 1.1 christos 526 1.1 christos r.base = sig.signature; 527 1.1 christos r.length = sig.siglen; 528 1.1 christos ret = dst_context_verify2(ctx, maxbits, &r); 529 1.1 christos if (ret == ISC_R_SUCCESS && downcase) { 530 1.1 christos char namebuf[DNS_NAME_FORMATSIZE]; 531 1.1 christos dns_name_format(&sig.signer, namebuf, sizeof(namebuf)); 532 1.1 christos isc_log_write(dns_lctx, DNS_LOGCATEGORY_DNSSEC, 533 1.1 christos DNS_LOGMODULE_DNSSEC, ISC_LOG_DEBUG(1), 534 1.1 christos "successfully validated after lower casing " 535 1.6 christos "signer '%s'", 536 1.6 christos namebuf); 537 1.1 christos inc_stat(dns_dnssecstats_downcase); 538 1.6 christos } else if (ret == ISC_R_SUCCESS) { 539 1.1 christos inc_stat(dns_dnssecstats_asis); 540 1.6 christos } 541 1.1 christos 542 1.1 christos cleanup_array: 543 1.16 christos isc_mem_cput(mctx, rdatas, nrdatas, sizeof(dns_rdata_t)); 544 1.1 christos cleanup_context: 545 1.1 christos dst_context_destroy(&ctx); 546 1.1 christos if (ret == DST_R_VERIFYFAILURE && !downcase) { 547 1.3 christos downcase = true; 548 1.1 christos goto again; 549 1.1 christos } 550 1.1 christos cleanup_struct: 551 1.1 christos dns_rdata_freestruct(&sig); 552 1.1 christos 553 1.6 christos if (ret == DST_R_VERIFYFAILURE) { 554 1.1 christos ret = DNS_R_SIGINVALID; 555 1.6 christos } 556 1.1 christos 557 1.6 christos if (ret != ISC_R_SUCCESS) { 558 1.1 christos inc_stat(dns_dnssecstats_fail); 559 1.6 christos } 560 1.1 christos 561 1.1 christos if (ret == ISC_R_SUCCESS && labels - sig.labels > 0) { 562 1.6 christos if (wild != NULL) { 563 1.6 christos RUNTIME_CHECK(dns_name_concatenate( 564 1.6 christos dns_wildcardname, 565 1.6 christos dns_fixedname_name(&fnewname), 566 1.6 christos wild, NULL) == ISC_R_SUCCESS); 567 1.6 christos } 568 1.1 christos inc_stat(dns_dnssecstats_wildcard); 569 1.1 christos ret = DNS_R_FROMWILDCARD; 570 1.1 christos } 571 1.16 christos return ret; 572 1.1 christos } 573 1.1 christos 574 1.3 christos bool 575 1.1 christos dns_dnssec_keyactive(dst_key_t *key, isc_stdtime_t now) { 576 1.1 christos isc_result_t result; 577 1.6 christos isc_stdtime_t publish, active, revoke, remove; 578 1.6 christos bool hint_publish, hint_zsign, hint_ksign, hint_revoke, hint_remove; 579 1.1 christos int major, minor; 580 1.6 christos bool ksk = false, zsk = false; 581 1.6 christos isc_result_t ret; 582 1.1 christos 583 1.1 christos /* Is this an old-style key? */ 584 1.1 christos result = dst_key_getprivateformat(key, &major, &minor); 585 1.1 christos RUNTIME_CHECK(result == ISC_R_SUCCESS); 586 1.1 christos 587 1.6 christos /* Is this a KSK? */ 588 1.6 christos ret = dst_key_getbool(key, DST_BOOL_KSK, &ksk); 589 1.6 christos if (ret != ISC_R_SUCCESS) { 590 1.6 christos ksk = ((dst_key_flags(key) & DNS_KEYFLAG_KSK) != 0); 591 1.6 christos } 592 1.6 christos ret = dst_key_getbool(key, DST_BOOL_ZSK, &zsk); 593 1.6 christos if (ret != ISC_R_SUCCESS) { 594 1.6 christos zsk = ((dst_key_flags(key) & DNS_KEYFLAG_KSK) == 0); 595 1.6 christos } 596 1.6 christos 597 1.1 christos /* 598 1.1 christos * Smart signing started with key format 1.3; prior to that, all 599 1.6 christos * keys are assumed active. 600 1.1 christos */ 601 1.6 christos if (major == 1 && minor <= 2) { 602 1.16 christos return true; 603 1.6 christos } 604 1.1 christos 605 1.6 christos hint_publish = dst_key_is_published(key, now, &publish); 606 1.6 christos hint_zsign = dst_key_is_signing(key, DST_BOOL_ZSK, now, &active); 607 1.6 christos hint_ksign = dst_key_is_signing(key, DST_BOOL_KSK, now, &active); 608 1.6 christos hint_revoke = dst_key_is_revoked(key, now, &revoke); 609 1.6 christos hint_remove = dst_key_is_removed(key, now, &remove); 610 1.1 christos 611 1.6 christos if (hint_remove) { 612 1.16 christos return false; 613 1.6 christos } 614 1.6 christos if (hint_publish && hint_revoke) { 615 1.16 christos return true; 616 1.6 christos } 617 1.6 christos if (hint_zsign && zsk) { 618 1.16 christos return true; 619 1.6 christos } 620 1.6 christos if (hint_ksign && ksk) { 621 1.16 christos return true; 622 1.6 christos } 623 1.16 christos return false; 624 1.1 christos } 625 1.1 christos 626 1.1 christos /*%< 627 1.1 christos * Indicate whether a key is scheduled to to have CDS/CDNSKEY records 628 1.1 christos * published now. 629 1.1 christos * 630 1.6 christos * Returns true if. 631 1.6 christos * - kasp says the DS record should be published (e.g. the DS state is in 632 1.6 christos * RUMOURED or OMNIPRESENT state). 633 1.6 christos * Or: 634 1.1 christos * - SyncPublish is set and in the past, AND 635 1.1 christos * - SyncDelete is unset or in the future 636 1.1 christos */ 637 1.3 christos static bool 638 1.1 christos syncpublish(dst_key_t *key, isc_stdtime_t now) { 639 1.1 christos isc_result_t result; 640 1.1 christos isc_stdtime_t when; 641 1.6 christos dst_key_state_t state; 642 1.1 christos int major, minor; 643 1.6 christos bool publish; 644 1.1 christos 645 1.1 christos /* 646 1.1 christos * Is this an old-style key? 647 1.1 christos */ 648 1.1 christos result = dst_key_getprivateformat(key, &major, &minor); 649 1.1 christos RUNTIME_CHECK(result == ISC_R_SUCCESS); 650 1.1 christos 651 1.1 christos /* 652 1.1 christos * Smart signing started with key format 1.3 653 1.1 christos */ 654 1.6 christos if (major == 1 && minor <= 2) { 655 1.16 christos return false; 656 1.6 christos } 657 1.6 christos 658 1.6 christos /* Check kasp state first. */ 659 1.6 christos result = dst_key_getstate(key, DST_KEY_DS, &state); 660 1.6 christos if (result == ISC_R_SUCCESS) { 661 1.16 christos return state == DST_KEY_STATE_RUMOURED || 662 1.16 christos state == DST_KEY_STATE_OMNIPRESENT; 663 1.6 christos } 664 1.1 christos 665 1.6 christos /* If no kasp state, check timings. */ 666 1.6 christos publish = false; 667 1.1 christos result = dst_key_gettime(key, DST_TIME_SYNCPUBLISH, &when); 668 1.6 christos if (result == ISC_R_SUCCESS && when <= now) { 669 1.6 christos publish = true; 670 1.6 christos } 671 1.1 christos result = dst_key_gettime(key, DST_TIME_SYNCDELETE, &when); 672 1.6 christos if (result == ISC_R_SUCCESS && when < now) { 673 1.6 christos publish = false; 674 1.6 christos } 675 1.16 christos return publish; 676 1.1 christos } 677 1.1 christos 678 1.1 christos /*%< 679 1.1 christos * Indicate whether a key is scheduled to to have CDS/CDNSKEY records 680 1.1 christos * deleted now. 681 1.1 christos * 682 1.6 christos * Returns true if: 683 1.6 christos * - kasp says the DS record should be unpublished (e.g. the DS state is in 684 1.6 christos * UNRETENTIVE or HIDDEN state). 685 1.6 christos * Or: 686 1.6 christos * - SyncDelete is set and in the past. 687 1.1 christos */ 688 1.3 christos static bool 689 1.1 christos syncdelete(dst_key_t *key, isc_stdtime_t now) { 690 1.1 christos isc_result_t result; 691 1.1 christos isc_stdtime_t when; 692 1.6 christos dst_key_state_t state; 693 1.1 christos int major, minor; 694 1.1 christos 695 1.1 christos /* 696 1.1 christos * Is this an old-style key? 697 1.1 christos */ 698 1.1 christos result = dst_key_getprivateformat(key, &major, &minor); 699 1.1 christos RUNTIME_CHECK(result == ISC_R_SUCCESS); 700 1.1 christos 701 1.1 christos /* 702 1.1 christos * Smart signing started with key format 1.3. 703 1.1 christos */ 704 1.6 christos if (major == 1 && minor <= 2) { 705 1.16 christos return false; 706 1.6 christos } 707 1.1 christos 708 1.6 christos /* Check kasp state first. */ 709 1.6 christos result = dst_key_getstate(key, DST_KEY_DS, &state); 710 1.6 christos if (result == ISC_R_SUCCESS) { 711 1.16 christos return state == DST_KEY_STATE_UNRETENTIVE || 712 1.16 christos state == DST_KEY_STATE_HIDDEN; 713 1.6 christos } 714 1.6 christos 715 1.6 christos /* If no kasp state, check timings. */ 716 1.1 christos result = dst_key_gettime(key, DST_TIME_SYNCDELETE, &when); 717 1.6 christos if (result != ISC_R_SUCCESS) { 718 1.16 christos return false; 719 1.6 christos } 720 1.6 christos if (when <= now) { 721 1.16 christos return true; 722 1.6 christos } 723 1.16 christos return false; 724 1.1 christos } 725 1.1 christos 726 1.6 christos #define is_zone_key(key) \ 727 1.6 christos ((dst_key_flags(key) & DNS_KEYFLAG_OWNERMASK) == DNS_KEYOWNER_ZONE) 728 1.1 christos 729 1.1 christos isc_result_t 730 1.1 christos dns_dnssec_signmessage(dns_message_t *msg, dst_key_t *key) { 731 1.6 christos dns_rdata_sig_t sig; /* SIG(0) */ 732 1.1 christos unsigned char data[512]; 733 1.1 christos unsigned char header[DNS_MESSAGE_HEADERLEN]; 734 1.1 christos isc_buffer_t headerbuf, databuf, sigbuf; 735 1.1 christos unsigned int sigsize; 736 1.1 christos isc_buffer_t *dynbuf = NULL; 737 1.1 christos dns_rdata_t *rdata; 738 1.1 christos dns_rdatalist_t *datalist; 739 1.1 christos dns_rdataset_t *dataset; 740 1.1 christos isc_region_t r; 741 1.1 christos isc_stdtime_t now; 742 1.1 christos dst_context_t *ctx = NULL; 743 1.1 christos isc_mem_t *mctx; 744 1.1 christos isc_result_t result; 745 1.1 christos 746 1.1 christos REQUIRE(msg != NULL); 747 1.1 christos REQUIRE(key != NULL); 748 1.1 christos 749 1.6 christos if (is_response(msg)) { 750 1.1 christos REQUIRE(msg->query.base != NULL); 751 1.6 christos } 752 1.1 christos 753 1.1 christos mctx = msg->mctx; 754 1.1 christos 755 1.1 christos memset(&sig, 0, sizeof(sig)); 756 1.1 christos 757 1.1 christos sig.mctx = mctx; 758 1.1 christos sig.common.rdclass = dns_rdataclass_any; 759 1.6 christos sig.common.rdtype = dns_rdatatype_sig; /* SIG(0) */ 760 1.1 christos ISC_LINK_INIT(&sig.common, link); 761 1.1 christos 762 1.1 christos sig.covered = 0; 763 1.1 christos sig.algorithm = dst_key_alg(key); 764 1.1 christos sig.labels = 0; /* the root name */ 765 1.1 christos sig.originalttl = 0; 766 1.1 christos 767 1.14 christos if (msg->fuzzing) { 768 1.14 christos now = msg->fuzztime; 769 1.14 christos } else { 770 1.16 christos now = isc_stdtime_now(); 771 1.14 christos } 772 1.1 christos sig.timesigned = now - DNS_TSIG_FUDGE; 773 1.1 christos sig.timeexpire = now + DNS_TSIG_FUDGE; 774 1.1 christos 775 1.1 christos sig.keyid = dst_key_id(key); 776 1.1 christos 777 1.1 christos dns_name_init(&sig.signer, NULL); 778 1.1 christos dns_name_clone(dst_key_name(key), &sig.signer); 779 1.1 christos 780 1.1 christos sig.siglen = 0; 781 1.1 christos sig.signature = NULL; 782 1.1 christos 783 1.1 christos isc_buffer_init(&databuf, data, sizeof(data)); 784 1.1 christos 785 1.19 christos CHECK(dst_context_create(key, mctx, DNS_LOGCATEGORY_DNSSEC, true, 0, 786 1.19 christos &ctx)); 787 1.1 christos 788 1.1 christos /* 789 1.1 christos * Digest the fields of the SIG - we can cheat and use 790 1.1 christos * dns_rdata_fromstruct. Since siglen is 0, the digested data 791 1.1 christos * is identical to dns format. 792 1.1 christos */ 793 1.19 christos CHECK(dns_rdata_fromstruct(NULL, dns_rdataclass_any, 794 1.19 christos dns_rdatatype_sig /* SIG(0) */, &sig, 795 1.19 christos &databuf)); 796 1.1 christos isc_buffer_usedregion(&databuf, &r); 797 1.19 christos CHECK(dst_context_adddata(ctx, &r)); 798 1.1 christos 799 1.1 christos /* 800 1.1 christos * If this is a response, digest the query. 801 1.1 christos */ 802 1.6 christos if (is_response(msg)) { 803 1.19 christos CHECK(dst_context_adddata(ctx, &msg->query)); 804 1.6 christos } 805 1.1 christos 806 1.1 christos /* 807 1.1 christos * Digest the header. 808 1.1 christos */ 809 1.1 christos isc_buffer_init(&headerbuf, header, sizeof(header)); 810 1.1 christos dns_message_renderheader(msg, &headerbuf); 811 1.1 christos isc_buffer_usedregion(&headerbuf, &r); 812 1.19 christos CHECK(dst_context_adddata(ctx, &r)); 813 1.1 christos 814 1.1 christos /* 815 1.1 christos * Digest the remainder of the message. 816 1.1 christos */ 817 1.1 christos isc_buffer_usedregion(msg->buffer, &r); 818 1.1 christos isc_region_consume(&r, DNS_MESSAGE_HEADERLEN); 819 1.19 christos CHECK(dst_context_adddata(ctx, &r)); 820 1.1 christos 821 1.19 christos CHECK(dst_key_sigsize(key, &sigsize)); 822 1.1 christos sig.siglen = sigsize; 823 1.6 christos sig.signature = isc_mem_get(mctx, sig.siglen); 824 1.1 christos 825 1.1 christos isc_buffer_init(&sigbuf, sig.signature, sig.siglen); 826 1.19 christos CHECK(dst_context_sign(ctx, &sigbuf)); 827 1.1 christos dst_context_destroy(&ctx); 828 1.1 christos 829 1.1 christos rdata = NULL; 830 1.16 christos dns_message_gettemprdata(msg, &rdata); 831 1.6 christos isc_buffer_allocate(msg->mctx, &dynbuf, 1024); 832 1.19 christos CHECK(dns_rdata_fromstruct(rdata, dns_rdataclass_any, 833 1.19 christos dns_rdatatype_sig /* SIG(0) */, &sig, 834 1.19 christos dynbuf)); 835 1.1 christos 836 1.1 christos isc_mem_put(mctx, sig.signature, sig.siglen); 837 1.1 christos 838 1.1 christos dns_message_takebuffer(msg, &dynbuf); 839 1.1 christos 840 1.1 christos datalist = NULL; 841 1.16 christos dns_message_gettemprdatalist(msg, &datalist); 842 1.1 christos datalist->rdclass = dns_rdataclass_any; 843 1.6 christos datalist->type = dns_rdatatype_sig; /* SIG(0) */ 844 1.1 christos ISC_LIST_APPEND(datalist->rdata, rdata, link); 845 1.1 christos dataset = NULL; 846 1.16 christos dns_message_gettemprdataset(msg, &dataset); 847 1.16 christos dns_rdatalist_tordataset(datalist, dataset); 848 1.1 christos msg->sig0 = dataset; 849 1.1 christos 850 1.16 christos return ISC_R_SUCCESS; 851 1.1 christos 852 1.19 christos cleanup: 853 1.6 christos if (dynbuf != NULL) { 854 1.1 christos isc_buffer_free(&dynbuf); 855 1.6 christos } 856 1.12 christos if (sig.signature != NULL) { 857 1.1 christos isc_mem_put(mctx, sig.signature, sig.siglen); 858 1.6 christos } 859 1.6 christos if (ctx != NULL) { 860 1.1 christos dst_context_destroy(&ctx); 861 1.6 christos } 862 1.1 christos 863 1.16 christos return result; 864 1.1 christos } 865 1.1 christos 866 1.1 christos isc_result_t 867 1.1 christos dns_dnssec_verifymessage(isc_buffer_t *source, dns_message_t *msg, 868 1.6 christos dst_key_t *key) { 869 1.6 christos dns_rdata_sig_t sig; /* SIG(0) */ 870 1.1 christos unsigned char header[DNS_MESSAGE_HEADERLEN]; 871 1.1 christos dns_rdata_t rdata = DNS_RDATA_INIT; 872 1.1 christos isc_region_t r, source_r, sig_r, header_r; 873 1.1 christos isc_stdtime_t now; 874 1.1 christos dst_context_t *ctx = NULL; 875 1.1 christos isc_mem_t *mctx; 876 1.1 christos isc_result_t result; 877 1.3 christos uint16_t addcount, addcount_n; 878 1.3 christos bool signeedsfree = false; 879 1.1 christos 880 1.1 christos REQUIRE(source != NULL); 881 1.1 christos REQUIRE(msg != NULL); 882 1.1 christos REQUIRE(key != NULL); 883 1.1 christos 884 1.1 christos mctx = msg->mctx; 885 1.1 christos 886 1.1 christos msg->verify_attempted = 1; 887 1.1 christos msg->verified_sig = 0; 888 1.1 christos msg->sig0status = dns_tsigerror_badsig; 889 1.1 christos 890 1.1 christos if (is_response(msg)) { 891 1.6 christos if (msg->query.base == NULL) { 892 1.16 christos return DNS_R_UNEXPECTEDTSIG; 893 1.6 christos } 894 1.1 christos } 895 1.1 christos 896 1.1 christos isc_buffer_usedregion(source, &source_r); 897 1.1 christos 898 1.19 christos CHECK(dns_rdataset_first(msg->sig0)); 899 1.1 christos dns_rdataset_current(msg->sig0, &rdata); 900 1.1 christos 901 1.19 christos CHECK(dns_rdata_tostruct(&rdata, &sig, NULL)); 902 1.3 christos signeedsfree = true; 903 1.1 christos 904 1.1 christos if (sig.labels != 0) { 905 1.19 christos CHECK(DNS_R_SIGINVALID); 906 1.1 christos } 907 1.1 christos 908 1.1 christos if (isc_serial_lt(sig.timeexpire, sig.timesigned)) { 909 1.1 christos msg->sig0status = dns_tsigerror_badtime; 910 1.19 christos CHECK(DNS_R_SIGINVALID); 911 1.1 christos } 912 1.1 christos 913 1.14 christos if (msg->fuzzing) { 914 1.14 christos now = msg->fuzztime; 915 1.14 christos } else { 916 1.16 christos now = isc_stdtime_now(); 917 1.14 christos } 918 1.14 christos 919 1.3 christos if (isc_serial_lt((uint32_t)now, sig.timesigned)) { 920 1.1 christos msg->sig0status = dns_tsigerror_badtime; 921 1.19 christos CHECK(DNS_R_SIGFUTURE); 922 1.6 christos } else if (isc_serial_lt(sig.timeexpire, (uint32_t)now)) { 923 1.1 christos msg->sig0status = dns_tsigerror_badtime; 924 1.19 christos CHECK(DNS_R_SIGEXPIRED); 925 1.1 christos } 926 1.1 christos 927 1.1 christos if (!dns_name_equal(dst_key_name(key), &sig.signer)) { 928 1.1 christos msg->sig0status = dns_tsigerror_badkey; 929 1.19 christos CHECK(DNS_R_SIGINVALID); 930 1.1 christos } 931 1.1 christos 932 1.19 christos CHECK(dst_context_create(key, mctx, DNS_LOGCATEGORY_DNSSEC, false, 0, 933 1.19 christos &ctx)); 934 1.1 christos 935 1.1 christos /* 936 1.1 christos * Digest the SIG(0) record, except for the signature. 937 1.1 christos */ 938 1.1 christos dns_rdata_toregion(&rdata, &r); 939 1.1 christos r.length -= sig.siglen; 940 1.19 christos CHECK(dst_context_adddata(ctx, &r)); 941 1.1 christos 942 1.1 christos /* 943 1.1 christos * If this is a response, digest the query. 944 1.1 christos */ 945 1.6 christos if (is_response(msg)) { 946 1.19 christos CHECK(dst_context_adddata(ctx, &msg->query)); 947 1.6 christos } 948 1.1 christos 949 1.1 christos /* 950 1.1 christos * Extract the header. 951 1.1 christos */ 952 1.1 christos memmove(header, source_r.base, DNS_MESSAGE_HEADERLEN); 953 1.1 christos 954 1.1 christos /* 955 1.1 christos * Decrement the additional field counter. 956 1.1 christos */ 957 1.1 christos memmove(&addcount, &header[DNS_MESSAGE_HEADERLEN - 2], 2); 958 1.1 christos addcount_n = ntohs(addcount); 959 1.3 christos addcount = htons((uint16_t)(addcount_n - 1)); 960 1.1 christos memmove(&header[DNS_MESSAGE_HEADERLEN - 2], &addcount, 2); 961 1.1 christos 962 1.1 christos /* 963 1.1 christos * Digest the modified header. 964 1.1 christos */ 965 1.6 christos header_r.base = (unsigned char *)header; 966 1.1 christos header_r.length = DNS_MESSAGE_HEADERLEN; 967 1.19 christos CHECK(dst_context_adddata(ctx, &header_r)); 968 1.1 christos 969 1.1 christos /* 970 1.1 christos * Digest all non-SIG(0) records. 971 1.1 christos */ 972 1.1 christos r.base = source_r.base + DNS_MESSAGE_HEADERLEN; 973 1.1 christos r.length = msg->sigstart - DNS_MESSAGE_HEADERLEN; 974 1.19 christos CHECK(dst_context_adddata(ctx, &r)); 975 1.1 christos 976 1.1 christos sig_r.base = sig.signature; 977 1.1 christos sig_r.length = sig.siglen; 978 1.1 christos result = dst_context_verify(ctx, &sig_r); 979 1.1 christos if (result != ISC_R_SUCCESS) { 980 1.1 christos msg->sig0status = dns_tsigerror_badsig; 981 1.19 christos goto cleanup; 982 1.1 christos } 983 1.1 christos 984 1.1 christos msg->verified_sig = 1; 985 1.1 christos msg->sig0status = dns_rcode_noerror; 986 1.1 christos 987 1.1 christos dst_context_destroy(&ctx); 988 1.1 christos dns_rdata_freestruct(&sig); 989 1.1 christos 990 1.16 christos return ISC_R_SUCCESS; 991 1.1 christos 992 1.19 christos cleanup: 993 1.6 christos if (signeedsfree) { 994 1.1 christos dns_rdata_freestruct(&sig); 995 1.6 christos } 996 1.6 christos if (ctx != NULL) { 997 1.1 christos dst_context_destroy(&ctx); 998 1.6 christos } 999 1.1 christos 1000 1.16 christos return result; 1001 1.1 christos } 1002 1.1 christos 1003 1.1 christos /*% 1004 1.1 christos * Does this key ('rdata') self sign the rrset ('rdataset')? 1005 1.1 christos */ 1006 1.3 christos bool 1007 1.1 christos dns_dnssec_selfsigns(dns_rdata_t *rdata, const dns_name_t *name, 1008 1.1 christos dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset, 1009 1.6 christos bool ignoretime, isc_mem_t *mctx) { 1010 1.1 christos INSIST(rdataset->type == dns_rdatatype_key || 1011 1.1 christos rdataset->type == dns_rdatatype_dnskey); 1012 1.1 christos if (rdataset->type == dns_rdatatype_key) { 1013 1.1 christos INSIST(sigrdataset->type == dns_rdatatype_sig); 1014 1.1 christos INSIST(sigrdataset->covers == dns_rdatatype_key); 1015 1.1 christos } else { 1016 1.1 christos INSIST(sigrdataset->type == dns_rdatatype_rrsig); 1017 1.1 christos INSIST(sigrdataset->covers == dns_rdatatype_dnskey); 1018 1.1 christos } 1019 1.1 christos 1020 1.16 christos return dns_dnssec_signs(rdata, name, rdataset, sigrdataset, ignoretime, 1021 1.16 christos mctx); 1022 1.1 christos } 1023 1.1 christos 1024 1.3 christos bool 1025 1.1 christos dns_dnssec_signs(dns_rdata_t *rdata, const dns_name_t *name, 1026 1.6 christos dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset, 1027 1.6 christos bool ignoretime, isc_mem_t *mctx) { 1028 1.1 christos dst_key_t *dstkey = NULL; 1029 1.1 christos dns_keytag_t keytag; 1030 1.1 christos dns_rdata_dnskey_t key; 1031 1.1 christos dns_rdata_rrsig_t sig; 1032 1.1 christos dns_rdata_t sigrdata = DNS_RDATA_INIT; 1033 1.1 christos isc_result_t result; 1034 1.1 christos 1035 1.1 christos INSIST(sigrdataset->type == dns_rdatatype_rrsig); 1036 1.6 christos if (sigrdataset->covers != rdataset->type) { 1037 1.16 christos return false; 1038 1.6 christos } 1039 1.1 christos 1040 1.1 christos result = dns_dnssec_keyfromrdata(name, rdata, mctx, &dstkey); 1041 1.6 christos if (result != ISC_R_SUCCESS) { 1042 1.16 christos return false; 1043 1.6 christos } 1044 1.1 christos result = dns_rdata_tostruct(rdata, &key, NULL); 1045 1.1 christos RUNTIME_CHECK(result == ISC_R_SUCCESS); 1046 1.1 christos 1047 1.1 christos keytag = dst_key_id(dstkey); 1048 1.6 christos for (result = dns_rdataset_first(sigrdataset); result == ISC_R_SUCCESS; 1049 1.1 christos result = dns_rdataset_next(sigrdataset)) 1050 1.1 christos { 1051 1.1 christos dns_rdata_reset(&sigrdata); 1052 1.1 christos dns_rdataset_current(sigrdataset, &sigrdata); 1053 1.1 christos result = dns_rdata_tostruct(&sigrdata, &sig, NULL); 1054 1.1 christos RUNTIME_CHECK(result == ISC_R_SUCCESS); 1055 1.1 christos 1056 1.6 christos if (sig.algorithm == key.algorithm && sig.keyid == keytag) { 1057 1.3 christos result = dns_dnssec_verify(name, rdataset, dstkey, 1058 1.3 christos ignoretime, 0, mctx, 1059 1.3 christos &sigrdata, NULL); 1060 1.1 christos if (result == ISC_R_SUCCESS) { 1061 1.1 christos dst_key_free(&dstkey); 1062 1.16 christos return true; 1063 1.1 christos } 1064 1.1 christos } 1065 1.1 christos } 1066 1.1 christos dst_key_free(&dstkey); 1067 1.16 christos return false; 1068 1.1 christos } 1069 1.1 christos 1070 1.16 christos void 1071 1.1 christos dns_dnsseckey_create(isc_mem_t *mctx, dst_key_t **dstkey, 1072 1.6 christos dns_dnsseckey_t **dkp) { 1073 1.1 christos isc_result_t result; 1074 1.1 christos dns_dnsseckey_t *dk; 1075 1.1 christos int major, minor; 1076 1.1 christos 1077 1.1 christos REQUIRE(dkp != NULL && *dkp == NULL); 1078 1.1 christos dk = isc_mem_get(mctx, sizeof(dns_dnsseckey_t)); 1079 1.1 christos 1080 1.1 christos dk->key = *dstkey; 1081 1.1 christos *dstkey = NULL; 1082 1.3 christos dk->force_publish = false; 1083 1.3 christos dk->force_sign = false; 1084 1.3 christos dk->hint_publish = false; 1085 1.3 christos dk->hint_sign = false; 1086 1.6 christos dk->hint_revoke = false; 1087 1.3 christos dk->hint_remove = false; 1088 1.3 christos dk->first_sign = false; 1089 1.3 christos dk->is_active = false; 1090 1.17 christos dk->pubkey = false; 1091 1.10 christos dk->purge = false; 1092 1.1 christos dk->prepublish = 0; 1093 1.1 christos dk->source = dns_keysource_unknown; 1094 1.1 christos dk->index = 0; 1095 1.1 christos 1096 1.1 christos /* KSK or ZSK? */ 1097 1.6 christos result = dst_key_getbool(dk->key, DST_BOOL_KSK, &dk->ksk); 1098 1.6 christos if (result != ISC_R_SUCCESS) { 1099 1.6 christos dk->ksk = ((dst_key_flags(dk->key) & DNS_KEYFLAG_KSK) != 0); 1100 1.6 christos } 1101 1.6 christos result = dst_key_getbool(dk->key, DST_BOOL_ZSK, &dk->zsk); 1102 1.6 christos if (result != ISC_R_SUCCESS) { 1103 1.6 christos dk->zsk = ((dst_key_flags(dk->key) & DNS_KEYFLAG_KSK) == 0); 1104 1.6 christos } 1105 1.1 christos 1106 1.1 christos /* Is this an old-style key? */ 1107 1.1 christos result = dst_key_getprivateformat(dk->key, &major, &minor); 1108 1.1 christos INSIST(result == ISC_R_SUCCESS); 1109 1.1 christos 1110 1.1 christos /* Smart signing started with key format 1.3 */ 1111 1.3 christos dk->legacy = (major == 1 && minor <= 2); 1112 1.1 christos 1113 1.1 christos ISC_LINK_INIT(dk, link); 1114 1.1 christos *dkp = dk; 1115 1.1 christos } 1116 1.1 christos 1117 1.1 christos void 1118 1.1 christos dns_dnsseckey_destroy(isc_mem_t *mctx, dns_dnsseckey_t **dkp) { 1119 1.1 christos dns_dnsseckey_t *dk; 1120 1.1 christos 1121 1.1 christos REQUIRE(dkp != NULL && *dkp != NULL); 1122 1.1 christos dk = *dkp; 1123 1.6 christos *dkp = NULL; 1124 1.6 christos if (dk->key != NULL) { 1125 1.1 christos dst_key_free(&dk->key); 1126 1.6 christos } 1127 1.1 christos isc_mem_put(mctx, dk, sizeof(dns_dnsseckey_t)); 1128 1.1 christos } 1129 1.1 christos 1130 1.6 christos void 1131 1.6 christos dns_dnssec_get_hints(dns_dnsseckey_t *key, isc_stdtime_t now) { 1132 1.6 christos isc_stdtime_t publish = 0, active = 0, revoke = 0, remove = 0; 1133 1.1 christos 1134 1.1 christos REQUIRE(key != NULL && key->key != NULL); 1135 1.1 christos 1136 1.6 christos key->hint_publish = dst_key_is_published(key->key, now, &publish); 1137 1.6 christos key->hint_sign = dst_key_is_signing(key->key, DST_BOOL_ZSK, now, 1138 1.6 christos &active); 1139 1.6 christos key->hint_revoke = dst_key_is_revoked(key->key, now, &revoke); 1140 1.6 christos key->hint_remove = dst_key_is_removed(key->key, now, &remove); 1141 1.6 christos 1142 1.6 christos /* 1143 1.6 christos * Activation date is set (maybe in the future), but publication date 1144 1.6 christos * isn't. Most likely the user wants to publish now and activate later. 1145 1.6 christos * Most likely because this is true for most rollovers, except for: 1146 1.6 christos * 1. The unpopular ZSK Double-RRSIG method. 1147 1.6 christos * 2. When introducing a new algorithm. 1148 1.6 christos * These two cases are rare enough that we will set hint_publish 1149 1.6 christos * anyway when hint_sign is set, because BIND 9 natively does not 1150 1.6 christos * support the ZSK Double-RRSIG method, and when introducing a new 1151 1.6 christos * algorithm, we strive to publish its signatures and DNSKEY records 1152 1.6 christos * at the same time. 1153 1.6 christos */ 1154 1.6 christos if (key->hint_sign && publish == 0) { 1155 1.3 christos key->hint_publish = true; 1156 1.1 christos } 1157 1.1 christos 1158 1.1 christos /* 1159 1.6 christos * If activation date is in the future, make note of how far off. 1160 1.1 christos */ 1161 1.6 christos if (key->hint_publish && active > now) { 1162 1.1 christos key->prepublish = active - now; 1163 1.1 christos } 1164 1.1 christos 1165 1.1 christos /* 1166 1.6 christos * Metadata says revoke. If the key is published, we *have to* sign 1167 1.6 christos * with it per RFC5011 -- even if it was not active before. 1168 1.1 christos * 1169 1.1 christos * If it hasn't already been done, we should also revoke it now. 1170 1.1 christos */ 1171 1.6 christos if (key->hint_publish && key->hint_revoke) { 1172 1.3 christos uint32_t flags; 1173 1.3 christos key->hint_sign = true; 1174 1.1 christos flags = dst_key_flags(key->key); 1175 1.1 christos if ((flags & DNS_KEYFLAG_REVOKE) == 0) { 1176 1.1 christos flags |= DNS_KEYFLAG_REVOKE; 1177 1.1 christos dst_key_setflags(key->key, flags); 1178 1.1 christos } 1179 1.1 christos } 1180 1.1 christos 1181 1.1 christos /* 1182 1.6 christos * Metadata says delete, so don't publish this key or sign with it 1183 1.6 christos * (note that signatures of a removed key may still be reused). 1184 1.1 christos */ 1185 1.6 christos if (key->hint_remove) { 1186 1.3 christos key->hint_publish = false; 1187 1.3 christos key->hint_sign = false; 1188 1.1 christos } 1189 1.1 christos } 1190 1.1 christos 1191 1.16 christos static isc_result_t 1192 1.19 christos findmatchingkeys(const char *directory, bool rrtypekey, char *namebuf, 1193 1.19 christos unsigned int len, isc_mem_t *mctx, isc_stdtime_t now, 1194 1.16 christos dns_dnsseckeylist_t *list) { 1195 1.19 christos isc_result_t result; 1196 1.16 christos isc_dir_t dir; 1197 1.19 christos bool dir_open = false, match = false; 1198 1.19 christos unsigned int i; 1199 1.1 christos dns_dnsseckey_t *key = NULL; 1200 1.1 christos dst_key_t *dstkey = NULL; 1201 1.1 christos 1202 1.1 christos isc_dir_init(&dir); 1203 1.6 christos if (directory == NULL) { 1204 1.1 christos directory = "."; 1205 1.6 christos } 1206 1.19 christos 1207 1.19 christos CHECK(isc_dir_open(&dir, directory)); 1208 1.3 christos dir_open = true; 1209 1.1 christos 1210 1.1 christos while (isc_dir_read(&dir) == ISC_R_SUCCESS) { 1211 1.6 christos if (dir.entry.name[0] != 'K' || dir.entry.length < len + 1 || 1212 1.1 christos dir.entry.name[len + 1] != '+' || 1213 1.1 christos strncasecmp(dir.entry.name + 1, namebuf, len) != 0) 1214 1.6 christos { 1215 1.1 christos continue; 1216 1.6 christos } 1217 1.1 christos 1218 1.6 christos for (i = len + 1 + 1; i < dir.entry.length; i++) { 1219 1.11 christos if (!isdigit((unsigned char)dir.entry.name[i])) { 1220 1.1 christos break; 1221 1.6 christos } 1222 1.1 christos } 1223 1.1 christos 1224 1.1 christos /* 1225 1.1 christos * Did we not read exactly 3 digits? 1226 1.1 christos * Did we overflow? 1227 1.1 christos * Did we correctly terminate? 1228 1.1 christos */ 1229 1.1 christos if (i != len + 1 + 1 + 3 || i >= dir.entry.length || 1230 1.13 christos dir.entry.name[i] != '+') 1231 1.13 christos { 1232 1.1 christos continue; 1233 1.6 christos } 1234 1.1 christos 1235 1.6 christos for (i++; i < dir.entry.length; i++) { 1236 1.11 christos if (!isdigit((unsigned char)dir.entry.name[i])) { 1237 1.1 christos break; 1238 1.6 christos } 1239 1.6 christos } 1240 1.6 christos 1241 1.1 christos /* 1242 1.1 christos * Did we not read exactly 5 more digits? 1243 1.1 christos * Did we overflow? 1244 1.1 christos * Did we correctly terminate? 1245 1.1 christos */ 1246 1.1 christos if (i != len + 1 + 1 + 3 + 1 + 5 || i >= dir.entry.length || 1247 1.1 christos strcmp(dir.entry.name + i, ".private") != 0) 1248 1.6 christos { 1249 1.6 christos continue; 1250 1.6 christos } 1251 1.1 christos 1252 1.19 christos int type = DST_TYPE_PUBLIC | DST_TYPE_PRIVATE | DST_TYPE_STATE; 1253 1.19 christos if (rrtypekey) { 1254 1.19 christos type |= DST_TYPE_KEY; 1255 1.19 christos } 1256 1.1 christos dstkey = NULL; 1257 1.19 christos result = dst_key_fromnamedfile(dir.entry.name, directory, type, 1258 1.19 christos mctx, &dstkey); 1259 1.19 christos if (result == DST_R_BADKEYTYPE) { 1260 1.19 christos continue; 1261 1.1 christos } 1262 1.1 christos if (result != ISC_R_SUCCESS) { 1263 1.6 christos isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, 1264 1.6 christos DNS_LOGMODULE_DNSSEC, ISC_LOG_WARNING, 1265 1.1 christos "dns_dnssec_findmatchingkeys: " 1266 1.1 christos "error reading key file %s: %s", 1267 1.1 christos dir.entry.name, 1268 1.1 christos isc_result_totext(result)); 1269 1.1 christos continue; 1270 1.1 christos } 1271 1.1 christos 1272 1.16 christos dns_dnsseckey_create(mctx, &dstkey, &key); 1273 1.1 christos key->source = dns_keysource_repository; 1274 1.6 christos dns_dnssec_get_hints(key, now); 1275 1.1 christos 1276 1.1 christos if (key->legacy) { 1277 1.1 christos dns_dnsseckey_destroy(mctx, &key); 1278 1.1 christos } else { 1279 1.16 christos ISC_LIST_APPEND(*list, key, link); 1280 1.19 christos match = true; 1281 1.1 christos key = NULL; 1282 1.1 christos } 1283 1.1 christos } 1284 1.19 christos result = match ? ISC_R_SUCCESS : ISC_R_NOTFOUND; 1285 1.1 christos 1286 1.19 christos cleanup: 1287 1.16 christos if (dir_open) { 1288 1.16 christos isc_dir_close(&dir); 1289 1.16 christos } 1290 1.16 christos if (dstkey != NULL) { 1291 1.16 christos dst_key_free(&dstkey); 1292 1.16 christos } 1293 1.16 christos return result; 1294 1.16 christos } 1295 1.16 christos 1296 1.16 christos /*% 1297 1.19 christos * Get a list of KEY or DNSKEY keys from the key repository. If rrtypekey 1298 1.19 christos * is true KEY keys will be returned otherwise DNSSEC keys. 1299 1.16 christos */ 1300 1.16 christos isc_result_t 1301 1.16 christos dns_dnssec_findmatchingkeys(const dns_name_t *origin, dns_kasp_t *kasp, 1302 1.16 christos const char *keydir, dns_keystorelist_t *keystores, 1303 1.19 christos isc_stdtime_t now, bool rrtypekey, isc_mem_t *mctx, 1304 1.16 christos dns_dnsseckeylist_t *keylist) { 1305 1.16 christos isc_result_t result = ISC_R_SUCCESS; 1306 1.16 christos dns_dnsseckeylist_t list; 1307 1.16 christos dns_dnsseckey_t *key = NULL; 1308 1.16 christos char namebuf[DNS_NAME_FORMATSIZE]; 1309 1.16 christos isc_buffer_t b; 1310 1.16 christos unsigned int len; 1311 1.16 christos 1312 1.16 christos REQUIRE(keylist != NULL); 1313 1.16 christos ISC_LIST_INIT(list); 1314 1.16 christos 1315 1.16 christos isc_buffer_init(&b, namebuf, sizeof(namebuf) - 1); 1316 1.19 christos CHECK(dns_name_tofilenametext(origin, false, &b)); 1317 1.16 christos len = isc_buffer_usedlength(&b); 1318 1.16 christos namebuf[len] = '\0'; 1319 1.16 christos 1320 1.16 christos if (kasp == NULL || (strcmp(dns_kasp_getname(kasp), "none") == 0) || 1321 1.16 christos (strcmp(dns_kasp_getname(kasp), "insecure") == 0)) 1322 1.16 christos { 1323 1.19 christos CHECK(findmatchingkeys(keydir, rrtypekey, namebuf, len, mctx, 1324 1.19 christos now, &list)); 1325 1.16 christos } else if (keystores != NULL) { 1326 1.16 christos for (dns_keystore_t *keystore = ISC_LIST_HEAD(*keystores); 1327 1.16 christos keystore != NULL; keystore = ISC_LIST_NEXT(keystore, link)) 1328 1.16 christos { 1329 1.16 christos for (dns_kasp_key_t *kkey = 1330 1.16 christos ISC_LIST_HEAD(dns_kasp_keys(kasp)); 1331 1.16 christos kkey != NULL; kkey = ISC_LIST_NEXT(kkey, link)) 1332 1.16 christos { 1333 1.16 christos if (dns_kasp_key_keystore(kkey) == keystore) { 1334 1.16 christos const char *directory = 1335 1.16 christos dns_keystore_directory(keystore, 1336 1.16 christos keydir); 1337 1.19 christos CHECK(findmatchingkeys( 1338 1.19 christos directory, rrtypekey, namebuf, 1339 1.19 christos len, mctx, now, &list)); 1340 1.16 christos break; 1341 1.16 christos } 1342 1.16 christos } 1343 1.16 christos } 1344 1.16 christos } 1345 1.16 christos 1346 1.1 christos if (!ISC_LIST_EMPTY(list)) { 1347 1.1 christos result = ISC_R_SUCCESS; 1348 1.1 christos ISC_LIST_APPENDLIST(*keylist, list, link); 1349 1.6 christos } else { 1350 1.1 christos result = ISC_R_NOTFOUND; 1351 1.6 christos } 1352 1.1 christos 1353 1.19 christos cleanup: 1354 1.1 christos while ((key = ISC_LIST_HEAD(list)) != NULL) { 1355 1.1 christos ISC_LIST_UNLINK(list, key, link); 1356 1.1 christos INSIST(key->key != NULL); 1357 1.1 christos dst_key_free(&key->key); 1358 1.1 christos dns_dnsseckey_destroy(mctx, &key); 1359 1.1 christos } 1360 1.16 christos return result; 1361 1.1 christos } 1362 1.1 christos 1363 1.1 christos /*% 1364 1.1 christos * Add 'newkey' to 'keylist' if it's not already there. 1365 1.1 christos * 1366 1.3 christos * If 'savekeys' is true, then we need to preserve all 1367 1.1 christos * the keys in the keyset, regardless of whether they have 1368 1.1 christos * metadata indicating they should be deactivated or removed. 1369 1.1 christos */ 1370 1.16 christos static void 1371 1.6 christos addkey(dns_dnsseckeylist_t *keylist, dst_key_t **newkey, bool savekeys, 1372 1.17 christos bool pubkey_only, isc_mem_t *mctx) { 1373 1.16 christos dns_dnsseckey_t *key = NULL; 1374 1.1 christos 1375 1.1 christos /* Skip duplicates */ 1376 1.6 christos for (key = ISC_LIST_HEAD(*keylist); key != NULL; 1377 1.13 christos key = ISC_LIST_NEXT(key, link)) 1378 1.13 christos { 1379 1.1 christos if (dst_key_id(key->key) == dst_key_id(*newkey) && 1380 1.1 christos dst_key_alg(key->key) == dst_key_alg(*newkey) && 1381 1.1 christos dns_name_equal(dst_key_name(key->key), 1382 1.1 christos dst_key_name(*newkey))) 1383 1.6 christos { 1384 1.1 christos break; 1385 1.6 christos } 1386 1.1 christos } 1387 1.1 christos 1388 1.1 christos if (key != NULL) { 1389 1.1 christos /* 1390 1.17 christos * Found a match. If we already had a private key, then 1391 1.17 christos * the new key can't be an improvement. If the existing 1392 1.17 christos * key was public-only but the new key is too, then it's 1393 1.17 christos * still not an improvement. Mark the old key as having 1394 1.17 christos * been found in the zone and stop. 1395 1.1 christos */ 1396 1.17 christos if (dst_key_isprivate(key->key) || !dst_key_isprivate(*newkey)) 1397 1.17 christos { 1398 1.17 christos key->source = dns_keysource_zoneapex; 1399 1.17 christos return; 1400 1.1 christos } 1401 1.1 christos 1402 1.17 christos /* 1403 1.17 christos * However, if the old key was public-only, and the new key 1404 1.17 christos * is private, then we're throwing away the old key. 1405 1.17 christos */ 1406 1.17 christos dst_key_free(&key->key); 1407 1.17 christos ISC_LIST_UNLINK(*keylist, key, link); 1408 1.17 christos dns_dnsseckey_destroy(mctx, &key); 1409 1.1 christos } 1410 1.1 christos 1411 1.17 christos /* Store the new key. */ 1412 1.16 christos dns_dnsseckey_create(mctx, newkey, &key); 1413 1.17 christos key->source = dns_keysource_zoneapex; 1414 1.17 christos key->pubkey = pubkey_only; 1415 1.1 christos if (key->legacy || savekeys) { 1416 1.3 christos key->force_publish = true; 1417 1.1 christos key->force_sign = dst_key_isprivate(key->key); 1418 1.1 christos } 1419 1.1 christos ISC_LIST_APPEND(*keylist, key, link); 1420 1.1 christos *newkey = NULL; 1421 1.1 christos } 1422 1.1 christos 1423 1.1 christos /*% 1424 1.1 christos * Mark all keys which signed the DNSKEY/SOA RRsets as "active", 1425 1.1 christos * for future reference. 1426 1.1 christos */ 1427 1.1 christos static isc_result_t 1428 1.1 christos mark_active_keys(dns_dnsseckeylist_t *keylist, dns_rdataset_t *rrsigs) { 1429 1.1 christos isc_result_t result = ISC_R_SUCCESS; 1430 1.1 christos dns_rdata_t rdata = DNS_RDATA_INIT; 1431 1.1 christos dns_rdataset_t sigs; 1432 1.1 christos dns_dnsseckey_t *key; 1433 1.1 christos 1434 1.1 christos REQUIRE(rrsigs != NULL && dns_rdataset_isassociated(rrsigs)); 1435 1.1 christos 1436 1.1 christos dns_rdataset_init(&sigs); 1437 1.1 christos dns_rdataset_clone(rrsigs, &sigs); 1438 1.6 christos for (key = ISC_LIST_HEAD(*keylist); key != NULL; 1439 1.13 christos key = ISC_LIST_NEXT(key, link)) 1440 1.13 christos { 1441 1.3 christos uint16_t keyid, sigid; 1442 1.1 christos dns_secalg_t keyalg, sigalg; 1443 1.1 christos keyid = dst_key_id(key->key); 1444 1.1 christos keyalg = dst_key_alg(key->key); 1445 1.1 christos 1446 1.1 christos for (result = dns_rdataset_first(&sigs); 1447 1.6 christos result == ISC_R_SUCCESS; result = dns_rdataset_next(&sigs)) 1448 1.6 christos { 1449 1.1 christos dns_rdata_rrsig_t sig; 1450 1.1 christos 1451 1.1 christos dns_rdata_reset(&rdata); 1452 1.1 christos dns_rdataset_current(&sigs, &rdata); 1453 1.1 christos result = dns_rdata_tostruct(&rdata, &sig, NULL); 1454 1.1 christos RUNTIME_CHECK(result == ISC_R_SUCCESS); 1455 1.1 christos sigalg = sig.algorithm; 1456 1.1 christos sigid = sig.keyid; 1457 1.1 christos if (keyid == sigid && keyalg == sigalg) { 1458 1.3 christos key->is_active = true; 1459 1.1 christos break; 1460 1.1 christos } 1461 1.1 christos } 1462 1.1 christos } 1463 1.1 christos 1464 1.6 christos if (result == ISC_R_NOMORE) { 1465 1.1 christos result = ISC_R_SUCCESS; 1466 1.6 christos } 1467 1.1 christos 1468 1.6 christos if (dns_rdataset_isassociated(&sigs)) { 1469 1.1 christos dns_rdataset_disassociate(&sigs); 1470 1.6 christos } 1471 1.16 christos return result; 1472 1.16 christos } 1473 1.16 christos 1474 1.16 christos static isc_result_t 1475 1.16 christos keyfromfile(dns_kasp_t *kasp, const char *keydir, dst_key_t *key, int type, 1476 1.16 christos isc_mem_t *mctx, dst_key_t **savekey) { 1477 1.16 christos const char *directory = keydir; 1478 1.16 christos isc_result_t result = ISC_R_NOTFOUND; 1479 1.16 christos 1480 1.16 christos if (kasp == NULL || (strcmp(dns_kasp_getname(kasp), "none") == 0) || 1481 1.16 christos (strcmp(dns_kasp_getname(kasp), "insecure") == 0)) 1482 1.16 christos { 1483 1.16 christos result = dst_key_fromfile(dst_key_name(key), dst_key_id(key), 1484 1.16 christos dst_key_alg(key), type, directory, 1485 1.16 christos mctx, savekey); 1486 1.16 christos } else { 1487 1.16 christos for (dns_kasp_key_t *kkey = ISC_LIST_HEAD(dns_kasp_keys(kasp)); 1488 1.16 christos kkey != NULL; kkey = ISC_LIST_NEXT(kkey, link)) 1489 1.16 christos { 1490 1.16 christos dns_keystore_t *ks = dns_kasp_key_keystore(kkey); 1491 1.16 christos directory = dns_keystore_directory(ks, keydir); 1492 1.16 christos result = dst_key_fromfile(dst_key_name(key), 1493 1.16 christos dst_key_id(key), 1494 1.16 christos dst_key_alg(key), type, 1495 1.16 christos directory, mctx, savekey); 1496 1.16 christos if (result == ISC_R_SUCCESS) { 1497 1.16 christos break; 1498 1.16 christos } 1499 1.16 christos } 1500 1.16 christos } 1501 1.16 christos 1502 1.16 christos return result; 1503 1.1 christos } 1504 1.1 christos 1505 1.1 christos /*% 1506 1.1 christos * Add the contents of a DNSKEY rdataset 'keyset' to 'keylist'. 1507 1.1 christos */ 1508 1.1 christos isc_result_t 1509 1.16 christos dns_dnssec_keylistfromrdataset(const dns_name_t *origin, dns_kasp_t *kasp, 1510 1.16 christos const char *directory, isc_mem_t *mctx, 1511 1.16 christos dns_rdataset_t *keyset, dns_rdataset_t *keysigs, 1512 1.16 christos dns_rdataset_t *soasigs, bool savekeys, 1513 1.16 christos bool publickey, dns_dnsseckeylist_t *keylist) { 1514 1.1 christos dns_rdataset_t keys; 1515 1.1 christos dns_rdata_t rdata = DNS_RDATA_INIT; 1516 1.11 christos dst_key_t *dnskey = NULL, *pubkey = NULL, *privkey = NULL; 1517 1.1 christos isc_result_t result; 1518 1.1 christos 1519 1.1 christos REQUIRE(keyset != NULL && dns_rdataset_isassociated(keyset)); 1520 1.1 christos 1521 1.1 christos dns_rdataset_init(&keys); 1522 1.1 christos 1523 1.1 christos dns_rdataset_clone(keyset, &keys); 1524 1.6 christos for (result = dns_rdataset_first(&keys); result == ISC_R_SUCCESS; 1525 1.6 christos result = dns_rdataset_next(&keys)) 1526 1.6 christos { 1527 1.1 christos dns_rdata_reset(&rdata); 1528 1.1 christos dns_rdataset_current(&keys, &rdata); 1529 1.4 christos 1530 1.4 christos REQUIRE(rdata.type == dns_rdatatype_key || 1531 1.4 christos rdata.type == dns_rdatatype_dnskey); 1532 1.4 christos REQUIRE(rdata.length > 3); 1533 1.4 christos 1534 1.4 christos /* Skip unsupported algorithms */ 1535 1.6 christos if (!dst_algorithm_supported(rdata.data[3])) { 1536 1.4 christos goto skip; 1537 1.6 christos } 1538 1.4 christos 1539 1.19 christos CHECK(dns_dnssec_keyfromrdata(origin, &rdata, mctx, &dnskey)); 1540 1.11 christos dst_key_setttl(dnskey, keys.ttl); 1541 1.1 christos 1542 1.17 christos if (!is_zone_key(dnskey)) { 1543 1.1 christos goto skip; 1544 1.6 christos } 1545 1.1 christos 1546 1.1 christos /* Corrupted .key file? */ 1547 1.11 christos if (!dns_name_equal(origin, dst_key_name(dnskey))) { 1548 1.1 christos goto skip; 1549 1.6 christos } 1550 1.1 christos 1551 1.1 christos if (publickey) { 1552 1.17 christos addkey(keylist, &dnskey, savekeys, true, mctx); 1553 1.1 christos goto skip; 1554 1.1 christos } 1555 1.1 christos 1556 1.11 christos /* Try to read the public key. */ 1557 1.16 christos result = keyfromfile(kasp, directory, dnskey, 1558 1.18 christos DST_TYPE_PUBLIC | DST_TYPE_STATE, mctx, 1559 1.16 christos &pubkey); 1560 1.11 christos if (result == ISC_R_FILENOTFOUND || result == ISC_R_NOPERM) { 1561 1.11 christos result = ISC_R_SUCCESS; 1562 1.11 christos } 1563 1.19 christos CHECK(result); 1564 1.11 christos 1565 1.16 christos if (kasp != NULL && dns_kasp_offlineksk(kasp) && 1566 1.16 christos (dst_key_flags(dnskey) & DNS_KEYFLAG_KSK) != 0) 1567 1.16 christos { 1568 1.16 christos result = ISC_R_NOPERM; 1569 1.16 christos goto addkey; 1570 1.16 christos } 1571 1.16 christos 1572 1.11 christos /* Now read the private key. */ 1573 1.18 christos result = keyfromfile(kasp, directory, dnskey, 1574 1.18 christos DST_TYPE_PUBLIC | DST_TYPE_PRIVATE | 1575 1.18 christos DST_TYPE_STATE, 1576 1.18 christos mctx, &privkey); 1577 1.1 christos 1578 1.1 christos /* 1579 1.1 christos * If the key was revoked and the private file 1580 1.1 christos * doesn't exist, maybe it was revoked internally 1581 1.1 christos * by named. Try loading the unrevoked version. 1582 1.1 christos */ 1583 1.1 christos if (result == ISC_R_FILENOTFOUND) { 1584 1.3 christos uint32_t flags; 1585 1.11 christos flags = dst_key_flags(dnskey); 1586 1.1 christos if ((flags & DNS_KEYFLAG_REVOKE) != 0) { 1587 1.11 christos dst_key_setflags(dnskey, 1588 1.1 christos flags & ~DNS_KEYFLAG_REVOKE); 1589 1.16 christos result = keyfromfile(kasp, directory, dnskey, 1590 1.18 christos DST_TYPE_PUBLIC | 1591 1.18 christos DST_TYPE_PRIVATE | 1592 1.18 christos DST_TYPE_STATE, 1593 1.16 christos mctx, &privkey); 1594 1.1 christos if (result == ISC_R_SUCCESS && 1595 1.11 christos dst_key_pubcompare(dnskey, privkey, false)) 1596 1.6 christos { 1597 1.1 christos dst_key_setflags(privkey, flags); 1598 1.1 christos } 1599 1.11 christos dst_key_setflags(dnskey, flags); 1600 1.1 christos } 1601 1.1 christos } 1602 1.1 christos 1603 1.1 christos if (result != ISC_R_SUCCESS) { 1604 1.1 christos char filename[DNS_NAME_FORMATSIZE + 1605 1.1 christos DNS_SECALG_FORMATSIZE + 1606 1.1 christos sizeof("key file for //65535")]; 1607 1.1 christos isc_result_t result2; 1608 1.1 christos isc_buffer_t buf; 1609 1.1 christos 1610 1.3 christos isc_buffer_init(&buf, filename, NAME_MAX); 1611 1.6 christos result2 = dst_key_getfilename( 1612 1.11 christos dst_key_name(dnskey), dst_key_id(dnskey), 1613 1.11 christos dst_key_alg(dnskey), 1614 1.18 christos DST_TYPE_PUBLIC | DST_TYPE_PRIVATE | 1615 1.18 christos DST_TYPE_STATE, 1616 1.16 christos NULL, mctx, &buf); 1617 1.1 christos if (result2 != ISC_R_SUCCESS) { 1618 1.1 christos char namebuf[DNS_NAME_FORMATSIZE]; 1619 1.1 christos char algbuf[DNS_SECALG_FORMATSIZE]; 1620 1.1 christos 1621 1.11 christos dns_name_format(dst_key_name(dnskey), namebuf, 1622 1.6 christos sizeof(namebuf)); 1623 1.11 christos dns_secalg_format(dst_key_alg(dnskey), algbuf, 1624 1.6 christos sizeof(algbuf)); 1625 1.1 christos snprintf(filename, sizeof(filename) - 1, 1626 1.6 christos "key file for %s/%s/%d", namebuf, 1627 1.11 christos algbuf, dst_key_id(dnskey)); 1628 1.1 christos } 1629 1.1 christos 1630 1.1 christos isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, 1631 1.1 christos DNS_LOGMODULE_DNSSEC, ISC_LOG_WARNING, 1632 1.1 christos "dns_dnssec_keylistfromrdataset: error " 1633 1.1 christos "reading %s: %s", 1634 1.1 christos filename, isc_result_totext(result)); 1635 1.1 christos } 1636 1.1 christos 1637 1.16 christos addkey: 1638 1.1 christos if (result == ISC_R_FILENOTFOUND || result == ISC_R_NOPERM) { 1639 1.11 christos if (pubkey != NULL) { 1640 1.17 christos addkey(keylist, &pubkey, savekeys, true, mctx); 1641 1.11 christos } else { 1642 1.17 christos addkey(keylist, &dnskey, savekeys, false, mctx); 1643 1.11 christos } 1644 1.1 christos goto skip; 1645 1.1 christos } 1646 1.19 christos CHECK(result); 1647 1.1 christos 1648 1.1 christos /* 1649 1.1 christos * Whatever the key's default TTL may have 1650 1.1 christos * been, the rdataset TTL takes priority. 1651 1.1 christos */ 1652 1.11 christos dst_key_setttl(privkey, dst_key_getttl(dnskey)); 1653 1.1 christos 1654 1.17 christos addkey(keylist, &privkey, savekeys, false, mctx); 1655 1.6 christos skip: 1656 1.11 christos if (dnskey != NULL) { 1657 1.11 christos dst_key_free(&dnskey); 1658 1.11 christos } 1659 1.6 christos if (pubkey != NULL) { 1660 1.1 christos dst_key_free(&pubkey); 1661 1.6 christos } 1662 1.6 christos if (privkey != NULL) { 1663 1.1 christos dst_key_free(&privkey); 1664 1.6 christos } 1665 1.1 christos } 1666 1.1 christos 1667 1.6 christos if (result != ISC_R_NOMORE) { 1668 1.1 christos RETERR(result); 1669 1.6 christos } 1670 1.1 christos 1671 1.6 christos if (keysigs != NULL && dns_rdataset_isassociated(keysigs)) { 1672 1.19 christos CHECK(mark_active_keys(keylist, keysigs)); 1673 1.6 christos } 1674 1.1 christos 1675 1.6 christos if (soasigs != NULL && dns_rdataset_isassociated(soasigs)) { 1676 1.19 christos CHECK(mark_active_keys(keylist, soasigs)); 1677 1.6 christos } 1678 1.1 christos 1679 1.1 christos result = ISC_R_SUCCESS; 1680 1.1 christos 1681 1.19 christos cleanup: 1682 1.6 christos if (dns_rdataset_isassociated(&keys)) { 1683 1.1 christos dns_rdataset_disassociate(&keys); 1684 1.6 christos } 1685 1.11 christos if (dnskey != NULL) { 1686 1.11 christos dst_key_free(&dnskey); 1687 1.11 christos } 1688 1.6 christos if (pubkey != NULL) { 1689 1.1 christos dst_key_free(&pubkey); 1690 1.6 christos } 1691 1.6 christos if (privkey != NULL) { 1692 1.1 christos dst_key_free(&privkey); 1693 1.6 christos } 1694 1.16 christos return result; 1695 1.1 christos } 1696 1.1 christos 1697 1.15 christos isc_result_t 1698 1.15 christos dns_dnssec_make_dnskey(dst_key_t *key, unsigned char *buf, int bufsize, 1699 1.15 christos dns_rdata_t *target) { 1700 1.1 christos isc_result_t result; 1701 1.1 christos isc_buffer_t b; 1702 1.1 christos isc_region_t r; 1703 1.1 christos 1704 1.1 christos isc_buffer_init(&b, buf, bufsize); 1705 1.1 christos result = dst_key_todns(key, &b); 1706 1.6 christos if (result != ISC_R_SUCCESS) { 1707 1.16 christos return result; 1708 1.6 christos } 1709 1.1 christos 1710 1.1 christos dns_rdata_reset(target); 1711 1.1 christos isc_buffer_usedregion(&b, &r); 1712 1.6 christos dns_rdata_fromregion(target, dst_key_class(key), dns_rdatatype_dnskey, 1713 1.6 christos &r); 1714 1.16 christos return ISC_R_SUCCESS; 1715 1.1 christos } 1716 1.1 christos 1717 1.1 christos static isc_result_t 1718 1.5 christos addrdata(dns_rdata_t *rdata, dns_diff_t *diff, const dns_name_t *origin, 1719 1.6 christos dns_ttl_t ttl, isc_mem_t *mctx) { 1720 1.1 christos dns_difftuple_t *tuple = NULL; 1721 1.1 christos 1722 1.6 christos RETERR(dns_difftuple_create(mctx, DNS_DIFFOP_ADD, origin, ttl, rdata, 1723 1.6 christos &tuple)); 1724 1.1 christos dns_diff_appendminimal(diff, &tuple); 1725 1.1 christos 1726 1.19 christos return ISC_R_SUCCESS; 1727 1.1 christos } 1728 1.1 christos 1729 1.1 christos static isc_result_t 1730 1.5 christos delrdata(dns_rdata_t *rdata, dns_diff_t *diff, const dns_name_t *origin, 1731 1.6 christos dns_ttl_t ttl, isc_mem_t *mctx) { 1732 1.1 christos dns_difftuple_t *tuple = NULL; 1733 1.1 christos 1734 1.6 christos RETERR(dns_difftuple_create(mctx, DNS_DIFFOP_DEL, origin, ttl, rdata, 1735 1.6 christos &tuple)); 1736 1.1 christos dns_diff_appendminimal(diff, &tuple); 1737 1.1 christos 1738 1.19 christos return ISC_R_SUCCESS; 1739 1.1 christos } 1740 1.1 christos 1741 1.1 christos static isc_result_t 1742 1.1 christos publish_key(dns_diff_t *diff, dns_dnsseckey_t *key, const dns_name_t *origin, 1743 1.14 christos dns_ttl_t ttl, isc_mem_t *mctx, 1744 1.14 christos void (*report)(const char *, ...) ISC_FORMAT_PRINTF(1, 2)) { 1745 1.1 christos isc_result_t result; 1746 1.1 christos unsigned char buf[DST_KEY_MAXSIZE]; 1747 1.4 christos char keystr[DST_KEY_FORMATSIZE]; 1748 1.1 christos dns_rdata_t dnskey = DNS_RDATA_INIT; 1749 1.1 christos 1750 1.1 christos dns_rdata_reset(&dnskey); 1751 1.19 christos CHECK(dns_dnssec_make_dnskey(key->key, buf, sizeof(buf), &dnskey)); 1752 1.4 christos dst_key_format(key->key, keystr, sizeof(keystr)); 1753 1.1 christos 1754 1.6 christos report("Fetching %s (%s) from key %s.", keystr, 1755 1.6 christos key->ksk ? (key->zsk ? "CSK" : "KSK") : "ZSK", 1756 1.6 christos key->source == dns_keysource_user ? "file" : "repository"); 1757 1.1 christos 1758 1.1 christos if (key->prepublish && ttl > key->prepublish) { 1759 1.1 christos isc_stdtime_t now; 1760 1.1 christos 1761 1.14 christos report("Key %s: Delaying activation to match the DNSKEY TTL " 1762 1.14 christos "(%u).", 1763 1.1 christos keystr, ttl); 1764 1.1 christos 1765 1.16 christos now = isc_stdtime_now(); 1766 1.1 christos dst_key_settime(key->key, DST_TIME_ACTIVATE, now + ttl); 1767 1.1 christos } 1768 1.1 christos 1769 1.1 christos /* publish key */ 1770 1.5 christos result = addrdata(&dnskey, diff, origin, ttl, mctx); 1771 1.1 christos 1772 1.19 christos cleanup: 1773 1.16 christos return result; 1774 1.1 christos } 1775 1.1 christos 1776 1.1 christos static isc_result_t 1777 1.1 christos remove_key(dns_diff_t *diff, dns_dnsseckey_t *key, const dns_name_t *origin, 1778 1.6 christos dns_ttl_t ttl, isc_mem_t *mctx, const char *reason, 1779 1.14 christos void (*report)(const char *, ...) ISC_FORMAT_PRINTF(1, 2)) { 1780 1.1 christos isc_result_t result; 1781 1.1 christos unsigned char buf[DST_KEY_MAXSIZE]; 1782 1.1 christos dns_rdata_t dnskey = DNS_RDATA_INIT; 1783 1.1 christos char alg[80]; 1784 1.14 christos char namebuf[DNS_NAME_FORMATSIZE]; 1785 1.1 christos 1786 1.1 christos dns_secalg_format(dst_key_alg(key->key), alg, sizeof(alg)); 1787 1.14 christos dns_name_format(dst_key_name(key->key), namebuf, sizeof(namebuf)); 1788 1.14 christos report("Removing %s key %s/%d/%s from DNSKEY RRset.", reason, namebuf, 1789 1.6 christos dst_key_id(key->key), alg); 1790 1.1 christos 1791 1.19 christos CHECK(dns_dnssec_make_dnskey(key->key, buf, sizeof(buf), &dnskey)); 1792 1.5 christos result = delrdata(&dnskey, diff, origin, ttl, mctx); 1793 1.1 christos 1794 1.19 christos cleanup: 1795 1.16 christos return result; 1796 1.1 christos } 1797 1.1 christos 1798 1.3 christos static bool 1799 1.1 christos exists(dns_rdataset_t *rdataset, dns_rdata_t *rdata) { 1800 1.1 christos isc_result_t result; 1801 1.1 christos dns_rdataset_t trdataset; 1802 1.1 christos 1803 1.1 christos dns_rdataset_init(&trdataset); 1804 1.1 christos dns_rdataset_clone(rdataset, &trdataset); 1805 1.6 christos for (result = dns_rdataset_first(&trdataset); result == ISC_R_SUCCESS; 1806 1.6 christos result = dns_rdataset_next(&trdataset)) 1807 1.6 christos { 1808 1.1 christos dns_rdata_t current = DNS_RDATA_INIT; 1809 1.1 christos 1810 1.1 christos dns_rdataset_current(&trdataset, ¤t); 1811 1.1 christos if (dns_rdata_compare(rdata, ¤t) == 0) { 1812 1.1 christos dns_rdataset_disassociate(&trdataset); 1813 1.16 christos return true; 1814 1.1 christos } 1815 1.1 christos } 1816 1.1 christos dns_rdataset_disassociate(&trdataset); 1817 1.16 christos return false; 1818 1.16 christos } 1819 1.16 christos 1820 1.16 christos static isc_result_t 1821 1.16 christos add_cds(dns_dnsseckey_t *key, dns_rdata_t *keyrdata, const char *keystr, 1822 1.16 christos dns_rdataset_t *cds, unsigned int digesttype, dns_ttl_t ttl, 1823 1.16 christos dns_diff_t *diff, isc_mem_t *mctx) { 1824 1.16 christos isc_result_t r = ISC_R_SUCCESS; 1825 1.16 christos unsigned char dsbuf[DNS_DS_BUFFERSIZE]; 1826 1.16 christos dns_rdata_t cdsrdata = DNS_RDATA_INIT; 1827 1.16 christos dns_name_t *origin = dst_key_name(key->key); 1828 1.16 christos 1829 1.16 christos r = dns_ds_buildrdata(origin, keyrdata, digesttype, dsbuf, &cdsrdata); 1830 1.16 christos if (r != ISC_R_SUCCESS) { 1831 1.16 christos char algbuf[DNS_DSDIGEST_FORMATSIZE]; 1832 1.16 christos dns_dsdigest_format(digesttype, algbuf, 1833 1.16 christos DNS_DSDIGEST_FORMATSIZE); 1834 1.16 christos isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, 1835 1.16 christos DNS_LOGMODULE_DNSSEC, ISC_LOG_ERROR, 1836 1.16 christos "build rdata CDS (%s) for key %s failed", algbuf, 1837 1.16 christos keystr); 1838 1.16 christos return r; 1839 1.16 christos } 1840 1.16 christos 1841 1.16 christos cdsrdata.type = dns_rdatatype_cds; 1842 1.16 christos if (!dns_rdataset_isassociated(cds) || !exists(cds, &cdsrdata)) { 1843 1.16 christos char algbuf[DNS_DSDIGEST_FORMATSIZE]; 1844 1.16 christos dns_dsdigest_format(digesttype, algbuf, 1845 1.16 christos DNS_DSDIGEST_FORMATSIZE); 1846 1.16 christos isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, 1847 1.16 christos DNS_LOGMODULE_DNSSEC, ISC_LOG_INFO, 1848 1.16 christos "CDS (%s) for key %s is now published", algbuf, 1849 1.16 christos keystr); 1850 1.16 christos r = addrdata(&cdsrdata, diff, origin, ttl, mctx); 1851 1.16 christos } 1852 1.16 christos return r; 1853 1.16 christos } 1854 1.16 christos 1855 1.16 christos static isc_result_t 1856 1.16 christos delete_cds(dns_dnsseckey_t *key, dns_rdata_t *keyrdata, const char *keystr, 1857 1.16 christos dns_rdataset_t *cds, unsigned int digesttype, dns_diff_t *diff, 1858 1.16 christos isc_mem_t *mctx) { 1859 1.16 christos isc_result_t r = ISC_R_SUCCESS; 1860 1.16 christos unsigned char dsbuf[DNS_DS_BUFFERSIZE]; 1861 1.16 christos dns_rdata_t cdsrdata = DNS_RDATA_INIT; 1862 1.16 christos dns_name_t *origin = dst_key_name(key->key); 1863 1.16 christos 1864 1.16 christos r = dns_ds_buildrdata(origin, keyrdata, digesttype, dsbuf, &cdsrdata); 1865 1.16 christos if (r != ISC_R_SUCCESS) { 1866 1.16 christos return r; 1867 1.16 christos } 1868 1.16 christos 1869 1.16 christos cdsrdata.type = dns_rdatatype_cds; 1870 1.16 christos if (exists(cds, &cdsrdata)) { 1871 1.16 christos char algbuf[DNS_DSDIGEST_FORMATSIZE]; 1872 1.16 christos dns_dsdigest_format(digesttype, algbuf, 1873 1.16 christos DNS_DSDIGEST_FORMATSIZE); 1874 1.16 christos isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, 1875 1.16 christos DNS_LOGMODULE_DNSSEC, ISC_LOG_INFO, 1876 1.16 christos "CDS (%s) for key %s is now deleted", algbuf, 1877 1.16 christos keystr); 1878 1.16 christos r = delrdata(&cdsrdata, diff, origin, cds->ttl, mctx); 1879 1.16 christos } 1880 1.16 christos return r; 1881 1.1 christos } 1882 1.1 christos 1883 1.1 christos isc_result_t 1884 1.1 christos dns_dnssec_syncupdate(dns_dnsseckeylist_t *keys, dns_dnsseckeylist_t *rmkeys, 1885 1.1 christos dns_rdataset_t *cds, dns_rdataset_t *cdnskey, 1886 1.16 christos isc_stdtime_t now, dns_kasp_digestlist_t *digests, 1887 1.16 christos bool gencdnskey, dns_ttl_t ttl, dns_diff_t *diff, 1888 1.6 christos isc_mem_t *mctx) { 1889 1.1 christos unsigned char keybuf[DST_KEY_MAXSIZE]; 1890 1.1 christos isc_result_t result; 1891 1.1 christos dns_dnsseckey_t *key; 1892 1.15 christos dns_ttl_t cdsttl = ttl; 1893 1.15 christos dns_ttl_t cdnskeyttl = ttl; 1894 1.15 christos 1895 1.16 christos REQUIRE(digests != NULL); 1896 1.15 christos REQUIRE(keys != NULL); 1897 1.15 christos REQUIRE(rmkeys != NULL); 1898 1.15 christos 1899 1.15 christos if (dns_rdataset_isassociated(cds)) { 1900 1.15 christos cdsttl = cds->ttl; 1901 1.15 christos } 1902 1.15 christos 1903 1.15 christos if (dns_rdataset_isassociated(cdnskey)) { 1904 1.15 christos cdnskeyttl = cdnskey->ttl; 1905 1.15 christos } 1906 1.1 christos 1907 1.6 christos for (key = ISC_LIST_HEAD(*keys); key != NULL; 1908 1.13 christos key = ISC_LIST_NEXT(key, link)) 1909 1.13 christos { 1910 1.1 christos dns_rdata_t cdnskeyrdata = DNS_RDATA_INIT; 1911 1.1 christos dns_name_t *origin = dst_key_name(key->key); 1912 1.1 christos 1913 1.19 christos CHECK(dns_dnssec_make_dnskey(key->key, keybuf, sizeof(keybuf), 1914 1.19 christos &cdnskeyrdata)); 1915 1.1 christos cdnskeyrdata.type = dns_rdatatype_cdnskey; 1916 1.1 christos 1917 1.1 christos if (syncpublish(key->key, now)) { 1918 1.7 christos char keystr[DST_KEY_FORMATSIZE]; 1919 1.7 christos dst_key_format(key->key, keystr, sizeof(keystr)); 1920 1.7 christos 1921 1.16 christos for (dns_kasp_digest_t *alg = ISC_LIST_HEAD(*digests); 1922 1.16 christos alg != NULL; alg = ISC_LIST_NEXT(alg, link)) 1923 1.16 christos { 1924 1.19 christos CHECK(add_cds(key, &cdnskeyrdata, 1925 1.19 christos (const char *)keystr, cds, 1926 1.19 christos alg->digest, cdsttl, diff, mctx)); 1927 1.16 christos } 1928 1.16 christos 1929 1.16 christos if (gencdnskey && 1930 1.16 christos (!dns_rdataset_isassociated(cdnskey) || 1931 1.16 christos !exists(cdnskey, &cdnskeyrdata))) 1932 1.13 christos { 1933 1.15 christos isc_log_write( 1934 1.15 christos dns_lctx, DNS_LOGCATEGORY_GENERAL, 1935 1.15 christos DNS_LOGMODULE_DNSSEC, ISC_LOG_INFO, 1936 1.15 christos "CDNSKEY for key %s is now published", 1937 1.15 christos keystr); 1938 1.5 christos RETERR(addrdata(&cdnskeyrdata, diff, origin, 1939 1.15 christos cdnskeyttl, mctx)); 1940 1.5 christos } 1941 1.1 christos } 1942 1.1 christos 1943 1.7 christos if (syncdelete(key->key, now)) { 1944 1.7 christos char keystr[DST_KEY_FORMATSIZE]; 1945 1.7 christos dst_key_format(key->key, keystr, sizeof(keystr)); 1946 1.7 christos 1947 1.7 christos if (dns_rdataset_isassociated(cds)) { 1948 1.16 christos /* Delete all possible CDS records */ 1949 1.16 christos delete_cds(key, &cdnskeyrdata, 1950 1.16 christos (const char *)keystr, cds, 1951 1.16 christos DNS_DSDIGEST_SHA1, diff, mctx); 1952 1.16 christos delete_cds(key, &cdnskeyrdata, 1953 1.16 christos (const char *)keystr, cds, 1954 1.16 christos DNS_DSDIGEST_SHA256, diff, mctx); 1955 1.16 christos delete_cds(key, &cdnskeyrdata, 1956 1.16 christos (const char *)keystr, cds, 1957 1.16 christos DNS_DSDIGEST_SHA384, diff, mctx); 1958 1.6 christos } 1959 1.1 christos 1960 1.7 christos if (dns_rdataset_isassociated(cdnskey)) { 1961 1.7 christos if (exists(cdnskey, &cdnskeyrdata)) { 1962 1.7 christos isc_log_write(dns_lctx, 1963 1.7 christos DNS_LOGCATEGORY_GENERAL, 1964 1.7 christos DNS_LOGMODULE_DNSSEC, 1965 1.7 christos ISC_LOG_INFO, 1966 1.7 christos "CDNSKEY for key %s is " 1967 1.7 christos "now deleted", 1968 1.7 christos keystr); 1969 1.7 christos RETERR(delrdata(&cdnskeyrdata, diff, 1970 1.7 christos origin, cdnskey->ttl, 1971 1.7 christos mctx)); 1972 1.7 christos } 1973 1.6 christos } 1974 1.1 christos } 1975 1.1 christos } 1976 1.1 christos 1977 1.1 christos if (!dns_rdataset_isassociated(cds) && 1978 1.13 christos !dns_rdataset_isassociated(cdnskey)) 1979 1.13 christos { 1980 1.16 christos return ISC_R_SUCCESS; 1981 1.6 christos } 1982 1.1 christos 1983 1.1 christos /* 1984 1.6 christos * Unconditionally remove CDS/DNSKEY records for removed keys. 1985 1.1 christos */ 1986 1.6 christos for (key = ISC_LIST_HEAD(*rmkeys); key != NULL; 1987 1.13 christos key = ISC_LIST_NEXT(key, link)) 1988 1.13 christos { 1989 1.1 christos dns_rdata_t cdnskeyrdata = DNS_RDATA_INIT; 1990 1.1 christos dns_name_t *origin = dst_key_name(key->key); 1991 1.1 christos 1992 1.7 christos char keystr[DST_KEY_FORMATSIZE]; 1993 1.7 christos dst_key_format(key->key, keystr, sizeof(keystr)); 1994 1.7 christos 1995 1.19 christos CHECK(dns_dnssec_make_dnskey(key->key, keybuf, sizeof(keybuf), 1996 1.19 christos &cdnskeyrdata)); 1997 1.1 christos 1998 1.1 christos if (dns_rdataset_isassociated(cds)) { 1999 1.16 christos delete_cds(key, &cdnskeyrdata, (const char *)keystr, 2000 1.16 christos cds, DNS_DSDIGEST_SHA1, diff, mctx); 2001 1.16 christos delete_cds(key, &cdnskeyrdata, (const char *)keystr, 2002 1.16 christos cds, DNS_DSDIGEST_SHA256, diff, mctx); 2003 1.16 christos delete_cds(key, &cdnskeyrdata, (const char *)keystr, 2004 1.16 christos cds, DNS_DSDIGEST_SHA384, diff, mctx); 2005 1.1 christos } 2006 1.1 christos 2007 1.1 christos if (dns_rdataset_isassociated(cdnskey)) { 2008 1.6 christos if (exists(cdnskey, &cdnskeyrdata)) { 2009 1.7 christos isc_log_write( 2010 1.7 christos dns_lctx, DNS_LOGCATEGORY_GENERAL, 2011 1.7 christos DNS_LOGMODULE_DNSSEC, ISC_LOG_INFO, 2012 1.7 christos "CDNSKEY for key %s is now deleted", 2013 1.7 christos keystr); 2014 1.1 christos RETERR(delrdata(&cdnskeyrdata, diff, origin, 2015 1.1 christos cdnskey->ttl, mctx)); 2016 1.6 christos } 2017 1.1 christos } 2018 1.1 christos } 2019 1.1 christos 2020 1.1 christos result = ISC_R_SUCCESS; 2021 1.1 christos 2022 1.19 christos cleanup: 2023 1.16 christos return result; 2024 1.1 christos } 2025 1.1 christos 2026 1.7 christos isc_result_t 2027 1.7 christos dns_dnssec_syncdelete(dns_rdataset_t *cds, dns_rdataset_t *cdnskey, 2028 1.7 christos dns_name_t *origin, dns_rdataclass_t zclass, 2029 1.7 christos dns_ttl_t ttl, dns_diff_t *diff, isc_mem_t *mctx, 2030 1.12 christos bool expect_cds_delete, bool expect_cdnskey_delete) { 2031 1.7 christos unsigned char dsbuf[5] = { 0, 0, 0, 0, 0 }; /* CDS DELETE rdata */ 2032 1.7 christos unsigned char keybuf[5] = { 0, 0, 3, 0, 0 }; /* CDNSKEY DELETE rdata */ 2033 1.7 christos char namebuf[DNS_NAME_FORMATSIZE]; 2034 1.7 christos dns_rdata_t cds_delete = DNS_RDATA_INIT; 2035 1.7 christos dns_rdata_t cdnskey_delete = DNS_RDATA_INIT; 2036 1.7 christos isc_region_t r; 2037 1.7 christos 2038 1.7 christos r.base = keybuf; 2039 1.7 christos r.length = sizeof(keybuf); 2040 1.7 christos dns_rdata_fromregion(&cdnskey_delete, zclass, dns_rdatatype_cdnskey, 2041 1.7 christos &r); 2042 1.7 christos 2043 1.7 christos r.base = dsbuf; 2044 1.7 christos r.length = sizeof(dsbuf); 2045 1.7 christos dns_rdata_fromregion(&cds_delete, zclass, dns_rdatatype_cds, &r); 2046 1.7 christos 2047 1.7 christos dns_name_format(origin, namebuf, sizeof(namebuf)); 2048 1.7 christos 2049 1.12 christos if (expect_cds_delete) { 2050 1.12 christos if (!dns_rdataset_isassociated(cds) || 2051 1.13 christos !exists(cds, &cds_delete)) 2052 1.13 christos { 2053 1.7 christos isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, 2054 1.7 christos DNS_LOGMODULE_DNSSEC, ISC_LOG_INFO, 2055 1.12 christos "CDS (DELETE) for zone %s is now " 2056 1.7 christos "published", 2057 1.7 christos namebuf); 2058 1.12 christos RETERR(addrdata(&cds_delete, diff, origin, ttl, mctx)); 2059 1.12 christos } 2060 1.12 christos } else { 2061 1.12 christos if (dns_rdataset_isassociated(cds) && exists(cds, &cds_delete)) 2062 1.12 christos { 2063 1.12 christos isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, 2064 1.12 christos DNS_LOGMODULE_DNSSEC, ISC_LOG_INFO, 2065 1.12 christos "CDS (DELETE) for zone %s is now " 2066 1.12 christos "deleted", 2067 1.12 christos namebuf); 2068 1.12 christos RETERR(delrdata(&cds_delete, diff, origin, cds->ttl, 2069 1.7 christos mctx)); 2070 1.7 christos } 2071 1.12 christos } 2072 1.7 christos 2073 1.12 christos if (expect_cdnskey_delete) { 2074 1.12 christos if (!dns_rdataset_isassociated(cdnskey) || 2075 1.13 christos !exists(cdnskey, &cdnskey_delete)) 2076 1.13 christos { 2077 1.7 christos isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, 2078 1.7 christos DNS_LOGMODULE_DNSSEC, ISC_LOG_INFO, 2079 1.12 christos "CDNSKEY (DELETE) for zone %s is now " 2080 1.7 christos "published", 2081 1.7 christos namebuf); 2082 1.12 christos RETERR(addrdata(&cdnskey_delete, diff, origin, ttl, 2083 1.12 christos mctx)); 2084 1.7 christos } 2085 1.7 christos } else { 2086 1.7 christos if (dns_rdataset_isassociated(cdnskey) && 2087 1.13 christos exists(cdnskey, &cdnskey_delete)) 2088 1.13 christos { 2089 1.7 christos isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, 2090 1.7 christos DNS_LOGMODULE_DNSSEC, ISC_LOG_INFO, 2091 1.7 christos "CDNSKEY (DELETE) for zone %s is now " 2092 1.7 christos "deleted", 2093 1.7 christos namebuf); 2094 1.7 christos RETERR(delrdata(&cdnskey_delete, diff, origin, 2095 1.7 christos cdnskey->ttl, mctx)); 2096 1.7 christos } 2097 1.7 christos } 2098 1.7 christos 2099 1.19 christos return ISC_R_SUCCESS; 2100 1.7 christos } 2101 1.7 christos 2102 1.1 christos /* 2103 1.1 christos * Update 'keys' with information from 'newkeys'. 2104 1.1 christos * 2105 1.1 christos * If 'removed' is not NULL, any keys that are being removed from 2106 1.1 christos * the zone will be added to the list for post-removal processing. 2107 1.1 christos */ 2108 1.1 christos isc_result_t 2109 1.1 christos dns_dnssec_updatekeys(dns_dnsseckeylist_t *keys, dns_dnsseckeylist_t *newkeys, 2110 1.1 christos dns_dnsseckeylist_t *removed, const dns_name_t *origin, 2111 1.6 christos dns_ttl_t hint_ttl, dns_diff_t *diff, isc_mem_t *mctx, 2112 1.14 christos void (*report)(const char *, ...) 2113 1.14 christos ISC_FORMAT_PRINTF(1, 2)) { 2114 1.1 christos isc_result_t result; 2115 1.1 christos dns_dnsseckey_t *key, *key1, *key2, *next; 2116 1.3 christos bool found_ttl = false; 2117 1.1 christos dns_ttl_t ttl = hint_ttl; 2118 1.1 christos 2119 1.1 christos /* 2120 1.1 christos * First, look through the existing key list to find keys 2121 1.1 christos * supplied from the command line which are not in the zone. 2122 1.1 christos * Update the zone to include them. 2123 1.1 christos * 2124 1.1 christos * Also, if there are keys published in the zone already, 2125 1.1 christos * use their TTL for all subsequent published keys. 2126 1.1 christos */ 2127 1.6 christos for (key = ISC_LIST_HEAD(*keys); key != NULL; 2128 1.13 christos key = ISC_LIST_NEXT(key, link)) 2129 1.13 christos { 2130 1.1 christos if (key->source == dns_keysource_user && 2131 1.4 christos (key->hint_publish || key->force_publish)) 2132 1.4 christos { 2133 1.19 christos CHECK(publish_key(diff, key, origin, ttl, mctx, 2134 1.19 christos report)); 2135 1.1 christos } 2136 1.1 christos if (key->source == dns_keysource_zoneapex) { 2137 1.1 christos ttl = dst_key_getttl(key->key); 2138 1.3 christos found_ttl = true; 2139 1.1 christos } 2140 1.1 christos } 2141 1.1 christos 2142 1.1 christos /* 2143 1.1 christos * If there were no existing keys, use the smallest nonzero 2144 1.1 christos * TTL of the keys found in the repository. 2145 1.1 christos */ 2146 1.1 christos if (!found_ttl && !ISC_LIST_EMPTY(*newkeys)) { 2147 1.1 christos dns_ttl_t shortest = 0; 2148 1.1 christos 2149 1.6 christos for (key = ISC_LIST_HEAD(*newkeys); key != NULL; 2150 1.13 christos key = ISC_LIST_NEXT(key, link)) 2151 1.13 christos { 2152 1.1 christos dns_ttl_t thisttl = dst_key_getttl(key->key); 2153 1.1 christos if (thisttl != 0 && 2154 1.13 christos (shortest == 0 || thisttl < shortest)) 2155 1.13 christos { 2156 1.1 christos shortest = thisttl; 2157 1.4 christos } 2158 1.1 christos } 2159 1.1 christos 2160 1.4 christos if (shortest != 0) { 2161 1.1 christos ttl = shortest; 2162 1.4 christos } 2163 1.1 christos } 2164 1.1 christos 2165 1.1 christos /* 2166 1.1 christos * Second, scan the list of newly found keys looking for matches 2167 1.1 christos * with known keys, and update accordingly. 2168 1.1 christos */ 2169 1.1 christos for (key1 = ISC_LIST_HEAD(*newkeys); key1 != NULL; key1 = next) { 2170 1.3 christos bool key_revoked = false; 2171 1.4 christos char keystr1[DST_KEY_FORMATSIZE]; 2172 1.4 christos char keystr2[DST_KEY_FORMATSIZE]; 2173 1.1 christos 2174 1.1 christos next = ISC_LIST_NEXT(key1, link); 2175 1.1 christos 2176 1.6 christos for (key2 = ISC_LIST_HEAD(*keys); key2 != NULL; 2177 1.4 christos key2 = ISC_LIST_NEXT(key2, link)) 2178 1.4 christos { 2179 1.1 christos int f1 = dst_key_flags(key1->key); 2180 1.1 christos int f2 = dst_key_flags(key2->key); 2181 1.1 christos int nr1 = f1 & ~DNS_KEYFLAG_REVOKE; 2182 1.1 christos int nr2 = f2 & ~DNS_KEYFLAG_REVOKE; 2183 1.1 christos if (nr1 == nr2 && 2184 1.1 christos dst_key_alg(key1->key) == dst_key_alg(key2->key) && 2185 1.4 christos dst_key_pubcompare(key1->key, key2->key, true)) 2186 1.4 christos { 2187 1.1 christos int r1, r2; 2188 1.1 christos r1 = dst_key_flags(key1->key) & 2189 1.6 christos DNS_KEYFLAG_REVOKE; 2190 1.1 christos r2 = dst_key_flags(key2->key) & 2191 1.6 christos DNS_KEYFLAG_REVOKE; 2192 1.3 christos key_revoked = (r1 != r2); 2193 1.1 christos break; 2194 1.1 christos } 2195 1.1 christos } 2196 1.1 christos 2197 1.6 christos /* Printable version of key1 (the newly acquired key) */ 2198 1.4 christos dst_key_format(key1->key, keystr1, sizeof(keystr1)); 2199 1.4 christos 2200 1.1 christos /* No match found in keys; add the new key. */ 2201 1.1 christos if (key2 == NULL) { 2202 1.1 christos ISC_LIST_UNLINK(*newkeys, key1, link); 2203 1.1 christos ISC_LIST_APPEND(*keys, key1, link); 2204 1.1 christos 2205 1.1 christos if (key1->source != dns_keysource_zoneapex && 2206 1.4 christos (key1->hint_publish || key1->force_publish)) 2207 1.4 christos { 2208 1.19 christos CHECK(publish_key(diff, key1, origin, ttl, mctx, 2209 1.19 christos report)); 2210 1.6 christos isc_log_write( 2211 1.6 christos dns_lctx, DNS_LOGCATEGORY_DNSSEC, 2212 1.6 christos DNS_LOGMODULE_DNSSEC, ISC_LOG_INFO, 2213 1.6 christos "DNSKEY %s (%s) is now published", 2214 1.6 christos keystr1, 2215 1.6 christos key1->ksk ? (key1->zsk ? "CSK" : "KSK") 2216 1.6 christos : "ZSK"); 2217 1.4 christos if (key1->hint_sign || key1->force_sign) { 2218 1.3 christos key1->first_sign = true; 2219 1.6 christos isc_log_write( 2220 1.6 christos dns_lctx, 2221 1.6 christos DNS_LOGCATEGORY_DNSSEC, 2222 1.6 christos DNS_LOGMODULE_DNSSEC, 2223 1.6 christos ISC_LOG_INFO, 2224 1.6 christos "DNSKEY %s (%s) is now " 2225 1.6 christos "active", 2226 1.6 christos keystr1, 2227 1.6 christos key1->ksk ? (key1->zsk ? "CSK" 2228 1.6 christos : "KSK") 2229 1.6 christos : "ZSK"); 2230 1.4 christos } 2231 1.1 christos } 2232 1.1 christos 2233 1.1 christos continue; 2234 1.1 christos } 2235 1.1 christos 2236 1.4 christos /* Printable version of key2 (the old key, if any) */ 2237 1.4 christos dst_key_format(key2->key, keystr2, sizeof(keystr2)); 2238 1.4 christos 2239 1.6 christos /* Copy key metadata. */ 2240 1.6 christos dst_key_copy_metadata(key2->key, key1->key); 2241 1.6 christos 2242 1.1 christos /* Match found: remove or update it as needed */ 2243 1.1 christos if (key1->hint_remove) { 2244 1.19 christos CHECK(remove_key(diff, key2, origin, ttl, mctx, 2245 1.19 christos "expired", report)); 2246 1.1 christos ISC_LIST_UNLINK(*keys, key2, link); 2247 1.4 christos 2248 1.4 christos if (removed != NULL) { 2249 1.1 christos ISC_LIST_APPEND(*removed, key2, link); 2250 1.6 christos isc_log_write( 2251 1.6 christos dns_lctx, DNS_LOGCATEGORY_DNSSEC, 2252 1.6 christos DNS_LOGMODULE_DNSSEC, ISC_LOG_INFO, 2253 1.6 christos "DNSKEY %s (%s) is now deleted", 2254 1.6 christos keystr2, 2255 1.6 christos key2->ksk ? (key2->zsk ? "CSK" : "KSK") 2256 1.6 christos : "ZSK"); 2257 1.4 christos } else { 2258 1.1 christos dns_dnsseckey_destroy(mctx, &key2); 2259 1.4 christos } 2260 1.1 christos } else if (key_revoked && 2261 1.4 christos (dst_key_flags(key1->key) & DNS_KEYFLAG_REVOKE) != 0) 2262 1.4 christos { 2263 1.1 christos /* 2264 1.1 christos * A previously valid key has been revoked. 2265 1.1 christos * We need to remove the old version and pull 2266 1.1 christos * in the new one. 2267 1.1 christos */ 2268 1.19 christos CHECK(remove_key(diff, key2, origin, ttl, mctx, 2269 1.19 christos "revoked", report)); 2270 1.1 christos ISC_LIST_UNLINK(*keys, key2, link); 2271 1.4 christos if (removed != NULL) { 2272 1.1 christos ISC_LIST_APPEND(*removed, key2, link); 2273 1.6 christos isc_log_write( 2274 1.6 christos dns_lctx, DNS_LOGCATEGORY_DNSSEC, 2275 1.6 christos DNS_LOGMODULE_DNSSEC, ISC_LOG_INFO, 2276 1.6 christos "DNSKEY %s (%s) is now revoked; " 2277 1.6 christos "new ID is %05d", 2278 1.6 christos keystr2, 2279 1.6 christos key2->ksk ? (key2->zsk ? "CSK" : "KSK") 2280 1.6 christos : "ZSK", 2281 1.6 christos dst_key_id(key1->key)); 2282 1.4 christos } else { 2283 1.1 christos dns_dnsseckey_destroy(mctx, &key2); 2284 1.4 christos } 2285 1.1 christos 2286 1.19 christos CHECK(publish_key(diff, key1, origin, ttl, mctx, 2287 1.19 christos report)); 2288 1.1 christos ISC_LIST_UNLINK(*newkeys, key1, link); 2289 1.1 christos ISC_LIST_APPEND(*keys, key1, link); 2290 1.1 christos 2291 1.1 christos /* 2292 1.1 christos * XXX: The revoke flag is only defined for trust 2293 1.1 christos * anchors. Setting the flag on a non-KSK is legal, 2294 1.1 christos * but not defined in any RFC. It seems reasonable 2295 1.1 christos * to treat it the same as a KSK: keep it in the 2296 1.1 christos * zone, sign the DNSKEY set with it, but not 2297 1.1 christos * sign other records with it. 2298 1.1 christos */ 2299 1.3 christos key1->ksk = true; 2300 1.1 christos continue; 2301 1.1 christos } else { 2302 1.1 christos if (!key2->is_active && 2303 1.13 christos (key1->hint_sign || key1->force_sign)) 2304 1.13 christos { 2305 1.3 christos key2->first_sign = true; 2306 1.6 christos isc_log_write( 2307 1.6 christos dns_lctx, DNS_LOGCATEGORY_DNSSEC, 2308 1.6 christos DNS_LOGMODULE_DNSSEC, ISC_LOG_INFO, 2309 1.6 christos "DNSKEY %s (%s) is now active", keystr1, 2310 1.6 christos key1->ksk ? (key1->zsk ? "CSK" : "KSK") 2311 1.6 christos : "ZSK"); 2312 1.6 christos } else if (key2->is_active && !key1->hint_sign && 2313 1.13 christos !key1->force_sign) 2314 1.13 christos { 2315 1.6 christos isc_log_write( 2316 1.6 christos dns_lctx, DNS_LOGCATEGORY_DNSSEC, 2317 1.6 christos DNS_LOGMODULE_DNSSEC, ISC_LOG_INFO, 2318 1.6 christos "DNSKEY %s (%s) is now inactive", 2319 1.6 christos keystr1, 2320 1.6 christos key1->ksk ? (key1->zsk ? "CSK" : "KSK") 2321 1.6 christos : "ZSK"); 2322 1.4 christos } 2323 1.4 christos 2324 1.1 christos key2->hint_sign = key1->hint_sign; 2325 1.1 christos key2->hint_publish = key1->hint_publish; 2326 1.1 christos } 2327 1.1 christos } 2328 1.1 christos 2329 1.1 christos /* Free any leftover keys in newkeys */ 2330 1.1 christos while (!ISC_LIST_EMPTY(*newkeys)) { 2331 1.1 christos key1 = ISC_LIST_HEAD(*newkeys); 2332 1.1 christos ISC_LIST_UNLINK(*newkeys, key1, link); 2333 1.1 christos dns_dnsseckey_destroy(mctx, &key1); 2334 1.1 christos } 2335 1.1 christos 2336 1.1 christos result = ISC_R_SUCCESS; 2337 1.1 christos 2338 1.19 christos cleanup: 2339 1.16 christos return result; 2340 1.6 christos } 2341 1.6 christos 2342 1.6 christos isc_result_t 2343 1.6 christos dns_dnssec_matchdskey(dns_name_t *name, dns_rdata_t *dsrdata, 2344 1.6 christos dns_rdataset_t *keyset, dns_rdata_t *keyrdata) { 2345 1.6 christos isc_result_t result; 2346 1.6 christos unsigned char buf[DNS_DS_BUFFERSIZE]; 2347 1.6 christos dns_keytag_t keytag; 2348 1.6 christos dns_rdata_dnskey_t key; 2349 1.6 christos dns_rdata_ds_t ds; 2350 1.6 christos isc_region_t r; 2351 1.6 christos 2352 1.6 christos result = dns_rdata_tostruct(dsrdata, &ds, NULL); 2353 1.6 christos RUNTIME_CHECK(result == ISC_R_SUCCESS); 2354 1.6 christos 2355 1.6 christos for (result = dns_rdataset_first(keyset); result == ISC_R_SUCCESS; 2356 1.6 christos result = dns_rdataset_next(keyset)) 2357 1.6 christos { 2358 1.6 christos dns_rdata_t newdsrdata = DNS_RDATA_INIT; 2359 1.6 christos 2360 1.6 christos dns_rdata_reset(keyrdata); 2361 1.6 christos dns_rdataset_current(keyset, keyrdata); 2362 1.6 christos 2363 1.6 christos result = dns_rdata_tostruct(keyrdata, &key, NULL); 2364 1.6 christos RUNTIME_CHECK(result == ISC_R_SUCCESS); 2365 1.6 christos 2366 1.6 christos dns_rdata_toregion(keyrdata, &r); 2367 1.6 christos keytag = dst_region_computeid(&r); 2368 1.6 christos 2369 1.6 christos if (ds.key_tag != keytag || ds.algorithm != key.algorithm) { 2370 1.6 christos continue; 2371 1.6 christos } 2372 1.6 christos 2373 1.6 christos result = dns_ds_buildrdata(name, keyrdata, ds.digest_type, buf, 2374 1.6 christos &newdsrdata); 2375 1.6 christos if (result != ISC_R_SUCCESS) { 2376 1.6 christos continue; 2377 1.6 christos } 2378 1.6 christos 2379 1.6 christos if (dns_rdata_compare(dsrdata, &newdsrdata) == 0) { 2380 1.6 christos break; 2381 1.6 christos } 2382 1.6 christos } 2383 1.6 christos if (result == ISC_R_NOMORE) { 2384 1.6 christos result = ISC_R_NOTFOUND; 2385 1.6 christos } 2386 1.6 christos 2387 1.16 christos return result; 2388 1.1 christos } 2389