1 /* $OpenBSD: ec_pmeth.c,v 1.24 2025/01/05 16:07:08 tb Exp $ */ 2 /* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL 3 * project 2006. 4 */ 5 /* ==================================================================== 6 * Copyright (c) 2006 The OpenSSL Project. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in 17 * the documentation and/or other materials provided with the 18 * distribution. 19 * 20 * 3. All advertising materials mentioning features or use of this 21 * software must display the following acknowledgment: 22 * "This product includes software developed by the OpenSSL Project 23 * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" 24 * 25 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to 26 * endorse or promote products derived from this software without 27 * prior written permission. For written permission, please contact 28 * licensing@OpenSSL.org. 29 * 30 * 5. Products derived from this software may not be called "OpenSSL" 31 * nor may "OpenSSL" appear in their names without prior written 32 * permission of the OpenSSL Project. 33 * 34 * 6. Redistributions of any form whatsoever must retain the following 35 * acknowledgment: 36 * "This product includes software developed by the OpenSSL Project 37 * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" 38 * 39 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY 40 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 41 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 42 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR 43 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 44 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 45 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 46 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 47 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 48 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 49 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 50 * OF THE POSSIBILITY OF SUCH DAMAGE. 51 * ==================================================================== 52 * 53 * This product includes cryptographic software written by Eric Young 54 * (eay@cryptsoft.com). This product includes software written by Tim 55 * Hudson (tjh@cryptsoft.com). 56 * 57 */ 58 59 #include <stdio.h> 60 #include <stdlib.h> 61 #include <string.h> 62 63 #include <openssl/asn1t.h> 64 #include <openssl/ec.h> 65 #include <openssl/err.h> 66 #include <openssl/evp.h> 67 #include <openssl/x509.h> 68 69 #include "bn_local.h" 70 #include "ec_local.h" 71 #include "evp_local.h" 72 73 /* EC pkey context structure */ 74 75 typedef struct { 76 /* Key and paramgen group */ 77 EC_GROUP *gen_group; 78 /* message digest */ 79 const EVP_MD *md; 80 /* Duplicate key if custom cofactor needed */ 81 EC_KEY *co_key; 82 /* Cofactor mode */ 83 signed char cofactor_mode; 84 /* KDF (if any) to use for ECDH */ 85 char kdf_type; 86 /* Message digest to use for key derivation */ 87 const EVP_MD *kdf_md; 88 /* User key material */ 89 unsigned char *kdf_ukm; 90 size_t kdf_ukmlen; 91 /* KDF output length */ 92 size_t kdf_outlen; 93 } EC_PKEY_CTX; 94 95 static int 96 pkey_ec_init(EVP_PKEY_CTX *ctx) 97 { 98 EC_PKEY_CTX *dctx; 99 100 if ((dctx = calloc(1, sizeof(EC_PKEY_CTX))) == NULL) { 101 ECerror(ERR_R_MALLOC_FAILURE); 102 return 0; 103 } 104 105 dctx->cofactor_mode = -1; 106 dctx->kdf_type = EVP_PKEY_ECDH_KDF_NONE; 107 108 ctx->data = dctx; 109 110 return 1; 111 } 112 113 static int 114 pkey_ec_copy(EVP_PKEY_CTX *dst, EVP_PKEY_CTX *src) 115 { 116 EC_PKEY_CTX *dctx, *sctx; 117 if (!pkey_ec_init(dst)) 118 return 0; 119 sctx = src->data; 120 dctx = dst->data; 121 if (sctx->gen_group) { 122 dctx->gen_group = EC_GROUP_dup(sctx->gen_group); 123 if (!dctx->gen_group) 124 return 0; 125 } 126 dctx->md = sctx->md; 127 128 if (sctx->co_key) { 129 dctx->co_key = EC_KEY_dup(sctx->co_key); 130 if (!dctx->co_key) 131 return 0; 132 } 133 dctx->kdf_type = sctx->kdf_type; 134 dctx->kdf_md = sctx->kdf_md; 135 dctx->kdf_outlen = sctx->kdf_outlen; 136 if (sctx->kdf_ukm) { 137 if ((dctx->kdf_ukm = calloc(1, sctx->kdf_ukmlen)) == NULL) 138 return 0; 139 memcpy(dctx->kdf_ukm, sctx->kdf_ukm, sctx->kdf_ukmlen); 140 } else 141 dctx->kdf_ukm = NULL; 142 143 dctx->kdf_ukmlen = sctx->kdf_ukmlen; 144 145 return 1; 146 } 147 148 static void 149 pkey_ec_cleanup(EVP_PKEY_CTX *ctx) 150 { 151 EC_PKEY_CTX *dctx = ctx->data; 152 153 if (dctx != NULL) { 154 EC_GROUP_free(dctx->gen_group); 155 EC_KEY_free(dctx->co_key); 156 free(dctx->kdf_ukm); 157 free(dctx); 158 ctx->data = NULL; 159 } 160 } 161 162 static int 163 pkey_ec_sign(EVP_PKEY_CTX *ctx, unsigned char *sig, size_t *siglen, 164 const unsigned char *tbs, size_t tbslen) 165 { 166 int ret, type; 167 unsigned int sltmp; 168 EC_PKEY_CTX *dctx = ctx->data; 169 EC_KEY *ec = ctx->pkey->pkey.ec; 170 171 if (!sig) { 172 *siglen = ECDSA_size(ec); 173 return 1; 174 } else if (*siglen < (size_t) ECDSA_size(ec)) { 175 ECerror(EC_R_BUFFER_TOO_SMALL); 176 return 0; 177 } 178 if (dctx->md) 179 type = EVP_MD_type(dctx->md); 180 else 181 type = NID_sha1; 182 183 ret = ECDSA_sign(type, tbs, tbslen, sig, &sltmp, ec); 184 if (ret <= 0) 185 return ret; 186 *siglen = (size_t) sltmp; 187 return 1; 188 } 189 190 static int 191 pkey_ec_verify(EVP_PKEY_CTX *ctx, 192 const unsigned char *sig, size_t siglen, 193 const unsigned char *tbs, size_t tbslen) 194 { 195 int ret, type; 196 EC_PKEY_CTX *dctx = ctx->data; 197 EC_KEY *ec = ctx->pkey->pkey.ec; 198 199 if (dctx->md) 200 type = EVP_MD_type(dctx->md); 201 else 202 type = NID_sha1; 203 204 ret = ECDSA_verify(type, tbs, tbslen, sig, siglen, ec); 205 206 return ret; 207 } 208 209 static int 210 pkey_ec_derive(EVP_PKEY_CTX *ctx, unsigned char *key, size_t *keylen) 211 { 212 int ret; 213 size_t outlen; 214 const EC_POINT *pubkey = NULL; 215 EC_KEY *eckey; 216 EC_PKEY_CTX *dctx = ctx->data; 217 218 if (!ctx->pkey || !ctx->peerkey) { 219 ECerror(EC_R_KEYS_NOT_SET); 220 return 0; 221 } 222 223 eckey = dctx->co_key ? dctx->co_key : ctx->pkey->pkey.ec; 224 if (!key) { 225 const EC_GROUP *group; 226 group = EC_KEY_get0_group(eckey); 227 *keylen = (EC_GROUP_get_degree(group) + 7) / 8; 228 return 1; 229 } 230 pubkey = EC_KEY_get0_public_key(ctx->peerkey->pkey.ec); 231 232 /* 233 * NB: unlike PKCS#3 DH, if *outlen is less than maximum size this is 234 * not an error, the result is truncated. 235 */ 236 237 outlen = *keylen; 238 239 ret = ECDH_compute_key(key, outlen, pubkey, eckey, 0); 240 if (ret <= 0) 241 return 0; 242 243 *keylen = ret; 244 245 return 1; 246 } 247 248 static int 249 pkey_ec_kdf_derive(EVP_PKEY_CTX *ctx, unsigned char *key, size_t *keylen) 250 { 251 EC_PKEY_CTX *dctx = ctx->data; 252 unsigned char *ktmp = NULL; 253 size_t ktmplen; 254 int rv = 0; 255 256 if (dctx->kdf_type == EVP_PKEY_ECDH_KDF_NONE) 257 return pkey_ec_derive(ctx, key, keylen); 258 259 if (!key) { 260 *keylen = dctx->kdf_outlen; 261 return 1; 262 } 263 if (*keylen != dctx->kdf_outlen) 264 return 0; 265 if (!pkey_ec_derive(ctx, NULL, &ktmplen)) 266 return 0; 267 if ((ktmp = calloc(1, ktmplen)) == NULL) { 268 ECerror(ERR_R_MALLOC_FAILURE); 269 return 0; 270 } 271 if (!pkey_ec_derive(ctx, ktmp, &ktmplen)) 272 goto err; 273 /* Do KDF stuff */ 274 if (!ecdh_KDF_X9_63(key, *keylen, ktmp, ktmplen, dctx->kdf_ukm, 275 dctx->kdf_ukmlen, dctx->kdf_md)) 276 goto err; 277 rv = 1; 278 279 err: 280 freezero(ktmp, ktmplen); 281 282 return rv; 283 } 284 285 static int 286 pkey_ec_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2) 287 { 288 EC_PKEY_CTX *dctx = ctx->data; 289 EC_GROUP *group; 290 291 switch (type) { 292 case EVP_PKEY_CTRL_EC_PARAMGEN_CURVE_NID: 293 group = EC_GROUP_new_by_curve_name(p1); 294 if (group == NULL) { 295 ECerror(EC_R_INVALID_CURVE); 296 return 0; 297 } 298 EC_GROUP_free(dctx->gen_group); 299 dctx->gen_group = group; 300 return 1; 301 302 case EVP_PKEY_CTRL_EC_PARAM_ENC: 303 if (!dctx->gen_group) { 304 ECerror(EC_R_NO_PARAMETERS_SET); 305 return 0; 306 } 307 EC_GROUP_set_asn1_flag(dctx->gen_group, p1); 308 return 1; 309 310 case EVP_PKEY_CTRL_EC_ECDH_COFACTOR: 311 if (p1 == -2) { 312 if (dctx->cofactor_mode != -1) 313 return dctx->cofactor_mode; 314 else { 315 EC_KEY *ec_key = ctx->pkey->pkey.ec; 316 return EC_KEY_get_flags(ec_key) & EC_FLAG_COFACTOR_ECDH ? 1 : 0; 317 } 318 } else if (p1 < -1 || p1 > 1) 319 return -2; 320 dctx->cofactor_mode = p1; 321 if (p1 != -1) { 322 EC_KEY *ec_key = ctx->pkey->pkey.ec; 323 if (!ec_key->group) 324 return -2; 325 /* If cofactor is 1 cofactor mode does nothing */ 326 if (BN_is_one(ec_key->group->cofactor)) 327 return 1; 328 if (!dctx->co_key) { 329 dctx->co_key = EC_KEY_dup(ec_key); 330 if (!dctx->co_key) 331 return 0; 332 } 333 if (p1) 334 EC_KEY_set_flags(dctx->co_key, EC_FLAG_COFACTOR_ECDH); 335 else 336 EC_KEY_clear_flags(dctx->co_key, EC_FLAG_COFACTOR_ECDH); 337 } else { 338 EC_KEY_free(dctx->co_key); 339 dctx->co_key = NULL; 340 } 341 return 1; 342 343 case EVP_PKEY_CTRL_EC_KDF_TYPE: 344 if (p1 == -2) 345 return dctx->kdf_type; 346 if (p1 != EVP_PKEY_ECDH_KDF_NONE && p1 != EVP_PKEY_ECDH_KDF_X9_63) 347 return -2; 348 dctx->kdf_type = p1; 349 return 1; 350 351 case EVP_PKEY_CTRL_EC_KDF_MD: 352 dctx->kdf_md = p2; 353 return 1; 354 355 case EVP_PKEY_CTRL_GET_EC_KDF_MD: 356 *(const EVP_MD **)p2 = dctx->kdf_md; 357 return 1; 358 359 case EVP_PKEY_CTRL_EC_KDF_OUTLEN: 360 if (p1 <= 0) 361 return -2; 362 dctx->kdf_outlen = (size_t)p1; 363 return 1; 364 365 case EVP_PKEY_CTRL_GET_EC_KDF_OUTLEN: 366 *(int *)p2 = dctx->kdf_outlen; 367 return 1; 368 369 case EVP_PKEY_CTRL_EC_KDF_UKM: 370 free(dctx->kdf_ukm); 371 dctx->kdf_ukm = p2; 372 if (p2) 373 dctx->kdf_ukmlen = p1; 374 else 375 dctx->kdf_ukmlen = 0; 376 return 1; 377 378 case EVP_PKEY_CTRL_GET_EC_KDF_UKM: 379 *(unsigned char **)p2 = dctx->kdf_ukm; 380 return dctx->kdf_ukmlen; 381 382 case EVP_PKEY_CTRL_MD: 383 /* RFC 3279, RFC 5758 and NIST CSOR. */ 384 switch (EVP_MD_type(p2)) { 385 case NID_sha1: 386 case NID_ecdsa_with_SHA1: 387 case NID_sha224: 388 case NID_sha256: 389 case NID_sha384: 390 case NID_sha512: 391 case NID_sha3_224: 392 case NID_sha3_256: 393 case NID_sha3_384: 394 case NID_sha3_512: 395 break; 396 default: 397 ECerror(EC_R_INVALID_DIGEST_TYPE); 398 return 0; 399 } 400 dctx->md = p2; 401 return 1; 402 403 case EVP_PKEY_CTRL_GET_MD: 404 *(const EVP_MD **)p2 = dctx->md; 405 return 1; 406 407 case EVP_PKEY_CTRL_PEER_KEY: 408 /* Default behaviour is OK */ 409 case EVP_PKEY_CTRL_DIGESTINIT: 410 case EVP_PKEY_CTRL_PKCS7_SIGN: 411 case EVP_PKEY_CTRL_CMS_SIGN: 412 return 1; 413 414 default: 415 return -2; 416 417 } 418 } 419 420 static int 421 pkey_ec_ctrl_str(EVP_PKEY_CTX *ctx, const char *type, const char *value) 422 { 423 if (!strcmp(type, "ec_paramgen_curve")) { 424 int nid; 425 nid = EC_curve_nist2nid(value); 426 if (nid == NID_undef) 427 nid = OBJ_sn2nid(value); 428 if (nid == NID_undef) 429 nid = OBJ_ln2nid(value); 430 if (nid == NID_undef) { 431 ECerror(EC_R_INVALID_CURVE); 432 return 0; 433 } 434 return EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx, nid); 435 } else if (strcmp(type, "ec_param_enc") == 0) { 436 int param_enc; 437 if (strcmp(value, "explicit") == 0) 438 param_enc = 0; 439 else if (strcmp(value, "named_curve") == 0) 440 param_enc = OPENSSL_EC_NAMED_CURVE; 441 else 442 return -2; 443 return EVP_PKEY_CTX_set_ec_param_enc(ctx, param_enc); 444 } else if (strcmp(type, "ecdh_kdf_md") == 0) { 445 const EVP_MD *md; 446 if ((md = EVP_get_digestbyname(value)) == NULL) { 447 ECerror(EC_R_INVALID_DIGEST); 448 return 0; 449 } 450 return EVP_PKEY_CTX_set_ecdh_kdf_md(ctx, md); 451 } else if (strcmp(type, "ecdh_cofactor_mode") == 0) { 452 int cofactor_mode; 453 const char *errstr; 454 455 cofactor_mode = strtonum(value, -1, 1, &errstr); 456 if (errstr != NULL) 457 return -2; 458 return EVP_PKEY_CTX_set_ecdh_cofactor_mode(ctx, cofactor_mode); 459 } 460 461 return -2; 462 } 463 464 static int 465 pkey_ec_paramgen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) 466 { 467 EC_KEY *ec = NULL; 468 EC_PKEY_CTX *dctx = ctx->data; 469 int ret = 0; 470 471 if (dctx->gen_group == NULL) { 472 ECerror(EC_R_NO_PARAMETERS_SET); 473 goto err; 474 } 475 476 if ((ec = EC_KEY_new()) == NULL) 477 goto err; 478 if (!EC_KEY_set_group(ec, dctx->gen_group)) 479 goto err; 480 if (!EVP_PKEY_assign_EC_KEY(pkey, ec)) 481 goto err; 482 ec = NULL; 483 484 ret = 1; 485 486 err: 487 EC_KEY_free(ec); 488 489 return ret; 490 } 491 492 static int 493 pkey_ec_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) 494 { 495 EC_KEY *ec = NULL; 496 EC_PKEY_CTX *dctx = ctx->data; 497 int ret = 0; 498 499 if (ctx->pkey == NULL && dctx->gen_group == NULL) { 500 ECerror(EC_R_NO_PARAMETERS_SET); 501 goto err; 502 } 503 504 if ((ec = EC_KEY_new()) == NULL) 505 goto err; 506 if (!EVP_PKEY_set1_EC_KEY(pkey, ec)) 507 goto err; 508 509 if (ctx->pkey != NULL) { 510 if (!EVP_PKEY_copy_parameters(pkey, ctx->pkey)) 511 goto err; 512 } else { 513 if (!EC_KEY_set_group(ec, dctx->gen_group)) 514 goto err; 515 } 516 517 if (!EC_KEY_generate_key(ec)) 518 goto err; 519 520 ret = 1; 521 522 err: 523 EC_KEY_free(ec); 524 525 return ret; 526 } 527 528 const EVP_PKEY_METHOD ec_pkey_meth = { 529 .pkey_id = EVP_PKEY_EC, 530 531 .init = pkey_ec_init, 532 .copy = pkey_ec_copy, 533 .cleanup = pkey_ec_cleanup, 534 535 .paramgen = pkey_ec_paramgen, 536 537 .keygen = pkey_ec_keygen, 538 539 .sign = pkey_ec_sign, 540 541 .verify = pkey_ec_verify, 542 543 .derive = pkey_ec_kdf_derive, 544 545 .ctrl = pkey_ec_ctrl, 546 .ctrl_str = pkey_ec_ctrl_str 547 }; 548