Patrick Welche <prlw1@cam.ac.uk>
[netbsd-mini2440.git] / external / bsd / bind / dist / lib / dns / openssldh_link.c
blob12db2e5562a9e8ecaeaebe115cac80a148b6ef35
1 /* $NetBSD$ */
3 /*
4 * Portions Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC")
5 * Portions Copyright (C) 1999-2002 Internet Software Consortium.
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS
12 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
13 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE
14 * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
17 * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 * Portions Copyright (C) 1995-2000 by Network Associates, Inc.
21 * Permission to use, copy, modify, and/or distribute this software for any
22 * purpose with or without fee is hereby granted, provided that the above
23 * copyright notice and this permission notice appear in all copies.
25 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS
26 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
27 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE
28 * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
29 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
30 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
31 * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
35 * Principal Author: Brian Wellington
36 * Id: openssldh_link.c,v 1.18 2009/10/30 05:08:23 marka Exp
39 #ifdef OPENSSL
41 #include <config.h>
43 #include <ctype.h>
45 #include <isc/mem.h>
46 #include <isc/string.h>
47 #include <isc/util.h>
49 #include <dst/result.h>
51 #include "dst_internal.h"
52 #include "dst_openssl.h"
53 #include "dst_parse.h"
55 #define PRIME768 "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088" \
56 "A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25" \
57 "F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A63A3620FFFFFFFFFFFFFFFF"
59 #define PRIME1024 "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E08" \
60 "8A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF2" \
61 "5F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406" \
62 "B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF"
64 #define PRIME1536 "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" \
65 "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" \
66 "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" \
67 "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" \
68 "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" \
69 "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" \
70 "83655D23DCA3AD961C62F356208552BB9ED529077096966D" \
71 "670C354E4ABC9804F1746C08CA237327FFFFFFFFFFFFFFFF"
74 static isc_result_t openssldh_todns(const dst_key_t *key, isc_buffer_t *data);
76 static BIGNUM bn2, bn768, bn1024, bn1536;
78 static isc_result_t
79 openssldh_computesecret(const dst_key_t *pub, const dst_key_t *priv,
80 isc_buffer_t *secret)
82 DH *dhpub, *dhpriv;
83 int ret;
84 isc_region_t r;
85 unsigned int len;
87 REQUIRE(pub->keydata.dh != NULL);
88 REQUIRE(priv->keydata.dh != NULL);
90 dhpub = pub->keydata.dh;
91 dhpriv = priv->keydata.dh;
93 len = DH_size(dhpriv);
94 isc_buffer_availableregion(secret, &r);
95 if (r.length < len)
96 return (ISC_R_NOSPACE);
97 ret = DH_compute_key(r.base, dhpub->pub_key, dhpriv);
98 if (ret == 0)
99 return (dst__openssl_toresult(DST_R_COMPUTESECRETFAILURE));
100 isc_buffer_add(secret, len);
101 return (ISC_R_SUCCESS);
104 static isc_boolean_t
105 openssldh_compare(const dst_key_t *key1, const dst_key_t *key2) {
106 int status;
107 DH *dh1, *dh2;
109 dh1 = key1->keydata.dh;
110 dh2 = key2->keydata.dh;
112 if (dh1 == NULL && dh2 == NULL)
113 return (ISC_TRUE);
114 else if (dh1 == NULL || dh2 == NULL)
115 return (ISC_FALSE);
117 status = BN_cmp(dh1->p, dh2->p) ||
118 BN_cmp(dh1->g, dh2->g) ||
119 BN_cmp(dh1->pub_key, dh2->pub_key);
121 if (status != 0)
122 return (ISC_FALSE);
124 if (dh1->priv_key != NULL || dh2->priv_key != NULL) {
125 if (dh1->priv_key == NULL || dh2->priv_key == NULL)
126 return (ISC_FALSE);
127 if (BN_cmp(dh1->priv_key, dh2->priv_key) != 0)
128 return (ISC_FALSE);
130 return (ISC_TRUE);
133 static isc_boolean_t
134 openssldh_paramcompare(const dst_key_t *key1, const dst_key_t *key2) {
135 int status;
136 DH *dh1, *dh2;
138 dh1 = key1->keydata.dh;
139 dh2 = key2->keydata.dh;
141 if (dh1 == NULL && dh2 == NULL)
142 return (ISC_TRUE);
143 else if (dh1 == NULL || dh2 == NULL)
144 return (ISC_FALSE);
146 status = BN_cmp(dh1->p, dh2->p) ||
147 BN_cmp(dh1->g, dh2->g);
149 if (status != 0)
150 return (ISC_FALSE);
151 return (ISC_TRUE);
154 #if OPENSSL_VERSION_NUMBER > 0x00908000L
155 static int
156 progress_cb(int p, int n, BN_GENCB *cb)
158 union {
159 void *dptr;
160 void (*fptr)(int);
161 } u;
163 UNUSED(n);
165 u.dptr = cb->arg;
166 if (u.fptr != NULL)
167 u.fptr(p);
168 return (1);
170 #endif
172 static isc_result_t
173 openssldh_generate(dst_key_t *key, int generator, void (*callback)(int)) {
174 DH *dh = NULL;
175 #if OPENSSL_VERSION_NUMBER > 0x00908000L
176 BN_GENCB cb;
177 union {
178 void *dptr;
179 void (*fptr)(int);
180 } u;
181 #else
183 UNUSED(callback);
184 #endif
186 if (generator == 0) {
187 if (key->key_size == 768 ||
188 key->key_size == 1024 ||
189 key->key_size == 1536)
191 dh = DH_new();
192 if (dh == NULL)
193 return (dst__openssl_toresult(ISC_R_NOMEMORY));
194 if (key->key_size == 768)
195 dh->p = &bn768;
196 else if (key->key_size == 1024)
197 dh->p = &bn1024;
198 else
199 dh->p = &bn1536;
200 dh->g = &bn2;
201 } else
202 generator = 2;
205 if (generator != 0) {
206 #if OPENSSL_VERSION_NUMBER > 0x00908000L
207 dh = DH_new();
208 if (dh == NULL)
209 return (dst__openssl_toresult(DST_R_OPENSSLFAILURE));
211 if (callback == NULL) {
212 BN_GENCB_set_old(&cb, NULL, NULL);
213 } else {
214 u.fptr = callback;
215 BN_GENCB_set(&cb, &progress_cb, u.dptr);
218 if (!DH_generate_parameters_ex(dh, key->key_size, generator,
219 &cb)) {
220 DH_free(dh);
221 return (dst__openssl_toresult(DST_R_OPENSSLFAILURE));
223 #else
224 dh = DH_generate_parameters(key->key_size, generator,
225 NULL, NULL);
226 #endif
229 if (dh == NULL)
230 return (dst__openssl_toresult(DST_R_OPENSSLFAILURE));
232 if (DH_generate_key(dh) == 0) {
233 DH_free(dh);
234 return (dst__openssl_toresult(DST_R_OPENSSLFAILURE));
236 dh->flags &= ~DH_FLAG_CACHE_MONT_P;
238 key->keydata.dh = dh;
240 return (ISC_R_SUCCESS);
243 static isc_boolean_t
244 openssldh_isprivate(const dst_key_t *key) {
245 DH *dh = key->keydata.dh;
246 return (ISC_TF(dh != NULL && dh->priv_key != NULL));
249 static void
250 openssldh_destroy(dst_key_t *key) {
251 DH *dh = key->keydata.dh;
253 if (dh == NULL)
254 return;
256 if (dh->p == &bn768 || dh->p == &bn1024 || dh->p == &bn1536)
257 dh->p = NULL;
258 if (dh->g == &bn2)
259 dh->g = NULL;
260 DH_free(dh);
261 key->keydata.dh = NULL;
264 static void
265 uint16_toregion(isc_uint16_t val, isc_region_t *region) {
266 *region->base++ = (val & 0xff00) >> 8;
267 *region->base++ = (val & 0x00ff);
270 static isc_uint16_t
271 uint16_fromregion(isc_region_t *region) {
272 isc_uint16_t val;
273 unsigned char *cp = region->base;
275 val = ((unsigned int)(cp[0])) << 8;
276 val |= ((unsigned int)(cp[1]));
278 region->base += 2;
279 return (val);
282 static isc_result_t
283 openssldh_todns(const dst_key_t *key, isc_buffer_t *data) {
284 DH *dh;
285 isc_region_t r;
286 isc_uint16_t dnslen, plen, glen, publen;
288 REQUIRE(key->keydata.dh != NULL);
290 dh = key->keydata.dh;
292 isc_buffer_availableregion(data, &r);
294 if (dh->g == &bn2 &&
295 (dh->p == &bn768 || dh->p == &bn1024 || dh->p == &bn1536)) {
296 plen = 1;
297 glen = 0;
299 else {
300 plen = BN_num_bytes(dh->p);
301 glen = BN_num_bytes(dh->g);
303 publen = BN_num_bytes(dh->pub_key);
304 dnslen = plen + glen + publen + 6;
305 if (r.length < (unsigned int) dnslen)
306 return (ISC_R_NOSPACE);
308 uint16_toregion(plen, &r);
309 if (plen == 1) {
310 if (dh->p == &bn768)
311 *r.base = 1;
312 else if (dh->p == &bn1024)
313 *r.base = 2;
314 else
315 *r.base = 3;
317 else
318 BN_bn2bin(dh->p, r.base);
319 r.base += plen;
321 uint16_toregion(glen, &r);
322 if (glen > 0)
323 BN_bn2bin(dh->g, r.base);
324 r.base += glen;
326 uint16_toregion(publen, &r);
327 BN_bn2bin(dh->pub_key, r.base);
328 r.base += publen;
330 isc_buffer_add(data, dnslen);
332 return (ISC_R_SUCCESS);
335 static isc_result_t
336 openssldh_fromdns(dst_key_t *key, isc_buffer_t *data) {
337 DH *dh;
338 isc_region_t r;
339 isc_uint16_t plen, glen, publen;
340 int special = 0;
342 isc_buffer_remainingregion(data, &r);
343 if (r.length == 0)
344 return (ISC_R_SUCCESS);
346 dh = DH_new();
347 if (dh == NULL)
348 return (dst__openssl_toresult(ISC_R_NOMEMORY));
349 dh->flags &= ~DH_FLAG_CACHE_MONT_P;
352 * Read the prime length. 1 & 2 are table entries, > 16 means a
353 * prime follows, otherwise an error.
355 if (r.length < 2) {
356 DH_free(dh);
357 return (DST_R_INVALIDPUBLICKEY);
359 plen = uint16_fromregion(&r);
360 if (plen < 16 && plen != 1 && plen != 2) {
361 DH_free(dh);
362 return (DST_R_INVALIDPUBLICKEY);
364 if (r.length < plen) {
365 DH_free(dh);
366 return (DST_R_INVALIDPUBLICKEY);
368 if (plen == 1 || plen == 2) {
369 if (plen == 1)
370 special = *r.base++;
371 else
372 special = uint16_fromregion(&r);
373 switch (special) {
374 case 1:
375 dh->p = &bn768;
376 break;
377 case 2:
378 dh->p = &bn1024;
379 break;
380 case 3:
381 dh->p = &bn1536;
382 break;
383 default:
384 DH_free(dh);
385 return (DST_R_INVALIDPUBLICKEY);
388 else {
389 dh->p = BN_bin2bn(r.base, plen, NULL);
390 r.base += plen;
394 * Read the generator length. This should be 0 if the prime was
395 * special, but it might not be. If it's 0 and the prime is not
396 * special, we have a problem.
398 if (r.length < 2) {
399 DH_free(dh);
400 return (DST_R_INVALIDPUBLICKEY);
402 glen = uint16_fromregion(&r);
403 if (r.length < glen) {
404 DH_free(dh);
405 return (DST_R_INVALIDPUBLICKEY);
407 if (special != 0) {
408 if (glen == 0)
409 dh->g = &bn2;
410 else {
411 dh->g = BN_bin2bn(r.base, glen, NULL);
412 if (BN_cmp(dh->g, &bn2) == 0) {
413 BN_free(dh->g);
414 dh->g = &bn2;
416 else {
417 DH_free(dh);
418 return (DST_R_INVALIDPUBLICKEY);
422 else {
423 if (glen == 0) {
424 DH_free(dh);
425 return (DST_R_INVALIDPUBLICKEY);
427 dh->g = BN_bin2bn(r.base, glen, NULL);
429 r.base += glen;
431 if (r.length < 2) {
432 DH_free(dh);
433 return (DST_R_INVALIDPUBLICKEY);
435 publen = uint16_fromregion(&r);
436 if (r.length < publen) {
437 DH_free(dh);
438 return (DST_R_INVALIDPUBLICKEY);
440 dh->pub_key = BN_bin2bn(r.base, publen, NULL);
441 r.base += publen;
443 key->key_size = BN_num_bits(dh->p);
445 isc_buffer_forward(data, plen + glen + publen + 6);
447 key->keydata.dh = dh;
449 return (ISC_R_SUCCESS);
452 static isc_result_t
453 openssldh_tofile(const dst_key_t *key, const char *directory) {
454 int i;
455 DH *dh;
456 dst_private_t priv;
457 unsigned char *bufs[4];
458 isc_result_t result;
460 if (key->keydata.dh == NULL)
461 return (DST_R_NULLKEY);
463 dh = key->keydata.dh;
465 for (i = 0; i < 4; i++) {
466 bufs[i] = isc_mem_get(key->mctx, BN_num_bytes(dh->p));
467 if (bufs[i] == NULL) {
468 result = ISC_R_NOMEMORY;
469 goto fail;
473 i = 0;
475 priv.elements[i].tag = TAG_DH_PRIME;
476 priv.elements[i].length = BN_num_bytes(dh->p);
477 BN_bn2bin(dh->p, bufs[i]);
478 priv.elements[i].data = bufs[i];
479 i++;
481 priv.elements[i].tag = TAG_DH_GENERATOR;
482 priv.elements[i].length = BN_num_bytes(dh->g);
483 BN_bn2bin(dh->g, bufs[i]);
484 priv.elements[i].data = bufs[i];
485 i++;
487 priv.elements[i].tag = TAG_DH_PRIVATE;
488 priv.elements[i].length = BN_num_bytes(dh->priv_key);
489 BN_bn2bin(dh->priv_key, bufs[i]);
490 priv.elements[i].data = bufs[i];
491 i++;
493 priv.elements[i].tag = TAG_DH_PUBLIC;
494 priv.elements[i].length = BN_num_bytes(dh->pub_key);
495 BN_bn2bin(dh->pub_key, bufs[i]);
496 priv.elements[i].data = bufs[i];
497 i++;
499 priv.nelements = i;
500 result = dst__privstruct_writefile(key, &priv, directory);
501 fail:
502 for (i = 0; i < 4; i++) {
503 if (bufs[i] == NULL)
504 break;
505 isc_mem_put(key->mctx, bufs[i], BN_num_bytes(dh->p));
507 return (result);
510 static isc_result_t
511 openssldh_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) {
512 dst_private_t priv;
513 isc_result_t ret;
514 int i;
515 DH *dh = NULL;
516 isc_mem_t *mctx;
517 #define DST_RET(a) {ret = a; goto err;}
519 UNUSED(pub);
520 mctx = key->mctx;
522 /* read private key file */
523 ret = dst__privstruct_parse(key, DST_ALG_DH, lexer, mctx, &priv);
524 if (ret != ISC_R_SUCCESS)
525 return (ret);
527 dh = DH_new();
528 if (dh == NULL)
529 DST_RET(ISC_R_NOMEMORY);
530 dh->flags &= ~DH_FLAG_CACHE_MONT_P;
531 key->keydata.dh = dh;
533 for (i = 0; i < priv.nelements; i++) {
534 BIGNUM *bn;
535 bn = BN_bin2bn(priv.elements[i].data,
536 priv.elements[i].length, NULL);
537 if (bn == NULL)
538 DST_RET(ISC_R_NOMEMORY);
540 switch (priv.elements[i].tag) {
541 case TAG_DH_PRIME:
542 dh->p = bn;
543 break;
544 case TAG_DH_GENERATOR:
545 dh->g = bn;
546 break;
547 case TAG_DH_PRIVATE:
548 dh->priv_key = bn;
549 break;
550 case TAG_DH_PUBLIC:
551 dh->pub_key = bn;
552 break;
555 dst__privstruct_free(&priv, mctx);
557 key->key_size = BN_num_bits(dh->p);
559 if ((key->key_size == 768 ||
560 key->key_size == 1024 ||
561 key->key_size == 1536) &&
562 BN_cmp(dh->g, &bn2) == 0)
564 if (key->key_size == 768 && BN_cmp(dh->p, &bn768) == 0) {
565 BN_free(dh->p);
566 BN_free(dh->g);
567 dh->p = &bn768;
568 dh->g = &bn2;
569 } else if (key->key_size == 1024 &&
570 BN_cmp(dh->p, &bn1024) == 0) {
571 BN_free(dh->p);
572 BN_free(dh->g);
573 dh->p = &bn1024;
574 dh->g = &bn2;
575 } else if (key->key_size == 1536 &&
576 BN_cmp(dh->p, &bn1536) == 0) {
577 BN_free(dh->p);
578 BN_free(dh->g);
579 dh->p = &bn1536;
580 dh->g = &bn2;
584 return (ISC_R_SUCCESS);
586 err:
587 openssldh_destroy(key);
588 dst__privstruct_free(&priv, mctx);
589 memset(&priv, 0, sizeof(priv));
590 return (ret);
593 static void
594 BN_fromhex(BIGNUM *b, const char *str) {
595 static const char hexdigits[] = "0123456789abcdef";
596 unsigned char data[512];
597 unsigned int i;
598 BIGNUM *out;
600 RUNTIME_CHECK(strlen(str) < 1024U && strlen(str) % 2 == 0U);
601 for (i = 0; i < strlen(str); i += 2) {
602 char *s;
603 unsigned int high, low;
605 s = strchr(hexdigits, tolower((unsigned char)str[i]));
606 RUNTIME_CHECK(s != NULL);
607 high = s - hexdigits;
609 s = strchr(hexdigits, tolower((unsigned char)str[i + 1]));
610 RUNTIME_CHECK(s != NULL);
611 low = s - hexdigits;
613 data[i/2] = (unsigned char)((high << 4) + low);
615 out = BN_bin2bn(data, strlen(str)/2, b);
616 RUNTIME_CHECK(out != NULL);
619 static void
620 openssldh_cleanup(void) {
621 BN_free(&bn2);
622 BN_free(&bn768);
623 BN_free(&bn1024);
624 BN_free(&bn1536);
627 static dst_func_t openssldh_functions = {
628 NULL, /*%< createctx */
629 NULL, /*%< destroyctx */
630 NULL, /*%< adddata */
631 NULL, /*%< openssldh_sign */
632 NULL, /*%< openssldh_verify */
633 openssldh_computesecret,
634 openssldh_compare,
635 openssldh_paramcompare,
636 openssldh_generate,
637 openssldh_isprivate,
638 openssldh_destroy,
639 openssldh_todns,
640 openssldh_fromdns,
641 openssldh_tofile,
642 openssldh_parse,
643 openssldh_cleanup,
644 NULL, /*%< fromlabel */
647 isc_result_t
648 dst__openssldh_init(dst_func_t **funcp) {
649 REQUIRE(funcp != NULL);
650 if (*funcp == NULL) {
651 BN_init(&bn2);
652 BN_init(&bn768);
653 BN_init(&bn1024);
654 BN_init(&bn1536);
655 BN_set_word(&bn2, 2);
656 BN_fromhex(&bn768, PRIME768);
657 BN_fromhex(&bn1024, PRIME1024);
658 BN_fromhex(&bn1536, PRIME1536);
659 *funcp = &openssldh_functions;
661 return (ISC_R_SUCCESS);
664 #else /* OPENSSL */
666 #include <isc/util.h>
668 EMPTY_TRANSLATION_UNIT
670 #endif /* OPENSSL */
671 /*! \file */