1 /* $NetBSD: kasp.c,v 1.8 2025/01/26 16:25:23 christos Exp $ */ 2 3 /* 4 * Copyright (C) Internet Systems Consortium, Inc. ("ISC") 5 * 6 * SPDX-License-Identifier: MPL-2.0 7 * 8 * This Source Code Form is subject to the terms of the Mozilla Public 9 * License, v. 2.0. If a copy of the MPL was not distributed with this 10 * file, you can obtain one at https://mozilla.org/MPL/2.0/. 11 * 12 * See the COPYRIGHT file distributed with this work for additional 13 * information regarding copyright ownership. 14 */ 15 16 /*! \file */ 17 18 #include <string.h> 19 20 #include <isc/assertions.h> 21 #include <isc/buffer.h> 22 #include <isc/file.h> 23 #include <isc/hex.h> 24 #include <isc/log.h> 25 #include <isc/mem.h> 26 #include <isc/util.h> 27 28 #include <dns/kasp.h> 29 #include <dns/keyvalues.h> 30 #include <dns/log.h> 31 32 #include <dst/dst.h> 33 34 /* Default TTLsig (maximum zone ttl) */ 35 #define DEFAULT_TTLSIG 604800 /* one week */ 36 37 isc_result_t 38 dns_kasp_create(isc_mem_t *mctx, const char *name, dns_kasp_t **kaspp) { 39 dns_kasp_t *kasp; 40 dns_kasp_t k = { 41 .magic = DNS_KASP_MAGIC, 42 .digests = ISC_LIST_INITIALIZER, 43 .keys = ISC_LIST_INITIALIZER, 44 .link = ISC_LINK_INITIALIZER, 45 }; 46 47 REQUIRE(name != NULL); 48 REQUIRE(kaspp != NULL && *kaspp == NULL); 49 50 kasp = isc_mem_get(mctx, sizeof(*kasp)); 51 *kasp = k; 52 53 kasp->mctx = NULL; 54 isc_mem_attach(mctx, &kasp->mctx); 55 kasp->name = isc_mem_strdup(mctx, name); 56 isc_mutex_init(&kasp->lock); 57 isc_refcount_init(&kasp->references, 1); 58 59 *kaspp = kasp; 60 return ISC_R_SUCCESS; 61 } 62 63 void 64 dns_kasp_attach(dns_kasp_t *source, dns_kasp_t **targetp) { 65 REQUIRE(DNS_KASP_VALID(source)); 66 REQUIRE(targetp != NULL && *targetp == NULL); 67 68 isc_refcount_increment(&source->references); 69 *targetp = source; 70 } 71 72 static void 73 destroy(dns_kasp_t *kasp) { 74 dns_kasp_key_t *key, *key_next; 75 dns_kasp_digest_t *digest, *digest_next; 76 77 REQUIRE(!ISC_LINK_LINKED(kasp, link)); 78 79 for (key = ISC_LIST_HEAD(kasp->keys); key != NULL; key = key_next) { 80 key_next = ISC_LIST_NEXT(key, link); 81 ISC_LIST_UNLINK(kasp->keys, key, link); 82 dns_kasp_key_destroy(key); 83 } 84 INSIST(ISC_LIST_EMPTY(kasp->keys)); 85 86 for (digest = ISC_LIST_HEAD(kasp->digests); digest != NULL; 87 digest = digest_next) 88 { 89 digest_next = ISC_LIST_NEXT(digest, link); 90 ISC_LIST_UNLINK(kasp->digests, digest, link); 91 isc_mem_put(kasp->mctx, digest, sizeof(*digest)); 92 } 93 INSIST(ISC_LIST_EMPTY(kasp->digests)); 94 95 isc_mutex_destroy(&kasp->lock); 96 isc_mem_free(kasp->mctx, kasp->name); 97 isc_mem_putanddetach(&kasp->mctx, kasp, sizeof(*kasp)); 98 } 99 100 void 101 dns_kasp_detach(dns_kasp_t **kaspp) { 102 REQUIRE(kaspp != NULL && DNS_KASP_VALID(*kaspp)); 103 104 dns_kasp_t *kasp = *kaspp; 105 *kaspp = NULL; 106 107 if (isc_refcount_decrement(&kasp->references) == 1) { 108 destroy(kasp); 109 } 110 } 111 112 const char * 113 dns_kasp_getname(dns_kasp_t *kasp) { 114 REQUIRE(DNS_KASP_VALID(kasp)); 115 116 return kasp->name; 117 } 118 119 void 120 dns_kasp_freeze(dns_kasp_t *kasp) { 121 REQUIRE(DNS_KASP_VALID(kasp)); 122 REQUIRE(!kasp->frozen); 123 124 kasp->frozen = true; 125 } 126 127 void 128 dns_kasp_thaw(dns_kasp_t *kasp) { 129 REQUIRE(DNS_KASP_VALID(kasp)); 130 REQUIRE(kasp->frozen); 131 132 kasp->frozen = false; 133 } 134 135 uint32_t 136 dns_kasp_signdelay(dns_kasp_t *kasp) { 137 REQUIRE(DNS_KASP_VALID(kasp)); 138 REQUIRE(kasp->frozen); 139 140 return kasp->signatures_validity - kasp->signatures_refresh; 141 } 142 143 uint32_t 144 dns_kasp_sigjitter(dns_kasp_t *kasp) { 145 REQUIRE(DNS_KASP_VALID(kasp)); 146 REQUIRE(kasp->frozen); 147 148 return kasp->signatures_jitter; 149 } 150 151 void 152 dns_kasp_setsigjitter(dns_kasp_t *kasp, uint32_t value) { 153 REQUIRE(DNS_KASP_VALID(kasp)); 154 REQUIRE(!kasp->frozen); 155 156 kasp->signatures_jitter = value; 157 } 158 159 uint32_t 160 dns_kasp_sigrefresh(dns_kasp_t *kasp) { 161 REQUIRE(DNS_KASP_VALID(kasp)); 162 REQUIRE(kasp->frozen); 163 164 return kasp->signatures_refresh; 165 } 166 167 void 168 dns_kasp_setsigrefresh(dns_kasp_t *kasp, uint32_t value) { 169 REQUIRE(DNS_KASP_VALID(kasp)); 170 REQUIRE(!kasp->frozen); 171 172 kasp->signatures_refresh = value; 173 } 174 175 uint32_t 176 dns_kasp_sigvalidity(dns_kasp_t *kasp) { 177 REQUIRE(DNS_KASP_VALID(kasp)); 178 REQUIRE(kasp->frozen); 179 180 return kasp->signatures_validity; 181 } 182 183 void 184 dns_kasp_setsigvalidity(dns_kasp_t *kasp, uint32_t value) { 185 REQUIRE(DNS_KASP_VALID(kasp)); 186 REQUIRE(!kasp->frozen); 187 188 kasp->signatures_validity = value; 189 } 190 191 uint32_t 192 dns_kasp_sigvalidity_dnskey(dns_kasp_t *kasp) { 193 REQUIRE(DNS_KASP_VALID(kasp)); 194 REQUIRE(kasp->frozen); 195 196 return kasp->signatures_validity_dnskey; 197 } 198 199 void 200 dns_kasp_setsigvalidity_dnskey(dns_kasp_t *kasp, uint32_t value) { 201 REQUIRE(DNS_KASP_VALID(kasp)); 202 REQUIRE(!kasp->frozen); 203 204 kasp->signatures_validity_dnskey = value; 205 } 206 207 dns_ttl_t 208 dns_kasp_dnskeyttl(dns_kasp_t *kasp) { 209 REQUIRE(DNS_KASP_VALID(kasp)); 210 REQUIRE(kasp->frozen); 211 212 return kasp->dnskey_ttl; 213 } 214 215 void 216 dns_kasp_setdnskeyttl(dns_kasp_t *kasp, dns_ttl_t ttl) { 217 REQUIRE(DNS_KASP_VALID(kasp)); 218 REQUIRE(!kasp->frozen); 219 220 kasp->dnskey_ttl = ttl; 221 } 222 223 uint32_t 224 dns_kasp_purgekeys(dns_kasp_t *kasp) { 225 REQUIRE(DNS_KASP_VALID(kasp)); 226 REQUIRE(kasp->frozen); 227 228 return kasp->purge_keys; 229 } 230 231 void 232 dns_kasp_setpurgekeys(dns_kasp_t *kasp, uint32_t value) { 233 REQUIRE(DNS_KASP_VALID(kasp)); 234 REQUIRE(!kasp->frozen); 235 236 kasp->purge_keys = value; 237 } 238 239 uint32_t 240 dns_kasp_publishsafety(dns_kasp_t *kasp) { 241 REQUIRE(DNS_KASP_VALID(kasp)); 242 REQUIRE(kasp->frozen); 243 244 return kasp->publish_safety; 245 } 246 247 void 248 dns_kasp_setpublishsafety(dns_kasp_t *kasp, uint32_t value) { 249 REQUIRE(DNS_KASP_VALID(kasp)); 250 REQUIRE(!kasp->frozen); 251 252 kasp->publish_safety = value; 253 } 254 255 uint32_t 256 dns_kasp_retiresafety(dns_kasp_t *kasp) { 257 REQUIRE(DNS_KASP_VALID(kasp)); 258 REQUIRE(kasp->frozen); 259 260 return kasp->retire_safety; 261 } 262 263 void 264 dns_kasp_setretiresafety(dns_kasp_t *kasp, uint32_t value) { 265 REQUIRE(DNS_KASP_VALID(kasp)); 266 REQUIRE(!kasp->frozen); 267 268 kasp->retire_safety = value; 269 } 270 271 bool 272 dns_kasp_inlinesigning(dns_kasp_t *kasp) { 273 REQUIRE(DNS_KASP_VALID(kasp)); 274 REQUIRE(kasp->frozen); 275 276 return kasp->inline_signing; 277 } 278 279 void 280 dns_kasp_setinlinesigning(dns_kasp_t *kasp, bool value) { 281 REQUIRE(DNS_KASP_VALID(kasp)); 282 REQUIRE(!kasp->frozen); 283 284 kasp->inline_signing = value; 285 } 286 287 dns_ttl_t 288 dns_kasp_zonemaxttl(dns_kasp_t *kasp, bool fallback) { 289 REQUIRE(DNS_KASP_VALID(kasp)); 290 REQUIRE(kasp->frozen); 291 292 if (kasp->zone_max_ttl == 0 && fallback) { 293 return DEFAULT_TTLSIG; 294 } 295 return kasp->zone_max_ttl; 296 } 297 298 void 299 dns_kasp_setzonemaxttl(dns_kasp_t *kasp, dns_ttl_t ttl) { 300 REQUIRE(DNS_KASP_VALID(kasp)); 301 REQUIRE(!kasp->frozen); 302 303 kasp->zone_max_ttl = ttl; 304 } 305 306 uint32_t 307 dns_kasp_zonepropagationdelay(dns_kasp_t *kasp) { 308 REQUIRE(DNS_KASP_VALID(kasp)); 309 REQUIRE(kasp->frozen); 310 311 return kasp->zone_propagation_delay; 312 } 313 314 void 315 dns_kasp_setzonepropagationdelay(dns_kasp_t *kasp, uint32_t value) { 316 REQUIRE(DNS_KASP_VALID(kasp)); 317 REQUIRE(!kasp->frozen); 318 319 kasp->zone_propagation_delay = value; 320 } 321 322 dns_ttl_t 323 dns_kasp_dsttl(dns_kasp_t *kasp) { 324 REQUIRE(DNS_KASP_VALID(kasp)); 325 REQUIRE(kasp->frozen); 326 327 return kasp->parent_ds_ttl; 328 } 329 330 void 331 dns_kasp_setdsttl(dns_kasp_t *kasp, dns_ttl_t ttl) { 332 REQUIRE(DNS_KASP_VALID(kasp)); 333 REQUIRE(!kasp->frozen); 334 335 kasp->parent_ds_ttl = ttl; 336 } 337 338 uint32_t 339 dns_kasp_parentpropagationdelay(dns_kasp_t *kasp) { 340 REQUIRE(DNS_KASP_VALID(kasp)); 341 REQUIRE(kasp->frozen); 342 343 return kasp->parent_propagation_delay; 344 } 345 346 void 347 dns_kasp_setparentpropagationdelay(dns_kasp_t *kasp, uint32_t value) { 348 REQUIRE(DNS_KASP_VALID(kasp)); 349 REQUIRE(!kasp->frozen); 350 351 kasp->parent_propagation_delay = value; 352 } 353 354 isc_result_t 355 dns_kasplist_find(dns_kasplist_t *list, const char *name, dns_kasp_t **kaspp) { 356 dns_kasp_t *kasp = NULL; 357 358 REQUIRE(kaspp != NULL && *kaspp == NULL); 359 360 if (list == NULL) { 361 return ISC_R_NOTFOUND; 362 } 363 364 for (kasp = ISC_LIST_HEAD(*list); kasp != NULL; 365 kasp = ISC_LIST_NEXT(kasp, link)) 366 { 367 if (strcmp(kasp->name, name) == 0) { 368 break; 369 } 370 } 371 372 if (kasp == NULL) { 373 return ISC_R_NOTFOUND; 374 } 375 376 dns_kasp_attach(kasp, kaspp); 377 return ISC_R_SUCCESS; 378 } 379 380 dns_kasp_keylist_t 381 dns_kasp_keys(dns_kasp_t *kasp) { 382 REQUIRE(DNS_KASP_VALID(kasp)); 383 REQUIRE(kasp->frozen); 384 385 return kasp->keys; 386 } 387 388 bool 389 dns_kasp_keylist_empty(dns_kasp_t *kasp) { 390 REQUIRE(DNS_KASP_VALID(kasp)); 391 392 return ISC_LIST_EMPTY(kasp->keys); 393 } 394 395 void 396 dns_kasp_addkey(dns_kasp_t *kasp, dns_kasp_key_t *key) { 397 REQUIRE(DNS_KASP_VALID(kasp)); 398 REQUIRE(!kasp->frozen); 399 REQUIRE(key != NULL); 400 401 ISC_LIST_APPEND(kasp->keys, key, link); 402 } 403 404 isc_result_t 405 dns_kasp_key_create(dns_kasp_t *kasp, dns_kasp_key_t **keyp) { 406 dns_kasp_key_t *key = NULL; 407 dns_kasp_key_t k = { .tag_max = 0xffff, .length = -1 }; 408 409 REQUIRE(DNS_KASP_VALID(kasp)); 410 REQUIRE(keyp != NULL && *keyp == NULL); 411 412 key = isc_mem_get(kasp->mctx, sizeof(*key)); 413 *key = k; 414 415 key->mctx = NULL; 416 isc_mem_attach(kasp->mctx, &key->mctx); 417 418 ISC_LINK_INIT(key, link); 419 420 *keyp = key; 421 return ISC_R_SUCCESS; 422 } 423 424 void 425 dns_kasp_key_destroy(dns_kasp_key_t *key) { 426 REQUIRE(key != NULL); 427 428 if (key->keystore != NULL) { 429 dns_keystore_detach(&key->keystore); 430 } 431 isc_mem_putanddetach(&key->mctx, key, sizeof(*key)); 432 } 433 434 uint32_t 435 dns_kasp_key_algorithm(dns_kasp_key_t *key) { 436 REQUIRE(key != NULL); 437 438 return key->algorithm; 439 } 440 441 unsigned int 442 dns_kasp_key_size(dns_kasp_key_t *key) { 443 unsigned int size = 0; 444 unsigned int min = 0; 445 446 REQUIRE(key != NULL); 447 448 switch (key->algorithm) { 449 case DNS_KEYALG_RSASHA1: 450 case DNS_KEYALG_NSEC3RSASHA1: 451 case DNS_KEYALG_RSASHA256: 452 case DNS_KEYALG_RSASHA512: 453 min = (key->algorithm == DNS_KEYALG_RSASHA512) ? 1024 : 512; 454 if (key->length > -1) { 455 size = (unsigned int)key->length; 456 if (size < min) { 457 size = min; 458 } 459 if (size > 4096) { 460 size = 4096; 461 } 462 } else { 463 size = 2048; 464 } 465 break; 466 case DNS_KEYALG_ECDSA256: 467 size = 256; 468 break; 469 case DNS_KEYALG_ECDSA384: 470 size = 384; 471 break; 472 case DNS_KEYALG_ED25519: 473 size = 256; 474 break; 475 case DNS_KEYALG_ED448: 476 size = 456; 477 break; 478 default: 479 /* unsupported */ 480 break; 481 } 482 return size; 483 } 484 485 uint32_t 486 dns_kasp_key_lifetime(dns_kasp_key_t *key) { 487 REQUIRE(key != NULL); 488 489 return key->lifetime; 490 } 491 492 dns_keystore_t * 493 dns_kasp_key_keystore(dns_kasp_key_t *key) { 494 REQUIRE(key != NULL); 495 496 return key->keystore; 497 } 498 499 bool 500 dns_kasp_key_ksk(dns_kasp_key_t *key) { 501 REQUIRE(key != NULL); 502 503 return key->role & DNS_KASP_KEY_ROLE_KSK; 504 } 505 506 bool 507 dns_kasp_key_zsk(dns_kasp_key_t *key) { 508 REQUIRE(key != NULL); 509 510 return key->role & DNS_KASP_KEY_ROLE_ZSK; 511 } 512 513 uint16_t 514 dns_kasp_key_tagmin(dns_kasp_key_t *key) { 515 REQUIRE(key != NULL); 516 return key->tag_min; 517 } 518 519 uint16_t 520 dns_kasp_key_tagmax(dns_kasp_key_t *key) { 521 REQUIRE(key != NULL); 522 return key->tag_min; 523 } 524 525 bool 526 dns_kasp_key_match(dns_kasp_key_t *key, dns_dnsseckey_t *dkey) { 527 isc_result_t ret; 528 bool role = false; 529 530 REQUIRE(key != NULL); 531 REQUIRE(dkey != NULL); 532 533 /* Matching algorithms? */ 534 if (dst_key_alg(dkey->key) != dns_kasp_key_algorithm(key)) { 535 return false; 536 } 537 /* Matching length? */ 538 if (dst_key_size(dkey->key) != dns_kasp_key_size(key)) { 539 return false; 540 } 541 /* Matching role? */ 542 ret = dst_key_getbool(dkey->key, DST_BOOL_KSK, &role); 543 if (ret != ISC_R_SUCCESS || role != dns_kasp_key_ksk(key)) { 544 return false; 545 } 546 ret = dst_key_getbool(dkey->key, DST_BOOL_ZSK, &role); 547 if (ret != ISC_R_SUCCESS || role != dns_kasp_key_zsk(key)) { 548 return false; 549 } 550 /* Valid key tag range? */ 551 uint16_t id = dst_key_id(dkey->key); 552 uint16_t rid = dst_key_rid(dkey->key); 553 if (id < key->tag_min || id > key->tag_max) { 554 return false; 555 } 556 if (rid < key->tag_min || rid > key->tag_max) { 557 return false; 558 } 559 560 /* Found a match. */ 561 return true; 562 } 563 564 uint8_t 565 dns_kasp_nsec3iter(dns_kasp_t *kasp) { 566 REQUIRE(kasp != NULL); 567 REQUIRE(kasp->frozen); 568 REQUIRE(kasp->nsec3); 569 570 return kasp->nsec3param.iterations; 571 } 572 573 uint8_t 574 dns_kasp_nsec3flags(dns_kasp_t *kasp) { 575 REQUIRE(kasp != NULL); 576 REQUIRE(kasp->frozen); 577 REQUIRE(kasp->nsec3); 578 579 if (kasp->nsec3param.optout) { 580 return 0x01; 581 } 582 return 0x00; 583 } 584 585 uint8_t 586 dns_kasp_nsec3saltlen(dns_kasp_t *kasp) { 587 REQUIRE(kasp != NULL); 588 REQUIRE(kasp->frozen); 589 REQUIRE(kasp->nsec3); 590 591 return kasp->nsec3param.saltlen; 592 } 593 594 bool 595 dns_kasp_nsec3(dns_kasp_t *kasp) { 596 REQUIRE(kasp != NULL); 597 REQUIRE(kasp->frozen); 598 599 return kasp->nsec3; 600 } 601 602 void 603 dns_kasp_setnsec3(dns_kasp_t *kasp, bool nsec3) { 604 REQUIRE(kasp != NULL); 605 REQUIRE(!kasp->frozen); 606 607 kasp->nsec3 = nsec3; 608 } 609 610 void 611 dns_kasp_setnsec3param(dns_kasp_t *kasp, uint8_t iter, bool optout, 612 uint8_t saltlen) { 613 REQUIRE(kasp != NULL); 614 REQUIRE(!kasp->frozen); 615 REQUIRE(kasp->nsec3); 616 617 kasp->nsec3param.iterations = iter; 618 kasp->nsec3param.optout = optout; 619 kasp->nsec3param.saltlen = saltlen; 620 } 621 622 bool 623 dns_kasp_offlineksk(dns_kasp_t *kasp) { 624 REQUIRE(kasp != NULL); 625 REQUIRE(kasp->frozen); 626 627 return kasp->offlineksk; 628 } 629 630 void 631 dns_kasp_setofflineksk(dns_kasp_t *kasp, bool offlineksk) { 632 REQUIRE(kasp != NULL); 633 REQUIRE(!kasp->frozen); 634 635 kasp->offlineksk = offlineksk; 636 } 637 638 bool 639 dns_kasp_cdnskey(dns_kasp_t *kasp) { 640 REQUIRE(kasp != NULL); 641 REQUIRE(kasp->frozen); 642 643 return kasp->cdnskey; 644 } 645 646 void 647 dns_kasp_setcdnskey(dns_kasp_t *kasp, bool cdnskey) { 648 REQUIRE(kasp != NULL); 649 REQUIRE(!kasp->frozen); 650 651 kasp->cdnskey = cdnskey; 652 } 653 654 dns_kasp_digestlist_t 655 dns_kasp_digests(dns_kasp_t *kasp) { 656 REQUIRE(DNS_KASP_VALID(kasp)); 657 REQUIRE(kasp->frozen); 658 659 return kasp->digests; 660 } 661 662 void 663 dns_kasp_adddigest(dns_kasp_t *kasp, dns_dsdigest_t alg) { 664 dns_kasp_digest_t *digest; 665 666 REQUIRE(DNS_KASP_VALID(kasp)); 667 REQUIRE(!kasp->frozen); 668 669 /* Suppress unsupported algorithms */ 670 if (!dst_ds_digest_supported(alg)) { 671 return; 672 } 673 674 /* Suppress duplicates */ 675 for (dns_kasp_digest_t *d = ISC_LIST_HEAD(kasp->digests); d != NULL; 676 d = ISC_LIST_NEXT(d, link)) 677 { 678 if (d->digest == alg) { 679 return; 680 } 681 } 682 683 digest = isc_mem_get(kasp->mctx, sizeof(*digest)); 684 digest->digest = alg; 685 ISC_LINK_INIT(digest, link); 686 ISC_LIST_APPEND(kasp->digests, digest, link); 687 } 688