xref: /netbsd-src/external/mpl/dhcp/bind/dist/lib/isccfg/kaspconf.c (revision 4afad4b7fa6d4a0d3dedf41d1587a7250710ae54)
1*4afad4b7Schristos /*	$NetBSD: kaspconf.c,v 1.1 2024/02/18 20:57:58 christos Exp $	*/
2*4afad4b7Schristos 
3*4afad4b7Schristos /*
4*4afad4b7Schristos  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
5*4afad4b7Schristos  *
6*4afad4b7Schristos  * SPDX-License-Identifier: MPL-2.0
7*4afad4b7Schristos  *
8*4afad4b7Schristos  * This Source Code Form is subject to the terms of the Mozilla Public
9*4afad4b7Schristos  * License, v. 2.0. If a copy of the MPL was not distributed with this
10*4afad4b7Schristos  * file, you can obtain one at https://mozilla.org/MPL/2.0/.
11*4afad4b7Schristos  *
12*4afad4b7Schristos  * See the COPYRIGHT file distributed with this work for additional
13*4afad4b7Schristos  * information regarding copyright ownership.
14*4afad4b7Schristos  */
15*4afad4b7Schristos 
16*4afad4b7Schristos #include <inttypes.h>
17*4afad4b7Schristos #include <stdbool.h>
18*4afad4b7Schristos #include <stdlib.h>
19*4afad4b7Schristos 
20*4afad4b7Schristos #include <isc/mem.h>
21*4afad4b7Schristos #include <isc/print.h>
22*4afad4b7Schristos #include <isc/region.h>
23*4afad4b7Schristos #include <isc/string.h>
24*4afad4b7Schristos #include <isc/util.h>
25*4afad4b7Schristos 
26*4afad4b7Schristos #include <dns/kasp.h>
27*4afad4b7Schristos #include <dns/keyvalues.h>
28*4afad4b7Schristos #include <dns/log.h>
29*4afad4b7Schristos #include <dns/nsec3.h>
30*4afad4b7Schristos #include <dns/result.h>
31*4afad4b7Schristos #include <dns/secalg.h>
32*4afad4b7Schristos 
33*4afad4b7Schristos #include <isccfg/cfg.h>
34*4afad4b7Schristos #include <isccfg/kaspconf.h>
35*4afad4b7Schristos #include <isccfg/namedconf.h>
36*4afad4b7Schristos 
37*4afad4b7Schristos #define DEFAULT_NSEC3PARAM_ITER	   5
38*4afad4b7Schristos #define DEFAULT_NSEC3PARAM_SALTLEN 8
39*4afad4b7Schristos 
40*4afad4b7Schristos /*
41*4afad4b7Schristos  * Utility function for getting a configuration option.
42*4afad4b7Schristos  */
43*4afad4b7Schristos static isc_result_t
confget(cfg_obj_t const * const * maps,const char * name,const cfg_obj_t ** obj)44*4afad4b7Schristos confget(cfg_obj_t const *const *maps, const char *name, const cfg_obj_t **obj) {
45*4afad4b7Schristos 	for (size_t i = 0;; i++) {
46*4afad4b7Schristos 		if (maps[i] == NULL) {
47*4afad4b7Schristos 			return (ISC_R_NOTFOUND);
48*4afad4b7Schristos 		}
49*4afad4b7Schristos 		if (cfg_map_get(maps[i], name, obj) == ISC_R_SUCCESS) {
50*4afad4b7Schristos 			return (ISC_R_SUCCESS);
51*4afad4b7Schristos 		}
52*4afad4b7Schristos 	}
53*4afad4b7Schristos }
54*4afad4b7Schristos 
55*4afad4b7Schristos /*
56*4afad4b7Schristos  * Utility function for configuring durations.
57*4afad4b7Schristos  */
58*4afad4b7Schristos static uint32_t
get_duration(const cfg_obj_t ** maps,const char * option,uint32_t dfl)59*4afad4b7Schristos get_duration(const cfg_obj_t **maps, const char *option, uint32_t dfl) {
60*4afad4b7Schristos 	const cfg_obj_t *obj;
61*4afad4b7Schristos 	isc_result_t result;
62*4afad4b7Schristos 	obj = NULL;
63*4afad4b7Schristos 
64*4afad4b7Schristos 	result = confget(maps, option, &obj);
65*4afad4b7Schristos 	if (result == ISC_R_NOTFOUND) {
66*4afad4b7Schristos 		return (dfl);
67*4afad4b7Schristos 	}
68*4afad4b7Schristos 	INSIST(result == ISC_R_SUCCESS);
69*4afad4b7Schristos 	return (cfg_obj_asduration(obj));
70*4afad4b7Schristos }
71*4afad4b7Schristos 
72*4afad4b7Schristos /*
73*4afad4b7Schristos  * Create a new kasp key derived from configuration.
74*4afad4b7Schristos  */
75*4afad4b7Schristos static isc_result_t
cfg_kaspkey_fromconfig(const cfg_obj_t * config,dns_kasp_t * kasp,isc_log_t * logctx)76*4afad4b7Schristos cfg_kaspkey_fromconfig(const cfg_obj_t *config, dns_kasp_t *kasp,
77*4afad4b7Schristos 		       isc_log_t *logctx) {
78*4afad4b7Schristos 	isc_result_t result;
79*4afad4b7Schristos 	dns_kasp_key_t *key = NULL;
80*4afad4b7Schristos 
81*4afad4b7Schristos 	/* Create a new key reference. */
82*4afad4b7Schristos 	result = dns_kasp_key_create(kasp, &key);
83*4afad4b7Schristos 	if (result != ISC_R_SUCCESS) {
84*4afad4b7Schristos 		return (result);
85*4afad4b7Schristos 	}
86*4afad4b7Schristos 
87*4afad4b7Schristos 	if (config == NULL) {
88*4afad4b7Schristos 		/* We are creating a key reference for the default kasp. */
89*4afad4b7Schristos 		key->role |= DNS_KASP_KEY_ROLE_KSK | DNS_KASP_KEY_ROLE_ZSK;
90*4afad4b7Schristos 		key->lifetime = 0; /* unlimited */
91*4afad4b7Schristos 		key->algorithm = DNS_KEYALG_ECDSA256;
92*4afad4b7Schristos 		key->length = -1;
93*4afad4b7Schristos 	} else {
94*4afad4b7Schristos 		const char *rolestr = NULL;
95*4afad4b7Schristos 		const cfg_obj_t *obj = NULL;
96*4afad4b7Schristos 		isc_consttextregion_t alg;
97*4afad4b7Schristos 
98*4afad4b7Schristos 		rolestr = cfg_obj_asstring(cfg_tuple_get(config, "role"));
99*4afad4b7Schristos 		if (strcmp(rolestr, "ksk") == 0) {
100*4afad4b7Schristos 			key->role |= DNS_KASP_KEY_ROLE_KSK;
101*4afad4b7Schristos 		} else if (strcmp(rolestr, "zsk") == 0) {
102*4afad4b7Schristos 			key->role |= DNS_KASP_KEY_ROLE_ZSK;
103*4afad4b7Schristos 		} else if (strcmp(rolestr, "csk") == 0) {
104*4afad4b7Schristos 			key->role |= DNS_KASP_KEY_ROLE_KSK;
105*4afad4b7Schristos 			key->role |= DNS_KASP_KEY_ROLE_ZSK;
106*4afad4b7Schristos 		}
107*4afad4b7Schristos 
108*4afad4b7Schristos 		key->lifetime = 0; /* unlimited */
109*4afad4b7Schristos 		obj = cfg_tuple_get(config, "lifetime");
110*4afad4b7Schristos 		if (cfg_obj_isduration(obj)) {
111*4afad4b7Schristos 			key->lifetime = cfg_obj_asduration(obj);
112*4afad4b7Schristos 		}
113*4afad4b7Schristos 
114*4afad4b7Schristos 		obj = cfg_tuple_get(config, "algorithm");
115*4afad4b7Schristos 		alg.base = cfg_obj_asstring(obj);
116*4afad4b7Schristos 		alg.length = strlen(alg.base);
117*4afad4b7Schristos 		result = dns_secalg_fromtext(&key->algorithm,
118*4afad4b7Schristos 					     (isc_textregion_t *)&alg);
119*4afad4b7Schristos 		if (result != ISC_R_SUCCESS) {
120*4afad4b7Schristos 			cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
121*4afad4b7Schristos 				    "dnssec-policy: bad algorithm %s",
122*4afad4b7Schristos 				    alg.base);
123*4afad4b7Schristos 			result = DNS_R_BADALG;
124*4afad4b7Schristos 			goto cleanup;
125*4afad4b7Schristos 		}
126*4afad4b7Schristos 
127*4afad4b7Schristos 		obj = cfg_tuple_get(config, "length");
128*4afad4b7Schristos 		if (cfg_obj_isuint32(obj)) {
129*4afad4b7Schristos 			uint32_t min, size;
130*4afad4b7Schristos 			size = cfg_obj_asuint32(obj);
131*4afad4b7Schristos 
132*4afad4b7Schristos 			switch (key->algorithm) {
133*4afad4b7Schristos 			case DNS_KEYALG_RSASHA1:
134*4afad4b7Schristos 			case DNS_KEYALG_NSEC3RSASHA1:
135*4afad4b7Schristos 			case DNS_KEYALG_RSASHA256:
136*4afad4b7Schristos 			case DNS_KEYALG_RSASHA512:
137*4afad4b7Schristos 				min = DNS_KEYALG_RSASHA512 ? 1024 : 512;
138*4afad4b7Schristos 				if (size < min || size > 4096) {
139*4afad4b7Schristos 					cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
140*4afad4b7Schristos 						    "dnssec-policy: key with "
141*4afad4b7Schristos 						    "algorithm %s has invalid "
142*4afad4b7Schristos 						    "key length %u",
143*4afad4b7Schristos 						    alg.base, size);
144*4afad4b7Schristos 					result = ISC_R_RANGE;
145*4afad4b7Schristos 					goto cleanup;
146*4afad4b7Schristos 				}
147*4afad4b7Schristos 				break;
148*4afad4b7Schristos 			case DNS_KEYALG_ECDSA256:
149*4afad4b7Schristos 			case DNS_KEYALG_ECDSA384:
150*4afad4b7Schristos 			case DNS_KEYALG_ED25519:
151*4afad4b7Schristos 			case DNS_KEYALG_ED448:
152*4afad4b7Schristos 				cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
153*4afad4b7Schristos 					    "dnssec-policy: key algorithm %s "
154*4afad4b7Schristos 					    "has predefined length; ignoring "
155*4afad4b7Schristos 					    "length value %u",
156*4afad4b7Schristos 					    alg.base, size);
157*4afad4b7Schristos 			default:
158*4afad4b7Schristos 				break;
159*4afad4b7Schristos 			}
160*4afad4b7Schristos 
161*4afad4b7Schristos 			key->length = size;
162*4afad4b7Schristos 		}
163*4afad4b7Schristos 	}
164*4afad4b7Schristos 
165*4afad4b7Schristos 	dns_kasp_addkey(kasp, key);
166*4afad4b7Schristos 	return (ISC_R_SUCCESS);
167*4afad4b7Schristos 
168*4afad4b7Schristos cleanup:
169*4afad4b7Schristos 
170*4afad4b7Schristos 	dns_kasp_key_destroy(key);
171*4afad4b7Schristos 	return (result);
172*4afad4b7Schristos }
173*4afad4b7Schristos 
174*4afad4b7Schristos static isc_result_t
cfg_nsec3param_fromconfig(const cfg_obj_t * config,dns_kasp_t * kasp,isc_log_t * logctx)175*4afad4b7Schristos cfg_nsec3param_fromconfig(const cfg_obj_t *config, dns_kasp_t *kasp,
176*4afad4b7Schristos 			  isc_log_t *logctx) {
177*4afad4b7Schristos 	dns_kasp_key_t *kkey;
178*4afad4b7Schristos 	unsigned int min_keysize = 4096;
179*4afad4b7Schristos 	const cfg_obj_t *obj = NULL;
180*4afad4b7Schristos 	uint32_t iter = DEFAULT_NSEC3PARAM_ITER;
181*4afad4b7Schristos 	uint32_t saltlen = DEFAULT_NSEC3PARAM_SALTLEN;
182*4afad4b7Schristos 	uint32_t badalg = 0;
183*4afad4b7Schristos 	bool optout = false;
184*4afad4b7Schristos 	isc_result_t ret = ISC_R_SUCCESS;
185*4afad4b7Schristos 
186*4afad4b7Schristos 	/* How many iterations. */
187*4afad4b7Schristos 	obj = cfg_tuple_get(config, "iterations");
188*4afad4b7Schristos 	if (cfg_obj_isuint32(obj)) {
189*4afad4b7Schristos 		iter = cfg_obj_asuint32(obj);
190*4afad4b7Schristos 	}
191*4afad4b7Schristos 	dns_kasp_freeze(kasp);
192*4afad4b7Schristos 	for (kkey = ISC_LIST_HEAD(dns_kasp_keys(kasp)); kkey != NULL;
193*4afad4b7Schristos 	     kkey = ISC_LIST_NEXT(kkey, link))
194*4afad4b7Schristos 	{
195*4afad4b7Schristos 		unsigned int keysize = dns_kasp_key_size(kkey);
196*4afad4b7Schristos 		uint32_t keyalg = dns_kasp_key_algorithm(kkey);
197*4afad4b7Schristos 
198*4afad4b7Schristos 		if (keysize < min_keysize) {
199*4afad4b7Schristos 			min_keysize = keysize;
200*4afad4b7Schristos 		}
201*4afad4b7Schristos 
202*4afad4b7Schristos 		/* NSEC3 cannot be used with certain key algorithms. */
203*4afad4b7Schristos 		if (keyalg == DNS_KEYALG_RSAMD5 || keyalg == DNS_KEYALG_DH ||
204*4afad4b7Schristos 		    keyalg == DNS_KEYALG_DSA || keyalg == DNS_KEYALG_RSASHA1)
205*4afad4b7Schristos 		{
206*4afad4b7Schristos 			badalg = keyalg;
207*4afad4b7Schristos 		}
208*4afad4b7Schristos 	}
209*4afad4b7Schristos 	dns_kasp_thaw(kasp);
210*4afad4b7Schristos 
211*4afad4b7Schristos 	if (badalg > 0) {
212*4afad4b7Schristos 		char algstr[DNS_SECALG_FORMATSIZE];
213*4afad4b7Schristos 		dns_secalg_format((dns_secalg_t)badalg, algstr, sizeof(algstr));
214*4afad4b7Schristos 		cfg_obj_log(
215*4afad4b7Schristos 			obj, logctx, ISC_LOG_ERROR,
216*4afad4b7Schristos 			"dnssec-policy: cannot use nsec3 with algorithm '%s'",
217*4afad4b7Schristos 			algstr);
218*4afad4b7Schristos 		return (DNS_R_NSEC3BADALG);
219*4afad4b7Schristos 	}
220*4afad4b7Schristos 
221*4afad4b7Schristos 	if (iter > dns_nsec3_maxiterations()) {
222*4afad4b7Schristos 		ret = DNS_R_NSEC3ITERRANGE;
223*4afad4b7Schristos 	}
224*4afad4b7Schristos 
225*4afad4b7Schristos 	if (ret == DNS_R_NSEC3ITERRANGE) {
226*4afad4b7Schristos 		cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
227*4afad4b7Schristos 			    "dnssec-policy: nsec3 iterations value %u "
228*4afad4b7Schristos 			    "out of range",
229*4afad4b7Schristos 			    iter);
230*4afad4b7Schristos 		return (ret);
231*4afad4b7Schristos 	}
232*4afad4b7Schristos 
233*4afad4b7Schristos 	/* Opt-out? */
234*4afad4b7Schristos 	obj = cfg_tuple_get(config, "optout");
235*4afad4b7Schristos 	if (cfg_obj_isboolean(obj)) {
236*4afad4b7Schristos 		optout = cfg_obj_asboolean(obj);
237*4afad4b7Schristos 	}
238*4afad4b7Schristos 
239*4afad4b7Schristos 	/* Salt */
240*4afad4b7Schristos 	obj = cfg_tuple_get(config, "salt-length");
241*4afad4b7Schristos 	if (cfg_obj_isuint32(obj)) {
242*4afad4b7Schristos 		saltlen = cfg_obj_asuint32(obj);
243*4afad4b7Schristos 	}
244*4afad4b7Schristos 	if (saltlen > 0xff) {
245*4afad4b7Schristos 		cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
246*4afad4b7Schristos 			    "dnssec-policy: nsec3 salt length %u too high",
247*4afad4b7Schristos 			    saltlen);
248*4afad4b7Schristos 		return (DNS_R_NSEC3SALTRANGE);
249*4afad4b7Schristos 	}
250*4afad4b7Schristos 
251*4afad4b7Schristos 	dns_kasp_setnsec3param(kasp, iter, optout, saltlen);
252*4afad4b7Schristos 	return (ISC_R_SUCCESS);
253*4afad4b7Schristos }
254*4afad4b7Schristos 
255*4afad4b7Schristos isc_result_t
cfg_kasp_fromconfig(const cfg_obj_t * config,const char * name,isc_mem_t * mctx,isc_log_t * logctx,dns_kasplist_t * kasplist,dns_kasp_t ** kaspp)256*4afad4b7Schristos cfg_kasp_fromconfig(const cfg_obj_t *config, const char *name, isc_mem_t *mctx,
257*4afad4b7Schristos 		    isc_log_t *logctx, dns_kasplist_t *kasplist,
258*4afad4b7Schristos 		    dns_kasp_t **kaspp) {
259*4afad4b7Schristos 	isc_result_t result;
260*4afad4b7Schristos 	const cfg_obj_t *maps[2];
261*4afad4b7Schristos 	const cfg_obj_t *koptions = NULL;
262*4afad4b7Schristos 	const cfg_obj_t *keys = NULL;
263*4afad4b7Schristos 	const cfg_obj_t *nsec3 = NULL;
264*4afad4b7Schristos 	const cfg_listelt_t *element = NULL;
265*4afad4b7Schristos 	const char *kaspname = NULL;
266*4afad4b7Schristos 	dns_kasp_t *kasp = NULL;
267*4afad4b7Schristos 	size_t i = 0;
268*4afad4b7Schristos 
269*4afad4b7Schristos 	REQUIRE(kaspp != NULL && *kaspp == NULL);
270*4afad4b7Schristos 
271*4afad4b7Schristos 	kaspname = (name == NULL)
272*4afad4b7Schristos 			   ? cfg_obj_asstring(cfg_tuple_get(config, "name"))
273*4afad4b7Schristos 			   : name;
274*4afad4b7Schristos 	INSIST(kaspname != NULL);
275*4afad4b7Schristos 
276*4afad4b7Schristos 	result = dns_kasplist_find(kasplist, kaspname, &kasp);
277*4afad4b7Schristos 
278*4afad4b7Schristos 	if (result == ISC_R_SUCCESS) {
279*4afad4b7Schristos 		cfg_obj_log(
280*4afad4b7Schristos 			config, logctx, ISC_LOG_ERROR,
281*4afad4b7Schristos 			"dnssec-policy: duplicately named policy found '%s'",
282*4afad4b7Schristos 			kaspname);
283*4afad4b7Schristos 		dns_kasp_detach(&kasp);
284*4afad4b7Schristos 		return (ISC_R_EXISTS);
285*4afad4b7Schristos 	}
286*4afad4b7Schristos 	if (result != ISC_R_NOTFOUND) {
287*4afad4b7Schristos 		return (result);
288*4afad4b7Schristos 	}
289*4afad4b7Schristos 
290*4afad4b7Schristos 	/* No kasp with configured name was found in list, create new one. */
291*4afad4b7Schristos 	INSIST(kasp == NULL);
292*4afad4b7Schristos 	result = dns_kasp_create(mctx, kaspname, &kasp);
293*4afad4b7Schristos 	if (result != ISC_R_SUCCESS) {
294*4afad4b7Schristos 		return (result);
295*4afad4b7Schristos 	}
296*4afad4b7Schristos 	INSIST(kasp != NULL);
297*4afad4b7Schristos 
298*4afad4b7Schristos 	/* Now configure. */
299*4afad4b7Schristos 	INSIST(DNS_KASP_VALID(kasp));
300*4afad4b7Schristos 
301*4afad4b7Schristos 	if (config != NULL) {
302*4afad4b7Schristos 		koptions = cfg_tuple_get(config, "options");
303*4afad4b7Schristos 		maps[i++] = koptions;
304*4afad4b7Schristos 	}
305*4afad4b7Schristos 	maps[i] = NULL;
306*4afad4b7Schristos 
307*4afad4b7Schristos 	/* Configuration: Signatures */
308*4afad4b7Schristos 	dns_kasp_setsigrefresh(kasp, get_duration(maps, "signatures-refresh",
309*4afad4b7Schristos 						  DNS_KASP_SIG_REFRESH));
310*4afad4b7Schristos 	dns_kasp_setsigvalidity(kasp, get_duration(maps, "signatures-validity",
311*4afad4b7Schristos 						   DNS_KASP_SIG_VALIDITY));
312*4afad4b7Schristos 	dns_kasp_setsigvalidity_dnskey(
313*4afad4b7Schristos 		kasp, get_duration(maps, "signatures-validity-dnskey",
314*4afad4b7Schristos 				   DNS_KASP_SIG_VALIDITY_DNSKEY));
315*4afad4b7Schristos 
316*4afad4b7Schristos 	/* Configuration: Keys */
317*4afad4b7Schristos 	dns_kasp_setdnskeyttl(
318*4afad4b7Schristos 		kasp, get_duration(maps, "dnskey-ttl", DNS_KASP_KEY_TTL));
319*4afad4b7Schristos 	dns_kasp_setpublishsafety(kasp, get_duration(maps, "publish-safety",
320*4afad4b7Schristos 						     DNS_KASP_PUBLISH_SAFETY));
321*4afad4b7Schristos 	dns_kasp_setretiresafety(kasp, get_duration(maps, "retire-safety",
322*4afad4b7Schristos 						    DNS_KASP_RETIRE_SAFETY));
323*4afad4b7Schristos 	dns_kasp_setpurgekeys(
324*4afad4b7Schristos 		kasp, get_duration(maps, "purge-keys", DNS_KASP_PURGE_KEYS));
325*4afad4b7Schristos 
326*4afad4b7Schristos 	(void)confget(maps, "keys", &keys);
327*4afad4b7Schristos 	if (keys != NULL) {
328*4afad4b7Schristos 		char role[256] = { 0 };
329*4afad4b7Schristos 		dns_kasp_key_t *kkey = NULL;
330*4afad4b7Schristos 
331*4afad4b7Schristos 		for (element = cfg_list_first(keys); element != NULL;
332*4afad4b7Schristos 		     element = cfg_list_next(element))
333*4afad4b7Schristos 		{
334*4afad4b7Schristos 			cfg_obj_t *kobj = cfg_listelt_value(element);
335*4afad4b7Schristos 			result = cfg_kaspkey_fromconfig(kobj, kasp, logctx);
336*4afad4b7Schristos 			if (result != ISC_R_SUCCESS) {
337*4afad4b7Schristos 				goto cleanup;
338*4afad4b7Schristos 			}
339*4afad4b7Schristos 		}
340*4afad4b7Schristos 		INSIST(!(dns_kasp_keylist_empty(kasp)));
341*4afad4b7Schristos 		dns_kasp_freeze(kasp);
342*4afad4b7Schristos 		for (kkey = ISC_LIST_HEAD(dns_kasp_keys(kasp)); kkey != NULL;
343*4afad4b7Schristos 		     kkey = ISC_LIST_NEXT(kkey, link))
344*4afad4b7Schristos 		{
345*4afad4b7Schristos 			uint32_t keyalg = dns_kasp_key_algorithm(kkey);
346*4afad4b7Schristos 			INSIST(keyalg < ARRAY_SIZE(role));
347*4afad4b7Schristos 
348*4afad4b7Schristos 			if (dns_kasp_key_zsk(kkey)) {
349*4afad4b7Schristos 				role[keyalg] |= DNS_KASP_KEY_ROLE_ZSK;
350*4afad4b7Schristos 			}
351*4afad4b7Schristos 
352*4afad4b7Schristos 			if (dns_kasp_key_ksk(kkey)) {
353*4afad4b7Schristos 				role[keyalg] |= DNS_KASP_KEY_ROLE_KSK;
354*4afad4b7Schristos 			}
355*4afad4b7Schristos 		}
356*4afad4b7Schristos 		dns_kasp_thaw(kasp);
357*4afad4b7Schristos 		for (i = 0; i < ARRAY_SIZE(role); i++) {
358*4afad4b7Schristos 			if (role[i] != 0 && role[i] != (DNS_KASP_KEY_ROLE_ZSK |
359*4afad4b7Schristos 							DNS_KASP_KEY_ROLE_KSK))
360*4afad4b7Schristos 			{
361*4afad4b7Schristos 				cfg_obj_log(keys, logctx, ISC_LOG_ERROR,
362*4afad4b7Schristos 					    "dnssec-policy: algorithm %zu "
363*4afad4b7Schristos 					    "requires both KSK and ZSK roles",
364*4afad4b7Schristos 					    i);
365*4afad4b7Schristos 				result = ISC_R_FAILURE;
366*4afad4b7Schristos 			}
367*4afad4b7Schristos 		}
368*4afad4b7Schristos 		if (result != ISC_R_SUCCESS) {
369*4afad4b7Schristos 			goto cleanup;
370*4afad4b7Schristos 		}
371*4afad4b7Schristos 	} else if (strcmp(kaspname, "insecure") == 0) {
372*4afad4b7Schristos 		/* "dnssec-policy insecure": key list must be empty */
373*4afad4b7Schristos 		INSIST(strcmp(kaspname, "insecure") == 0);
374*4afad4b7Schristos 		INSIST(dns_kasp_keylist_empty(kasp));
375*4afad4b7Schristos 	} else {
376*4afad4b7Schristos 		/* No keys clause configured, use the "default". */
377*4afad4b7Schristos 		result = cfg_kaspkey_fromconfig(NULL, kasp, logctx);
378*4afad4b7Schristos 		if (result != ISC_R_SUCCESS) {
379*4afad4b7Schristos 			goto cleanup;
380*4afad4b7Schristos 		}
381*4afad4b7Schristos 		INSIST(!(dns_kasp_keylist_empty(kasp)));
382*4afad4b7Schristos 	}
383*4afad4b7Schristos 
384*4afad4b7Schristos 	/* Configuration: NSEC3 */
385*4afad4b7Schristos 	(void)confget(maps, "nsec3param", &nsec3);
386*4afad4b7Schristos 	if (nsec3 == NULL) {
387*4afad4b7Schristos 		dns_kasp_setnsec3(kasp, false);
388*4afad4b7Schristos 	} else {
389*4afad4b7Schristos 		dns_kasp_setnsec3(kasp, true);
390*4afad4b7Schristos 		result = cfg_nsec3param_fromconfig(nsec3, kasp, logctx);
391*4afad4b7Schristos 		if (result != ISC_R_SUCCESS) {
392*4afad4b7Schristos 			goto cleanup;
393*4afad4b7Schristos 		}
394*4afad4b7Schristos 	}
395*4afad4b7Schristos 
396*4afad4b7Schristos 	/* Configuration: Zone settings */
397*4afad4b7Schristos 	dns_kasp_setzonemaxttl(
398*4afad4b7Schristos 		kasp, get_duration(maps, "max-zone-ttl", DNS_KASP_ZONE_MAXTTL));
399*4afad4b7Schristos 	dns_kasp_setzonepropagationdelay(
400*4afad4b7Schristos 		kasp, get_duration(maps, "zone-propagation-delay",
401*4afad4b7Schristos 				   DNS_KASP_ZONE_PROPDELAY));
402*4afad4b7Schristos 
403*4afad4b7Schristos 	/* Configuration: Parent settings */
404*4afad4b7Schristos 	dns_kasp_setdsttl(kasp,
405*4afad4b7Schristos 			  get_duration(maps, "parent-ds-ttl", DNS_KASP_DS_TTL));
406*4afad4b7Schristos 	dns_kasp_setparentpropagationdelay(
407*4afad4b7Schristos 		kasp, get_duration(maps, "parent-propagation-delay",
408*4afad4b7Schristos 				   DNS_KASP_PARENT_PROPDELAY));
409*4afad4b7Schristos 
410*4afad4b7Schristos 	/* Append it to the list for future lookups. */
411*4afad4b7Schristos 	ISC_LIST_APPEND(*kasplist, kasp, link);
412*4afad4b7Schristos 	INSIST(!(ISC_LIST_EMPTY(*kasplist)));
413*4afad4b7Schristos 
414*4afad4b7Schristos 	/* Success: Attach the kasp to the pointer and return. */
415*4afad4b7Schristos 	dns_kasp_attach(kasp, kaspp);
416*4afad4b7Schristos 
417*4afad4b7Schristos 	/* Don't detach as kasp is on '*kasplist' */
418*4afad4b7Schristos 	return (ISC_R_SUCCESS);
419*4afad4b7Schristos 
420*4afad4b7Schristos cleanup:
421*4afad4b7Schristos 
422*4afad4b7Schristos 	/* Something bad happened, detach (destroys kasp) and return error. */
423*4afad4b7Schristos 	dns_kasp_detach(&kasp);
424*4afad4b7Schristos 	return (result);
425*4afad4b7Schristos }
426