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