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