dst_api.c revision 1.3 1 /* $NetBSD: dst_api.c,v 1.3 2019/01/09 16:55:11 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 <config.h>
31
32 #include <inttypes.h>
33 #include <stdbool.h>
34 #include <stdlib.h>
35 #include <time.h>
36
37 #include <isc/buffer.h>
38 #include <isc/dir.h>
39 #include <isc/fsaccess.h>
40 #include <isc/lex.h>
41 #include <isc/mem.h>
42 #include <isc/once.h>
43 #include <isc/platform.h>
44 #include <isc/print.h>
45 #include <isc/refcount.h>
46 #include <isc/random.h>
47 #include <isc/safe.h>
48 #include <isc/string.h>
49 #include <isc/time.h>
50 #include <isc/util.h>
51 #include <isc/file.h>
52
53 #include <pk11/site.h>
54
55 #define DST_KEY_INTERNAL
56
57 #include <dns/fixedname.h>
58 #include <dns/keyvalues.h>
59 #include <dns/name.h>
60 #include <dns/rdata.h>
61 #include <dns/rdataclass.h>
62 #include <dns/ttl.h>
63 #include <dns/types.h>
64
65 #include <dst/result.h>
66
67 #include "dst_internal.h"
68
69 #define DST_AS_STR(t) ((t).value.as_textregion.base)
70
71 static dst_func_t *dst_t_func[DST_MAX_ALGS];
72
73 static bool dst_initialized = false;
74
75 void gss_log(int level, const char *fmt, ...) ISC_FORMAT_PRINTF(2, 3);
76
77 /*
78 * Static functions.
79 */
80 static dst_key_t * get_key_struct(const dns_name_t *name,
81 unsigned int alg,
82 unsigned int flags,
83 unsigned int protocol,
84 unsigned int bits,
85 dns_rdataclass_t rdclass,
86 dns_ttl_t ttl,
87 isc_mem_t *mctx);
88 static isc_result_t write_public_key(const dst_key_t *key, int type,
89 const char *directory);
90 static isc_result_t buildfilename(dns_name_t *name,
91 dns_keytag_t id,
92 unsigned int alg,
93 unsigned int type,
94 const char *directory,
95 isc_buffer_t *out);
96 static isc_result_t computeid(dst_key_t *key);
97 static isc_result_t frombuffer(const dns_name_t *name,
98 unsigned int alg,
99 unsigned int flags,
100 unsigned int protocol,
101 dns_rdataclass_t rdclass,
102 isc_buffer_t *source,
103 isc_mem_t *mctx,
104 dst_key_t **keyp);
105
106 static isc_result_t algorithm_status(unsigned int alg);
107
108 static isc_result_t addsuffix(char *filename, int len,
109 const char *dirname, const char *ofilename,
110 const char *suffix);
111
112 #define RETERR(x) \
113 do { \
114 result = (x); \
115 if (result != ISC_R_SUCCESS) \
116 goto out; \
117 } while (/*CONSTCOND*/0)
118
119 #define CHECKALG(alg) \
120 do { \
121 isc_result_t _r; \
122 _r = algorithm_status(alg); \
123 if (_r != ISC_R_SUCCESS) \
124 return (_r); \
125 } while (/*CONSTCOND*/0); \
126
127 isc_result_t
128 dst_lib_init(isc_mem_t *mctx, const char *engine) {
129 isc_result_t result;
130
131 REQUIRE(mctx != NULL);
132 REQUIRE(dst_initialized == false);
133
134 UNUSED(engine);
135
136 dst_result_register();
137
138 memset(dst_t_func, 0, sizeof(dst_t_func));
139 RETERR(dst__hmacmd5_init(&dst_t_func[DST_ALG_HMACMD5]));
140 RETERR(dst__hmacsha1_init(&dst_t_func[DST_ALG_HMACSHA1]));
141 RETERR(dst__hmacsha224_init(&dst_t_func[DST_ALG_HMACSHA224]));
142 RETERR(dst__hmacsha256_init(&dst_t_func[DST_ALG_HMACSHA256]));
143 RETERR(dst__hmacsha384_init(&dst_t_func[DST_ALG_HMACSHA384]));
144 RETERR(dst__hmacsha512_init(&dst_t_func[DST_ALG_HMACSHA512]));
145 RETERR(dst__openssl_init(mctx, engine));
146 RETERR(dst__openssldh_init(&dst_t_func[DST_ALG_DH]));
147 #if USE_OPENSSL
148 RETERR(dst__opensslrsa_init(&dst_t_func[DST_ALG_RSAMD5],
149 DST_ALG_RSAMD5));
150 RETERR(dst__opensslrsa_init(&dst_t_func[DST_ALG_RSASHA1],
151 DST_ALG_RSASHA1));
152 RETERR(dst__opensslrsa_init(&dst_t_func[DST_ALG_NSEC3RSASHA1],
153 DST_ALG_NSEC3RSASHA1));
154 RETERR(dst__opensslrsa_init(&dst_t_func[DST_ALG_RSASHA256],
155 DST_ALG_RSASHA256));
156 RETERR(dst__opensslrsa_init(&dst_t_func[DST_ALG_RSASHA512],
157 DST_ALG_RSASHA512));
158 RETERR(dst__opensslecdsa_init(&dst_t_func[DST_ALG_ECDSA256]));
159 RETERR(dst__opensslecdsa_init(&dst_t_func[DST_ALG_ECDSA384]));
160 #ifdef HAVE_OPENSSL_ED25519
161 RETERR(dst__openssleddsa_init(&dst_t_func[DST_ALG_ED25519]));
162 #endif
163 #ifdef HAVE_OPENSSL_ED448
164 RETERR(dst__openssleddsa_init(&dst_t_func[DST_ALG_ED448]));
165 #endif
166 #endif /* USE_OPENSSL */
167
168 #if USE_PKCS11
169 RETERR(dst__pkcs11_init(mctx, engine));
170 RETERR(dst__pkcs11rsa_init(&dst_t_func[DST_ALG_RSAMD5]));
171 RETERR(dst__pkcs11rsa_init(&dst_t_func[DST_ALG_RSASHA1]));
172 RETERR(dst__pkcs11rsa_init(&dst_t_func[DST_ALG_NSEC3RSASHA1]));
173 RETERR(dst__pkcs11rsa_init(&dst_t_func[DST_ALG_RSASHA256]));
174 RETERR(dst__pkcs11rsa_init(&dst_t_func[DST_ALG_RSASHA512]));
175 RETERR(dst__pkcs11ecdsa_init(&dst_t_func[DST_ALG_ECDSA256]));
176 RETERR(dst__pkcs11ecdsa_init(&dst_t_func[DST_ALG_ECDSA384]));
177 #ifdef HAVE_PKCS11_ED25519
178 RETERR(dst__pkcs11eddsa_init(&dst_t_func[DST_ALG_ED25519]));
179 #endif
180 #ifdef HAVE_PKCS11_ED448
181 RETERR(dst__pkcs11eddsa_init(&dst_t_func[DST_ALG_ED448]));
182 #endif
183 #endif /* USE_PKCS11 */
184 #ifdef GSSAPI
185 RETERR(dst__gssapi_init(&dst_t_func[DST_ALG_GSSAPI]));
186 #endif
187
188 dst_initialized = true;
189 return (ISC_R_SUCCESS);
190
191 out:
192 /* avoid immediate crash! */
193 dst_initialized = true;
194 dst_lib_destroy();
195 return (result);
196 }
197
198 void
199 dst_lib_destroy(void) {
200 int i;
201 RUNTIME_CHECK(dst_initialized == true);
202 dst_initialized = false;
203
204 for (i = 0; i < DST_MAX_ALGS; i++)
205 if (dst_t_func[i] != NULL && dst_t_func[i]->cleanup != NULL)
206 dst_t_func[i]->cleanup();
207 dst__openssl_destroy();
208 #if USE_PKCS11
209 (void) dst__pkcs11_destroy();
210 #endif /* USE_PKCS11 */
211 }
212
213 bool
214 dst_algorithm_supported(unsigned int alg) {
215 REQUIRE(dst_initialized == true);
216
217 if (alg >= DST_MAX_ALGS || dst_t_func[alg] == NULL)
218 return (false);
219 return (true);
220 }
221
222 bool
223 dst_ds_digest_supported(unsigned int digest_type) {
224 return (digest_type == DNS_DSDIGEST_SHA1 ||
225 digest_type == DNS_DSDIGEST_SHA256 ||
226 digest_type == DNS_DSDIGEST_SHA384);
227 }
228
229 isc_result_t
230 dst_context_create(dst_key_t *key, isc_mem_t *mctx,
231 isc_logcategory_t *category, bool useforsigning,
232 int maxbits, dst_context_t **dctxp)
233 {
234 dst_context_t *dctx;
235 isc_result_t result;
236
237 REQUIRE(dst_initialized == true);
238 REQUIRE(VALID_KEY(key));
239 REQUIRE(mctx != NULL);
240 REQUIRE(dctxp != NULL && *dctxp == NULL);
241
242 if (key->func->createctx == NULL &&
243 key->func->createctx2 == NULL)
244 return (DST_R_UNSUPPORTEDALG);
245 if (key->keydata.generic == NULL)
246 return (DST_R_NULLKEY);
247
248 dctx = isc_mem_get(mctx, sizeof(dst_context_t));
249 if (dctx == NULL)
250 return (ISC_R_NOMEMORY);
251 memset(dctx, 0, sizeof(*dctx));
252 dst_key_attach(key, &dctx->key);
253 isc_mem_attach(mctx, &dctx->mctx);
254 dctx->category = category;
255 if (useforsigning)
256 dctx->use = DO_SIGN;
257 else
258 dctx->use = DO_VERIFY;
259 if (key->func->createctx2 != NULL)
260 result = key->func->createctx2(key, maxbits, dctx);
261 else
262 result = key->func->createctx(key, dctx);
263 if (result != ISC_R_SUCCESS) {
264 if (dctx->key != NULL)
265 dst_key_free(&dctx->key);
266 isc_mem_putanddetach(&dctx->mctx, dctx, sizeof(dst_context_t));
267 return (result);
268 }
269 dctx->magic = CTX_MAGIC;
270 *dctxp = dctx;
271 return (ISC_R_SUCCESS);
272 }
273
274 void
275 dst_context_destroy(dst_context_t **dctxp) {
276 dst_context_t *dctx;
277
278 REQUIRE(dctxp != NULL && VALID_CTX(*dctxp));
279
280 dctx = *dctxp;
281 INSIST(dctx->key->func->destroyctx != NULL);
282 dctx->key->func->destroyctx(dctx);
283 if (dctx->key != NULL)
284 dst_key_free(&dctx->key);
285 dctx->magic = 0;
286 isc_mem_putanddetach(&dctx->mctx, dctx, sizeof(dst_context_t));
287 *dctxp = NULL;
288 }
289
290 isc_result_t
291 dst_context_adddata(dst_context_t *dctx, const isc_region_t *data) {
292 REQUIRE(VALID_CTX(dctx));
293 REQUIRE(data != NULL);
294 INSIST(dctx->key->func->adddata != NULL);
295
296 return (dctx->key->func->adddata(dctx, data));
297 }
298
299 isc_result_t
300 dst_context_sign(dst_context_t *dctx, isc_buffer_t *sig) {
301 dst_key_t *key;
302
303 REQUIRE(VALID_CTX(dctx));
304 REQUIRE(sig != NULL);
305
306 key = dctx->key;
307 CHECKALG(key->key_alg);
308 if (key->keydata.generic == NULL)
309 return (DST_R_NULLKEY);
310
311 if (key->func->sign == NULL)
312 return (DST_R_NOTPRIVATEKEY);
313 if (key->func->isprivate == NULL ||
314 key->func->isprivate(key) == false)
315 return (DST_R_NOTPRIVATEKEY);
316
317 return (key->func->sign(dctx, sig));
318 }
319
320 isc_result_t
321 dst_context_verify(dst_context_t *dctx, isc_region_t *sig) {
322 REQUIRE(VALID_CTX(dctx));
323 REQUIRE(sig != NULL);
324
325 CHECKALG(dctx->key->key_alg);
326 if (dctx->key->keydata.generic == NULL)
327 return (DST_R_NULLKEY);
328 if (dctx->key->func->verify == NULL)
329 return (DST_R_NOTPUBLICKEY);
330
331 return (dctx->key->func->verify(dctx, sig));
332 }
333
334 isc_result_t
335 dst_context_verify2(dst_context_t *dctx, unsigned int maxbits,
336 isc_region_t *sig)
337 {
338 REQUIRE(VALID_CTX(dctx));
339 REQUIRE(sig != NULL);
340
341 CHECKALG(dctx->key->key_alg);
342 if (dctx->key->keydata.generic == NULL)
343 return (DST_R_NULLKEY);
344 if (dctx->key->func->verify == NULL &&
345 dctx->key->func->verify2 == NULL)
346 return (DST_R_NOTPUBLICKEY);
347
348 return (dctx->key->func->verify2 != NULL ?
349 dctx->key->func->verify2(dctx, maxbits, sig) :
350 dctx->key->func->verify(dctx, sig));
351 }
352
353 isc_result_t
354 dst_key_computesecret(const dst_key_t *pub, const dst_key_t *priv,
355 isc_buffer_t *secret)
356 {
357 REQUIRE(dst_initialized == true);
358 REQUIRE(VALID_KEY(pub) && VALID_KEY(priv));
359 REQUIRE(secret != NULL);
360
361 CHECKALG(pub->key_alg);
362 CHECKALG(priv->key_alg);
363
364 if (pub->keydata.generic == NULL || priv->keydata.generic == NULL)
365 return (DST_R_NULLKEY);
366
367 if (pub->key_alg != priv->key_alg ||
368 pub->func->computesecret == NULL ||
369 priv->func->computesecret == NULL)
370 return (DST_R_KEYCANNOTCOMPUTESECRET);
371
372 if (dst_key_isprivate(priv) == false)
373 return (DST_R_NOTPRIVATEKEY);
374
375 return (pub->func->computesecret(pub, priv, secret));
376 }
377
378 isc_result_t
379 dst_key_tofile(const dst_key_t *key, int type, const char *directory) {
380 isc_result_t ret = ISC_R_SUCCESS;
381
382 REQUIRE(dst_initialized == true);
383 REQUIRE(VALID_KEY(key));
384 REQUIRE((type & (DST_TYPE_PRIVATE | DST_TYPE_PUBLIC)) != 0);
385
386 CHECKALG(key->key_alg);
387
388 if (key->func->tofile == NULL)
389 return (DST_R_UNSUPPORTEDALG);
390
391 if ((type & DST_TYPE_PUBLIC) != 0) {
392 ret = write_public_key(key, type, directory);
393 if (ret != ISC_R_SUCCESS)
394 return (ret);
395 }
396
397 if (((type & DST_TYPE_PRIVATE) != 0) &&
398 (key->key_flags & DNS_KEYFLAG_TYPEMASK) != DNS_KEYTYPE_NOKEY)
399 return (key->func->tofile(key, directory));
400 else
401 return (ISC_R_SUCCESS);
402 }
403
404 void
405 dst_key_setexternal(dst_key_t *key, bool value) {
406 key->external = value;
407 }
408
409 bool
410 dst_key_isexternal(dst_key_t *key) {
411 return (key->external);
412 }
413
414 isc_result_t
415 dst_key_getfilename(dns_name_t *name, dns_keytag_t id,
416 unsigned int alg, int type, const char *directory,
417 isc_mem_t *mctx, isc_buffer_t *buf)
418 {
419 isc_result_t result;
420
421 REQUIRE(dst_initialized == true);
422 REQUIRE(dns_name_isabsolute(name));
423 REQUIRE((type & (DST_TYPE_PRIVATE | DST_TYPE_PUBLIC)) != 0);
424 REQUIRE(mctx != NULL);
425 REQUIRE(buf != NULL);
426
427 CHECKALG(alg);
428
429 result = buildfilename(name, id, alg, type, directory, buf);
430 if (result == ISC_R_SUCCESS) {
431 if (isc_buffer_availablelength(buf) > 0)
432 isc_buffer_putuint8(buf, 0);
433 else
434 result = ISC_R_NOSPACE;
435 }
436
437 return (result);
438 }
439
440 isc_result_t
441 dst_key_fromfile(dns_name_t *name, dns_keytag_t id,
442 unsigned int alg, int type, const char *directory,
443 isc_mem_t *mctx, dst_key_t **keyp)
444 {
445 isc_result_t result;
446 char filename[NAME_MAX];
447 isc_buffer_t buf;
448 dst_key_t *key;
449
450 REQUIRE(dst_initialized == true);
451 REQUIRE(dns_name_isabsolute(name));
452 REQUIRE((type & (DST_TYPE_PRIVATE | DST_TYPE_PUBLIC)) != 0);
453 REQUIRE(mctx != NULL);
454 REQUIRE(keyp != NULL && *keyp == NULL);
455
456 CHECKALG(alg);
457
458 key = NULL;
459
460 isc_buffer_init(&buf, filename, NAME_MAX);
461 result = dst_key_getfilename(name, id, alg, type, NULL, mctx, &buf);
462 if (result != ISC_R_SUCCESS)
463 goto out;
464
465 result = dst_key_fromnamedfile(filename, directory, type, mctx, &key);
466 if (result != ISC_R_SUCCESS)
467 goto out;
468
469 result = computeid(key);
470 if (result != ISC_R_SUCCESS)
471 goto out;
472
473 if (!dns_name_equal(name, key->key_name) || id != key->key_id ||
474 alg != key->key_alg) {
475 result = DST_R_INVALIDPRIVATEKEY;
476 goto out;
477 }
478
479 *keyp = key;
480 result = ISC_R_SUCCESS;
481
482 out:
483 if ((key != NULL) && (result != ISC_R_SUCCESS))
484 dst_key_free(&key);
485
486 return (result);
487 }
488
489 isc_result_t
490 dst_key_fromnamedfile(const char *filename, const char *dirname,
491 int type, isc_mem_t *mctx, dst_key_t **keyp)
492 {
493 isc_result_t result;
494 dst_key_t *pubkey = NULL, *key = NULL;
495 char *newfilename = NULL;
496 int newfilenamelen = 0;
497 isc_lex_t *lex = NULL;
498
499 REQUIRE(dst_initialized == true);
500 REQUIRE(filename != NULL);
501 REQUIRE((type & (DST_TYPE_PRIVATE | DST_TYPE_PUBLIC)) != 0);
502 REQUIRE(mctx != NULL);
503 REQUIRE(keyp != NULL && *keyp == NULL);
504
505 /* If an absolute path is specified, don't use the key directory */
506 #ifndef WIN32
507 if (filename[0] == '/')
508 dirname = NULL;
509 #else /* WIN32 */
510 if (filename[0] == '/' || filename[0] == '\\')
511 dirname = NULL;
512 #endif
513
514 newfilenamelen = strlen(filename) + 5;
515 if (dirname != NULL)
516 newfilenamelen += strlen(dirname) + 1;
517 newfilename = isc_mem_get(mctx, newfilenamelen);
518 if (newfilename == NULL)
519 return (ISC_R_NOMEMORY);
520 result = addsuffix(newfilename, newfilenamelen,
521 dirname, filename, ".key");
522 INSIST(result == ISC_R_SUCCESS);
523
524 result = dst_key_read_public(newfilename, type, mctx, &pubkey);
525 isc_mem_put(mctx, newfilename, newfilenamelen);
526 newfilename = NULL;
527 RETERR(result);
528
529 if ((type & (DST_TYPE_PRIVATE | DST_TYPE_PUBLIC)) == DST_TYPE_PUBLIC ||
530 (pubkey->key_flags & DNS_KEYFLAG_TYPEMASK) == DNS_KEYTYPE_NOKEY) {
531 result = computeid(pubkey);
532 if (result != ISC_R_SUCCESS) {
533 dst_key_free(&pubkey);
534 return (result);
535 }
536
537 *keyp = pubkey;
538 return (ISC_R_SUCCESS);
539 }
540
541 result = algorithm_status(pubkey->key_alg);
542 if (result != ISC_R_SUCCESS) {
543 dst_key_free(&pubkey);
544 return (result);
545 }
546
547 key = get_key_struct(pubkey->key_name, pubkey->key_alg,
548 pubkey->key_flags, pubkey->key_proto, 0,
549 pubkey->key_class, pubkey->key_ttl, mctx);
550 if (key == NULL) {
551 dst_key_free(&pubkey);
552 return (ISC_R_NOMEMORY);
553 }
554
555 if (key->func->parse == NULL)
556 RETERR(DST_R_UNSUPPORTEDALG);
557
558 newfilenamelen = strlen(filename) + 9;
559 if (dirname != NULL)
560 newfilenamelen += strlen(dirname) + 1;
561 newfilename = isc_mem_get(mctx, newfilenamelen);
562 if (newfilename == NULL)
563 RETERR(ISC_R_NOMEMORY);
564 result = addsuffix(newfilename, newfilenamelen,
565 dirname, filename, ".private");
566 INSIST(result == ISC_R_SUCCESS);
567
568 RETERR(isc_lex_create(mctx, 1500, &lex));
569 RETERR(isc_lex_openfile(lex, newfilename));
570 isc_mem_put(mctx, newfilename, newfilenamelen);
571
572 RETERR(key->func->parse(key, lex, pubkey));
573 isc_lex_destroy(&lex);
574
575 RETERR(computeid(key));
576
577 if (pubkey->key_id != key->key_id)
578 RETERR(DST_R_INVALIDPRIVATEKEY);
579 dst_key_free(&pubkey);
580
581 *keyp = key;
582 return (ISC_R_SUCCESS);
583
584 out:
585 if (pubkey != NULL)
586 dst_key_free(&pubkey);
587 if (newfilename != NULL)
588 isc_mem_put(mctx, newfilename, newfilenamelen);
589 if (lex != NULL)
590 isc_lex_destroy(&lex);
591 if (key != NULL)
592 dst_key_free(&key);
593 return (result);
594 }
595
596 isc_result_t
597 dst_key_todns(const dst_key_t *key, isc_buffer_t *target) {
598 REQUIRE(dst_initialized == true);
599 REQUIRE(VALID_KEY(key));
600 REQUIRE(target != NULL);
601
602 CHECKALG(key->key_alg);
603
604 if (key->func->todns == NULL)
605 return (DST_R_UNSUPPORTEDALG);
606
607 if (isc_buffer_availablelength(target) < 4)
608 return (ISC_R_NOSPACE);
609 isc_buffer_putuint16(target, (uint16_t)(key->key_flags & 0xffff));
610 isc_buffer_putuint8(target, (uint8_t)key->key_proto);
611 isc_buffer_putuint8(target, (uint8_t)key->key_alg);
612
613 if ((key->key_flags & DNS_KEYFLAG_EXTENDED) != 0) {
614 if (isc_buffer_availablelength(target) < 2)
615 return (ISC_R_NOSPACE);
616 isc_buffer_putuint16(target,
617 (uint16_t)((key->key_flags >> 16)
618 & 0xffff));
619 }
620
621 if (key->keydata.generic == NULL) /*%< NULL KEY */
622 return (ISC_R_SUCCESS);
623
624 return (key->func->todns(key, target));
625 }
626
627 isc_result_t
628 dst_key_fromdns(const dns_name_t *name, dns_rdataclass_t rdclass,
629 isc_buffer_t *source, isc_mem_t *mctx, dst_key_t **keyp)
630 {
631 uint8_t alg, proto;
632 uint32_t flags, extflags;
633 dst_key_t *key = NULL;
634 dns_keytag_t id, rid;
635 isc_region_t r;
636 isc_result_t result;
637
638 REQUIRE(dst_initialized);
639
640 isc_buffer_remainingregion(source, &r);
641
642 if (isc_buffer_remaininglength(source) < 4)
643 return (DST_R_INVALIDPUBLICKEY);
644 flags = isc_buffer_getuint16(source);
645 proto = isc_buffer_getuint8(source);
646 alg = isc_buffer_getuint8(source);
647
648 id = dst_region_computeid(&r, alg);
649 rid = dst_region_computerid(&r, alg);
650
651 if ((flags & DNS_KEYFLAG_EXTENDED) != 0) {
652 if (isc_buffer_remaininglength(source) < 2)
653 return (DST_R_INVALIDPUBLICKEY);
654 extflags = isc_buffer_getuint16(source);
655 flags |= (extflags << 16);
656 }
657
658 result = frombuffer(name, alg, flags, proto, rdclass, source,
659 mctx, &key);
660 if (result != ISC_R_SUCCESS)
661 return (result);
662 key->key_id = id;
663 key->key_rid = rid;
664
665 *keyp = key;
666 return (ISC_R_SUCCESS);
667 }
668
669 isc_result_t
670 dst_key_frombuffer(const dns_name_t *name, unsigned int alg,
671 unsigned int flags, unsigned int protocol,
672 dns_rdataclass_t rdclass,
673 isc_buffer_t *source, isc_mem_t *mctx, dst_key_t **keyp)
674 {
675 dst_key_t *key = NULL;
676 isc_result_t result;
677
678 REQUIRE(dst_initialized);
679
680 result = frombuffer(name, alg, flags, protocol, rdclass, source,
681 mctx, &key);
682 if (result != ISC_R_SUCCESS)
683 return (result);
684
685 result = computeid(key);
686 if (result != ISC_R_SUCCESS) {
687 dst_key_free(&key);
688 return (result);
689 }
690
691 *keyp = key;
692 return (ISC_R_SUCCESS);
693 }
694
695 isc_result_t
696 dst_key_tobuffer(const dst_key_t *key, isc_buffer_t *target) {
697 REQUIRE(dst_initialized == true);
698 REQUIRE(VALID_KEY(key));
699 REQUIRE(target != NULL);
700
701 CHECKALG(key->key_alg);
702
703 if (key->func->todns == NULL)
704 return (DST_R_UNSUPPORTEDALG);
705
706 return (key->func->todns(key, target));
707 }
708
709 isc_result_t
710 dst_key_privatefrombuffer(dst_key_t *key, isc_buffer_t *buffer) {
711 isc_lex_t *lex = NULL;
712 isc_result_t result = ISC_R_SUCCESS;
713
714 REQUIRE(dst_initialized == true);
715 REQUIRE(VALID_KEY(key));
716 REQUIRE(!dst_key_isprivate(key));
717 REQUIRE(buffer != NULL);
718
719 if (key->func->parse == NULL)
720 RETERR(DST_R_UNSUPPORTEDALG);
721
722 RETERR(isc_lex_create(key->mctx, 1500, &lex));
723 RETERR(isc_lex_openbuffer(lex, buffer));
724 RETERR(key->func->parse(key, lex, NULL));
725 out:
726 if (lex != NULL)
727 isc_lex_destroy(&lex);
728 return (result);
729 }
730
731 gss_ctx_id_t
732 dst_key_getgssctx(const dst_key_t *key)
733 {
734 REQUIRE(key != NULL);
735
736 return (key->keydata.gssctx);
737 }
738
739 isc_result_t
740 dst_key_fromgssapi(const dns_name_t *name, gss_ctx_id_t gssctx,
741 isc_mem_t *mctx, dst_key_t **keyp, isc_region_t *intoken)
742 {
743 dst_key_t *key;
744 isc_result_t result;
745
746 REQUIRE(gssctx != NULL);
747 REQUIRE(keyp != NULL && *keyp == NULL);
748
749 key = get_key_struct(name, DST_ALG_GSSAPI, 0, DNS_KEYPROTO_DNSSEC,
750 0, dns_rdataclass_in, 0, mctx);
751 if (key == NULL)
752 return (ISC_R_NOMEMORY);
753
754 if (intoken != NULL) {
755 /*
756 * Keep the token for use by external ssu rules. They may need
757 * to examine the PAC in the kerberos ticket.
758 */
759 RETERR(isc_buffer_allocate(key->mctx, &key->key_tkeytoken,
760 intoken->length));
761 RETERR(isc_buffer_copyregion(key->key_tkeytoken, intoken));
762 }
763
764 key->keydata.gssctx = gssctx;
765 *keyp = key;
766 result = ISC_R_SUCCESS;
767 out:
768 if (result != ISC_R_SUCCESS) {
769 dst_key_free(&key);
770 }
771 return result;
772 }
773
774 isc_result_t
775 dst_key_buildinternal(const dns_name_t *name, unsigned int alg,
776 unsigned int bits, unsigned int flags,
777 unsigned int protocol, dns_rdataclass_t rdclass,
778 void *data, isc_mem_t *mctx, dst_key_t **keyp)
779 {
780 dst_key_t *key;
781 isc_result_t result;
782
783 REQUIRE(dst_initialized == true);
784 REQUIRE(dns_name_isabsolute(name));
785 REQUIRE(mctx != NULL);
786 REQUIRE(keyp != NULL && *keyp == NULL);
787 REQUIRE(data != NULL);
788
789 CHECKALG(alg);
790
791 key = get_key_struct(name, alg, flags, protocol, bits, rdclass,
792 0, mctx);
793 if (key == NULL)
794 return (ISC_R_NOMEMORY);
795
796 key->keydata.generic = data;
797
798 result = computeid(key);
799 if (result != ISC_R_SUCCESS) {
800 dst_key_free(&key);
801 return (result);
802 }
803
804 *keyp = key;
805 return (ISC_R_SUCCESS);
806 }
807
808 isc_result_t
809 dst_key_fromlabel(const dns_name_t *name, int alg, unsigned int flags,
810 unsigned int protocol, dns_rdataclass_t rdclass,
811 const char *engine, const char *label, const char *pin,
812 isc_mem_t *mctx, dst_key_t **keyp)
813 {
814 dst_key_t *key;
815 isc_result_t result;
816
817 REQUIRE(dst_initialized == true);
818 REQUIRE(dns_name_isabsolute(name));
819 REQUIRE(mctx != NULL);
820 REQUIRE(keyp != NULL && *keyp == NULL);
821 REQUIRE(label != NULL);
822
823 CHECKALG(alg);
824
825 key = get_key_struct(name, alg, flags, protocol, 0, rdclass, 0, mctx);
826 if (key == NULL)
827 return (ISC_R_NOMEMORY);
828
829 if (key->func->fromlabel == NULL) {
830 dst_key_free(&key);
831 return (DST_R_UNSUPPORTEDALG);
832 }
833
834 result = key->func->fromlabel(key, engine, label, pin);
835 if (result != ISC_R_SUCCESS) {
836 dst_key_free(&key);
837 return (result);
838 }
839
840 result = computeid(key);
841 if (result != ISC_R_SUCCESS) {
842 dst_key_free(&key);
843 return (result);
844 }
845
846 *keyp = key;
847 return (ISC_R_SUCCESS);
848 }
849
850 isc_result_t
851 dst_key_generate(const dns_name_t *name, unsigned int alg,
852 unsigned int bits, unsigned int param,
853 unsigned int flags, unsigned int protocol,
854 dns_rdataclass_t rdclass,
855 isc_mem_t *mctx, dst_key_t **keyp,
856 void (*callback)(int))
857 {
858 dst_key_t *key;
859 isc_result_t ret;
860
861 REQUIRE(dst_initialized == true);
862 REQUIRE(dns_name_isabsolute(name));
863 REQUIRE(mctx != NULL);
864 REQUIRE(keyp != NULL && *keyp == NULL);
865
866 CHECKALG(alg);
867
868 key = get_key_struct(name, alg, flags, protocol, bits,
869 rdclass, 0, mctx);
870 if (key == NULL)
871 return (ISC_R_NOMEMORY);
872
873 if (bits == 0) { /*%< NULL KEY */
874 key->key_flags |= DNS_KEYTYPE_NOKEY;
875 *keyp = key;
876 return (ISC_R_SUCCESS);
877 }
878
879 if (key->func->generate == NULL) {
880 dst_key_free(&key);
881 return (DST_R_UNSUPPORTEDALG);
882 }
883
884 ret = key->func->generate(key, param, callback);
885 if (ret != ISC_R_SUCCESS) {
886 dst_key_free(&key);
887 return (ret);
888 }
889
890 ret = computeid(key);
891 if (ret != ISC_R_SUCCESS) {
892 dst_key_free(&key);
893 return (ret);
894 }
895
896 *keyp = key;
897 return (ISC_R_SUCCESS);
898 }
899
900 isc_result_t
901 dst_key_getnum(const dst_key_t *key, int type, uint32_t *valuep)
902 {
903 REQUIRE(VALID_KEY(key));
904 REQUIRE(valuep != NULL);
905 REQUIRE(type <= DST_MAX_NUMERIC);
906 if (!key->numset[type])
907 return (ISC_R_NOTFOUND);
908 *valuep = key->nums[type];
909 return (ISC_R_SUCCESS);
910 }
911
912 void
913 dst_key_setnum(dst_key_t *key, int type, uint32_t value)
914 {
915 REQUIRE(VALID_KEY(key));
916 REQUIRE(type <= DST_MAX_NUMERIC);
917 key->nums[type] = value;
918 key->numset[type] = true;
919 }
920
921 void
922 dst_key_unsetnum(dst_key_t *key, int type)
923 {
924 REQUIRE(VALID_KEY(key));
925 REQUIRE(type <= DST_MAX_NUMERIC);
926 key->numset[type] = false;
927 }
928
929 isc_result_t
930 dst_key_gettime(const dst_key_t *key, int type, isc_stdtime_t *timep) {
931 REQUIRE(VALID_KEY(key));
932 REQUIRE(timep != NULL);
933 REQUIRE(type <= DST_MAX_TIMES);
934 if (!key->timeset[type])
935 return (ISC_R_NOTFOUND);
936 *timep = key->times[type];
937 return (ISC_R_SUCCESS);
938 }
939
940 void
941 dst_key_settime(dst_key_t *key, int type, isc_stdtime_t when) {
942 REQUIRE(VALID_KEY(key));
943 REQUIRE(type <= DST_MAX_TIMES);
944 key->times[type] = when;
945 key->timeset[type] = true;
946 }
947
948 void
949 dst_key_unsettime(dst_key_t *key, int type) {
950 REQUIRE(VALID_KEY(key));
951 REQUIRE(type <= DST_MAX_TIMES);
952 key->timeset[type] = false;
953 }
954
955 isc_result_t
956 dst_key_getprivateformat(const dst_key_t *key, int *majorp, int *minorp) {
957 REQUIRE(VALID_KEY(key));
958 REQUIRE(majorp != NULL);
959 REQUIRE(minorp != NULL);
960 *majorp = key->fmt_major;
961 *minorp = key->fmt_minor;
962 return (ISC_R_SUCCESS);
963 }
964
965 void
966 dst_key_setprivateformat(dst_key_t *key, int major, int minor) {
967 REQUIRE(VALID_KEY(key));
968 key->fmt_major = major;
969 key->fmt_minor = minor;
970 }
971
972 static bool
973 comparekeys(const dst_key_t *key1, const dst_key_t *key2,
974 bool match_revoked_key,
975 bool (*compare)(const dst_key_t *key1,
976 const dst_key_t *key2))
977 {
978 REQUIRE(dst_initialized == true);
979 REQUIRE(VALID_KEY(key1));
980 REQUIRE(VALID_KEY(key2));
981
982 if (key1 == key2)
983 return (true);
984
985 if (key1->key_alg != key2->key_alg)
986 return (false);
987
988 if (key1->key_id != key2->key_id) {
989 if (!match_revoked_key)
990 return (false);
991 if (key1->key_alg == DST_ALG_RSAMD5)
992 return (false);
993 if ((key1->key_flags & DNS_KEYFLAG_REVOKE) ==
994 (key2->key_flags & DNS_KEYFLAG_REVOKE))
995 return (false);
996 if (key1->key_id != key2->key_rid &&
997 key1->key_rid != key2->key_id)
998 return (false);
999 }
1000
1001 if (compare != NULL)
1002 return (compare(key1, key2));
1003 else
1004 return (false);
1005 }
1006
1007
1008 /*
1009 * Compares only the public portion of two keys, by converting them
1010 * both to wire format and comparing the results.
1011 */
1012 static bool
1013 pub_compare(const dst_key_t *key1, const dst_key_t *key2) {
1014 isc_result_t result;
1015 unsigned char buf1[DST_KEY_MAXSIZE], buf2[DST_KEY_MAXSIZE];
1016 isc_buffer_t b1, b2;
1017 isc_region_t r1, r2;
1018
1019 isc_buffer_init(&b1, buf1, sizeof(buf1));
1020 result = dst_key_todns(key1, &b1);
1021 if (result != ISC_R_SUCCESS)
1022 return (false);
1023 /* Zero out flags. */
1024 buf1[0] = buf1[1] = 0;
1025 if ((key1->key_flags & DNS_KEYFLAG_EXTENDED) != 0)
1026 isc_buffer_subtract(&b1, 2);
1027
1028 isc_buffer_init(&b2, buf2, sizeof(buf2));
1029 result = dst_key_todns(key2, &b2);
1030 if (result != ISC_R_SUCCESS)
1031 return (false);
1032 /* Zero out flags. */
1033 buf2[0] = buf2[1] = 0;
1034 if ((key2->key_flags & DNS_KEYFLAG_EXTENDED) != 0)
1035 isc_buffer_subtract(&b2, 2);
1036
1037 isc_buffer_usedregion(&b1, &r1);
1038 /* Remove extended flags. */
1039 if ((key1->key_flags & DNS_KEYFLAG_EXTENDED) != 0) {
1040 memmove(&buf1[4], &buf1[6], r1.length - 6);
1041 r1.length -= 2;
1042 }
1043
1044 isc_buffer_usedregion(&b2, &r2);
1045 /* Remove extended flags. */
1046 if ((key2->key_flags & DNS_KEYFLAG_EXTENDED) != 0) {
1047 memmove(&buf2[4], &buf2[6], r2.length - 6);
1048 r2.length -= 2;
1049 }
1050 return (isc_region_compare(&r1, &r2) == 0);
1051 }
1052
1053 bool
1054 dst_key_compare(const dst_key_t *key1, const dst_key_t *key2) {
1055 return (comparekeys(key1, key2, false, key1->func->compare));
1056 }
1057
1058 bool
1059 dst_key_pubcompare(const dst_key_t *key1, const dst_key_t *key2,
1060 bool match_revoked_key)
1061 {
1062 return (comparekeys(key1, key2, match_revoked_key, pub_compare));
1063 }
1064
1065
1066 bool
1067 dst_key_paramcompare(const dst_key_t *key1, const dst_key_t *key2) {
1068 REQUIRE(dst_initialized == true);
1069 REQUIRE(VALID_KEY(key1));
1070 REQUIRE(VALID_KEY(key2));
1071
1072 if (key1 == key2)
1073 return (true);
1074 if (key1->key_alg == key2->key_alg &&
1075 key1->func->paramcompare != NULL &&
1076 key1->func->paramcompare(key1, key2) == true)
1077 return (true);
1078 else
1079 return (false);
1080 }
1081
1082 void
1083 dst_key_attach(dst_key_t *source, dst_key_t **target) {
1084
1085 REQUIRE(dst_initialized == true);
1086 REQUIRE(target != NULL && *target == NULL);
1087 REQUIRE(VALID_KEY(source));
1088
1089 isc_refcount_increment(&source->refs);
1090 *target = source;
1091 }
1092
1093 void
1094 dst_key_free(dst_key_t **keyp) {
1095 REQUIRE(dst_initialized == true);
1096 REQUIRE(keyp != NULL && VALID_KEY(*keyp));
1097 dst_key_t *key = *keyp;
1098 *keyp = NULL;
1099
1100 if (isc_refcount_decrement(&key->refs) == 1) {
1101 isc_refcount_destroy(&key->refs);
1102 isc_mem_t *mctx = key->mctx;
1103 if (key->keydata.generic != NULL) {
1104 INSIST(key->func->destroy != NULL);
1105 key->func->destroy(key);
1106 }
1107 if (key->engine != NULL)
1108 isc_mem_free(mctx, key->engine);
1109 if (key->label != NULL)
1110 isc_mem_free(mctx, key->label);
1111 dns_name_free(key->key_name, mctx);
1112 isc_mem_put(mctx, key->key_name, sizeof(dns_name_t));
1113 if (key->key_tkeytoken) {
1114 isc_buffer_free(&key->key_tkeytoken);
1115 }
1116 isc_safe_memwipe(key, sizeof(*key));
1117 isc_mem_putanddetach(&mctx, key, sizeof(*key));
1118 }
1119 }
1120
1121 bool
1122 dst_key_isprivate(const dst_key_t *key) {
1123 REQUIRE(VALID_KEY(key));
1124 INSIST(key->func->isprivate != NULL);
1125 return (key->func->isprivate(key));
1126 }
1127
1128 isc_result_t
1129 dst_key_buildfilename(const dst_key_t *key, int type,
1130 const char *directory, isc_buffer_t *out) {
1131
1132 REQUIRE(VALID_KEY(key));
1133 REQUIRE(type == DST_TYPE_PRIVATE || type == DST_TYPE_PUBLIC ||
1134 type == 0);
1135
1136 return (buildfilename(key->key_name, key->key_id, key->key_alg,
1137 type, directory, out));
1138 }
1139
1140 isc_result_t
1141 dst_key_sigsize(const dst_key_t *key, unsigned int *n) {
1142 REQUIRE(dst_initialized == true);
1143 REQUIRE(VALID_KEY(key));
1144 REQUIRE(n != NULL);
1145
1146 /* XXXVIX this switch statement is too sparse to gen a jump table. */
1147 switch (key->key_alg) {
1148 case DST_ALG_RSAMD5:
1149 case DST_ALG_RSASHA1:
1150 case DST_ALG_NSEC3RSASHA1:
1151 case DST_ALG_RSASHA256:
1152 case DST_ALG_RSASHA512:
1153 *n = (key->key_size + 7) / 8;
1154 break;
1155 case DST_ALG_ECDSA256:
1156 *n = DNS_SIG_ECDSA256SIZE;
1157 break;
1158 case DST_ALG_ECDSA384:
1159 *n = DNS_SIG_ECDSA384SIZE;
1160 break;
1161 case DST_ALG_ED25519:
1162 *n = DNS_SIG_ED25519SIZE;
1163 break;
1164 case DST_ALG_ED448:
1165 *n = DNS_SIG_ED448SIZE;
1166 break;
1167 case DST_ALG_HMACMD5:
1168 *n = isc_md_type_get_size(ISC_MD_MD5);
1169 break;
1170 case DST_ALG_HMACSHA1:
1171 *n = isc_md_type_get_size(ISC_MD_SHA1);
1172 break;
1173 case DST_ALG_HMACSHA224:
1174 *n = isc_md_type_get_size(ISC_MD_SHA224);
1175 break;
1176 case DST_ALG_HMACSHA256:
1177 *n = isc_md_type_get_size(ISC_MD_SHA256);
1178 break;
1179 case DST_ALG_HMACSHA384:
1180 *n = isc_md_type_get_size(ISC_MD_SHA384);
1181 break;
1182 case DST_ALG_HMACSHA512:
1183 *n = isc_md_type_get_size(ISC_MD_SHA512);
1184 break;
1185 case DST_ALG_GSSAPI:
1186 *n = 128; /*%< XXX */
1187 break;
1188 case DST_ALG_DH:
1189 default:
1190 return (DST_R_UNSUPPORTEDALG);
1191 }
1192 return (ISC_R_SUCCESS);
1193 }
1194
1195 isc_result_t
1196 dst_key_secretsize(const dst_key_t *key, unsigned int *n) {
1197 REQUIRE(dst_initialized == true);
1198 REQUIRE(VALID_KEY(key));
1199 REQUIRE(n != NULL);
1200
1201 if (key->key_alg == DST_ALG_DH) {
1202 *n = (key->key_size + 7) / 8;
1203 return (ISC_R_SUCCESS);
1204 }
1205 return (DST_R_UNSUPPORTEDALG);
1206 }
1207
1208 /*%
1209 * Set the flags on a key, then recompute the key ID
1210 */
1211 isc_result_t
1212 dst_key_setflags(dst_key_t *key, uint32_t flags) {
1213 REQUIRE(VALID_KEY(key));
1214 key->key_flags = flags;
1215 return (computeid(key));
1216 }
1217
1218 void
1219 dst_key_format(const dst_key_t *key, char *cp, unsigned int size) {
1220 char namestr[DNS_NAME_FORMATSIZE];
1221 char algstr[DNS_NAME_FORMATSIZE];
1222
1223 dns_name_format(dst_key_name(key), namestr, sizeof(namestr));
1224 dns_secalg_format((dns_secalg_t) dst_key_alg(key), algstr,
1225 sizeof(algstr));
1226 snprintf(cp, size, "%s/%s/%d", namestr, algstr, dst_key_id(key));
1227 }
1228
1229 isc_result_t
1230 dst_key_dump(dst_key_t *key, isc_mem_t *mctx, char **buffer, int *length) {
1231
1232 REQUIRE(buffer != NULL && *buffer == NULL);
1233 REQUIRE(length != NULL && *length == 0);
1234 REQUIRE(VALID_KEY(key));
1235
1236 if (key->func->dump == NULL)
1237 return (ISC_R_NOTIMPLEMENTED);
1238 return (key->func->dump(key, mctx, buffer, length));
1239 }
1240
1241 isc_result_t
1242 dst_key_restore(dns_name_t *name, unsigned int alg, unsigned int flags,
1243 unsigned int protocol, dns_rdataclass_t rdclass,
1244 isc_mem_t *mctx, const char *keystr, dst_key_t **keyp)
1245 {
1246 isc_result_t result;
1247 dst_key_t *key;
1248
1249 REQUIRE(dst_initialized == true);
1250 REQUIRE(keyp != NULL && *keyp == NULL);
1251
1252 if (alg >= DST_MAX_ALGS || dst_t_func[alg] == NULL)
1253 return (DST_R_UNSUPPORTEDALG);
1254
1255 if (dst_t_func[alg]->restore == NULL)
1256 return (ISC_R_NOTIMPLEMENTED);
1257
1258 key = get_key_struct(name, alg, flags, protocol, 0, rdclass, 0, mctx);
1259 if (key == NULL)
1260 return (ISC_R_NOMEMORY);
1261
1262 result = (dst_t_func[alg]->restore)(key, keystr);
1263 if (result == ISC_R_SUCCESS)
1264 *keyp = key;
1265 else
1266 dst_key_free(&key);
1267
1268 return (result);
1269 }
1270
1271 /***
1272 *** Static methods
1273 ***/
1274
1275 /*%
1276 * Allocates a key structure and fills in some of the fields.
1277 */
1278 static dst_key_t *
1279 get_key_struct(const dns_name_t *name, unsigned int alg,
1280 unsigned int flags, unsigned int protocol,
1281 unsigned int bits, dns_rdataclass_t rdclass,
1282 dns_ttl_t ttl, isc_mem_t *mctx)
1283 {
1284 dst_key_t *key;
1285 isc_result_t result;
1286 int i;
1287
1288 key = (dst_key_t *) isc_mem_get(mctx, sizeof(dst_key_t));
1289 if (key == NULL)
1290 return (NULL);
1291
1292 memset(key, 0, sizeof(dst_key_t));
1293
1294 key->key_name = isc_mem_get(mctx, sizeof(dns_name_t));
1295 if (key->key_name == NULL) {
1296 isc_mem_put(mctx, key, sizeof(dst_key_t));
1297 return (NULL);
1298 }
1299
1300 dns_name_init(key->key_name, NULL);
1301 result = dns_name_dup(name, mctx, key->key_name);
1302 if (result != ISC_R_SUCCESS) {
1303 isc_mem_put(mctx, key->key_name, sizeof(dns_name_t));
1304 isc_mem_put(mctx, key, sizeof(dst_key_t));
1305 return (NULL);
1306 }
1307
1308 isc_refcount_init(&key->refs, 1);
1309 isc_mem_attach(mctx, &key->mctx);
1310 key->key_alg = alg;
1311 key->key_flags = flags;
1312 key->key_proto = protocol;
1313 key->keydata.generic = NULL;
1314 key->key_size = bits;
1315 key->key_class = rdclass;
1316 key->key_ttl = ttl;
1317 key->func = dst_t_func[alg];
1318 key->fmt_major = 0;
1319 key->fmt_minor = 0;
1320 for (i = 0; i < (DST_MAX_TIMES + 1); i++) {
1321 key->times[i] = 0;
1322 key->timeset[i] = false;
1323 }
1324 key->inactive = false;
1325 key->magic = KEY_MAGIC;
1326 return (key);
1327 }
1328
1329 bool
1330 dst_key_inactive(const dst_key_t *key) {
1331
1332 REQUIRE(VALID_KEY(key));
1333
1334 return (key->inactive);
1335 }
1336
1337 void
1338 dst_key_setinactive(dst_key_t *key, bool inactive) {
1339
1340 REQUIRE(VALID_KEY(key));
1341
1342 key->inactive = inactive;
1343 }
1344
1345 /*%
1346 * Reads a public key from disk
1347 */
1348 isc_result_t
1349 dst_key_read_public(const char *filename, int type,
1350 isc_mem_t *mctx, dst_key_t **keyp)
1351 {
1352 u_char rdatabuf[DST_KEY_MAXSIZE];
1353 isc_buffer_t b;
1354 dns_fixedname_t name;
1355 isc_lex_t *lex = NULL;
1356 isc_token_t token;
1357 isc_result_t ret;
1358 dns_rdata_t rdata = DNS_RDATA_INIT;
1359 unsigned int opt = ISC_LEXOPT_DNSMULTILINE;
1360 dns_rdataclass_t rdclass = dns_rdataclass_in;
1361 isc_lexspecials_t specials;
1362 uint32_t ttl = 0;
1363 isc_result_t result;
1364 dns_rdatatype_t keytype;
1365
1366 /*
1367 * Open the file and read its formatted contents
1368 * File format:
1369 * domain.name [ttl] [class] [KEY|DNSKEY] <flags> <protocol> <algorithm> <key>
1370 */
1371
1372 /* 1500 should be large enough for any key */
1373 ret = isc_lex_create(mctx, 1500, &lex);
1374 if (ret != ISC_R_SUCCESS)
1375 goto cleanup;
1376
1377 memset(specials, 0, sizeof(specials));
1378 specials['('] = 1;
1379 specials[')'] = 1;
1380 specials['"'] = 1;
1381 isc_lex_setspecials(lex, specials);
1382 isc_lex_setcomments(lex, ISC_LEXCOMMENT_DNSMASTERFILE);
1383
1384 ret = isc_lex_openfile(lex, filename);
1385 if (ret != ISC_R_SUCCESS)
1386 goto cleanup;
1387
1388 #define NEXTTOKEN(lex, opt, token) { \
1389 ret = isc_lex_gettoken(lex, opt, token); \
1390 if (ret != ISC_R_SUCCESS) \
1391 goto cleanup; \
1392 }
1393
1394 #define BADTOKEN() { \
1395 ret = ISC_R_UNEXPECTEDTOKEN; \
1396 goto cleanup; \
1397 }
1398
1399 /* Read the domain name */
1400 NEXTTOKEN(lex, opt, &token);
1401 if (token.type != isc_tokentype_string)
1402 BADTOKEN();
1403
1404 /*
1405 * We don't support "@" in .key files.
1406 */
1407 if (!strcmp(DST_AS_STR(token), "@"))
1408 BADTOKEN();
1409
1410 dns_fixedname_init(&name);
1411 isc_buffer_init(&b, DST_AS_STR(token), strlen(DST_AS_STR(token)));
1412 isc_buffer_add(&b, strlen(DST_AS_STR(token)));
1413 ret = dns_name_fromtext(dns_fixedname_name(&name), &b, dns_rootname,
1414 0, NULL);
1415 if (ret != ISC_R_SUCCESS)
1416 goto cleanup;
1417
1418 /* Read the next word: either TTL, class, or 'KEY' */
1419 NEXTTOKEN(lex, opt, &token);
1420
1421 if (token.type != isc_tokentype_string)
1422 BADTOKEN();
1423
1424 /* If it's a TTL, read the next one */
1425 result = dns_ttl_fromtext(&token.value.as_textregion, &ttl);
1426 if (result == ISC_R_SUCCESS)
1427 NEXTTOKEN(lex, opt, &token);
1428
1429 if (token.type != isc_tokentype_string)
1430 BADTOKEN();
1431
1432 ret = dns_rdataclass_fromtext(&rdclass, &token.value.as_textregion);
1433 if (ret == ISC_R_SUCCESS)
1434 NEXTTOKEN(lex, opt, &token);
1435
1436 if (token.type != isc_tokentype_string)
1437 BADTOKEN();
1438
1439 if (strcasecmp(DST_AS_STR(token), "DNSKEY") == 0)
1440 keytype = dns_rdatatype_dnskey;
1441 else if (strcasecmp(DST_AS_STR(token), "KEY") == 0)
1442 keytype = dns_rdatatype_key; /*%< SIG(0), TKEY */
1443 else
1444 BADTOKEN();
1445
1446 if (((type & DST_TYPE_KEY) != 0 && keytype != dns_rdatatype_key) ||
1447 ((type & DST_TYPE_KEY) == 0 && keytype != dns_rdatatype_dnskey)) {
1448 ret = DST_R_BADKEYTYPE;
1449 goto cleanup;
1450 }
1451
1452 isc_buffer_init(&b, rdatabuf, sizeof(rdatabuf));
1453 ret = dns_rdata_fromtext(&rdata, rdclass, keytype, lex, NULL,
1454 false, mctx, &b, NULL);
1455 if (ret != ISC_R_SUCCESS)
1456 goto cleanup;
1457
1458 ret = dst_key_fromdns(dns_fixedname_name(&name), rdclass, &b, mctx,
1459 keyp);
1460 if (ret != ISC_R_SUCCESS)
1461 goto cleanup;
1462
1463 dst_key_setttl(*keyp, ttl);
1464
1465 cleanup:
1466 if (lex != NULL)
1467 isc_lex_destroy(&lex);
1468 return (ret);
1469 }
1470
1471 static bool
1472 issymmetric(const dst_key_t *key) {
1473 REQUIRE(dst_initialized == true);
1474 REQUIRE(VALID_KEY(key));
1475
1476 /* XXXVIX this switch statement is too sparse to gen a jump table. */
1477 switch (key->key_alg) {
1478 case DST_ALG_RSAMD5:
1479 case DST_ALG_RSASHA1:
1480 case DST_ALG_NSEC3RSASHA1:
1481 case DST_ALG_RSASHA256:
1482 case DST_ALG_RSASHA512:
1483 case DST_ALG_DH:
1484 case DST_ALG_ECDSA256:
1485 case DST_ALG_ECDSA384:
1486 case DST_ALG_ED25519:
1487 case DST_ALG_ED448:
1488 return (false);
1489 case DST_ALG_HMACMD5:
1490 case DST_ALG_HMACSHA1:
1491 case DST_ALG_HMACSHA224:
1492 case DST_ALG_HMACSHA256:
1493 case DST_ALG_HMACSHA384:
1494 case DST_ALG_HMACSHA512:
1495 case DST_ALG_GSSAPI:
1496 return (true);
1497 default:
1498 return (false);
1499 }
1500 }
1501
1502 /*%
1503 * Write key timing metadata to a file pointer, preceded by 'tag'
1504 */
1505 static void
1506 printtime(const dst_key_t *key, int type, const char *tag, FILE *stream) {
1507 isc_result_t result;
1508 char output[26]; /* Minimum buffer as per ctime_r() specification. */
1509 isc_stdtime_t when;
1510 time_t t;
1511 char utc[sizeof("YYYYMMDDHHSSMM")];
1512 isc_buffer_t b;
1513 isc_region_t r;
1514
1515 result = dst_key_gettime(key, type, &when);
1516 if (result == ISC_R_NOTFOUND)
1517 return;
1518
1519 /* time_t and isc_stdtime_t might be different sizes */
1520 t = when;
1521 #ifdef WIN32
1522 if (ctime_s(output, sizeof(output), &t) != 0)
1523 goto error;
1524 #else
1525 if (ctime_r(&t, output) == NULL)
1526 goto error;
1527 #endif
1528
1529 isc_buffer_init(&b, utc, sizeof(utc));
1530 result = dns_time32_totext(when, &b);
1531 if (result != ISC_R_SUCCESS)
1532 goto error;
1533
1534 isc_buffer_usedregion(&b, &r);
1535 fprintf(stream, "%s: %.*s (%.*s)\n", tag, (int)r.length, r.base,
1536 (int)strlen(output) - 1, output);
1537 return;
1538
1539 error:
1540 fprintf(stream, "%s: (set, unable to display)\n", tag);
1541 }
1542
1543 /*%
1544 * Writes a public key to disk in DNS format.
1545 */
1546 static isc_result_t
1547 write_public_key(const dst_key_t *key, int type, const char *directory) {
1548 FILE *fp;
1549 isc_buffer_t keyb, textb, fileb, classb;
1550 isc_region_t r;
1551 char filename[NAME_MAX];
1552 unsigned char key_array[DST_KEY_MAXSIZE];
1553 char text_array[DST_KEY_MAXTEXTSIZE];
1554 char class_array[10];
1555 isc_result_t ret;
1556 dns_rdata_t rdata = DNS_RDATA_INIT;
1557 isc_fsaccess_t access;
1558
1559 REQUIRE(VALID_KEY(key));
1560
1561 isc_buffer_init(&keyb, key_array, sizeof(key_array));
1562 isc_buffer_init(&textb, text_array, sizeof(text_array));
1563 isc_buffer_init(&classb, class_array, sizeof(class_array));
1564
1565 ret = dst_key_todns(key, &keyb);
1566 if (ret != ISC_R_SUCCESS)
1567 return (ret);
1568
1569 isc_buffer_usedregion(&keyb, &r);
1570 dns_rdata_fromregion(&rdata, key->key_class, dns_rdatatype_dnskey, &r);
1571
1572 ret = dns_rdata_totext(&rdata, (dns_name_t *) NULL, &textb);
1573 if (ret != ISC_R_SUCCESS)
1574 return (DST_R_INVALIDPUBLICKEY);
1575
1576 ret = dns_rdataclass_totext(key->key_class, &classb);
1577 if (ret != ISC_R_SUCCESS)
1578 return (DST_R_INVALIDPUBLICKEY);
1579
1580 /*
1581 * Make the filename.
1582 */
1583 isc_buffer_init(&fileb, filename, sizeof(filename));
1584 ret = dst_key_buildfilename(key, DST_TYPE_PUBLIC, directory, &fileb);
1585 if (ret != ISC_R_SUCCESS)
1586 return (ret);
1587
1588 /*
1589 * Create public key file.
1590 */
1591 if ((fp = fopen(filename, "w")) == NULL)
1592 return (DST_R_WRITEERROR);
1593
1594 if (issymmetric(key)) {
1595 access = 0;
1596 isc_fsaccess_add(ISC_FSACCESS_OWNER,
1597 ISC_FSACCESS_READ | ISC_FSACCESS_WRITE,
1598 &access);
1599 (void)isc_fsaccess_set(filename, access);
1600 }
1601
1602 /* Write key information in comments */
1603 if ((type & DST_TYPE_KEY) == 0) {
1604 fprintf(fp, "; This is a %s%s-signing key, keyid %d, for ",
1605 (key->key_flags & DNS_KEYFLAG_REVOKE) != 0 ?
1606 "revoked " :
1607 "",
1608 (key->key_flags & DNS_KEYFLAG_KSK) != 0 ?
1609 "key" :
1610 "zone",
1611 key->key_id);
1612 ret = dns_name_print(key->key_name, fp);
1613 if (ret != ISC_R_SUCCESS) {
1614 fclose(fp);
1615 return (ret);
1616 }
1617 fputc('\n', fp);
1618
1619 printtime(key, DST_TIME_CREATED, "; Created", fp);
1620 printtime(key, DST_TIME_PUBLISH, "; Publish", fp);
1621 printtime(key, DST_TIME_ACTIVATE, "; Activate", fp);
1622 printtime(key, DST_TIME_REVOKE, "; Revoke", fp);
1623 printtime(key, DST_TIME_INACTIVE, "; Inactive", fp);
1624 printtime(key, DST_TIME_DELETE, "; Delete", fp);
1625 printtime(key, DST_TIME_SYNCPUBLISH , "; SyncPublish", fp);
1626 printtime(key, DST_TIME_SYNCDELETE , "; SyncDelete", fp);
1627 }
1628
1629 /* Now print the actual key */
1630 ret = dns_name_print(key->key_name, fp);
1631 fprintf(fp, " ");
1632
1633 if (key->key_ttl != 0)
1634 fprintf(fp, "%u ", key->key_ttl);
1635
1636 isc_buffer_usedregion(&classb, &r);
1637 if ((unsigned) fwrite(r.base, 1, r.length, fp) != r.length)
1638 ret = DST_R_WRITEERROR;
1639
1640 if ((type & DST_TYPE_KEY) != 0)
1641 fprintf(fp, " KEY ");
1642 else
1643 fprintf(fp, " DNSKEY ");
1644
1645 isc_buffer_usedregion(&textb, &r);
1646 if ((unsigned) fwrite(r.base, 1, r.length, fp) != r.length)
1647 ret = DST_R_WRITEERROR;
1648
1649 fputc('\n', fp);
1650 fflush(fp);
1651 if (ferror(fp))
1652 ret = DST_R_WRITEERROR;
1653 fclose(fp);
1654
1655 return (ret);
1656 }
1657
1658 static isc_result_t
1659 buildfilename(dns_name_t *name, dns_keytag_t id,
1660 unsigned int alg, unsigned int type,
1661 const char *directory, isc_buffer_t *out)
1662 {
1663 const char *suffix = "";
1664 isc_result_t result;
1665
1666 REQUIRE(out != NULL);
1667 if ((type & DST_TYPE_PRIVATE) != 0)
1668 suffix = ".private";
1669 else if (type == DST_TYPE_PUBLIC)
1670 suffix = ".key";
1671 if (directory != NULL) {
1672 if (isc_buffer_availablelength(out) < strlen(directory))
1673 return (ISC_R_NOSPACE);
1674 isc_buffer_putstr(out, directory);
1675 if (strlen(directory) > 0U &&
1676 directory[strlen(directory) - 1] != '/')
1677 isc_buffer_putstr(out, "/");
1678 }
1679 if (isc_buffer_availablelength(out) < 1)
1680 return (ISC_R_NOSPACE);
1681 isc_buffer_putstr(out, "K");
1682 result = dns_name_tofilenametext(name, false, out);
1683 if (result != ISC_R_SUCCESS)
1684 return (result);
1685
1686 return (isc_buffer_printf(out, "+%03d+%05d%s", alg, id, suffix));
1687 }
1688
1689 static isc_result_t
1690 computeid(dst_key_t *key) {
1691 isc_buffer_t dnsbuf;
1692 unsigned char dns_array[DST_KEY_MAXSIZE];
1693 isc_region_t r;
1694 isc_result_t ret;
1695
1696 isc_buffer_init(&dnsbuf, dns_array, sizeof(dns_array));
1697 ret = dst_key_todns(key, &dnsbuf);
1698 if (ret != ISC_R_SUCCESS)
1699 return (ret);
1700
1701 isc_buffer_usedregion(&dnsbuf, &r);
1702 key->key_id = dst_region_computeid(&r, key->key_alg);
1703 key->key_rid = dst_region_computerid(&r, key->key_alg);
1704 return (ISC_R_SUCCESS);
1705 }
1706
1707 static isc_result_t
1708 frombuffer(const dns_name_t *name, unsigned int alg, unsigned int flags,
1709 unsigned int protocol, dns_rdataclass_t rdclass,
1710 isc_buffer_t *source, isc_mem_t *mctx, dst_key_t **keyp)
1711 {
1712 dst_key_t *key;
1713 isc_result_t ret;
1714
1715 REQUIRE(dns_name_isabsolute(name));
1716 REQUIRE(source != NULL);
1717 REQUIRE(mctx != NULL);
1718 REQUIRE(keyp != NULL && *keyp == NULL);
1719
1720 key = get_key_struct(name, alg, flags, protocol, 0, rdclass, 0, mctx);
1721 if (key == NULL)
1722 return (ISC_R_NOMEMORY);
1723
1724 if (isc_buffer_remaininglength(source) > 0) {
1725 ret = algorithm_status(alg);
1726 if (ret != ISC_R_SUCCESS) {
1727 dst_key_free(&key);
1728 return (ret);
1729 }
1730 if (key->func->fromdns == NULL) {
1731 dst_key_free(&key);
1732 return (DST_R_UNSUPPORTEDALG);
1733 }
1734
1735 ret = key->func->fromdns(key, source);
1736 if (ret != ISC_R_SUCCESS) {
1737 dst_key_free(&key);
1738 return (ret);
1739 }
1740 }
1741
1742 *keyp = key;
1743 return (ISC_R_SUCCESS);
1744 }
1745
1746 static isc_result_t
1747 algorithm_status(unsigned int alg) {
1748 REQUIRE(dst_initialized == true);
1749
1750 if (dst_algorithm_supported(alg)) {
1751 return (ISC_R_SUCCESS);
1752 }
1753 return (DST_R_UNSUPPORTEDALG);
1754 }
1755
1756 static isc_result_t
1757 addsuffix(char *filename, int len, const char *odirname,
1758 const char *ofilename, const char *suffix)
1759 {
1760 int olen = strlen(ofilename);
1761 int n;
1762
1763 if (olen > 1 && ofilename[olen - 1] == '.')
1764 olen -= 1;
1765 else if (olen > 8 && strcmp(ofilename + olen - 8, ".private") == 0)
1766 olen -= 8;
1767 else if (olen > 4 && strcmp(ofilename + olen - 4, ".key") == 0)
1768 olen -= 4;
1769
1770 if (odirname == NULL)
1771 n = snprintf(filename, len, "%.*s%s", olen, ofilename, suffix);
1772 else
1773 n = snprintf(filename, len, "%s/%.*s%s",
1774 odirname, olen, ofilename, suffix);
1775 if (n < 0)
1776 return (ISC_R_FAILURE);
1777 if (n >= len)
1778 return (ISC_R_NOSPACE);
1779 return (ISC_R_SUCCESS);
1780 }
1781
1782 isc_buffer_t *
1783 dst_key_tkeytoken(const dst_key_t *key) {
1784 REQUIRE(VALID_KEY(key));
1785 return (key->key_tkeytoken);
1786 }
1787