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