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