1 /* $NetBSD: opensslgost_link.c,v 1.10 2015/07/08 17:28:58 christos Exp $ */ 2 3 /* 4 * Copyright (C) 2010-2014 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: opensslgost_link.c,v 1.5 2011/01/19 23:47:12 tbox Exp */ 20 21 #include <config.h> 22 23 #if defined(OPENSSL) && defined(HAVE_OPENSSL_GOST) 24 25 #include <isc/entropy.h> 26 #include <isc/mem.h> 27 #include <isc/string.h> 28 #include <isc/util.h> 29 30 #include <dst/result.h> 31 32 #include "dst_internal.h" 33 #include "dst_openssl.h" 34 #include "dst_parse.h" 35 #include "dst_gost.h" 36 37 #include <openssl/err.h> 38 #include <openssl/objects.h> 39 #include <openssl/rsa.h> 40 #include <openssl/engine.h> 41 42 static ENGINE *e = NULL; 43 static const EVP_MD *opensslgost_digest; 44 extern const EVP_MD *EVP_gost(void); 45 46 const EVP_MD *EVP_gost(void) { 47 return (opensslgost_digest); 48 } 49 50 /* ISC methods */ 51 52 isc_result_t 53 isc_gost_init(isc_gost_t *ctx) { 54 const EVP_MD *md; 55 int ret; 56 57 INSIST(ctx != NULL); 58 59 md = EVP_gost(); 60 if (md == NULL) 61 return (DST_R_CRYPTOFAILURE); 62 EVP_MD_CTX_init(ctx); 63 ret = EVP_DigestInit(ctx, md); 64 if (ret != 1) 65 return (DST_R_CRYPTOFAILURE); 66 return (ISC_R_SUCCESS); 67 } 68 69 void 70 isc_gost_invalidate(isc_gost_t *ctx) { 71 EVP_MD_CTX_cleanup(ctx); 72 } 73 74 isc_result_t 75 isc_gost_update(isc_gost_t *ctx, const unsigned char *data, 76 unsigned int len) 77 { 78 int ret; 79 80 INSIST(ctx != NULL); 81 INSIST(data != NULL); 82 83 ret = EVP_DigestUpdate(ctx, (const void *) data, (size_t) len); 84 if (ret != 1) 85 return (DST_R_CRYPTOFAILURE); 86 return (ISC_R_SUCCESS); 87 } 88 89 isc_result_t 90 isc_gost_final(isc_gost_t *ctx, unsigned char *digest) { 91 int ret; 92 93 INSIST(ctx != NULL); 94 INSIST(digest != NULL); 95 96 ret = EVP_DigestFinal(ctx, digest, NULL); 97 if (ret != 1) 98 return (DST_R_CRYPTOFAILURE); 99 return (ISC_R_SUCCESS); 100 } 101 102 /* DST methods */ 103 104 #define DST_RET(a) {ret = a; goto err;} 105 106 static isc_result_t opensslgost_todns(const dst_key_t *key, 107 isc_buffer_t *data); 108 109 static isc_result_t 110 opensslgost_createctx(dst_key_t *key, dst_context_t *dctx) { 111 EVP_MD_CTX *evp_md_ctx; 112 const EVP_MD *md = EVP_gost(); 113 114 UNUSED(key); 115 116 if (md == NULL) 117 return (DST_R_OPENSSLFAILURE); 118 119 evp_md_ctx = EVP_MD_CTX_create(); 120 if (evp_md_ctx == NULL) 121 return (ISC_R_NOMEMORY); 122 123 if (!EVP_DigestInit_ex(evp_md_ctx, md, NULL)) { 124 EVP_MD_CTX_destroy(evp_md_ctx); 125 return (ISC_R_FAILURE); 126 } 127 dctx->ctxdata.evp_md_ctx = evp_md_ctx; 128 129 return (ISC_R_SUCCESS); 130 } 131 132 static void 133 opensslgost_destroyctx(dst_context_t *dctx) { 134 EVP_MD_CTX *evp_md_ctx = dctx->ctxdata.evp_md_ctx; 135 136 if (evp_md_ctx != NULL) { 137 EVP_MD_CTX_destroy(evp_md_ctx); 138 dctx->ctxdata.evp_md_ctx = NULL; 139 } 140 } 141 142 static isc_result_t 143 opensslgost_adddata(dst_context_t *dctx, const isc_region_t *data) { 144 EVP_MD_CTX *evp_md_ctx = dctx->ctxdata.evp_md_ctx; 145 146 if (!EVP_DigestUpdate(evp_md_ctx, data->base, data->length)) 147 return (ISC_R_FAILURE); 148 149 return (ISC_R_SUCCESS); 150 } 151 152 static isc_result_t 153 opensslgost_sign(dst_context_t *dctx, isc_buffer_t *sig) { 154 dst_key_t *key = dctx->key; 155 isc_region_t r; 156 unsigned int siglen = 0; 157 EVP_MD_CTX *evp_md_ctx = dctx->ctxdata.evp_md_ctx; 158 EVP_PKEY *pkey = key->keydata.pkey; 159 160 isc_buffer_availableregion(sig, &r); 161 162 if (r.length < (unsigned int) EVP_PKEY_size(pkey)) 163 return (ISC_R_NOSPACE); 164 165 if (!EVP_SignFinal(evp_md_ctx, r.base, &siglen, pkey)) 166 return (ISC_R_FAILURE); 167 168 isc_buffer_add(sig, siglen); 169 170 return (ISC_R_SUCCESS); 171 } 172 173 static isc_result_t 174 opensslgost_verify(dst_context_t *dctx, const isc_region_t *sig) { 175 dst_key_t *key = dctx->key; 176 int status = 0; 177 EVP_MD_CTX *evp_md_ctx = dctx->ctxdata.evp_md_ctx; 178 EVP_PKEY *pkey = key->keydata.pkey; 179 180 status = EVP_VerifyFinal(evp_md_ctx, sig->base, sig->length, pkey); 181 switch (status) { 182 case 1: 183 return (ISC_R_SUCCESS); 184 case 0: 185 return (dst__openssl_toresult(DST_R_VERIFYFAILURE)); 186 default: 187 return (dst__openssl_toresult3(dctx->category, 188 "EVP_VerifyFinal", 189 DST_R_VERIFYFAILURE)); 190 } 191 } 192 193 static isc_boolean_t 194 opensslgost_compare(const dst_key_t *key1, const dst_key_t *key2) { 195 EVP_PKEY *pkey1, *pkey2; 196 197 pkey1 = key1->keydata.pkey; 198 pkey2 = key2->keydata.pkey; 199 200 if (pkey1 == NULL && pkey2 == NULL) 201 return (ISC_TRUE); 202 else if (pkey1 == NULL || pkey2 == NULL) 203 return (ISC_FALSE); 204 205 if (EVP_PKEY_cmp(pkey1, pkey2) != 1) 206 return (ISC_FALSE); 207 return (ISC_TRUE); 208 } 209 210 static int 211 progress_cb(EVP_PKEY_CTX *ctx) 212 { 213 union { 214 void *dptr; 215 void (*fptr)(int); 216 } u; 217 int p; 218 219 u.dptr = EVP_PKEY_CTX_get_app_data(ctx); 220 p = EVP_PKEY_CTX_get_keygen_info(ctx, 0); 221 if (u.fptr != NULL) 222 u.fptr(p); 223 return (1); 224 } 225 226 static isc_result_t 227 opensslgost_generate(dst_key_t *key, int unused, void (*callback)(int)) { 228 EVP_PKEY_CTX *ctx; 229 union { 230 void *dptr; 231 void (*fptr)(int); 232 } u; 233 EVP_PKEY *pkey = NULL; 234 isc_result_t ret; 235 236 UNUSED(unused); 237 ctx = EVP_PKEY_CTX_new_id(NID_id_GostR3410_2001, NULL); 238 if (ctx == NULL) 239 DST_RET(dst__openssl_toresult2("EVP_PKEY_CTX_new_id", 240 DST_R_OPENSSLFAILURE)); 241 if (callback != NULL) { 242 u.fptr = callback; 243 EVP_PKEY_CTX_set_app_data(ctx, u.dptr); 244 EVP_PKEY_CTX_set_cb(ctx, &progress_cb); 245 } 246 if (EVP_PKEY_keygen_init(ctx) <= 0) 247 DST_RET(dst__openssl_toresult2("EVP_PKEY_keygen_init", 248 DST_R_OPENSSLFAILURE)); 249 if (EVP_PKEY_CTX_ctrl_str(ctx, "paramset", "A") <= 0) 250 DST_RET(dst__openssl_toresult2("EVP_PKEY_CTX_ctrl_str", 251 DST_R_OPENSSLFAILURE)); 252 if (EVP_PKEY_keygen(ctx, &pkey) <= 0) 253 DST_RET(dst__openssl_toresult2("EVP_PKEY_keygen", 254 DST_R_OPENSSLFAILURE)); 255 key->keydata.pkey = pkey; 256 key->key_size = EVP_PKEY_bits(pkey); 257 EVP_PKEY_CTX_free(ctx); 258 return (ISC_R_SUCCESS); 259 260 err: 261 if (pkey != NULL) 262 EVP_PKEY_free(pkey); 263 if (ctx != NULL) 264 EVP_PKEY_CTX_free(ctx); 265 return (ret); 266 } 267 268 static isc_boolean_t 269 opensslgost_isprivate(const dst_key_t *key) { 270 EVP_PKEY *pkey = key->keydata.pkey; 271 EC_KEY *ec; 272 273 INSIST(pkey != NULL); 274 275 ec = EVP_PKEY_get0(pkey); 276 return (ISC_TF(ec != NULL && EC_KEY_get0_private_key(ec) != NULL)); 277 } 278 279 static void 280 opensslgost_destroy(dst_key_t *key) { 281 EVP_PKEY *pkey = key->keydata.pkey; 282 283 EVP_PKEY_free(pkey); 284 key->keydata.pkey = NULL; 285 } 286 287 unsigned char gost_prefix[37] = { 288 0x30, 0x63, 0x30, 0x1c, 0x06, 0x06, 0x2a, 0x85, 289 0x03, 0x02, 0x02, 0x13, 0x30, 0x12, 0x06, 0x07, 290 0x2a, 0x85, 0x03, 0x02, 0x02, 0x23, 0x01, 0x06, 291 0x07, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x1e, 0x01, 292 0x03, 0x43, 0x00, 0x04, 0x40 293 }; 294 295 static isc_result_t 296 opensslgost_todns(const dst_key_t *key, isc_buffer_t *data) { 297 EVP_PKEY *pkey; 298 isc_region_t r; 299 unsigned char der[37 + 64], *p; 300 int len; 301 302 REQUIRE(key->keydata.pkey != NULL); 303 304 pkey = key->keydata.pkey; 305 306 isc_buffer_availableregion(data, &r); 307 if (r.length < 64) 308 return (ISC_R_NOSPACE); 309 310 p = der; 311 len = i2d_PUBKEY(pkey, &p); 312 INSIST(len == sizeof(der)); 313 INSIST(memcmp(gost_prefix, der, 37) == 0); 314 memmove(r.base, der + 37, 64); 315 isc_buffer_add(data, 64); 316 317 return (ISC_R_SUCCESS); 318 } 319 320 static isc_result_t 321 opensslgost_fromdns(dst_key_t *key, isc_buffer_t *data) { 322 isc_region_t r; 323 EVP_PKEY *pkey = NULL; 324 unsigned char der[37 + 64]; 325 const unsigned char *p; 326 327 isc_buffer_remainingregion(data, &r); 328 if (r.length == 0) 329 return (ISC_R_SUCCESS); 330 331 if (r.length != 64) 332 return (DST_R_INVALIDPUBLICKEY); 333 memmove(der, gost_prefix, 37); 334 memmove(der + 37, r.base, 64); 335 isc_buffer_forward(data, 64); 336 337 p = der; 338 if (d2i_PUBKEY(&pkey, &p, (long) sizeof(der)) == NULL) 339 return (dst__openssl_toresult2("d2i_PUBKEY", 340 DST_R_OPENSSLFAILURE)); 341 key->keydata.pkey = pkey; 342 key->key_size = EVP_PKEY_bits(pkey); 343 344 return (ISC_R_SUCCESS); 345 } 346 347 #ifdef PREFER_GOSTASN1 348 349 static isc_result_t 350 opensslgost_tofile(const dst_key_t *key, const char *directory) { 351 EVP_PKEY *pkey; 352 dst_private_t priv; 353 isc_result_t result; 354 unsigned char *der, *p; 355 int len; 356 357 if (key->keydata.pkey == NULL) 358 return (DST_R_NULLKEY); 359 360 if (key->external) { 361 priv.nelements = 0; 362 return (dst__privstruct_writefile(key, &priv, directory)); 363 } 364 365 pkey = key->keydata.pkey; 366 367 len = i2d_PrivateKey(pkey, NULL); 368 der = isc_mem_get(key->mctx, (size_t) len); 369 if (der == NULL) 370 return (ISC_R_NOMEMORY); 371 372 p = der; 373 if (i2d_PrivateKey(pkey, &p) != len) { 374 result = dst__openssl_toresult2("i2d_PrivateKey", 375 DST_R_OPENSSLFAILURE); 376 goto fail; 377 } 378 379 priv.elements[0].tag = TAG_GOST_PRIVASN1; 380 priv.elements[0].length = len; 381 priv.elements[0].data = der; 382 priv.nelements = 1; 383 384 result = dst__privstruct_writefile(key, &priv, directory); 385 fail: 386 if (der != NULL) 387 isc_mem_put(key->mctx, der, (size_t) len); 388 return (result); 389 } 390 391 #else 392 393 static isc_result_t 394 opensslgost_tofile(const dst_key_t *key, const char *directory) { 395 EVP_PKEY *pkey; 396 EC_KEY *eckey; 397 const BIGNUM *privkey; 398 dst_private_t priv; 399 isc_result_t ret; 400 unsigned char *buf = NULL; 401 402 if (key->keydata.pkey == NULL) 403 return (DST_R_NULLKEY); 404 405 if (key->external) { 406 priv.nelements = 0; 407 return (dst__privstruct_writefile(key, &priv, directory)); 408 } 409 410 pkey = key->keydata.pkey; 411 eckey = EVP_PKEY_get0(pkey); 412 if (eckey == NULL) 413 return (dst__openssl_toresult(DST_R_OPENSSLFAILURE)); 414 privkey = EC_KEY_get0_private_key(eckey); 415 if (privkey == NULL) 416 return (ISC_R_FAILURE); 417 418 buf = isc_mem_get(key->mctx, BN_num_bytes(privkey)); 419 if (buf == NULL) 420 return (ISC_R_NOMEMORY); 421 422 priv.elements[0].tag = TAG_GOST_PRIVRAW; 423 priv.elements[0].length = BN_num_bytes(privkey); 424 BN_bn2bin(privkey, buf); 425 priv.elements[0].data = buf; 426 priv.nelements = 1; 427 428 ret = dst__privstruct_writefile(key, &priv, directory); 429 430 if (buf != NULL) 431 isc_mem_put(key->mctx, buf, BN_num_bytes(privkey)); 432 return (ret); 433 } 434 #endif 435 436 static unsigned char gost_dummy_key[71] = { 437 0x30, 0x45, 0x02, 0x01, 0x00, 0x30, 0x1c, 0x06, 438 0x06, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x13, 0x30, 439 0x12, 0x06, 0x07, 0x2a, 0x85, 0x03, 0x02, 0x02, 440 0x23, 0x01, 0x06, 0x07, 0x2a, 0x85, 0x03, 0x02, 441 0x02, 0x1e, 0x01, 0x04, 0x22, 0x02, 0x20, 0x1b, 442 0x3f, 0x94, 0xf7, 0x1a, 0x5f, 0x2f, 0xe7, 0xe5, 443 0x74, 0x0b, 0x8c, 0xd4, 0xb7, 0x18, 0xdd, 0x65, 444 0x68, 0x26, 0xd1, 0x54, 0xfb, 0x77, 0xba, 0x63, 445 0x72, 0xd9, 0xf0, 0x63, 0x87, 0xe0, 0xd6 446 }; 447 448 static isc_result_t 449 opensslgost_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { 450 dst_private_t priv; 451 isc_result_t ret; 452 isc_mem_t *mctx = key->mctx; 453 EVP_PKEY *pkey = NULL; 454 EC_KEY *eckey; 455 const EC_POINT *pubkey = NULL; 456 BIGNUM *privkey = NULL; 457 const unsigned char *p; 458 459 /* read private key file */ 460 ret = dst__privstruct_parse(key, DST_ALG_ECCGOST, lexer, mctx, &priv); 461 if (ret != ISC_R_SUCCESS) 462 return (ret); 463 464 if (key->external) { 465 if (priv.nelements != 0) 466 DST_RET(DST_R_INVALIDPRIVATEKEY); 467 if (pub == NULL) 468 DST_RET(DST_R_INVALIDPRIVATEKEY); 469 key->keydata.pkey = pub->keydata.pkey; 470 pub->keydata.pkey = NULL; 471 key->key_size = pub->key_size; 472 dst__privstruct_free(&priv, mctx); 473 memset(&priv, 0, sizeof(priv)); 474 return (ISC_R_SUCCESS); 475 } 476 477 INSIST((priv.elements[0].tag == TAG_GOST_PRIVASN1) || 478 (priv.elements[0].tag == TAG_GOST_PRIVRAW)); 479 480 if (priv.elements[0].tag == TAG_GOST_PRIVASN1) { 481 p = priv.elements[0].data; 482 if (d2i_PrivateKey(NID_id_GostR3410_2001, &pkey, &p, 483 (long) priv.elements[0].length) == NULL) 484 DST_RET(dst__openssl_toresult2( 485 "d2i_PrivateKey", 486 DST_R_INVALIDPRIVATEKEY)); 487 } else { 488 if ((pub != NULL) && (pub->keydata.pkey != NULL)) { 489 eckey = EVP_PKEY_get0(pub->keydata.pkey); 490 pubkey = EC_KEY_get0_public_key(eckey); 491 } 492 493 privkey = BN_bin2bn(priv.elements[0].data, 494 priv.elements[0].length, NULL); 495 if (privkey == NULL) 496 DST_RET(ISC_R_NOMEMORY); 497 498 /* can't create directly the whole key */ 499 p = gost_dummy_key; 500 if (d2i_PrivateKey(NID_id_GostR3410_2001, &pkey, &p, 501 (long) sizeof(gost_dummy_key)) == NULL) 502 DST_RET(dst__openssl_toresult2( 503 "d2i_PrivateKey", 504 DST_R_INVALIDPRIVATEKEY)); 505 506 eckey = EVP_PKEY_get0(pkey); 507 if (eckey == NULL) 508 return (dst__openssl_toresult(DST_R_OPENSSLFAILURE)); 509 if (!EC_KEY_set_private_key(eckey, privkey)) 510 DST_RET(ISC_R_NOMEMORY); 511 512 /* have to (re)set the public key */ 513 #ifdef notyet 514 (void) gost2001_compute_public(eckey); 515 #else 516 if ((pubkey != NULL) && !EC_KEY_set_public_key(eckey, pubkey)) 517 DST_RET(ISC_R_NOMEMORY); 518 #endif 519 BN_clear_free(privkey); 520 privkey = NULL; 521 } 522 key->keydata.pkey = pkey; 523 key->key_size = EVP_PKEY_bits(pkey); 524 dst__privstruct_free(&priv, mctx); 525 memset(&priv, 0, sizeof(priv)); 526 return (ISC_R_SUCCESS); 527 528 err: 529 if (privkey != NULL) 530 BN_clear_free(privkey); 531 if (pkey != NULL) 532 EVP_PKEY_free(pkey); 533 opensslgost_destroy(key); 534 dst__privstruct_free(&priv, mctx); 535 memset(&priv, 0, sizeof(priv)); 536 return (ret); 537 } 538 539 static void 540 opensslgost_cleanup(void) { 541 if (e != NULL) { 542 ENGINE_finish(e); 543 ENGINE_free(e); 544 e = NULL; 545 } 546 } 547 548 static dst_func_t opensslgost_functions = { 549 opensslgost_createctx, 550 NULL, /*%< createctx2 */ 551 opensslgost_destroyctx, 552 opensslgost_adddata, 553 opensslgost_sign, 554 opensslgost_verify, 555 NULL, /*%< verify2 */ 556 NULL, /*%< computesecret */ 557 opensslgost_compare, 558 NULL, /*%< paramcompare */ 559 opensslgost_generate, 560 opensslgost_isprivate, 561 opensslgost_destroy, 562 opensslgost_todns, 563 opensslgost_fromdns, 564 opensslgost_tofile, 565 opensslgost_parse, 566 opensslgost_cleanup, 567 NULL, /*%< fromlabel */ 568 NULL, /*%< dump */ 569 NULL /*%< restore */ 570 }; 571 572 isc_result_t 573 dst__opensslgost_init(dst_func_t **funcp) { 574 isc_result_t ret; 575 576 REQUIRE(funcp != NULL); 577 578 /* check if the gost engine works properly */ 579 e = ENGINE_by_id("gost"); 580 if (e == NULL) 581 return (dst__openssl_toresult2("ENGINE_by_id", 582 DST_R_OPENSSLFAILURE)); 583 if (ENGINE_init(e) <= 0) { 584 ENGINE_free(e); 585 e = NULL; 586 return (dst__openssl_toresult2("ENGINE_init", 587 DST_R_OPENSSLFAILURE)); 588 } 589 /* better than to rely on digest_gost symbol */ 590 opensslgost_digest = ENGINE_get_digest(e, NID_id_GostR3411_94); 591 if (opensslgost_digest == NULL) 592 DST_RET(dst__openssl_toresult2("ENGINE_get_digest", 593 DST_R_OPENSSLFAILURE)); 594 /* from openssl.cnf */ 595 if (ENGINE_register_pkey_asn1_meths(e) <= 0) 596 DST_RET(dst__openssl_toresult2( 597 "ENGINE_register_pkey_asn1_meths", 598 DST_R_OPENSSLFAILURE)); 599 if (ENGINE_ctrl_cmd_string(e, 600 "CRYPT_PARAMS", 601 "id-Gost28147-89-CryptoPro-A-ParamSet", 602 0) <= 0) 603 DST_RET(dst__openssl_toresult2("ENGINE_ctrl_cmd_string", 604 DST_R_OPENSSLFAILURE)); 605 606 if (*funcp == NULL) 607 *funcp = &opensslgost_functions; 608 return (ISC_R_SUCCESS); 609 610 err: 611 ENGINE_finish(e); 612 ENGINE_free(e); 613 e = NULL; 614 return (ret); 615 } 616 617 #else /* HAVE_OPENSSL_GOST */ 618 619 #include <isc/util.h> 620 621 EMPTY_TRANSLATION_UNIT 622 623 #endif /* HAVE_OPENSSL_GOST */ 624 /*! \file */ 625