]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - contrib/bind9/lib/dns/dst_api.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.git] / contrib / bind9 / lib / dns / dst_api.c
1 /*
2  * Portions Copyright (C) 2004-2010  Internet Systems Consortium, Inc. ("ISC")
3  * Portions Copyright (C) 1999-2003  Internet Software Consortium.
4  *
5  * Permission to use, copy, modify, and/or distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS
10  * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
11  * WARRANTIES OF MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE
12  * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
15  * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  *
17  * Portions Copyright (C) 1995-2000 by Network Associates, Inc.
18  *
19  * Permission to use, copy, modify, and/or distribute this software for any
20  * purpose with or without fee is hereby granted, provided that the above
21  * copyright notice and this permission notice appear in all copies.
22  *
23  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS
24  * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
25  * WARRANTIES OF MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE
26  * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
27  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
28  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
29  * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
30  */
31
32 /*
33  * Principal Author: Brian Wellington
34  * $Id: dst_api.c,v 1.16.12.10 2010/01/15 19:38:53 each Exp $
35  */
36
37 /*! \file */
38
39 #include <config.h>
40
41 #include <stdlib.h>
42
43 #include <isc/buffer.h>
44 #include <isc/dir.h>
45 #include <isc/entropy.h>
46 #include <isc/fsaccess.h>
47 #include <isc/hmacsha.h>
48 #include <isc/lex.h>
49 #include <isc/mem.h>
50 #include <isc/once.h>
51 #include <isc/print.h>
52 #include <isc/random.h>
53 #include <isc/string.h>
54 #include <isc/time.h>
55 #include <isc/util.h>
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 static isc_entropy_t *dst_entropy_pool = NULL;
73 static unsigned int dst_entropy_flags = 0;
74 static isc_boolean_t dst_initialized = ISC_FALSE;
75
76 void gss_log(int level, const char *fmt, ...) ISC_FORMAT_PRINTF(2, 3);
77
78 isc_mem_t *dst__memory_pool = NULL;
79
80 /*
81  * Static functions.
82  */
83 static dst_key_t *      get_key_struct(dns_name_t *name,
84                                        unsigned int alg,
85                                        unsigned int flags,
86                                        unsigned int protocol,
87                                        unsigned int bits,
88                                        dns_rdataclass_t rdclass,
89                                        isc_mem_t *mctx);
90 static isc_result_t     write_public_key(const dst_key_t *key, int type,
91                                          const char *directory);
92 static isc_result_t     buildfilename(dns_name_t *name,
93                                       dns_keytag_t id,
94                                       unsigned int alg,
95                                       unsigned int type,
96                                       const char *directory,
97                                       isc_buffer_t *out);
98 static isc_result_t     computeid(dst_key_t *key);
99 static isc_result_t     frombuffer(dns_name_t *name,
100                                    unsigned int alg,
101                                    unsigned int flags,
102                                    unsigned int protocol,
103                                    dns_rdataclass_t rdclass,
104                                    isc_buffer_t *source,
105                                    isc_mem_t *mctx,
106                                    dst_key_t **keyp);
107
108 static isc_result_t     algorithm_status(unsigned int alg);
109
110 static isc_result_t     addsuffix(char *filename, unsigned int len,
111                                   const char *ofilename, const char *suffix);
112
113 #define RETERR(x)                               \
114         do {                                    \
115                 result = (x);                   \
116                 if (result != ISC_R_SUCCESS)    \
117                         goto out;               \
118         } while (0)
119
120 #define CHECKALG(alg)                           \
121         do {                                    \
122                 isc_result_t _r;                \
123                 _r = algorithm_status(alg);     \
124                 if (_r != ISC_R_SUCCESS)        \
125                         return (_r);            \
126         } while (0);                            \
127
128 #ifdef OPENSSL
129 static void *
130 default_memalloc(void *arg, size_t size) {
131         UNUSED(arg);
132         if (size == 0U)
133                 size = 1;
134         return (malloc(size));
135 }
136
137 static void
138 default_memfree(void *arg, void *ptr) {
139         UNUSED(arg);
140         free(ptr);
141 }
142 #endif
143
144 isc_result_t
145 dst_lib_init(isc_mem_t *mctx, isc_entropy_t *ectx, unsigned int eflags) {
146         isc_result_t result;
147
148         REQUIRE(mctx != NULL && ectx != NULL);
149         REQUIRE(dst_initialized == ISC_FALSE);
150
151         dst__memory_pool = NULL;
152
153 #ifdef OPENSSL
154         UNUSED(mctx);
155         /*
156          * When using --with-openssl, there seems to be no good way of not
157          * leaking memory due to the openssl error handling mechanism.
158          * Avoid assertions by using a local memory context and not checking
159          * for leaks on exit.  Note: as there are leaks we cannot use
160          * ISC_MEMFLAG_INTERNAL as it will free up memory still being used
161          * by libcrypto.
162          */
163         result = isc_mem_createx2(0, 0, default_memalloc, default_memfree,
164                                   NULL, &dst__memory_pool, 0);
165         if (result != ISC_R_SUCCESS)
166                 return (result);
167         isc_mem_setname(dst__memory_pool, "dst", NULL);
168         isc_mem_setdestroycheck(dst__memory_pool, ISC_FALSE);
169 #else
170         isc_mem_attach(mctx, &dst__memory_pool);
171 #endif
172         isc_entropy_attach(ectx, &dst_entropy_pool);
173         dst_entropy_flags = eflags;
174
175         dst_result_register();
176
177         memset(dst_t_func, 0, sizeof(dst_t_func));
178         RETERR(dst__hmacmd5_init(&dst_t_func[DST_ALG_HMACMD5]));
179         RETERR(dst__hmacsha1_init(&dst_t_func[DST_ALG_HMACSHA1]));
180         RETERR(dst__hmacsha224_init(&dst_t_func[DST_ALG_HMACSHA224]));
181         RETERR(dst__hmacsha256_init(&dst_t_func[DST_ALG_HMACSHA256]));
182         RETERR(dst__hmacsha384_init(&dst_t_func[DST_ALG_HMACSHA384]));
183         RETERR(dst__hmacsha512_init(&dst_t_func[DST_ALG_HMACSHA512]));
184 #ifdef OPENSSL
185         RETERR(dst__openssl_init());
186         RETERR(dst__opensslrsa_init(&dst_t_func[DST_ALG_RSAMD5],
187                                     DST_ALG_RSAMD5));
188         RETERR(dst__opensslrsa_init(&dst_t_func[DST_ALG_RSASHA1],
189                                     DST_ALG_RSASHA1));
190         RETERR(dst__opensslrsa_init(&dst_t_func[DST_ALG_NSEC3RSASHA1],
191                                     DST_ALG_NSEC3RSASHA1));
192         RETERR(dst__opensslrsa_init(&dst_t_func[DST_ALG_RSASHA256],
193                                     DST_ALG_RSASHA256));
194         RETERR(dst__opensslrsa_init(&dst_t_func[DST_ALG_RSASHA512],
195                                     DST_ALG_RSASHA512));
196 #ifdef HAVE_OPENSSL_DSA
197         RETERR(dst__openssldsa_init(&dst_t_func[DST_ALG_DSA]));
198         RETERR(dst__openssldsa_init(&dst_t_func[DST_ALG_NSEC3DSA]));
199 #endif
200         RETERR(dst__openssldh_init(&dst_t_func[DST_ALG_DH]));
201 #endif /* OPENSSL */
202 #ifdef GSSAPI
203         RETERR(dst__gssapi_init(&dst_t_func[DST_ALG_GSSAPI]));
204 #endif
205         dst_initialized = ISC_TRUE;
206         return (ISC_R_SUCCESS);
207
208  out:
209         dst_lib_destroy();
210         return (result);
211 }
212
213 void
214 dst_lib_destroy(void) {
215         int i;
216         RUNTIME_CHECK(dst_initialized == ISC_TRUE);
217         dst_initialized = ISC_FALSE;
218
219         for (i = 0; i < DST_MAX_ALGS; i++)
220                 if (dst_t_func[i] != NULL && dst_t_func[i]->cleanup != NULL)
221                         dst_t_func[i]->cleanup();
222 #ifdef OPENSSL
223         dst__openssl_destroy();
224 #endif
225         if (dst__memory_pool != NULL)
226                 isc_mem_detach(&dst__memory_pool);
227         if (dst_entropy_pool != NULL)
228                 isc_entropy_detach(&dst_entropy_pool);
229
230 }
231
232 isc_boolean_t
233 dst_algorithm_supported(unsigned int alg) {
234         REQUIRE(dst_initialized == ISC_TRUE);
235
236         if (alg >= DST_MAX_ALGS || dst_t_func[alg] == NULL)
237                 return (ISC_FALSE);
238         return (ISC_TRUE);
239 }
240
241 isc_result_t
242 dst_context_create(dst_key_t *key, isc_mem_t *mctx, dst_context_t **dctxp) {
243         dst_context_t *dctx;
244         isc_result_t result;
245
246         REQUIRE(dst_initialized == ISC_TRUE);
247         REQUIRE(VALID_KEY(key));
248         REQUIRE(mctx != NULL);
249         REQUIRE(dctxp != NULL && *dctxp == NULL);
250
251         if (key->func->createctx == NULL)
252                 return (DST_R_UNSUPPORTEDALG);
253         if (key->keydata.generic == NULL)
254                 return (DST_R_NULLKEY);
255
256         dctx = isc_mem_get(mctx, sizeof(dst_context_t));
257         if (dctx == NULL)
258                 return (ISC_R_NOMEMORY);
259         dctx->key = key;
260         dctx->mctx = mctx;
261         result = key->func->createctx(key, dctx);
262         if (result != ISC_R_SUCCESS) {
263                 isc_mem_put(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         dctx->magic = 0;
281         isc_mem_put(dctx->mctx, dctx, sizeof(dst_context_t));
282         *dctxp = NULL;
283 }
284
285 isc_result_t
286 dst_context_adddata(dst_context_t *dctx, const isc_region_t *data) {
287         REQUIRE(VALID_CTX(dctx));
288         REQUIRE(data != NULL);
289         INSIST(dctx->key->func->adddata != NULL);
290
291         return (dctx->key->func->adddata(dctx, data));
292 }
293
294 isc_result_t
295 dst_context_sign(dst_context_t *dctx, isc_buffer_t *sig) {
296         dst_key_t *key;
297
298         REQUIRE(VALID_CTX(dctx));
299         REQUIRE(sig != NULL);
300
301         key = dctx->key;
302         CHECKALG(key->key_alg);
303         if (key->keydata.generic == NULL)
304                 return (DST_R_NULLKEY);
305
306         if (key->func->sign == NULL)
307                 return (DST_R_NOTPRIVATEKEY);
308         if (key->func->isprivate == NULL ||
309             key->func->isprivate(key) == ISC_FALSE)
310                 return (DST_R_NOTPRIVATEKEY);
311
312         return (key->func->sign(dctx, sig));
313 }
314
315 isc_result_t
316 dst_context_verify(dst_context_t *dctx, isc_region_t *sig) {
317         REQUIRE(VALID_CTX(dctx));
318         REQUIRE(sig != NULL);
319
320         CHECKALG(dctx->key->key_alg);
321         if (dctx->key->keydata.generic == NULL)
322                 return (DST_R_NULLKEY);
323         if (dctx->key->func->verify == NULL)
324                 return (DST_R_NOTPUBLICKEY);
325
326         return (dctx->key->func->verify(dctx, sig));
327 }
328
329 isc_result_t
330 dst_key_computesecret(const dst_key_t *pub, const dst_key_t *priv,
331                       isc_buffer_t *secret)
332 {
333         REQUIRE(dst_initialized == ISC_TRUE);
334         REQUIRE(VALID_KEY(pub) && VALID_KEY(priv));
335         REQUIRE(secret != NULL);
336
337         CHECKALG(pub->key_alg);
338         CHECKALG(priv->key_alg);
339
340         if (pub->keydata.generic == NULL || priv->keydata.generic == NULL)
341                 return (DST_R_NULLKEY);
342
343         if (pub->key_alg != priv->key_alg ||
344             pub->func->computesecret == NULL ||
345             priv->func->computesecret == NULL)
346                 return (DST_R_KEYCANNOTCOMPUTESECRET);
347
348         if (dst_key_isprivate(priv) == ISC_FALSE)
349                 return (DST_R_NOTPRIVATEKEY);
350
351         return (pub->func->computesecret(pub, priv, secret));
352 }
353
354 isc_result_t
355 dst_key_tofile(const dst_key_t *key, int type, const char *directory) {
356         isc_result_t ret = ISC_R_SUCCESS;
357
358         REQUIRE(dst_initialized == ISC_TRUE);
359         REQUIRE(VALID_KEY(key));
360         REQUIRE((type & (DST_TYPE_PRIVATE | DST_TYPE_PUBLIC)) != 0);
361
362         CHECKALG(key->key_alg);
363
364         if (key->func->tofile == NULL)
365                 return (DST_R_UNSUPPORTEDALG);
366
367         if (type & DST_TYPE_PUBLIC) {
368                 ret = write_public_key(key, type, directory);
369                 if (ret != ISC_R_SUCCESS)
370                         return (ret);
371         }
372
373         if ((type & DST_TYPE_PRIVATE) &&
374             (key->key_flags & DNS_KEYFLAG_TYPEMASK) != DNS_KEYTYPE_NOKEY)
375                 return (key->func->tofile(key, directory));
376         else
377                 return (ISC_R_SUCCESS);
378 }
379
380 isc_result_t
381 dst_key_fromfile(dns_name_t *name, dns_keytag_t id,
382                  unsigned int alg, int type, const char *directory,
383                  isc_mem_t *mctx, dst_key_t **keyp)
384 {
385         char filename[ISC_DIR_NAMEMAX];
386         isc_buffer_t b;
387         dst_key_t *key;
388         isc_result_t result;
389
390         REQUIRE(dst_initialized == ISC_TRUE);
391         REQUIRE(dns_name_isabsolute(name));
392         REQUIRE((type & (DST_TYPE_PRIVATE | DST_TYPE_PUBLIC)) != 0);
393         REQUIRE(mctx != NULL);
394         REQUIRE(keyp != NULL && *keyp == NULL);
395
396         CHECKALG(alg);
397
398         isc_buffer_init(&b, filename, sizeof(filename));
399         result = buildfilename(name, id, alg, type, directory, &b);
400         if (result != ISC_R_SUCCESS)
401                 return (result);
402
403         key = NULL;
404         result = dst_key_fromnamedfile(filename, type, mctx, &key);
405         if (result != ISC_R_SUCCESS)
406                 return (result);
407
408         result = computeid(key);
409         if (result != ISC_R_SUCCESS) {
410                 dst_key_free(&key);
411                 return (result);
412         }
413
414         if (!dns_name_equal(name, key->key_name) || id != key->key_id ||
415             alg != key->key_alg) {
416                 dst_key_free(&key);
417                 return (DST_R_INVALIDPRIVATEKEY);
418         }
419         key->key_id = id;
420
421         *keyp = key;
422         return (ISC_R_SUCCESS);
423 }
424
425 isc_result_t
426 dst_key_fromnamedfile(const char *filename, int type, isc_mem_t *mctx,
427                       dst_key_t **keyp)
428 {
429         isc_result_t result;
430         dst_key_t *pubkey = NULL, *key = NULL;
431         dns_keytag_t id;
432         char *newfilename = NULL;
433         int newfilenamelen = 0;
434         isc_lex_t *lex = NULL;
435
436         REQUIRE(dst_initialized == ISC_TRUE);
437         REQUIRE(filename != NULL);
438         REQUIRE((type & (DST_TYPE_PRIVATE | DST_TYPE_PUBLIC)) != 0);
439         REQUIRE(mctx != NULL);
440         REQUIRE(keyp != NULL && *keyp == NULL);
441
442         newfilenamelen = strlen(filename) + 5;
443         newfilename = isc_mem_get(mctx, newfilenamelen);
444         if (newfilename == NULL)
445                 return (ISC_R_NOMEMORY);
446         result = addsuffix(newfilename, newfilenamelen, filename, ".key");
447         INSIST(result == ISC_R_SUCCESS);
448
449         result = dst_key_read_public(newfilename, type, mctx, &pubkey);
450         isc_mem_put(mctx, newfilename, newfilenamelen);
451         newfilename = NULL;
452         if (result != ISC_R_SUCCESS)
453                 return (result);
454
455         if ((type & (DST_TYPE_PRIVATE | DST_TYPE_PUBLIC)) == DST_TYPE_PUBLIC ||
456             (pubkey->key_flags & DNS_KEYFLAG_TYPEMASK) == DNS_KEYTYPE_NOKEY) {
457                 result = computeid(pubkey);
458                 if (result != ISC_R_SUCCESS) {
459                         dst_key_free(&pubkey);
460                         return (result);
461                 }
462
463                 *keyp = pubkey;
464                 return (ISC_R_SUCCESS);
465         }
466
467         result = algorithm_status(pubkey->key_alg);
468         if (result != ISC_R_SUCCESS) {
469                 dst_key_free(&pubkey);
470                 return (result);
471         }
472
473         key = get_key_struct(pubkey->key_name, pubkey->key_alg,
474                              pubkey->key_flags, pubkey->key_proto, 0,
475                              pubkey->key_class, mctx);
476         id = pubkey->key_id;
477         dst_key_free(&pubkey);
478
479         if (key == NULL)
480                 return (ISC_R_NOMEMORY);
481
482         if (key->func->parse == NULL)
483                 RETERR(DST_R_UNSUPPORTEDALG);
484
485         newfilenamelen = strlen(filename) + 9;
486         newfilename = isc_mem_get(mctx, newfilenamelen);
487         if (newfilename == NULL)
488                 RETERR(ISC_R_NOMEMORY);
489         result = addsuffix(newfilename, newfilenamelen, filename, ".private");
490         INSIST(result == ISC_R_SUCCESS);
491
492         RETERR(isc_lex_create(mctx, 1500, &lex));
493         RETERR(isc_lex_openfile(lex, newfilename));
494         isc_mem_put(mctx, newfilename, newfilenamelen);
495
496         RETERR(key->func->parse(key, lex));
497         isc_lex_destroy(&lex);
498
499         RETERR(computeid(key));
500
501         if (id != key->key_id)
502                 RETERR(DST_R_INVALIDPRIVATEKEY);
503
504         *keyp = key;
505         return (ISC_R_SUCCESS);
506  out:
507         if (newfilename != NULL)
508                 isc_mem_put(mctx, newfilename, newfilenamelen);
509         if (lex != NULL)
510                 isc_lex_destroy(&lex);
511         dst_key_free(&key);
512         return (result);
513 }
514
515 isc_result_t
516 dst_key_todns(const dst_key_t *key, isc_buffer_t *target) {
517         REQUIRE(dst_initialized == ISC_TRUE);
518         REQUIRE(VALID_KEY(key));
519         REQUIRE(target != NULL);
520
521         CHECKALG(key->key_alg);
522
523         if (key->func->todns == NULL)
524                 return (DST_R_UNSUPPORTEDALG);
525
526         if (isc_buffer_availablelength(target) < 4)
527                 return (ISC_R_NOSPACE);
528         isc_buffer_putuint16(target, (isc_uint16_t)(key->key_flags & 0xffff));
529         isc_buffer_putuint8(target, (isc_uint8_t)key->key_proto);
530         isc_buffer_putuint8(target, (isc_uint8_t)key->key_alg);
531
532         if (key->key_flags & DNS_KEYFLAG_EXTENDED) {
533                 if (isc_buffer_availablelength(target) < 2)
534                         return (ISC_R_NOSPACE);
535                 isc_buffer_putuint16(target,
536                                      (isc_uint16_t)((key->key_flags >> 16)
537                                                     & 0xffff));
538         }
539
540         if (key->keydata.generic == NULL) /*%< NULL KEY */
541                 return (ISC_R_SUCCESS);
542
543         return (key->func->todns(key, target));
544 }
545
546 isc_result_t
547 dst_key_fromdns(dns_name_t *name, dns_rdataclass_t rdclass,
548                 isc_buffer_t *source, isc_mem_t *mctx, dst_key_t **keyp)
549 {
550         isc_uint8_t alg, proto;
551         isc_uint32_t flags, extflags;
552         dst_key_t *key = NULL;
553         dns_keytag_t id;
554         isc_region_t r;
555         isc_result_t result;
556
557         REQUIRE(dst_initialized);
558
559         isc_buffer_remainingregion(source, &r);
560
561         if (isc_buffer_remaininglength(source) < 4)
562                 return (DST_R_INVALIDPUBLICKEY);
563         flags = isc_buffer_getuint16(source);
564         proto = isc_buffer_getuint8(source);
565         alg = isc_buffer_getuint8(source);
566
567         id = dst_region_computeid(&r, alg);
568
569         if (flags & DNS_KEYFLAG_EXTENDED) {
570                 if (isc_buffer_remaininglength(source) < 2)
571                         return (DST_R_INVALIDPUBLICKEY);
572                 extflags = isc_buffer_getuint16(source);
573                 flags |= (extflags << 16);
574         }
575
576         result = frombuffer(name, alg, flags, proto, rdclass, source,
577                             mctx, &key);
578         if (result != ISC_R_SUCCESS)
579                 return (result);
580         key->key_id = id;
581
582         *keyp = key;
583         return (ISC_R_SUCCESS);
584 }
585
586 isc_result_t
587 dst_key_frombuffer(dns_name_t *name, unsigned int alg,
588                    unsigned int flags, unsigned int protocol,
589                    dns_rdataclass_t rdclass,
590                    isc_buffer_t *source, isc_mem_t *mctx, dst_key_t **keyp)
591 {
592         dst_key_t *key = NULL;
593         isc_result_t result;
594
595         REQUIRE(dst_initialized);
596
597         result = frombuffer(name, alg, flags, protocol, rdclass, source,
598                             mctx, &key);
599         if (result != ISC_R_SUCCESS)
600                 return (result);
601
602         result = computeid(key);
603         if (result != ISC_R_SUCCESS) {
604                 dst_key_free(&key);
605                 return (result);
606         }
607
608         *keyp = key;
609         return (ISC_R_SUCCESS);
610 }
611
612 isc_result_t
613 dst_key_tobuffer(const dst_key_t *key, isc_buffer_t *target) {
614         REQUIRE(dst_initialized == ISC_TRUE);
615         REQUIRE(VALID_KEY(key));
616         REQUIRE(target != NULL);
617
618         CHECKALG(key->key_alg);
619
620         if (key->func->todns == NULL)
621                 return (DST_R_UNSUPPORTEDALG);
622
623         return (key->func->todns(key, target));
624 }
625
626 isc_result_t
627 dst_key_privatefrombuffer(dst_key_t *key, isc_buffer_t *buffer) {
628         isc_lex_t *lex = NULL;
629         isc_result_t result = ISC_R_SUCCESS;
630
631         REQUIRE(dst_initialized == ISC_TRUE);
632         REQUIRE(VALID_KEY(key));
633         REQUIRE(!dst_key_isprivate(key));
634         REQUIRE(buffer != NULL);
635
636         if (key->func->parse == NULL)
637                 RETERR(DST_R_UNSUPPORTEDALG);
638
639         RETERR(isc_lex_create(key->mctx, 1500, &lex));
640         RETERR(isc_lex_openbuffer(lex, buffer));
641         RETERR(key->func->parse(key, lex));
642  out:
643         if (lex != NULL)
644                 isc_lex_destroy(&lex);
645         return (result);
646 }
647
648 gss_ctx_id_t
649 dst_key_getgssctx(const dst_key_t *key)
650 {
651         REQUIRE(key != NULL);
652
653         return (key->keydata.gssctx);
654 }
655
656 isc_result_t
657 dst_key_fromgssapi(dns_name_t *name, gss_ctx_id_t gssctx, isc_mem_t *mctx,
658                    dst_key_t **keyp)
659 {
660         dst_key_t *key;
661
662         REQUIRE(gssctx != NULL);
663         REQUIRE(keyp != NULL && *keyp == NULL);
664
665         key = get_key_struct(name, DST_ALG_GSSAPI, 0, DNS_KEYPROTO_DNSSEC,
666                              0, dns_rdataclass_in, mctx);
667         if (key == NULL)
668                 return (ISC_R_NOMEMORY);
669
670         key->keydata.gssctx = gssctx;
671         *keyp = key;
672         return (ISC_R_SUCCESS);
673 }
674
675 isc_result_t
676 dst_key_fromlabel(dns_name_t *name, int alg, unsigned int flags,
677                   unsigned int protocol, dns_rdataclass_t rdclass,
678                   const char *engine, const char *label, const char *pin,
679                   isc_mem_t *mctx, dst_key_t **keyp)
680 {
681         dst_key_t *key;
682         isc_result_t result;
683
684         REQUIRE(dst_initialized == ISC_TRUE);
685         REQUIRE(dns_name_isabsolute(name));
686         REQUIRE(mctx != NULL);
687         REQUIRE(keyp != NULL && *keyp == NULL);
688         REQUIRE(label != NULL);
689
690         CHECKALG(alg);
691
692         key = get_key_struct(name, alg, flags, protocol, 0, rdclass, mctx);
693         if (key == NULL)
694                 return (ISC_R_NOMEMORY);
695
696         if (key->func->fromlabel == NULL) {
697                 dst_key_free(&key);
698                 return (DST_R_UNSUPPORTEDALG);
699         }
700
701         result = key->func->fromlabel(key, engine, label, pin);
702         if (result != ISC_R_SUCCESS) {
703                 dst_key_free(&key);
704                 return (result);
705         }
706
707         result = computeid(key);
708         if (result != ISC_R_SUCCESS) {
709                 dst_key_free(&key);
710                 return (result);
711         }
712
713         *keyp = key;
714         return (ISC_R_SUCCESS);
715 }
716
717 isc_result_t
718 dst_key_generate(dns_name_t *name, unsigned int alg,
719                  unsigned int bits, unsigned int param,
720                  unsigned int flags, unsigned int protocol,
721                  dns_rdataclass_t rdclass,
722                  isc_mem_t *mctx, dst_key_t **keyp)
723 {
724         dst_key_t *key;
725         isc_result_t ret;
726
727         REQUIRE(dst_initialized == ISC_TRUE);
728         REQUIRE(dns_name_isabsolute(name));
729         REQUIRE(mctx != NULL);
730         REQUIRE(keyp != NULL && *keyp == NULL);
731
732         CHECKALG(alg);
733
734         key = get_key_struct(name, alg, flags, protocol, bits, rdclass, mctx);
735         if (key == NULL)
736                 return (ISC_R_NOMEMORY);
737
738         if (bits == 0) { /*%< NULL KEY */
739                 key->key_flags |= DNS_KEYTYPE_NOKEY;
740                 *keyp = key;
741                 return (ISC_R_SUCCESS);
742         }
743
744         if (key->func->generate == NULL) {
745                 dst_key_free(&key);
746                 return (DST_R_UNSUPPORTEDALG);
747         }
748
749         ret = key->func->generate(key, param);
750         if (ret != ISC_R_SUCCESS) {
751                 dst_key_free(&key);
752                 return (ret);
753         }
754
755         ret = computeid(key);
756         if (ret != ISC_R_SUCCESS) {
757                 dst_key_free(&key);
758                 return (ret);
759         }
760
761         *keyp = key;
762         return (ISC_R_SUCCESS);
763 }
764
765 isc_boolean_t
766 dst_key_compare(const dst_key_t *key1, const dst_key_t *key2) {
767         REQUIRE(dst_initialized == ISC_TRUE);
768         REQUIRE(VALID_KEY(key1));
769         REQUIRE(VALID_KEY(key2));
770
771         if (key1 == key2)
772                 return (ISC_TRUE);
773         if (key1 == NULL || key2 == NULL)
774                 return (ISC_FALSE);
775         if (key1->key_alg == key2->key_alg &&
776             key1->key_id == key2->key_id &&
777             key1->func->compare != NULL &&
778             key1->func->compare(key1, key2) == ISC_TRUE)
779                 return (ISC_TRUE);
780         else
781                 return (ISC_FALSE);
782 }
783
784 isc_boolean_t
785 dst_key_paramcompare(const dst_key_t *key1, const dst_key_t *key2) {
786         REQUIRE(dst_initialized == ISC_TRUE);
787         REQUIRE(VALID_KEY(key1));
788         REQUIRE(VALID_KEY(key2));
789
790         if (key1 == key2)
791                 return (ISC_TRUE);
792         if (key1 == NULL || key2 == NULL)
793                 return (ISC_FALSE);
794         if (key1->key_alg == key2->key_alg &&
795             key1->func->paramcompare != NULL &&
796             key1->func->paramcompare(key1, key2) == ISC_TRUE)
797                 return (ISC_TRUE);
798         else
799                 return (ISC_FALSE);
800 }
801
802 void
803 dst_key_free(dst_key_t **keyp) {
804         isc_mem_t *mctx;
805         dst_key_t *key;
806
807         REQUIRE(dst_initialized == ISC_TRUE);
808         REQUIRE(keyp != NULL && VALID_KEY(*keyp));
809
810         key = *keyp;
811         mctx = key->mctx;
812
813         if (key->keydata.generic != NULL) {
814                 INSIST(key->func->destroy != NULL);
815                 key->func->destroy(key);
816         }
817         if (key->engine != NULL)
818                 isc_mem_free(mctx, key->engine);
819         if (key->label != NULL)
820                 isc_mem_free(mctx, key->label);
821         dns_name_free(key->key_name, mctx);
822         isc_mem_put(mctx, key->key_name, sizeof(dns_name_t));
823         memset(key, 0, sizeof(dst_key_t));
824         isc_mem_put(mctx, key, sizeof(dst_key_t));
825         *keyp = NULL;
826 }
827
828 isc_boolean_t
829 dst_key_isprivate(const dst_key_t *key) {
830         REQUIRE(VALID_KEY(key));
831         INSIST(key->func->isprivate != NULL);
832         return (key->func->isprivate(key));
833 }
834
835 isc_result_t
836 dst_key_buildfilename(const dst_key_t *key, int type,
837                       const char *directory, isc_buffer_t *out) {
838
839         REQUIRE(VALID_KEY(key));
840         REQUIRE(type == DST_TYPE_PRIVATE || type == DST_TYPE_PUBLIC ||
841                 type == 0);
842
843         return (buildfilename(key->key_name, key->key_id, key->key_alg,
844                               type, directory, out));
845 }
846
847 isc_result_t
848 dst_key_sigsize(const dst_key_t *key, unsigned int *n) {
849         REQUIRE(dst_initialized == ISC_TRUE);
850         REQUIRE(VALID_KEY(key));
851         REQUIRE(n != NULL);
852
853         /* XXXVIX this switch statement is too sparse to gen a jump table. */
854         switch (key->key_alg) {
855         case DST_ALG_RSAMD5:
856         case DST_ALG_RSASHA1:
857         case DST_ALG_NSEC3RSASHA1:
858         case DST_ALG_RSASHA256:
859         case DST_ALG_RSASHA512:
860                 *n = (key->key_size + 7) / 8;
861                 break;
862         case DST_ALG_DSA:
863         case DST_ALG_NSEC3DSA:
864                 *n = DNS_SIG_DSASIGSIZE;
865                 break;
866         case DST_ALG_HMACMD5:
867                 *n = 16;
868                 break;
869         case DST_ALG_HMACSHA1:
870                 *n = ISC_SHA1_DIGESTLENGTH;
871                 break;
872         case DST_ALG_HMACSHA224:
873                 *n = ISC_SHA224_DIGESTLENGTH;
874                 break;
875         case DST_ALG_HMACSHA256:
876                 *n = ISC_SHA256_DIGESTLENGTH;
877                 break;
878         case DST_ALG_HMACSHA384:
879                 *n = ISC_SHA384_DIGESTLENGTH;
880                 break;
881         case DST_ALG_HMACSHA512:
882                 *n = ISC_SHA512_DIGESTLENGTH;
883                 break;
884         case DST_ALG_GSSAPI:
885                 *n = 128; /*%< XXX */
886                 break;
887         case DST_ALG_DH:
888         default:
889                 return (DST_R_UNSUPPORTEDALG);
890         }
891         return (ISC_R_SUCCESS);
892 }
893
894 isc_result_t
895 dst_key_secretsize(const dst_key_t *key, unsigned int *n) {
896         REQUIRE(dst_initialized == ISC_TRUE);
897         REQUIRE(VALID_KEY(key));
898         REQUIRE(n != NULL);
899
900         if (key->key_alg == DST_ALG_DH)
901                 *n = (key->key_size + 7) / 8;
902         else
903                 return (DST_R_UNSUPPORTEDALG);
904         return (ISC_R_SUCCESS);
905 }
906
907 /***
908  *** Static methods
909  ***/
910
911 /*%
912  * Allocates a key structure and fills in some of the fields.
913  */
914 static dst_key_t *
915 get_key_struct(dns_name_t *name, unsigned int alg,
916                unsigned int flags, unsigned int protocol,
917                unsigned int bits, dns_rdataclass_t rdclass,
918                isc_mem_t *mctx)
919 {
920         dst_key_t *key;
921         isc_result_t result;
922
923         key = (dst_key_t *) isc_mem_get(mctx, sizeof(dst_key_t));
924         if (key == NULL)
925                 return (NULL);
926
927         memset(key, 0, sizeof(dst_key_t));
928         key->magic = KEY_MAGIC;
929
930         key->key_name = isc_mem_get(mctx, sizeof(dns_name_t));
931         if (key->key_name == NULL) {
932                 isc_mem_put(mctx, key, sizeof(dst_key_t));
933                 return (NULL);
934         }
935         dns_name_init(key->key_name, NULL);
936         result = dns_name_dup(name, mctx, key->key_name);
937         if (result != ISC_R_SUCCESS) {
938                 isc_mem_put(mctx, key->key_name, sizeof(dns_name_t));
939                 isc_mem_put(mctx, key, sizeof(dst_key_t));
940                 return (NULL);
941         }
942         key->key_alg = alg;
943         key->key_flags = flags;
944         key->key_proto = protocol;
945         key->mctx = mctx;
946         key->keydata.generic = NULL;
947         key->key_size = bits;
948         key->key_class = rdclass;
949         key->func = dst_t_func[alg];
950         return (key);
951 }
952
953 /*%
954  * Reads a public key from disk
955  */
956 isc_result_t
957 dst_key_read_public(const char *filename, int type,
958                     isc_mem_t *mctx, dst_key_t **keyp)
959 {
960         u_char rdatabuf[DST_KEY_MAXSIZE];
961         isc_buffer_t b;
962         dns_fixedname_t name;
963         isc_lex_t *lex = NULL;
964         isc_token_t token;
965         isc_result_t ret;
966         dns_rdata_t rdata = DNS_RDATA_INIT;
967         unsigned int opt = ISC_LEXOPT_DNSMULTILINE;
968         dns_rdataclass_t rdclass = dns_rdataclass_in;
969         isc_lexspecials_t specials;
970         isc_uint32_t ttl;
971         isc_result_t result;
972         dns_rdatatype_t keytype;
973
974         /*
975          * Open the file and read its formatted contents
976          * File format:
977          *    domain.name [ttl] [class] [KEY|DNSKEY] <flags> <protocol> <algorithm> <key>
978          */
979
980         /* 1500 should be large enough for any key */
981         ret = isc_lex_create(mctx, 1500, &lex);
982         if (ret != ISC_R_SUCCESS)
983                 goto cleanup;
984
985         memset(specials, 0, sizeof(specials));
986         specials['('] = 1;
987         specials[')'] = 1;
988         specials['"'] = 1;
989         isc_lex_setspecials(lex, specials);
990         isc_lex_setcomments(lex, ISC_LEXCOMMENT_DNSMASTERFILE);
991
992         ret = isc_lex_openfile(lex, filename);
993         if (ret != ISC_R_SUCCESS)
994                 goto cleanup;
995
996 #define NEXTTOKEN(lex, opt, token) { \
997         ret = isc_lex_gettoken(lex, opt, token); \
998         if (ret != ISC_R_SUCCESS) \
999                 goto cleanup; \
1000         }
1001
1002 #define BADTOKEN() { \
1003         ret = ISC_R_UNEXPECTEDTOKEN; \
1004         goto cleanup; \
1005         }
1006
1007         /* Read the domain name */
1008         NEXTTOKEN(lex, opt, &token);
1009         if (token.type != isc_tokentype_string)
1010                 BADTOKEN();
1011
1012         /*
1013          * We don't support "@" in .key files.
1014          */
1015         if (!strcmp(DST_AS_STR(token), "@"))
1016                 BADTOKEN();
1017
1018         dns_fixedname_init(&name);
1019         isc_buffer_init(&b, DST_AS_STR(token), strlen(DST_AS_STR(token)));
1020         isc_buffer_add(&b, strlen(DST_AS_STR(token)));
1021         ret = dns_name_fromtext(dns_fixedname_name(&name), &b, dns_rootname,
1022                                 ISC_FALSE, NULL);
1023         if (ret != ISC_R_SUCCESS)
1024                 goto cleanup;
1025
1026         /* Read the next word: either TTL, class, or 'KEY' */
1027         NEXTTOKEN(lex, opt, &token);
1028
1029         if (token.type != isc_tokentype_string)
1030                 BADTOKEN();
1031
1032         /* If it's a TTL, read the next one */
1033         result = dns_ttl_fromtext(&token.value.as_textregion, &ttl);
1034         if (result == ISC_R_SUCCESS)
1035                 NEXTTOKEN(lex, opt, &token);
1036
1037         if (token.type != isc_tokentype_string)
1038                 BADTOKEN();
1039
1040         ret = dns_rdataclass_fromtext(&rdclass, &token.value.as_textregion);
1041         if (ret == ISC_R_SUCCESS)
1042                 NEXTTOKEN(lex, opt, &token);
1043
1044         if (token.type != isc_tokentype_string)
1045                 BADTOKEN();
1046
1047         if (strcasecmp(DST_AS_STR(token), "DNSKEY") == 0)
1048                 keytype = dns_rdatatype_dnskey;
1049         else if (strcasecmp(DST_AS_STR(token), "KEY") == 0)
1050                 keytype = dns_rdatatype_key; /*%< SIG(0), TKEY */
1051         else
1052                 BADTOKEN();
1053
1054         if (((type & DST_TYPE_KEY) != 0 && keytype != dns_rdatatype_key) ||
1055             ((type & DST_TYPE_KEY) == 0 && keytype != dns_rdatatype_dnskey)) {
1056                 ret = DST_R_BADKEYTYPE;
1057                 goto cleanup;
1058         }
1059
1060         isc_buffer_init(&b, rdatabuf, sizeof(rdatabuf));
1061         ret = dns_rdata_fromtext(&rdata, rdclass, keytype, lex, NULL,
1062                                  ISC_FALSE, mctx, &b, NULL);
1063         if (ret != ISC_R_SUCCESS)
1064                 goto cleanup;
1065
1066         ret = dst_key_fromdns(dns_fixedname_name(&name), rdclass, &b, mctx,
1067                               keyp);
1068         if (ret != ISC_R_SUCCESS)
1069                 goto cleanup;
1070
1071  cleanup:
1072         if (lex != NULL)
1073                 isc_lex_destroy(&lex);
1074         return (ret);
1075 }
1076
1077 static isc_boolean_t
1078 issymmetric(const dst_key_t *key) {
1079         REQUIRE(dst_initialized == ISC_TRUE);
1080         REQUIRE(VALID_KEY(key));
1081
1082         /* XXXVIX this switch statement is too sparse to gen a jump table. */
1083         switch (key->key_alg) {
1084         case DST_ALG_RSAMD5:
1085         case DST_ALG_RSASHA1:
1086         case DST_ALG_NSEC3RSASHA1:
1087         case DST_ALG_RSASHA256:
1088         case DST_ALG_RSASHA512:
1089         case DST_ALG_DSA:
1090         case DST_ALG_NSEC3DSA:
1091         case DST_ALG_DH:
1092                 return (ISC_FALSE);
1093         case DST_ALG_HMACMD5:
1094         case DST_ALG_GSSAPI:
1095                 return (ISC_TRUE);
1096         default:
1097                 return (ISC_FALSE);
1098         }
1099 }
1100
1101 /*%
1102  * Writes a public key to disk in DNS format.
1103  */
1104 static isc_result_t
1105 write_public_key(const dst_key_t *key, int type, const char *directory) {
1106         FILE *fp;
1107         isc_buffer_t keyb, textb, fileb, classb;
1108         isc_region_t r;
1109         char filename[ISC_DIR_NAMEMAX];
1110         unsigned char key_array[DST_KEY_MAXSIZE];
1111         char text_array[DST_KEY_MAXTEXTSIZE];
1112         char class_array[10];
1113         isc_result_t ret;
1114         dns_rdata_t rdata = DNS_RDATA_INIT;
1115         isc_fsaccess_t access;
1116
1117         REQUIRE(VALID_KEY(key));
1118
1119         isc_buffer_init(&keyb, key_array, sizeof(key_array));
1120         isc_buffer_init(&textb, text_array, sizeof(text_array));
1121         isc_buffer_init(&classb, class_array, sizeof(class_array));
1122
1123         ret = dst_key_todns(key, &keyb);
1124         if (ret != ISC_R_SUCCESS)
1125                 return (ret);
1126
1127         isc_buffer_usedregion(&keyb, &r);
1128         dns_rdata_fromregion(&rdata, key->key_class, dns_rdatatype_dnskey, &r);
1129
1130         ret = dns_rdata_totext(&rdata, (dns_name_t *) NULL, &textb);
1131         if (ret != ISC_R_SUCCESS)
1132                 return (DST_R_INVALIDPUBLICKEY);
1133
1134         ret = dns_rdataclass_totext(key->key_class, &classb);
1135         if (ret != ISC_R_SUCCESS)
1136                 return (DST_R_INVALIDPUBLICKEY);
1137
1138         /*
1139          * Make the filename.
1140          */
1141         isc_buffer_init(&fileb, filename, sizeof(filename));
1142         ret = dst_key_buildfilename(key, DST_TYPE_PUBLIC, directory, &fileb);
1143         if (ret != ISC_R_SUCCESS)
1144                 return (ret);
1145
1146         /*
1147          * Create public key file.
1148          */
1149         if ((fp = fopen(filename, "w")) == NULL)
1150                 return (DST_R_WRITEERROR);
1151
1152         if (issymmetric(key)) {
1153                 access = 0;
1154                 isc_fsaccess_add(ISC_FSACCESS_OWNER,
1155                                  ISC_FSACCESS_READ | ISC_FSACCESS_WRITE,
1156                                  &access);
1157                 (void)isc_fsaccess_set(filename, access);
1158         }
1159
1160         ret = dns_name_print(key->key_name, fp);
1161         if (ret != ISC_R_SUCCESS) {
1162                 fclose(fp);
1163                 return (ret);
1164         }
1165
1166         fprintf(fp, " ");
1167
1168         isc_buffer_usedregion(&classb, &r);
1169         isc_util_fwrite(r.base, 1, r.length, fp);
1170
1171         if ((type & DST_TYPE_KEY) != 0)
1172                 fprintf(fp, " KEY ");
1173         else
1174                 fprintf(fp, " DNSKEY ");
1175
1176         isc_buffer_usedregion(&textb, &r);
1177         isc_util_fwrite(r.base, 1, r.length, fp);
1178
1179         fputc('\n', fp);
1180         fflush(fp);
1181         if (ferror(fp))
1182                 ret = DST_R_WRITEERROR;
1183         fclose(fp);
1184
1185         return (ret);
1186 }
1187
1188 static isc_result_t
1189 buildfilename(dns_name_t *name, dns_keytag_t id,
1190               unsigned int alg, unsigned int type,
1191               const char *directory, isc_buffer_t *out)
1192 {
1193         const char *suffix = "";
1194         unsigned int len;
1195         isc_result_t result;
1196
1197         REQUIRE(out != NULL);
1198         if ((type & DST_TYPE_PRIVATE) != 0)
1199                 suffix = ".private";
1200         else if (type == DST_TYPE_PUBLIC)
1201                 suffix = ".key";
1202         if (directory != NULL) {
1203                 if (isc_buffer_availablelength(out) < strlen(directory))
1204                         return (ISC_R_NOSPACE);
1205                 isc_buffer_putstr(out, directory);
1206                 if (strlen(directory) > 0U &&
1207                     directory[strlen(directory) - 1] != '/')
1208                         isc_buffer_putstr(out, "/");
1209         }
1210         if (isc_buffer_availablelength(out) < 1)
1211                 return (ISC_R_NOSPACE);
1212         isc_buffer_putstr(out, "K");
1213         result = dns_name_tofilenametext(name, ISC_FALSE, out);
1214         if (result != ISC_R_SUCCESS)
1215                 return (result);
1216         len = 1 + 3 + 1 + 5 + strlen(suffix) + 1;
1217         if (isc_buffer_availablelength(out) < len)
1218                 return (ISC_R_NOSPACE);
1219         sprintf((char *) isc_buffer_used(out), "+%03d+%05d%s", alg, id,
1220                 suffix);
1221         isc_buffer_add(out, len);
1222
1223         return (ISC_R_SUCCESS);
1224 }
1225
1226 static isc_result_t
1227 computeid(dst_key_t *key) {
1228         isc_buffer_t dnsbuf;
1229         unsigned char dns_array[DST_KEY_MAXSIZE];
1230         isc_region_t r;
1231         isc_result_t ret;
1232
1233         isc_buffer_init(&dnsbuf, dns_array, sizeof(dns_array));
1234         ret = dst_key_todns(key, &dnsbuf);
1235         if (ret != ISC_R_SUCCESS)
1236                 return (ret);
1237
1238         isc_buffer_usedregion(&dnsbuf, &r);
1239         key->key_id = dst_region_computeid(&r, key->key_alg);
1240         return (ISC_R_SUCCESS);
1241 }
1242
1243 static isc_result_t
1244 frombuffer(dns_name_t *name, unsigned int alg, unsigned int flags,
1245            unsigned int protocol, dns_rdataclass_t rdclass,
1246            isc_buffer_t *source, isc_mem_t *mctx, dst_key_t **keyp)
1247 {
1248         dst_key_t *key;
1249         isc_result_t ret;
1250
1251         REQUIRE(dns_name_isabsolute(name));
1252         REQUIRE(source != NULL);
1253         REQUIRE(mctx != NULL);
1254         REQUIRE(keyp != NULL && *keyp == NULL);
1255
1256         key = get_key_struct(name, alg, flags, protocol, 0, rdclass, mctx);
1257         if (key == NULL)
1258                 return (ISC_R_NOMEMORY);
1259
1260         if (isc_buffer_remaininglength(source) > 0) {
1261                 ret = algorithm_status(alg);
1262                 if (ret != ISC_R_SUCCESS) {
1263                         dst_key_free(&key);
1264                         return (ret);
1265                 }
1266                 if (key->func->fromdns == NULL) {
1267                         dst_key_free(&key);
1268                         return (DST_R_UNSUPPORTEDALG);
1269                 }
1270
1271                 ret = key->func->fromdns(key, source);
1272                 if (ret != ISC_R_SUCCESS) {
1273                         dst_key_free(&key);
1274                         return (ret);
1275                 }
1276         }
1277
1278         *keyp = key;
1279         return (ISC_R_SUCCESS);
1280 }
1281
1282 static isc_result_t
1283 algorithm_status(unsigned int alg) {
1284         REQUIRE(dst_initialized == ISC_TRUE);
1285
1286         if (dst_algorithm_supported(alg))
1287                 return (ISC_R_SUCCESS);
1288 #ifndef OPENSSL
1289         if (alg == DST_ALG_RSAMD5 || alg == DST_ALG_RSASHA1 ||
1290             alg == DST_ALG_DSA || alg == DST_ALG_DH ||
1291             alg == DST_ALG_HMACMD5 || alg == DST_ALG_NSEC3DSA ||
1292             alg == DST_ALG_NSEC3RSASHA1 ||
1293             alg == DST_ALG_RSASHA256 || alg == DST_ALG_RSASHA512)
1294                 return (DST_R_NOCRYPTO);
1295 #endif
1296         return (DST_R_UNSUPPORTEDALG);
1297 }
1298
1299 static isc_result_t
1300 addsuffix(char *filename, unsigned int len, const char *ofilename,
1301           const char *suffix)
1302 {
1303         int olen = strlen(ofilename);
1304         int n;
1305
1306         if (olen > 1 && ofilename[olen - 1] == '.')
1307                 olen -= 1;
1308         else if (olen > 8 && strcmp(ofilename + olen - 8, ".private") == 0)
1309                 olen -= 8;
1310         else if (olen > 4 && strcmp(ofilename + olen - 4, ".key") == 0)
1311                 olen -= 4;
1312
1313         n = snprintf(filename, len, "%.*s%s", olen, ofilename, suffix);
1314         if (n < 0)
1315                 return (ISC_R_FAILURE);
1316         if ((unsigned int)n >= len)
1317                 return (ISC_R_NOSPACE);
1318         return (ISC_R_SUCCESS);
1319 }
1320
1321 isc_result_t
1322 dst__entropy_getdata(void *buf, unsigned int len, isc_boolean_t pseudo) {
1323         unsigned int flags = dst_entropy_flags;
1324
1325         if (len == 0)
1326                 return (ISC_R_SUCCESS);
1327         if (pseudo)
1328                 flags &= ~ISC_ENTROPY_GOODONLY;
1329         return (isc_entropy_getdata(dst_entropy_pool, buf, len, NULL, flags));
1330 }
1331
1332 unsigned int
1333 dst__entropy_status(void) {
1334 #ifdef GSSAPI
1335         unsigned int flags = dst_entropy_flags;
1336         isc_result_t ret;
1337         unsigned char buf[32];
1338         static isc_boolean_t first = ISC_TRUE;
1339
1340         if (first) {
1341                 /* Someone believes RAND_status() initializes the PRNG */
1342                 flags &= ~ISC_ENTROPY_GOODONLY;
1343                 ret = isc_entropy_getdata(dst_entropy_pool, buf,
1344                                           sizeof(buf), NULL, flags);
1345                 INSIST(ret == ISC_R_SUCCESS);
1346                 isc_entropy_putdata(dst_entropy_pool, buf,
1347                                     sizeof(buf), 2 * sizeof(buf));
1348                 first = ISC_FALSE;
1349         }
1350 #endif
1351         return (isc_entropy_status(dst_entropy_pool));
1352 }