]> CyberLeo.Net >> Repos - FreeBSD/releng/8.0.git/blob - contrib/bind9/lib/dns/dst_api.c
Adjust to reflect 8.0-RELEASE.
[FreeBSD/releng/8.0.git] / contrib / bind9 / lib / dns / dst_api.c
1 /*
2  * Portions Copyright (C) 2004-2009  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.3 2009/03/02 02:00:34 marka 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         RETERR(dst__opensslrsa_init(&dst_t_func[DST_ALG_RSASHA1]));
188         RETERR(dst__opensslrsa_init(&dst_t_func[DST_ALG_NSEC3RSASHA1]));
189 #ifdef HAVE_OPENSSL_DSA
190         RETERR(dst__openssldsa_init(&dst_t_func[DST_ALG_DSA]));
191         RETERR(dst__openssldsa_init(&dst_t_func[DST_ALG_NSEC3DSA]));
192 #endif
193         RETERR(dst__openssldh_init(&dst_t_func[DST_ALG_DH]));
194 #endif /* OPENSSL */
195 #ifdef GSSAPI
196         RETERR(dst__gssapi_init(&dst_t_func[DST_ALG_GSSAPI]));
197 #endif
198         dst_initialized = ISC_TRUE;
199         return (ISC_R_SUCCESS);
200
201  out:
202         dst_lib_destroy();
203         return (result);
204 }
205
206 void
207 dst_lib_destroy(void) {
208         int i;
209         RUNTIME_CHECK(dst_initialized == ISC_TRUE);
210         dst_initialized = ISC_FALSE;
211
212         for (i = 0; i < DST_MAX_ALGS; i++)
213                 if (dst_t_func[i] != NULL && dst_t_func[i]->cleanup != NULL)
214                         dst_t_func[i]->cleanup();
215 #ifdef OPENSSL
216         dst__openssl_destroy();
217 #endif
218         if (dst__memory_pool != NULL)
219                 isc_mem_detach(&dst__memory_pool);
220         if (dst_entropy_pool != NULL)
221                 isc_entropy_detach(&dst_entropy_pool);
222
223 }
224
225 isc_boolean_t
226 dst_algorithm_supported(unsigned int alg) {
227         REQUIRE(dst_initialized == ISC_TRUE);
228
229         if (alg >= DST_MAX_ALGS || dst_t_func[alg] == NULL)
230                 return (ISC_FALSE);
231         return (ISC_TRUE);
232 }
233
234 isc_result_t
235 dst_context_create(dst_key_t *key, isc_mem_t *mctx, dst_context_t **dctxp) {
236         dst_context_t *dctx;
237         isc_result_t result;
238
239         REQUIRE(dst_initialized == ISC_TRUE);
240         REQUIRE(VALID_KEY(key));
241         REQUIRE(mctx != NULL);
242         REQUIRE(dctxp != NULL && *dctxp == NULL);
243
244         if (key->func->createctx == NULL)
245                 return (DST_R_UNSUPPORTEDALG);
246         if (key->keydata.generic == NULL)
247                 return (DST_R_NULLKEY);
248
249         dctx = isc_mem_get(mctx, sizeof(dst_context_t));
250         if (dctx == NULL)
251                 return (ISC_R_NOMEMORY);
252         dctx->key = key;
253         dctx->mctx = mctx;
254         result = key->func->createctx(key, dctx);
255         if (result != ISC_R_SUCCESS) {
256                 isc_mem_put(mctx, dctx, sizeof(dst_context_t));
257                 return (result);
258         }
259         dctx->magic = CTX_MAGIC;
260         *dctxp = dctx;
261         return (ISC_R_SUCCESS);
262 }
263
264 void
265 dst_context_destroy(dst_context_t **dctxp) {
266         dst_context_t *dctx;
267
268         REQUIRE(dctxp != NULL && VALID_CTX(*dctxp));
269
270         dctx = *dctxp;
271         INSIST(dctx->key->func->destroyctx != NULL);
272         dctx->key->func->destroyctx(dctx);
273         dctx->magic = 0;
274         isc_mem_put(dctx->mctx, dctx, sizeof(dst_context_t));
275         *dctxp = NULL;
276 }
277
278 isc_result_t
279 dst_context_adddata(dst_context_t *dctx, const isc_region_t *data) {
280         REQUIRE(VALID_CTX(dctx));
281         REQUIRE(data != NULL);
282         INSIST(dctx->key->func->adddata != NULL);
283
284         return (dctx->key->func->adddata(dctx, data));
285 }
286
287 isc_result_t
288 dst_context_sign(dst_context_t *dctx, isc_buffer_t *sig) {
289         dst_key_t *key;
290
291         REQUIRE(VALID_CTX(dctx));
292         REQUIRE(sig != NULL);
293
294         key = dctx->key;
295         CHECKALG(key->key_alg);
296         if (key->keydata.generic == NULL)
297                 return (DST_R_NULLKEY);
298
299         if (key->func->sign == NULL)
300                 return (DST_R_NOTPRIVATEKEY);
301         if (key->func->isprivate == NULL ||
302             key->func->isprivate(key) == ISC_FALSE)
303                 return (DST_R_NOTPRIVATEKEY);
304
305         return (key->func->sign(dctx, sig));
306 }
307
308 isc_result_t
309 dst_context_verify(dst_context_t *dctx, isc_region_t *sig) {
310         REQUIRE(VALID_CTX(dctx));
311         REQUIRE(sig != NULL);
312
313         CHECKALG(dctx->key->key_alg);
314         if (dctx->key->keydata.generic == NULL)
315                 return (DST_R_NULLKEY);
316         if (dctx->key->func->verify == NULL)
317                 return (DST_R_NOTPUBLICKEY);
318
319         return (dctx->key->func->verify(dctx, sig));
320 }
321
322 isc_result_t
323 dst_key_computesecret(const dst_key_t *pub, const dst_key_t *priv,
324                       isc_buffer_t *secret)
325 {
326         REQUIRE(dst_initialized == ISC_TRUE);
327         REQUIRE(VALID_KEY(pub) && VALID_KEY(priv));
328         REQUIRE(secret != NULL);
329
330         CHECKALG(pub->key_alg);
331         CHECKALG(priv->key_alg);
332
333         if (pub->keydata.generic == NULL || priv->keydata.generic == NULL)
334                 return (DST_R_NULLKEY);
335
336         if (pub->key_alg != priv->key_alg ||
337             pub->func->computesecret == NULL ||
338             priv->func->computesecret == NULL)
339                 return (DST_R_KEYCANNOTCOMPUTESECRET);
340
341         if (dst_key_isprivate(priv) == ISC_FALSE)
342                 return (DST_R_NOTPRIVATEKEY);
343
344         return (pub->func->computesecret(pub, priv, secret));
345 }
346
347 isc_result_t
348 dst_key_tofile(const dst_key_t *key, int type, const char *directory) {
349         isc_result_t ret = ISC_R_SUCCESS;
350
351         REQUIRE(dst_initialized == ISC_TRUE);
352         REQUIRE(VALID_KEY(key));
353         REQUIRE((type & (DST_TYPE_PRIVATE | DST_TYPE_PUBLIC)) != 0);
354
355         CHECKALG(key->key_alg);
356
357         if (key->func->tofile == NULL)
358                 return (DST_R_UNSUPPORTEDALG);
359
360         if (type & DST_TYPE_PUBLIC) {
361                 ret = write_public_key(key, type, directory);
362                 if (ret != ISC_R_SUCCESS)
363                         return (ret);
364         }
365
366         if ((type & DST_TYPE_PRIVATE) &&
367             (key->key_flags & DNS_KEYFLAG_TYPEMASK) != DNS_KEYTYPE_NOKEY)
368                 return (key->func->tofile(key, directory));
369         else
370                 return (ISC_R_SUCCESS);
371 }
372
373 isc_result_t
374 dst_key_fromfile(dns_name_t *name, dns_keytag_t id,
375                  unsigned int alg, int type, const char *directory,
376                  isc_mem_t *mctx, dst_key_t **keyp)
377 {
378         char filename[ISC_DIR_NAMEMAX];
379         isc_buffer_t b;
380         dst_key_t *key;
381         isc_result_t result;
382
383         REQUIRE(dst_initialized == ISC_TRUE);
384         REQUIRE(dns_name_isabsolute(name));
385         REQUIRE((type & (DST_TYPE_PRIVATE | DST_TYPE_PUBLIC)) != 0);
386         REQUIRE(mctx != NULL);
387         REQUIRE(keyp != NULL && *keyp == NULL);
388
389         CHECKALG(alg);
390
391         isc_buffer_init(&b, filename, sizeof(filename));
392         result = buildfilename(name, id, alg, type, directory, &b);
393         if (result != ISC_R_SUCCESS)
394                 return (result);
395
396         key = NULL;
397         result = dst_key_fromnamedfile(filename, type, mctx, &key);
398         if (result != ISC_R_SUCCESS)
399                 return (result);
400
401         result = computeid(key);
402         if (result != ISC_R_SUCCESS) {
403                 dst_key_free(&key);
404                 return (result);
405         }
406
407         if (!dns_name_equal(name, key->key_name) || id != key->key_id ||
408             alg != key->key_alg) {
409                 dst_key_free(&key);
410                 return (DST_R_INVALIDPRIVATEKEY);
411         }
412         key->key_id = id;
413
414         *keyp = key;
415         return (ISC_R_SUCCESS);
416 }
417
418 isc_result_t
419 dst_key_fromnamedfile(const char *filename, int type, isc_mem_t *mctx,
420                       dst_key_t **keyp)
421 {
422         isc_result_t result;
423         dst_key_t *pubkey = NULL, *key = NULL;
424         dns_keytag_t id;
425         char *newfilename = NULL;
426         int newfilenamelen = 0;
427         isc_lex_t *lex = NULL;
428
429         REQUIRE(dst_initialized == ISC_TRUE);
430         REQUIRE(filename != NULL);
431         REQUIRE((type & (DST_TYPE_PRIVATE | DST_TYPE_PUBLIC)) != 0);
432         REQUIRE(mctx != NULL);
433         REQUIRE(keyp != NULL && *keyp == NULL);
434
435         newfilenamelen = strlen(filename) + 5;
436         newfilename = isc_mem_get(mctx, newfilenamelen);
437         if (newfilename == NULL)
438                 return (ISC_R_NOMEMORY);
439         result = addsuffix(newfilename, newfilenamelen, filename, ".key");
440         INSIST(result == ISC_R_SUCCESS);
441
442         result = dst_key_read_public(newfilename, type, mctx, &pubkey);
443         isc_mem_put(mctx, newfilename, newfilenamelen);
444         newfilename = NULL;
445         if (result != ISC_R_SUCCESS)
446                 return (result);
447
448         if ((type & (DST_TYPE_PRIVATE | DST_TYPE_PUBLIC)) == DST_TYPE_PUBLIC ||
449             (pubkey->key_flags & DNS_KEYFLAG_TYPEMASK) == DNS_KEYTYPE_NOKEY) {
450                 result = computeid(pubkey);
451                 if (result != ISC_R_SUCCESS) {
452                         dst_key_free(&pubkey);
453                         return (result);
454                 }
455
456                 *keyp = pubkey;
457                 return (ISC_R_SUCCESS);
458         }
459
460         result = algorithm_status(pubkey->key_alg);
461         if (result != ISC_R_SUCCESS) {
462                 dst_key_free(&pubkey);
463                 return (result);
464         }
465
466         key = get_key_struct(pubkey->key_name, pubkey->key_alg,
467                              pubkey->key_flags, pubkey->key_proto, 0,
468                              pubkey->key_class, mctx);
469         id = pubkey->key_id;
470         dst_key_free(&pubkey);
471
472         if (key == NULL)
473                 return (ISC_R_NOMEMORY);
474
475         if (key->func->parse == NULL)
476                 RETERR(DST_R_UNSUPPORTEDALG);
477
478         newfilenamelen = strlen(filename) + 9;
479         newfilename = isc_mem_get(mctx, newfilenamelen);
480         if (newfilename == NULL)
481                 RETERR(ISC_R_NOMEMORY);
482         result = addsuffix(newfilename, newfilenamelen, filename, ".private");
483         INSIST(result == ISC_R_SUCCESS);
484
485         RETERR(isc_lex_create(mctx, 1500, &lex));
486         RETERR(isc_lex_openfile(lex, newfilename));
487         isc_mem_put(mctx, newfilename, newfilenamelen);
488
489         RETERR(key->func->parse(key, lex));
490         isc_lex_destroy(&lex);
491
492         RETERR(computeid(key));
493
494         if (id != key->key_id)
495                 RETERR(DST_R_INVALIDPRIVATEKEY);
496
497         *keyp = key;
498         return (ISC_R_SUCCESS);
499  out:
500         if (newfilename != NULL)
501                 isc_mem_put(mctx, newfilename, newfilenamelen);
502         if (lex != NULL)
503                 isc_lex_destroy(&lex);
504         dst_key_free(&key);
505         return (result);
506 }
507
508 isc_result_t
509 dst_key_todns(const dst_key_t *key, isc_buffer_t *target) {
510         REQUIRE(dst_initialized == ISC_TRUE);
511         REQUIRE(VALID_KEY(key));
512         REQUIRE(target != NULL);
513
514         CHECKALG(key->key_alg);
515
516         if (key->func->todns == NULL)
517                 return (DST_R_UNSUPPORTEDALG);
518
519         if (isc_buffer_availablelength(target) < 4)
520                 return (ISC_R_NOSPACE);
521         isc_buffer_putuint16(target, (isc_uint16_t)(key->key_flags & 0xffff));
522         isc_buffer_putuint8(target, (isc_uint8_t)key->key_proto);
523         isc_buffer_putuint8(target, (isc_uint8_t)key->key_alg);
524
525         if (key->key_flags & DNS_KEYFLAG_EXTENDED) {
526                 if (isc_buffer_availablelength(target) < 2)
527                         return (ISC_R_NOSPACE);
528                 isc_buffer_putuint16(target,
529                                      (isc_uint16_t)((key->key_flags >> 16)
530                                                     & 0xffff));
531         }
532
533         if (key->keydata.generic == NULL) /*%< NULL KEY */
534                 return (ISC_R_SUCCESS);
535
536         return (key->func->todns(key, target));
537 }
538
539 isc_result_t
540 dst_key_fromdns(dns_name_t *name, dns_rdataclass_t rdclass,
541                 isc_buffer_t *source, isc_mem_t *mctx, dst_key_t **keyp)
542 {
543         isc_uint8_t alg, proto;
544         isc_uint32_t flags, extflags;
545         dst_key_t *key = NULL;
546         dns_keytag_t id;
547         isc_region_t r;
548         isc_result_t result;
549
550         REQUIRE(dst_initialized);
551
552         isc_buffer_remainingregion(source, &r);
553
554         if (isc_buffer_remaininglength(source) < 4)
555                 return (DST_R_INVALIDPUBLICKEY);
556         flags = isc_buffer_getuint16(source);
557         proto = isc_buffer_getuint8(source);
558         alg = isc_buffer_getuint8(source);
559
560         id = dst_region_computeid(&r, alg);
561
562         if (flags & DNS_KEYFLAG_EXTENDED) {
563                 if (isc_buffer_remaininglength(source) < 2)
564                         return (DST_R_INVALIDPUBLICKEY);
565                 extflags = isc_buffer_getuint16(source);
566                 flags |= (extflags << 16);
567         }
568
569         result = frombuffer(name, alg, flags, proto, rdclass, source,
570                             mctx, &key);
571         if (result != ISC_R_SUCCESS)
572                 return (result);
573         key->key_id = id;
574
575         *keyp = key;
576         return (ISC_R_SUCCESS);
577 }
578
579 isc_result_t
580 dst_key_frombuffer(dns_name_t *name, unsigned int alg,
581                    unsigned int flags, unsigned int protocol,
582                    dns_rdataclass_t rdclass,
583                    isc_buffer_t *source, isc_mem_t *mctx, dst_key_t **keyp)
584 {
585         dst_key_t *key = NULL;
586         isc_result_t result;
587
588         REQUIRE(dst_initialized);
589
590         result = frombuffer(name, alg, flags, protocol, rdclass, source,
591                             mctx, &key);
592         if (result != ISC_R_SUCCESS)
593                 return (result);
594
595         result = computeid(key);
596         if (result != ISC_R_SUCCESS) {
597                 dst_key_free(&key);
598                 return (result);
599         }
600
601         *keyp = key;
602         return (ISC_R_SUCCESS);
603 }
604
605 isc_result_t
606 dst_key_tobuffer(const dst_key_t *key, isc_buffer_t *target) {
607         REQUIRE(dst_initialized == ISC_TRUE);
608         REQUIRE(VALID_KEY(key));
609         REQUIRE(target != NULL);
610
611         CHECKALG(key->key_alg);
612
613         if (key->func->todns == NULL)
614                 return (DST_R_UNSUPPORTEDALG);
615
616         return (key->func->todns(key, target));
617 }
618
619 isc_result_t
620 dst_key_privatefrombuffer(dst_key_t *key, isc_buffer_t *buffer) {
621         isc_lex_t *lex = NULL;
622         isc_result_t result = ISC_R_SUCCESS;
623
624         REQUIRE(dst_initialized == ISC_TRUE);
625         REQUIRE(VALID_KEY(key));
626         REQUIRE(!dst_key_isprivate(key));
627         REQUIRE(buffer != NULL);
628
629         if (key->func->parse == NULL)
630                 RETERR(DST_R_UNSUPPORTEDALG);
631
632         RETERR(isc_lex_create(key->mctx, 1500, &lex));
633         RETERR(isc_lex_openbuffer(lex, buffer));
634         RETERR(key->func->parse(key, lex));
635  out:
636         if (lex != NULL)
637                 isc_lex_destroy(&lex);
638         return (result);
639 }
640
641 gss_ctx_id_t
642 dst_key_getgssctx(const dst_key_t *key)
643 {
644         REQUIRE(key != NULL);
645
646         return (key->keydata.gssctx);
647 }
648
649 isc_result_t
650 dst_key_fromgssapi(dns_name_t *name, gss_ctx_id_t gssctx, isc_mem_t *mctx,
651                    dst_key_t **keyp)
652 {
653         dst_key_t *key;
654
655         REQUIRE(gssctx != NULL);
656         REQUIRE(keyp != NULL && *keyp == NULL);
657
658         key = get_key_struct(name, DST_ALG_GSSAPI, 0, DNS_KEYPROTO_DNSSEC,
659                              0, dns_rdataclass_in, mctx);
660         if (key == NULL)
661                 return (ISC_R_NOMEMORY);
662
663         key->keydata.gssctx = gssctx;
664         *keyp = key;
665         return (ISC_R_SUCCESS);
666 }
667
668 isc_result_t
669 dst_key_fromlabel(dns_name_t *name, int alg, unsigned int flags,
670                   unsigned int protocol, dns_rdataclass_t rdclass,
671                   const char *engine, const char *label, const char *pin,
672                   isc_mem_t *mctx, dst_key_t **keyp)
673 {
674         dst_key_t *key;
675         isc_result_t result;
676
677         REQUIRE(dst_initialized == ISC_TRUE);
678         REQUIRE(dns_name_isabsolute(name));
679         REQUIRE(mctx != NULL);
680         REQUIRE(keyp != NULL && *keyp == NULL);
681         REQUIRE(label != NULL);
682
683         CHECKALG(alg);
684
685         key = get_key_struct(name, alg, flags, protocol, 0, rdclass, mctx);
686         if (key == NULL)
687                 return (ISC_R_NOMEMORY);
688
689         if (key->func->fromlabel == NULL) {
690                 dst_key_free(&key);
691                 return (DST_R_UNSUPPORTEDALG);
692         }
693
694         result = key->func->fromlabel(key, engine, label, pin);
695         if (result != ISC_R_SUCCESS) {
696                 dst_key_free(&key);
697                 return (result);
698         }
699
700         result = computeid(key);
701         if (result != ISC_R_SUCCESS) {
702                 dst_key_free(&key);
703                 return (result);
704         }
705
706         *keyp = key;
707         return (ISC_R_SUCCESS);
708 }
709
710 isc_result_t
711 dst_key_generate(dns_name_t *name, unsigned int alg,
712                  unsigned int bits, unsigned int param,
713                  unsigned int flags, unsigned int protocol,
714                  dns_rdataclass_t rdclass,
715                  isc_mem_t *mctx, dst_key_t **keyp)
716 {
717         dst_key_t *key;
718         isc_result_t ret;
719
720         REQUIRE(dst_initialized == ISC_TRUE);
721         REQUIRE(dns_name_isabsolute(name));
722         REQUIRE(mctx != NULL);
723         REQUIRE(keyp != NULL && *keyp == NULL);
724
725         CHECKALG(alg);
726
727         key = get_key_struct(name, alg, flags, protocol, bits, rdclass, mctx);
728         if (key == NULL)
729                 return (ISC_R_NOMEMORY);
730
731         if (bits == 0) { /*%< NULL KEY */
732                 key->key_flags |= DNS_KEYTYPE_NOKEY;
733                 *keyp = key;
734                 return (ISC_R_SUCCESS);
735         }
736
737         if (key->func->generate == NULL) {
738                 dst_key_free(&key);
739                 return (DST_R_UNSUPPORTEDALG);
740         }
741
742         ret = key->func->generate(key, param);
743         if (ret != ISC_R_SUCCESS) {
744                 dst_key_free(&key);
745                 return (ret);
746         }
747
748         ret = computeid(key);
749         if (ret != ISC_R_SUCCESS) {
750                 dst_key_free(&key);
751                 return (ret);
752         }
753
754         *keyp = key;
755         return (ISC_R_SUCCESS);
756 }
757
758 isc_boolean_t
759 dst_key_compare(const dst_key_t *key1, const dst_key_t *key2) {
760         REQUIRE(dst_initialized == ISC_TRUE);
761         REQUIRE(VALID_KEY(key1));
762         REQUIRE(VALID_KEY(key2));
763
764         if (key1 == key2)
765                 return (ISC_TRUE);
766         if (key1 == NULL || key2 == NULL)
767                 return (ISC_FALSE);
768         if (key1->key_alg == key2->key_alg &&
769             key1->key_id == key2->key_id &&
770             key1->func->compare != NULL &&
771             key1->func->compare(key1, key2) == ISC_TRUE)
772                 return (ISC_TRUE);
773         else
774                 return (ISC_FALSE);
775 }
776
777 isc_boolean_t
778 dst_key_paramcompare(const dst_key_t *key1, const dst_key_t *key2) {
779         REQUIRE(dst_initialized == ISC_TRUE);
780         REQUIRE(VALID_KEY(key1));
781         REQUIRE(VALID_KEY(key2));
782
783         if (key1 == key2)
784                 return (ISC_TRUE);
785         if (key1 == NULL || key2 == NULL)
786                 return (ISC_FALSE);
787         if (key1->key_alg == key2->key_alg &&
788             key1->func->paramcompare != NULL &&
789             key1->func->paramcompare(key1, key2) == ISC_TRUE)
790                 return (ISC_TRUE);
791         else
792                 return (ISC_FALSE);
793 }
794
795 void
796 dst_key_free(dst_key_t **keyp) {
797         isc_mem_t *mctx;
798         dst_key_t *key;
799
800         REQUIRE(dst_initialized == ISC_TRUE);
801         REQUIRE(keyp != NULL && VALID_KEY(*keyp));
802
803         key = *keyp;
804         mctx = key->mctx;
805
806         if (key->keydata.generic != NULL) {
807                 INSIST(key->func->destroy != NULL);
808                 key->func->destroy(key);
809         }
810         if (key->engine != NULL)
811                 isc_mem_free(mctx, key->engine);
812         if (key->label != NULL)
813                 isc_mem_free(mctx, key->label);
814         dns_name_free(key->key_name, mctx);
815         isc_mem_put(mctx, key->key_name, sizeof(dns_name_t));
816         memset(key, 0, sizeof(dst_key_t));
817         isc_mem_put(mctx, key, sizeof(dst_key_t));
818         *keyp = NULL;
819 }
820
821 isc_boolean_t
822 dst_key_isprivate(const dst_key_t *key) {
823         REQUIRE(VALID_KEY(key));
824         INSIST(key->func->isprivate != NULL);
825         return (key->func->isprivate(key));
826 }
827
828 isc_result_t
829 dst_key_buildfilename(const dst_key_t *key, int type,
830                       const char *directory, isc_buffer_t *out) {
831
832         REQUIRE(VALID_KEY(key));
833         REQUIRE(type == DST_TYPE_PRIVATE || type == DST_TYPE_PUBLIC ||
834                 type == 0);
835
836         return (buildfilename(key->key_name, key->key_id, key->key_alg,
837                               type, directory, out));
838 }
839
840 isc_result_t
841 dst_key_sigsize(const dst_key_t *key, unsigned int *n) {
842         REQUIRE(dst_initialized == ISC_TRUE);
843         REQUIRE(VALID_KEY(key));
844         REQUIRE(n != NULL);
845
846         /* XXXVIX this switch statement is too sparse to gen a jump table. */
847         switch (key->key_alg) {
848         case DST_ALG_RSAMD5:
849         case DST_ALG_RSASHA1:
850         case DST_ALG_NSEC3RSASHA1:
851                 *n = (key->key_size + 7) / 8;
852                 break;
853         case DST_ALG_DSA:
854         case DST_ALG_NSEC3DSA:
855                 *n = DNS_SIG_DSASIGSIZE;
856                 break;
857         case DST_ALG_HMACMD5:
858                 *n = 16;
859                 break;
860         case DST_ALG_HMACSHA1:
861                 *n = ISC_SHA1_DIGESTLENGTH;
862                 break;
863         case DST_ALG_HMACSHA224:
864                 *n = ISC_SHA224_DIGESTLENGTH;
865                 break;
866         case DST_ALG_HMACSHA256:
867                 *n = ISC_SHA256_DIGESTLENGTH;
868                 break;
869         case DST_ALG_HMACSHA384:
870                 *n = ISC_SHA384_DIGESTLENGTH;
871                 break;
872         case DST_ALG_HMACSHA512:
873                 *n = ISC_SHA512_DIGESTLENGTH;
874                 break;
875         case DST_ALG_GSSAPI:
876                 *n = 128; /*%< XXX */
877                 break;
878         case DST_ALG_DH:
879         default:
880                 return (DST_R_UNSUPPORTEDALG);
881         }
882         return (ISC_R_SUCCESS);
883 }
884
885 isc_result_t
886 dst_key_secretsize(const dst_key_t *key, unsigned int *n) {
887         REQUIRE(dst_initialized == ISC_TRUE);
888         REQUIRE(VALID_KEY(key));
889         REQUIRE(n != NULL);
890
891         if (key->key_alg == DST_ALG_DH)
892                 *n = (key->key_size + 7) / 8;
893         else
894                 return (DST_R_UNSUPPORTEDALG);
895         return (ISC_R_SUCCESS);
896 }
897
898 /***
899  *** Static methods
900  ***/
901
902 /*%
903  * Allocates a key structure and fills in some of the fields.
904  */
905 static dst_key_t *
906 get_key_struct(dns_name_t *name, unsigned int alg,
907                unsigned int flags, unsigned int protocol,
908                unsigned int bits, dns_rdataclass_t rdclass,
909                isc_mem_t *mctx)
910 {
911         dst_key_t *key;
912         isc_result_t result;
913
914         key = (dst_key_t *) isc_mem_get(mctx, sizeof(dst_key_t));
915         if (key == NULL)
916                 return (NULL);
917
918         memset(key, 0, sizeof(dst_key_t));
919         key->magic = KEY_MAGIC;
920
921         key->key_name = isc_mem_get(mctx, sizeof(dns_name_t));
922         if (key->key_name == NULL) {
923                 isc_mem_put(mctx, key, sizeof(dst_key_t));
924                 return (NULL);
925         }
926         dns_name_init(key->key_name, NULL);
927         result = dns_name_dup(name, mctx, key->key_name);
928         if (result != ISC_R_SUCCESS) {
929                 isc_mem_put(mctx, key->key_name, sizeof(dns_name_t));
930                 isc_mem_put(mctx, key, sizeof(dst_key_t));
931                 return (NULL);
932         }
933         key->key_alg = alg;
934         key->key_flags = flags;
935         key->key_proto = protocol;
936         key->mctx = mctx;
937         key->keydata.generic = NULL;
938         key->key_size = bits;
939         key->key_class = rdclass;
940         key->func = dst_t_func[alg];
941         return (key);
942 }
943
944 /*%
945  * Reads a public key from disk
946  */
947 isc_result_t
948 dst_key_read_public(const char *filename, int type,
949                     isc_mem_t *mctx, dst_key_t **keyp)
950 {
951         u_char rdatabuf[DST_KEY_MAXSIZE];
952         isc_buffer_t b;
953         dns_fixedname_t name;
954         isc_lex_t *lex = NULL;
955         isc_token_t token;
956         isc_result_t ret;
957         dns_rdata_t rdata = DNS_RDATA_INIT;
958         unsigned int opt = ISC_LEXOPT_DNSMULTILINE;
959         dns_rdataclass_t rdclass = dns_rdataclass_in;
960         isc_lexspecials_t specials;
961         isc_uint32_t ttl;
962         isc_result_t result;
963         dns_rdatatype_t keytype;
964
965         /*
966          * Open the file and read its formatted contents
967          * File format:
968          *    domain.name [ttl] [class] [KEY|DNSKEY] <flags> <protocol> <algorithm> <key>
969          */
970
971         /* 1500 should be large enough for any key */
972         ret = isc_lex_create(mctx, 1500, &lex);
973         if (ret != ISC_R_SUCCESS)
974                 goto cleanup;
975
976         memset(specials, 0, sizeof(specials));
977         specials['('] = 1;
978         specials[')'] = 1;
979         specials['"'] = 1;
980         isc_lex_setspecials(lex, specials);
981         isc_lex_setcomments(lex, ISC_LEXCOMMENT_DNSMASTERFILE);
982
983         ret = isc_lex_openfile(lex, filename);
984         if (ret != ISC_R_SUCCESS)
985                 goto cleanup;
986
987 #define NEXTTOKEN(lex, opt, token) { \
988         ret = isc_lex_gettoken(lex, opt, token); \
989         if (ret != ISC_R_SUCCESS) \
990                 goto cleanup; \
991         }
992
993 #define BADTOKEN() { \
994         ret = ISC_R_UNEXPECTEDTOKEN; \
995         goto cleanup; \
996         }
997
998         /* Read the domain name */
999         NEXTTOKEN(lex, opt, &token);
1000         if (token.type != isc_tokentype_string)
1001                 BADTOKEN();
1002
1003         /*
1004          * We don't support "@" in .key files.
1005          */
1006         if (!strcmp(DST_AS_STR(token), "@"))
1007                 BADTOKEN();
1008
1009         dns_fixedname_init(&name);
1010         isc_buffer_init(&b, DST_AS_STR(token), strlen(DST_AS_STR(token)));
1011         isc_buffer_add(&b, strlen(DST_AS_STR(token)));
1012         ret = dns_name_fromtext(dns_fixedname_name(&name), &b, dns_rootname,
1013                                 ISC_FALSE, NULL);
1014         if (ret != ISC_R_SUCCESS)
1015                 goto cleanup;
1016
1017         /* Read the next word: either TTL, class, or 'KEY' */
1018         NEXTTOKEN(lex, opt, &token);
1019
1020         /* If it's a TTL, read the next one */
1021         result = dns_ttl_fromtext(&token.value.as_textregion, &ttl);
1022         if (result == ISC_R_SUCCESS)
1023                 NEXTTOKEN(lex, opt, &token);
1024
1025         if (token.type != isc_tokentype_string)
1026                 BADTOKEN();
1027
1028         ret = dns_rdataclass_fromtext(&rdclass, &token.value.as_textregion);
1029         if (ret == ISC_R_SUCCESS)
1030                 NEXTTOKEN(lex, opt, &token);
1031
1032         if (token.type != isc_tokentype_string)
1033                 BADTOKEN();
1034
1035         if (strcasecmp(DST_AS_STR(token), "DNSKEY") == 0)
1036                 keytype = dns_rdatatype_dnskey;
1037         else if (strcasecmp(DST_AS_STR(token), "KEY") == 0)
1038                 keytype = dns_rdatatype_key; /*%< SIG(0), TKEY */
1039         else
1040                 BADTOKEN();
1041
1042         if (((type & DST_TYPE_KEY) != 0 && keytype != dns_rdatatype_key) ||
1043             ((type & DST_TYPE_KEY) == 0 && keytype != dns_rdatatype_dnskey)) {
1044                 ret = DST_R_BADKEYTYPE;
1045                 goto cleanup;
1046         }
1047
1048         isc_buffer_init(&b, rdatabuf, sizeof(rdatabuf));
1049         ret = dns_rdata_fromtext(&rdata, rdclass, keytype, lex, NULL,
1050                                  ISC_FALSE, mctx, &b, NULL);
1051         if (ret != ISC_R_SUCCESS)
1052                 goto cleanup;
1053
1054         ret = dst_key_fromdns(dns_fixedname_name(&name), rdclass, &b, mctx,
1055                               keyp);
1056         if (ret != ISC_R_SUCCESS)
1057                 goto cleanup;
1058
1059  cleanup:
1060         if (lex != NULL)
1061                 isc_lex_destroy(&lex);
1062         return (ret);
1063 }
1064
1065 static isc_boolean_t
1066 issymmetric(const dst_key_t *key) {
1067         REQUIRE(dst_initialized == ISC_TRUE);
1068         REQUIRE(VALID_KEY(key));
1069
1070         /* XXXVIX this switch statement is too sparse to gen a jump table. */
1071         switch (key->key_alg) {
1072         case DST_ALG_RSAMD5:
1073         case DST_ALG_RSASHA1:
1074         case DST_ALG_NSEC3RSASHA1:
1075         case DST_ALG_DSA:
1076         case DST_ALG_NSEC3DSA:
1077         case DST_ALG_DH:
1078                 return (ISC_FALSE);
1079         case DST_ALG_HMACMD5:
1080         case DST_ALG_GSSAPI:
1081                 return (ISC_TRUE);
1082         default:
1083                 return (ISC_FALSE);
1084         }
1085 }
1086
1087 /*%
1088  * Writes a public key to disk in DNS format.
1089  */
1090 static isc_result_t
1091 write_public_key(const dst_key_t *key, int type, const char *directory) {
1092         FILE *fp;
1093         isc_buffer_t keyb, textb, fileb, classb;
1094         isc_region_t r;
1095         char filename[ISC_DIR_NAMEMAX];
1096         unsigned char key_array[DST_KEY_MAXSIZE];
1097         char text_array[DST_KEY_MAXTEXTSIZE];
1098         char class_array[10];
1099         isc_result_t ret;
1100         dns_rdata_t rdata = DNS_RDATA_INIT;
1101         isc_fsaccess_t access;
1102
1103         REQUIRE(VALID_KEY(key));
1104
1105         isc_buffer_init(&keyb, key_array, sizeof(key_array));
1106         isc_buffer_init(&textb, text_array, sizeof(text_array));
1107         isc_buffer_init(&classb, class_array, sizeof(class_array));
1108
1109         ret = dst_key_todns(key, &keyb);
1110         if (ret != ISC_R_SUCCESS)
1111                 return (ret);
1112
1113         isc_buffer_usedregion(&keyb, &r);
1114         dns_rdata_fromregion(&rdata, key->key_class, dns_rdatatype_dnskey, &r);
1115
1116         ret = dns_rdata_totext(&rdata, (dns_name_t *) NULL, &textb);
1117         if (ret != ISC_R_SUCCESS)
1118                 return (DST_R_INVALIDPUBLICKEY);
1119
1120         ret = dns_rdataclass_totext(key->key_class, &classb);
1121         if (ret != ISC_R_SUCCESS)
1122                 return (DST_R_INVALIDPUBLICKEY);
1123
1124         /*
1125          * Make the filename.
1126          */
1127         isc_buffer_init(&fileb, filename, sizeof(filename));
1128         ret = dst_key_buildfilename(key, DST_TYPE_PUBLIC, directory, &fileb);
1129         if (ret != ISC_R_SUCCESS)
1130                 return (ret);
1131
1132         /*
1133          * Create public key file.
1134          */
1135         if ((fp = fopen(filename, "w")) == NULL)
1136                 return (DST_R_WRITEERROR);
1137
1138         if (issymmetric(key)) {
1139                 access = 0;
1140                 isc_fsaccess_add(ISC_FSACCESS_OWNER,
1141                                  ISC_FSACCESS_READ | ISC_FSACCESS_WRITE,
1142                                  &access);
1143                 (void)isc_fsaccess_set(filename, access);
1144         }
1145
1146         ret = dns_name_print(key->key_name, fp);
1147         if (ret != ISC_R_SUCCESS) {
1148                 fclose(fp);
1149                 return (ret);
1150         }
1151
1152         fprintf(fp, " ");
1153
1154         isc_buffer_usedregion(&classb, &r);
1155         fwrite(r.base, 1, r.length, fp);
1156
1157         if ((type & DST_TYPE_KEY) != 0)
1158                 fprintf(fp, " KEY ");
1159         else
1160                 fprintf(fp, " DNSKEY ");
1161
1162         isc_buffer_usedregion(&textb, &r);
1163         fwrite(r.base, 1, r.length, fp);
1164
1165         fputc('\n', fp);
1166         fflush(fp);
1167         if (ferror(fp))
1168                 ret = DST_R_WRITEERROR;
1169         fclose(fp);
1170
1171         return (ret);
1172 }
1173
1174 static isc_result_t
1175 buildfilename(dns_name_t *name, dns_keytag_t id,
1176               unsigned int alg, unsigned int type,
1177               const char *directory, isc_buffer_t *out)
1178 {
1179         const char *suffix = "";
1180         unsigned int len;
1181         isc_result_t result;
1182
1183         REQUIRE(out != NULL);
1184         if ((type & DST_TYPE_PRIVATE) != 0)
1185                 suffix = ".private";
1186         else if (type == DST_TYPE_PUBLIC)
1187                 suffix = ".key";
1188         if (directory != NULL) {
1189                 if (isc_buffer_availablelength(out) < strlen(directory))
1190                         return (ISC_R_NOSPACE);
1191                 isc_buffer_putstr(out, directory);
1192                 if (strlen(directory) > 0U &&
1193                     directory[strlen(directory) - 1] != '/')
1194                         isc_buffer_putstr(out, "/");
1195         }
1196         if (isc_buffer_availablelength(out) < 1)
1197                 return (ISC_R_NOSPACE);
1198         isc_buffer_putstr(out, "K");
1199         result = dns_name_tofilenametext(name, ISC_FALSE, out);
1200         if (result != ISC_R_SUCCESS)
1201                 return (result);
1202         len = 1 + 3 + 1 + 5 + strlen(suffix) + 1;
1203         if (isc_buffer_availablelength(out) < len)
1204                 return (ISC_R_NOSPACE);
1205         sprintf((char *) isc_buffer_used(out), "+%03d+%05d%s", alg, id,
1206                 suffix);
1207         isc_buffer_add(out, len);
1208
1209         return (ISC_R_SUCCESS);
1210 }
1211
1212 static isc_result_t
1213 computeid(dst_key_t *key) {
1214         isc_buffer_t dnsbuf;
1215         unsigned char dns_array[DST_KEY_MAXSIZE];
1216         isc_region_t r;
1217         isc_result_t ret;
1218
1219         isc_buffer_init(&dnsbuf, dns_array, sizeof(dns_array));
1220         ret = dst_key_todns(key, &dnsbuf);
1221         if (ret != ISC_R_SUCCESS)
1222                 return (ret);
1223
1224         isc_buffer_usedregion(&dnsbuf, &r);
1225         key->key_id = dst_region_computeid(&r, key->key_alg);
1226         return (ISC_R_SUCCESS);
1227 }
1228
1229 static isc_result_t
1230 frombuffer(dns_name_t *name, unsigned int alg, unsigned int flags,
1231            unsigned int protocol, dns_rdataclass_t rdclass,
1232            isc_buffer_t *source, isc_mem_t *mctx, dst_key_t **keyp)
1233 {
1234         dst_key_t *key;
1235         isc_result_t ret;
1236
1237         REQUIRE(dns_name_isabsolute(name));
1238         REQUIRE(source != NULL);
1239         REQUIRE(mctx != NULL);
1240         REQUIRE(keyp != NULL && *keyp == NULL);
1241
1242         key = get_key_struct(name, alg, flags, protocol, 0, rdclass, mctx);
1243         if (key == NULL)
1244                 return (ISC_R_NOMEMORY);
1245
1246         if (isc_buffer_remaininglength(source) > 0) {
1247                 ret = algorithm_status(alg);
1248                 if (ret != ISC_R_SUCCESS) {
1249                         dst_key_free(&key);
1250                         return (ret);
1251                 }
1252                 if (key->func->fromdns == NULL) {
1253                         dst_key_free(&key);
1254                         return (DST_R_UNSUPPORTEDALG);
1255                 }
1256
1257                 ret = key->func->fromdns(key, source);
1258                 if (ret != ISC_R_SUCCESS) {
1259                         dst_key_free(&key);
1260                         return (ret);
1261                 }
1262         }
1263
1264         *keyp = key;
1265         return (ISC_R_SUCCESS);
1266 }
1267
1268 static isc_result_t
1269 algorithm_status(unsigned int alg) {
1270         REQUIRE(dst_initialized == ISC_TRUE);
1271
1272         if (dst_algorithm_supported(alg))
1273                 return (ISC_R_SUCCESS);
1274 #ifndef OPENSSL
1275         if (alg == DST_ALG_RSAMD5 || alg == DST_ALG_RSASHA1 ||
1276             alg == DST_ALG_DSA || alg == DST_ALG_DH ||
1277             alg == DST_ALG_HMACMD5 || alg == DST_ALG_NSEC3DSA ||
1278             alg == DST_ALG_NSEC3RSASHA1)
1279                 return (DST_R_NOCRYPTO);
1280 #endif
1281         return (DST_R_UNSUPPORTEDALG);
1282 }
1283
1284 static isc_result_t
1285 addsuffix(char *filename, unsigned int len, const char *ofilename,
1286           const char *suffix)
1287 {
1288         int olen = strlen(ofilename);
1289         int n;
1290
1291         if (olen > 1 && ofilename[olen - 1] == '.')
1292                 olen -= 1;
1293         else if (olen > 8 && strcmp(ofilename + olen - 8, ".private") == 0)
1294                 olen -= 8;
1295         else if (olen > 4 && strcmp(ofilename + olen - 4, ".key") == 0)
1296                 olen -= 4;
1297
1298         n = snprintf(filename, len, "%.*s%s", olen, ofilename, suffix);
1299         if (n < 0)
1300                 return (ISC_R_NOSPACE);
1301         return (ISC_R_SUCCESS);
1302 }
1303
1304 isc_result_t
1305 dst__entropy_getdata(void *buf, unsigned int len, isc_boolean_t pseudo) {
1306         unsigned int flags = dst_entropy_flags;
1307         if (pseudo)
1308                 flags &= ~ISC_ENTROPY_GOODONLY;
1309         return (isc_entropy_getdata(dst_entropy_pool, buf, len, NULL, flags));
1310 }
1311
1312 unsigned int
1313 dst__entropy_status(void) {
1314         return (isc_entropy_status(dst_entropy_pool));
1315 }