Home | History | Annotate | Line # | Download | only in dns
      1 /*	$NetBSD: kasp.c,v 1.9 2026/01/29 18:37:49 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 bool
    288 dns_kasp_manualmode(dns_kasp_t *kasp) {
    289 	REQUIRE(DNS_KASP_VALID(kasp));
    290 	REQUIRE(kasp->frozen);
    291 
    292 	return kasp->manual_mode;
    293 }
    294 
    295 void
    296 dns_kasp_setmanualmode(dns_kasp_t *kasp, bool value) {
    297 	REQUIRE(DNS_KASP_VALID(kasp));
    298 	REQUIRE(!kasp->frozen);
    299 
    300 	kasp->manual_mode = value;
    301 }
    302 
    303 dns_ttl_t
    304 dns_kasp_zonemaxttl(dns_kasp_t *kasp, bool fallback) {
    305 	REQUIRE(DNS_KASP_VALID(kasp));
    306 	REQUIRE(kasp->frozen);
    307 
    308 	if (kasp->zone_max_ttl == 0 && fallback) {
    309 		return DEFAULT_TTLSIG;
    310 	}
    311 	return kasp->zone_max_ttl;
    312 }
    313 
    314 void
    315 dns_kasp_setzonemaxttl(dns_kasp_t *kasp, dns_ttl_t ttl) {
    316 	REQUIRE(DNS_KASP_VALID(kasp));
    317 	REQUIRE(!kasp->frozen);
    318 
    319 	kasp->zone_max_ttl = ttl;
    320 }
    321 
    322 uint32_t
    323 dns_kasp_zonepropagationdelay(dns_kasp_t *kasp) {
    324 	REQUIRE(DNS_KASP_VALID(kasp));
    325 	REQUIRE(kasp->frozen);
    326 
    327 	return kasp->zone_propagation_delay;
    328 }
    329 
    330 void
    331 dns_kasp_setzonepropagationdelay(dns_kasp_t *kasp, uint32_t value) {
    332 	REQUIRE(DNS_KASP_VALID(kasp));
    333 	REQUIRE(!kasp->frozen);
    334 
    335 	kasp->zone_propagation_delay = value;
    336 }
    337 
    338 dns_ttl_t
    339 dns_kasp_dsttl(dns_kasp_t *kasp) {
    340 	REQUIRE(DNS_KASP_VALID(kasp));
    341 	REQUIRE(kasp->frozen);
    342 
    343 	return kasp->parent_ds_ttl;
    344 }
    345 
    346 void
    347 dns_kasp_setdsttl(dns_kasp_t *kasp, dns_ttl_t ttl) {
    348 	REQUIRE(DNS_KASP_VALID(kasp));
    349 	REQUIRE(!kasp->frozen);
    350 
    351 	kasp->parent_ds_ttl = ttl;
    352 }
    353 
    354 uint32_t
    355 dns_kasp_parentpropagationdelay(dns_kasp_t *kasp) {
    356 	REQUIRE(DNS_KASP_VALID(kasp));
    357 	REQUIRE(kasp->frozen);
    358 
    359 	return kasp->parent_propagation_delay;
    360 }
    361 
    362 void
    363 dns_kasp_setparentpropagationdelay(dns_kasp_t *kasp, uint32_t value) {
    364 	REQUIRE(DNS_KASP_VALID(kasp));
    365 	REQUIRE(!kasp->frozen);
    366 
    367 	kasp->parent_propagation_delay = value;
    368 }
    369 
    370 isc_result_t
    371 dns_kasplist_find(dns_kasplist_t *list, const char *name, dns_kasp_t **kaspp) {
    372 	dns_kasp_t *kasp = NULL;
    373 
    374 	REQUIRE(kaspp != NULL && *kaspp == NULL);
    375 
    376 	if (list == NULL) {
    377 		return ISC_R_NOTFOUND;
    378 	}
    379 
    380 	for (kasp = ISC_LIST_HEAD(*list); kasp != NULL;
    381 	     kasp = ISC_LIST_NEXT(kasp, link))
    382 	{
    383 		if (strcmp(kasp->name, name) == 0) {
    384 			break;
    385 		}
    386 	}
    387 
    388 	if (kasp == NULL) {
    389 		return ISC_R_NOTFOUND;
    390 	}
    391 
    392 	dns_kasp_attach(kasp, kaspp);
    393 	return ISC_R_SUCCESS;
    394 }
    395 
    396 dns_kasp_keylist_t
    397 dns_kasp_keys(dns_kasp_t *kasp) {
    398 	REQUIRE(DNS_KASP_VALID(kasp));
    399 	REQUIRE(kasp->frozen);
    400 
    401 	return kasp->keys;
    402 }
    403 
    404 bool
    405 dns_kasp_keylist_empty(dns_kasp_t *kasp) {
    406 	REQUIRE(DNS_KASP_VALID(kasp));
    407 
    408 	return ISC_LIST_EMPTY(kasp->keys);
    409 }
    410 
    411 void
    412 dns_kasp_addkey(dns_kasp_t *kasp, dns_kasp_key_t *key) {
    413 	REQUIRE(DNS_KASP_VALID(kasp));
    414 	REQUIRE(!kasp->frozen);
    415 	REQUIRE(key != NULL);
    416 
    417 	ISC_LIST_APPEND(kasp->keys, key, link);
    418 }
    419 
    420 isc_result_t
    421 dns_kasp_key_create(dns_kasp_t *kasp, dns_kasp_key_t **keyp) {
    422 	dns_kasp_key_t *key = NULL;
    423 	dns_kasp_key_t k = { .tag_max = 0xffff, .length = -1 };
    424 
    425 	REQUIRE(DNS_KASP_VALID(kasp));
    426 	REQUIRE(keyp != NULL && *keyp == NULL);
    427 
    428 	key = isc_mem_get(kasp->mctx, sizeof(*key));
    429 	*key = k;
    430 
    431 	key->mctx = NULL;
    432 	isc_mem_attach(kasp->mctx, &key->mctx);
    433 
    434 	ISC_LINK_INIT(key, link);
    435 
    436 	*keyp = key;
    437 	return ISC_R_SUCCESS;
    438 }
    439 
    440 void
    441 dns_kasp_key_destroy(dns_kasp_key_t *key) {
    442 	REQUIRE(key != NULL);
    443 
    444 	if (key->keystore != NULL) {
    445 		dns_keystore_detach(&key->keystore);
    446 	}
    447 	isc_mem_putanddetach(&key->mctx, key, sizeof(*key));
    448 }
    449 
    450 uint32_t
    451 dns_kasp_key_algorithm(dns_kasp_key_t *key) {
    452 	REQUIRE(key != NULL);
    453 
    454 	return key->algorithm;
    455 }
    456 
    457 unsigned int
    458 dns_kasp_key_size(dns_kasp_key_t *key) {
    459 	unsigned int size = 0;
    460 	unsigned int min = 0;
    461 
    462 	REQUIRE(key != NULL);
    463 
    464 	switch (key->algorithm) {
    465 	case DNS_KEYALG_RSASHA1:
    466 	case DNS_KEYALG_NSEC3RSASHA1:
    467 	case DNS_KEYALG_RSASHA256:
    468 	case DNS_KEYALG_RSASHA512:
    469 		min = (key->algorithm == DNS_KEYALG_RSASHA512) ? 1024 : 512;
    470 		if (key->length > -1) {
    471 			size = (unsigned int)key->length;
    472 			if (size < min) {
    473 				size = min;
    474 			}
    475 			if (size > 4096) {
    476 				size = 4096;
    477 			}
    478 		} else {
    479 			size = 2048;
    480 		}
    481 		break;
    482 	case DNS_KEYALG_ECDSA256:
    483 		size = 256;
    484 		break;
    485 	case DNS_KEYALG_ECDSA384:
    486 		size = 384;
    487 		break;
    488 	case DNS_KEYALG_ED25519:
    489 		size = 256;
    490 		break;
    491 	case DNS_KEYALG_ED448:
    492 		size = 456;
    493 		break;
    494 	default:
    495 		/* unsupported */
    496 		break;
    497 	}
    498 	return size;
    499 }
    500 
    501 uint32_t
    502 dns_kasp_key_lifetime(dns_kasp_key_t *key) {
    503 	REQUIRE(key != NULL);
    504 
    505 	return key->lifetime;
    506 }
    507 
    508 dns_keystore_t *
    509 dns_kasp_key_keystore(dns_kasp_key_t *key) {
    510 	REQUIRE(key != NULL);
    511 
    512 	return key->keystore;
    513 }
    514 
    515 bool
    516 dns_kasp_key_ksk(dns_kasp_key_t *key) {
    517 	REQUIRE(key != NULL);
    518 
    519 	return key->role & DNS_KASP_KEY_ROLE_KSK;
    520 }
    521 
    522 bool
    523 dns_kasp_key_zsk(dns_kasp_key_t *key) {
    524 	REQUIRE(key != NULL);
    525 
    526 	return key->role & DNS_KASP_KEY_ROLE_ZSK;
    527 }
    528 
    529 uint16_t
    530 dns_kasp_key_tagmin(dns_kasp_key_t *key) {
    531 	REQUIRE(key != NULL);
    532 	return key->tag_min;
    533 }
    534 
    535 uint16_t
    536 dns_kasp_key_tagmax(dns_kasp_key_t *key) {
    537 	REQUIRE(key != NULL);
    538 	return key->tag_min;
    539 }
    540 
    541 bool
    542 dns_kasp_key_match(dns_kasp_key_t *key, dns_dnsseckey_t *dkey) {
    543 	isc_result_t ret;
    544 	bool role = false;
    545 
    546 	REQUIRE(key != NULL);
    547 	REQUIRE(dkey != NULL);
    548 
    549 	/* Matching algorithms? */
    550 	if (dst_key_alg(dkey->key) != dns_kasp_key_algorithm(key)) {
    551 		return false;
    552 	}
    553 	/* Matching length? */
    554 	if (dst_key_size(dkey->key) != dns_kasp_key_size(key)) {
    555 		return false;
    556 	}
    557 	/* Matching role? */
    558 	ret = dst_key_getbool(dkey->key, DST_BOOL_KSK, &role);
    559 	if (ret != ISC_R_SUCCESS || role != dns_kasp_key_ksk(key)) {
    560 		return false;
    561 	}
    562 	ret = dst_key_getbool(dkey->key, DST_BOOL_ZSK, &role);
    563 	if (ret != ISC_R_SUCCESS || role != dns_kasp_key_zsk(key)) {
    564 		return false;
    565 	}
    566 	/* Valid key tag range? */
    567 	uint16_t id = dst_key_id(dkey->key);
    568 	uint16_t rid = dst_key_rid(dkey->key);
    569 	if (id < key->tag_min || id > key->tag_max) {
    570 		return false;
    571 	}
    572 	if (rid < key->tag_min || rid > key->tag_max) {
    573 		return false;
    574 	}
    575 
    576 	/* Found a match. */
    577 	return true;
    578 }
    579 
    580 void
    581 dns_kasp_key_format(dns_kasp_key_t *key, char *cp, unsigned int size) {
    582 	REQUIRE(key != NULL);
    583 	REQUIRE(cp != NULL);
    584 
    585 	char algstr[DNS_NAME_FORMATSIZE];
    586 	bool csk = dns_kasp_key_ksk(key) && dns_kasp_key_zsk(key);
    587 	const char *rolestr = (csk ? "csk"
    588 				   : (dns_kasp_key_ksk(key) ? "ksk" : "zsk"));
    589 
    590 	dns_secalg_format((dns_secalg_t)key->algorithm, algstr, sizeof(algstr));
    591 	snprintf(cp, size, "%s algorithm:%s length:%u tag-range:%u-%u", rolestr,
    592 		 algstr, dns_kasp_key_size(key), key->tag_min, key->tag_max);
    593 }
    594 
    595 uint8_t
    596 dns_kasp_nsec3iter(dns_kasp_t *kasp) {
    597 	REQUIRE(kasp != NULL);
    598 	REQUIRE(kasp->frozen);
    599 	REQUIRE(kasp->nsec3);
    600 
    601 	return kasp->nsec3param.iterations;
    602 }
    603 
    604 uint8_t
    605 dns_kasp_nsec3flags(dns_kasp_t *kasp) {
    606 	REQUIRE(kasp != NULL);
    607 	REQUIRE(kasp->frozen);
    608 	REQUIRE(kasp->nsec3);
    609 
    610 	if (kasp->nsec3param.optout) {
    611 		return 0x01;
    612 	}
    613 	return 0x00;
    614 }
    615 
    616 uint8_t
    617 dns_kasp_nsec3saltlen(dns_kasp_t *kasp) {
    618 	REQUIRE(kasp != NULL);
    619 	REQUIRE(kasp->frozen);
    620 	REQUIRE(kasp->nsec3);
    621 
    622 	return kasp->nsec3param.saltlen;
    623 }
    624 
    625 bool
    626 dns_kasp_nsec3(dns_kasp_t *kasp) {
    627 	REQUIRE(kasp != NULL);
    628 	REQUIRE(kasp->frozen);
    629 
    630 	return kasp->nsec3;
    631 }
    632 
    633 void
    634 dns_kasp_setnsec3(dns_kasp_t *kasp, bool nsec3) {
    635 	REQUIRE(kasp != NULL);
    636 	REQUIRE(!kasp->frozen);
    637 
    638 	kasp->nsec3 = nsec3;
    639 }
    640 
    641 void
    642 dns_kasp_setnsec3param(dns_kasp_t *kasp, uint8_t iter, bool optout,
    643 		       uint8_t saltlen) {
    644 	REQUIRE(kasp != NULL);
    645 	REQUIRE(!kasp->frozen);
    646 	REQUIRE(kasp->nsec3);
    647 
    648 	kasp->nsec3param.iterations = iter;
    649 	kasp->nsec3param.optout = optout;
    650 	kasp->nsec3param.saltlen = saltlen;
    651 }
    652 
    653 bool
    654 dns_kasp_offlineksk(dns_kasp_t *kasp) {
    655 	REQUIRE(kasp != NULL);
    656 	REQUIRE(kasp->frozen);
    657 
    658 	return kasp->offlineksk;
    659 }
    660 
    661 void
    662 dns_kasp_setofflineksk(dns_kasp_t *kasp, bool offlineksk) {
    663 	REQUIRE(kasp != NULL);
    664 	REQUIRE(!kasp->frozen);
    665 
    666 	kasp->offlineksk = offlineksk;
    667 }
    668 
    669 bool
    670 dns_kasp_cdnskey(dns_kasp_t *kasp) {
    671 	REQUIRE(kasp != NULL);
    672 	REQUIRE(kasp->frozen);
    673 
    674 	return kasp->cdnskey;
    675 }
    676 
    677 void
    678 dns_kasp_setcdnskey(dns_kasp_t *kasp, bool cdnskey) {
    679 	REQUIRE(kasp != NULL);
    680 	REQUIRE(!kasp->frozen);
    681 
    682 	kasp->cdnskey = cdnskey;
    683 }
    684 
    685 dns_kasp_digestlist_t
    686 dns_kasp_digests(dns_kasp_t *kasp) {
    687 	REQUIRE(DNS_KASP_VALID(kasp));
    688 	REQUIRE(kasp->frozen);
    689 
    690 	return kasp->digests;
    691 }
    692 
    693 void
    694 dns_kasp_adddigest(dns_kasp_t *kasp, dns_dsdigest_t alg) {
    695 	dns_kasp_digest_t *digest;
    696 
    697 	REQUIRE(DNS_KASP_VALID(kasp));
    698 	REQUIRE(!kasp->frozen);
    699 
    700 	/* Suppress unsupported algorithms */
    701 	if (!dst_ds_digest_supported(alg)) {
    702 		return;
    703 	}
    704 
    705 	/* Suppress duplicates */
    706 	for (dns_kasp_digest_t *d = ISC_LIST_HEAD(kasp->digests); d != NULL;
    707 	     d = ISC_LIST_NEXT(d, link))
    708 	{
    709 		if (d->digest == alg) {
    710 			return;
    711 		}
    712 	}
    713 
    714 	digest = isc_mem_get(kasp->mctx, sizeof(*digest));
    715 	digest->digest = alg;
    716 	ISC_LINK_INIT(digest, link);
    717 	ISC_LIST_APPEND(kasp->digests, digest, link);
    718 }
    719