Remove building with NOCRYPTO option
[minix.git] / external / bsd / bind / dist / lib / dns / dst_api.c
blobeae295b2f4af6cbb97fd1ddb951ded015969b078
1 /* $NetBSD: dst_api.c,v 1.11 2014/12/10 04:37:58 christos Exp $ */
3 /*
4 * Portions Copyright (C) 2004-2014 Internet Systems Consortium, Inc. ("ISC")
5 * Portions Copyright (C) 1999-2003 Internet Software Consortium.
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS
12 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
13 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE
14 * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
17 * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 * Portions Copyright (C) 1995-2000 by Network Associates, Inc.
21 * Permission to use, copy, modify, and/or distribute this software for any
22 * purpose with or without fee is hereby granted, provided that the above
23 * copyright notice and this permission notice appear in all copies.
25 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS
26 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
27 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE
28 * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
29 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
30 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
31 * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
35 * Principal Author: Brian Wellington
36 * Id: dst_api.c,v 1.65 2011/10/20 21:20:02 marka Exp
39 /*! \file */
41 #include <config.h>
43 #include <stdlib.h>
44 #include <time.h>
46 #include <isc/buffer.h>
47 #include <isc/dir.h>
48 #include <isc/entropy.h>
49 #include <isc/fsaccess.h>
50 #include <isc/hmacsha.h>
51 #include <isc/lex.h>
52 #include <isc/mem.h>
53 #include <isc/once.h>
54 #include <isc/platform.h>
55 #include <isc/print.h>
56 #include <isc/refcount.h>
57 #include <isc/random.h>
58 #include <isc/string.h>
59 #include <isc/time.h>
60 #include <isc/util.h>
61 #include <isc/file.h>
63 #define DST_KEY_INTERNAL
65 #include <dns/fixedname.h>
66 #include <dns/keyvalues.h>
67 #include <dns/name.h>
68 #include <dns/rdata.h>
69 #include <dns/rdataclass.h>
70 #include <dns/ttl.h>
71 #include <dns/types.h>
73 #include <dst/result.h>
75 #include "dst_internal.h"
77 #define DST_AS_STR(t) ((t).value.as_textregion.base)
79 static dst_func_t *dst_t_func[DST_MAX_ALGS];
80 static isc_entropy_t *dst_entropy_pool = NULL;
81 static unsigned int dst_entropy_flags = 0;
82 static isc_boolean_t dst_initialized = ISC_FALSE;
84 void gss_log(int level, const char *fmt, ...) ISC_FORMAT_PRINTF(2, 3);
86 isc_mem_t *dst__memory_pool = NULL;
89 * Static functions.
91 static dst_key_t * get_key_struct(dns_name_t *name,
92 unsigned int alg,
93 unsigned int flags,
94 unsigned int protocol,
95 unsigned int bits,
96 dns_rdataclass_t rdclass,
97 dns_ttl_t ttl,
98 isc_mem_t *mctx);
99 static isc_result_t write_public_key(const dst_key_t *key, int type,
100 const char *directory);
101 static isc_result_t buildfilename(dns_name_t *name,
102 dns_keytag_t id,
103 unsigned int alg,
104 unsigned int type,
105 const char *directory,
106 isc_buffer_t *out);
107 static isc_result_t computeid(dst_key_t *key);
108 static isc_result_t frombuffer(dns_name_t *name,
109 unsigned int alg,
110 unsigned int flags,
111 unsigned int protocol,
112 dns_rdataclass_t rdclass,
113 isc_buffer_t *source,
114 isc_mem_t *mctx,
115 dst_key_t **keyp);
117 static isc_result_t algorithm_status(unsigned int alg);
119 static isc_result_t addsuffix(char *filename, int len,
120 const char *dirname, const char *ofilename,
121 const char *suffix);
123 #define RETERR(x) \
124 do { \
125 result = (x); \
126 if (result != ISC_R_SUCCESS) \
127 goto out; \
128 } while (/*CONSTCOND*/0)
130 #define CHECKALG(alg) \
131 do { \
132 isc_result_t _r; \
133 _r = algorithm_status(alg); \
134 if (_r != ISC_R_SUCCESS) \
135 return (_r); \
136 } while (/*CONSTCOND*/0); \
138 #if defined(OPENSSL)
139 static void *
140 default_memalloc(void *arg, size_t size) {
141 UNUSED(arg);
142 if (size == 0U)
143 size = 1;
144 return (malloc(size));
147 static void
148 default_memfree(void *arg, void *ptr) {
149 UNUSED(arg);
150 free(ptr);
152 #endif
154 isc_result_t
155 dst_lib_init(isc_mem_t *mctx, isc_entropy_t *ectx, unsigned int eflags) {
156 return (dst_lib_init2(mctx, ectx, NULL, eflags));
159 isc_result_t
160 dst_lib_init2(isc_mem_t *mctx, isc_entropy_t *ectx,
161 const char *engine, unsigned int eflags) {
162 isc_result_t result;
164 REQUIRE(mctx != NULL);
165 UNUSED(ectx);
166 REQUIRE(dst_initialized == ISC_FALSE);
168 #if !defined(OPENSSL) && !defined(PKCS11CRYPTO)
169 UNUSED(engine);
170 #endif
172 dst__memory_pool = NULL;
174 #if defined(OPENSSL)
175 UNUSED(mctx);
177 * When using --with-openssl, there seems to be no good way of not
178 * leaking memory due to the openssl error handling mechanism.
179 * Avoid assertions by using a local memory context and not checking
180 * for leaks on exit. Note: as there are leaks we cannot use
181 * ISC_MEMFLAG_INTERNAL as it will free up memory still being used
182 * by libcrypto.
184 result = isc_mem_createx2(0, 0, default_memalloc, default_memfree,
185 NULL, &dst__memory_pool, 0);
186 if (result != ISC_R_SUCCESS)
187 return (result);
188 isc_mem_setname(dst__memory_pool, "dst", NULL);
189 #ifndef OPENSSL_LEAKS
190 isc_mem_setdestroycheck(dst__memory_pool, ISC_FALSE);
191 #endif
192 #else /* OPENSSL */
193 isc_mem_attach(mctx, &dst__memory_pool);
194 #endif /* OPENSSL */
195 if (ectx != NULL) {
196 isc_entropy_attach(ectx, &dst_entropy_pool);
197 dst_entropy_flags = eflags;
200 dst_result_register();
202 memset(dst_t_func, 0, sizeof(dst_t_func));
203 RETERR(dst__hmacmd5_init(&dst_t_func[DST_ALG_HMACMD5]));
204 RETERR(dst__hmacsha1_init(&dst_t_func[DST_ALG_HMACSHA1]));
205 RETERR(dst__hmacsha224_init(&dst_t_func[DST_ALG_HMACSHA224]));
206 RETERR(dst__hmacsha256_init(&dst_t_func[DST_ALG_HMACSHA256]));
207 RETERR(dst__hmacsha384_init(&dst_t_func[DST_ALG_HMACSHA384]));
208 RETERR(dst__hmacsha512_init(&dst_t_func[DST_ALG_HMACSHA512]));
209 #ifdef OPENSSL
210 RETERR(dst__openssl_init(engine));
211 RETERR(dst__opensslrsa_init(&dst_t_func[DST_ALG_RSAMD5],
212 DST_ALG_RSAMD5));
213 RETERR(dst__opensslrsa_init(&dst_t_func[DST_ALG_RSASHA1],
214 DST_ALG_RSASHA1));
215 RETERR(dst__opensslrsa_init(&dst_t_func[DST_ALG_NSEC3RSASHA1],
216 DST_ALG_NSEC3RSASHA1));
217 RETERR(dst__opensslrsa_init(&dst_t_func[DST_ALG_RSASHA256],
218 DST_ALG_RSASHA256));
219 RETERR(dst__opensslrsa_init(&dst_t_func[DST_ALG_RSASHA512],
220 DST_ALG_RSASHA512));
221 #ifdef HAVE_OPENSSL_DSA
222 RETERR(dst__openssldsa_init(&dst_t_func[DST_ALG_DSA]));
223 RETERR(dst__openssldsa_init(&dst_t_func[DST_ALG_NSEC3DSA]));
224 #endif
225 RETERR(dst__openssldh_init(&dst_t_func[DST_ALG_DH]));
226 #ifdef HAVE_OPENSSL_GOST
227 RETERR(dst__opensslgost_init(&dst_t_func[DST_ALG_ECCGOST]));
228 #endif
229 #ifdef HAVE_OPENSSL_ECDSA
230 RETERR(dst__opensslecdsa_init(&dst_t_func[DST_ALG_ECDSA256]));
231 RETERR(dst__opensslecdsa_init(&dst_t_func[DST_ALG_ECDSA384]));
232 #endif
233 #elif PKCS11CRYPTO
234 RETERR(dst__pkcs11_init(mctx, engine));
235 RETERR(dst__pkcs11rsa_init(&dst_t_func[DST_ALG_RSAMD5]));
236 RETERR(dst__pkcs11rsa_init(&dst_t_func[DST_ALG_RSASHA1]));
237 RETERR(dst__pkcs11rsa_init(&dst_t_func[DST_ALG_NSEC3RSASHA1]));
238 RETERR(dst__pkcs11rsa_init(&dst_t_func[DST_ALG_RSASHA256]));
239 RETERR(dst__pkcs11rsa_init(&dst_t_func[DST_ALG_RSASHA512]));
240 RETERR(dst__pkcs11dsa_init(&dst_t_func[DST_ALG_DSA]));
241 RETERR(dst__pkcs11dsa_init(&dst_t_func[DST_ALG_NSEC3DSA]));
242 RETERR(dst__pkcs11dh_init(&dst_t_func[DST_ALG_DH]));
243 #ifdef HAVE_PKCS11_ECDSA
244 RETERR(dst__pkcs11ecdsa_init(&dst_t_func[DST_ALG_ECDSA256]));
245 RETERR(dst__pkcs11ecdsa_init(&dst_t_func[DST_ALG_ECDSA384]));
246 #endif
247 #ifdef HAVE_PKCS11_GOST
248 RETERR(dst__pkcs11gost_init(&dst_t_func[DST_ALG_ECCGOST]));
249 #endif
250 #endif /* if OPENSSL, elif PKCS11CRYPTO */
251 #ifdef GSSAPI
252 RETERR(dst__gssapi_init(&dst_t_func[DST_ALG_GSSAPI]));
253 #endif
254 dst_initialized = ISC_TRUE;
255 return (ISC_R_SUCCESS);
257 out:
258 /* avoid immediate crash! */
259 dst_initialized = ISC_TRUE;
260 dst_lib_destroy();
261 return (result);
264 void
265 dst_lib_destroy(void) {
266 int i;
267 RUNTIME_CHECK(dst_initialized == ISC_TRUE);
268 dst_initialized = ISC_FALSE;
270 for (i = 0; i < DST_MAX_ALGS; i++)
271 if (dst_t_func[i] != NULL && dst_t_func[i]->cleanup != NULL)
272 dst_t_func[i]->cleanup();
273 #ifdef OPENSSL
274 dst__openssl_destroy();
275 #elif PKCS11CRYPTO
276 (void) dst__pkcs11_destroy();
277 #endif /* if OPENSSL, elif PKCS11CRYPTO */
278 if (dst__memory_pool != NULL)
279 isc_mem_detach(&dst__memory_pool);
280 if (dst_entropy_pool != NULL)
281 isc_entropy_detach(&dst_entropy_pool);
284 isc_boolean_t
285 dst_algorithm_supported(unsigned int alg) {
286 REQUIRE(dst_initialized == ISC_TRUE);
288 if (alg >= DST_MAX_ALGS || dst_t_func[alg] == NULL)
289 return (ISC_FALSE);
290 return (ISC_TRUE);
293 isc_boolean_t
294 dst_ds_digest_supported(unsigned int digest_type) {
295 #if defined(HAVE_OPENSSL_GOST) || defined(HAVE_PKCS11_GOST)
296 return (ISC_TF(digest_type == DNS_DSDIGEST_SHA1 ||
297 digest_type == DNS_DSDIGEST_SHA256 ||
298 digest_type == DNS_DSDIGEST_GOST ||
299 digest_type == DNS_DSDIGEST_SHA384));
300 #else
301 return (ISC_TF(digest_type == DNS_DSDIGEST_SHA1 ||
302 digest_type == DNS_DSDIGEST_SHA256 ||
303 digest_type == DNS_DSDIGEST_SHA384));
304 #endif
307 isc_result_t
308 dst_context_create(dst_key_t *key, isc_mem_t *mctx, dst_context_t **dctxp) {
309 return (dst_context_create4(key, mctx, DNS_LOGCATEGORY_GENERAL,
310 ISC_TRUE, 0, dctxp));
313 isc_result_t
314 dst_context_create2(dst_key_t *key, isc_mem_t *mctx,
315 isc_logcategory_t *category, dst_context_t **dctxp)
317 return (dst_context_create4(key, mctx, category, ISC_TRUE, 0, dctxp));
320 isc_result_t
321 dst_context_create3(dst_key_t *key, isc_mem_t *mctx,
322 isc_logcategory_t *category, isc_boolean_t useforsigning,
323 dst_context_t **dctxp)
325 return (dst_context_create4(key, mctx, category,
326 useforsigning, 0, dctxp));
329 isc_result_t
330 dst_context_create4(dst_key_t *key, isc_mem_t *mctx,
331 isc_logcategory_t *category, isc_boolean_t useforsigning,
332 int maxbits, dst_context_t **dctxp)
334 dst_context_t *dctx;
335 isc_result_t result;
337 REQUIRE(dst_initialized == ISC_TRUE);
338 REQUIRE(VALID_KEY(key));
339 REQUIRE(mctx != NULL);
340 REQUIRE(dctxp != NULL && *dctxp == NULL);
342 if (key->func->createctx == NULL &&
343 key->func->createctx2 == NULL)
344 return (DST_R_UNSUPPORTEDALG);
345 if (key->keydata.generic == NULL)
346 return (DST_R_NULLKEY);
348 dctx = isc_mem_get(mctx, sizeof(dst_context_t));
349 if (dctx == NULL)
350 return (ISC_R_NOMEMORY);
351 dctx->key = key;
352 dctx->mctx = mctx;
353 dctx->category = category;
354 if (useforsigning)
355 dctx->use = DO_SIGN;
356 else
357 dctx->use = DO_VERIFY;
358 if (key->func->createctx2 != NULL)
359 result = key->func->createctx2(key, maxbits, dctx);
360 else
361 result = key->func->createctx(key, dctx);
362 if (result != ISC_R_SUCCESS) {
363 isc_mem_put(mctx, dctx, sizeof(dst_context_t));
364 return (result);
366 dctx->magic = CTX_MAGIC;
367 *dctxp = dctx;
368 return (ISC_R_SUCCESS);
371 void
372 dst_context_destroy(dst_context_t **dctxp) {
373 dst_context_t *dctx;
375 REQUIRE(dctxp != NULL && VALID_CTX(*dctxp));
377 dctx = *dctxp;
378 INSIST(dctx->key->func->destroyctx != NULL);
379 dctx->key->func->destroyctx(dctx);
380 dctx->magic = 0;
381 isc_mem_put(dctx->mctx, dctx, sizeof(dst_context_t));
382 *dctxp = NULL;
385 isc_result_t
386 dst_context_adddata(dst_context_t *dctx, const isc_region_t *data) {
387 REQUIRE(VALID_CTX(dctx));
388 REQUIRE(data != NULL);
389 INSIST(dctx->key->func->adddata != NULL);
391 return (dctx->key->func->adddata(dctx, data));
394 isc_result_t
395 dst_context_sign(dst_context_t *dctx, isc_buffer_t *sig) {
396 dst_key_t *key;
398 REQUIRE(VALID_CTX(dctx));
399 REQUIRE(sig != NULL);
401 key = dctx->key;
402 CHECKALG(key->key_alg);
403 if (key->keydata.generic == NULL)
404 return (DST_R_NULLKEY);
406 if (key->func->sign == NULL)
407 return (DST_R_NOTPRIVATEKEY);
408 if (key->func->isprivate == NULL ||
409 key->func->isprivate(key) == ISC_FALSE)
410 return (DST_R_NOTPRIVATEKEY);
412 return (key->func->sign(dctx, sig));
415 isc_result_t
416 dst_context_verify(dst_context_t *dctx, isc_region_t *sig) {
417 REQUIRE(VALID_CTX(dctx));
418 REQUIRE(sig != NULL);
420 CHECKALG(dctx->key->key_alg);
421 if (dctx->key->keydata.generic == NULL)
422 return (DST_R_NULLKEY);
423 if (dctx->key->func->verify == NULL)
424 return (DST_R_NOTPUBLICKEY);
426 return (dctx->key->func->verify(dctx, sig));
429 isc_result_t
430 dst_context_verify2(dst_context_t *dctx, unsigned int maxbits,
431 isc_region_t *sig)
433 REQUIRE(VALID_CTX(dctx));
434 REQUIRE(sig != NULL);
436 CHECKALG(dctx->key->key_alg);
437 if (dctx->key->keydata.generic == NULL)
438 return (DST_R_NULLKEY);
439 if (dctx->key->func->verify == NULL &&
440 dctx->key->func->verify2 == NULL)
441 return (DST_R_NOTPUBLICKEY);
443 return (dctx->key->func->verify2 != NULL ?
444 dctx->key->func->verify2(dctx, maxbits, sig) :
445 dctx->key->func->verify(dctx, sig));
448 isc_result_t
449 dst_key_computesecret(const dst_key_t *pub, const dst_key_t *priv,
450 isc_buffer_t *secret)
452 REQUIRE(dst_initialized == ISC_TRUE);
453 REQUIRE(VALID_KEY(pub) && VALID_KEY(priv));
454 REQUIRE(secret != NULL);
456 CHECKALG(pub->key_alg);
457 CHECKALG(priv->key_alg);
459 if (pub->keydata.generic == NULL || priv->keydata.generic == NULL)
460 return (DST_R_NULLKEY);
462 if (pub->key_alg != priv->key_alg ||
463 pub->func->computesecret == NULL ||
464 priv->func->computesecret == NULL)
465 return (DST_R_KEYCANNOTCOMPUTESECRET);
467 if (dst_key_isprivate(priv) == ISC_FALSE)
468 return (DST_R_NOTPRIVATEKEY);
470 return (pub->func->computesecret(pub, priv, secret));
473 isc_result_t
474 dst_key_tofile(const dst_key_t *key, int type, const char *directory) {
475 isc_result_t ret = ISC_R_SUCCESS;
477 REQUIRE(dst_initialized == ISC_TRUE);
478 REQUIRE(VALID_KEY(key));
479 REQUIRE((type & (DST_TYPE_PRIVATE | DST_TYPE_PUBLIC)) != 0);
481 CHECKALG(key->key_alg);
483 if (key->func->tofile == NULL)
484 return (DST_R_UNSUPPORTEDALG);
486 if (type & DST_TYPE_PUBLIC) {
487 ret = write_public_key(key, type, directory);
488 if (ret != ISC_R_SUCCESS)
489 return (ret);
492 if ((type & DST_TYPE_PRIVATE) &&
493 (key->key_flags & DNS_KEYFLAG_TYPEMASK) != DNS_KEYTYPE_NOKEY)
494 return (key->func->tofile(key, directory));
495 else
496 return (ISC_R_SUCCESS);
499 void
500 dst_key_setexternal(dst_key_t *key, isc_boolean_t value) {
501 key->external = value;
504 isc_boolean_t
505 dst_key_isexternal(dst_key_t *key) {
506 return (key->external);
509 isc_result_t
510 dst_key_fromfile(dns_name_t *name, dns_keytag_t id,
511 unsigned int alg, int type, const char *directory,
512 isc_mem_t *mctx, dst_key_t **keyp)
514 char filename[ISC_DIR_NAMEMAX];
515 isc_buffer_t b;
516 dst_key_t *key;
517 isc_result_t result;
519 REQUIRE(dst_initialized == ISC_TRUE);
520 REQUIRE(dns_name_isabsolute(name));
521 REQUIRE((type & (DST_TYPE_PRIVATE | DST_TYPE_PUBLIC)) != 0);
522 REQUIRE(mctx != NULL);
523 REQUIRE(keyp != NULL && *keyp == NULL);
525 CHECKALG(alg);
527 isc_buffer_init(&b, filename, sizeof(filename));
528 result = buildfilename(name, id, alg, type, directory, &b);
529 if (result != ISC_R_SUCCESS)
530 return (result);
532 key = NULL;
533 result = dst_key_fromnamedfile(filename, NULL, type, mctx, &key);
534 if (result != ISC_R_SUCCESS)
535 return (result);
537 result = computeid(key);
538 if (result != ISC_R_SUCCESS) {
539 dst_key_free(&key);
540 return (result);
543 if (!dns_name_equal(name, key->key_name) || id != key->key_id ||
544 alg != key->key_alg) {
545 dst_key_free(&key);
546 return (DST_R_INVALIDPRIVATEKEY);
549 *keyp = key;
550 return (ISC_R_SUCCESS);
553 isc_result_t
554 dst_key_fromnamedfile(const char *filename, const char *dirname,
555 int type, isc_mem_t *mctx, dst_key_t **keyp)
557 isc_result_t result;
558 dst_key_t *pubkey = NULL, *key = NULL;
559 char *newfilename = NULL;
560 int newfilenamelen = 0;
561 isc_lex_t *lex = NULL;
563 REQUIRE(dst_initialized == ISC_TRUE);
564 REQUIRE(filename != NULL);
565 REQUIRE((type & (DST_TYPE_PRIVATE | DST_TYPE_PUBLIC)) != 0);
566 REQUIRE(mctx != NULL);
567 REQUIRE(keyp != NULL && *keyp == NULL);
569 /* If an absolute path is specified, don't use the key directory */
570 #ifndef WIN32
571 if (filename[0] == '/')
572 dirname = NULL;
573 #else /* WIN32 */
574 if (filename[0] == '/' || filename[0] == '\\')
575 dirname = NULL;
576 #endif
578 newfilenamelen = strlen(filename) + 5;
579 if (dirname != NULL)
580 newfilenamelen += strlen(dirname) + 1;
581 newfilename = isc_mem_get(mctx, newfilenamelen);
582 if (newfilename == NULL)
583 return (ISC_R_NOMEMORY);
584 result = addsuffix(newfilename, newfilenamelen,
585 dirname, filename, ".key");
586 INSIST(result == ISC_R_SUCCESS);
588 result = dst_key_read_public(newfilename, type, mctx, &pubkey);
589 isc_mem_put(mctx, newfilename, newfilenamelen);
590 newfilename = NULL;
591 RETERR(result);
593 if ((type & (DST_TYPE_PRIVATE | DST_TYPE_PUBLIC)) == DST_TYPE_PUBLIC ||
594 (pubkey->key_flags & DNS_KEYFLAG_TYPEMASK) == DNS_KEYTYPE_NOKEY) {
595 result = computeid(pubkey);
596 if (result != ISC_R_SUCCESS) {
597 dst_key_free(&pubkey);
598 return (result);
601 *keyp = pubkey;
602 return (ISC_R_SUCCESS);
605 result = algorithm_status(pubkey->key_alg);
606 if (result != ISC_R_SUCCESS) {
607 dst_key_free(&pubkey);
608 return (result);
611 key = get_key_struct(pubkey->key_name, pubkey->key_alg,
612 pubkey->key_flags, pubkey->key_proto, 0,
613 pubkey->key_class, pubkey->key_ttl, mctx);
614 if (key == NULL) {
615 dst_key_free(&pubkey);
616 return (ISC_R_NOMEMORY);
619 if (key->func->parse == NULL)
620 RETERR(DST_R_UNSUPPORTEDALG);
622 newfilenamelen = strlen(filename) + 9;
623 if (dirname != NULL)
624 newfilenamelen += strlen(dirname) + 1;
625 newfilename = isc_mem_get(mctx, newfilenamelen);
626 if (newfilename == NULL)
627 RETERR(ISC_R_NOMEMORY);
628 result = addsuffix(newfilename, newfilenamelen,
629 dirname, filename, ".private");
630 INSIST(result == ISC_R_SUCCESS);
632 RETERR(isc_lex_create(mctx, 1500, &lex));
633 RETERR(isc_lex_openfile(lex, newfilename));
634 isc_mem_put(mctx, newfilename, newfilenamelen);
636 RETERR(key->func->parse(key, lex, pubkey));
637 isc_lex_destroy(&lex);
639 RETERR(computeid(key));
641 if (pubkey->key_id != key->key_id)
642 RETERR(DST_R_INVALIDPRIVATEKEY);
643 dst_key_free(&pubkey);
645 *keyp = key;
646 return (ISC_R_SUCCESS);
648 out:
649 if (pubkey != NULL)
650 dst_key_free(&pubkey);
651 if (newfilename != NULL)
652 isc_mem_put(mctx, newfilename, newfilenamelen);
653 if (lex != NULL)
654 isc_lex_destroy(&lex);
655 if (key != NULL)
656 dst_key_free(&key);
657 return (result);
660 isc_result_t
661 dst_key_todns(const dst_key_t *key, isc_buffer_t *target) {
662 REQUIRE(dst_initialized == ISC_TRUE);
663 REQUIRE(VALID_KEY(key));
664 REQUIRE(target != NULL);
666 CHECKALG(key->key_alg);
668 if (key->func->todns == NULL)
669 return (DST_R_UNSUPPORTEDALG);
671 if (isc_buffer_availablelength(target) < 4)
672 return (ISC_R_NOSPACE);
673 isc_buffer_putuint16(target, (isc_uint16_t)(key->key_flags & 0xffff));
674 isc_buffer_putuint8(target, (isc_uint8_t)key->key_proto);
675 isc_buffer_putuint8(target, (isc_uint8_t)key->key_alg);
677 if (key->key_flags & DNS_KEYFLAG_EXTENDED) {
678 if (isc_buffer_availablelength(target) < 2)
679 return (ISC_R_NOSPACE);
680 isc_buffer_putuint16(target,
681 (isc_uint16_t)((key->key_flags >> 16)
682 & 0xffff));
685 if (key->keydata.generic == NULL) /*%< NULL KEY */
686 return (ISC_R_SUCCESS);
688 return (key->func->todns(key, target));
691 isc_result_t
692 dst_key_fromdns(dns_name_t *name, dns_rdataclass_t rdclass,
693 isc_buffer_t *source, isc_mem_t *mctx, dst_key_t **keyp)
695 isc_uint8_t alg, proto;
696 isc_uint32_t flags, extflags;
697 dst_key_t *key = NULL;
698 dns_keytag_t id, rid;
699 isc_region_t r;
700 isc_result_t result;
702 REQUIRE(dst_initialized);
704 isc_buffer_remainingregion(source, &r);
706 if (isc_buffer_remaininglength(source) < 4)
707 return (DST_R_INVALIDPUBLICKEY);
708 flags = isc_buffer_getuint16(source);
709 proto = isc_buffer_getuint8(source);
710 alg = isc_buffer_getuint8(source);
712 id = dst_region_computeid(&r, alg);
713 rid = dst_region_computerid(&r, alg);
715 if (flags & DNS_KEYFLAG_EXTENDED) {
716 if (isc_buffer_remaininglength(source) < 2)
717 return (DST_R_INVALIDPUBLICKEY);
718 extflags = isc_buffer_getuint16(source);
719 flags |= (extflags << 16);
722 result = frombuffer(name, alg, flags, proto, rdclass, source,
723 mctx, &key);
724 if (result != ISC_R_SUCCESS)
725 return (result);
726 key->key_id = id;
727 key->key_rid = rid;
729 *keyp = key;
730 return (ISC_R_SUCCESS);
733 isc_result_t
734 dst_key_frombuffer(dns_name_t *name, unsigned int alg,
735 unsigned int flags, unsigned int protocol,
736 dns_rdataclass_t rdclass,
737 isc_buffer_t *source, isc_mem_t *mctx, dst_key_t **keyp)
739 dst_key_t *key = NULL;
740 isc_result_t result;
742 REQUIRE(dst_initialized);
744 result = frombuffer(name, alg, flags, protocol, rdclass, source,
745 mctx, &key);
746 if (result != ISC_R_SUCCESS)
747 return (result);
749 result = computeid(key);
750 if (result != ISC_R_SUCCESS) {
751 dst_key_free(&key);
752 return (result);
755 *keyp = key;
756 return (ISC_R_SUCCESS);
759 isc_result_t
760 dst_key_tobuffer(const dst_key_t *key, isc_buffer_t *target) {
761 REQUIRE(dst_initialized == ISC_TRUE);
762 REQUIRE(VALID_KEY(key));
763 REQUIRE(target != NULL);
765 CHECKALG(key->key_alg);
767 if (key->func->todns == NULL)
768 return (DST_R_UNSUPPORTEDALG);
770 return (key->func->todns(key, target));
773 isc_result_t
774 dst_key_privatefrombuffer(dst_key_t *key, isc_buffer_t *buffer) {
775 isc_lex_t *lex = NULL;
776 isc_result_t result = ISC_R_SUCCESS;
778 REQUIRE(dst_initialized == ISC_TRUE);
779 REQUIRE(VALID_KEY(key));
780 REQUIRE(!dst_key_isprivate(key));
781 REQUIRE(buffer != NULL);
783 if (key->func->parse == NULL)
784 RETERR(DST_R_UNSUPPORTEDALG);
786 RETERR(isc_lex_create(key->mctx, 1500, &lex));
787 RETERR(isc_lex_openbuffer(lex, buffer));
788 RETERR(key->func->parse(key, lex, NULL));
789 out:
790 if (lex != NULL)
791 isc_lex_destroy(&lex);
792 return (result);
795 gss_ctx_id_t
796 dst_key_getgssctx(const dst_key_t *key)
798 REQUIRE(key != NULL);
800 return (key->keydata.gssctx);
803 isc_result_t
804 dst_key_fromgssapi(dns_name_t *name, gss_ctx_id_t gssctx, isc_mem_t *mctx,
805 dst_key_t **keyp, isc_region_t *intoken)
807 dst_key_t *key;
808 isc_result_t result;
810 REQUIRE(gssctx != NULL);
811 REQUIRE(keyp != NULL && *keyp == NULL);
813 key = get_key_struct(name, DST_ALG_GSSAPI, 0, DNS_KEYPROTO_DNSSEC,
814 0, dns_rdataclass_in, 0, mctx);
815 if (key == NULL)
816 return (ISC_R_NOMEMORY);
818 if (intoken != NULL) {
820 * Keep the token for use by external ssu rules. They may need
821 * to examine the PAC in the kerberos ticket.
823 RETERR(isc_buffer_allocate(key->mctx, &key->key_tkeytoken,
824 intoken->length));
825 RETERR(isc_buffer_copyregion(key->key_tkeytoken, intoken));
828 key->keydata.gssctx = gssctx;
829 *keyp = key;
830 result = ISC_R_SUCCESS;
831 out:
832 return result;
835 isc_result_t
836 dst_key_buildinternal(dns_name_t *name, unsigned int alg,
837 unsigned int bits, unsigned int flags,
838 unsigned int protocol, dns_rdataclass_t rdclass,
839 void *data, isc_mem_t *mctx, dst_key_t **keyp)
841 dst_key_t *key;
842 isc_result_t result;
844 REQUIRE(dst_initialized == ISC_TRUE);
845 REQUIRE(dns_name_isabsolute(name));
846 REQUIRE(mctx != NULL);
847 REQUIRE(keyp != NULL && *keyp == NULL);
848 REQUIRE(data != NULL);
850 CHECKALG(alg);
852 key = get_key_struct(name, alg, flags, protocol, bits, rdclass,
853 0, mctx);
854 if (key == NULL)
855 return (ISC_R_NOMEMORY);
857 key->keydata.generic = data;
859 result = computeid(key);
860 if (result != ISC_R_SUCCESS) {
861 dst_key_free(&key);
862 return (result);
865 *keyp = key;
866 return (ISC_R_SUCCESS);
869 isc_result_t
870 dst_key_fromlabel(dns_name_t *name, int alg, unsigned int flags,
871 unsigned int protocol, dns_rdataclass_t rdclass,
872 const char *engine, const char *label, const char *pin,
873 isc_mem_t *mctx, dst_key_t **keyp)
875 dst_key_t *key;
876 isc_result_t result;
878 REQUIRE(dst_initialized == ISC_TRUE);
879 REQUIRE(dns_name_isabsolute(name));
880 REQUIRE(mctx != NULL);
881 REQUIRE(keyp != NULL && *keyp == NULL);
882 REQUIRE(label != NULL);
884 CHECKALG(alg);
886 key = get_key_struct(name, alg, flags, protocol, 0, rdclass, 0, mctx);
887 if (key == NULL)
888 return (ISC_R_NOMEMORY);
890 if (key->func->fromlabel == NULL) {
891 dst_key_free(&key);
892 return (DST_R_UNSUPPORTEDALG);
895 result = key->func->fromlabel(key, engine, label, pin);
896 if (result != ISC_R_SUCCESS) {
897 dst_key_free(&key);
898 return (result);
901 result = computeid(key);
902 if (result != ISC_R_SUCCESS) {
903 dst_key_free(&key);
904 return (result);
907 *keyp = key;
908 return (ISC_R_SUCCESS);
911 isc_result_t
912 dst_key_generate(dns_name_t *name, unsigned int alg,
913 unsigned int bits, unsigned int param,
914 unsigned int flags, unsigned int protocol,
915 dns_rdataclass_t rdclass,
916 isc_mem_t *mctx, dst_key_t **keyp)
918 return (dst_key_generate2(name, alg, bits, param, flags, protocol,
919 rdclass, mctx, keyp, NULL));
922 isc_result_t
923 dst_key_generate2(dns_name_t *name, unsigned int alg,
924 unsigned int bits, unsigned int param,
925 unsigned int flags, unsigned int protocol,
926 dns_rdataclass_t rdclass,
927 isc_mem_t *mctx, dst_key_t **keyp,
928 void (*callback)(int))
930 dst_key_t *key;
931 isc_result_t ret;
933 REQUIRE(dst_initialized == ISC_TRUE);
934 REQUIRE(dns_name_isabsolute(name));
935 REQUIRE(mctx != NULL);
936 REQUIRE(keyp != NULL && *keyp == NULL);
938 CHECKALG(alg);
940 key = get_key_struct(name, alg, flags, protocol, bits,
941 rdclass, 0, mctx);
942 if (key == NULL)
943 return (ISC_R_NOMEMORY);
945 if (bits == 0) { /*%< NULL KEY */
946 key->key_flags |= DNS_KEYTYPE_NOKEY;
947 *keyp = key;
948 return (ISC_R_SUCCESS);
951 if (key->func->generate == NULL) {
952 dst_key_free(&key);
953 return (DST_R_UNSUPPORTEDALG);
956 ret = key->func->generate(key, param, callback);
957 if (ret != ISC_R_SUCCESS) {
958 dst_key_free(&key);
959 return (ret);
962 ret = computeid(key);
963 if (ret != ISC_R_SUCCESS) {
964 dst_key_free(&key);
965 return (ret);
968 *keyp = key;
969 return (ISC_R_SUCCESS);
972 isc_result_t
973 dst_key_getnum(const dst_key_t *key, int type, isc_uint32_t *valuep)
975 REQUIRE(VALID_KEY(key));
976 REQUIRE(valuep != NULL);
977 REQUIRE(type <= DST_MAX_NUMERIC);
978 if (!key->numset[type])
979 return (ISC_R_NOTFOUND);
980 *valuep = key->nums[type];
981 return (ISC_R_SUCCESS);
984 void
985 dst_key_setnum(dst_key_t *key, int type, isc_uint32_t value)
987 REQUIRE(VALID_KEY(key));
988 REQUIRE(type <= DST_MAX_NUMERIC);
989 key->nums[type] = value;
990 key->numset[type] = ISC_TRUE;
993 void
994 dst_key_unsetnum(dst_key_t *key, int type)
996 REQUIRE(VALID_KEY(key));
997 REQUIRE(type <= DST_MAX_NUMERIC);
998 key->numset[type] = ISC_FALSE;
1001 isc_result_t
1002 dst_key_gettime(const dst_key_t *key, int type, isc_stdtime_t *timep) {
1003 REQUIRE(VALID_KEY(key));
1004 REQUIRE(timep != NULL);
1005 REQUIRE(type <= DST_MAX_TIMES);
1006 if (!key->timeset[type])
1007 return (ISC_R_NOTFOUND);
1008 *timep = key->times[type];
1009 return (ISC_R_SUCCESS);
1012 void
1013 dst_key_settime(dst_key_t *key, int type, isc_stdtime_t when) {
1014 REQUIRE(VALID_KEY(key));
1015 REQUIRE(type <= DST_MAX_TIMES);
1016 key->times[type] = when;
1017 key->timeset[type] = ISC_TRUE;
1020 void
1021 dst_key_unsettime(dst_key_t *key, int type) {
1022 REQUIRE(VALID_KEY(key));
1023 REQUIRE(type <= DST_MAX_TIMES);
1024 key->timeset[type] = ISC_FALSE;
1027 isc_result_t
1028 dst_key_getprivateformat(const dst_key_t *key, int *majorp, int *minorp) {
1029 REQUIRE(VALID_KEY(key));
1030 REQUIRE(majorp != NULL);
1031 REQUIRE(minorp != NULL);
1032 *majorp = key->fmt_major;
1033 *minorp = key->fmt_minor;
1034 return (ISC_R_SUCCESS);
1037 void
1038 dst_key_setprivateformat(dst_key_t *key, int major, int minor) {
1039 REQUIRE(VALID_KEY(key));
1040 key->fmt_major = major;
1041 key->fmt_minor = minor;
1044 static isc_boolean_t
1045 comparekeys(const dst_key_t *key1, const dst_key_t *key2,
1046 isc_boolean_t match_revoked_key,
1047 isc_boolean_t (*compare)(const dst_key_t *key1,
1048 const dst_key_t *key2))
1050 REQUIRE(dst_initialized == ISC_TRUE);
1051 REQUIRE(VALID_KEY(key1));
1052 REQUIRE(VALID_KEY(key2));
1054 if (key1 == key2)
1055 return (ISC_TRUE);
1057 if (key1 == NULL || key2 == NULL)
1058 return (ISC_FALSE);
1060 if (key1->key_alg != key2->key_alg)
1061 return (ISC_FALSE);
1063 if (key1->key_id != key2->key_id) {
1064 if (!match_revoked_key)
1065 return (ISC_FALSE);
1066 if (key1->key_alg == DST_ALG_RSAMD5)
1067 return (ISC_FALSE);
1068 if ((key1->key_flags & DNS_KEYFLAG_REVOKE) ==
1069 (key2->key_flags & DNS_KEYFLAG_REVOKE))
1070 return (ISC_FALSE);
1071 if (key1->key_id != key2->key_rid &&
1072 key1->key_rid != key2->key_id)
1073 return (ISC_FALSE);
1076 if (compare != NULL)
1077 return (compare(key1, key2));
1078 else
1079 return (ISC_FALSE);
1084 * Compares only the public portion of two keys, by converting them
1085 * both to wire format and comparing the results.
1087 static isc_boolean_t
1088 pub_compare(const dst_key_t *key1, const dst_key_t *key2) {
1089 isc_result_t result;
1090 unsigned char buf1[DST_KEY_MAXSIZE], buf2[DST_KEY_MAXSIZE];
1091 isc_buffer_t b1, b2;
1092 isc_region_t r1, r2;
1094 isc_buffer_init(&b1, buf1, sizeof(buf1));
1095 result = dst_key_todns(key1, &b1);
1096 if (result != ISC_R_SUCCESS)
1097 return (ISC_FALSE);
1098 /* Zero out flags. */
1099 buf1[0] = buf1[1] = 0;
1100 if ((key1->key_flags & DNS_KEYFLAG_EXTENDED) != 0)
1101 isc_buffer_subtract(&b1, 2);
1103 isc_buffer_init(&b2, buf2, sizeof(buf2));
1104 result = dst_key_todns(key2, &b2);
1105 if (result != ISC_R_SUCCESS)
1106 return (ISC_FALSE);
1107 /* Zero out flags. */
1108 buf2[0] = buf2[1] = 0;
1109 if ((key2->key_flags & DNS_KEYFLAG_EXTENDED) != 0)
1110 isc_buffer_subtract(&b2, 2);
1112 isc_buffer_usedregion(&b1, &r1);
1113 /* Remove extended flags. */
1114 if ((key1->key_flags & DNS_KEYFLAG_EXTENDED) != 0) {
1115 memmove(&buf1[4], &buf1[6], r1.length - 6);
1116 r1.length -= 2;
1119 isc_buffer_usedregion(&b2, &r2);
1120 /* Remove extended flags. */
1121 if ((key2->key_flags & DNS_KEYFLAG_EXTENDED) != 0) {
1122 memmove(&buf2[4], &buf2[6], r2.length - 6);
1123 r2.length -= 2;
1125 return (ISC_TF(isc_region_compare(&r1, &r2) == 0));
1128 isc_boolean_t
1129 dst_key_compare(const dst_key_t *key1, const dst_key_t *key2) {
1130 return (comparekeys(key1, key2, ISC_FALSE, key1->func->compare));
1133 isc_boolean_t
1134 dst_key_pubcompare(const dst_key_t *key1, const dst_key_t *key2,
1135 isc_boolean_t match_revoked_key)
1137 return (comparekeys(key1, key2, match_revoked_key, pub_compare));
1141 isc_boolean_t
1142 dst_key_paramcompare(const dst_key_t *key1, const dst_key_t *key2) {
1143 REQUIRE(dst_initialized == ISC_TRUE);
1144 REQUIRE(VALID_KEY(key1));
1145 REQUIRE(VALID_KEY(key2));
1147 if (key1 == key2)
1148 return (ISC_TRUE);
1149 if (key1 == NULL || key2 == NULL)
1150 return (ISC_FALSE);
1151 if (key1->key_alg == key2->key_alg &&
1152 key1->func->paramcompare != NULL &&
1153 key1->func->paramcompare(key1, key2) == ISC_TRUE)
1154 return (ISC_TRUE);
1155 else
1156 return (ISC_FALSE);
1159 void
1160 dst_key_attach(dst_key_t *source, dst_key_t **target) {
1162 REQUIRE(dst_initialized == ISC_TRUE);
1163 REQUIRE(target != NULL && *target == NULL);
1164 REQUIRE(VALID_KEY(source));
1166 isc_refcount_increment(&source->refs, NULL);
1167 *target = source;
1170 void
1171 dst_key_free(dst_key_t **keyp) {
1172 isc_mem_t *mctx;
1173 dst_key_t *key;
1174 unsigned int refs;
1176 REQUIRE(dst_initialized == ISC_TRUE);
1177 REQUIRE(keyp != NULL && VALID_KEY(*keyp));
1179 key = *keyp;
1180 mctx = key->mctx;
1182 isc_refcount_decrement(&key->refs, &refs);
1183 if (refs != 0)
1184 return;
1186 isc_refcount_destroy(&key->refs);
1187 if (key->keydata.generic != NULL) {
1188 INSIST(key->func->destroy != NULL);
1189 key->func->destroy(key);
1191 if (key->engine != NULL)
1192 isc_mem_free(mctx, key->engine);
1193 if (key->label != NULL)
1194 isc_mem_free(mctx, key->label);
1195 dns_name_free(key->key_name, mctx);
1196 isc_mem_put(mctx, key->key_name, sizeof(dns_name_t));
1197 if (key->key_tkeytoken) {
1198 isc_buffer_free(&key->key_tkeytoken);
1200 memset(key, 0, sizeof(dst_key_t));
1201 isc_mem_putanddetach(&mctx, key, sizeof(dst_key_t));
1202 *keyp = NULL;
1205 isc_boolean_t
1206 dst_key_isprivate(const dst_key_t *key) {
1207 REQUIRE(VALID_KEY(key));
1208 INSIST(key->func->isprivate != NULL);
1209 return (key->func->isprivate(key));
1212 isc_result_t
1213 dst_key_buildfilename(const dst_key_t *key, int type,
1214 const char *directory, isc_buffer_t *out) {
1216 REQUIRE(VALID_KEY(key));
1217 REQUIRE(type == DST_TYPE_PRIVATE || type == DST_TYPE_PUBLIC ||
1218 type == 0);
1220 return (buildfilename(key->key_name, key->key_id, key->key_alg,
1221 type, directory, out));
1224 isc_result_t
1225 dst_key_sigsize(const dst_key_t *key, unsigned int *n) {
1226 REQUIRE(dst_initialized == ISC_TRUE);
1227 REQUIRE(VALID_KEY(key));
1228 REQUIRE(n != NULL);
1230 /* XXXVIX this switch statement is too sparse to gen a jump table. */
1231 switch (key->key_alg) {
1232 case DST_ALG_RSAMD5:
1233 case DST_ALG_RSASHA1:
1234 case DST_ALG_NSEC3RSASHA1:
1235 case DST_ALG_RSASHA256:
1236 case DST_ALG_RSASHA512:
1237 *n = (key->key_size + 7) / 8;
1238 break;
1239 case DST_ALG_DSA:
1240 case DST_ALG_NSEC3DSA:
1241 *n = DNS_SIG_DSASIGSIZE;
1242 break;
1243 case DST_ALG_ECCGOST:
1244 *n = DNS_SIG_GOSTSIGSIZE;
1245 break;
1246 case DST_ALG_ECDSA256:
1247 *n = DNS_SIG_ECDSA256SIZE;
1248 break;
1249 case DST_ALG_ECDSA384:
1250 *n = DNS_SIG_ECDSA384SIZE;
1251 break;
1252 case DST_ALG_HMACMD5:
1253 *n = 16;
1254 break;
1255 case DST_ALG_HMACSHA1:
1256 *n = ISC_SHA1_DIGESTLENGTH;
1257 break;
1258 case DST_ALG_HMACSHA224:
1259 *n = ISC_SHA224_DIGESTLENGTH;
1260 break;
1261 case DST_ALG_HMACSHA256:
1262 *n = ISC_SHA256_DIGESTLENGTH;
1263 break;
1264 case DST_ALG_HMACSHA384:
1265 *n = ISC_SHA384_DIGESTLENGTH;
1266 break;
1267 case DST_ALG_HMACSHA512:
1268 *n = ISC_SHA512_DIGESTLENGTH;
1269 break;
1270 case DST_ALG_GSSAPI:
1271 *n = 128; /*%< XXX */
1272 break;
1273 case DST_ALG_DH:
1274 default:
1275 return (DST_R_UNSUPPORTEDALG);
1277 return (ISC_R_SUCCESS);
1280 isc_result_t
1281 dst_key_secretsize(const dst_key_t *key, unsigned int *n) {
1282 REQUIRE(dst_initialized == ISC_TRUE);
1283 REQUIRE(VALID_KEY(key));
1284 REQUIRE(n != NULL);
1286 if (key->key_alg == DST_ALG_DH)
1287 *n = (key->key_size + 7) / 8;
1288 else
1289 return (DST_R_UNSUPPORTEDALG);
1290 return (ISC_R_SUCCESS);
1294 * Set the flags on a key, then recompute the key ID
1296 isc_result_t
1297 dst_key_setflags(dst_key_t *key, isc_uint32_t flags) {
1298 REQUIRE(VALID_KEY(key));
1299 key->key_flags = flags;
1300 return (computeid(key));
1303 void
1304 dst_key_format(const dst_key_t *key, char *cp, unsigned int size) {
1305 char namestr[DNS_NAME_FORMATSIZE];
1306 char algstr[DNS_NAME_FORMATSIZE];
1308 dns_name_format(dst_key_name(key), namestr, sizeof(namestr));
1309 dns_secalg_format((dns_secalg_t) dst_key_alg(key), algstr,
1310 sizeof(algstr));
1311 snprintf(cp, size, "%s/%s/%d", namestr, algstr, dst_key_id(key));
1314 isc_result_t
1315 dst_key_dump(dst_key_t *key, isc_mem_t *mctx, char **buffer, int *length) {
1317 REQUIRE(buffer != NULL && *buffer == NULL);
1318 REQUIRE(length != NULL && *length == 0);
1319 REQUIRE(VALID_KEY(key));
1321 if (key->func->dump == NULL)
1322 return (ISC_R_NOTIMPLEMENTED);
1323 return (key->func->dump(key, mctx, buffer, length));
1326 isc_result_t
1327 dst_key_restore(dns_name_t *name, unsigned int alg, unsigned int flags,
1328 unsigned int protocol, dns_rdataclass_t rdclass,
1329 isc_mem_t *mctx, const char *keystr, dst_key_t **keyp)
1331 isc_result_t result;
1332 dst_key_t *key;
1334 REQUIRE(dst_initialized == ISC_TRUE);
1335 REQUIRE(keyp != NULL && *keyp == NULL);
1337 if (alg >= DST_MAX_ALGS || dst_t_func[alg] == NULL)
1338 return (DST_R_UNSUPPORTEDALG);
1340 if (dst_t_func[alg]->restore == NULL)
1341 return (ISC_R_NOTIMPLEMENTED);
1343 key = get_key_struct(name, alg, flags, protocol, 0, rdclass, 0, mctx);
1344 if (key == NULL)
1345 return (ISC_R_NOMEMORY);
1347 result = (dst_t_func[alg]->restore)(key, keystr);
1348 if (result == ISC_R_SUCCESS)
1349 *keyp = key;
1350 else
1351 dst_key_free(&key);
1353 return (result);
1356 /***
1357 *** Static methods
1358 ***/
1361 * Allocates a key structure and fills in some of the fields.
1363 static dst_key_t *
1364 get_key_struct(dns_name_t *name, unsigned int alg,
1365 unsigned int flags, unsigned int protocol,
1366 unsigned int bits, dns_rdataclass_t rdclass,
1367 dns_ttl_t ttl, isc_mem_t *mctx)
1369 dst_key_t *key;
1370 isc_result_t result;
1371 int i;
1373 key = (dst_key_t *) isc_mem_get(mctx, sizeof(dst_key_t));
1374 if (key == NULL)
1375 return (NULL);
1377 memset(key, 0, sizeof(dst_key_t));
1379 key->key_name = isc_mem_get(mctx, sizeof(dns_name_t));
1380 if (key->key_name == NULL) {
1381 isc_mem_put(mctx, key, sizeof(dst_key_t));
1382 return (NULL);
1385 dns_name_init(key->key_name, NULL);
1386 result = dns_name_dup(name, mctx, key->key_name);
1387 if (result != ISC_R_SUCCESS) {
1388 isc_mem_put(mctx, key->key_name, sizeof(dns_name_t));
1389 isc_mem_put(mctx, key, sizeof(dst_key_t));
1390 return (NULL);
1393 result = isc_refcount_init(&key->refs, 1);
1394 if (result != ISC_R_SUCCESS) {
1395 dns_name_free(key->key_name, mctx);
1396 isc_mem_put(mctx, key->key_name, sizeof(dns_name_t));
1397 isc_mem_put(mctx, key, sizeof(dst_key_t));
1398 return (NULL);
1400 isc_mem_attach(mctx, &key->mctx);
1401 key->key_alg = alg;
1402 key->key_flags = flags;
1403 key->key_proto = protocol;
1404 key->keydata.generic = NULL;
1405 key->key_size = bits;
1406 key->key_class = rdclass;
1407 key->key_ttl = ttl;
1408 key->func = dst_t_func[alg];
1409 key->fmt_major = 0;
1410 key->fmt_minor = 0;
1411 for (i = 0; i < (DST_MAX_TIMES + 1); i++) {
1412 key->times[i] = 0;
1413 key->timeset[i] = ISC_FALSE;
1415 key->inactive = ISC_FALSE;
1416 key->magic = KEY_MAGIC;
1417 return (key);
1420 isc_boolean_t
1421 dst_key_inactive(const dst_key_t *key) {
1423 REQUIRE(VALID_KEY(key));
1425 return (key->inactive);
1428 void
1429 dst_key_setinactive(dst_key_t *key, isc_boolean_t inactive) {
1431 REQUIRE(VALID_KEY(key));
1433 key->inactive = inactive;
1437 * Reads a public key from disk
1439 isc_result_t
1440 dst_key_read_public(const char *filename, int type,
1441 isc_mem_t *mctx, dst_key_t **keyp)
1443 u_char rdatabuf[DST_KEY_MAXSIZE];
1444 isc_buffer_t b;
1445 dns_fixedname_t name;
1446 isc_lex_t *lex = NULL;
1447 isc_token_t token;
1448 isc_result_t ret;
1449 dns_rdata_t rdata = DNS_RDATA_INIT;
1450 unsigned int opt = ISC_LEXOPT_DNSMULTILINE;
1451 dns_rdataclass_t rdclass = dns_rdataclass_in;
1452 isc_lexspecials_t specials;
1453 isc_uint32_t ttl = 0;
1454 isc_result_t result;
1455 dns_rdatatype_t keytype;
1458 * Open the file and read its formatted contents
1459 * File format:
1460 * domain.name [ttl] [class] [KEY|DNSKEY] <flags> <protocol> <algorithm> <key>
1463 /* 1500 should be large enough for any key */
1464 ret = isc_lex_create(mctx, 1500, &lex);
1465 if (ret != ISC_R_SUCCESS)
1466 goto cleanup;
1468 memset(specials, 0, sizeof(specials));
1469 specials['('] = 1;
1470 specials[')'] = 1;
1471 specials['"'] = 1;
1472 isc_lex_setspecials(lex, specials);
1473 isc_lex_setcomments(lex, ISC_LEXCOMMENT_DNSMASTERFILE);
1475 ret = isc_lex_openfile(lex, filename);
1476 if (ret != ISC_R_SUCCESS)
1477 goto cleanup;
1479 #define NEXTTOKEN(lex, opt, token) { \
1480 ret = isc_lex_gettoken(lex, opt, token); \
1481 if (ret != ISC_R_SUCCESS) \
1482 goto cleanup; \
1485 #define BADTOKEN() { \
1486 ret = ISC_R_UNEXPECTEDTOKEN; \
1487 goto cleanup; \
1490 /* Read the domain name */
1491 NEXTTOKEN(lex, opt, &token);
1492 if (token.type != isc_tokentype_string)
1493 BADTOKEN();
1496 * We don't support "@" in .key files.
1498 if (!strcmp(DST_AS_STR(token), "@"))
1499 BADTOKEN();
1501 dns_fixedname_init(&name);
1502 isc_buffer_init(&b, DST_AS_STR(token), strlen(DST_AS_STR(token)));
1503 isc_buffer_add(&b, strlen(DST_AS_STR(token)));
1504 ret = dns_name_fromtext(dns_fixedname_name(&name), &b, dns_rootname,
1505 0, NULL);
1506 if (ret != ISC_R_SUCCESS)
1507 goto cleanup;
1509 /* Read the next word: either TTL, class, or 'KEY' */
1510 NEXTTOKEN(lex, opt, &token);
1512 if (token.type != isc_tokentype_string)
1513 BADTOKEN();
1515 /* If it's a TTL, read the next one */
1516 result = dns_ttl_fromtext(&token.value.as_textregion, &ttl);
1517 if (result == ISC_R_SUCCESS)
1518 NEXTTOKEN(lex, opt, &token);
1520 if (token.type != isc_tokentype_string)
1521 BADTOKEN();
1523 ret = dns_rdataclass_fromtext(&rdclass, &token.value.as_textregion);
1524 if (ret == ISC_R_SUCCESS)
1525 NEXTTOKEN(lex, opt, &token);
1527 if (token.type != isc_tokentype_string)
1528 BADTOKEN();
1530 if (strcasecmp(DST_AS_STR(token), "DNSKEY") == 0)
1531 keytype = dns_rdatatype_dnskey;
1532 else if (strcasecmp(DST_AS_STR(token), "KEY") == 0)
1533 keytype = dns_rdatatype_key; /*%< SIG(0), TKEY */
1534 else
1535 BADTOKEN();
1537 if (((type & DST_TYPE_KEY) != 0 && keytype != dns_rdatatype_key) ||
1538 ((type & DST_TYPE_KEY) == 0 && keytype != dns_rdatatype_dnskey)) {
1539 ret = DST_R_BADKEYTYPE;
1540 goto cleanup;
1543 isc_buffer_init(&b, rdatabuf, sizeof(rdatabuf));
1544 ret = dns_rdata_fromtext(&rdata, rdclass, keytype, lex, NULL,
1545 ISC_FALSE, mctx, &b, NULL);
1546 if (ret != ISC_R_SUCCESS)
1547 goto cleanup;
1549 ret = dst_key_fromdns(dns_fixedname_name(&name), rdclass, &b, mctx,
1550 keyp);
1551 if (ret != ISC_R_SUCCESS)
1552 goto cleanup;
1554 dst_key_setttl(*keyp, ttl);
1556 cleanup:
1557 if (lex != NULL)
1558 isc_lex_destroy(&lex);
1559 return (ret);
1562 static isc_boolean_t
1563 issymmetric(const dst_key_t *key) {
1564 REQUIRE(dst_initialized == ISC_TRUE);
1565 REQUIRE(VALID_KEY(key));
1567 /* XXXVIX this switch statement is too sparse to gen a jump table. */
1568 switch (key->key_alg) {
1569 case DST_ALG_RSAMD5:
1570 case DST_ALG_RSASHA1:
1571 case DST_ALG_NSEC3RSASHA1:
1572 case DST_ALG_RSASHA256:
1573 case DST_ALG_RSASHA512:
1574 case DST_ALG_DSA:
1575 case DST_ALG_NSEC3DSA:
1576 case DST_ALG_DH:
1577 case DST_ALG_ECCGOST:
1578 case DST_ALG_ECDSA256:
1579 case DST_ALG_ECDSA384:
1580 return (ISC_FALSE);
1581 case DST_ALG_HMACMD5:
1582 case DST_ALG_GSSAPI:
1583 return (ISC_TRUE);
1584 default:
1585 return (ISC_FALSE);
1590 * Write key timing metadata to a file pointer, preceded by 'tag'
1592 static void
1593 printtime(const dst_key_t *key, int type, const char *tag, FILE *stream) {
1594 isc_result_t result;
1595 #ifdef ISC_PLATFORM_USETHREADS
1596 char output[26]; /* Minimum buffer as per ctime_r() specification. */
1597 #else
1598 const char *output;
1599 #endif
1600 isc_stdtime_t when;
1601 time_t t;
1602 char utc[sizeof("YYYYMMDDHHSSMM")];
1603 isc_buffer_t b;
1604 isc_region_t r;
1606 result = dst_key_gettime(key, type, &when);
1607 if (result == ISC_R_NOTFOUND)
1608 return;
1610 /* time_t and isc_stdtime_t might be different sizes */
1611 t = when;
1612 #ifdef ISC_PLATFORM_USETHREADS
1613 #ifdef WIN32
1614 if (ctime_s(output, sizeof(output), &t) != 0)
1615 goto error;
1616 #else
1617 if (ctime_r(&t, output) == NULL)
1618 goto error;
1619 #endif
1620 #else
1621 output = ctime(&t);
1622 #endif
1624 isc_buffer_init(&b, utc, sizeof(utc));
1625 result = dns_time32_totext(when, &b);
1626 if (result != ISC_R_SUCCESS)
1627 goto error;
1629 isc_buffer_usedregion(&b, &r);
1630 fprintf(stream, "%s: %.*s (%.*s)\n", tag, (int)r.length, r.base,
1631 (int)strlen(output) - 1, output);
1632 return;
1634 error:
1635 fprintf(stream, "%s: (set, unable to display)\n", tag);
1639 * Writes a public key to disk in DNS format.
1641 static isc_result_t
1642 write_public_key(const dst_key_t *key, int type, const char *directory) {
1643 FILE *fp;
1644 isc_buffer_t keyb, textb, fileb, classb;
1645 isc_region_t r;
1646 char filename[ISC_DIR_NAMEMAX];
1647 unsigned char key_array[DST_KEY_MAXSIZE];
1648 char text_array[DST_KEY_MAXTEXTSIZE];
1649 char class_array[10];
1650 isc_result_t ret;
1651 dns_rdata_t rdata = DNS_RDATA_INIT;
1652 isc_fsaccess_t access;
1654 REQUIRE(VALID_KEY(key));
1656 isc_buffer_init(&keyb, key_array, sizeof(key_array));
1657 isc_buffer_init(&textb, text_array, sizeof(text_array));
1658 isc_buffer_init(&classb, class_array, sizeof(class_array));
1660 ret = dst_key_todns(key, &keyb);
1661 if (ret != ISC_R_SUCCESS)
1662 return (ret);
1664 isc_buffer_usedregion(&keyb, &r);
1665 dns_rdata_fromregion(&rdata, key->key_class, dns_rdatatype_dnskey, &r);
1667 ret = dns_rdata_totext(&rdata, (dns_name_t *) NULL, &textb);
1668 if (ret != ISC_R_SUCCESS)
1669 return (DST_R_INVALIDPUBLICKEY);
1671 ret = dns_rdataclass_totext(key->key_class, &classb);
1672 if (ret != ISC_R_SUCCESS)
1673 return (DST_R_INVALIDPUBLICKEY);
1676 * Make the filename.
1678 isc_buffer_init(&fileb, filename, sizeof(filename));
1679 ret = dst_key_buildfilename(key, DST_TYPE_PUBLIC, directory, &fileb);
1680 if (ret != ISC_R_SUCCESS)
1681 return (ret);
1684 * Create public key file.
1686 if ((fp = fopen(filename, "w")) == NULL)
1687 return (DST_R_WRITEERROR);
1689 if (issymmetric(key)) {
1690 access = 0;
1691 isc_fsaccess_add(ISC_FSACCESS_OWNER,
1692 ISC_FSACCESS_READ | ISC_FSACCESS_WRITE,
1693 &access);
1694 (void)isc_fsaccess_set(filename, access);
1697 /* Write key information in comments */
1698 if ((type & DST_TYPE_KEY) == 0) {
1699 fprintf(fp, "; This is a %s%s-signing key, keyid %d, for ",
1700 (key->key_flags & DNS_KEYFLAG_REVOKE) != 0 ?
1701 "revoked " :
1703 (key->key_flags & DNS_KEYFLAG_KSK) != 0 ?
1704 "key" :
1705 "zone",
1706 key->key_id);
1707 ret = dns_name_print(key->key_name, fp);
1708 if (ret != ISC_R_SUCCESS) {
1709 fclose(fp);
1710 return (ret);
1712 fputc('\n', fp);
1714 printtime(key, DST_TIME_CREATED, "; Created", fp);
1715 printtime(key, DST_TIME_PUBLISH, "; Publish", fp);
1716 printtime(key, DST_TIME_ACTIVATE, "; Activate", fp);
1717 printtime(key, DST_TIME_REVOKE, "; Revoke", fp);
1718 printtime(key, DST_TIME_INACTIVE, "; Inactive", fp);
1719 printtime(key, DST_TIME_DELETE, "; Delete", fp);
1722 /* Now print the actual key */
1723 ret = dns_name_print(key->key_name, fp);
1724 fprintf(fp, " ");
1726 if (key->key_ttl != 0)
1727 fprintf(fp, "%d ", key->key_ttl);
1729 isc_buffer_usedregion(&classb, &r);
1730 if ((unsigned) fwrite(r.base, 1, r.length, fp) != r.length)
1731 ret = DST_R_WRITEERROR;
1733 if ((type & DST_TYPE_KEY) != 0)
1734 fprintf(fp, " KEY ");
1735 else
1736 fprintf(fp, " DNSKEY ");
1738 isc_buffer_usedregion(&textb, &r);
1739 if ((unsigned) fwrite(r.base, 1, r.length, fp) != r.length)
1740 ret = DST_R_WRITEERROR;
1742 fputc('\n', fp);
1743 fflush(fp);
1744 if (ferror(fp))
1745 ret = DST_R_WRITEERROR;
1746 fclose(fp);
1748 return (ret);
1751 static isc_result_t
1752 buildfilename(dns_name_t *name, dns_keytag_t id,
1753 unsigned int alg, unsigned int type,
1754 const char *directory, isc_buffer_t *out)
1756 const char *suffix = "";
1757 unsigned int len;
1758 isc_result_t result;
1760 REQUIRE(out != NULL);
1761 if ((type & DST_TYPE_PRIVATE) != 0)
1762 suffix = ".private";
1763 else if (type == DST_TYPE_PUBLIC)
1764 suffix = ".key";
1765 if (directory != NULL) {
1766 if (isc_buffer_availablelength(out) < strlen(directory))
1767 return (ISC_R_NOSPACE);
1768 isc_buffer_putstr(out, directory);
1769 if (strlen(directory) > 0U &&
1770 directory[strlen(directory) - 1] != '/')
1771 isc_buffer_putstr(out, "/");
1773 if (isc_buffer_availablelength(out) < 1)
1774 return (ISC_R_NOSPACE);
1775 isc_buffer_putstr(out, "K");
1776 result = dns_name_tofilenametext(name, ISC_FALSE, out);
1777 if (result != ISC_R_SUCCESS)
1778 return (result);
1779 len = 1 + 3 + 1 + 5 + strlen(suffix) + 1;
1780 if (isc_buffer_availablelength(out) < len)
1781 return (ISC_R_NOSPACE);
1782 sprintf((char *) isc_buffer_used(out), "+%03d+%05d%s", alg, id,
1783 suffix);
1784 isc_buffer_add(out, len);
1786 return (ISC_R_SUCCESS);
1789 static isc_result_t
1790 computeid(dst_key_t *key) {
1791 isc_buffer_t dnsbuf;
1792 unsigned char dns_array[DST_KEY_MAXSIZE];
1793 isc_region_t r;
1794 isc_result_t ret;
1796 isc_buffer_init(&dnsbuf, dns_array, sizeof(dns_array));
1797 ret = dst_key_todns(key, &dnsbuf);
1798 if (ret != ISC_R_SUCCESS)
1799 return (ret);
1801 isc_buffer_usedregion(&dnsbuf, &r);
1802 key->key_id = dst_region_computeid(&r, key->key_alg);
1803 key->key_rid = dst_region_computerid(&r, key->key_alg);
1804 return (ISC_R_SUCCESS);
1807 static isc_result_t
1808 frombuffer(dns_name_t *name, unsigned int alg, unsigned int flags,
1809 unsigned int protocol, dns_rdataclass_t rdclass,
1810 isc_buffer_t *source, isc_mem_t *mctx, dst_key_t **keyp)
1812 dst_key_t *key;
1813 isc_result_t ret;
1815 REQUIRE(dns_name_isabsolute(name));
1816 REQUIRE(source != NULL);
1817 REQUIRE(mctx != NULL);
1818 REQUIRE(keyp != NULL && *keyp == NULL);
1820 key = get_key_struct(name, alg, flags, protocol, 0, rdclass, 0, mctx);
1821 if (key == NULL)
1822 return (ISC_R_NOMEMORY);
1824 if (isc_buffer_remaininglength(source) > 0) {
1825 ret = algorithm_status(alg);
1826 if (ret != ISC_R_SUCCESS) {
1827 dst_key_free(&key);
1828 return (ret);
1830 if (key->func->fromdns == NULL) {
1831 dst_key_free(&key);
1832 return (DST_R_UNSUPPORTEDALG);
1835 ret = key->func->fromdns(key, source);
1836 if (ret != ISC_R_SUCCESS) {
1837 dst_key_free(&key);
1838 return (ret);
1842 *keyp = key;
1843 return (ISC_R_SUCCESS);
1846 static isc_result_t
1847 algorithm_status(unsigned int alg) {
1848 REQUIRE(dst_initialized == ISC_TRUE);
1850 if (dst_algorithm_supported(alg))
1851 return (ISC_R_SUCCESS);
1852 #if !defined(OPENSSL) && !defined(PKCS11CRYPTO)
1853 if (alg == DST_ALG_RSAMD5 || alg == DST_ALG_RSASHA1 ||
1854 alg == DST_ALG_DSA || alg == DST_ALG_DH ||
1855 alg == DST_ALG_HMACMD5 || alg == DST_ALG_NSEC3DSA ||
1856 alg == DST_ALG_NSEC3RSASHA1 ||
1857 alg == DST_ALG_RSASHA256 || alg == DST_ALG_RSASHA512 ||
1858 alg == DST_ALG_ECCGOST ||
1859 alg == DST_ALG_ECDSA256 || alg == DST_ALG_ECDSA384)
1860 return (DST_R_NOCRYPTO);
1861 #endif
1862 return (DST_R_UNSUPPORTEDALG);
1865 static isc_result_t
1866 addsuffix(char *filename, int len, const char *odirname,
1867 const char *ofilename, const char *suffix)
1869 int olen = strlen(ofilename);
1870 int n;
1872 if (olen > 1 && ofilename[olen - 1] == '.')
1873 olen -= 1;
1874 else if (olen > 8 && strcmp(ofilename + olen - 8, ".private") == 0)
1875 olen -= 8;
1876 else if (olen > 4 && strcmp(ofilename + olen - 4, ".key") == 0)
1877 olen -= 4;
1879 if (odirname == NULL)
1880 n = snprintf(filename, len, "%.*s%s", olen, ofilename, suffix);
1881 else
1882 n = snprintf(filename, len, "%s/%.*s%s",
1883 odirname, olen, ofilename, suffix);
1884 if (n < 0)
1885 return (ISC_R_FAILURE);
1886 if (n >= len)
1887 return (ISC_R_NOSPACE);
1888 return (ISC_R_SUCCESS);
1891 isc_result_t
1892 dst__entropy_getdata(void *buf, unsigned int len, isc_boolean_t pseudo) {
1893 unsigned int flags = dst_entropy_flags;
1895 if (dst_entropy_pool == NULL)
1896 return (ISC_R_FAILURE);
1898 if (len == 0)
1899 return (ISC_R_SUCCESS);
1901 #ifdef PKCS11CRYPTO
1902 UNUSED(pseudo);
1903 UNUSED(flags);
1904 return (pk11_rand_bytes(buf, len));
1905 #else /* PKCS11CRYPTO */
1906 if (pseudo)
1907 flags &= ~ISC_ENTROPY_GOODONLY;
1908 else
1909 flags |= ISC_ENTROPY_BLOCKING;
1910 return (isc_entropy_getdata(dst_entropy_pool, buf, len, NULL, flags));
1911 #endif /* PKCS11CRYPTO */
1914 unsigned int
1915 dst__entropy_status(void) {
1916 #ifndef PKCS11CRYPTO
1917 #ifdef GSSAPI
1918 unsigned int flags = dst_entropy_flags;
1919 isc_result_t ret;
1920 unsigned char buf[32];
1921 static isc_boolean_t first = ISC_TRUE;
1923 if (dst_entropy_pool == NULL)
1924 return (0);
1926 if (first) {
1927 /* Someone believes RAND_status() initializes the PRNG */
1928 flags &= ~ISC_ENTROPY_GOODONLY;
1929 ret = isc_entropy_getdata(dst_entropy_pool, buf,
1930 sizeof(buf), NULL, flags);
1931 INSIST(ret == ISC_R_SUCCESS);
1932 isc_entropy_putdata(dst_entropy_pool, buf,
1933 sizeof(buf), 2 * sizeof(buf));
1934 first = ISC_FALSE;
1936 #endif
1937 return (isc_entropy_status(dst_entropy_pool));
1938 #else
1939 return (0);
1940 #endif
1943 isc_buffer_t *
1944 dst_key_tkeytoken(const dst_key_t *key) {
1945 REQUIRE(VALID_KEY(key));
1946 return (key->key_tkeytoken);