1/*	$NetBSD: kasp.c,v 1.6 2024/02/21 22:52:06 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/* Default TTLsig (maximum zone ttl) */
33#define DEFAULT_TTLSIG 604800 /* one week */
34
35isc_result_t
36dns_kasp_create(isc_mem_t *mctx, const char *name, dns_kasp_t **kaspp) {
37	dns_kasp_t *kasp;
38	dns_kasp_t k = {
39		.magic = DNS_KASP_MAGIC,
40	};
41
42	REQUIRE(name != NULL);
43	REQUIRE(kaspp != NULL && *kaspp == NULL);
44
45	kasp = isc_mem_get(mctx, sizeof(*kasp));
46	*kasp = k;
47
48	kasp->mctx = NULL;
49	isc_mem_attach(mctx, &kasp->mctx);
50	kasp->name = isc_mem_strdup(mctx, name);
51	isc_mutex_init(&kasp->lock);
52	isc_refcount_init(&kasp->references, 1);
53
54	ISC_LINK_INIT(kasp, link);
55	ISC_LIST_INIT(kasp->keys);
56
57	*kaspp = kasp;
58	return (ISC_R_SUCCESS);
59}
60
61void
62dns_kasp_attach(dns_kasp_t *source, dns_kasp_t **targetp) {
63	REQUIRE(DNS_KASP_VALID(source));
64	REQUIRE(targetp != NULL && *targetp == NULL);
65
66	isc_refcount_increment(&source->references);
67	*targetp = source;
68}
69
70static void
71destroy(dns_kasp_t *kasp) {
72	dns_kasp_key_t *key;
73	dns_kasp_key_t *key_next;
74
75	REQUIRE(!ISC_LINK_LINKED(kasp, link));
76
77	for (key = ISC_LIST_HEAD(kasp->keys); key != NULL; key = key_next) {
78		key_next = ISC_LIST_NEXT(key, link);
79		ISC_LIST_UNLINK(kasp->keys, key, link);
80		dns_kasp_key_destroy(key);
81	}
82	INSIST(ISC_LIST_EMPTY(kasp->keys));
83
84	isc_mutex_destroy(&kasp->lock);
85	isc_mem_free(kasp->mctx, kasp->name);
86	isc_mem_putanddetach(&kasp->mctx, kasp, sizeof(*kasp));
87}
88
89void
90dns_kasp_detach(dns_kasp_t **kaspp) {
91	REQUIRE(kaspp != NULL && DNS_KASP_VALID(*kaspp));
92
93	dns_kasp_t *kasp = *kaspp;
94	*kaspp = NULL;
95
96	if (isc_refcount_decrement(&kasp->references) == 1) {
97		destroy(kasp);
98	}
99}
100
101const char *
102dns_kasp_getname(dns_kasp_t *kasp) {
103	REQUIRE(DNS_KASP_VALID(kasp));
104
105	return (kasp->name);
106}
107
108void
109dns_kasp_freeze(dns_kasp_t *kasp) {
110	REQUIRE(DNS_KASP_VALID(kasp));
111	REQUIRE(!kasp->frozen);
112
113	kasp->frozen = true;
114}
115
116void
117dns_kasp_thaw(dns_kasp_t *kasp) {
118	REQUIRE(DNS_KASP_VALID(kasp));
119	REQUIRE(kasp->frozen);
120
121	kasp->frozen = false;
122}
123
124uint32_t
125dns_kasp_signdelay(dns_kasp_t *kasp) {
126	REQUIRE(DNS_KASP_VALID(kasp));
127	REQUIRE(kasp->frozen);
128
129	return (kasp->signatures_validity - kasp->signatures_refresh);
130}
131
132uint32_t
133dns_kasp_sigrefresh(dns_kasp_t *kasp) {
134	REQUIRE(DNS_KASP_VALID(kasp));
135	REQUIRE(kasp->frozen);
136
137	return (kasp->signatures_refresh);
138}
139
140void
141dns_kasp_setsigrefresh(dns_kasp_t *kasp, uint32_t value) {
142	REQUIRE(DNS_KASP_VALID(kasp));
143	REQUIRE(!kasp->frozen);
144
145	kasp->signatures_refresh = value;
146}
147
148uint32_t
149dns_kasp_sigvalidity(dns_kasp_t *kasp) {
150	REQUIRE(DNS_KASP_VALID(kasp));
151	REQUIRE(kasp->frozen);
152
153	return (kasp->signatures_validity);
154}
155
156void
157dns_kasp_setsigvalidity(dns_kasp_t *kasp, uint32_t value) {
158	REQUIRE(DNS_KASP_VALID(kasp));
159	REQUIRE(!kasp->frozen);
160
161	kasp->signatures_validity = value;
162}
163
164uint32_t
165dns_kasp_sigvalidity_dnskey(dns_kasp_t *kasp) {
166	REQUIRE(DNS_KASP_VALID(kasp));
167	REQUIRE(kasp->frozen);
168
169	return (kasp->signatures_validity_dnskey);
170}
171
172void
173dns_kasp_setsigvalidity_dnskey(dns_kasp_t *kasp, uint32_t value) {
174	REQUIRE(DNS_KASP_VALID(kasp));
175	REQUIRE(!kasp->frozen);
176
177	kasp->signatures_validity_dnskey = value;
178}
179
180dns_ttl_t
181dns_kasp_dnskeyttl(dns_kasp_t *kasp) {
182	REQUIRE(DNS_KASP_VALID(kasp));
183	REQUIRE(kasp->frozen);
184
185	return (kasp->dnskey_ttl);
186}
187
188void
189dns_kasp_setdnskeyttl(dns_kasp_t *kasp, dns_ttl_t ttl) {
190	REQUIRE(DNS_KASP_VALID(kasp));
191	REQUIRE(!kasp->frozen);
192
193	kasp->dnskey_ttl = ttl;
194}
195
196uint32_t
197dns_kasp_purgekeys(dns_kasp_t *kasp) {
198	REQUIRE(DNS_KASP_VALID(kasp));
199	REQUIRE(kasp->frozen);
200
201	return (kasp->purge_keys);
202}
203
204void
205dns_kasp_setpurgekeys(dns_kasp_t *kasp, uint32_t value) {
206	REQUIRE(DNS_KASP_VALID(kasp));
207	REQUIRE(!kasp->frozen);
208
209	kasp->purge_keys = value;
210}
211
212uint32_t
213dns_kasp_publishsafety(dns_kasp_t *kasp) {
214	REQUIRE(DNS_KASP_VALID(kasp));
215	REQUIRE(kasp->frozen);
216
217	return (kasp->publish_safety);
218}
219
220void
221dns_kasp_setpublishsafety(dns_kasp_t *kasp, uint32_t value) {
222	REQUIRE(DNS_KASP_VALID(kasp));
223	REQUIRE(!kasp->frozen);
224
225	kasp->publish_safety = value;
226}
227
228uint32_t
229dns_kasp_retiresafety(dns_kasp_t *kasp) {
230	REQUIRE(DNS_KASP_VALID(kasp));
231	REQUIRE(kasp->frozen);
232
233	return (kasp->retire_safety);
234}
235
236void
237dns_kasp_setretiresafety(dns_kasp_t *kasp, uint32_t value) {
238	REQUIRE(DNS_KASP_VALID(kasp));
239	REQUIRE(!kasp->frozen);
240
241	kasp->retire_safety = value;
242}
243
244dns_ttl_t
245dns_kasp_zonemaxttl(dns_kasp_t *kasp, bool fallback) {
246	REQUIRE(DNS_KASP_VALID(kasp));
247	REQUIRE(kasp->frozen);
248
249	if (kasp->zone_max_ttl == 0 && fallback) {
250		return (DEFAULT_TTLSIG);
251	}
252	return (kasp->zone_max_ttl);
253}
254
255void
256dns_kasp_setzonemaxttl(dns_kasp_t *kasp, dns_ttl_t ttl) {
257	REQUIRE(DNS_KASP_VALID(kasp));
258	REQUIRE(!kasp->frozen);
259
260	kasp->zone_max_ttl = ttl;
261}
262
263uint32_t
264dns_kasp_zonepropagationdelay(dns_kasp_t *kasp) {
265	REQUIRE(DNS_KASP_VALID(kasp));
266	REQUIRE(kasp->frozen);
267
268	return (kasp->zone_propagation_delay);
269}
270
271void
272dns_kasp_setzonepropagationdelay(dns_kasp_t *kasp, uint32_t value) {
273	REQUIRE(DNS_KASP_VALID(kasp));
274	REQUIRE(!kasp->frozen);
275
276	kasp->zone_propagation_delay = value;
277}
278
279dns_ttl_t
280dns_kasp_dsttl(dns_kasp_t *kasp) {
281	REQUIRE(DNS_KASP_VALID(kasp));
282	REQUIRE(kasp->frozen);
283
284	return (kasp->parent_ds_ttl);
285}
286
287void
288dns_kasp_setdsttl(dns_kasp_t *kasp, dns_ttl_t ttl) {
289	REQUIRE(DNS_KASP_VALID(kasp));
290	REQUIRE(!kasp->frozen);
291
292	kasp->parent_ds_ttl = ttl;
293}
294
295uint32_t
296dns_kasp_parentpropagationdelay(dns_kasp_t *kasp) {
297	REQUIRE(DNS_KASP_VALID(kasp));
298	REQUIRE(kasp->frozen);
299
300	return (kasp->parent_propagation_delay);
301}
302
303void
304dns_kasp_setparentpropagationdelay(dns_kasp_t *kasp, uint32_t value) {
305	REQUIRE(DNS_KASP_VALID(kasp));
306	REQUIRE(!kasp->frozen);
307
308	kasp->parent_propagation_delay = value;
309}
310
311isc_result_t
312dns_kasplist_find(dns_kasplist_t *list, const char *name, dns_kasp_t **kaspp) {
313	dns_kasp_t *kasp = NULL;
314
315	REQUIRE(kaspp != NULL && *kaspp == NULL);
316
317	if (list == NULL) {
318		return (ISC_R_NOTFOUND);
319	}
320
321	for (kasp = ISC_LIST_HEAD(*list); kasp != NULL;
322	     kasp = ISC_LIST_NEXT(kasp, link))
323	{
324		if (strcmp(kasp->name, name) == 0) {
325			break;
326		}
327	}
328
329	if (kasp == NULL) {
330		return (ISC_R_NOTFOUND);
331	}
332
333	dns_kasp_attach(kasp, kaspp);
334	return (ISC_R_SUCCESS);
335}
336
337dns_kasp_keylist_t
338dns_kasp_keys(dns_kasp_t *kasp) {
339	REQUIRE(DNS_KASP_VALID(kasp));
340	REQUIRE(kasp->frozen);
341
342	return (kasp->keys);
343}
344
345bool
346dns_kasp_keylist_empty(dns_kasp_t *kasp) {
347	REQUIRE(DNS_KASP_VALID(kasp));
348
349	return (ISC_LIST_EMPTY(kasp->keys));
350}
351
352void
353dns_kasp_addkey(dns_kasp_t *kasp, dns_kasp_key_t *key) {
354	REQUIRE(DNS_KASP_VALID(kasp));
355	REQUIRE(!kasp->frozen);
356	REQUIRE(key != NULL);
357
358	ISC_LIST_APPEND(kasp->keys, key, link);
359}
360
361isc_result_t
362dns_kasp_key_create(dns_kasp_t *kasp, dns_kasp_key_t **keyp) {
363	dns_kasp_key_t *key;
364
365	REQUIRE(DNS_KASP_VALID(kasp));
366	REQUIRE(keyp != NULL && *keyp == NULL);
367
368	key = isc_mem_get(kasp->mctx, sizeof(*key));
369	key->mctx = NULL;
370	isc_mem_attach(kasp->mctx, &key->mctx);
371
372	ISC_LINK_INIT(key, link);
373
374	key->lifetime = 0;
375	key->algorithm = 0;
376	key->length = -1;
377	key->role = 0;
378	*keyp = key;
379	return (ISC_R_SUCCESS);
380}
381
382void
383dns_kasp_key_destroy(dns_kasp_key_t *key) {
384	REQUIRE(key != NULL);
385
386	isc_mem_putanddetach(&key->mctx, key, sizeof(*key));
387}
388
389uint32_t
390dns_kasp_key_algorithm(dns_kasp_key_t *key) {
391	REQUIRE(key != NULL);
392
393	return (key->algorithm);
394}
395
396unsigned int
397dns_kasp_key_size(dns_kasp_key_t *key) {
398	unsigned int size = 0;
399	unsigned int min = 0;
400
401	REQUIRE(key != NULL);
402
403	switch (key->algorithm) {
404	case DNS_KEYALG_RSASHA1:
405	case DNS_KEYALG_NSEC3RSASHA1:
406	case DNS_KEYALG_RSASHA256:
407	case DNS_KEYALG_RSASHA512:
408		min = (key->algorithm == DNS_KEYALG_RSASHA512) ? 1024 : 512;
409		if (key->length > -1) {
410			size = (unsigned int)key->length;
411			if (size < min) {
412				size = min;
413			}
414			if (size > 4096) {
415				size = 4096;
416			}
417		} else {
418			size = 2048;
419		}
420		break;
421	case DNS_KEYALG_ECDSA256:
422		size = 256;
423		break;
424	case DNS_KEYALG_ECDSA384:
425		size = 384;
426		break;
427	case DNS_KEYALG_ED25519:
428		size = 256;
429		break;
430	case DNS_KEYALG_ED448:
431		size = 456;
432		break;
433	default:
434		/* unsupported */
435		break;
436	}
437	return (size);
438}
439
440uint32_t
441dns_kasp_key_lifetime(dns_kasp_key_t *key) {
442	REQUIRE(key != NULL);
443
444	return (key->lifetime);
445}
446
447bool
448dns_kasp_key_ksk(dns_kasp_key_t *key) {
449	REQUIRE(key != NULL);
450
451	return (key->role & DNS_KASP_KEY_ROLE_KSK);
452}
453
454bool
455dns_kasp_key_zsk(dns_kasp_key_t *key) {
456	REQUIRE(key != NULL);
457
458	return (key->role & DNS_KASP_KEY_ROLE_ZSK);
459}
460
461uint8_t
462dns_kasp_nsec3iter(dns_kasp_t *kasp) {
463	REQUIRE(kasp != NULL);
464	REQUIRE(kasp->frozen);
465	REQUIRE(kasp->nsec3);
466
467	return (kasp->nsec3param.iterations);
468}
469
470uint8_t
471dns_kasp_nsec3flags(dns_kasp_t *kasp) {
472	REQUIRE(kasp != NULL);
473	REQUIRE(kasp->frozen);
474	REQUIRE(kasp->nsec3);
475
476	if (kasp->nsec3param.optout) {
477		return (0x01);
478	}
479	return (0x00);
480}
481
482uint8_t
483dns_kasp_nsec3saltlen(dns_kasp_t *kasp) {
484	REQUIRE(kasp != NULL);
485	REQUIRE(kasp->frozen);
486	REQUIRE(kasp->nsec3);
487
488	return (kasp->nsec3param.saltlen);
489}
490
491bool
492dns_kasp_nsec3(dns_kasp_t *kasp) {
493	REQUIRE(kasp != NULL);
494	REQUIRE(kasp->frozen);
495
496	return kasp->nsec3;
497}
498
499void
500dns_kasp_setnsec3(dns_kasp_t *kasp, bool nsec3) {
501	REQUIRE(kasp != NULL);
502	REQUIRE(!kasp->frozen);
503
504	kasp->nsec3 = nsec3;
505}
506
507void
508dns_kasp_setnsec3param(dns_kasp_t *kasp, uint8_t iter, bool optout,
509		       uint8_t saltlen) {
510	REQUIRE(kasp != NULL);
511	REQUIRE(!kasp->frozen);
512	REQUIRE(kasp->nsec3);
513
514	kasp->nsec3param.iterations = iter;
515	kasp->nsec3param.optout = optout;
516	kasp->nsec3param.saltlen = saltlen;
517}
518