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