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