1 /* $NetBSD: opensslecdsa_link.c,v 1.9 2025/01/26 16:25:23 christos Exp $ */ 2 3 /* 4 * Copyright (C) Internet Systems Consortium, Inc. ("ISC") 5 * 6 * SPDX-License-Identifier: MPL-2.0 7 * 8 * This Source Code Form is subject to the terms of the Mozilla Public 9 * License, v. 2.0. If a copy of the MPL was not distributed with this 10 * file, you can obtain one at https://mozilla.org/MPL/2.0/. 11 * 12 * See the COPYRIGHT file distributed with this work for additional 13 * information regarding copyright ownership. 14 */ 15 16 /*! \file */ 17 18 #include <stdbool.h> 19 20 #include <openssl/bn.h> 21 #include <openssl/ecdsa.h> 22 #include <openssl/err.h> 23 #include <openssl/evp.h> 24 #include <openssl/objects.h> 25 #include <openssl/opensslv.h> 26 #if OPENSSL_VERSION_NUMBER >= 0x30000000L 27 #include <openssl/core_names.h> 28 #include <openssl/param_build.h> 29 #endif 30 31 #include <isc/mem.h> 32 #include <isc/result.h> 33 #include <isc/safe.h> 34 #include <isc/string.h> 35 #include <isc/util.h> 36 37 #include <dns/keyvalues.h> 38 39 #include "dst_internal.h" 40 #include "dst_openssl.h" 41 #include "dst_parse.h" 42 #include "openssl_shim.h" 43 44 #ifndef NID_X9_62_prime256v1 45 #error "P-256 group is not known (NID_X9_62_prime256v1)" 46 #endif /* ifndef NID_X9_62_prime256v1 */ 47 #ifndef NID_secp384r1 48 #error "P-384 group is not known (NID_secp384r1)" 49 #endif /* ifndef NID_secp384r1 */ 50 51 #define MAX_PUBKEY_SIZE DNS_KEY_ECDSA384SIZE 52 53 #define MAX_PRIVKEY_SIZE (MAX_PUBKEY_SIZE / 2) 54 55 #define DST_RET(a) \ 56 { \ 57 ret = a; \ 58 goto err; \ 59 } 60 61 static bool 62 opensslecdsa_valid_key_alg(unsigned int key_alg) { 63 switch (key_alg) { 64 case DST_ALG_ECDSA256: 65 case DST_ALG_ECDSA384: 66 return true; 67 default: 68 return false; 69 } 70 } 71 72 static int 73 opensslecdsa_key_alg_to_group_nid(unsigned int key_alg) { 74 switch (key_alg) { 75 case DST_ALG_ECDSA256: 76 return NID_X9_62_prime256v1; 77 case DST_ALG_ECDSA384: 78 return NID_secp384r1; 79 default: 80 UNREACHABLE(); 81 } 82 } 83 84 static size_t 85 opensslecdsa_key_alg_to_publickey_size(unsigned int key_alg) { 86 switch (key_alg) { 87 case DST_ALG_ECDSA256: 88 return DNS_KEY_ECDSA256SIZE; 89 case DST_ALG_ECDSA384: 90 return DNS_KEY_ECDSA384SIZE; 91 default: 92 UNREACHABLE(); 93 } 94 } 95 96 /* 97 * OpenSSL requires us to set the public key portion, but since our private key 98 * file format does not contain it directly, we generate it as needed. 99 */ 100 static EC_POINT * 101 opensslecdsa_generate_public_key(const EC_GROUP *group, const BIGNUM *privkey) { 102 EC_POINT *pubkey = EC_POINT_new(group); 103 if (pubkey == NULL) { 104 return NULL; 105 } 106 if (EC_POINT_mul(group, pubkey, privkey, NULL, NULL, NULL) != 1) { 107 EC_POINT_free(pubkey); 108 return NULL; 109 } 110 return pubkey; 111 } 112 113 static int 114 BN_bn2bin_fixed(const BIGNUM *bn, unsigned char *buf, int size) { 115 int bytes = size - BN_num_bytes(bn); 116 117 INSIST(bytes >= 0); 118 119 while (bytes-- > 0) { 120 *buf++ = 0; 121 } 122 BN_bn2bin(bn, buf); 123 return size; 124 } 125 126 #if OPENSSL_VERSION_NUMBER >= 0x30000000L 127 128 static const char * 129 opensslecdsa_key_alg_to_group_name(unsigned int key_alg) { 130 switch (key_alg) { 131 case DST_ALG_ECDSA256: 132 return "prime256v1"; 133 case DST_ALG_ECDSA384: 134 return "secp384r1"; 135 default: 136 UNREACHABLE(); 137 } 138 } 139 140 static isc_result_t 141 opensslecdsa_create_pkey_params(unsigned int key_alg, bool private, 142 const unsigned char *key, size_t key_len, 143 EVP_PKEY **pkey) { 144 isc_result_t ret; 145 int status; 146 int group_nid = opensslecdsa_key_alg_to_group_nid(key_alg); 147 const char *groupname = opensslecdsa_key_alg_to_group_name(key_alg); 148 OSSL_PARAM_BLD *bld = NULL; 149 OSSL_PARAM *params = NULL; 150 EVP_PKEY_CTX *ctx = NULL; 151 EC_POINT *pubkey = NULL; 152 EC_GROUP *group = NULL; 153 BIGNUM *priv = NULL; 154 unsigned char buf[MAX_PUBKEY_SIZE + 1]; 155 156 bld = OSSL_PARAM_BLD_new(); 157 if (bld == NULL) { 158 DST_RET(dst__openssl_toresult2("OSSL_PARAM_BLD_new", 159 DST_R_OPENSSLFAILURE)); 160 } 161 status = OSSL_PARAM_BLD_push_utf8_string( 162 bld, OSSL_PKEY_PARAM_GROUP_NAME, groupname, 0); 163 if (status != 1) { 164 DST_RET(dst__openssl_toresult2("OSSL_PARAM_BLD_push_" 165 "utf8_string", 166 DST_R_OPENSSLFAILURE)); 167 } 168 169 if (private) { 170 group = EC_GROUP_new_by_curve_name(group_nid); 171 if (group == NULL) { 172 DST_RET(dst__openssl_toresult2("EC_GROUP_new_by_" 173 "curve_name", 174 DST_R_OPENSSLFAILURE)); 175 } 176 177 priv = BN_bin2bn(key, key_len, NULL); 178 if (priv == NULL) { 179 DST_RET(dst__openssl_toresult2("BN_bin2bn", 180 DST_R_OPENSSLFAILURE)); 181 } 182 183 status = OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_PRIV_KEY, 184 priv); 185 if (status != 1) { 186 DST_RET(dst__openssl_toresult2("OSSL_PARAM_BLD_push_BN", 187 DST_R_OPENSSLFAILURE)); 188 } 189 190 pubkey = opensslecdsa_generate_public_key(group, priv); 191 if (pubkey == NULL) { 192 DST_RET(dst__openssl_toresult(DST_R_OPENSSLFAILURE)); 193 } 194 195 key = buf; 196 key_len = EC_POINT_point2oct(group, pubkey, 197 POINT_CONVERSION_UNCOMPRESSED, buf, 198 sizeof(buf), NULL); 199 if (key_len == 0) { 200 DST_RET(dst__openssl_toresult2("EC_POINT_point2oct", 201 DST_R_OPENSSLFAILURE)); 202 } 203 } else { 204 INSIST(key_len + 1 <= sizeof(buf)); 205 buf[0] = POINT_CONVERSION_UNCOMPRESSED; 206 memmove(buf + 1, key, key_len); 207 key = buf; 208 key_len = key_len + 1; 209 } 210 211 status = OSSL_PARAM_BLD_push_octet_string(bld, OSSL_PKEY_PARAM_PUB_KEY, 212 key, key_len); 213 if (status != 1) { 214 DST_RET(dst__openssl_toresult2("OSSL_PARAM_BLD_push_" 215 "octet_string", 216 DST_R_OPENSSLFAILURE)); 217 } 218 219 params = OSSL_PARAM_BLD_to_param(bld); 220 if (params == NULL) { 221 DST_RET(dst__openssl_toresult2("OSSL_PARAM_BLD_to_param", 222 DST_R_OPENSSLFAILURE)); 223 } 224 ctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL); 225 if (ctx == NULL) { 226 DST_RET(dst__openssl_toresult2("EVP_PKEY_CTX_new_from_name", 227 DST_R_OPENSSLFAILURE)); 228 } 229 status = EVP_PKEY_fromdata_init(ctx); 230 if (status != 1) { 231 /* This will fail if the default provider is an engine. 232 * Return ISC_R_FAILURE to retry using the legacy API. */ 233 DST_RET(dst__openssl_toresult(ISC_R_FAILURE)); 234 } 235 status = EVP_PKEY_fromdata( 236 ctx, pkey, private ? EVP_PKEY_KEYPAIR : EVP_PKEY_PUBLIC_KEY, 237 params); 238 if (status != 1 || *pkey == NULL) { 239 DST_RET(dst__openssl_toresult2("EVP_PKEY_fromdata", 240 DST_R_OPENSSLFAILURE)); 241 } 242 243 ret = ISC_R_SUCCESS; 244 245 err: 246 OSSL_PARAM_free(params); 247 OSSL_PARAM_BLD_free(bld); 248 EVP_PKEY_CTX_free(ctx); 249 BN_clear_free(priv); 250 EC_POINT_free(pubkey); 251 EC_GROUP_free(group); 252 253 return ret; 254 } 255 256 static bool 257 opensslecdsa_extract_public_key_params(const dst_key_t *key, unsigned char *dst, 258 size_t dstlen) { 259 EVP_PKEY *pkey = key->keydata.pkeypair.pub; 260 BIGNUM *x = NULL; 261 BIGNUM *y = NULL; 262 bool ret = false; 263 264 if (EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_EC_PUB_X, &x) == 1 && 265 EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_EC_PUB_Y, &y) == 1) 266 { 267 BN_bn2bin_fixed(x, &dst[0], dstlen / 2); 268 BN_bn2bin_fixed(y, &dst[dstlen / 2], dstlen / 2); 269 ret = true; 270 } 271 BN_clear_free(x); 272 BN_clear_free(y); 273 return ret; 274 } 275 276 #endif 277 278 #if OPENSSL_VERSION_NUMBER < 0x30000000L || OPENSSL_API_LEVEL < 30000 279 280 static isc_result_t 281 opensslecdsa_create_pkey_legacy(unsigned int key_alg, bool private, 282 const unsigned char *key, size_t key_len, 283 EVP_PKEY **retkey) { 284 isc_result_t ret = ISC_R_SUCCESS; 285 EC_KEY *eckey = NULL; 286 EVP_PKEY *pkey = NULL; 287 BIGNUM *privkey = NULL; 288 EC_POINT *pubkey = NULL; 289 unsigned char buf[MAX_PUBKEY_SIZE + 1]; 290 int group_nid = opensslecdsa_key_alg_to_group_nid(key_alg); 291 292 eckey = EC_KEY_new_by_curve_name(group_nid); 293 if (eckey == NULL) { 294 DST_RET(dst__openssl_toresult(DST_R_OPENSSLFAILURE)); 295 } 296 297 if (private) { 298 const EC_GROUP *group = EC_KEY_get0_group(eckey); 299 300 privkey = BN_bin2bn(key, key_len, NULL); 301 if (privkey == NULL) { 302 DST_RET(dst__openssl_toresult(DST_R_OPENSSLFAILURE)); 303 } 304 if (!EC_KEY_set_private_key(eckey, privkey)) { 305 DST_RET(dst__openssl_toresult(DST_R_INVALIDPRIVATEKEY)); 306 } 307 308 pubkey = opensslecdsa_generate_public_key(group, privkey); 309 if (pubkey == NULL) { 310 DST_RET(dst__openssl_toresult(DST_R_OPENSSLFAILURE)); 311 } 312 if (EC_KEY_set_public_key(eckey, pubkey) != 1) { 313 DST_RET(dst__openssl_toresult(DST_R_OPENSSLFAILURE)); 314 } 315 } else { 316 const unsigned char *cp = buf; 317 INSIST(key_len + 1 <= sizeof(buf)); 318 buf[0] = POINT_CONVERSION_UNCOMPRESSED; 319 memmove(buf + 1, key, key_len); 320 if (o2i_ECPublicKey(&eckey, &cp, key_len + 1) == NULL) { 321 DST_RET(dst__openssl_toresult(DST_R_INVALIDPUBLICKEY)); 322 } 323 if (EC_KEY_check_key(eckey) != 1) { 324 DST_RET(dst__openssl_toresult(DST_R_INVALIDPUBLICKEY)); 325 } 326 } 327 328 pkey = EVP_PKEY_new(); 329 if (pkey == NULL) { 330 DST_RET(dst__openssl_toresult(ISC_R_NOMEMORY)); 331 } 332 if (!EVP_PKEY_set1_EC_KEY(pkey, eckey)) { 333 DST_RET(dst__openssl_toresult(ISC_R_FAILURE)); 334 } 335 336 *retkey = pkey; 337 pkey = NULL; 338 339 err: 340 BN_clear_free(privkey); 341 EC_POINT_free(pubkey); 342 EC_KEY_free(eckey); 343 EVP_PKEY_free(pkey); 344 return ret; 345 } 346 347 static bool 348 opensslecdsa_extract_public_key_legacy(const dst_key_t *key, unsigned char *dst, 349 size_t dstlen) { 350 EVP_PKEY *pkey = key->keydata.pkeypair.pub; 351 const EC_KEY *eckey = EVP_PKEY_get0_EC_KEY(pkey); 352 const EC_GROUP *group = (eckey == NULL) ? NULL 353 : EC_KEY_get0_group(eckey); 354 const EC_POINT *pub = (eckey == NULL) ? NULL 355 : EC_KEY_get0_public_key(eckey); 356 unsigned char buf[MAX_PUBKEY_SIZE + 1]; 357 size_t len; 358 359 if (group == NULL || pub == NULL) { 360 return false; 361 } 362 363 len = EC_POINT_point2oct(group, pub, POINT_CONVERSION_UNCOMPRESSED, buf, 364 sizeof(buf), NULL); 365 if (len == dstlen + 1) { 366 memmove(dst, buf + 1, dstlen); 367 return true; 368 } 369 return false; 370 } 371 372 #endif 373 374 static bool 375 opensslecdsa_extract_public_key(const dst_key_t *key, unsigned char *dst, 376 size_t dstlen) { 377 #if OPENSSL_VERSION_NUMBER >= 0x30000000L 378 if (opensslecdsa_extract_public_key_params(key, dst, dstlen)) { 379 return true; 380 } 381 #endif 382 #if OPENSSL_VERSION_NUMBER < 0x30000000L || OPENSSL_API_LEVEL < 30000 383 if (opensslecdsa_extract_public_key_legacy(key, dst, dstlen)) { 384 return true; 385 } 386 #endif 387 return false; 388 } 389 390 static isc_result_t 391 opensslecdsa_create_pkey(unsigned int key_alg, bool private, 392 const unsigned char *key, size_t key_len, 393 EVP_PKEY **retkey) { 394 isc_result_t ret; 395 #if OPENSSL_VERSION_NUMBER >= 0x30000000L 396 ret = opensslecdsa_create_pkey_params(key_alg, private, key, key_len, 397 retkey); 398 if (ret != ISC_R_FAILURE) { 399 return ret; 400 } 401 #endif 402 #if OPENSSL_VERSION_NUMBER < 0x30000000L || OPENSSL_API_LEVEL < 30000 403 ret = opensslecdsa_create_pkey_legacy(key_alg, private, key, key_len, 404 retkey); 405 if (ret == ISC_R_SUCCESS) { 406 return ret; 407 } 408 #endif 409 return DST_R_OPENSSLFAILURE; 410 } 411 412 #if OPENSSL_VERSION_NUMBER >= 0x30000000L 413 414 static isc_result_t 415 opensslecdsa_generate_pkey_with_uri(int group_nid, const char *label, 416 EVP_PKEY **retkey) { 417 int status; 418 isc_result_t ret; 419 char *uri = UNCONST(label); 420 EVP_PKEY_CTX *ctx = NULL; 421 OSSL_PARAM params[3]; 422 423 /* Generate the key's parameters. */ 424 params[0] = OSSL_PARAM_construct_utf8_string("pkcs11_uri", uri, 0); 425 params[1] = OSSL_PARAM_construct_utf8_string( 426 "pkcs11_key_usage", (char *)"digitalSignature", 0); 427 params[2] = OSSL_PARAM_construct_end(); 428 429 ctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", "provider=pkcs11"); 430 if (ctx == NULL) { 431 DST_RET(dst__openssl_toresult2("EVP_PKEY_CTX_new_from_name", 432 DST_R_OPENSSLFAILURE)); 433 } 434 435 status = EVP_PKEY_keygen_init(ctx); 436 if (status != 1) { 437 DST_RET(dst__openssl_toresult2("EVP_PKEY_keygen_init", 438 DST_R_OPENSSLFAILURE)); 439 } 440 441 status = EVP_PKEY_CTX_set_params(ctx, params); 442 if (status != 1) { 443 DST_RET(dst__openssl_toresult2("EVP_PKEY_CTX_set_params", 444 DST_R_OPENSSLFAILURE)); 445 } 446 /* 447 * Setting the P-384 curve doesn't work correctly when using: 448 * OSSL_PARAM_construct_utf8_string("ec_paramgen_curve", "P-384", 0); 449 * 450 * Instead use the OpenSSL function to set the curve nid param. 451 */ 452 status = EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx, group_nid); 453 if (status != 1) { 454 DST_RET(dst__openssl_toresult2("EVP_PKEY_CTX_set_ec_paramgen_" 455 "curve_nid", 456 DST_R_OPENSSLFAILURE)); 457 } 458 459 /* Generate the key. */ 460 status = EVP_PKEY_generate(ctx, retkey); 461 if (status != 1) { 462 DST_RET(dst__openssl_toresult2("EVP_PKEY_generate", 463 DST_R_OPENSSLFAILURE)); 464 } 465 466 ret = ISC_R_SUCCESS; 467 468 err: 469 EVP_PKEY_CTX_free(ctx); 470 return ret; 471 } 472 473 static isc_result_t 474 opensslecdsa_generate_pkey(unsigned int key_alg, const char *label, 475 EVP_PKEY **retkey) { 476 isc_result_t ret; 477 EVP_PKEY_CTX *ctx = NULL; 478 EVP_PKEY *params_pkey = NULL; 479 int group_nid = opensslecdsa_key_alg_to_group_nid(key_alg); 480 int status; 481 482 if (label != NULL) { 483 return opensslecdsa_generate_pkey_with_uri(group_nid, label, 484 retkey); 485 } 486 487 /* Generate the key's parameters. */ 488 ctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL); 489 if (ctx == NULL) { 490 DST_RET(dst__openssl_toresult2("EVP_PKEY_CTX_new_from_name", 491 DST_R_OPENSSLFAILURE)); 492 } 493 status = EVP_PKEY_paramgen_init(ctx); 494 if (status != 1) { 495 DST_RET(dst__openssl_toresult2("EVP_PKEY_paramgen_init", 496 DST_R_OPENSSLFAILURE)); 497 } 498 status = EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx, group_nid); 499 if (status != 1) { 500 DST_RET(dst__openssl_toresult2("EVP_PKEY_CTX_set_ec_paramgen_" 501 "curve_nid", 502 DST_R_OPENSSLFAILURE)); 503 } 504 status = EVP_PKEY_paramgen(ctx, ¶ms_pkey); 505 if (status != 1 || params_pkey == NULL) { 506 DST_RET(dst__openssl_toresult2("EVP_PKEY_paramgen", 507 DST_R_OPENSSLFAILURE)); 508 } 509 EVP_PKEY_CTX_free(ctx); 510 511 /* Generate the key. */ 512 ctx = EVP_PKEY_CTX_new(params_pkey, NULL); 513 if (ctx == NULL) { 514 DST_RET(dst__openssl_toresult2("EVP_PKEY_CTX_new", 515 DST_R_OPENSSLFAILURE)); 516 } 517 status = EVP_PKEY_keygen_init(ctx); 518 if (status != 1) { 519 DST_RET(dst__openssl_toresult2("EVP_PKEY_keygen_init", 520 DST_R_OPENSSLFAILURE)); 521 } 522 523 status = EVP_PKEY_keygen(ctx, retkey); 524 if (status != 1) { 525 DST_RET(dst__openssl_toresult2("EVP_PKEY_keygen", 526 DST_R_OPENSSLFAILURE)); 527 } 528 ret = ISC_R_SUCCESS; 529 530 err: 531 EVP_PKEY_free(params_pkey); 532 EVP_PKEY_CTX_free(ctx); 533 return ret; 534 } 535 536 static isc_result_t 537 opensslecdsa_validate_pkey_group(unsigned int key_alg, EVP_PKEY *pkey) { 538 const char *groupname = opensslecdsa_key_alg_to_group_name(key_alg); 539 char gname[64]; 540 541 if (EVP_PKEY_get_group_name(pkey, gname, sizeof(gname), NULL) != 1) { 542 return DST_R_INVALIDPRIVATEKEY; 543 } 544 if (strcmp(gname, groupname) != 0) { 545 return DST_R_INVALIDPRIVATEKEY; 546 } 547 return ISC_R_SUCCESS; 548 } 549 550 static bool 551 opensslecdsa_extract_private_key(const dst_key_t *key, unsigned char *buf, 552 size_t buflen) { 553 EVP_PKEY *pkey = key->keydata.pkeypair.priv; 554 BIGNUM *priv = NULL; 555 556 if (EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_PRIV_KEY, &priv) != 1) { 557 return false; 558 } 559 560 BN_bn2bin_fixed(priv, buf, buflen); 561 BN_clear_free(priv); 562 return true; 563 } 564 565 #else 566 567 static isc_result_t 568 opensslecdsa_generate_pkey(unsigned int key_alg, const char *label, 569 EVP_PKEY **retkey) { 570 isc_result_t ret; 571 EC_KEY *eckey = NULL; 572 EVP_PKEY *pkey = NULL; 573 int group_nid; 574 575 UNUSED(label); 576 577 group_nid = opensslecdsa_key_alg_to_group_nid(key_alg); 578 579 eckey = EC_KEY_new_by_curve_name(group_nid); 580 if (eckey == NULL) { 581 DST_RET(dst__openssl_toresult2("EC_KEY_new_by_curve_name", 582 DST_R_OPENSSLFAILURE)); 583 } 584 585 if (EC_KEY_generate_key(eckey) != 1) { 586 DST_RET(dst__openssl_toresult2("EC_KEY_generate_key", 587 DST_R_OPENSSLFAILURE)); 588 } 589 590 pkey = EVP_PKEY_new(); 591 if (pkey == NULL) { 592 DST_RET(dst__openssl_toresult(ISC_R_NOMEMORY)); 593 } 594 if (EVP_PKEY_set1_EC_KEY(pkey, eckey) != 1) { 595 DST_RET(dst__openssl_toresult2("EVP_PKEY_set1_EC_KEY", 596 DST_R_OPENSSLFAILURE)); 597 } 598 *retkey = pkey; 599 pkey = NULL; 600 ret = ISC_R_SUCCESS; 601 602 err: 603 EC_KEY_free(eckey); 604 EVP_PKEY_free(pkey); 605 return ret; 606 } 607 608 static isc_result_t 609 opensslecdsa_validate_pkey_group(unsigned int key_alg, EVP_PKEY *pkey) { 610 const EC_KEY *eckey = EVP_PKEY_get0_EC_KEY(pkey); 611 int group_nid; 612 613 if (eckey == NULL) { 614 return dst__openssl_toresult(DST_R_INVALIDPRIVATEKEY); 615 } 616 617 group_nid = opensslecdsa_key_alg_to_group_nid(key_alg); 618 619 if (EC_GROUP_get_curve_name(EC_KEY_get0_group(eckey)) != group_nid) { 620 return DST_R_INVALIDPRIVATEKEY; 621 } 622 623 return ISC_R_SUCCESS; 624 } 625 626 static bool 627 opensslecdsa_extract_private_key(const dst_key_t *key, unsigned char *buf, 628 size_t buflen) { 629 const EC_KEY *eckey = NULL; 630 const BIGNUM *privkey = NULL; 631 632 eckey = EVP_PKEY_get0_EC_KEY(key->keydata.pkeypair.priv); 633 if (eckey == NULL) { 634 ERR_clear_error(); 635 return false; 636 } 637 638 privkey = EC_KEY_get0_private_key(eckey); 639 if (privkey == NULL) { 640 ERR_clear_error(); 641 return false; 642 } 643 644 BN_bn2bin_fixed(privkey, buf, buflen); 645 return true; 646 } 647 648 #endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ 649 650 static isc_result_t 651 opensslecdsa_createctx(dst_key_t *key, dst_context_t *dctx) { 652 isc_result_t ret = ISC_R_SUCCESS; 653 EVP_MD_CTX *evp_md_ctx; 654 const EVP_MD *type = NULL; 655 656 UNUSED(key); 657 REQUIRE(opensslecdsa_valid_key_alg(dctx->key->key_alg)); 658 REQUIRE(dctx->use == DO_SIGN || dctx->use == DO_VERIFY); 659 660 evp_md_ctx = EVP_MD_CTX_create(); 661 if (evp_md_ctx == NULL) { 662 DST_RET(dst__openssl_toresult(ISC_R_NOMEMORY)); 663 } 664 if (dctx->key->key_alg == DST_ALG_ECDSA256) { 665 type = EVP_sha256(); 666 } else { 667 type = EVP_sha384(); 668 } 669 670 if (dctx->use == DO_SIGN) { 671 if (EVP_DigestSignInit(evp_md_ctx, NULL, type, NULL, 672 dctx->key->keydata.pkeypair.priv) != 1) 673 { 674 EVP_MD_CTX_destroy(evp_md_ctx); 675 DST_RET(dst__openssl_toresult3(dctx->category, 676 "EVP_DigestSignInit", 677 ISC_R_FAILURE)); 678 } 679 } else { 680 if (EVP_DigestVerifyInit(evp_md_ctx, NULL, type, NULL, 681 dctx->key->keydata.pkeypair.pub) != 1) 682 { 683 EVP_MD_CTX_destroy(evp_md_ctx); 684 DST_RET(dst__openssl_toresult3(dctx->category, 685 "EVP_DigestVerifyInit", 686 ISC_R_FAILURE)); 687 } 688 } 689 690 dctx->ctxdata.evp_md_ctx = evp_md_ctx; 691 692 err: 693 return ret; 694 } 695 696 static void 697 opensslecdsa_destroyctx(dst_context_t *dctx) { 698 EVP_MD_CTX *evp_md_ctx = dctx->ctxdata.evp_md_ctx; 699 700 REQUIRE(opensslecdsa_valid_key_alg(dctx->key->key_alg)); 701 REQUIRE(dctx->use == DO_SIGN || dctx->use == DO_VERIFY); 702 703 if (evp_md_ctx != NULL) { 704 EVP_MD_CTX_destroy(evp_md_ctx); 705 dctx->ctxdata.evp_md_ctx = NULL; 706 } 707 } 708 709 static isc_result_t 710 opensslecdsa_adddata(dst_context_t *dctx, const isc_region_t *data) { 711 isc_result_t ret = ISC_R_SUCCESS; 712 EVP_MD_CTX *evp_md_ctx = dctx->ctxdata.evp_md_ctx; 713 714 REQUIRE(opensslecdsa_valid_key_alg(dctx->key->key_alg)); 715 REQUIRE(dctx->use == DO_SIGN || dctx->use == DO_VERIFY); 716 717 if (dctx->use == DO_SIGN) { 718 if (EVP_DigestSignUpdate(evp_md_ctx, data->base, 719 data->length) != 1) 720 { 721 DST_RET(dst__openssl_toresult3(dctx->category, 722 "EVP_DigestSignUpdate", 723 ISC_R_FAILURE)); 724 } 725 } else { 726 if (EVP_DigestVerifyUpdate(evp_md_ctx, data->base, 727 data->length) != 1) 728 { 729 DST_RET(dst__openssl_toresult3(dctx->category, 730 "EVP_DigestVerifyUpdate", 731 ISC_R_FAILURE)); 732 } 733 } 734 735 err: 736 return ret; 737 } 738 739 static isc_result_t 740 opensslecdsa_sign(dst_context_t *dctx, isc_buffer_t *sig) { 741 isc_result_t ret; 742 dst_key_t *key = dctx->key; 743 isc_region_t region; 744 EVP_MD_CTX *evp_md_ctx = dctx->ctxdata.evp_md_ctx; 745 ECDSA_SIG *ecdsasig = NULL; 746 size_t siglen, sigder_len = 0, sigder_alloced = 0; 747 unsigned char *sigder = NULL; 748 const unsigned char *sigder_copy; 749 const BIGNUM *r, *s; 750 751 REQUIRE(opensslecdsa_valid_key_alg(key->key_alg)); 752 REQUIRE(dctx->use == DO_SIGN); 753 754 if (key->key_alg == DST_ALG_ECDSA256) { 755 siglen = DNS_SIG_ECDSA256SIZE; 756 } else { 757 siglen = DNS_SIG_ECDSA384SIZE; 758 } 759 760 isc_buffer_availableregion(sig, ®ion); 761 if (region.length < siglen) { 762 DST_RET(ISC_R_NOSPACE); 763 } 764 765 if (EVP_DigestSignFinal(evp_md_ctx, NULL, &sigder_len) != 1) { 766 DST_RET(dst__openssl_toresult3( 767 dctx->category, "EVP_DigestSignFinal", ISC_R_FAILURE)); 768 } 769 if (sigder_len == 0) { 770 DST_RET(ISC_R_FAILURE); 771 } 772 sigder = isc_mem_get(dctx->mctx, sigder_len); 773 sigder_alloced = sigder_len; 774 if (EVP_DigestSignFinal(evp_md_ctx, sigder, &sigder_len) != 1) { 775 DST_RET(dst__openssl_toresult3( 776 dctx->category, "EVP_DigestSignFinal", ISC_R_FAILURE)); 777 } 778 sigder_copy = sigder; 779 if (d2i_ECDSA_SIG(&ecdsasig, &sigder_copy, sigder_len) == NULL) { 780 DST_RET(dst__openssl_toresult3(dctx->category, "d2i_ECDSA_SIG", 781 ISC_R_FAILURE)); 782 } 783 784 ECDSA_SIG_get0(ecdsasig, &r, &s); 785 BN_bn2bin_fixed(r, region.base, siglen / 2); 786 isc_region_consume(®ion, siglen / 2); 787 BN_bn2bin_fixed(s, region.base, siglen / 2); 788 isc_region_consume(®ion, siglen / 2); 789 ECDSA_SIG_free(ecdsasig); 790 isc_buffer_add(sig, siglen); 791 ret = ISC_R_SUCCESS; 792 793 err: 794 if (sigder != NULL && sigder_alloced != 0) { 795 isc_mem_put(dctx->mctx, sigder, sigder_alloced); 796 } 797 798 return ret; 799 } 800 801 static isc_result_t 802 opensslecdsa_verify(dst_context_t *dctx, const isc_region_t *sig) { 803 isc_result_t ret; 804 dst_key_t *key = dctx->key; 805 int status; 806 unsigned char *cp = sig->base; 807 ECDSA_SIG *ecdsasig = NULL; 808 EVP_MD_CTX *evp_md_ctx = dctx->ctxdata.evp_md_ctx; 809 size_t siglen, sigder_len = 0, sigder_alloced = 0; 810 unsigned char *sigder = NULL; 811 unsigned char *sigder_copy; 812 BIGNUM *r = NULL, *s = NULL; 813 814 REQUIRE(opensslecdsa_valid_key_alg(key->key_alg)); 815 REQUIRE(dctx->use == DO_VERIFY); 816 817 if (key->key_alg == DST_ALG_ECDSA256) { 818 siglen = DNS_SIG_ECDSA256SIZE; 819 } else { 820 siglen = DNS_SIG_ECDSA384SIZE; 821 } 822 823 if (sig->length != siglen) { 824 DST_RET(DST_R_VERIFYFAILURE); 825 } 826 827 ecdsasig = ECDSA_SIG_new(); 828 if (ecdsasig == NULL) { 829 DST_RET(dst__openssl_toresult(ISC_R_NOMEMORY)); 830 } 831 r = BN_bin2bn(cp, siglen / 2, NULL); 832 cp += siglen / 2; 833 s = BN_bin2bn(cp, siglen / 2, NULL); 834 /* cp += siglen / 2; */ 835 ECDSA_SIG_set0(ecdsasig, r, s); 836 837 status = i2d_ECDSA_SIG(ecdsasig, NULL); 838 if (status < 0) { 839 DST_RET(dst__openssl_toresult3(dctx->category, "i2d_ECDSA_SIG", 840 DST_R_VERIFYFAILURE)); 841 } 842 843 sigder_len = (size_t)status; 844 sigder = isc_mem_get(dctx->mctx, sigder_len); 845 sigder_alloced = sigder_len; 846 847 sigder_copy = sigder; 848 status = i2d_ECDSA_SIG(ecdsasig, &sigder_copy); 849 if (status < 0) { 850 DST_RET(dst__openssl_toresult3(dctx->category, "i2d_ECDSA_SIG", 851 DST_R_VERIFYFAILURE)); 852 } 853 854 status = EVP_DigestVerifyFinal(evp_md_ctx, sigder, sigder_len); 855 856 switch (status) { 857 case 1: 858 ret = ISC_R_SUCCESS; 859 break; 860 case 0: 861 ret = dst__openssl_toresult(DST_R_VERIFYFAILURE); 862 break; 863 default: 864 ret = dst__openssl_toresult3(dctx->category, 865 "EVP_DigestVerifyFinal", 866 DST_R_VERIFYFAILURE); 867 break; 868 } 869 870 err: 871 if (ecdsasig != NULL) { 872 ECDSA_SIG_free(ecdsasig); 873 } 874 if (sigder != NULL && sigder_alloced != 0) { 875 isc_mem_put(dctx->mctx, sigder, sigder_alloced); 876 } 877 878 return ret; 879 } 880 881 static isc_result_t 882 opensslecdsa_generate(dst_key_t *key, int unused, void (*callback)(int)) { 883 isc_result_t ret; 884 EVP_PKEY *pkey = NULL; 885 886 REQUIRE(opensslecdsa_valid_key_alg(key->key_alg)); 887 UNUSED(unused); 888 UNUSED(callback); 889 890 ret = opensslecdsa_generate_pkey(key->key_alg, key->label, &pkey); 891 if (ret != ISC_R_SUCCESS) { 892 return ret; 893 } 894 895 key->key_size = EVP_PKEY_bits(pkey); 896 key->keydata.pkeypair.priv = pkey; 897 key->keydata.pkeypair.pub = pkey; 898 return ret; 899 } 900 901 static isc_result_t 902 opensslecdsa_todns(const dst_key_t *key, isc_buffer_t *data) { 903 isc_result_t ret; 904 isc_region_t r; 905 size_t keysize; 906 907 REQUIRE(opensslecdsa_valid_key_alg(key->key_alg)); 908 REQUIRE(key->keydata.pkeypair.pub != NULL); 909 910 keysize = opensslecdsa_key_alg_to_publickey_size(key->key_alg); 911 isc_buffer_availableregion(data, &r); 912 if (r.length < keysize) { 913 DST_RET(ISC_R_NOSPACE); 914 } 915 if (!opensslecdsa_extract_public_key(key, r.base, keysize)) { 916 DST_RET(dst__openssl_toresult(DST_R_OPENSSLFAILURE)); 917 } 918 919 isc_buffer_add(data, keysize); 920 ret = ISC_R_SUCCESS; 921 922 err: 923 return ret; 924 } 925 926 static isc_result_t 927 opensslecdsa_fromdns(dst_key_t *key, isc_buffer_t *data) { 928 isc_result_t ret; 929 EVP_PKEY *pkey = NULL; 930 isc_region_t r; 931 size_t len; 932 933 REQUIRE(opensslecdsa_valid_key_alg(key->key_alg)); 934 len = opensslecdsa_key_alg_to_publickey_size(key->key_alg); 935 936 isc_buffer_remainingregion(data, &r); 937 if (r.length == 0) { 938 DST_RET(ISC_R_SUCCESS); 939 } 940 if (r.length != len) { 941 DST_RET(DST_R_INVALIDPUBLICKEY); 942 } 943 944 ret = opensslecdsa_create_pkey(key->key_alg, false, r.base, len, &pkey); 945 if (ret != ISC_R_SUCCESS) { 946 DST_RET(ret); 947 } 948 949 isc_buffer_forward(data, len); 950 key->key_size = EVP_PKEY_bits(pkey); 951 key->keydata.pkeypair.pub = pkey; 952 ret = ISC_R_SUCCESS; 953 954 err: 955 return ret; 956 } 957 958 static isc_result_t 959 opensslecdsa_tofile(const dst_key_t *key, const char *directory) { 960 isc_result_t ret; 961 dst_private_t priv; 962 unsigned char buf[MAX_PRIVKEY_SIZE]; 963 size_t keylen = 0; 964 unsigned short i; 965 966 if (key->keydata.pkeypair.pub == NULL) { 967 DST_RET(DST_R_NULLKEY); 968 } 969 970 if (key->external) { 971 priv.nelements = 0; 972 DST_RET(dst__privstruct_writefile(key, &priv, directory)); 973 } 974 975 if (key->keydata.pkeypair.priv == NULL) { 976 DST_RET(DST_R_NULLKEY); 977 } 978 979 keylen = opensslecdsa_key_alg_to_publickey_size(key->key_alg) / 2; 980 INSIST(keylen <= sizeof(buf)); 981 982 i = 0; 983 if (opensslecdsa_extract_private_key(key, buf, keylen)) { 984 priv.elements[i].tag = TAG_ECDSA_PRIVATEKEY; 985 priv.elements[i].length = keylen; 986 priv.elements[i].data = buf; 987 i++; 988 } 989 if (key->engine != NULL) { 990 priv.elements[i].tag = TAG_ECDSA_ENGINE; 991 priv.elements[i].length = (unsigned short)strlen(key->engine) + 992 1; 993 priv.elements[i].data = (unsigned char *)key->engine; 994 i++; 995 } 996 997 if (key->label != NULL) { 998 priv.elements[i].tag = TAG_ECDSA_LABEL; 999 priv.elements[i].length = (unsigned short)strlen(key->label) + 1000 1; 1001 priv.elements[i].data = (unsigned char *)key->label; 1002 i++; 1003 } 1004 1005 priv.nelements = i; 1006 ret = dst__privstruct_writefile(key, &priv, directory); 1007 1008 err: 1009 isc_safe_memwipe(buf, keylen); 1010 return ret; 1011 } 1012 1013 static isc_result_t 1014 opensslecdsa_fromlabel(dst_key_t *key, const char *engine, const char *label, 1015 const char *pin); 1016 1017 static isc_result_t 1018 opensslecdsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { 1019 dst_private_t priv; 1020 isc_result_t ret; 1021 EVP_PKEY *pkey = NULL; 1022 const char *engine = NULL; 1023 const char *label = NULL; 1024 int i, privkey_index = -1; 1025 1026 REQUIRE(opensslecdsa_valid_key_alg(key->key_alg)); 1027 1028 /* read private key file */ 1029 ret = dst__privstruct_parse(key, DST_ALG_ECDSA256, lexer, key->mctx, 1030 &priv); 1031 if (ret != ISC_R_SUCCESS) { 1032 goto err; 1033 } 1034 1035 if (key->external) { 1036 if (priv.nelements != 0 || pub == NULL) { 1037 DST_RET(dst__openssl_toresult(DST_R_INVALIDPRIVATEKEY)); 1038 } 1039 key->keydata.pkeypair.priv = pub->keydata.pkeypair.priv; 1040 key->keydata.pkeypair.pub = pub->keydata.pkeypair.pub; 1041 pub->keydata.pkeypair.priv = NULL; 1042 pub->keydata.pkeypair.pub = NULL; 1043 DST_RET(ISC_R_SUCCESS); 1044 } 1045 1046 for (i = 0; i < priv.nelements; i++) { 1047 switch (priv.elements[i].tag) { 1048 case TAG_ECDSA_ENGINE: 1049 engine = (char *)priv.elements[i].data; 1050 break; 1051 case TAG_ECDSA_LABEL: 1052 label = (char *)priv.elements[i].data; 1053 break; 1054 case TAG_ECDSA_PRIVATEKEY: 1055 privkey_index = i; 1056 break; 1057 default: 1058 break; 1059 } 1060 } 1061 1062 if (label != NULL) { 1063 ret = opensslecdsa_fromlabel(key, engine, label, NULL); 1064 if (ret != ISC_R_SUCCESS) { 1065 goto err; 1066 } 1067 /* Check that the public component matches if given */ 1068 if (pub != NULL && EVP_PKEY_eq(key->keydata.pkeypair.pub, 1069 pub->keydata.pkeypair.pub) != 1) 1070 { 1071 DST_RET(DST_R_INVALIDPRIVATEKEY); 1072 } 1073 DST_RET(ISC_R_SUCCESS); 1074 } 1075 1076 if (privkey_index < 0) { 1077 DST_RET(dst__openssl_toresult(DST_R_INVALIDPRIVATEKEY)); 1078 } 1079 1080 ret = opensslecdsa_create_pkey( 1081 key->key_alg, true, priv.elements[privkey_index].data, 1082 priv.elements[privkey_index].length, &pkey); 1083 if (ret != ISC_R_SUCCESS) { 1084 goto err; 1085 } 1086 1087 /* Check that the public component matches if given */ 1088 if (pub != NULL && EVP_PKEY_eq(pkey, pub->keydata.pkeypair.pub) != 1) { 1089 DST_RET(DST_R_INVALIDPRIVATEKEY); 1090 } 1091 1092 key->key_size = EVP_PKEY_bits(pkey); 1093 key->keydata.pkeypair.priv = pkey; 1094 key->keydata.pkeypair.pub = pkey; 1095 pkey = NULL; 1096 1097 err: 1098 EVP_PKEY_free(pkey); 1099 if (ret != ISC_R_SUCCESS) { 1100 key->keydata.generic = NULL; 1101 } 1102 dst__privstruct_free(&priv, key->mctx); 1103 isc_safe_memwipe(&priv, sizeof(priv)); 1104 1105 return ret; 1106 } 1107 1108 static isc_result_t 1109 opensslecdsa_fromlabel(dst_key_t *key, const char *engine, const char *label, 1110 const char *pin) { 1111 EVP_PKEY *privpkey = NULL, *pubpkey = NULL; 1112 isc_result_t ret; 1113 1114 REQUIRE(opensslecdsa_valid_key_alg(key->key_alg)); 1115 UNUSED(pin); 1116 1117 ret = dst__openssl_fromlabel(EVP_PKEY_EC, engine, label, pin, &pubpkey, 1118 &privpkey); 1119 if (ret != ISC_R_SUCCESS) { 1120 goto err; 1121 } 1122 1123 ret = opensslecdsa_validate_pkey_group(key->key_alg, privpkey); 1124 if (ret != ISC_R_SUCCESS) { 1125 goto err; 1126 } 1127 ret = opensslecdsa_validate_pkey_group(key->key_alg, pubpkey); 1128 if (ret != ISC_R_SUCCESS) { 1129 goto err; 1130 } 1131 1132 if (engine != NULL) { 1133 key->engine = isc_mem_strdup(key->mctx, engine); 1134 } 1135 key->label = isc_mem_strdup(key->mctx, label); 1136 key->key_size = EVP_PKEY_bits(privpkey); 1137 key->keydata.pkeypair.priv = privpkey; 1138 key->keydata.pkeypair.pub = pubpkey; 1139 privpkey = NULL; 1140 pubpkey = NULL; 1141 1142 err: 1143 EVP_PKEY_free(privpkey); 1144 EVP_PKEY_free(pubpkey); 1145 return ret; 1146 } 1147 1148 static dst_func_t opensslecdsa_functions = { 1149 opensslecdsa_createctx, 1150 NULL, /*%< createctx2 */ 1151 opensslecdsa_destroyctx, 1152 opensslecdsa_adddata, 1153 opensslecdsa_sign, 1154 opensslecdsa_verify, 1155 NULL, /*%< verify2 */ 1156 NULL, /*%< computesecret */ 1157 dst__openssl_keypair_compare, 1158 NULL, /*%< paramcompare */ 1159 opensslecdsa_generate, 1160 dst__openssl_keypair_isprivate, 1161 dst__openssl_keypair_destroy, 1162 opensslecdsa_todns, 1163 opensslecdsa_fromdns, 1164 opensslecdsa_tofile, 1165 opensslecdsa_parse, 1166 NULL, /*%< cleanup */ 1167 opensslecdsa_fromlabel, /*%< fromlabel */ 1168 NULL, /*%< dump */ 1169 NULL, /*%< restore */ 1170 }; 1171 1172 isc_result_t 1173 dst__opensslecdsa_init(dst_func_t **funcp) { 1174 REQUIRE(funcp != NULL); 1175 if (*funcp == NULL) { 1176 *funcp = &opensslecdsa_functions; 1177 } 1178 return ISC_R_SUCCESS; 1179 } 1180