1/* $NetBSD: opensslecdsa_link.c,v 1.2.2.2 2012/12/15 05:39:58 riz Exp $ */ 2 3/* 4 * Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC") 5 * 6 * Permission to use, copy, modify, and/or 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. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 11 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 12 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 13 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 14 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 15 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 16 * PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19/* Id */ 20 21#include <config.h> 22 23#ifdef HAVE_OPENSSL_ECDSA 24 25#if !defined(HAVE_EVP_SHA256) || !defined(HAVE_EVP_SHA384) 26#error "ECDSA without EVP for SHA2?" 27#endif 28 29#include <isc/entropy.h> 30#include <isc/mem.h> 31#include <isc/sha2.h> 32#include <isc/string.h> 33#include <isc/util.h> 34 35#include <dns/keyvalues.h> 36#include <dst/result.h> 37 38#include "dst_internal.h" 39#include "dst_openssl.h" 40#include "dst_parse.h" 41 42#include <openssl/err.h> 43#include <openssl/objects.h> 44#include <openssl/ecdsa.h> 45#include <openssl/bn.h> 46 47#ifndef NID_X9_62_prime256v1 48#error "P-256 group is not known (NID_X9_62_prime256v1)" 49#endif 50#ifndef NID_secp384r1 51#error "P-384 group is not known (NID_secp384r1)" 52#endif 53 54#define DST_RET(a) {ret = a; goto err;} 55 56static isc_result_t opensslecdsa_todns(const dst_key_t *key, 57 isc_buffer_t *data); 58 59static isc_result_t 60opensslecdsa_createctx(dst_key_t *key, dst_context_t *dctx) { 61 EVP_MD_CTX *evp_md_ctx; 62 const EVP_MD *type = NULL; 63 64 UNUSED(key); 65 REQUIRE(dctx->key->key_alg == DST_ALG_ECDSA256 || 66 dctx->key->key_alg == DST_ALG_ECDSA384); 67 68 evp_md_ctx = EVP_MD_CTX_create(); 69 if (evp_md_ctx == NULL) 70 return (ISC_R_NOMEMORY); 71 if (dctx->key->key_alg == DST_ALG_ECDSA256) 72 type = EVP_sha256(); 73 else 74 type = EVP_sha384(); 75 76 if (!EVP_DigestInit_ex(evp_md_ctx, type, NULL)) { 77 EVP_MD_CTX_destroy(evp_md_ctx); 78 return (dst__openssl_toresult2("EVP_DigestInit_ex", 79 ISC_R_FAILURE)); 80 } 81 82 dctx->ctxdata.evp_md_ctx = evp_md_ctx; 83 84 return (ISC_R_SUCCESS); 85} 86 87static void 88opensslecdsa_destroyctx(dst_context_t *dctx) { 89 EVP_MD_CTX *evp_md_ctx = dctx->ctxdata.evp_md_ctx; 90 91 REQUIRE(dctx->key->key_alg == DST_ALG_ECDSA256 || 92 dctx->key->key_alg == DST_ALG_ECDSA384); 93 94 if (evp_md_ctx != NULL) { 95 EVP_MD_CTX_destroy(evp_md_ctx); 96 dctx->ctxdata.evp_md_ctx = NULL; 97 } 98} 99 100static isc_result_t 101opensslecdsa_adddata(dst_context_t *dctx, const isc_region_t *data) { 102 EVP_MD_CTX *evp_md_ctx = dctx->ctxdata.evp_md_ctx; 103 104 REQUIRE(dctx->key->key_alg == DST_ALG_ECDSA256 || 105 dctx->key->key_alg == DST_ALG_ECDSA384); 106 107 if (!EVP_DigestUpdate(evp_md_ctx, data->base, data->length)) 108 return (dst__openssl_toresult2("EVP_DigestUpdate", 109 ISC_R_FAILURE)); 110 111 return (ISC_R_SUCCESS); 112} 113 114static int 115BN_bn2bin_fixed(BIGNUM *bn, unsigned char *buf, int size) { 116 int bytes = size - BN_num_bytes(bn); 117 118 while (bytes-- > 0) 119 *buf++ = 0; 120 BN_bn2bin(bn, buf); 121 return (size); 122} 123 124static isc_result_t 125opensslecdsa_sign(dst_context_t *dctx, isc_buffer_t *sig) { 126 isc_result_t ret; 127 dst_key_t *key = dctx->key; 128 isc_region_t r; 129 ECDSA_SIG *ecdsasig; 130 EVP_MD_CTX *evp_md_ctx = dctx->ctxdata.evp_md_ctx; 131 EVP_PKEY *pkey = key->keydata.pkey; 132 EC_KEY *eckey = EVP_PKEY_get1_EC_KEY(pkey); 133 unsigned int dgstlen, siglen; 134 unsigned char digest[EVP_MAX_MD_SIZE]; 135 136 REQUIRE(key->key_alg == DST_ALG_ECDSA256 || 137 key->key_alg == DST_ALG_ECDSA384); 138 139 if (eckey == NULL) 140 return (ISC_R_FAILURE); 141 142 if (key->key_alg == DST_ALG_ECDSA256) 143 siglen = DNS_SIG_ECDSA256SIZE; 144 else 145 siglen = DNS_SIG_ECDSA384SIZE; 146 147 isc_buffer_availableregion(sig, &r); 148 if (r.length < siglen) 149 DST_RET(ISC_R_NOSPACE); 150 151 if (!EVP_DigestFinal(evp_md_ctx, digest, &dgstlen)) 152 DST_RET(dst__openssl_toresult2("EVP_DigestFinal", 153 ISC_R_FAILURE)); 154 155 ecdsasig = ECDSA_do_sign(digest, dgstlen, eckey); 156 if (ecdsasig == NULL) 157 DST_RET(dst__openssl_toresult2("ECDSA_do_sign", 158 DST_R_SIGNFAILURE)); 159 BN_bn2bin_fixed(ecdsasig->r, r.base, siglen / 2); 160 r.base += siglen / 2; 161 BN_bn2bin_fixed(ecdsasig->s, r.base, siglen / 2); 162 r.base += siglen / 2; 163 ECDSA_SIG_free(ecdsasig); 164 isc_buffer_add(sig, siglen); 165 ret = ISC_R_SUCCESS; 166 167 err: 168 if (eckey != NULL) 169 EC_KEY_free(eckey); 170 return (ret); 171} 172 173static isc_result_t 174opensslecdsa_verify(dst_context_t *dctx, const isc_region_t *sig) { 175 isc_result_t ret; 176 dst_key_t *key = dctx->key; 177 int status; 178 unsigned char *cp = sig->base; 179 ECDSA_SIG *ecdsasig = NULL; 180 EVP_MD_CTX *evp_md_ctx = dctx->ctxdata.evp_md_ctx; 181 EVP_PKEY *pkey = key->keydata.pkey; 182 EC_KEY *eckey = EVP_PKEY_get1_EC_KEY(pkey); 183 unsigned int dgstlen, siglen; 184 unsigned char digest[EVP_MAX_MD_SIZE]; 185 186 REQUIRE(key->key_alg == DST_ALG_ECDSA256 || 187 key->key_alg == DST_ALG_ECDSA384); 188 189 if (eckey == NULL) 190 return (ISC_R_FAILURE); 191 192 if (key->key_alg == DST_ALG_ECDSA256) 193 siglen = DNS_SIG_ECDSA256SIZE; 194 else 195 siglen = DNS_SIG_ECDSA384SIZE; 196 197 if (sig->length != siglen) 198 return (DST_R_VERIFYFAILURE); 199 200 if (!EVP_DigestFinal_ex(evp_md_ctx, digest, &dgstlen)) 201 DST_RET (dst__openssl_toresult2("EVP_DigestFinal_ex", 202 ISC_R_FAILURE)); 203 204 ecdsasig = ECDSA_SIG_new(); 205 if (ecdsasig == NULL) 206 DST_RET (ISC_R_NOMEMORY); 207 ecdsasig->r = BN_bin2bn(cp, siglen / 2, NULL); 208 cp += siglen / 2; 209 ecdsasig->s = BN_bin2bn(cp, siglen / 2, NULL); 210 /* cp += siglen / 2; */ 211 212 status = ECDSA_do_verify(digest, dgstlen, ecdsasig, eckey); 213 switch (status) { 214 case 1: 215 ret = ISC_R_SUCCESS; 216 break; 217 case 0: 218 ret = dst__openssl_toresult(DST_R_VERIFYFAILURE); 219 break; 220 default: 221 ret = dst__openssl_toresult2("ECDSA_do_verify", 222 DST_R_VERIFYFAILURE); 223 break; 224 } 225 226 err: 227 if (ecdsasig != NULL) 228 ECDSA_SIG_free(ecdsasig); 229 if (eckey != NULL) 230 EC_KEY_free(eckey); 231 return (ret); 232} 233 234static isc_boolean_t 235opensslecdsa_compare(const dst_key_t *key1, const dst_key_t *key2) { 236 isc_boolean_t ret; 237 int status; 238 EVP_PKEY *pkey1 = key1->keydata.pkey; 239 EVP_PKEY *pkey2 = key2->keydata.pkey; 240 EC_KEY *eckey1 = NULL; 241 EC_KEY *eckey2 = NULL; 242 const BIGNUM *priv1, *priv2; 243 244 if (pkey1 == NULL && pkey2 == NULL) 245 return (ISC_TRUE); 246 else if (pkey1 == NULL || pkey2 == NULL) 247 return (ISC_FALSE); 248 249 eckey1 = EVP_PKEY_get1_EC_KEY(pkey1); 250 eckey2 = EVP_PKEY_get1_EC_KEY(pkey2); 251 if (eckey1 == NULL && eckey2 == NULL) { 252 DST_RET (ISC_TRUE); 253 } else if (eckey1 == NULL || eckey2 == NULL) 254 DST_RET (ISC_FALSE); 255 256 status = EVP_PKEY_cmp(pkey1, pkey2); 257 if (status != 1) 258 DST_RET (ISC_FALSE); 259 260 priv1 = EC_KEY_get0_private_key(eckey1); 261 priv2 = EC_KEY_get0_private_key(eckey2); 262 if (priv1 != NULL || priv2 != NULL) { 263 if (priv1 == NULL || priv2 == NULL) 264 DST_RET (ISC_FALSE); 265 if (BN_cmp(priv1, priv2) != 0) 266 DST_RET (ISC_FALSE); 267 } 268 ret = ISC_TRUE; 269 270 err: 271 if (eckey1 != NULL) 272 EC_KEY_free(eckey1); 273 if (eckey2 != NULL) 274 EC_KEY_free(eckey2); 275 return (ret); 276} 277 278static isc_result_t 279opensslecdsa_generate(dst_key_t *key, int unused, void (*callback)(int)) { 280 isc_result_t ret; 281 EVP_PKEY *pkey; 282 EC_KEY *eckey = NULL; 283 int group_nid; 284 285 REQUIRE(key->key_alg == DST_ALG_ECDSA256 || 286 key->key_alg == DST_ALG_ECDSA384); 287 UNUSED(unused); 288 UNUSED(callback); 289 290 if (key->key_alg == DST_ALG_ECDSA256) 291 group_nid = NID_X9_62_prime256v1; 292 else 293 group_nid = NID_secp384r1; 294 295 eckey = EC_KEY_new_by_curve_name(group_nid); 296 if (eckey == NULL) 297 return (dst__openssl_toresult2("EC_KEY_new_by_curve_name", 298 DST_R_OPENSSLFAILURE)); 299 300 if (EC_KEY_generate_key(eckey) != 1) 301 DST_RET (dst__openssl_toresult2("EC_KEY_generate_key", 302 DST_R_OPENSSLFAILURE)); 303 304 pkey = EVP_PKEY_new(); 305 if (pkey == NULL) 306 DST_RET (ISC_R_NOMEMORY); 307 if (!EVP_PKEY_set1_EC_KEY(pkey, eckey)) { 308 EVP_PKEY_free(pkey); 309 DST_RET (ISC_R_FAILURE); 310 } 311 key->keydata.pkey = pkey; 312 ret = ISC_R_SUCCESS; 313 314 err: 315 if (eckey != NULL) 316 EC_KEY_free(eckey); 317 return (ret); 318} 319 320static isc_boolean_t 321opensslecdsa_isprivate(const dst_key_t *key) { 322 isc_boolean_t ret; 323 EVP_PKEY *pkey = key->keydata.pkey; 324 EC_KEY *eckey = EVP_PKEY_get1_EC_KEY(pkey); 325 326 ret = ISC_TF(eckey != NULL && EC_KEY_get0_private_key(eckey) != NULL); 327 if (eckey != NULL) 328 EC_KEY_free(eckey); 329 return (ret); 330} 331 332static void 333opensslecdsa_destroy(dst_key_t *key) { 334 EVP_PKEY *pkey = key->keydata.pkey; 335 336 EVP_PKEY_free(pkey); 337 key->keydata.pkey = NULL; 338} 339 340static isc_result_t 341opensslecdsa_todns(const dst_key_t *key, isc_buffer_t *data) { 342 isc_result_t ret; 343 EVP_PKEY *pkey; 344 EC_KEY *eckey = NULL; 345 isc_region_t r; 346 int len; 347 unsigned char *cp; 348 unsigned char buf[DNS_KEY_ECDSA384SIZE + 1]; 349 350 REQUIRE(key->keydata.pkey != NULL); 351 352 pkey = key->keydata.pkey; 353 eckey = EVP_PKEY_get1_EC_KEY(pkey); 354 if (eckey == NULL) 355 return (dst__openssl_toresult(ISC_R_FAILURE)); 356 len = i2o_ECPublicKey(eckey, NULL); 357 /* skip form */ 358 len--; 359 360 isc_buffer_availableregion(data, &r); 361 if (r.length < (unsigned int) len) 362 DST_RET (ISC_R_NOSPACE); 363 cp = buf; 364 if (!i2o_ECPublicKey(eckey, &cp)) 365 DST_RET (dst__openssl_toresult(ISC_R_FAILURE)); 366 memcpy(r.base, buf + 1, len); 367 isc_buffer_add(data, len); 368 ret = ISC_R_SUCCESS; 369 370 err: 371 if (eckey != NULL) 372 EC_KEY_free(eckey); 373 return (ret); 374} 375 376static isc_result_t 377opensslecdsa_fromdns(dst_key_t *key, isc_buffer_t *data) { 378 isc_result_t ret; 379 EVP_PKEY *pkey; 380 EC_KEY *eckey = NULL; 381 isc_region_t r; 382 int group_nid; 383 unsigned int len; 384 const unsigned char *cp; 385 unsigned char buf[DNS_KEY_ECDSA384SIZE + 1]; 386 387 REQUIRE(key->key_alg == DST_ALG_ECDSA256 || 388 key->key_alg == DST_ALG_ECDSA384); 389 390 if (key->key_alg == DST_ALG_ECDSA256) { 391 len = DNS_KEY_ECDSA256SIZE; 392 group_nid = NID_X9_62_prime256v1; 393 } else { 394 len = DNS_KEY_ECDSA384SIZE; 395 group_nid = NID_secp384r1; 396 } 397 398 isc_buffer_remainingregion(data, &r); 399 if (r.length == 0) 400 return (ISC_R_SUCCESS); 401 if (r.length < len) 402 return (DST_R_INVALIDPUBLICKEY); 403 404 eckey = EC_KEY_new_by_curve_name(group_nid); 405 if (eckey == NULL) 406 return (dst__openssl_toresult(DST_R_OPENSSLFAILURE)); 407 408 buf[0] = POINT_CONVERSION_UNCOMPRESSED; 409 memcpy(buf + 1, r.base, len); 410 cp = buf; 411 if (o2i_ECPublicKey(&eckey, 412 (const unsigned char **) &cp, 413 (long) len + 1) == NULL) 414 DST_RET (dst__openssl_toresult(DST_R_INVALIDPUBLICKEY)); 415 if (EC_KEY_check_key(eckey) != 1) 416 DST_RET (dst__openssl_toresult(DST_R_INVALIDPUBLICKEY)); 417 418 pkey = EVP_PKEY_new(); 419 if (pkey == NULL) 420 DST_RET (ISC_R_NOMEMORY); 421 if (!EVP_PKEY_set1_EC_KEY(pkey, eckey)) { 422 EVP_PKEY_free(pkey); 423 DST_RET (dst__openssl_toresult(ISC_R_FAILURE)); 424 } 425 426 isc_buffer_forward(data, len); 427 key->keydata.pkey = pkey; 428 ret = ISC_R_SUCCESS; 429 430 err: 431 if (eckey != NULL) 432 EC_KEY_free(eckey); 433 return (ret); 434} 435 436static isc_result_t 437opensslecdsa_tofile(const dst_key_t *key, const char *directory) { 438 isc_result_t ret; 439 EVP_PKEY *pkey; 440 EC_KEY *eckey = NULL; 441 const BIGNUM *privkey; 442 dst_private_t priv; 443 unsigned char *buf = NULL; 444 445 if (key->keydata.pkey == NULL) 446 return (DST_R_NULLKEY); 447 448 pkey = key->keydata.pkey; 449 eckey = EVP_PKEY_get1_EC_KEY(pkey); 450 if (eckey == NULL) 451 return (dst__openssl_toresult(DST_R_OPENSSLFAILURE)); 452 privkey = EC_KEY_get0_private_key(eckey); 453 if (privkey == NULL) 454 DST_RET (ISC_R_FAILURE); 455 456 buf = isc_mem_get(key->mctx, BN_num_bytes(privkey)); 457 if (buf == NULL) 458 DST_RET (ISC_R_NOMEMORY); 459 460 priv.elements[0].tag = TAG_ECDSA_PRIVATEKEY; 461 priv.elements[0].length = BN_num_bytes(privkey); 462 BN_bn2bin(privkey, buf); 463 priv.elements[0].data = buf; 464 priv.nelements = ECDSA_NTAGS; 465 ret = dst__privstruct_writefile(key, &priv, directory); 466 467 err: 468 if (eckey != NULL) 469 EC_KEY_free(eckey); 470 if (buf != NULL) 471 isc_mem_put(key->mctx, buf, BN_num_bytes(privkey)); 472 return (ret); 473} 474 475static isc_result_t 476ecdsa_check(EC_KEY *eckey, dst_key_t *pub) 477{ 478 isc_result_t ret = ISC_R_FAILURE; 479 EVP_PKEY *pkey; 480 EC_KEY *pubeckey = NULL; 481 const EC_POINT *pubkey; 482 483 if (pub == NULL) 484 return (ISC_R_SUCCESS); 485 pkey = pub->keydata.pkey; 486 if (pkey == NULL) 487 return (ISC_R_SUCCESS); 488 pubeckey = EVP_PKEY_get1_EC_KEY(pkey); 489 if (pubeckey == NULL) 490 return (ISC_R_SUCCESS); 491 pubkey = EC_KEY_get0_public_key(pubeckey); 492 if (pubkey == NULL) 493 DST_RET (ISC_R_SUCCESS); 494 if (EC_KEY_set_public_key(eckey, pubkey) != 1) 495 DST_RET (ISC_R_SUCCESS); 496 if (EC_KEY_check_key(eckey) == 1) 497 DST_RET (ISC_R_SUCCESS); 498 499 err: 500 if (pubeckey != NULL) 501 EC_KEY_free(pubeckey); 502 return (ret); 503} 504 505static isc_result_t 506opensslecdsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { 507 dst_private_t priv; 508 isc_result_t ret; 509 EVP_PKEY *pkey; 510 EC_KEY *eckey = NULL; 511 BIGNUM *privkey; 512 int group_nid; 513 isc_mem_t *mctx = key->mctx; 514 515 REQUIRE(key->key_alg == DST_ALG_ECDSA256 || 516 key->key_alg == DST_ALG_ECDSA384); 517 518 if (key->key_alg == DST_ALG_ECDSA256) 519 group_nid = NID_X9_62_prime256v1; 520 else 521 group_nid = NID_secp384r1; 522 523 eckey = EC_KEY_new_by_curve_name(group_nid); 524 if (eckey == NULL) 525 return (dst__openssl_toresult(DST_R_OPENSSLFAILURE)); 526 527 /* read private key file */ 528 ret = dst__privstruct_parse(key, DST_ALG_ECDSA256, lexer, mctx, &priv); 529 if (ret != ISC_R_SUCCESS) 530 goto err; 531 532 privkey = BN_bin2bn(priv.elements[0].data, 533 priv.elements[0].length, NULL); 534 if (privkey == NULL) 535 DST_RET(ISC_R_NOMEMORY); 536 if (!EC_KEY_set_private_key(eckey, privkey)) 537 DST_RET(ISC_R_NOMEMORY); 538 if (ecdsa_check(eckey, pub) != ISC_R_SUCCESS) 539 DST_RET(DST_R_INVALIDPRIVATEKEY); 540 dst__privstruct_free(&priv, mctx); 541 memset(&priv, 0, sizeof(priv)); 542 543 pkey = EVP_PKEY_new(); 544 if (pkey == NULL) 545 DST_RET (ISC_R_NOMEMORY); 546 if (!EVP_PKEY_set1_EC_KEY(pkey, eckey)) { 547 EVP_PKEY_free(pkey); 548 DST_RET (dst__openssl_toresult(DST_R_OPENSSLFAILURE)); 549 } 550 key->keydata.pkey = pkey; 551 ret = ISC_R_SUCCESS; 552 553 err: 554 if (eckey != NULL) 555 EC_KEY_free(eckey); 556 dst__privstruct_free(&priv, mctx); 557 memset(&priv, 0, sizeof(priv)); 558 return (ret); 559} 560 561static dst_func_t opensslecdsa_functions = { 562 opensslecdsa_createctx, 563 opensslecdsa_destroyctx, 564 opensslecdsa_adddata, 565 opensslecdsa_sign, 566 opensslecdsa_verify, 567 NULL, /*%< verify2 */ 568 NULL, /*%< computesecret */ 569 opensslecdsa_compare, 570 NULL, /*%< paramcompare */ 571 opensslecdsa_generate, 572 opensslecdsa_isprivate, 573 opensslecdsa_destroy, 574 opensslecdsa_todns, 575 opensslecdsa_fromdns, 576 opensslecdsa_tofile, 577 opensslecdsa_parse, 578 NULL, /*%< cleanup */ 579 NULL, /*%< fromlabel */ 580 NULL, /*%< dump */ 581 NULL, /*%< restore */ 582}; 583 584isc_result_t 585dst__opensslecdsa_init(dst_func_t **funcp) { 586 REQUIRE(funcp != NULL); 587 if (*funcp == NULL) 588 *funcp = &opensslecdsa_functions; 589 return (ISC_R_SUCCESS); 590} 591 592#else /* HAVE_OPENSSL_ECDSA */ 593 594#include <isc/util.h> 595 596EMPTY_TRANSLATION_UNIT 597 598#endif /* HAVE_OPENSSL_ECDSA */ 599/*! \file */ 600