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