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