Add BIND 9.2.4rc7.
[dragonfly.git] / contrib / bind-9.2.4rc7 / lib / dns / sec / dst / openssldh_link.c
blobfb29bec193024e30e716dc87debfa631f3c8e841
1 /*
2 * Portions Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
3 * Portions Copyright (C) 1999-2001 Internet Software Consortium.
4 * Portions Copyright (C) 1995-2000 by Network Associates, Inc.
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS
11 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE
13 * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
16 * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 * Principal Author: Brian Wellington
21 * $Id: openssldh_link.c,v 1.38.2.4 2004/03/16 12:45:41 marka Exp $
24 #ifdef OPENSSL
26 #include <config.h>
28 #include <ctype.h>
30 #include <isc/mem.h>
31 #include <isc/string.h>
32 #include <isc/util.h>
34 #include <dst/result.h>
36 #include "dst_internal.h"
37 #include "dst_parse.h"
39 #include <openssl/dh.h>
41 #define PRIME768 "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088" \
42 "A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25" \
43 "F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A63A3620FFFFFFFFFFFFFFFF"
45 #define PRIME1024 "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E08" \
46 "8A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF2" \
47 "5F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406" \
48 "B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF"
50 static isc_result_t openssldh_todns(const dst_key_t *key, isc_buffer_t *data);
52 static BIGNUM bn2, bn768, bn1024;
54 static isc_result_t
55 openssldh_computesecret(const dst_key_t *pub, const dst_key_t *priv,
56 isc_buffer_t *secret)
58 DH *dhpub, *dhpriv;
59 int ret;
60 isc_region_t r;
61 unsigned int len;
63 REQUIRE(pub->opaque != NULL);
64 REQUIRE(priv->opaque != NULL);
66 dhpub = (DH *) pub->opaque;
67 dhpriv = (DH *) priv->opaque;
69 len = DH_size(dhpriv);
70 isc_buffer_availableregion(secret, &r);
71 if (r.length < len)
72 return (ISC_R_NOSPACE);
73 ret = DH_compute_key(r.base, dhpub->pub_key, dhpriv);
74 if (ret == 0)
75 return (DST_R_COMPUTESECRETFAILURE);
76 isc_buffer_add(secret, len);
77 return (ISC_R_SUCCESS);
80 static isc_boolean_t
81 openssldh_compare(const dst_key_t *key1, const dst_key_t *key2) {
82 int status;
83 DH *dh1, *dh2;
85 dh1 = (DH *) key1->opaque;
86 dh2 = (DH *) key2->opaque;
88 if (dh1 == NULL && dh2 == NULL)
89 return (ISC_TRUE);
90 else if (dh1 == NULL || dh2 == NULL)
91 return (ISC_FALSE);
93 status = BN_cmp(dh1->p, dh2->p) ||
94 BN_cmp(dh1->g, dh2->g) ||
95 BN_cmp(dh1->pub_key, dh2->pub_key);
97 if (status != 0)
98 return (ISC_FALSE);
100 if (dh1->priv_key != NULL || dh2->priv_key != NULL) {
101 if (dh1->priv_key == NULL || dh2->priv_key == NULL)
102 return (ISC_FALSE);
103 if (BN_cmp(dh1->priv_key, dh2->priv_key) != 0)
104 return (ISC_FALSE);
106 return (ISC_TRUE);
109 static isc_boolean_t
110 openssldh_paramcompare(const dst_key_t *key1, const dst_key_t *key2) {
111 int status;
112 DH *dh1, *dh2;
114 dh1 = (DH *) key1->opaque;
115 dh2 = (DH *) key2->opaque;
117 if (dh1 == NULL && dh2 == NULL)
118 return (ISC_TRUE);
119 else if (dh1 == NULL || dh2 == NULL)
120 return (ISC_FALSE);
122 status = BN_cmp(dh1->p, dh2->p) ||
123 BN_cmp(dh1->g, dh2->g);
125 if (status != 0)
126 return (ISC_FALSE);
127 return (ISC_TRUE);
130 static isc_result_t
131 openssldh_generate(dst_key_t *key, int generator) {
132 DH *dh = NULL;
134 if (generator == 0) {
135 if (key->key_size == 768 || key->key_size == 1024) {
136 dh = DH_new();
137 if (dh == NULL)
138 return (ISC_R_NOMEMORY);
139 if (key->key_size == 768)
140 dh->p = &bn768;
141 else
142 dh->p = &bn1024;
143 dh->g = &bn2;
145 else
146 generator = 2;
149 if (generator != 0)
150 dh = DH_generate_parameters(key->key_size, generator,
151 NULL, NULL);
153 if (dh == NULL)
154 return (DST_R_OPENSSLFAILURE);
156 if (DH_generate_key(dh) == 0) {
157 DH_free(dh);
158 return (DST_R_OPENSSLFAILURE);
160 dh->flags &= ~DH_FLAG_CACHE_MONT_P;
162 key->opaque = dh;
164 return (ISC_R_SUCCESS);
167 static isc_boolean_t
168 openssldh_isprivate(const dst_key_t *key) {
169 DH *dh = (DH *) key->opaque;
170 return (ISC_TF(dh != NULL && dh->priv_key != NULL));
173 static isc_boolean_t
174 openssldh_issymmetric(void) {
175 return (ISC_FALSE);
178 static void
179 openssldh_destroy(dst_key_t *key) {
180 DH *dh = key->opaque;
182 if (dh == NULL)
183 return;
185 if (dh->p == &bn768 || dh->p == &bn1024)
186 dh->p = NULL;
187 if (dh->g == &bn2)
188 dh->g = NULL;
189 DH_free(dh);
190 key->opaque = NULL;
193 static void
194 uint16_toregion(isc_uint16_t val, isc_region_t *region) {
195 *region->base++ = (val & 0xff00) >> 8;
196 *region->base++ = (val & 0x00ff);
199 static isc_uint16_t
200 uint16_fromregion(isc_region_t *region) {
201 isc_uint16_t val;
202 unsigned char *cp = region->base;
204 val = ((unsigned int)(cp[0])) << 8;
205 val |= ((unsigned int)(cp[1]));
207 region->base += 2;
208 return (val);
211 static isc_result_t
212 openssldh_todns(const dst_key_t *key, isc_buffer_t *data) {
213 DH *dh;
214 isc_region_t r;
215 isc_uint16_t dnslen, plen, glen, publen;
217 REQUIRE(key->opaque != NULL);
219 dh = (DH *) key->opaque;
221 isc_buffer_availableregion(data, &r);
223 if (dh->g == &bn2 && (dh->p == &bn768 || dh->p == &bn1024)) {
224 plen = 1;
225 glen = 0;
227 else {
228 plen = BN_num_bytes(dh->p);
229 glen = BN_num_bytes(dh->g);
231 publen = BN_num_bytes(dh->pub_key);
232 dnslen = plen + glen + publen + 6;
233 if (r.length < (unsigned int) dnslen)
234 return (ISC_R_NOSPACE);
236 uint16_toregion(plen, &r);
237 if (plen == 1) {
238 if (dh->p == &bn768)
239 *r.base = 1;
240 else
241 *r.base = 2;
243 else
244 BN_bn2bin(dh->p, r.base);
245 r.base += plen;
247 uint16_toregion(glen, &r);
248 if (glen > 0)
249 BN_bn2bin(dh->g, r.base);
250 r.base += glen;
252 uint16_toregion(publen, &r);
253 BN_bn2bin(dh->pub_key, r.base);
254 r.base += publen;
256 isc_buffer_add(data, dnslen);
258 return (ISC_R_SUCCESS);
261 static isc_result_t
262 openssldh_fromdns(dst_key_t *key, isc_buffer_t *data) {
263 DH *dh;
264 isc_region_t r;
265 isc_uint16_t plen, glen, publen;
266 int special = 0;
268 isc_buffer_remainingregion(data, &r);
269 if (r.length == 0)
270 return (ISC_R_SUCCESS);
272 dh = DH_new();
273 if (dh == NULL)
274 return (ISC_R_NOMEMORY);
275 dh->flags &= ~DH_FLAG_CACHE_MONT_P;
278 * Read the prime length. 1 & 2 are table entries, > 16 means a
279 * prime follows, otherwise an error.
281 if (r.length < 2) {
282 DH_free(dh);
283 return (DST_R_INVALIDPUBLICKEY);
285 plen = uint16_fromregion(&r);
286 if (plen < 16 && plen != 1 && plen != 2) {
287 DH_free(dh);
288 return (DST_R_INVALIDPUBLICKEY);
290 if (r.length < plen) {
291 DH_free(dh);
292 return (DST_R_INVALIDPUBLICKEY);
294 if (plen == 1 || plen == 2) {
295 if (plen == 1)
296 special = *r.base++;
297 else
298 special = uint16_fromregion(&r);
299 switch (special) {
300 case 1:
301 dh->p = &bn768;
302 break;
303 case 2:
304 dh->p = &bn1024;
305 break;
306 default:
307 DH_free(dh);
308 return (DST_R_INVALIDPUBLICKEY);
311 else {
312 dh->p = BN_bin2bn(r.base, plen, NULL);
313 r.base += plen;
317 * Read the generator length. This should be 0 if the prime was
318 * special, but it might not be. If it's 0 and the prime is not
319 * special, we have a problem.
321 if (r.length < 2) {
322 DH_free(dh);
323 return (DST_R_INVALIDPUBLICKEY);
325 glen = uint16_fromregion(&r);
326 if (r.length < glen) {
327 DH_free(dh);
328 return (DST_R_INVALIDPUBLICKEY);
330 if (special != 0) {
331 if (glen == 0)
332 dh->g = &bn2;
333 else {
334 dh->g = BN_bin2bn(r.base, glen, NULL);
335 if (BN_cmp(dh->g, &bn2) == 0) {
336 BN_free(dh->g);
337 dh->g = &bn2;
339 else {
340 DH_free(dh);
341 return (DST_R_INVALIDPUBLICKEY);
345 else {
346 if (glen == 0) {
347 DH_free(dh);
348 return (DST_R_INVALIDPUBLICKEY);
350 dh->g = BN_bin2bn(r.base, glen, NULL);
352 r.base += glen;
354 if (r.length < 2) {
355 DH_free(dh);
356 return (DST_R_INVALIDPUBLICKEY);
358 publen = uint16_fromregion(&r);
359 if (r.length < publen) {
360 DH_free(dh);
361 return (DST_R_INVALIDPUBLICKEY);
363 dh->pub_key = BN_bin2bn(r.base, publen, NULL);
364 r.base += publen;
366 key->key_size = BN_num_bits(dh->p);
368 isc_buffer_forward(data, plen + glen + publen + 6);
370 key->opaque = (void *) dh;
372 return (ISC_R_SUCCESS);
375 static isc_result_t
376 openssldh_tofile(const dst_key_t *key, const char *directory) {
377 int i;
378 DH *dh;
379 dst_private_t priv;
380 unsigned char *bufs[4];
381 isc_result_t result;
383 if (key->opaque == NULL)
384 return (DST_R_NULLKEY);
386 dh = (DH *) key->opaque;
388 for (i = 0; i < 4; i++) {
389 bufs[i] = isc_mem_get(key->mctx, BN_num_bytes(dh->p));
390 if (bufs[i] == NULL) {
391 result = ISC_R_NOMEMORY;
392 goto fail;
396 i = 0;
398 priv.elements[i].tag = TAG_DH_PRIME;
399 priv.elements[i].length = BN_num_bytes(dh->p);
400 BN_bn2bin(dh->p, bufs[i]);
401 priv.elements[i].data = bufs[i];
402 i++;
404 priv.elements[i].tag = TAG_DH_GENERATOR;
405 priv.elements[i].length = BN_num_bytes(dh->g);
406 BN_bn2bin(dh->g, bufs[i]);
407 priv.elements[i].data = bufs[i];
408 i++;
410 priv.elements[i].tag = TAG_DH_PRIVATE;
411 priv.elements[i].length = BN_num_bytes(dh->priv_key);
412 BN_bn2bin(dh->priv_key, bufs[i]);
413 priv.elements[i].data = bufs[i];
414 i++;
416 priv.elements[i].tag = TAG_DH_PUBLIC;
417 priv.elements[i].length = BN_num_bytes(dh->pub_key);
418 BN_bn2bin(dh->pub_key, bufs[i]);
419 priv.elements[i].data = bufs[i];
420 i++;
422 priv.nelements = i;
423 result = dst__privstruct_writefile(key, &priv, directory);
424 fail:
425 for (i = 0; i < 4; i++) {
426 if (bufs[i] == NULL)
427 break;
428 isc_mem_put(key->mctx, bufs[i], BN_num_bytes(dh->p));
430 return (result);
433 static isc_result_t
434 openssldh_fromfile(dst_key_t *key, const char *filename) {
435 dst_private_t priv;
436 isc_result_t ret;
437 int i;
438 DH *dh = NULL;
439 isc_mem_t *mctx;
440 #define DST_RET(a) {ret = a; goto err;}
442 mctx = key->mctx;
444 /* read private key file */
445 ret = dst__privstruct_parsefile(key, filename, mctx, &priv);
446 if (ret != ISC_R_SUCCESS)
447 return (ret);
449 dh = DH_new();
450 if (dh == NULL)
451 DST_RET(ISC_R_NOMEMORY);
452 dh->flags &= ~DH_FLAG_CACHE_MONT_P;
453 key->opaque = dh;
455 for (i = 0; i < priv.nelements; i++) {
456 BIGNUM *bn;
457 bn = BN_bin2bn(priv.elements[i].data,
458 priv.elements[i].length, NULL);
459 if (bn == NULL)
460 DST_RET(ISC_R_NOMEMORY);
462 switch (priv.elements[i].tag) {
463 case TAG_DH_PRIME:
464 dh->p = bn;
465 break;
466 case TAG_DH_GENERATOR:
467 dh->g = bn;
468 break;
469 case TAG_DH_PRIVATE:
470 dh->priv_key = bn;
471 break;
472 case TAG_DH_PUBLIC:
473 dh->pub_key = bn;
474 break;
477 dst__privstruct_free(&priv, mctx);
479 key->key_size = BN_num_bits(dh->p);
481 if ((key->key_size == 768 || key->key_size == 1024) &&
482 BN_cmp(dh->g, &bn2) == 0)
484 if (key->key_size == 768 && BN_cmp(dh->p, &bn768) == 0) {
485 BN_free(dh->p);
486 BN_free(dh->g);
487 dh->p = &bn768;
488 dh->g = &bn2;
489 } else if (key->key_size == 1024 &&
490 BN_cmp(dh->p, &bn1024) == 0) {
491 BN_free(dh->p);
492 BN_free(dh->g);
493 dh->p = &bn1024;
494 dh->g = &bn2;
498 return (ISC_R_SUCCESS);
500 err:
501 openssldh_destroy(key);
502 dst__privstruct_free(&priv, mctx);
503 memset(&priv, 0, sizeof(priv));
504 return (ret);
507 static void
508 BN_fromhex(BIGNUM *b, const char *str) {
509 static const char hexdigits[] = "0123456789abcdef";
510 unsigned char data[512];
511 unsigned int i;
512 BIGNUM *out;
514 RUNTIME_CHECK(strlen(str) < 1024U && strlen(str) % 2 == 0U);
515 for (i = 0; i < strlen(str); i += 2) {
516 char *s;
517 unsigned int high, low;
519 s = strchr(hexdigits, tolower((unsigned char)str[i]));
520 RUNTIME_CHECK(s != NULL);
521 high = s - hexdigits;
523 s = strchr(hexdigits, tolower((unsigned char)str[i + 1]));
524 RUNTIME_CHECK(s != NULL);
525 low = s - hexdigits;
527 data[i/2] = (unsigned char)((high << 4) + low);
529 out = BN_bin2bn(data, strlen(str)/2, b);
530 RUNTIME_CHECK(out != NULL);
533 static dst_func_t openssldh_functions = {
534 NULL, /* createctx */
535 NULL, /* destroyctx */
536 NULL, /* adddata */
537 NULL, /* openssldh_sign */
538 NULL, /* openssldh_verify */
539 openssldh_computesecret,
540 openssldh_compare,
541 openssldh_paramcompare,
542 openssldh_generate,
543 openssldh_isprivate,
544 openssldh_issymmetric,
545 openssldh_destroy,
546 openssldh_todns,
547 openssldh_fromdns,
548 openssldh_tofile,
549 openssldh_fromfile,
552 isc_result_t
553 dst__openssldh_init(dst_func_t **funcp) {
554 REQUIRE(funcp != NULL && *funcp == NULL);
555 BN_init(&bn2);
556 BN_init(&bn768);
557 BN_init(&bn1024);
558 BN_set_word(&bn2, 2);
559 BN_fromhex(&bn768, PRIME768);
560 BN_fromhex(&bn1024, PRIME1024);
561 *funcp = &openssldh_functions;
562 return (ISC_R_SUCCESS);
565 void
566 dst__openssldh_destroy(void) {
567 BN_free(&bn2);
568 BN_free(&bn768);
569 BN_free(&bn1024);
572 #endif /* OPENSSL */