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