openssldh_link.c revision 287410
1/* 2 * Portions Copyright (C) 2004-2009, 2011-2013 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/* 33 * Principal Author: Brian Wellington 34 * $Id: openssldh_link.c,v 1.20 2011/01/11 23:47:13 tbox Exp $ 35 */ 36 37#ifdef OPENSSL 38 39#include <config.h> 40 41#include <ctype.h> 42 43#include <isc/mem.h> 44#include <isc/string.h> 45#include <isc/util.h> 46 47#include <dst/result.h> 48 49#include "dst_internal.h" 50#include "dst_openssl.h" 51#include "dst_parse.h" 52 53#define PRIME768 "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088" \ 54 "A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25" \ 55 "F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A63A3620FFFFFFFFFFFFFFFF" 56 57#define PRIME1024 "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E08" \ 58 "8A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF2" \ 59 "5F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406" \ 60 "B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF" 61 62#define PRIME1536 "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" \ 63 "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" \ 64 "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" \ 65 "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" \ 66 "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" \ 67 "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" \ 68 "83655D23DCA3AD961C62F356208552BB9ED529077096966D" \ 69 "670C354E4ABC9804F1746C08CA237327FFFFFFFFFFFFFFFF" 70 71 72static isc_result_t openssldh_todns(const dst_key_t *key, isc_buffer_t *data); 73 74static BIGNUM bn2, bn768, bn1024, bn1536; 75 76static isc_result_t 77openssldh_computesecret(const dst_key_t *pub, const dst_key_t *priv, 78 isc_buffer_t *secret) 79{ 80 DH *dhpub, *dhpriv; 81 int ret; 82 isc_region_t r; 83 unsigned int len; 84 85 REQUIRE(pub->keydata.dh != NULL); 86 REQUIRE(priv->keydata.dh != NULL); 87 88 dhpub = pub->keydata.dh; 89 dhpriv = priv->keydata.dh; 90 91 len = DH_size(dhpriv); 92 isc_buffer_availableregion(secret, &r); 93 if (r.length < len) 94 return (ISC_R_NOSPACE); 95 ret = DH_compute_key(r.base, dhpub->pub_key, dhpriv); 96 if (ret == 0) 97 return (dst__openssl_toresult2("DH_compute_key", 98 DST_R_COMPUTESECRETFAILURE)); 99 isc_buffer_add(secret, len); 100 return (ISC_R_SUCCESS); 101} 102 103static isc_boolean_t 104openssldh_compare(const dst_key_t *key1, const dst_key_t *key2) { 105 int status; 106 DH *dh1, *dh2; 107 108 dh1 = key1->keydata.dh; 109 dh2 = key2->keydata.dh; 110 111 if (dh1 == NULL && dh2 == NULL) 112 return (ISC_TRUE); 113 else if (dh1 == NULL || dh2 == NULL) 114 return (ISC_FALSE); 115 116 status = BN_cmp(dh1->p, dh2->p) || 117 BN_cmp(dh1->g, dh2->g) || 118 BN_cmp(dh1->pub_key, dh2->pub_key); 119 120 if (status != 0) 121 return (ISC_FALSE); 122 123 if (dh1->priv_key != NULL || dh2->priv_key != NULL) { 124 if (dh1->priv_key == NULL || dh2->priv_key == NULL) 125 return (ISC_FALSE); 126 if (BN_cmp(dh1->priv_key, dh2->priv_key) != 0) 127 return (ISC_FALSE); 128 } 129 return (ISC_TRUE); 130} 131 132static isc_boolean_t 133openssldh_paramcompare(const dst_key_t *key1, const dst_key_t *key2) { 134 int status; 135 DH *dh1, *dh2; 136 137 dh1 = key1->keydata.dh; 138 dh2 = key2->keydata.dh; 139 140 if (dh1 == NULL && dh2 == NULL) 141 return (ISC_TRUE); 142 else if (dh1 == NULL || dh2 == NULL) 143 return (ISC_FALSE); 144 145 status = BN_cmp(dh1->p, dh2->p) || 146 BN_cmp(dh1->g, dh2->g); 147 148 if (status != 0) 149 return (ISC_FALSE); 150 return (ISC_TRUE); 151} 152 153#if OPENSSL_VERSION_NUMBER > 0x00908000L 154static int 155progress_cb(int p, int n, BN_GENCB *cb) 156{ 157 union { 158 void *dptr; 159 void (*fptr)(int); 160 } u; 161 162 UNUSED(n); 163 164 u.dptr = cb->arg; 165 if (u.fptr != NULL) 166 u.fptr(p); 167 return (1); 168} 169#endif 170 171static isc_result_t 172openssldh_generate(dst_key_t *key, int generator, void (*callback)(int)) { 173 DH *dh = NULL; 174#if OPENSSL_VERSION_NUMBER > 0x00908000L 175 BN_GENCB cb; 176 union { 177 void *dptr; 178 void (*fptr)(int); 179 } u; 180#else 181 182 UNUSED(callback); 183#endif 184 185 if (generator == 0) { 186 if (key->key_size == 768 || 187 key->key_size == 1024 || 188 key->key_size == 1536) 189 { 190 dh = DH_new(); 191 if (dh == NULL) 192 return (dst__openssl_toresult(ISC_R_NOMEMORY)); 193 if (key->key_size == 768) 194 dh->p = &bn768; 195 else if (key->key_size == 1024) 196 dh->p = &bn1024; 197 else 198 dh->p = &bn1536; 199 dh->g = &bn2; 200 } else 201 generator = 2; 202 } 203 204 if (generator != 0) { 205#if OPENSSL_VERSION_NUMBER > 0x00908000L 206 dh = DH_new(); 207 if (dh == NULL) 208 return (dst__openssl_toresult(ISC_R_NOMEMORY)); 209 210 if (callback == NULL) { 211 BN_GENCB_set_old(&cb, NULL, NULL); 212 } else { 213 u.fptr = callback; 214 BN_GENCB_set(&cb, &progress_cb, u.dptr); 215 } 216 217 if (!DH_generate_parameters_ex(dh, key->key_size, generator, 218 &cb)) { 219 DH_free(dh); 220 return (dst__openssl_toresult2( 221 "DH_generate_parameters_ex", 222 DST_R_OPENSSLFAILURE)); 223 } 224#else 225 dh = DH_generate_parameters(key->key_size, generator, 226 NULL, NULL); 227#endif 228 } 229 230 if (dh == NULL) 231 return (dst__openssl_toresult2("DH_generate_parameters", 232 DST_R_OPENSSLFAILURE)); 233 234 if (DH_generate_key(dh) == 0) { 235 DH_free(dh); 236 return (dst__openssl_toresult2("DH_generate_key", 237 DST_R_OPENSSLFAILURE)); 238 } 239 dh->flags &= ~DH_FLAG_CACHE_MONT_P; 240 241 key->keydata.dh = dh; 242 243 return (ISC_R_SUCCESS); 244} 245 246static isc_boolean_t 247openssldh_isprivate(const dst_key_t *key) { 248 DH *dh = key->keydata.dh; 249 return (ISC_TF(dh != NULL && dh->priv_key != NULL)); 250} 251 252static void 253openssldh_destroy(dst_key_t *key) { 254 DH *dh = key->keydata.dh; 255 256 if (dh == NULL) 257 return; 258 259 if (dh->p == &bn768 || dh->p == &bn1024 || dh->p == &bn1536) 260 dh->p = NULL; 261 if (dh->g == &bn2) 262 dh->g = NULL; 263 DH_free(dh); 264 key->keydata.dh = NULL; 265} 266 267static void 268uint16_toregion(isc_uint16_t val, isc_region_t *region) { 269 *region->base = (val & 0xff00) >> 8; 270 isc_region_consume(region, 1); 271 *region->base = (val & 0x00ff); 272 isc_region_consume(region, 1); 273} 274 275static isc_uint16_t 276uint16_fromregion(isc_region_t *region) { 277 isc_uint16_t val; 278 unsigned char *cp = region->base; 279 280 val = ((unsigned int)(cp[0])) << 8; 281 val |= ((unsigned int)(cp[1])); 282 283 isc_region_consume(region, 2); 284 285 return (val); 286} 287 288static isc_result_t 289openssldh_todns(const dst_key_t *key, isc_buffer_t *data) { 290 DH *dh; 291 isc_region_t r; 292 isc_uint16_t dnslen, plen, glen, publen; 293 294 REQUIRE(key->keydata.dh != NULL); 295 296 dh = key->keydata.dh; 297 298 isc_buffer_availableregion(data, &r); 299 300 if (dh->g == &bn2 && 301 (dh->p == &bn768 || dh->p == &bn1024 || dh->p == &bn1536)) { 302 plen = 1; 303 glen = 0; 304 } 305 else { 306 plen = BN_num_bytes(dh->p); 307 glen = BN_num_bytes(dh->g); 308 } 309 publen = BN_num_bytes(dh->pub_key); 310 dnslen = plen + glen + publen + 6; 311 if (r.length < (unsigned int) dnslen) 312 return (ISC_R_NOSPACE); 313 314 uint16_toregion(plen, &r); 315 if (plen == 1) { 316 if (dh->p == &bn768) 317 *r.base = 1; 318 else if (dh->p == &bn1024) 319 *r.base = 2; 320 else 321 *r.base = 3; 322 } 323 else 324 BN_bn2bin(dh->p, r.base); 325 isc_region_consume(&r, plen); 326 327 uint16_toregion(glen, &r); 328 if (glen > 0) 329 BN_bn2bin(dh->g, r.base); 330 isc_region_consume(&r, glen); 331 332 uint16_toregion(publen, &r); 333 BN_bn2bin(dh->pub_key, r.base); 334 isc_region_consume(&r, publen); 335 336 isc_buffer_add(data, dnslen); 337 338 return (ISC_R_SUCCESS); 339} 340 341static isc_result_t 342openssldh_fromdns(dst_key_t *key, isc_buffer_t *data) { 343 DH *dh; 344 isc_region_t r; 345 isc_uint16_t plen, glen, publen; 346 int special = 0; 347 348 isc_buffer_remainingregion(data, &r); 349 if (r.length == 0) 350 return (ISC_R_SUCCESS); 351 352 dh = DH_new(); 353 if (dh == NULL) 354 return (dst__openssl_toresult(ISC_R_NOMEMORY)); 355 dh->flags &= ~DH_FLAG_CACHE_MONT_P; 356 357 /* 358 * Read the prime length. 1 & 2 are table entries, > 16 means a 359 * prime follows, otherwise an error. 360 */ 361 if (r.length < 2) { 362 DH_free(dh); 363 return (DST_R_INVALIDPUBLICKEY); 364 } 365 plen = uint16_fromregion(&r); 366 if (plen < 16 && plen != 1 && plen != 2) { 367 DH_free(dh); 368 return (DST_R_INVALIDPUBLICKEY); 369 } 370 if (r.length < plen) { 371 DH_free(dh); 372 return (DST_R_INVALIDPUBLICKEY); 373 } 374 if (plen == 1 || plen == 2) { 375 if (plen == 1) { 376 special = *r.base; 377 isc_region_consume(&r, 1); 378 } else { 379 special = uint16_fromregion(&r); 380 } 381 switch (special) { 382 case 1: 383 dh->p = &bn768; 384 break; 385 case 2: 386 dh->p = &bn1024; 387 break; 388 case 3: 389 dh->p = &bn1536; 390 break; 391 default: 392 DH_free(dh); 393 return (DST_R_INVALIDPUBLICKEY); 394 } 395 } else { 396 dh->p = BN_bin2bn(r.base, plen, NULL); 397 isc_region_consume(&r, plen); 398 } 399 400 /* 401 * Read the generator length. This should be 0 if the prime was 402 * special, but it might not be. If it's 0 and the prime is not 403 * special, we have a problem. 404 */ 405 if (r.length < 2) { 406 DH_free(dh); 407 return (DST_R_INVALIDPUBLICKEY); 408 } 409 glen = uint16_fromregion(&r); 410 if (r.length < glen) { 411 DH_free(dh); 412 return (DST_R_INVALIDPUBLICKEY); 413 } 414 if (special != 0) { 415 if (glen == 0) 416 dh->g = &bn2; 417 else { 418 dh->g = BN_bin2bn(r.base, glen, NULL); 419 if (BN_cmp(dh->g, &bn2) == 0) { 420 BN_free(dh->g); 421 dh->g = &bn2; 422 } 423 else { 424 DH_free(dh); 425 return (DST_R_INVALIDPUBLICKEY); 426 } 427 } 428 } else { 429 if (glen == 0) { 430 DH_free(dh); 431 return (DST_R_INVALIDPUBLICKEY); 432 } 433 dh->g = BN_bin2bn(r.base, glen, NULL); 434 } 435 isc_region_consume(&r, glen); 436 437 if (r.length < 2) { 438 DH_free(dh); 439 return (DST_R_INVALIDPUBLICKEY); 440 } 441 publen = uint16_fromregion(&r); 442 if (r.length < publen) { 443 DH_free(dh); 444 return (DST_R_INVALIDPUBLICKEY); 445 } 446 dh->pub_key = BN_bin2bn(r.base, publen, NULL); 447 isc_region_consume(&r, publen); 448 449 key->key_size = BN_num_bits(dh->p); 450 451 isc_buffer_forward(data, plen + glen + publen + 6); 452 453 key->keydata.dh = dh; 454 455 return (ISC_R_SUCCESS); 456} 457 458static isc_result_t 459openssldh_tofile(const dst_key_t *key, const char *directory) { 460 int i; 461 DH *dh; 462 dst_private_t priv; 463 unsigned char *bufs[4]; 464 isc_result_t result; 465 466 if (key->keydata.dh == NULL) 467 return (DST_R_NULLKEY); 468 469 dh = key->keydata.dh; 470 471 memset(bufs, 0, sizeof(bufs)); 472 for (i = 0; i < 4; i++) { 473 bufs[i] = isc_mem_get(key->mctx, BN_num_bytes(dh->p)); 474 if (bufs[i] == NULL) { 475 result = ISC_R_NOMEMORY; 476 goto fail; 477 } 478 } 479 480 i = 0; 481 482 priv.elements[i].tag = TAG_DH_PRIME; 483 priv.elements[i].length = BN_num_bytes(dh->p); 484 BN_bn2bin(dh->p, bufs[i]); 485 priv.elements[i].data = bufs[i]; 486 i++; 487 488 priv.elements[i].tag = TAG_DH_GENERATOR; 489 priv.elements[i].length = BN_num_bytes(dh->g); 490 BN_bn2bin(dh->g, bufs[i]); 491 priv.elements[i].data = bufs[i]; 492 i++; 493 494 priv.elements[i].tag = TAG_DH_PRIVATE; 495 priv.elements[i].length = BN_num_bytes(dh->priv_key); 496 BN_bn2bin(dh->priv_key, bufs[i]); 497 priv.elements[i].data = bufs[i]; 498 i++; 499 500 priv.elements[i].tag = TAG_DH_PUBLIC; 501 priv.elements[i].length = BN_num_bytes(dh->pub_key); 502 BN_bn2bin(dh->pub_key, bufs[i]); 503 priv.elements[i].data = bufs[i]; 504 i++; 505 506 priv.nelements = i; 507 result = dst__privstruct_writefile(key, &priv, directory); 508 fail: 509 for (i = 0; i < 4; i++) { 510 if (bufs[i] == NULL) 511 break; 512 isc_mem_put(key->mctx, bufs[i], BN_num_bytes(dh->p)); 513 } 514 return (result); 515} 516 517static isc_result_t 518openssldh_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { 519 dst_private_t priv; 520 isc_result_t ret; 521 int i; 522 DH *dh = NULL; 523 isc_mem_t *mctx; 524#define DST_RET(a) {ret = a; goto err;} 525 526 UNUSED(pub); 527 mctx = key->mctx; 528 529 /* read private key file */ 530 ret = dst__privstruct_parse(key, DST_ALG_DH, lexer, mctx, &priv); 531 if (ret != ISC_R_SUCCESS) 532 return (ret); 533 534 dh = DH_new(); 535 if (dh == NULL) 536 DST_RET(ISC_R_NOMEMORY); 537 dh->flags &= ~DH_FLAG_CACHE_MONT_P; 538 key->keydata.dh = dh; 539 540 for (i = 0; i < priv.nelements; i++) { 541 BIGNUM *bn; 542 bn = BN_bin2bn(priv.elements[i].data, 543 priv.elements[i].length, NULL); 544 if (bn == NULL) 545 DST_RET(ISC_R_NOMEMORY); 546 547 switch (priv.elements[i].tag) { 548 case TAG_DH_PRIME: 549 dh->p = bn; 550 break; 551 case TAG_DH_GENERATOR: 552 dh->g = bn; 553 break; 554 case TAG_DH_PRIVATE: 555 dh->priv_key = bn; 556 break; 557 case TAG_DH_PUBLIC: 558 dh->pub_key = bn; 559 break; 560 } 561 } 562 dst__privstruct_free(&priv, mctx); 563 564 key->key_size = BN_num_bits(dh->p); 565 566 if ((key->key_size == 768 || 567 key->key_size == 1024 || 568 key->key_size == 1536) && 569 BN_cmp(dh->g, &bn2) == 0) 570 { 571 if (key->key_size == 768 && BN_cmp(dh->p, &bn768) == 0) { 572 BN_free(dh->p); 573 BN_free(dh->g); 574 dh->p = &bn768; 575 dh->g = &bn2; 576 } else if (key->key_size == 1024 && 577 BN_cmp(dh->p, &bn1024) == 0) { 578 BN_free(dh->p); 579 BN_free(dh->g); 580 dh->p = &bn1024; 581 dh->g = &bn2; 582 } else if (key->key_size == 1536 && 583 BN_cmp(dh->p, &bn1536) == 0) { 584 BN_free(dh->p); 585 BN_free(dh->g); 586 dh->p = &bn1536; 587 dh->g = &bn2; 588 } 589 } 590 591 return (ISC_R_SUCCESS); 592 593 err: 594 openssldh_destroy(key); 595 dst__privstruct_free(&priv, mctx); 596 memset(&priv, 0, sizeof(priv)); 597 return (ret); 598} 599 600static void 601BN_fromhex(BIGNUM *b, const char *str) { 602 static const char hexdigits[] = "0123456789abcdef"; 603 unsigned char data[512]; 604 unsigned int i; 605 BIGNUM *out; 606 607 RUNTIME_CHECK(strlen(str) < 1024U && strlen(str) % 2 == 0U); 608 for (i = 0; i < strlen(str); i += 2) { 609 char *s; 610 unsigned int high, low; 611 612 s = strchr(hexdigits, tolower((unsigned char)str[i])); 613 RUNTIME_CHECK(s != NULL); 614 high = (unsigned int)(s - hexdigits); 615 616 s = strchr(hexdigits, tolower((unsigned char)str[i + 1])); 617 RUNTIME_CHECK(s != NULL); 618 low = (unsigned int)(s - hexdigits); 619 620 data[i/2] = (unsigned char)((high << 4) + low); 621 } 622 out = BN_bin2bn(data, strlen(str)/2, b); 623 RUNTIME_CHECK(out != NULL); 624} 625 626static void 627openssldh_cleanup(void) { 628 BN_free(&bn2); 629 BN_free(&bn768); 630 BN_free(&bn1024); 631 BN_free(&bn1536); 632} 633 634static dst_func_t openssldh_functions = { 635 NULL, /*%< createctx */ 636 NULL, /*%< destroyctx */ 637 NULL, /*%< adddata */ 638 NULL, /*%< openssldh_sign */ 639 NULL, /*%< openssldh_verify */ 640 NULL, /*%< openssldh_verify2 */ 641 openssldh_computesecret, 642 openssldh_compare, 643 openssldh_paramcompare, 644 openssldh_generate, 645 openssldh_isprivate, 646 openssldh_destroy, 647 openssldh_todns, 648 openssldh_fromdns, 649 openssldh_tofile, 650 openssldh_parse, 651 openssldh_cleanup, 652 NULL, /*%< fromlabel */ 653 NULL, /*%< dump */ 654 NULL, /*%< restore */ 655}; 656 657isc_result_t 658dst__openssldh_init(dst_func_t **funcp) { 659 REQUIRE(funcp != NULL); 660 if (*funcp == NULL) { 661 BN_init(&bn2); 662 BN_init(&bn768); 663 BN_init(&bn1024); 664 BN_init(&bn1536); 665 BN_set_word(&bn2, 2); 666 BN_fromhex(&bn768, PRIME768); 667 BN_fromhex(&bn1024, PRIME1024); 668 BN_fromhex(&bn1536, PRIME1536); 669 *funcp = &openssldh_functions; 670 } 671 return (ISC_R_SUCCESS); 672} 673 674#else /* OPENSSL */ 675 676#include <isc/util.h> 677 678EMPTY_TRANSLATION_UNIT 679 680#endif /* OPENSSL */ 681/*! \file */ 682