xref: /netbsd/external/mpl/bind/dist/lib/dns/dst_api.c (revision 4ac1c27e)
1 /*	$NetBSD: dst_api.c,v 1.13 2023/01/25 21:43:30 christos Exp $	*/
2 
3 /*
4  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
5  *
6  * SPDX-License-Identifier: MPL-2.0 AND ISC
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 /*
17  * Copyright (C) Network Associates, Inc.
18  *
19  * Permission to use, copy, modify, and/or distribute this software for any
20  * purpose with or without fee is hereby granted, provided that the above
21  * copyright notice and this permission notice appear in all copies.
22  *
23  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS
24  * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
25  * WARRANTIES OF MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE
26  * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
27  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
28  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
29  * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
30  */
31 
32 /*! \file */
33 
34 #include <inttypes.h>
35 #include <stdbool.h>
36 #include <stdlib.h>
37 #include <time.h>
38 
39 #include <isc/buffer.h>
40 #include <isc/dir.h>
41 #include <isc/file.h>
42 #include <isc/fsaccess.h>
43 #include <isc/lex.h>
44 #include <isc/mem.h>
45 #include <isc/once.h>
46 #include <isc/platform.h>
47 #include <isc/print.h>
48 #include <isc/random.h>
49 #include <isc/refcount.h>
50 #include <isc/safe.h>
51 #include <isc/string.h>
52 #include <isc/time.h>
53 #include <isc/util.h>
54 
55 #include <pk11/site.h>
56 
57 #define DST_KEY_INTERNAL
58 
59 #include <dns/fixedname.h>
60 #include <dns/keyvalues.h>
61 #include <dns/name.h>
62 #include <dns/rdata.h>
63 #include <dns/rdataclass.h>
64 #include <dns/ttl.h>
65 #include <dns/types.h>
66 
67 #include <dst/result.h>
68 
69 #include "dst_internal.h"
70 
71 #define DST_AS_STR(t) ((t).value.as_textregion.base)
72 
73 #define NEXTTOKEN(lex, opt, token)                       \
74 	{                                                \
75 		ret = isc_lex_gettoken(lex, opt, token); \
76 		if (ret != ISC_R_SUCCESS)                \
77 			goto cleanup;                    \
78 	}
79 
80 #define NEXTTOKEN_OR_EOF(lex, opt, token)                \
81 	do {                                             \
82 		ret = isc_lex_gettoken(lex, opt, token); \
83 		if (ret == ISC_R_EOF)                    \
84 			break;                           \
85 		if (ret != ISC_R_SUCCESS)                \
86 			goto cleanup;                    \
87 	} while ((*token).type == isc_tokentype_eol);
88 
89 #define READLINE(lex, opt, token)                        \
90 	do {                                             \
91 		ret = isc_lex_gettoken(lex, opt, token); \
92 		if (ret == ISC_R_EOF)                    \
93 			break;                           \
94 		if (ret != ISC_R_SUCCESS)                \
95 			goto cleanup;                    \
96 	} while ((*token).type != isc_tokentype_eol)
97 
98 #define BADTOKEN()                           \
99 	{                                    \
100 		ret = ISC_R_UNEXPECTEDTOKEN; \
101 		goto cleanup;                \
102 	}
103 
104 #define NUMERIC_NTAGS (DST_MAX_NUMERIC + 1)
105 static const char *numerictags[NUMERIC_NTAGS] = {
106 	"Predecessor:", "Successor:",  "MaxTTL:",    "RollPeriod:",
107 	"Lifetime:",	"DSPubCount:", "DSRemCount:"
108 };
109 
110 #define BOOLEAN_NTAGS (DST_MAX_BOOLEAN + 1)
111 static const char *booleantags[BOOLEAN_NTAGS] = { "KSK:", "ZSK:" };
112 
113 #define TIMING_NTAGS (DST_MAX_TIMES + 1)
114 static const char *timingtags[TIMING_NTAGS] = {
115 	"Generated:",	 "Published:",	  "Active:",	   "Revoked:",
116 	"Retired:",	 "Removed:",
117 
118 	"DSPublish:",	 "SyncPublish:",  "SyncDelete:",
119 
120 	"DNSKEYChange:", "ZRRSIGChange:", "KRRSIGChange:", "DSChange:",
121 
122 	"DSRemoved:"
123 };
124 
125 #define KEYSTATES_NTAGS (DST_MAX_KEYSTATES + 1)
126 static const char *keystatestags[KEYSTATES_NTAGS] = {
127 	"DNSKEYState:", "ZRRSIGState:", "KRRSIGState:", "DSState:", "GoalState:"
128 };
129 
130 #define KEYSTATES_NVALUES 4
131 static const char *keystates[KEYSTATES_NVALUES] = {
132 	"hidden",
133 	"rumoured",
134 	"omnipresent",
135 	"unretentive",
136 };
137 
138 #define STATE_ALGORITHM_STR "Algorithm:"
139 #define STATE_LENGTH_STR    "Length:"
140 #define MAX_NTAGS \
141 	(DST_MAX_NUMERIC + DST_MAX_BOOLEAN + DST_MAX_TIMES + DST_MAX_KEYSTATES)
142 
143 static dst_func_t *dst_t_func[DST_MAX_ALGS];
144 
145 static bool dst_initialized = false;
146 
147 void
148 gss_log(int level, const char *fmt, ...) ISC_FORMAT_PRINTF(2, 3);
149 
150 /*
151  * Static functions.
152  */
153 static dst_key_t *
154 get_key_struct(const dns_name_t *name, unsigned int alg, unsigned int flags,
155 	       unsigned int protocol, unsigned int bits,
156 	       dns_rdataclass_t rdclass, dns_ttl_t ttl, isc_mem_t *mctx);
157 static isc_result_t
158 write_public_key(const dst_key_t *key, int type, const char *directory);
159 static isc_result_t
160 write_key_state(const dst_key_t *key, int type, const char *directory);
161 static isc_result_t
162 buildfilename(dns_name_t *name, dns_keytag_t id, unsigned int alg,
163 	      unsigned int type, const char *directory, isc_buffer_t *out);
164 static isc_result_t
165 computeid(dst_key_t *key);
166 static isc_result_t
167 frombuffer(const dns_name_t *name, unsigned int alg, unsigned int flags,
168 	   unsigned int protocol, dns_rdataclass_t rdclass,
169 	   isc_buffer_t *source, isc_mem_t *mctx, dst_key_t **keyp);
170 
171 static isc_result_t
172 algorithm_status(unsigned int alg);
173 
174 static isc_result_t
175 addsuffix(char *filename, int len, const char *dirname, const char *ofilename,
176 	  const char *suffix);
177 
178 #define RETERR(x)                            \
179 	do {                                 \
180 		result = (x);                \
181 		if (result != ISC_R_SUCCESS) \
182 			goto out;            \
183 	} while (0)
184 
185 #define CHECKALG(alg)                       \
186 	do {                                \
187 		isc_result_t _r;            \
188 		_r = algorithm_status(alg); \
189 		if (_r != ISC_R_SUCCESS)    \
190 			return ((_r));      \
191 	} while (0)
192 
193 isc_result_t
dst_lib_init(isc_mem_t * mctx,const char * engine)194 dst_lib_init(isc_mem_t *mctx, const char *engine) {
195 	isc_result_t result;
196 
197 	REQUIRE(mctx != NULL);
198 	REQUIRE(!dst_initialized);
199 
200 	UNUSED(engine);
201 
202 	dst_result_register();
203 
204 	memset(dst_t_func, 0, sizeof(dst_t_func));
205 	RETERR(dst__hmacmd5_init(&dst_t_func[DST_ALG_HMACMD5]));
206 	RETERR(dst__hmacsha1_init(&dst_t_func[DST_ALG_HMACSHA1]));
207 	RETERR(dst__hmacsha224_init(&dst_t_func[DST_ALG_HMACSHA224]));
208 	RETERR(dst__hmacsha256_init(&dst_t_func[DST_ALG_HMACSHA256]));
209 	RETERR(dst__hmacsha384_init(&dst_t_func[DST_ALG_HMACSHA384]));
210 	RETERR(dst__hmacsha512_init(&dst_t_func[DST_ALG_HMACSHA512]));
211 	RETERR(dst__openssl_init(engine));
212 	RETERR(dst__openssldh_init(&dst_t_func[DST_ALG_DH]));
213 #if USE_OPENSSL
214 	RETERR(dst__opensslrsa_init(&dst_t_func[DST_ALG_RSASHA1],
215 				    DST_ALG_RSASHA1));
216 	RETERR(dst__opensslrsa_init(&dst_t_func[DST_ALG_NSEC3RSASHA1],
217 				    DST_ALG_NSEC3RSASHA1));
218 	RETERR(dst__opensslrsa_init(&dst_t_func[DST_ALG_RSASHA256],
219 				    DST_ALG_RSASHA256));
220 	RETERR(dst__opensslrsa_init(&dst_t_func[DST_ALG_RSASHA512],
221 				    DST_ALG_RSASHA512));
222 	RETERR(dst__opensslecdsa_init(&dst_t_func[DST_ALG_ECDSA256]));
223 	RETERR(dst__opensslecdsa_init(&dst_t_func[DST_ALG_ECDSA384]));
224 #ifdef HAVE_OPENSSL_ED25519
225 	RETERR(dst__openssleddsa_init(&dst_t_func[DST_ALG_ED25519]));
226 #endif /* ifdef HAVE_OPENSSL_ED25519 */
227 #ifdef HAVE_OPENSSL_ED448
228 	RETERR(dst__openssleddsa_init(&dst_t_func[DST_ALG_ED448]));
229 #endif /* ifdef HAVE_OPENSSL_ED448 */
230 #endif /* USE_OPENSSL */
231 
232 #if USE_PKCS11
233 	RETERR(dst__pkcs11_init(mctx, engine));
234 	RETERR(dst__pkcs11rsa_init(&dst_t_func[DST_ALG_RSASHA1]));
235 	RETERR(dst__pkcs11rsa_init(&dst_t_func[DST_ALG_NSEC3RSASHA1]));
236 	RETERR(dst__pkcs11rsa_init(&dst_t_func[DST_ALG_RSASHA256]));
237 	RETERR(dst__pkcs11rsa_init(&dst_t_func[DST_ALG_RSASHA512]));
238 	RETERR(dst__pkcs11ecdsa_init(&dst_t_func[DST_ALG_ECDSA256]));
239 	RETERR(dst__pkcs11ecdsa_init(&dst_t_func[DST_ALG_ECDSA384]));
240 	RETERR(dst__pkcs11eddsa_init(&dst_t_func[DST_ALG_ED25519]));
241 	RETERR(dst__pkcs11eddsa_init(&dst_t_func[DST_ALG_ED448]));
242 #endif /* USE_PKCS11 */
243 #ifdef GSSAPI
244 	RETERR(dst__gssapi_init(&dst_t_func[DST_ALG_GSSAPI]));
245 #endif /* ifdef GSSAPI */
246 
247 	dst_initialized = true;
248 	return (ISC_R_SUCCESS);
249 
250 out:
251 	/* avoid immediate crash! */
252 	dst_initialized = true;
253 	dst_lib_destroy();
254 	return (result);
255 }
256 
257 void
dst_lib_destroy(void)258 dst_lib_destroy(void) {
259 	int i;
260 	RUNTIME_CHECK(dst_initialized);
261 	dst_initialized = false;
262 
263 	for (i = 0; i < DST_MAX_ALGS; i++) {
264 		if (dst_t_func[i] != NULL && dst_t_func[i]->cleanup != NULL) {
265 			dst_t_func[i]->cleanup();
266 		}
267 	}
268 	dst__openssl_destroy();
269 #if USE_PKCS11
270 	(void)dst__pkcs11_destroy();
271 #endif /* USE_PKCS11 */
272 }
273 
274 bool
dst_algorithm_supported(unsigned int alg)275 dst_algorithm_supported(unsigned int alg) {
276 	REQUIRE(dst_initialized);
277 
278 	if (alg >= DST_MAX_ALGS || dst_t_func[alg] == NULL) {
279 		return (false);
280 	}
281 	return (true);
282 }
283 
284 bool
dst_ds_digest_supported(unsigned int digest_type)285 dst_ds_digest_supported(unsigned int digest_type) {
286 	return (digest_type == DNS_DSDIGEST_SHA1 ||
287 		digest_type == DNS_DSDIGEST_SHA256 ||
288 		digest_type == DNS_DSDIGEST_SHA384);
289 }
290 
291 isc_result_t
dst_context_create(dst_key_t * key,isc_mem_t * mctx,isc_logcategory_t * category,bool useforsigning,int maxbits,dst_context_t ** dctxp)292 dst_context_create(dst_key_t *key, isc_mem_t *mctx, isc_logcategory_t *category,
293 		   bool useforsigning, int maxbits, dst_context_t **dctxp) {
294 	dst_context_t *dctx;
295 	isc_result_t result;
296 
297 	REQUIRE(dst_initialized);
298 	REQUIRE(VALID_KEY(key));
299 	REQUIRE(mctx != NULL);
300 	REQUIRE(dctxp != NULL && *dctxp == NULL);
301 
302 	if (key->func->createctx == NULL && key->func->createctx2 == NULL) {
303 		return (DST_R_UNSUPPORTEDALG);
304 	}
305 	if (key->keydata.generic == NULL) {
306 		return (DST_R_NULLKEY);
307 	}
308 
309 	dctx = isc_mem_get(mctx, sizeof(dst_context_t));
310 	memset(dctx, 0, sizeof(*dctx));
311 	dst_key_attach(key, &dctx->key);
312 	isc_mem_attach(mctx, &dctx->mctx);
313 	dctx->category = category;
314 	if (useforsigning) {
315 		dctx->use = DO_SIGN;
316 	} else {
317 		dctx->use = DO_VERIFY;
318 	}
319 	if (key->func->createctx2 != NULL) {
320 		result = key->func->createctx2(key, maxbits, dctx);
321 	} else {
322 		result = key->func->createctx(key, dctx);
323 	}
324 	if (result != ISC_R_SUCCESS) {
325 		if (dctx->key != NULL) {
326 			dst_key_free(&dctx->key);
327 		}
328 		isc_mem_putanddetach(&dctx->mctx, dctx, sizeof(dst_context_t));
329 		return (result);
330 	}
331 	dctx->magic = CTX_MAGIC;
332 	*dctxp = dctx;
333 	return (ISC_R_SUCCESS);
334 }
335 
336 void
dst_context_destroy(dst_context_t ** dctxp)337 dst_context_destroy(dst_context_t **dctxp) {
338 	dst_context_t *dctx;
339 
340 	REQUIRE(dctxp != NULL && VALID_CTX(*dctxp));
341 
342 	dctx = *dctxp;
343 	*dctxp = NULL;
344 	INSIST(dctx->key->func->destroyctx != NULL);
345 	dctx->key->func->destroyctx(dctx);
346 	if (dctx->key != NULL) {
347 		dst_key_free(&dctx->key);
348 	}
349 	dctx->magic = 0;
350 	isc_mem_putanddetach(&dctx->mctx, dctx, sizeof(dst_context_t));
351 }
352 
353 isc_result_t
dst_context_adddata(dst_context_t * dctx,const isc_region_t * data)354 dst_context_adddata(dst_context_t *dctx, const isc_region_t *data) {
355 	REQUIRE(VALID_CTX(dctx));
356 	REQUIRE(data != NULL);
357 	INSIST(dctx->key->func->adddata != NULL);
358 
359 	return (dctx->key->func->adddata(dctx, data));
360 }
361 
362 isc_result_t
dst_context_sign(dst_context_t * dctx,isc_buffer_t * sig)363 dst_context_sign(dst_context_t *dctx, isc_buffer_t *sig) {
364 	dst_key_t *key;
365 
366 	REQUIRE(VALID_CTX(dctx));
367 	REQUIRE(sig != NULL);
368 
369 	key = dctx->key;
370 	CHECKALG(key->key_alg);
371 	if (key->keydata.generic == NULL) {
372 		return (DST_R_NULLKEY);
373 	}
374 
375 	if (key->func->sign == NULL) {
376 		return (DST_R_NOTPRIVATEKEY);
377 	}
378 	if (key->func->isprivate == NULL || !key->func->isprivate(key)) {
379 		return (DST_R_NOTPRIVATEKEY);
380 	}
381 
382 	return (key->func->sign(dctx, sig));
383 }
384 
385 isc_result_t
dst_context_verify(dst_context_t * dctx,isc_region_t * sig)386 dst_context_verify(dst_context_t *dctx, isc_region_t *sig) {
387 	REQUIRE(VALID_CTX(dctx));
388 	REQUIRE(sig != NULL);
389 
390 	CHECKALG(dctx->key->key_alg);
391 	if (dctx->key->keydata.generic == NULL) {
392 		return (DST_R_NULLKEY);
393 	}
394 	if (dctx->key->func->verify == NULL) {
395 		return (DST_R_NOTPUBLICKEY);
396 	}
397 
398 	return (dctx->key->func->verify(dctx, sig));
399 }
400 
401 isc_result_t
dst_context_verify2(dst_context_t * dctx,unsigned int maxbits,isc_region_t * sig)402 dst_context_verify2(dst_context_t *dctx, unsigned int maxbits,
403 		    isc_region_t *sig) {
404 	REQUIRE(VALID_CTX(dctx));
405 	REQUIRE(sig != NULL);
406 
407 	CHECKALG(dctx->key->key_alg);
408 	if (dctx->key->keydata.generic == NULL) {
409 		return (DST_R_NULLKEY);
410 	}
411 	if (dctx->key->func->verify == NULL && dctx->key->func->verify2 == NULL)
412 	{
413 		return (DST_R_NOTPUBLICKEY);
414 	}
415 
416 	return (dctx->key->func->verify2 != NULL
417 			? dctx->key->func->verify2(dctx, maxbits, sig)
418 			: dctx->key->func->verify(dctx, sig));
419 }
420 
421 isc_result_t
dst_key_computesecret(const dst_key_t * pub,const dst_key_t * priv,isc_buffer_t * secret)422 dst_key_computesecret(const dst_key_t *pub, const dst_key_t *priv,
423 		      isc_buffer_t *secret) {
424 	REQUIRE(dst_initialized);
425 	REQUIRE(VALID_KEY(pub) && VALID_KEY(priv));
426 	REQUIRE(secret != NULL);
427 
428 	CHECKALG(pub->key_alg);
429 	CHECKALG(priv->key_alg);
430 
431 	if (pub->keydata.generic == NULL || priv->keydata.generic == NULL) {
432 		return (DST_R_NULLKEY);
433 	}
434 
435 	if (pub->key_alg != priv->key_alg || pub->func->computesecret == NULL ||
436 	    priv->func->computesecret == NULL)
437 	{
438 		return (DST_R_KEYCANNOTCOMPUTESECRET);
439 	}
440 
441 	if (!dst_key_isprivate(priv)) {
442 		return (DST_R_NOTPRIVATEKEY);
443 	}
444 
445 	return (pub->func->computesecret(pub, priv, secret));
446 }
447 
448 isc_result_t
dst_key_tofile(const dst_key_t * key,int type,const char * directory)449 dst_key_tofile(const dst_key_t *key, int type, const char *directory) {
450 	isc_result_t ret = ISC_R_SUCCESS;
451 
452 	REQUIRE(dst_initialized);
453 	REQUIRE(VALID_KEY(key));
454 	REQUIRE((type &
455 		 (DST_TYPE_PRIVATE | DST_TYPE_PUBLIC | DST_TYPE_STATE)) != 0);
456 
457 	CHECKALG(key->key_alg);
458 
459 	if (key->func->tofile == NULL) {
460 		return (DST_R_UNSUPPORTEDALG);
461 	}
462 
463 	if ((type & DST_TYPE_PUBLIC) != 0) {
464 		ret = write_public_key(key, type, directory);
465 		if (ret != ISC_R_SUCCESS) {
466 			return (ret);
467 		}
468 	}
469 
470 	if ((type & DST_TYPE_STATE) != 0) {
471 		ret = write_key_state(key, type, directory);
472 		if (ret != ISC_R_SUCCESS) {
473 			return (ret);
474 		}
475 	}
476 
477 	if (((type & DST_TYPE_PRIVATE) != 0) &&
478 	    (key->key_flags & DNS_KEYFLAG_TYPEMASK) != DNS_KEYTYPE_NOKEY)
479 	{
480 		return (key->func->tofile(key, directory));
481 	}
482 	return (ISC_R_SUCCESS);
483 }
484 
485 void
dst_key_setexternal(dst_key_t * key,bool value)486 dst_key_setexternal(dst_key_t *key, bool value) {
487 	REQUIRE(VALID_KEY(key));
488 
489 	key->external = value;
490 }
491 
492 bool
dst_key_isexternal(dst_key_t * key)493 dst_key_isexternal(dst_key_t *key) {
494 	REQUIRE(VALID_KEY(key));
495 
496 	return (key->external);
497 }
498 
499 void
dst_key_setmodified(dst_key_t * key,bool value)500 dst_key_setmodified(dst_key_t *key, bool value) {
501 	REQUIRE(VALID_KEY(key));
502 
503 	isc_mutex_lock(&key->mdlock);
504 	key->modified = value;
505 	isc_mutex_unlock(&key->mdlock);
506 }
507 
508 bool
dst_key_ismodified(const dst_key_t * key)509 dst_key_ismodified(const dst_key_t *key) {
510 	bool modified;
511 	dst_key_t *k;
512 
513 	REQUIRE(VALID_KEY(key));
514 
515 	DE_CONST(key, k);
516 
517 	isc_mutex_lock(&k->mdlock);
518 	modified = key->modified;
519 	isc_mutex_unlock(&k->mdlock);
520 
521 	return (modified);
522 }
523 
524 isc_result_t
dst_key_getfilename(dns_name_t * name,dns_keytag_t id,unsigned int alg,int type,const char * directory,isc_mem_t * mctx,isc_buffer_t * buf)525 dst_key_getfilename(dns_name_t *name, dns_keytag_t id, unsigned int alg,
526 		    int type, const char *directory, isc_mem_t *mctx,
527 		    isc_buffer_t *buf) {
528 	isc_result_t result;
529 
530 	REQUIRE(dst_initialized);
531 	REQUIRE(dns_name_isabsolute(name));
532 	REQUIRE((type &
533 		 (DST_TYPE_PRIVATE | DST_TYPE_PUBLIC | DST_TYPE_STATE)) != 0);
534 	REQUIRE(mctx != NULL);
535 	REQUIRE(buf != NULL);
536 
537 	CHECKALG(alg);
538 
539 	result = buildfilename(name, id, alg, type, directory, buf);
540 	if (result == ISC_R_SUCCESS) {
541 		if (isc_buffer_availablelength(buf) > 0) {
542 			isc_buffer_putuint8(buf, 0);
543 		} else {
544 			result = ISC_R_NOSPACE;
545 		}
546 	}
547 
548 	return (result);
549 }
550 
551 isc_result_t
dst_key_fromfile(dns_name_t * name,dns_keytag_t id,unsigned int alg,int type,const char * directory,isc_mem_t * mctx,dst_key_t ** keyp)552 dst_key_fromfile(dns_name_t *name, dns_keytag_t id, unsigned int alg, int type,
553 		 const char *directory, isc_mem_t *mctx, dst_key_t **keyp) {
554 	isc_result_t result;
555 	char filename[NAME_MAX];
556 	isc_buffer_t buf;
557 	dst_key_t *key;
558 
559 	REQUIRE(dst_initialized);
560 	REQUIRE(dns_name_isabsolute(name));
561 	REQUIRE((type & (DST_TYPE_PRIVATE | DST_TYPE_PUBLIC)) != 0);
562 	REQUIRE(mctx != NULL);
563 	REQUIRE(keyp != NULL && *keyp == NULL);
564 
565 	CHECKALG(alg);
566 
567 	key = NULL;
568 
569 	isc_buffer_init(&buf, filename, NAME_MAX);
570 	result = dst_key_getfilename(name, id, alg, type, NULL, mctx, &buf);
571 	if (result != ISC_R_SUCCESS) {
572 		goto out;
573 	}
574 
575 	result = dst_key_fromnamedfile(filename, directory, type, mctx, &key);
576 	if (result != ISC_R_SUCCESS) {
577 		goto out;
578 	}
579 
580 	result = computeid(key);
581 	if (result != ISC_R_SUCCESS) {
582 		goto out;
583 	}
584 
585 	if (!dns_name_equal(name, key->key_name) || id != key->key_id ||
586 	    alg != key->key_alg)
587 	{
588 		result = DST_R_INVALIDPRIVATEKEY;
589 		goto out;
590 	}
591 
592 	*keyp = key;
593 	result = ISC_R_SUCCESS;
594 
595 out:
596 	if ((key != NULL) && (result != ISC_R_SUCCESS)) {
597 		dst_key_free(&key);
598 	}
599 
600 	return (result);
601 }
602 
603 isc_result_t
dst_key_fromnamedfile(const char * filename,const char * dirname,int type,isc_mem_t * mctx,dst_key_t ** keyp)604 dst_key_fromnamedfile(const char *filename, const char *dirname, int type,
605 		      isc_mem_t *mctx, dst_key_t **keyp) {
606 	isc_result_t result;
607 	dst_key_t *pubkey = NULL, *key = NULL;
608 	char *newfilename = NULL, *statefilename = NULL;
609 	int newfilenamelen = 0, statefilenamelen = 0;
610 	isc_lex_t *lex = NULL;
611 
612 	REQUIRE(dst_initialized);
613 	REQUIRE(filename != NULL);
614 	REQUIRE((type & (DST_TYPE_PRIVATE | DST_TYPE_PUBLIC)) != 0);
615 	REQUIRE(mctx != NULL);
616 	REQUIRE(keyp != NULL && *keyp == NULL);
617 
618 	/* If an absolute path is specified, don't use the key directory */
619 #ifndef WIN32
620 	if (filename[0] == '/') {
621 		dirname = NULL;
622 	}
623 #else  /* WIN32 */
624 	if (filename[0] == '/' || filename[0] == '\\') {
625 		dirname = NULL;
626 	}
627 #endif /* ifndef WIN32 */
628 
629 	newfilenamelen = strlen(filename) + 5;
630 	if (dirname != NULL) {
631 		newfilenamelen += strlen(dirname) + 1;
632 	}
633 	newfilename = isc_mem_get(mctx, newfilenamelen);
634 	result = addsuffix(newfilename, newfilenamelen, dirname, filename,
635 			   ".key");
636 	INSIST(result == ISC_R_SUCCESS);
637 
638 	RETERR(dst_key_read_public(newfilename, type, mctx, &pubkey));
639 	isc_mem_put(mctx, newfilename, newfilenamelen);
640 
641 	/*
642 	 * Read the state file, if requested by type.
643 	 */
644 	if ((type & DST_TYPE_STATE) != 0) {
645 		statefilenamelen = strlen(filename) + 7;
646 		if (dirname != NULL) {
647 			statefilenamelen += strlen(dirname) + 1;
648 		}
649 		statefilename = isc_mem_get(mctx, statefilenamelen);
650 		result = addsuffix(statefilename, statefilenamelen, dirname,
651 				   filename, ".state");
652 		INSIST(result == ISC_R_SUCCESS);
653 	}
654 
655 	pubkey->kasp = false;
656 	if ((type & DST_TYPE_STATE) != 0) {
657 		result = dst_key_read_state(statefilename, mctx, &pubkey);
658 		if (result == ISC_R_SUCCESS) {
659 			pubkey->kasp = true;
660 		} else if (result == ISC_R_FILENOTFOUND) {
661 			/* Having no state is valid. */
662 			result = ISC_R_SUCCESS;
663 		}
664 		RETERR(result);
665 	}
666 
667 	if ((type & (DST_TYPE_PRIVATE | DST_TYPE_PUBLIC)) == DST_TYPE_PUBLIC ||
668 	    (pubkey->key_flags & DNS_KEYFLAG_TYPEMASK) == DNS_KEYTYPE_NOKEY)
669 	{
670 		RETERR(computeid(pubkey));
671 		pubkey->modified = false;
672 		*keyp = pubkey;
673 		pubkey = NULL;
674 		goto out;
675 	}
676 
677 	RETERR(algorithm_status(pubkey->key_alg));
678 
679 	key = get_key_struct(pubkey->key_name, pubkey->key_alg,
680 			     pubkey->key_flags, pubkey->key_proto,
681 			     pubkey->key_size, pubkey->key_class,
682 			     pubkey->key_ttl, mctx);
683 	if (key == NULL) {
684 		RETERR(ISC_R_NOMEMORY);
685 	}
686 
687 	if (key->func->parse == NULL) {
688 		RETERR(DST_R_UNSUPPORTEDALG);
689 	}
690 
691 	newfilenamelen = strlen(filename) + 9;
692 	if (dirname != NULL) {
693 		newfilenamelen += strlen(dirname) + 1;
694 	}
695 	newfilename = isc_mem_get(mctx, newfilenamelen);
696 	result = addsuffix(newfilename, newfilenamelen, dirname, filename,
697 			   ".private");
698 	INSIST(result == ISC_R_SUCCESS);
699 
700 	RETERR(isc_lex_create(mctx, 1500, &lex));
701 	RETERR(isc_lex_openfile(lex, newfilename));
702 	isc_mem_put(mctx, newfilename, newfilenamelen);
703 
704 	RETERR(key->func->parse(key, lex, pubkey));
705 	isc_lex_destroy(&lex);
706 
707 	key->kasp = false;
708 	if ((type & DST_TYPE_STATE) != 0) {
709 		result = dst_key_read_state(statefilename, mctx, &key);
710 		if (result == ISC_R_SUCCESS) {
711 			key->kasp = true;
712 		} else if (result == ISC_R_FILENOTFOUND) {
713 			/* Having no state is valid. */
714 			result = ISC_R_SUCCESS;
715 		}
716 		RETERR(result);
717 	}
718 
719 	RETERR(computeid(key));
720 
721 	if (pubkey->key_id != key->key_id) {
722 		RETERR(DST_R_INVALIDPRIVATEKEY);
723 	}
724 
725 	key->modified = false;
726 	*keyp = key;
727 	key = NULL;
728 
729 out:
730 	if (pubkey != NULL) {
731 		dst_key_free(&pubkey);
732 	}
733 	if (newfilename != NULL) {
734 		isc_mem_put(mctx, newfilename, newfilenamelen);
735 	}
736 	if (statefilename != NULL) {
737 		isc_mem_put(mctx, statefilename, statefilenamelen);
738 	}
739 	if (lex != NULL) {
740 		isc_lex_destroy(&lex);
741 	}
742 	if (key != NULL) {
743 		dst_key_free(&key);
744 	}
745 	return (result);
746 }
747 
748 isc_result_t
dst_key_todns(const dst_key_t * key,isc_buffer_t * target)749 dst_key_todns(const dst_key_t *key, isc_buffer_t *target) {
750 	REQUIRE(dst_initialized);
751 	REQUIRE(VALID_KEY(key));
752 	REQUIRE(target != NULL);
753 
754 	CHECKALG(key->key_alg);
755 
756 	if (key->func->todns == NULL) {
757 		return (DST_R_UNSUPPORTEDALG);
758 	}
759 
760 	if (isc_buffer_availablelength(target) < 4) {
761 		return (ISC_R_NOSPACE);
762 	}
763 	isc_buffer_putuint16(target, (uint16_t)(key->key_flags & 0xffff));
764 	isc_buffer_putuint8(target, (uint8_t)key->key_proto);
765 	isc_buffer_putuint8(target, (uint8_t)key->key_alg);
766 
767 	if ((key->key_flags & DNS_KEYFLAG_EXTENDED) != 0) {
768 		if (isc_buffer_availablelength(target) < 2) {
769 			return (ISC_R_NOSPACE);
770 		}
771 		isc_buffer_putuint16(
772 			target, (uint16_t)((key->key_flags >> 16) & 0xffff));
773 	}
774 
775 	if (key->keydata.generic == NULL) { /*%< NULL KEY */
776 		return (ISC_R_SUCCESS);
777 	}
778 
779 	return (key->func->todns(key, target));
780 }
781 
782 isc_result_t
dst_key_fromdns(const dns_name_t * name,dns_rdataclass_t rdclass,isc_buffer_t * source,isc_mem_t * mctx,dst_key_t ** keyp)783 dst_key_fromdns(const dns_name_t *name, dns_rdataclass_t rdclass,
784 		isc_buffer_t *source, isc_mem_t *mctx, dst_key_t **keyp) {
785 	uint8_t alg, proto;
786 	uint32_t flags, extflags;
787 	dst_key_t *key = NULL;
788 	dns_keytag_t id, rid;
789 	isc_region_t r;
790 	isc_result_t result;
791 
792 	REQUIRE(dst_initialized);
793 
794 	isc_buffer_remainingregion(source, &r);
795 
796 	if (isc_buffer_remaininglength(source) < 4) {
797 		return (DST_R_INVALIDPUBLICKEY);
798 	}
799 	flags = isc_buffer_getuint16(source);
800 	proto = isc_buffer_getuint8(source);
801 	alg = isc_buffer_getuint8(source);
802 
803 	id = dst_region_computeid(&r);
804 	rid = dst_region_computerid(&r);
805 
806 	if ((flags & DNS_KEYFLAG_EXTENDED) != 0) {
807 		if (isc_buffer_remaininglength(source) < 2) {
808 			return (DST_R_INVALIDPUBLICKEY);
809 		}
810 		extflags = isc_buffer_getuint16(source);
811 		flags |= (extflags << 16);
812 	}
813 
814 	result = frombuffer(name, alg, flags, proto, rdclass, source, mctx,
815 			    &key);
816 	if (result != ISC_R_SUCCESS) {
817 		return (result);
818 	}
819 	key->key_id = id;
820 	key->key_rid = rid;
821 
822 	*keyp = key;
823 	return (ISC_R_SUCCESS);
824 }
825 
826 isc_result_t
dst_key_frombuffer(const dns_name_t * name,unsigned int alg,unsigned int flags,unsigned int protocol,dns_rdataclass_t rdclass,isc_buffer_t * source,isc_mem_t * mctx,dst_key_t ** keyp)827 dst_key_frombuffer(const dns_name_t *name, unsigned int alg, unsigned int flags,
828 		   unsigned int protocol, dns_rdataclass_t rdclass,
829 		   isc_buffer_t *source, isc_mem_t *mctx, dst_key_t **keyp) {
830 	dst_key_t *key = NULL;
831 	isc_result_t result;
832 
833 	REQUIRE(dst_initialized);
834 
835 	result = frombuffer(name, alg, flags, protocol, rdclass, source, mctx,
836 			    &key);
837 	if (result != ISC_R_SUCCESS) {
838 		return (result);
839 	}
840 
841 	result = computeid(key);
842 	if (result != ISC_R_SUCCESS) {
843 		dst_key_free(&key);
844 		return (result);
845 	}
846 
847 	*keyp = key;
848 	return (ISC_R_SUCCESS);
849 }
850 
851 isc_result_t
dst_key_tobuffer(const dst_key_t * key,isc_buffer_t * target)852 dst_key_tobuffer(const dst_key_t *key, isc_buffer_t *target) {
853 	REQUIRE(dst_initialized);
854 	REQUIRE(VALID_KEY(key));
855 	REQUIRE(target != NULL);
856 
857 	CHECKALG(key->key_alg);
858 
859 	if (key->func->todns == NULL) {
860 		return (DST_R_UNSUPPORTEDALG);
861 	}
862 
863 	return (key->func->todns(key, target));
864 }
865 
866 isc_result_t
dst_key_privatefrombuffer(dst_key_t * key,isc_buffer_t * buffer)867 dst_key_privatefrombuffer(dst_key_t *key, isc_buffer_t *buffer) {
868 	isc_lex_t *lex = NULL;
869 	isc_result_t result = ISC_R_SUCCESS;
870 
871 	REQUIRE(dst_initialized);
872 	REQUIRE(VALID_KEY(key));
873 	REQUIRE(!dst_key_isprivate(key));
874 	REQUIRE(buffer != NULL);
875 
876 	if (key->func->parse == NULL) {
877 		RETERR(DST_R_UNSUPPORTEDALG);
878 	}
879 
880 	RETERR(isc_lex_create(key->mctx, 1500, &lex));
881 	RETERR(isc_lex_openbuffer(lex, buffer));
882 	RETERR(key->func->parse(key, lex, NULL));
883 out:
884 	if (lex != NULL) {
885 		isc_lex_destroy(&lex);
886 	}
887 	return (result);
888 }
889 
890 dns_gss_ctx_id_t
dst_key_getgssctx(const dst_key_t * key)891 dst_key_getgssctx(const dst_key_t *key) {
892 	REQUIRE(key != NULL);
893 
894 	return (key->keydata.gssctx);
895 }
896 
897 isc_result_t
dst_key_fromgssapi(const dns_name_t * name,dns_gss_ctx_id_t gssctx,isc_mem_t * mctx,dst_key_t ** keyp,isc_region_t * intoken)898 dst_key_fromgssapi(const dns_name_t *name, dns_gss_ctx_id_t gssctx,
899 		   isc_mem_t *mctx, dst_key_t **keyp, isc_region_t *intoken) {
900 	dst_key_t *key;
901 	isc_result_t result;
902 
903 	REQUIRE(gssctx != NULL);
904 	REQUIRE(keyp != NULL && *keyp == NULL);
905 
906 	key = get_key_struct(name, DST_ALG_GSSAPI, 0, DNS_KEYPROTO_DNSSEC, 0,
907 			     dns_rdataclass_in, 0, mctx);
908 	if (key == NULL) {
909 		return (ISC_R_NOMEMORY);
910 	}
911 
912 	if (intoken != NULL) {
913 		/*
914 		 * Keep the token for use by external ssu rules. They may need
915 		 * to examine the PAC in the kerberos ticket.
916 		 */
917 		isc_buffer_allocate(key->mctx, &key->key_tkeytoken,
918 				    intoken->length);
919 		RETERR(isc_buffer_copyregion(key->key_tkeytoken, intoken));
920 	}
921 
922 	key->keydata.gssctx = gssctx;
923 	*keyp = key;
924 	result = ISC_R_SUCCESS;
925 out:
926 	if (result != ISC_R_SUCCESS) {
927 		dst_key_free(&key);
928 	}
929 	return (result);
930 }
931 
932 isc_result_t
dst_key_buildinternal(const dns_name_t * name,unsigned int alg,unsigned int bits,unsigned int flags,unsigned int protocol,dns_rdataclass_t rdclass,void * data,isc_mem_t * mctx,dst_key_t ** keyp)933 dst_key_buildinternal(const dns_name_t *name, unsigned int alg,
934 		      unsigned int bits, unsigned int flags,
935 		      unsigned int protocol, dns_rdataclass_t rdclass,
936 		      void *data, isc_mem_t *mctx, dst_key_t **keyp) {
937 	dst_key_t *key;
938 	isc_result_t result;
939 
940 	REQUIRE(dst_initialized);
941 	REQUIRE(dns_name_isabsolute(name));
942 	REQUIRE(mctx != NULL);
943 	REQUIRE(keyp != NULL && *keyp == NULL);
944 	REQUIRE(data != NULL);
945 
946 	CHECKALG(alg);
947 
948 	key = get_key_struct(name, alg, flags, protocol, bits, rdclass, 0,
949 			     mctx);
950 	if (key == NULL) {
951 		return (ISC_R_NOMEMORY);
952 	}
953 
954 	key->keydata.generic = data;
955 
956 	result = computeid(key);
957 	if (result != ISC_R_SUCCESS) {
958 		dst_key_free(&key);
959 		return (result);
960 	}
961 
962 	*keyp = key;
963 	return (ISC_R_SUCCESS);
964 }
965 
966 isc_result_t
dst_key_fromlabel(const dns_name_t * name,int alg,unsigned int flags,unsigned int protocol,dns_rdataclass_t rdclass,const char * engine,const char * label,const char * pin,isc_mem_t * mctx,dst_key_t ** keyp)967 dst_key_fromlabel(const dns_name_t *name, int alg, unsigned int flags,
968 		  unsigned int protocol, dns_rdataclass_t rdclass,
969 		  const char *engine, const char *label, const char *pin,
970 		  isc_mem_t *mctx, dst_key_t **keyp) {
971 	dst_key_t *key;
972 	isc_result_t result;
973 
974 	REQUIRE(dst_initialized);
975 	REQUIRE(dns_name_isabsolute(name));
976 	REQUIRE(mctx != NULL);
977 	REQUIRE(keyp != NULL && *keyp == NULL);
978 	REQUIRE(label != NULL);
979 
980 	CHECKALG(alg);
981 
982 	key = get_key_struct(name, alg, flags, protocol, 0, rdclass, 0, mctx);
983 	if (key == NULL) {
984 		return (ISC_R_NOMEMORY);
985 	}
986 
987 	if (key->func->fromlabel == NULL) {
988 		dst_key_free(&key);
989 		return (DST_R_UNSUPPORTEDALG);
990 	}
991 
992 	result = key->func->fromlabel(key, engine, label, pin);
993 	if (result != ISC_R_SUCCESS) {
994 		dst_key_free(&key);
995 		return (result);
996 	}
997 
998 	result = computeid(key);
999 	if (result != ISC_R_SUCCESS) {
1000 		dst_key_free(&key);
1001 		return (result);
1002 	}
1003 
1004 	*keyp = key;
1005 	return (ISC_R_SUCCESS);
1006 }
1007 
1008 isc_result_t
dst_key_generate(const dns_name_t * name,unsigned int alg,unsigned int bits,unsigned int param,unsigned int flags,unsigned int protocol,dns_rdataclass_t rdclass,isc_mem_t * mctx,dst_key_t ** keyp,void (* callback)(int))1009 dst_key_generate(const dns_name_t *name, unsigned int alg, unsigned int bits,
1010 		 unsigned int param, unsigned int flags, unsigned int protocol,
1011 		 dns_rdataclass_t rdclass, isc_mem_t *mctx, dst_key_t **keyp,
1012 		 void (*callback)(int)) {
1013 	dst_key_t *key;
1014 	isc_result_t ret;
1015 
1016 	REQUIRE(dst_initialized);
1017 	REQUIRE(dns_name_isabsolute(name));
1018 	REQUIRE(mctx != NULL);
1019 	REQUIRE(keyp != NULL && *keyp == NULL);
1020 
1021 	CHECKALG(alg);
1022 
1023 	key = get_key_struct(name, alg, flags, protocol, bits, rdclass, 0,
1024 			     mctx);
1025 	if (key == NULL) {
1026 		return (ISC_R_NOMEMORY);
1027 	}
1028 
1029 	if (bits == 0) { /*%< NULL KEY */
1030 		key->key_flags |= DNS_KEYTYPE_NOKEY;
1031 		*keyp = key;
1032 		return (ISC_R_SUCCESS);
1033 	}
1034 
1035 	if (key->func->generate == NULL) {
1036 		dst_key_free(&key);
1037 		return (DST_R_UNSUPPORTEDALG);
1038 	}
1039 
1040 	ret = key->func->generate(key, param, callback);
1041 	if (ret != ISC_R_SUCCESS) {
1042 		dst_key_free(&key);
1043 		return (ret);
1044 	}
1045 
1046 	ret = computeid(key);
1047 	if (ret != ISC_R_SUCCESS) {
1048 		dst_key_free(&key);
1049 		return (ret);
1050 	}
1051 
1052 	*keyp = key;
1053 	return (ISC_R_SUCCESS);
1054 }
1055 
1056 isc_result_t
dst_key_getbool(const dst_key_t * key,int type,bool * valuep)1057 dst_key_getbool(const dst_key_t *key, int type, bool *valuep) {
1058 	dst_key_t *k;
1059 
1060 	REQUIRE(VALID_KEY(key));
1061 	REQUIRE(valuep != NULL);
1062 	REQUIRE(type <= DST_MAX_BOOLEAN);
1063 
1064 	DE_CONST(key, k);
1065 
1066 	isc_mutex_lock(&k->mdlock);
1067 	if (!key->boolset[type]) {
1068 		isc_mutex_unlock(&k->mdlock);
1069 		return (ISC_R_NOTFOUND);
1070 	}
1071 	*valuep = key->bools[type];
1072 	isc_mutex_unlock(&k->mdlock);
1073 
1074 	return (ISC_R_SUCCESS);
1075 }
1076 
1077 void
dst_key_setbool(dst_key_t * key,int type,bool value)1078 dst_key_setbool(dst_key_t *key, int type, bool value) {
1079 	REQUIRE(VALID_KEY(key));
1080 	REQUIRE(type <= DST_MAX_BOOLEAN);
1081 
1082 	isc_mutex_lock(&key->mdlock);
1083 	key->modified = key->modified || !key->boolset[type] ||
1084 			key->bools[type] != value;
1085 	key->bools[type] = value;
1086 	key->boolset[type] = true;
1087 	isc_mutex_unlock(&key->mdlock);
1088 }
1089 
1090 void
dst_key_unsetbool(dst_key_t * key,int type)1091 dst_key_unsetbool(dst_key_t *key, int type) {
1092 	REQUIRE(VALID_KEY(key));
1093 	REQUIRE(type <= DST_MAX_BOOLEAN);
1094 
1095 	isc_mutex_lock(&key->mdlock);
1096 	key->modified = key->modified || key->boolset[type];
1097 	key->boolset[type] = false;
1098 	isc_mutex_unlock(&key->mdlock);
1099 }
1100 
1101 isc_result_t
dst_key_getnum(const dst_key_t * key,int type,uint32_t * valuep)1102 dst_key_getnum(const dst_key_t *key, int type, uint32_t *valuep) {
1103 	dst_key_t *k;
1104 
1105 	REQUIRE(VALID_KEY(key));
1106 	REQUIRE(valuep != NULL);
1107 	REQUIRE(type <= DST_MAX_NUMERIC);
1108 
1109 	DE_CONST(key, k);
1110 
1111 	isc_mutex_lock(&k->mdlock);
1112 	if (!key->numset[type]) {
1113 		isc_mutex_unlock(&k->mdlock);
1114 		return (ISC_R_NOTFOUND);
1115 	}
1116 	*valuep = key->nums[type];
1117 	isc_mutex_unlock(&k->mdlock);
1118 
1119 	return (ISC_R_SUCCESS);
1120 }
1121 
1122 void
dst_key_setnum(dst_key_t * key,int type,uint32_t value)1123 dst_key_setnum(dst_key_t *key, int type, uint32_t value) {
1124 	REQUIRE(VALID_KEY(key));
1125 	REQUIRE(type <= DST_MAX_NUMERIC);
1126 
1127 	isc_mutex_lock(&key->mdlock);
1128 	key->modified = key->modified || !key->numset[type] ||
1129 			key->nums[type] != value;
1130 	key->nums[type] = value;
1131 	key->numset[type] = true;
1132 	isc_mutex_unlock(&key->mdlock);
1133 }
1134 
1135 void
dst_key_unsetnum(dst_key_t * key,int type)1136 dst_key_unsetnum(dst_key_t *key, int type) {
1137 	REQUIRE(VALID_KEY(key));
1138 	REQUIRE(type <= DST_MAX_NUMERIC);
1139 
1140 	isc_mutex_lock(&key->mdlock);
1141 	key->modified = key->modified || key->numset[type];
1142 	key->numset[type] = false;
1143 	isc_mutex_unlock(&key->mdlock);
1144 }
1145 
1146 isc_result_t
dst_key_gettime(const dst_key_t * key,int type,isc_stdtime_t * timep)1147 dst_key_gettime(const dst_key_t *key, int type, isc_stdtime_t *timep) {
1148 	dst_key_t *k;
1149 
1150 	REQUIRE(VALID_KEY(key));
1151 	REQUIRE(timep != NULL);
1152 	REQUIRE(type <= DST_MAX_TIMES);
1153 
1154 	DE_CONST(key, k);
1155 
1156 	isc_mutex_lock(&k->mdlock);
1157 	if (!key->timeset[type]) {
1158 		isc_mutex_unlock(&k->mdlock);
1159 		return (ISC_R_NOTFOUND);
1160 	}
1161 	*timep = key->times[type];
1162 	isc_mutex_unlock(&k->mdlock);
1163 	return (ISC_R_SUCCESS);
1164 }
1165 
1166 void
dst_key_settime(dst_key_t * key,int type,isc_stdtime_t when)1167 dst_key_settime(dst_key_t *key, int type, isc_stdtime_t when) {
1168 	REQUIRE(VALID_KEY(key));
1169 	REQUIRE(type <= DST_MAX_TIMES);
1170 
1171 	isc_mutex_lock(&key->mdlock);
1172 	key->modified = key->modified || !key->timeset[type] ||
1173 			key->times[type] != when;
1174 	key->times[type] = when;
1175 	key->timeset[type] = true;
1176 	isc_mutex_unlock(&key->mdlock);
1177 }
1178 
1179 void
dst_key_unsettime(dst_key_t * key,int type)1180 dst_key_unsettime(dst_key_t *key, int type) {
1181 	REQUIRE(VALID_KEY(key));
1182 	REQUIRE(type <= DST_MAX_TIMES);
1183 
1184 	isc_mutex_lock(&key->mdlock);
1185 	key->modified = key->modified || key->timeset[type];
1186 	key->timeset[type] = false;
1187 	isc_mutex_unlock(&key->mdlock);
1188 }
1189 
1190 isc_result_t
dst_key_getstate(const dst_key_t * key,int type,dst_key_state_t * statep)1191 dst_key_getstate(const dst_key_t *key, int type, dst_key_state_t *statep) {
1192 	dst_key_t *k;
1193 
1194 	REQUIRE(VALID_KEY(key));
1195 	REQUIRE(statep != NULL);
1196 	REQUIRE(type <= DST_MAX_KEYSTATES);
1197 
1198 	DE_CONST(key, k);
1199 
1200 	isc_mutex_lock(&k->mdlock);
1201 	if (!key->keystateset[type]) {
1202 		isc_mutex_unlock(&k->mdlock);
1203 		return (ISC_R_NOTFOUND);
1204 	}
1205 	*statep = key->keystates[type];
1206 	isc_mutex_unlock(&k->mdlock);
1207 
1208 	return (ISC_R_SUCCESS);
1209 }
1210 
1211 void
dst_key_setstate(dst_key_t * key,int type,dst_key_state_t state)1212 dst_key_setstate(dst_key_t *key, int type, dst_key_state_t state) {
1213 	REQUIRE(VALID_KEY(key));
1214 	REQUIRE(type <= DST_MAX_KEYSTATES);
1215 
1216 	isc_mutex_lock(&key->mdlock);
1217 	key->modified = key->modified || !key->keystateset[type] ||
1218 			key->keystates[type] != state;
1219 	key->keystates[type] = state;
1220 	key->keystateset[type] = true;
1221 	isc_mutex_unlock(&key->mdlock);
1222 }
1223 
1224 void
dst_key_unsetstate(dst_key_t * key,int type)1225 dst_key_unsetstate(dst_key_t *key, int type) {
1226 	REQUIRE(VALID_KEY(key));
1227 	REQUIRE(type <= DST_MAX_KEYSTATES);
1228 
1229 	isc_mutex_lock(&key->mdlock);
1230 	key->modified = key->modified || key->keystateset[type];
1231 	key->keystateset[type] = false;
1232 	isc_mutex_unlock(&key->mdlock);
1233 }
1234 
1235 isc_result_t
dst_key_getprivateformat(const dst_key_t * key,int * majorp,int * minorp)1236 dst_key_getprivateformat(const dst_key_t *key, int *majorp, int *minorp) {
1237 	REQUIRE(VALID_KEY(key));
1238 	REQUIRE(majorp != NULL);
1239 	REQUIRE(minorp != NULL);
1240 	*majorp = key->fmt_major;
1241 	*minorp = key->fmt_minor;
1242 	return (ISC_R_SUCCESS);
1243 }
1244 
1245 void
dst_key_setprivateformat(dst_key_t * key,int major,int minor)1246 dst_key_setprivateformat(dst_key_t *key, int major, int minor) {
1247 	REQUIRE(VALID_KEY(key));
1248 	key->fmt_major = major;
1249 	key->fmt_minor = minor;
1250 }
1251 
1252 static bool
comparekeys(const dst_key_t * key1,const dst_key_t * key2,bool match_revoked_key,bool (* compare)(const dst_key_t * key1,const dst_key_t * key2))1253 comparekeys(const dst_key_t *key1, const dst_key_t *key2,
1254 	    bool match_revoked_key,
1255 	    bool (*compare)(const dst_key_t *key1, const dst_key_t *key2)) {
1256 	REQUIRE(dst_initialized);
1257 	REQUIRE(VALID_KEY(key1));
1258 	REQUIRE(VALID_KEY(key2));
1259 
1260 	if (key1 == key2) {
1261 		return (true);
1262 	}
1263 
1264 	if (key1->key_alg != key2->key_alg) {
1265 		return (false);
1266 	}
1267 
1268 	if (key1->key_id != key2->key_id) {
1269 		if (!match_revoked_key) {
1270 			return (false);
1271 		}
1272 		if ((key1->key_flags & DNS_KEYFLAG_REVOKE) ==
1273 		    (key2->key_flags & DNS_KEYFLAG_REVOKE))
1274 		{
1275 			return (false);
1276 		}
1277 		if (key1->key_id != key2->key_rid &&
1278 		    key1->key_rid != key2->key_id)
1279 		{
1280 			return (false);
1281 		}
1282 	}
1283 
1284 	if (compare != NULL) {
1285 		return (compare(key1, key2));
1286 	} else {
1287 		return (false);
1288 	}
1289 }
1290 
1291 /*
1292  * Compares only the public portion of two keys, by converting them
1293  * both to wire format and comparing the results.
1294  */
1295 static bool
pub_compare(const dst_key_t * key1,const dst_key_t * key2)1296 pub_compare(const dst_key_t *key1, const dst_key_t *key2) {
1297 	isc_result_t result;
1298 	unsigned char buf1[DST_KEY_MAXSIZE], buf2[DST_KEY_MAXSIZE];
1299 	isc_buffer_t b1, b2;
1300 	isc_region_t r1, r2;
1301 
1302 	isc_buffer_init(&b1, buf1, sizeof(buf1));
1303 	result = dst_key_todns(key1, &b1);
1304 	if (result != ISC_R_SUCCESS) {
1305 		return (false);
1306 	}
1307 	/* Zero out flags. */
1308 	buf1[0] = buf1[1] = 0;
1309 	if ((key1->key_flags & DNS_KEYFLAG_EXTENDED) != 0) {
1310 		isc_buffer_subtract(&b1, 2);
1311 	}
1312 
1313 	isc_buffer_init(&b2, buf2, sizeof(buf2));
1314 	result = dst_key_todns(key2, &b2);
1315 	if (result != ISC_R_SUCCESS) {
1316 		return (false);
1317 	}
1318 	/* Zero out flags. */
1319 	buf2[0] = buf2[1] = 0;
1320 	if ((key2->key_flags & DNS_KEYFLAG_EXTENDED) != 0) {
1321 		isc_buffer_subtract(&b2, 2);
1322 	}
1323 
1324 	isc_buffer_usedregion(&b1, &r1);
1325 	/* Remove extended flags. */
1326 	if ((key1->key_flags & DNS_KEYFLAG_EXTENDED) != 0) {
1327 		memmove(&buf1[4], &buf1[6], r1.length - 6);
1328 		r1.length -= 2;
1329 	}
1330 
1331 	isc_buffer_usedregion(&b2, &r2);
1332 	/* Remove extended flags. */
1333 	if ((key2->key_flags & DNS_KEYFLAG_EXTENDED) != 0) {
1334 		memmove(&buf2[4], &buf2[6], r2.length - 6);
1335 		r2.length -= 2;
1336 	}
1337 	return (isc_region_compare(&r1, &r2) == 0);
1338 }
1339 
1340 bool
dst_key_compare(const dst_key_t * key1,const dst_key_t * key2)1341 dst_key_compare(const dst_key_t *key1, const dst_key_t *key2) {
1342 	return (comparekeys(key1, key2, false, key1->func->compare));
1343 }
1344 
1345 bool
dst_key_pubcompare(const dst_key_t * key1,const dst_key_t * key2,bool match_revoked_key)1346 dst_key_pubcompare(const dst_key_t *key1, const dst_key_t *key2,
1347 		   bool match_revoked_key) {
1348 	return (comparekeys(key1, key2, match_revoked_key, pub_compare));
1349 }
1350 
1351 bool
dst_key_paramcompare(const dst_key_t * key1,const dst_key_t * key2)1352 dst_key_paramcompare(const dst_key_t *key1, const dst_key_t *key2) {
1353 	REQUIRE(dst_initialized);
1354 	REQUIRE(VALID_KEY(key1));
1355 	REQUIRE(VALID_KEY(key2));
1356 
1357 	if (key1 == key2) {
1358 		return (true);
1359 	}
1360 	if (key1->key_alg == key2->key_alg &&
1361 	    key1->func->paramcompare != NULL &&
1362 	    key1->func->paramcompare(key1, key2))
1363 	{
1364 		return (true);
1365 	} else {
1366 		return (false);
1367 	}
1368 }
1369 
1370 void
dst_key_attach(dst_key_t * source,dst_key_t ** target)1371 dst_key_attach(dst_key_t *source, dst_key_t **target) {
1372 	REQUIRE(dst_initialized);
1373 	REQUIRE(target != NULL && *target == NULL);
1374 	REQUIRE(VALID_KEY(source));
1375 
1376 	isc_refcount_increment(&source->refs);
1377 	*target = source;
1378 }
1379 
1380 void
dst_key_free(dst_key_t ** keyp)1381 dst_key_free(dst_key_t **keyp) {
1382 	REQUIRE(dst_initialized);
1383 	REQUIRE(keyp != NULL && VALID_KEY(*keyp));
1384 	dst_key_t *key = *keyp;
1385 	*keyp = NULL;
1386 
1387 	if (isc_refcount_decrement(&key->refs) == 1) {
1388 		isc_refcount_destroy(&key->refs);
1389 		isc_mem_t *mctx = key->mctx;
1390 		if (key->keydata.generic != NULL) {
1391 			INSIST(key->func->destroy != NULL);
1392 			key->func->destroy(key);
1393 		}
1394 		if (key->engine != NULL) {
1395 			isc_mem_free(mctx, key->engine);
1396 		}
1397 		if (key->label != NULL) {
1398 			isc_mem_free(mctx, key->label);
1399 		}
1400 		dns_name_free(key->key_name, mctx);
1401 		isc_mem_put(mctx, key->key_name, sizeof(dns_name_t));
1402 		if (key->key_tkeytoken) {
1403 			isc_buffer_free(&key->key_tkeytoken);
1404 		}
1405 		isc_mutex_destroy(&key->mdlock);
1406 		isc_safe_memwipe(key, sizeof(*key));
1407 		isc_mem_putanddetach(&mctx, key, sizeof(*key));
1408 	}
1409 }
1410 
1411 bool
dst_key_isprivate(const dst_key_t * key)1412 dst_key_isprivate(const dst_key_t *key) {
1413 	REQUIRE(VALID_KEY(key));
1414 	INSIST(key->func->isprivate != NULL);
1415 	return (key->func->isprivate(key));
1416 }
1417 
1418 isc_result_t
dst_key_buildfilename(const dst_key_t * key,int type,const char * directory,isc_buffer_t * out)1419 dst_key_buildfilename(const dst_key_t *key, int type, const char *directory,
1420 		      isc_buffer_t *out) {
1421 	REQUIRE(VALID_KEY(key));
1422 	REQUIRE(type == DST_TYPE_PRIVATE || type == DST_TYPE_PUBLIC ||
1423 		type == DST_TYPE_STATE || type == 0);
1424 
1425 	return (buildfilename(key->key_name, key->key_id, key->key_alg, type,
1426 			      directory, out));
1427 }
1428 
1429 isc_result_t
dst_key_sigsize(const dst_key_t * key,unsigned int * n)1430 dst_key_sigsize(const dst_key_t *key, unsigned int *n) {
1431 	REQUIRE(dst_initialized);
1432 	REQUIRE(VALID_KEY(key));
1433 	REQUIRE(n != NULL);
1434 
1435 	/* XXXVIX this switch statement is too sparse to gen a jump table. */
1436 	switch (key->key_alg) {
1437 	case DST_ALG_RSASHA1:
1438 	case DST_ALG_NSEC3RSASHA1:
1439 	case DST_ALG_RSASHA256:
1440 	case DST_ALG_RSASHA512:
1441 		*n = (key->key_size + 7) / 8;
1442 		break;
1443 	case DST_ALG_ECDSA256:
1444 		*n = DNS_SIG_ECDSA256SIZE;
1445 		break;
1446 	case DST_ALG_ECDSA384:
1447 		*n = DNS_SIG_ECDSA384SIZE;
1448 		break;
1449 	case DST_ALG_ED25519:
1450 		*n = DNS_SIG_ED25519SIZE;
1451 		break;
1452 	case DST_ALG_ED448:
1453 		*n = DNS_SIG_ED448SIZE;
1454 		break;
1455 	case DST_ALG_HMACMD5:
1456 		*n = isc_md_type_get_size(ISC_MD_MD5);
1457 		break;
1458 	case DST_ALG_HMACSHA1:
1459 		*n = isc_md_type_get_size(ISC_MD_SHA1);
1460 		break;
1461 	case DST_ALG_HMACSHA224:
1462 		*n = isc_md_type_get_size(ISC_MD_SHA224);
1463 		break;
1464 	case DST_ALG_HMACSHA256:
1465 		*n = isc_md_type_get_size(ISC_MD_SHA256);
1466 		break;
1467 	case DST_ALG_HMACSHA384:
1468 		*n = isc_md_type_get_size(ISC_MD_SHA384);
1469 		break;
1470 	case DST_ALG_HMACSHA512:
1471 		*n = isc_md_type_get_size(ISC_MD_SHA512);
1472 		break;
1473 	case DST_ALG_GSSAPI:
1474 		*n = 128; /*%< XXX */
1475 		break;
1476 	case DST_ALG_DH:
1477 	default:
1478 		return (DST_R_UNSUPPORTEDALG);
1479 	}
1480 	return (ISC_R_SUCCESS);
1481 }
1482 
1483 isc_result_t
dst_key_secretsize(const dst_key_t * key,unsigned int * n)1484 dst_key_secretsize(const dst_key_t *key, unsigned int *n) {
1485 	REQUIRE(dst_initialized);
1486 	REQUIRE(VALID_KEY(key));
1487 	REQUIRE(n != NULL);
1488 
1489 	if (key->key_alg == DST_ALG_DH) {
1490 		*n = (key->key_size + 7) / 8;
1491 		return (ISC_R_SUCCESS);
1492 	}
1493 	return (DST_R_UNSUPPORTEDALG);
1494 }
1495 
1496 /*%
1497  * Set the flags on a key, then recompute the key ID
1498  */
1499 isc_result_t
dst_key_setflags(dst_key_t * key,uint32_t flags)1500 dst_key_setflags(dst_key_t *key, uint32_t flags) {
1501 	REQUIRE(VALID_KEY(key));
1502 	key->key_flags = flags;
1503 	return (computeid(key));
1504 }
1505 
1506 void
dst_key_format(const dst_key_t * key,char * cp,unsigned int size)1507 dst_key_format(const dst_key_t *key, char *cp, unsigned int size) {
1508 	char namestr[DNS_NAME_FORMATSIZE];
1509 	char algstr[DNS_NAME_FORMATSIZE];
1510 
1511 	dns_name_format(dst_key_name(key), namestr, sizeof(namestr));
1512 	dns_secalg_format((dns_secalg_t)dst_key_alg(key), algstr,
1513 			  sizeof(algstr));
1514 	snprintf(cp, size, "%s/%s/%d", namestr, algstr, dst_key_id(key));
1515 }
1516 
1517 isc_result_t
dst_key_dump(dst_key_t * key,isc_mem_t * mctx,char ** buffer,int * length)1518 dst_key_dump(dst_key_t *key, isc_mem_t *mctx, char **buffer, int *length) {
1519 	REQUIRE(buffer != NULL && *buffer == NULL);
1520 	REQUIRE(length != NULL && *length == 0);
1521 	REQUIRE(VALID_KEY(key));
1522 
1523 	if (key->func->dump == NULL) {
1524 		return (ISC_R_NOTIMPLEMENTED);
1525 	}
1526 	return (key->func->dump(key, mctx, buffer, length));
1527 }
1528 
1529 isc_result_t
dst_key_restore(dns_name_t * name,unsigned int alg,unsigned int flags,unsigned int protocol,dns_rdataclass_t rdclass,isc_mem_t * mctx,const char * keystr,dst_key_t ** keyp)1530 dst_key_restore(dns_name_t *name, unsigned int alg, unsigned int flags,
1531 		unsigned int protocol, dns_rdataclass_t rdclass,
1532 		isc_mem_t *mctx, const char *keystr, dst_key_t **keyp) {
1533 	isc_result_t result;
1534 	dst_key_t *key;
1535 
1536 	REQUIRE(dst_initialized);
1537 	REQUIRE(keyp != NULL && *keyp == NULL);
1538 
1539 	if (alg >= DST_MAX_ALGS || dst_t_func[alg] == NULL) {
1540 		return (DST_R_UNSUPPORTEDALG);
1541 	}
1542 
1543 	if (dst_t_func[alg]->restore == NULL) {
1544 		return (ISC_R_NOTIMPLEMENTED);
1545 	}
1546 
1547 	key = get_key_struct(name, alg, flags, protocol, 0, rdclass, 0, mctx);
1548 	if (key == NULL) {
1549 		return (ISC_R_NOMEMORY);
1550 	}
1551 
1552 	result = (dst_t_func[alg]->restore)(key, keystr);
1553 	if (result == ISC_R_SUCCESS) {
1554 		*keyp = key;
1555 	} else {
1556 		dst_key_free(&key);
1557 	}
1558 
1559 	return (result);
1560 }
1561 
1562 /***
1563  *** Static methods
1564  ***/
1565 
1566 /*%
1567  * Allocates a key structure and fills in some of the fields.
1568  */
1569 static dst_key_t *
get_key_struct(const dns_name_t * name,unsigned int alg,unsigned int flags,unsigned int protocol,unsigned int bits,dns_rdataclass_t rdclass,dns_ttl_t ttl,isc_mem_t * mctx)1570 get_key_struct(const dns_name_t *name, unsigned int alg, unsigned int flags,
1571 	       unsigned int protocol, unsigned int bits,
1572 	       dns_rdataclass_t rdclass, dns_ttl_t ttl, isc_mem_t *mctx) {
1573 	dst_key_t *key;
1574 	int i;
1575 
1576 	key = isc_mem_get(mctx, sizeof(dst_key_t));
1577 
1578 	memset(key, 0, sizeof(dst_key_t));
1579 
1580 	key->key_name = isc_mem_get(mctx, sizeof(dns_name_t));
1581 
1582 	dns_name_init(key->key_name, NULL);
1583 	dns_name_dup(name, mctx, key->key_name);
1584 
1585 	isc_refcount_init(&key->refs, 1);
1586 	isc_mem_attach(mctx, &key->mctx);
1587 	key->key_alg = alg;
1588 	key->key_flags = flags;
1589 	key->key_proto = protocol;
1590 	key->keydata.generic = NULL;
1591 	key->key_size = bits;
1592 	key->key_class = rdclass;
1593 	key->key_ttl = ttl;
1594 	key->func = dst_t_func[alg];
1595 	key->fmt_major = 0;
1596 	key->fmt_minor = 0;
1597 	for (i = 0; i < (DST_MAX_TIMES + 1); i++) {
1598 		key->times[i] = 0;
1599 		key->timeset[i] = false;
1600 	}
1601 	isc_mutex_init(&key->mdlock);
1602 	key->inactive = false;
1603 	key->magic = KEY_MAGIC;
1604 	return (key);
1605 }
1606 
1607 bool
dst_key_inactive(const dst_key_t * key)1608 dst_key_inactive(const dst_key_t *key) {
1609 	REQUIRE(VALID_KEY(key));
1610 
1611 	return (key->inactive);
1612 }
1613 
1614 void
dst_key_setinactive(dst_key_t * key,bool inactive)1615 dst_key_setinactive(dst_key_t *key, bool inactive) {
1616 	REQUIRE(VALID_KEY(key));
1617 
1618 	key->inactive = inactive;
1619 }
1620 
1621 /*%
1622  * Reads a public key from disk.
1623  */
1624 isc_result_t
dst_key_read_public(const char * filename,int type,isc_mem_t * mctx,dst_key_t ** keyp)1625 dst_key_read_public(const char *filename, int type, isc_mem_t *mctx,
1626 		    dst_key_t **keyp) {
1627 	u_char rdatabuf[DST_KEY_MAXSIZE];
1628 	isc_buffer_t b;
1629 	dns_fixedname_t name;
1630 	isc_lex_t *lex = NULL;
1631 	isc_token_t token;
1632 	isc_result_t ret;
1633 	dns_rdata_t rdata = DNS_RDATA_INIT;
1634 	unsigned int opt = ISC_LEXOPT_DNSMULTILINE;
1635 	dns_rdataclass_t rdclass = dns_rdataclass_in;
1636 	isc_lexspecials_t specials;
1637 	uint32_t ttl = 0;
1638 	isc_result_t result;
1639 	dns_rdatatype_t keytype;
1640 
1641 	/*
1642 	 * Open the file and read its formatted contents
1643 	 * File format:
1644 	 *    domain.name [ttl] [class] [KEY|DNSKEY] <flags> <protocol>
1645 	 * <algorithm> <key>
1646 	 */
1647 
1648 	/* 1500 should be large enough for any key */
1649 	ret = isc_lex_create(mctx, 1500, &lex);
1650 	if (ret != ISC_R_SUCCESS) {
1651 		goto cleanup;
1652 	}
1653 
1654 	memset(specials, 0, sizeof(specials));
1655 	specials['('] = 1;
1656 	specials[')'] = 1;
1657 	specials['"'] = 1;
1658 	isc_lex_setspecials(lex, specials);
1659 	isc_lex_setcomments(lex, ISC_LEXCOMMENT_DNSMASTERFILE);
1660 
1661 	ret = isc_lex_openfile(lex, filename);
1662 	if (ret != ISC_R_SUCCESS) {
1663 		goto cleanup;
1664 	}
1665 
1666 	/* Read the domain name */
1667 	NEXTTOKEN(lex, opt, &token);
1668 	if (token.type != isc_tokentype_string) {
1669 		BADTOKEN();
1670 	}
1671 
1672 	/*
1673 	 * We don't support "@" in .key files.
1674 	 */
1675 	if (!strcmp(DST_AS_STR(token), "@")) {
1676 		BADTOKEN();
1677 	}
1678 
1679 	dns_fixedname_init(&name);
1680 	isc_buffer_init(&b, DST_AS_STR(token), strlen(DST_AS_STR(token)));
1681 	isc_buffer_add(&b, strlen(DST_AS_STR(token)));
1682 	ret = dns_name_fromtext(dns_fixedname_name(&name), &b, dns_rootname, 0,
1683 				NULL);
1684 	if (ret != ISC_R_SUCCESS) {
1685 		goto cleanup;
1686 	}
1687 
1688 	/* Read the next word: either TTL, class, or 'KEY' */
1689 	NEXTTOKEN(lex, opt, &token);
1690 
1691 	if (token.type != isc_tokentype_string) {
1692 		BADTOKEN();
1693 	}
1694 
1695 	/* If it's a TTL, read the next one */
1696 	result = dns_ttl_fromtext(&token.value.as_textregion, &ttl);
1697 	if (result == ISC_R_SUCCESS) {
1698 		NEXTTOKEN(lex, opt, &token);
1699 	}
1700 
1701 	if (token.type != isc_tokentype_string) {
1702 		BADTOKEN();
1703 	}
1704 
1705 	ret = dns_rdataclass_fromtext(&rdclass, &token.value.as_textregion);
1706 	if (ret == ISC_R_SUCCESS) {
1707 		NEXTTOKEN(lex, opt, &token);
1708 	}
1709 
1710 	if (token.type != isc_tokentype_string) {
1711 		BADTOKEN();
1712 	}
1713 
1714 	if (strcasecmp(DST_AS_STR(token), "DNSKEY") == 0) {
1715 		keytype = dns_rdatatype_dnskey;
1716 	} else if (strcasecmp(DST_AS_STR(token), "KEY") == 0) {
1717 		keytype = dns_rdatatype_key; /*%< SIG(0), TKEY */
1718 	} else {
1719 		BADTOKEN();
1720 	}
1721 
1722 	if (((type & DST_TYPE_KEY) != 0 && keytype != dns_rdatatype_key) ||
1723 	    ((type & DST_TYPE_KEY) == 0 && keytype != dns_rdatatype_dnskey))
1724 	{
1725 		ret = DST_R_BADKEYTYPE;
1726 		goto cleanup;
1727 	}
1728 
1729 	isc_buffer_init(&b, rdatabuf, sizeof(rdatabuf));
1730 	ret = dns_rdata_fromtext(&rdata, rdclass, keytype, lex, NULL, false,
1731 				 mctx, &b, NULL);
1732 	if (ret != ISC_R_SUCCESS) {
1733 		goto cleanup;
1734 	}
1735 
1736 	ret = dst_key_fromdns(dns_fixedname_name(&name), rdclass, &b, mctx,
1737 			      keyp);
1738 	if (ret != ISC_R_SUCCESS) {
1739 		goto cleanup;
1740 	}
1741 
1742 	dst_key_setttl(*keyp, ttl);
1743 
1744 cleanup:
1745 	if (lex != NULL) {
1746 		isc_lex_destroy(&lex);
1747 	}
1748 	return (ret);
1749 }
1750 
1751 static int
find_metadata(const char * s,const char * tags[],int ntags)1752 find_metadata(const char *s, const char *tags[], int ntags) {
1753 	for (int i = 0; i < ntags; i++) {
1754 		if (tags[i] != NULL && strcasecmp(s, tags[i]) == 0) {
1755 			return (i);
1756 		}
1757 	}
1758 	return (-1);
1759 }
1760 
1761 static int
find_numericdata(const char * s)1762 find_numericdata(const char *s) {
1763 	return (find_metadata(s, numerictags, NUMERIC_NTAGS));
1764 }
1765 
1766 static int
find_booleandata(const char * s)1767 find_booleandata(const char *s) {
1768 	return (find_metadata(s, booleantags, BOOLEAN_NTAGS));
1769 }
1770 
1771 static int
find_timingdata(const char * s)1772 find_timingdata(const char *s) {
1773 	return (find_metadata(s, timingtags, TIMING_NTAGS));
1774 }
1775 
1776 static int
find_keystatedata(const char * s)1777 find_keystatedata(const char *s) {
1778 	return (find_metadata(s, keystatestags, KEYSTATES_NTAGS));
1779 }
1780 
1781 static isc_result_t
keystate_fromtext(const char * s,dst_key_state_t * state)1782 keystate_fromtext(const char *s, dst_key_state_t *state) {
1783 	for (int i = 0; i < KEYSTATES_NVALUES; i++) {
1784 		if (keystates[i] != NULL && strcasecmp(s, keystates[i]) == 0) {
1785 			*state = (dst_key_state_t)i;
1786 			return (ISC_R_SUCCESS);
1787 		}
1788 	}
1789 	return (ISC_R_NOTFOUND);
1790 }
1791 
1792 /*%
1793  * Reads a key state from disk.
1794  */
1795 isc_result_t
dst_key_read_state(const char * filename,isc_mem_t * mctx,dst_key_t ** keyp)1796 dst_key_read_state(const char *filename, isc_mem_t *mctx, dst_key_t **keyp) {
1797 	isc_lex_t *lex = NULL;
1798 	isc_token_t token;
1799 	isc_result_t ret;
1800 	unsigned int opt = ISC_LEXOPT_EOL;
1801 
1802 	ret = isc_lex_create(mctx, 1500, &lex);
1803 	if (ret != ISC_R_SUCCESS) {
1804 		goto cleanup;
1805 	}
1806 	isc_lex_setcomments(lex, ISC_LEXCOMMENT_DNSMASTERFILE);
1807 
1808 	ret = isc_lex_openfile(lex, filename);
1809 	if (ret != ISC_R_SUCCESS) {
1810 		goto cleanup;
1811 	}
1812 
1813 	/*
1814 	 * Read the comment line.
1815 	 */
1816 	READLINE(lex, opt, &token);
1817 
1818 	/*
1819 	 * Read the algorithm line.
1820 	 */
1821 	NEXTTOKEN(lex, opt, &token);
1822 	if (token.type != isc_tokentype_string ||
1823 	    strcmp(DST_AS_STR(token), STATE_ALGORITHM_STR) != 0)
1824 	{
1825 		BADTOKEN();
1826 	}
1827 
1828 	NEXTTOKEN(lex, opt | ISC_LEXOPT_NUMBER, &token);
1829 	if (token.type != isc_tokentype_number ||
1830 	    token.value.as_ulong != (unsigned long)dst_key_alg(*keyp))
1831 	{
1832 		BADTOKEN();
1833 	}
1834 
1835 	READLINE(lex, opt, &token);
1836 
1837 	/*
1838 	 * Read the length line.
1839 	 */
1840 	NEXTTOKEN(lex, opt, &token);
1841 	if (token.type != isc_tokentype_string ||
1842 	    strcmp(DST_AS_STR(token), STATE_LENGTH_STR) != 0)
1843 	{
1844 		BADTOKEN();
1845 	}
1846 
1847 	NEXTTOKEN(lex, opt | ISC_LEXOPT_NUMBER, &token);
1848 	if (token.type != isc_tokentype_number ||
1849 	    token.value.as_ulong != (unsigned long)dst_key_size(*keyp))
1850 	{
1851 		BADTOKEN();
1852 	}
1853 
1854 	READLINE(lex, opt, &token);
1855 
1856 	/*
1857 	 * Read the metadata.
1858 	 */
1859 	for (int n = 0; n < MAX_NTAGS; n++) {
1860 		int tag;
1861 
1862 		NEXTTOKEN_OR_EOF(lex, opt, &token);
1863 		if (ret == ISC_R_EOF) {
1864 			break;
1865 		}
1866 		if (token.type != isc_tokentype_string) {
1867 			BADTOKEN();
1868 		}
1869 
1870 		/* Numeric metadata */
1871 		tag = find_numericdata(DST_AS_STR(token));
1872 		if (tag >= 0) {
1873 			INSIST(tag < NUMERIC_NTAGS);
1874 
1875 			NEXTTOKEN(lex, opt | ISC_LEXOPT_NUMBER, &token);
1876 			if (token.type != isc_tokentype_number) {
1877 				BADTOKEN();
1878 			}
1879 
1880 			dst_key_setnum(*keyp, tag, token.value.as_ulong);
1881 			goto next;
1882 		}
1883 
1884 		/* Boolean metadata */
1885 		tag = find_booleandata(DST_AS_STR(token));
1886 		if (tag >= 0) {
1887 			INSIST(tag < BOOLEAN_NTAGS);
1888 
1889 			NEXTTOKEN(lex, opt, &token);
1890 			if (token.type != isc_tokentype_string) {
1891 				BADTOKEN();
1892 			}
1893 
1894 			if (strcmp(DST_AS_STR(token), "yes") == 0) {
1895 				dst_key_setbool(*keyp, tag, true);
1896 			} else if (strcmp(DST_AS_STR(token), "no") == 0) {
1897 				dst_key_setbool(*keyp, tag, false);
1898 			} else {
1899 				BADTOKEN();
1900 			}
1901 			goto next;
1902 		}
1903 
1904 		/* Timing metadata */
1905 		tag = find_timingdata(DST_AS_STR(token));
1906 		if (tag >= 0) {
1907 			uint32_t when;
1908 
1909 			INSIST(tag < TIMING_NTAGS);
1910 
1911 			NEXTTOKEN(lex, opt, &token);
1912 			if (token.type != isc_tokentype_string) {
1913 				BADTOKEN();
1914 			}
1915 
1916 			ret = dns_time32_fromtext(DST_AS_STR(token), &when);
1917 			if (ret != ISC_R_SUCCESS) {
1918 				goto cleanup;
1919 			}
1920 
1921 			dst_key_settime(*keyp, tag, when);
1922 			goto next;
1923 		}
1924 
1925 		/* Keystate metadata */
1926 		tag = find_keystatedata(DST_AS_STR(token));
1927 		if (tag >= 0) {
1928 			dst_key_state_t state;
1929 
1930 			INSIST(tag < KEYSTATES_NTAGS);
1931 
1932 			NEXTTOKEN(lex, opt, &token);
1933 			if (token.type != isc_tokentype_string) {
1934 				BADTOKEN();
1935 			}
1936 
1937 			ret = keystate_fromtext(DST_AS_STR(token), &state);
1938 			if (ret != ISC_R_SUCCESS) {
1939 				goto cleanup;
1940 			}
1941 
1942 			dst_key_setstate(*keyp, tag, state);
1943 			goto next;
1944 		}
1945 
1946 	next:
1947 		READLINE(lex, opt, &token);
1948 	}
1949 
1950 	/* Done, successfully parsed the whole file. */
1951 	ret = ISC_R_SUCCESS;
1952 
1953 cleanup:
1954 	if (lex != NULL) {
1955 		isc_lex_destroy(&lex);
1956 	}
1957 	return (ret);
1958 }
1959 
1960 static bool
issymmetric(const dst_key_t * key)1961 issymmetric(const dst_key_t *key) {
1962 	REQUIRE(dst_initialized);
1963 	REQUIRE(VALID_KEY(key));
1964 
1965 	/* XXXVIX this switch statement is too sparse to gen a jump table. */
1966 	switch (key->key_alg) {
1967 	case DST_ALG_RSASHA1:
1968 	case DST_ALG_NSEC3RSASHA1:
1969 	case DST_ALG_RSASHA256:
1970 	case DST_ALG_RSASHA512:
1971 	case DST_ALG_DH:
1972 	case DST_ALG_ECDSA256:
1973 	case DST_ALG_ECDSA384:
1974 	case DST_ALG_ED25519:
1975 	case DST_ALG_ED448:
1976 		return (false);
1977 	case DST_ALG_HMACMD5:
1978 	case DST_ALG_HMACSHA1:
1979 	case DST_ALG_HMACSHA224:
1980 	case DST_ALG_HMACSHA256:
1981 	case DST_ALG_HMACSHA384:
1982 	case DST_ALG_HMACSHA512:
1983 	case DST_ALG_GSSAPI:
1984 		return (true);
1985 	default:
1986 		return (false);
1987 	}
1988 }
1989 
1990 /*%
1991  * Write key boolean metadata to a file pointer, preceded by 'tag'
1992  */
1993 static void
printbool(const dst_key_t * key,int type,const char * tag,FILE * stream)1994 printbool(const dst_key_t *key, int type, const char *tag, FILE *stream) {
1995 	isc_result_t result;
1996 	bool value = 0;
1997 
1998 	result = dst_key_getbool(key, type, &value);
1999 	if (result != ISC_R_SUCCESS) {
2000 		return;
2001 	}
2002 	fprintf(stream, "%s: %s\n", tag, value ? "yes" : "no");
2003 }
2004 
2005 /*%
2006  * Write key numeric metadata to a file pointer, preceded by 'tag'
2007  */
2008 static void
printnum(const dst_key_t * key,int type,const char * tag,FILE * stream)2009 printnum(const dst_key_t *key, int type, const char *tag, FILE *stream) {
2010 	isc_result_t result;
2011 	uint32_t value = 0;
2012 
2013 	result = dst_key_getnum(key, type, &value);
2014 	if (result != ISC_R_SUCCESS) {
2015 		return;
2016 	}
2017 	fprintf(stream, "%s: %u\n", tag, value);
2018 }
2019 
2020 /*%
2021  * Write key timing metadata to a file pointer, preceded by 'tag'
2022  */
2023 static void
printtime(const dst_key_t * key,int type,const char * tag,FILE * stream)2024 printtime(const dst_key_t *key, int type, const char *tag, FILE *stream) {
2025 	isc_result_t result;
2026 	char output[26]; /* Minimum buffer as per ctime_r() specification. */
2027 	isc_stdtime_t when;
2028 	char utc[sizeof("YYYYMMDDHHSSMM")];
2029 	isc_buffer_t b;
2030 	isc_region_t r;
2031 
2032 	result = dst_key_gettime(key, type, &when);
2033 	if (result == ISC_R_NOTFOUND) {
2034 		return;
2035 	}
2036 
2037 	isc_stdtime_tostring(when, output, sizeof(output));
2038 	isc_buffer_init(&b, utc, sizeof(utc));
2039 	result = dns_time32_totext(when, &b);
2040 	if (result != ISC_R_SUCCESS) {
2041 		goto error;
2042 	}
2043 
2044 	isc_buffer_usedregion(&b, &r);
2045 	fprintf(stream, "%s: %.*s (%s)\n", tag, (int)r.length, r.base, output);
2046 	return;
2047 
2048 error:
2049 	fprintf(stream, "%s: (set, unable to display)\n", tag);
2050 }
2051 
2052 /*%
2053  * Write key state metadata to a file pointer, preceded by 'tag'
2054  */
2055 static void
printstate(const dst_key_t * key,int type,const char * tag,FILE * stream)2056 printstate(const dst_key_t *key, int type, const char *tag, FILE *stream) {
2057 	isc_result_t result;
2058 	dst_key_state_t value = 0;
2059 
2060 	result = dst_key_getstate(key, type, &value);
2061 	if (result != ISC_R_SUCCESS) {
2062 		return;
2063 	}
2064 	fprintf(stream, "%s: %s\n", tag, keystates[value]);
2065 }
2066 
2067 /*%
2068  * Writes a key state to disk.
2069  */
2070 static isc_result_t
write_key_state(const dst_key_t * key,int type,const char * directory)2071 write_key_state(const dst_key_t *key, int type, const char *directory) {
2072 	FILE *fp;
2073 	isc_buffer_t fileb;
2074 	char filename[NAME_MAX];
2075 	isc_result_t ret;
2076 	isc_fsaccess_t access;
2077 
2078 	REQUIRE(VALID_KEY(key));
2079 
2080 	/*
2081 	 * Make the filename.
2082 	 */
2083 	isc_buffer_init(&fileb, filename, sizeof(filename));
2084 	ret = dst_key_buildfilename(key, DST_TYPE_STATE, directory, &fileb);
2085 	if (ret != ISC_R_SUCCESS) {
2086 		return (ret);
2087 	}
2088 
2089 	/*
2090 	 * Create public key file.
2091 	 */
2092 	if ((fp = fopen(filename, "w")) == NULL) {
2093 		return (DST_R_WRITEERROR);
2094 	}
2095 
2096 	if (issymmetric(key)) {
2097 		access = 0;
2098 		isc_fsaccess_add(ISC_FSACCESS_OWNER,
2099 				 ISC_FSACCESS_READ | ISC_FSACCESS_WRITE,
2100 				 &access);
2101 		(void)isc_fsaccess_set(filename, access);
2102 	}
2103 
2104 	/* Write key state */
2105 	if ((type & DST_TYPE_KEY) == 0) {
2106 		fprintf(fp, "; This is the state of key %d, for ", key->key_id);
2107 		ret = dns_name_print(key->key_name, fp);
2108 		if (ret != ISC_R_SUCCESS) {
2109 			fclose(fp);
2110 			return (ret);
2111 		}
2112 		fputc('\n', fp);
2113 
2114 		fprintf(fp, "Algorithm: %u\n", key->key_alg);
2115 		fprintf(fp, "Length: %u\n", key->key_size);
2116 
2117 		printnum(key, DST_NUM_LIFETIME, "Lifetime", fp);
2118 		printnum(key, DST_NUM_PREDECESSOR, "Predecessor", fp);
2119 		printnum(key, DST_NUM_SUCCESSOR, "Successor", fp);
2120 
2121 		printbool(key, DST_BOOL_KSK, "KSK", fp);
2122 		printbool(key, DST_BOOL_ZSK, "ZSK", fp);
2123 
2124 		printtime(key, DST_TIME_CREATED, "Generated", fp);
2125 		printtime(key, DST_TIME_PUBLISH, "Published", fp);
2126 		printtime(key, DST_TIME_ACTIVATE, "Active", fp);
2127 		printtime(key, DST_TIME_INACTIVE, "Retired", fp);
2128 		printtime(key, DST_TIME_REVOKE, "Revoked", fp);
2129 		printtime(key, DST_TIME_DELETE, "Removed", fp);
2130 		printtime(key, DST_TIME_DSPUBLISH, "DSPublish", fp);
2131 		printtime(key, DST_TIME_DSDELETE, "DSRemoved", fp);
2132 		printtime(key, DST_TIME_SYNCPUBLISH, "PublishCDS", fp);
2133 		printtime(key, DST_TIME_SYNCDELETE, "DeleteCDS", fp);
2134 
2135 		printnum(key, DST_NUM_DSPUBCOUNT, "DSPubCount", fp);
2136 		printnum(key, DST_NUM_DSDELCOUNT, "DSDelCount", fp);
2137 
2138 		printtime(key, DST_TIME_DNSKEY, "DNSKEYChange", fp);
2139 		printtime(key, DST_TIME_ZRRSIG, "ZRRSIGChange", fp);
2140 		printtime(key, DST_TIME_KRRSIG, "KRRSIGChange", fp);
2141 		printtime(key, DST_TIME_DS, "DSChange", fp);
2142 
2143 		printstate(key, DST_KEY_DNSKEY, "DNSKEYState", fp);
2144 		printstate(key, DST_KEY_ZRRSIG, "ZRRSIGState", fp);
2145 		printstate(key, DST_KEY_KRRSIG, "KRRSIGState", fp);
2146 		printstate(key, DST_KEY_DS, "DSState", fp);
2147 		printstate(key, DST_KEY_GOAL, "GoalState", fp);
2148 	}
2149 
2150 	fflush(fp);
2151 	if (ferror(fp)) {
2152 		ret = DST_R_WRITEERROR;
2153 	}
2154 	fclose(fp);
2155 
2156 	return (ret);
2157 }
2158 
2159 /*%
2160  * Writes a public key to disk in DNS format.
2161  */
2162 static isc_result_t
write_public_key(const dst_key_t * key,int type,const char * directory)2163 write_public_key(const dst_key_t *key, int type, const char *directory) {
2164 	FILE *fp;
2165 	isc_buffer_t keyb, textb, fileb, classb;
2166 	isc_region_t r;
2167 	char filename[NAME_MAX];
2168 	unsigned char key_array[DST_KEY_MAXSIZE];
2169 	char text_array[DST_KEY_MAXTEXTSIZE];
2170 	char class_array[10];
2171 	isc_result_t ret;
2172 	dns_rdata_t rdata = DNS_RDATA_INIT;
2173 	isc_fsaccess_t access;
2174 
2175 	REQUIRE(VALID_KEY(key));
2176 
2177 	isc_buffer_init(&keyb, key_array, sizeof(key_array));
2178 	isc_buffer_init(&textb, text_array, sizeof(text_array));
2179 	isc_buffer_init(&classb, class_array, sizeof(class_array));
2180 
2181 	ret = dst_key_todns(key, &keyb);
2182 	if (ret != ISC_R_SUCCESS) {
2183 		return (ret);
2184 	}
2185 
2186 	isc_buffer_usedregion(&keyb, &r);
2187 	dns_rdata_fromregion(&rdata, key->key_class, dns_rdatatype_dnskey, &r);
2188 
2189 	ret = dns_rdata_totext(&rdata, (dns_name_t *)NULL, &textb);
2190 	if (ret != ISC_R_SUCCESS) {
2191 		return (DST_R_INVALIDPUBLICKEY);
2192 	}
2193 
2194 	ret = dns_rdataclass_totext(key->key_class, &classb);
2195 	if (ret != ISC_R_SUCCESS) {
2196 		return (DST_R_INVALIDPUBLICKEY);
2197 	}
2198 
2199 	/*
2200 	 * Make the filename.
2201 	 */
2202 	isc_buffer_init(&fileb, filename, sizeof(filename));
2203 	ret = dst_key_buildfilename(key, DST_TYPE_PUBLIC, directory, &fileb);
2204 	if (ret != ISC_R_SUCCESS) {
2205 		return (ret);
2206 	}
2207 
2208 	/*
2209 	 * Create public key file.
2210 	 */
2211 	if ((fp = fopen(filename, "w")) == NULL) {
2212 		return (DST_R_WRITEERROR);
2213 	}
2214 
2215 	if (issymmetric(key)) {
2216 		access = 0;
2217 		isc_fsaccess_add(ISC_FSACCESS_OWNER,
2218 				 ISC_FSACCESS_READ | ISC_FSACCESS_WRITE,
2219 				 &access);
2220 		(void)isc_fsaccess_set(filename, access);
2221 	}
2222 
2223 	/* Write key information in comments */
2224 	if ((type & DST_TYPE_KEY) == 0) {
2225 		fprintf(fp, "; This is a %s%s-signing key, keyid %d, for ",
2226 			(key->key_flags & DNS_KEYFLAG_REVOKE) != 0 ? "revoked "
2227 								   : "",
2228 			(key->key_flags & DNS_KEYFLAG_KSK) != 0 ? "key"
2229 								: "zone",
2230 			key->key_id);
2231 		ret = dns_name_print(key->key_name, fp);
2232 		if (ret != ISC_R_SUCCESS) {
2233 			fclose(fp);
2234 			return (ret);
2235 		}
2236 		fputc('\n', fp);
2237 
2238 		printtime(key, DST_TIME_CREATED, "; Created", fp);
2239 		printtime(key, DST_TIME_PUBLISH, "; Publish", fp);
2240 		printtime(key, DST_TIME_ACTIVATE, "; Activate", fp);
2241 		printtime(key, DST_TIME_REVOKE, "; Revoke", fp);
2242 		printtime(key, DST_TIME_INACTIVE, "; Inactive", fp);
2243 		printtime(key, DST_TIME_DELETE, "; Delete", fp);
2244 		printtime(key, DST_TIME_SYNCPUBLISH, "; SyncPublish", fp);
2245 		printtime(key, DST_TIME_SYNCDELETE, "; SyncDelete", fp);
2246 	}
2247 
2248 	/* Now print the actual key */
2249 	ret = dns_name_print(key->key_name, fp);
2250 	fprintf(fp, " ");
2251 
2252 	if (key->key_ttl != 0) {
2253 		fprintf(fp, "%u ", key->key_ttl);
2254 	}
2255 
2256 	isc_buffer_usedregion(&classb, &r);
2257 	if ((unsigned)fwrite(r.base, 1, r.length, fp) != r.length) {
2258 		ret = DST_R_WRITEERROR;
2259 	}
2260 
2261 	if ((type & DST_TYPE_KEY) != 0) {
2262 		fprintf(fp, " KEY ");
2263 	} else {
2264 		fprintf(fp, " DNSKEY ");
2265 	}
2266 
2267 	isc_buffer_usedregion(&textb, &r);
2268 	if ((unsigned)fwrite(r.base, 1, r.length, fp) != r.length) {
2269 		ret = DST_R_WRITEERROR;
2270 	}
2271 
2272 	fputc('\n', fp);
2273 	fflush(fp);
2274 	if (ferror(fp)) {
2275 		ret = DST_R_WRITEERROR;
2276 	}
2277 	fclose(fp);
2278 
2279 	return (ret);
2280 }
2281 
2282 static isc_result_t
buildfilename(dns_name_t * name,dns_keytag_t id,unsigned int alg,unsigned int type,const char * directory,isc_buffer_t * out)2283 buildfilename(dns_name_t *name, dns_keytag_t id, unsigned int alg,
2284 	      unsigned int type, const char *directory, isc_buffer_t *out) {
2285 	const char *suffix = "";
2286 	isc_result_t result;
2287 
2288 	REQUIRE(out != NULL);
2289 	if ((type & DST_TYPE_PRIVATE) != 0) {
2290 		suffix = ".private";
2291 	} else if ((type & DST_TYPE_PUBLIC) != 0) {
2292 		suffix = ".key";
2293 	} else if ((type & DST_TYPE_STATE) != 0) {
2294 		suffix = ".state";
2295 	}
2296 
2297 	if (directory != NULL) {
2298 		if (isc_buffer_availablelength(out) < strlen(directory)) {
2299 			return (ISC_R_NOSPACE);
2300 		}
2301 		isc_buffer_putstr(out, directory);
2302 		if (strlen(directory) > 0U &&
2303 		    directory[strlen(directory) - 1] != '/')
2304 		{
2305 			isc_buffer_putstr(out, "/");
2306 		}
2307 	}
2308 	if (isc_buffer_availablelength(out) < 1) {
2309 		return (ISC_R_NOSPACE);
2310 	}
2311 	isc_buffer_putstr(out, "K");
2312 	result = dns_name_tofilenametext(name, false, out);
2313 	if (result != ISC_R_SUCCESS) {
2314 		return (result);
2315 	}
2316 
2317 	return (isc_buffer_printf(out, "+%03d+%05d%s", alg, id, suffix));
2318 }
2319 
2320 static isc_result_t
computeid(dst_key_t * key)2321 computeid(dst_key_t *key) {
2322 	isc_buffer_t dnsbuf;
2323 	unsigned char dns_array[DST_KEY_MAXSIZE];
2324 	isc_region_t r;
2325 	isc_result_t ret;
2326 
2327 	isc_buffer_init(&dnsbuf, dns_array, sizeof(dns_array));
2328 	ret = dst_key_todns(key, &dnsbuf);
2329 	if (ret != ISC_R_SUCCESS) {
2330 		return (ret);
2331 	}
2332 
2333 	isc_buffer_usedregion(&dnsbuf, &r);
2334 	key->key_id = dst_region_computeid(&r);
2335 	key->key_rid = dst_region_computerid(&r);
2336 	return (ISC_R_SUCCESS);
2337 }
2338 
2339 static isc_result_t
frombuffer(const dns_name_t * name,unsigned int alg,unsigned int flags,unsigned int protocol,dns_rdataclass_t rdclass,isc_buffer_t * source,isc_mem_t * mctx,dst_key_t ** keyp)2340 frombuffer(const dns_name_t *name, unsigned int alg, unsigned int flags,
2341 	   unsigned int protocol, dns_rdataclass_t rdclass,
2342 	   isc_buffer_t *source, isc_mem_t *mctx, dst_key_t **keyp) {
2343 	dst_key_t *key;
2344 	isc_result_t ret;
2345 
2346 	REQUIRE(dns_name_isabsolute(name));
2347 	REQUIRE(source != NULL);
2348 	REQUIRE(mctx != NULL);
2349 	REQUIRE(keyp != NULL && *keyp == NULL);
2350 
2351 	key = get_key_struct(name, alg, flags, protocol, 0, rdclass, 0, mctx);
2352 	if (key == NULL) {
2353 		return (ISC_R_NOMEMORY);
2354 	}
2355 
2356 	if (isc_buffer_remaininglength(source) > 0) {
2357 		ret = algorithm_status(alg);
2358 		if (ret != ISC_R_SUCCESS) {
2359 			dst_key_free(&key);
2360 			return (ret);
2361 		}
2362 		if (key->func->fromdns == NULL) {
2363 			dst_key_free(&key);
2364 			return (DST_R_UNSUPPORTEDALG);
2365 		}
2366 
2367 		ret = key->func->fromdns(key, source);
2368 		if (ret != ISC_R_SUCCESS) {
2369 			dst_key_free(&key);
2370 			return (ret);
2371 		}
2372 	}
2373 
2374 	*keyp = key;
2375 	return (ISC_R_SUCCESS);
2376 }
2377 
2378 static isc_result_t
algorithm_status(unsigned int alg)2379 algorithm_status(unsigned int alg) {
2380 	REQUIRE(dst_initialized);
2381 
2382 	if (dst_algorithm_supported(alg)) {
2383 		return (ISC_R_SUCCESS);
2384 	}
2385 	return (DST_R_UNSUPPORTEDALG);
2386 }
2387 
2388 static isc_result_t
addsuffix(char * filename,int len,const char * odirname,const char * ofilename,const char * suffix)2389 addsuffix(char *filename, int len, const char *odirname, const char *ofilename,
2390 	  const char *suffix) {
2391 	int olen = strlen(ofilename);
2392 	int n;
2393 
2394 	if (olen > 1 && ofilename[olen - 1] == '.') {
2395 		olen -= 1;
2396 	} else if (olen > 8 && strcmp(ofilename + olen - 8, ".private") == 0) {
2397 		olen -= 8;
2398 	} else if (olen > 4 && strcmp(ofilename + olen - 4, ".key") == 0) {
2399 		olen -= 4;
2400 	}
2401 
2402 	if (odirname == NULL) {
2403 		n = snprintf(filename, len, "%.*s%s", olen, ofilename, suffix);
2404 	} else {
2405 		n = snprintf(filename, len, "%s/%.*s%s", odirname, olen,
2406 			     ofilename, suffix);
2407 	}
2408 	if (n < 0) {
2409 		return (ISC_R_FAILURE);
2410 	}
2411 	if (n >= len) {
2412 		return (ISC_R_NOSPACE);
2413 	}
2414 	return (ISC_R_SUCCESS);
2415 }
2416 
2417 isc_buffer_t *
dst_key_tkeytoken(const dst_key_t * key)2418 dst_key_tkeytoken(const dst_key_t *key) {
2419 	REQUIRE(VALID_KEY(key));
2420 	return (key->key_tkeytoken);
2421 }
2422 
2423 /*
2424  * A key is considered unused if it does not have any timing metadata set
2425  * other than "Created".
2426  *
2427  */
2428 bool
dst_key_is_unused(dst_key_t * key)2429 dst_key_is_unused(dst_key_t *key) {
2430 	isc_stdtime_t val;
2431 	dst_key_state_t st;
2432 	int state_type;
2433 	bool state_type_set;
2434 
2435 	REQUIRE(VALID_KEY(key));
2436 
2437 	/*
2438 	 * None of the key timing metadata, except Created, may be set.  Key
2439 	 * state times may be set only if their respective state is HIDDEN.
2440 	 */
2441 	for (int i = 0; i < DST_MAX_TIMES + 1; i++) {
2442 		state_type_set = false;
2443 
2444 		switch (i) {
2445 		case DST_TIME_CREATED:
2446 			break;
2447 		case DST_TIME_DNSKEY:
2448 			state_type = DST_KEY_DNSKEY;
2449 			state_type_set = true;
2450 			break;
2451 		case DST_TIME_ZRRSIG:
2452 			state_type = DST_KEY_ZRRSIG;
2453 			state_type_set = true;
2454 			break;
2455 		case DST_TIME_KRRSIG:
2456 			state_type = DST_KEY_KRRSIG;
2457 			state_type_set = true;
2458 			break;
2459 		case DST_TIME_DS:
2460 			state_type = DST_KEY_DS;
2461 			state_type_set = true;
2462 			break;
2463 		default:
2464 			break;
2465 		}
2466 
2467 		/* Created is fine. */
2468 		if (i == DST_TIME_CREATED) {
2469 			continue;
2470 		}
2471 		/* No such timing metadata found, that is fine too. */
2472 		if (dst_key_gettime(key, i, &val) == ISC_R_NOTFOUND) {
2473 			continue;
2474 		}
2475 		/*
2476 		 * Found timing metadata and it is not related to key states.
2477 		 * This key is used.
2478 		 */
2479 		if (!state_type_set) {
2480 			return (false);
2481 		}
2482 		/*
2483 		 * If the state is not HIDDEN, the key is in use.
2484 		 * If the state is not set, this is odd and we default to NA.
2485 		 */
2486 		if (dst_key_getstate(key, state_type, &st) != ISC_R_SUCCESS) {
2487 			st = DST_KEY_STATE_NA;
2488 		}
2489 		if (st != DST_KEY_STATE_HIDDEN) {
2490 			return (false);
2491 		}
2492 	}
2493 	/* This key is unused. */
2494 	return (true);
2495 }
2496 
2497 isc_result_t
dst_key_role(dst_key_t * key,bool * ksk,bool * zsk)2498 dst_key_role(dst_key_t *key, bool *ksk, bool *zsk) {
2499 	bool k = false, z = false;
2500 	isc_result_t result, ret = ISC_R_SUCCESS;
2501 
2502 	if (ksk != NULL) {
2503 		result = dst_key_getbool(key, DST_BOOL_KSK, &k);
2504 		if (result == ISC_R_SUCCESS) {
2505 			*ksk = k;
2506 		} else {
2507 			*ksk = ((dst_key_flags(key) & DNS_KEYFLAG_KSK) != 0);
2508 			ret = result;
2509 		}
2510 	}
2511 
2512 	if (zsk != NULL) {
2513 		result = dst_key_getbool(key, DST_BOOL_ZSK, &z);
2514 		if (result == ISC_R_SUCCESS) {
2515 			*zsk = z;
2516 		} else {
2517 			*zsk = ((dst_key_flags(key) & DNS_KEYFLAG_KSK) == 0);
2518 			ret = result;
2519 		}
2520 	}
2521 	return (ret);
2522 }
2523 
2524 /* Hints on key whether it can be published and/or used for signing. */
2525 
2526 bool
dst_key_is_published(dst_key_t * key,isc_stdtime_t now,isc_stdtime_t * publish)2527 dst_key_is_published(dst_key_t *key, isc_stdtime_t now,
2528 		     isc_stdtime_t *publish) {
2529 	dst_key_state_t state;
2530 	isc_result_t result;
2531 	isc_stdtime_t when;
2532 	bool state_ok = true, time_ok = false;
2533 
2534 	REQUIRE(VALID_KEY(key));
2535 
2536 	result = dst_key_gettime(key, DST_TIME_PUBLISH, &when);
2537 	if (result == ISC_R_SUCCESS) {
2538 		*publish = when;
2539 		time_ok = (when <= now);
2540 	}
2541 
2542 	/* Check key states:
2543 	 * If the DNSKEY state is RUMOURED or OMNIPRESENT, it means it
2544 	 * should be published.
2545 	 */
2546 	result = dst_key_getstate(key, DST_KEY_DNSKEY, &state);
2547 	if (result == ISC_R_SUCCESS) {
2548 		state_ok = ((state == DST_KEY_STATE_RUMOURED) ||
2549 			    (state == DST_KEY_STATE_OMNIPRESENT));
2550 		/*
2551 		 * Key states trump timing metadata.
2552 		 * Ignore inactive time.
2553 		 */
2554 		time_ok = true;
2555 	}
2556 
2557 	return (state_ok && time_ok);
2558 }
2559 
2560 bool
dst_key_is_active(dst_key_t * key,isc_stdtime_t now)2561 dst_key_is_active(dst_key_t *key, isc_stdtime_t now) {
2562 	dst_key_state_t state;
2563 	isc_result_t result;
2564 	isc_stdtime_t when = 0;
2565 	bool ksk = false, zsk = false, inactive = false;
2566 	bool ds_ok = true, zrrsig_ok = true, time_ok = false;
2567 
2568 	REQUIRE(VALID_KEY(key));
2569 
2570 	result = dst_key_gettime(key, DST_TIME_INACTIVE, &when);
2571 	if (result == ISC_R_SUCCESS) {
2572 		inactive = (when <= now);
2573 	}
2574 
2575 	result = dst_key_gettime(key, DST_TIME_ACTIVATE, &when);
2576 	if (result == ISC_R_SUCCESS) {
2577 		time_ok = (when <= now);
2578 	}
2579 
2580 	(void)dst_key_role(key, &ksk, &zsk);
2581 
2582 	/* Check key states:
2583 	 * KSK: If the DS is RUMOURED or OMNIPRESENT the key is considered
2584 	 * active.
2585 	 */
2586 	if (ksk) {
2587 		result = dst_key_getstate(key, DST_KEY_DS, &state);
2588 		if (result == ISC_R_SUCCESS) {
2589 			ds_ok = ((state == DST_KEY_STATE_RUMOURED) ||
2590 				 (state == DST_KEY_STATE_OMNIPRESENT));
2591 			/*
2592 			 * Key states trump timing metadata.
2593 			 * Ignore inactive time.
2594 			 */
2595 			time_ok = true;
2596 			inactive = false;
2597 		}
2598 	}
2599 	/*
2600 	 * ZSK: If the ZRRSIG state is RUMOURED or OMNIPRESENT, it means the
2601 	 * key is active.
2602 	 */
2603 	if (zsk) {
2604 		result = dst_key_getstate(key, DST_KEY_ZRRSIG, &state);
2605 		if (result == ISC_R_SUCCESS) {
2606 			zrrsig_ok = ((state == DST_KEY_STATE_RUMOURED) ||
2607 				     (state == DST_KEY_STATE_OMNIPRESENT));
2608 			/*
2609 			 * Key states trump timing metadata.
2610 			 * Ignore inactive time.
2611 			 */
2612 			time_ok = true;
2613 			inactive = false;
2614 		}
2615 	}
2616 	return (ds_ok && zrrsig_ok && time_ok && !inactive);
2617 }
2618 
2619 bool
dst_key_is_signing(dst_key_t * key,int role,isc_stdtime_t now,isc_stdtime_t * active)2620 dst_key_is_signing(dst_key_t *key, int role, isc_stdtime_t now,
2621 		   isc_stdtime_t *active) {
2622 	dst_key_state_t state;
2623 	isc_result_t result;
2624 	isc_stdtime_t when = 0;
2625 	bool ksk = false, zsk = false, inactive = false;
2626 	bool krrsig_ok = true, zrrsig_ok = true, time_ok = false;
2627 
2628 	REQUIRE(VALID_KEY(key));
2629 
2630 	result = dst_key_gettime(key, DST_TIME_INACTIVE, &when);
2631 	if (result == ISC_R_SUCCESS) {
2632 		inactive = (when <= now);
2633 	}
2634 
2635 	result = dst_key_gettime(key, DST_TIME_ACTIVATE, &when);
2636 	if (result == ISC_R_SUCCESS) {
2637 		*active = when;
2638 		time_ok = (when <= now);
2639 	}
2640 
2641 	(void)dst_key_role(key, &ksk, &zsk);
2642 
2643 	/* Check key states:
2644 	 * If the RRSIG state is RUMOURED or OMNIPRESENT, it means the key
2645 	 * is active.
2646 	 */
2647 	if (ksk && role == DST_BOOL_KSK) {
2648 		result = dst_key_getstate(key, DST_KEY_KRRSIG, &state);
2649 		if (result == ISC_R_SUCCESS) {
2650 			krrsig_ok = ((state == DST_KEY_STATE_RUMOURED) ||
2651 				     (state == DST_KEY_STATE_OMNIPRESENT));
2652 			/*
2653 			 * Key states trump timing metadata.
2654 			 * Ignore inactive time.
2655 			 */
2656 			time_ok = true;
2657 			inactive = false;
2658 		}
2659 	} else if (zsk && role == DST_BOOL_ZSK) {
2660 		result = dst_key_getstate(key, DST_KEY_ZRRSIG, &state);
2661 		if (result == ISC_R_SUCCESS) {
2662 			zrrsig_ok = ((state == DST_KEY_STATE_RUMOURED) ||
2663 				     (state == DST_KEY_STATE_OMNIPRESENT));
2664 			/*
2665 			 * Key states trump timing metadata.
2666 			 * Ignore inactive time.
2667 			 */
2668 			time_ok = true;
2669 			inactive = false;
2670 		}
2671 	}
2672 	return (krrsig_ok && zrrsig_ok && time_ok && !inactive);
2673 }
2674 
2675 bool
dst_key_is_revoked(dst_key_t * key,isc_stdtime_t now,isc_stdtime_t * revoke)2676 dst_key_is_revoked(dst_key_t *key, isc_stdtime_t now, isc_stdtime_t *revoke) {
2677 	isc_result_t result;
2678 	isc_stdtime_t when = 0;
2679 	bool time_ok = false;
2680 
2681 	REQUIRE(VALID_KEY(key));
2682 
2683 	result = dst_key_gettime(key, DST_TIME_REVOKE, &when);
2684 	if (result == ISC_R_SUCCESS) {
2685 		*revoke = when;
2686 		time_ok = (when <= now);
2687 	}
2688 
2689 	return (time_ok);
2690 }
2691 
2692 bool
dst_key_is_removed(dst_key_t * key,isc_stdtime_t now,isc_stdtime_t * remove)2693 dst_key_is_removed(dst_key_t *key, isc_stdtime_t now, isc_stdtime_t *remove) {
2694 	dst_key_state_t state;
2695 	isc_result_t result;
2696 	isc_stdtime_t when = 0;
2697 	bool state_ok = true, time_ok = false;
2698 
2699 	REQUIRE(VALID_KEY(key));
2700 
2701 	if (dst_key_is_unused(key)) {
2702 		/* This key was never used. */
2703 		return (false);
2704 	}
2705 
2706 	result = dst_key_gettime(key, DST_TIME_DELETE, &when);
2707 	if (result == ISC_R_SUCCESS) {
2708 		*remove = when;
2709 		time_ok = (when <= now);
2710 	}
2711 
2712 	/* Check key states:
2713 	 * If the DNSKEY state is UNRETENTIVE or HIDDEN, it means the key
2714 	 * should not be published.
2715 	 */
2716 	result = dst_key_getstate(key, DST_KEY_DNSKEY, &state);
2717 	if (result == ISC_R_SUCCESS) {
2718 		state_ok = ((state == DST_KEY_STATE_UNRETENTIVE) ||
2719 			    (state == DST_KEY_STATE_HIDDEN));
2720 		/*
2721 		 * Key states trump timing metadata.
2722 		 * Ignore delete time.
2723 		 */
2724 		time_ok = true;
2725 	}
2726 
2727 	return (state_ok && time_ok);
2728 }
2729 
2730 dst_key_state_t
dst_key_goal(dst_key_t * key)2731 dst_key_goal(dst_key_t *key) {
2732 	dst_key_state_t state;
2733 	isc_result_t result;
2734 
2735 	REQUIRE(VALID_KEY(key));
2736 
2737 	result = dst_key_getstate(key, DST_KEY_GOAL, &state);
2738 	if (result == ISC_R_SUCCESS) {
2739 		return (state);
2740 	}
2741 	return (DST_KEY_STATE_HIDDEN);
2742 }
2743 
2744 bool
dst_key_haskasp(dst_key_t * key)2745 dst_key_haskasp(dst_key_t *key) {
2746 	REQUIRE(VALID_KEY(key));
2747 
2748 	return (key->kasp);
2749 }
2750 
2751 void
dst_key_copy_metadata(dst_key_t * to,dst_key_t * from)2752 dst_key_copy_metadata(dst_key_t *to, dst_key_t *from) {
2753 	dst_key_state_t state;
2754 	isc_stdtime_t when;
2755 	uint32_t num;
2756 	bool yesno;
2757 	isc_result_t result;
2758 
2759 	REQUIRE(VALID_KEY(to));
2760 	REQUIRE(VALID_KEY(from));
2761 
2762 	for (int i = 0; i < DST_MAX_TIMES + 1; i++) {
2763 		result = dst_key_gettime(from, i, &when);
2764 		if (result == ISC_R_SUCCESS) {
2765 			dst_key_settime(to, i, when);
2766 		} else {
2767 			dst_key_unsettime(to, i);
2768 		}
2769 	}
2770 
2771 	for (int i = 0; i < DST_MAX_NUMERIC + 1; i++) {
2772 		result = dst_key_getnum(from, i, &num);
2773 		if (result == ISC_R_SUCCESS) {
2774 			dst_key_setnum(to, i, num);
2775 		} else {
2776 			dst_key_unsetnum(to, i);
2777 		}
2778 	}
2779 
2780 	for (int i = 0; i < DST_MAX_BOOLEAN + 1; i++) {
2781 		result = dst_key_getbool(from, i, &yesno);
2782 		if (result == ISC_R_SUCCESS) {
2783 			dst_key_setbool(to, i, yesno);
2784 		} else {
2785 			dst_key_unsetbool(to, i);
2786 		}
2787 	}
2788 
2789 	for (int i = 0; i < DST_MAX_KEYSTATES + 1; i++) {
2790 		result = dst_key_getstate(from, i, &state);
2791 		if (result == ISC_R_SUCCESS) {
2792 			dst_key_setstate(to, i, state);
2793 		} else {
2794 			dst_key_unsetstate(to, i);
2795 		}
2796 	}
2797 
2798 	dst_key_setmodified(to, dst_key_ismodified(from));
2799 }
2800