xref: /netbsd-src/external/mpl/bind/dist/lib/dns/kasp.c (revision bcda20f65a8566e103791ec395f7f499ef322704)
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