bind - Upgraded vendor branch to 9.5.2-P1
[dragonfly.git] / contrib / bind-9.5.2 / lib / dns / openssldsa_link.c
1 /*
2  * Portions Copyright (C) 2004-2007, 2009  Internet Systems Consortium, Inc. ("ISC")
3  * Portions Copyright (C) 1999-2002  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 /* $Id: openssldsa_link.c,v 1.11.92.2 2009/01/14 23:46:33 tbox Exp $ */
33
34 #ifdef OPENSSL
35
36 #include <config.h>
37
38 #include <string.h>
39
40 #include <isc/entropy.h>
41 #include <isc/mem.h>
42 #include <isc/sha1.h>
43 #include <isc/util.h>
44
45 #include <dst/result.h>
46
47 #include "dst_internal.h"
48 #include "dst_openssl.h"
49 #include "dst_parse.h"
50
51 #include <openssl/dsa.h>
52
53 static isc_result_t openssldsa_todns(const dst_key_t *key, isc_buffer_t *data);
54
55 static isc_result_t
56 openssldsa_createctx(dst_key_t *key, dst_context_t *dctx) {
57         isc_sha1_t *sha1ctx;
58
59         UNUSED(key);
60
61         sha1ctx = isc_mem_get(dctx->mctx, sizeof(isc_sha1_t));
62         isc_sha1_init(sha1ctx);
63         dctx->ctxdata.sha1ctx = sha1ctx;
64         return (ISC_R_SUCCESS);
65 }
66
67 static void
68 openssldsa_destroyctx(dst_context_t *dctx) {
69         isc_sha1_t *sha1ctx = dctx->ctxdata.sha1ctx;
70
71         if (sha1ctx != NULL) {
72                 isc_sha1_invalidate(sha1ctx);
73                 isc_mem_put(dctx->mctx, sha1ctx, sizeof(isc_sha1_t));
74                 dctx->ctxdata.sha1ctx = NULL;
75         }
76 }
77
78 static isc_result_t
79 openssldsa_adddata(dst_context_t *dctx, const isc_region_t *data) {
80         isc_sha1_t *sha1ctx = dctx->ctxdata.sha1ctx;
81
82         isc_sha1_update(sha1ctx, data->base, data->length);
83         return (ISC_R_SUCCESS);
84 }
85
86 static int
87 BN_bn2bin_fixed(BIGNUM *bn, unsigned char *buf, int size) {
88         int bytes = size - BN_num_bytes(bn);
89         while (bytes-- > 0)
90                 *buf++ = 0;
91         BN_bn2bin(bn, buf);
92         return (size);
93 }
94
95 static isc_result_t
96 openssldsa_sign(dst_context_t *dctx, isc_buffer_t *sig) {
97         isc_sha1_t *sha1ctx = dctx->ctxdata.sha1ctx;
98         dst_key_t *key = dctx->key;
99         DSA *dsa = key->keydata.dsa;
100         DSA_SIG *dsasig;
101         isc_region_t r;
102         unsigned char digest[ISC_SHA1_DIGESTLENGTH];
103
104         isc_buffer_availableregion(sig, &r);
105         if (r.length < ISC_SHA1_DIGESTLENGTH * 2 + 1)
106                 return (ISC_R_NOSPACE);
107
108         isc_sha1_final(sha1ctx, digest);
109
110         dsasig = DSA_do_sign(digest, ISC_SHA1_DIGESTLENGTH, dsa);
111         if (dsasig == NULL)
112                 return (dst__openssl_toresult(DST_R_SIGNFAILURE));
113
114         *r.base++ = (key->key_size - 512)/64;
115         BN_bn2bin_fixed(dsasig->r, r.base, ISC_SHA1_DIGESTLENGTH);
116         r.base += ISC_SHA1_DIGESTLENGTH;
117         BN_bn2bin_fixed(dsasig->s, r.base, ISC_SHA1_DIGESTLENGTH);
118         r.base += ISC_SHA1_DIGESTLENGTH;
119         DSA_SIG_free(dsasig);
120         isc_buffer_add(sig, ISC_SHA1_DIGESTLENGTH * 2 + 1);
121
122         return (ISC_R_SUCCESS);
123 }
124
125 static isc_result_t
126 openssldsa_verify(dst_context_t *dctx, const isc_region_t *sig) {
127         isc_sha1_t *sha1ctx = dctx->ctxdata.sha1ctx;
128         dst_key_t *key = dctx->key;
129         DSA *dsa = key->keydata.dsa;
130         DSA_SIG *dsasig;
131         int status = 0;
132         unsigned char digest[ISC_SHA1_DIGESTLENGTH];
133         unsigned char *cp = sig->base;
134
135         isc_sha1_final(sha1ctx, digest);
136
137         if (sig->length < 2 * ISC_SHA1_DIGESTLENGTH + 1)
138                 return (DST_R_VERIFYFAILURE);
139
140         cp++;   /*%< Skip T */
141         dsasig = DSA_SIG_new();
142         dsasig->r = BN_bin2bn(cp, ISC_SHA1_DIGESTLENGTH, NULL);
143         cp += ISC_SHA1_DIGESTLENGTH;
144         dsasig->s = BN_bin2bn(cp, ISC_SHA1_DIGESTLENGTH, NULL);
145         cp += ISC_SHA1_DIGESTLENGTH;
146
147         status = DSA_do_verify(digest, ISC_SHA1_DIGESTLENGTH, dsasig, dsa);
148         DSA_SIG_free(dsasig);
149         if (status != 1)
150                 return (dst__openssl_toresult(DST_R_VERIFYFAILURE));
151
152         return (ISC_R_SUCCESS);
153 }
154
155 static isc_boolean_t
156 openssldsa_compare(const dst_key_t *key1, const dst_key_t *key2) {
157         int status;
158         DSA *dsa1, *dsa2;
159
160         dsa1 = key1->keydata.dsa;
161         dsa2 = key2->keydata.dsa;
162
163         if (dsa1 == NULL && dsa2 == NULL)
164                 return (ISC_TRUE);
165         else if (dsa1 == NULL || dsa2 == NULL)
166                 return (ISC_FALSE);
167
168         status = BN_cmp(dsa1->p, dsa2->p) ||
169                  BN_cmp(dsa1->q, dsa2->q) ||
170                  BN_cmp(dsa1->g, dsa2->g) ||
171                  BN_cmp(dsa1->pub_key, dsa2->pub_key);
172
173         if (status != 0)
174                 return (ISC_FALSE);
175
176         if (dsa1->priv_key != NULL || dsa2->priv_key != NULL) {
177                 if (dsa1->priv_key == NULL || dsa2->priv_key == NULL)
178                         return (ISC_FALSE);
179                 if (BN_cmp(dsa1->priv_key, dsa2->priv_key))
180                         return (ISC_FALSE);
181         }
182         return (ISC_TRUE);
183 }
184
185 static isc_result_t
186 openssldsa_generate(dst_key_t *key, int unused) {
187 #if OPENSSL_VERSION_NUMBER > 0x00908000L
188         BN_GENCB cb;
189 #endif
190         DSA *dsa;
191         unsigned char rand_array[ISC_SHA1_DIGESTLENGTH];
192         isc_result_t result;
193
194         UNUSED(unused);
195
196         result = dst__entropy_getdata(rand_array, sizeof(rand_array),
197                                       ISC_FALSE);
198         if (result != ISC_R_SUCCESS)
199                 return (result);
200
201 #if OPENSSL_VERSION_NUMBER > 0x00908000L
202         dsa = DSA_new();
203         if (dsa == NULL)
204                 return (dst__openssl_toresult(DST_R_OPENSSLFAILURE));
205
206         BN_GENCB_set_old(&cb, NULL, NULL);
207
208         if (!DSA_generate_parameters_ex(dsa, key->key_size, rand_array,
209                                         ISC_SHA1_DIGESTLENGTH,  NULL, NULL,
210                                         &cb))
211         {
212                 DSA_free(dsa);
213                 return (dst__openssl_toresult(DST_R_OPENSSLFAILURE));
214         }
215 #else
216         dsa = DSA_generate_parameters(key->key_size, rand_array,
217                                       ISC_SHA1_DIGESTLENGTH, NULL, NULL,
218                                       NULL, NULL);
219         if (dsa == NULL)
220                 return (dst__openssl_toresult(DST_R_OPENSSLFAILURE));
221 #endif
222
223         if (DSA_generate_key(dsa) == 0) {
224                 DSA_free(dsa);
225                 return (dst__openssl_toresult(DST_R_OPENSSLFAILURE));
226         }
227         dsa->flags &= ~DSA_FLAG_CACHE_MONT_P;
228
229         key->keydata.dsa = dsa;
230
231         return (ISC_R_SUCCESS);
232 }
233
234 static isc_boolean_t
235 openssldsa_isprivate(const dst_key_t *key) {
236         DSA *dsa = key->keydata.dsa;
237         return (ISC_TF(dsa != NULL && dsa->priv_key != NULL));
238 }
239
240 static void
241 openssldsa_destroy(dst_key_t *key) {
242         DSA *dsa = key->keydata.dsa;
243         DSA_free(dsa);
244         key->keydata.dsa = NULL;
245 }
246
247
248 static isc_result_t
249 openssldsa_todns(const dst_key_t *key, isc_buffer_t *data) {
250         DSA *dsa;
251         isc_region_t r;
252         int dnslen;
253         unsigned int t, p_bytes;
254
255         REQUIRE(key->keydata.dsa != NULL);
256
257         dsa = key->keydata.dsa;
258
259         isc_buffer_availableregion(data, &r);
260
261         t = (BN_num_bytes(dsa->p) - 64) / 8;
262         if (t > 8)
263                 return (DST_R_INVALIDPUBLICKEY);
264         p_bytes = 64 + 8 * t;
265
266         dnslen = 1 + (key->key_size * 3)/8 + ISC_SHA1_DIGESTLENGTH;
267         if (r.length < (unsigned int) dnslen)
268                 return (ISC_R_NOSPACE);
269
270         *r.base++ = t;
271         BN_bn2bin_fixed(dsa->q, r.base, ISC_SHA1_DIGESTLENGTH);
272         r.base += ISC_SHA1_DIGESTLENGTH;
273         BN_bn2bin_fixed(dsa->p, r.base, key->key_size/8);
274         r.base += p_bytes;
275         BN_bn2bin_fixed(dsa->g, r.base, key->key_size/8);
276         r.base += p_bytes;
277         BN_bn2bin_fixed(dsa->pub_key, r.base, key->key_size/8);
278         r.base += p_bytes;
279
280         isc_buffer_add(data, dnslen);
281
282         return (ISC_R_SUCCESS);
283 }
284
285 static isc_result_t
286 openssldsa_fromdns(dst_key_t *key, isc_buffer_t *data) {
287         DSA *dsa;
288         isc_region_t r;
289         unsigned int t, p_bytes;
290         isc_mem_t *mctx = key->mctx;
291
292         UNUSED(mctx);
293
294         isc_buffer_remainingregion(data, &r);
295         if (r.length == 0)
296                 return (ISC_R_SUCCESS);
297
298         dsa = DSA_new();
299         if (dsa == NULL)
300                 return (ISC_R_NOMEMORY);
301         dsa->flags &= ~DSA_FLAG_CACHE_MONT_P;
302
303         t = (unsigned int) *r.base++;
304         if (t > 8) {
305                 DSA_free(dsa);
306                 return (DST_R_INVALIDPUBLICKEY);
307         }
308         p_bytes = 64 + 8 * t;
309
310         if (r.length < 1 + ISC_SHA1_DIGESTLENGTH + 3 * p_bytes) {
311                 DSA_free(dsa);
312                 return (DST_R_INVALIDPUBLICKEY);
313         }
314
315         dsa->q = BN_bin2bn(r.base, ISC_SHA1_DIGESTLENGTH, NULL);
316         r.base += ISC_SHA1_DIGESTLENGTH;
317
318         dsa->p = BN_bin2bn(r.base, p_bytes, NULL);
319         r.base += p_bytes;
320
321         dsa->g = BN_bin2bn(r.base, p_bytes, NULL);
322         r.base += p_bytes;
323
324         dsa->pub_key = BN_bin2bn(r.base, p_bytes, NULL);
325         r.base += p_bytes;
326
327         key->key_size = p_bytes * 8;
328
329         isc_buffer_forward(data, 1 + ISC_SHA1_DIGESTLENGTH + 3 * p_bytes);
330
331         key->keydata.dsa = dsa;
332
333         return (ISC_R_SUCCESS);
334 }
335
336
337 static isc_result_t
338 openssldsa_tofile(const dst_key_t *key, const char *directory) {
339         int cnt = 0;
340         DSA *dsa;
341         dst_private_t priv;
342         unsigned char bufs[5][128];
343
344         if (key->keydata.dsa == NULL)
345                 return (DST_R_NULLKEY);
346
347         dsa = key->keydata.dsa;
348
349         priv.elements[cnt].tag = TAG_DSA_PRIME;
350         priv.elements[cnt].length = BN_num_bytes(dsa->p);
351         BN_bn2bin(dsa->p, bufs[cnt]);
352         priv.elements[cnt].data = bufs[cnt];
353         cnt++;
354
355         priv.elements[cnt].tag = TAG_DSA_SUBPRIME;
356         priv.elements[cnt].length = BN_num_bytes(dsa->q);
357         BN_bn2bin(dsa->q, bufs[cnt]);
358         priv.elements[cnt].data = bufs[cnt];
359         cnt++;
360
361         priv.elements[cnt].tag = TAG_DSA_BASE;
362         priv.elements[cnt].length = BN_num_bytes(dsa->g);
363         BN_bn2bin(dsa->g, bufs[cnt]);
364         priv.elements[cnt].data = bufs[cnt];
365         cnt++;
366
367         priv.elements[cnt].tag = TAG_DSA_PRIVATE;
368         priv.elements[cnt].length = BN_num_bytes(dsa->priv_key);
369         BN_bn2bin(dsa->priv_key, bufs[cnt]);
370         priv.elements[cnt].data = bufs[cnt];
371         cnt++;
372
373         priv.elements[cnt].tag = TAG_DSA_PUBLIC;
374         priv.elements[cnt].length = BN_num_bytes(dsa->pub_key);
375         BN_bn2bin(dsa->pub_key, bufs[cnt]);
376         priv.elements[cnt].data = bufs[cnt];
377         cnt++;
378
379         priv.nelements = cnt;
380         return (dst__privstruct_writefile(key, &priv, directory));
381 }
382
383 static isc_result_t
384 openssldsa_parse(dst_key_t *key, isc_lex_t *lexer) {
385         dst_private_t priv;
386         isc_result_t ret;
387         int i;
388         DSA *dsa = NULL;
389         isc_mem_t *mctx = key->mctx;
390 #define DST_RET(a) {ret = a; goto err;}
391
392         /* read private key file */
393         ret = dst__privstruct_parse(key, DST_ALG_DSA, lexer, mctx, &priv);
394         if (ret != ISC_R_SUCCESS)
395                 return (ret);
396
397         dsa = DSA_new();
398         if (dsa == NULL)
399                 DST_RET(ISC_R_NOMEMORY);
400         dsa->flags &= ~DSA_FLAG_CACHE_MONT_P;
401         key->keydata.dsa = dsa;
402
403         for (i=0; i < priv.nelements; i++) {
404                 BIGNUM *bn;
405                 bn = BN_bin2bn(priv.elements[i].data,
406                                priv.elements[i].length, NULL);
407                 if (bn == NULL)
408                         DST_RET(ISC_R_NOMEMORY);
409
410                 switch (priv.elements[i].tag) {
411                         case TAG_DSA_PRIME:
412                                 dsa->p = bn;
413                                 break;
414                         case TAG_DSA_SUBPRIME:
415                                 dsa->q = bn;
416                                 break;
417                         case TAG_DSA_BASE:
418                                 dsa->g = bn;
419                                 break;
420                         case TAG_DSA_PRIVATE:
421                                 dsa->priv_key = bn;
422                                 break;
423                         case TAG_DSA_PUBLIC:
424                                 dsa->pub_key = bn;
425                                 break;
426                 }
427         }
428         dst__privstruct_free(&priv, mctx);
429
430         key->key_size = BN_num_bits(dsa->p);
431
432         return (ISC_R_SUCCESS);
433
434  err:
435         openssldsa_destroy(key);
436         dst__privstruct_free(&priv, mctx);
437         memset(&priv, 0, sizeof(priv));
438         return (ret);
439 }
440
441 static dst_func_t openssldsa_functions = {
442         openssldsa_createctx,
443         openssldsa_destroyctx,
444         openssldsa_adddata,
445         openssldsa_sign,
446         openssldsa_verify,
447         NULL, /*%< computesecret */
448         openssldsa_compare,
449         NULL, /*%< paramcompare */
450         openssldsa_generate,
451         openssldsa_isprivate,
452         openssldsa_destroy,
453         openssldsa_todns,
454         openssldsa_fromdns,
455         openssldsa_tofile,
456         openssldsa_parse,
457         NULL, /*%< cleanup */
458 };
459
460 isc_result_t
461 dst__openssldsa_init(dst_func_t **funcp) {
462         REQUIRE(funcp != NULL);
463         if (*funcp == NULL)
464                 *funcp = &openssldsa_functions;
465         return (ISC_R_SUCCESS);
466 }
467
468 #else /* OPENSSL */
469
470 #include <isc/util.h>
471
472 EMPTY_TRANSLATION_UNIT
473
474 #endif /* OPENSSL */
475 /*! \file */