1 /* $OpenBSD: ec_pmeth.c,v 1.21 2023/12/28 22:12:37 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 <string.h> 61 62 #include <openssl/asn1t.h> 63 #include <openssl/ec.h> 64 #include <openssl/err.h> 65 #include <openssl/evp.h> 66 #include <openssl/x509.h> 67 68 #include "bn_local.h" 69 #include "ec_local.h" 70 #include "evp_local.h" 71 72 /* EC pkey context structure */ 73 74 typedef struct { 75 /* Key and paramgen group */ 76 EC_GROUP *gen_group; 77 /* message digest */ 78 const EVP_MD *md; 79 /* Duplicate key if custom cofactor needed */ 80 EC_KEY *co_key; 81 /* Cofactor mode */ 82 signed char cofactor_mode; 83 /* KDF (if any) to use for ECDH */ 84 char kdf_type; 85 /* Message digest to use for key derivation */ 86 const EVP_MD *kdf_md; 87 /* User key material */ 88 unsigned char *kdf_ukm; 89 size_t kdf_ukmlen; 90 /* KDF output length */ 91 size_t kdf_outlen; 92 } EC_PKEY_CTX; 93 94 static int 95 pkey_ec_init(EVP_PKEY_CTX *ctx) 96 { 97 EC_PKEY_CTX *dctx; 98 99 if ((dctx = calloc(1, sizeof(EC_PKEY_CTX))) == NULL) { 100 ECerror(ERR_R_MALLOC_FAILURE); 101 return 0; 102 } 103 104 dctx->cofactor_mode = -1; 105 dctx->kdf_type = EVP_PKEY_ECDH_KDF_NONE; 106 107 ctx->data = dctx; 108 109 return 1; 110 } 111 112 static int 113 pkey_ec_copy(EVP_PKEY_CTX *dst, EVP_PKEY_CTX *src) 114 { 115 EC_PKEY_CTX *dctx, *sctx; 116 if (!pkey_ec_init(dst)) 117 return 0; 118 sctx = src->data; 119 dctx = dst->data; 120 if (sctx->gen_group) { 121 dctx->gen_group = EC_GROUP_dup(sctx->gen_group); 122 if (!dctx->gen_group) 123 return 0; 124 } 125 dctx->md = sctx->md; 126 127 if (sctx->co_key) { 128 dctx->co_key = EC_KEY_dup(sctx->co_key); 129 if (!dctx->co_key) 130 return 0; 131 } 132 dctx->kdf_type = sctx->kdf_type; 133 dctx->kdf_md = sctx->kdf_md; 134 dctx->kdf_outlen = sctx->kdf_outlen; 135 if (sctx->kdf_ukm) { 136 if ((dctx->kdf_ukm = calloc(1, sctx->kdf_ukmlen)) == NULL) 137 return 0; 138 memcpy(dctx->kdf_ukm, sctx->kdf_ukm, sctx->kdf_ukmlen); 139 } else 140 dctx->kdf_ukm = NULL; 141 142 dctx->kdf_ukmlen = sctx->kdf_ukmlen; 143 144 return 1; 145 } 146 147 static void 148 pkey_ec_cleanup(EVP_PKEY_CTX *ctx) 149 { 150 EC_PKEY_CTX *dctx = ctx->data; 151 152 if (dctx != NULL) { 153 EC_GROUP_free(dctx->gen_group); 154 EC_KEY_free(dctx->co_key); 155 free(dctx->kdf_ukm); 156 free(dctx); 157 ctx->data = NULL; 158 } 159 } 160 161 static int 162 pkey_ec_sign(EVP_PKEY_CTX *ctx, unsigned char *sig, size_t *siglen, 163 const unsigned char *tbs, size_t tbslen) 164 { 165 int ret, type; 166 unsigned int sltmp; 167 EC_PKEY_CTX *dctx = ctx->data; 168 EC_KEY *ec = ctx->pkey->pkey.ec; 169 170 if (!sig) { 171 *siglen = ECDSA_size(ec); 172 return 1; 173 } else if (*siglen < (size_t) ECDSA_size(ec)) { 174 ECerror(EC_R_BUFFER_TOO_SMALL); 175 return 0; 176 } 177 if (dctx->md) 178 type = EVP_MD_type(dctx->md); 179 else 180 type = NID_sha1; 181 182 ret = ECDSA_sign(type, tbs, tbslen, sig, &sltmp, ec); 183 if (ret <= 0) 184 return ret; 185 *siglen = (size_t) sltmp; 186 return 1; 187 } 188 189 static int 190 pkey_ec_verify(EVP_PKEY_CTX *ctx, 191 const unsigned char *sig, size_t siglen, 192 const unsigned char *tbs, size_t tbslen) 193 { 194 int ret, type; 195 EC_PKEY_CTX *dctx = ctx->data; 196 EC_KEY *ec = ctx->pkey->pkey.ec; 197 198 if (dctx->md) 199 type = EVP_MD_type(dctx->md); 200 else 201 type = NID_sha1; 202 203 ret = ECDSA_verify(type, tbs, tbslen, sig, siglen, ec); 204 205 return ret; 206 } 207 208 static int 209 pkey_ec_derive(EVP_PKEY_CTX *ctx, unsigned char *key, size_t *keylen) 210 { 211 int ret; 212 size_t outlen; 213 const EC_POINT *pubkey = NULL; 214 EC_KEY *eckey; 215 EC_PKEY_CTX *dctx = ctx->data; 216 217 if (!ctx->pkey || !ctx->peerkey) { 218 ECerror(EC_R_KEYS_NOT_SET); 219 return 0; 220 } 221 222 eckey = dctx->co_key ? dctx->co_key : ctx->pkey->pkey.ec; 223 if (!key) { 224 const EC_GROUP *group; 225 group = EC_KEY_get0_group(eckey); 226 *keylen = (EC_GROUP_get_degree(group) + 7) / 8; 227 return 1; 228 } 229 pubkey = EC_KEY_get0_public_key(ctx->peerkey->pkey.ec); 230 231 /* 232 * NB: unlike PKCS#3 DH, if *outlen is less than maximum size this is 233 * not an error, the result is truncated. 234 */ 235 236 outlen = *keylen; 237 238 ret = ECDH_compute_key(key, outlen, pubkey, eckey, 0); 239 if (ret <= 0) 240 return 0; 241 242 *keylen = ret; 243 244 return 1; 245 } 246 247 static int 248 pkey_ec_kdf_derive(EVP_PKEY_CTX *ctx, unsigned char *key, size_t *keylen) 249 { 250 EC_PKEY_CTX *dctx = ctx->data; 251 unsigned char *ktmp = NULL; 252 size_t ktmplen; 253 int rv = 0; 254 255 if (dctx->kdf_type == EVP_PKEY_ECDH_KDF_NONE) 256 return pkey_ec_derive(ctx, key, keylen); 257 258 if (!key) { 259 *keylen = dctx->kdf_outlen; 260 return 1; 261 } 262 if (*keylen != dctx->kdf_outlen) 263 return 0; 264 if (!pkey_ec_derive(ctx, NULL, &ktmplen)) 265 return 0; 266 if ((ktmp = calloc(1, ktmplen)) == NULL) { 267 ECerror(ERR_R_MALLOC_FAILURE); 268 return 0; 269 } 270 if (!pkey_ec_derive(ctx, ktmp, &ktmplen)) 271 goto err; 272 /* Do KDF stuff */ 273 if (!ecdh_KDF_X9_63(key, *keylen, ktmp, ktmplen, dctx->kdf_ukm, 274 dctx->kdf_ukmlen, dctx->kdf_md)) 275 goto err; 276 rv = 1; 277 278 err: 279 freezero(ktmp, ktmplen); 280 281 return rv; 282 } 283 284 static int 285 pkey_ec_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2) 286 { 287 EC_PKEY_CTX *dctx = ctx->data; 288 EC_GROUP *group; 289 290 switch (type) { 291 case EVP_PKEY_CTRL_EC_PARAMGEN_CURVE_NID: 292 group = EC_GROUP_new_by_curve_name(p1); 293 if (group == NULL) { 294 ECerror(EC_R_INVALID_CURVE); 295 return 0; 296 } 297 EC_GROUP_free(dctx->gen_group); 298 dctx->gen_group = group; 299 return 1; 300 301 case EVP_PKEY_CTRL_EC_PARAM_ENC: 302 if (!dctx->gen_group) { 303 ECerror(EC_R_NO_PARAMETERS_SET); 304 return 0; 305 } 306 EC_GROUP_set_asn1_flag(dctx->gen_group, p1); 307 return 1; 308 309 case EVP_PKEY_CTRL_EC_ECDH_COFACTOR: 310 if (p1 == -2) { 311 if (dctx->cofactor_mode != -1) 312 return dctx->cofactor_mode; 313 else { 314 EC_KEY *ec_key = ctx->pkey->pkey.ec; 315 return EC_KEY_get_flags(ec_key) & EC_FLAG_COFACTOR_ECDH ? 1 : 0; 316 } 317 } else if (p1 < -1 || p1 > 1) 318 return -2; 319 dctx->cofactor_mode = p1; 320 if (p1 != -1) { 321 EC_KEY *ec_key = ctx->pkey->pkey.ec; 322 if (!ec_key->group) 323 return -2; 324 /* If cofactor is 1 cofactor mode does nothing */ 325 if (BN_is_one(&ec_key->group->cofactor)) 326 return 1; 327 if (!dctx->co_key) { 328 dctx->co_key = EC_KEY_dup(ec_key); 329 if (!dctx->co_key) 330 return 0; 331 } 332 if (p1) 333 EC_KEY_set_flags(dctx->co_key, EC_FLAG_COFACTOR_ECDH); 334 else 335 EC_KEY_clear_flags(dctx->co_key, EC_FLAG_COFACTOR_ECDH); 336 } else { 337 EC_KEY_free(dctx->co_key); 338 dctx->co_key = NULL; 339 } 340 return 1; 341 342 case EVP_PKEY_CTRL_EC_KDF_TYPE: 343 if (p1 == -2) 344 return dctx->kdf_type; 345 if (p1 != EVP_PKEY_ECDH_KDF_NONE && p1 != EVP_PKEY_ECDH_KDF_X9_63) 346 return -2; 347 dctx->kdf_type = p1; 348 return 1; 349 350 case EVP_PKEY_CTRL_EC_KDF_MD: 351 dctx->kdf_md = p2; 352 return 1; 353 354 case EVP_PKEY_CTRL_GET_EC_KDF_MD: 355 *(const EVP_MD **)p2 = dctx->kdf_md; 356 return 1; 357 358 case EVP_PKEY_CTRL_EC_KDF_OUTLEN: 359 if (p1 <= 0) 360 return -2; 361 dctx->kdf_outlen = (size_t)p1; 362 return 1; 363 364 case EVP_PKEY_CTRL_GET_EC_KDF_OUTLEN: 365 *(int *)p2 = dctx->kdf_outlen; 366 return 1; 367 368 case EVP_PKEY_CTRL_EC_KDF_UKM: 369 free(dctx->kdf_ukm); 370 dctx->kdf_ukm = p2; 371 if (p2) 372 dctx->kdf_ukmlen = p1; 373 else 374 dctx->kdf_ukmlen = 0; 375 return 1; 376 377 case EVP_PKEY_CTRL_GET_EC_KDF_UKM: 378 *(unsigned char **)p2 = dctx->kdf_ukm; 379 return dctx->kdf_ukmlen; 380 381 case EVP_PKEY_CTRL_MD: 382 /* RFC 3279, RFC 5758 and NIST CSOR. */ 383 if (EVP_MD_type((const EVP_MD *) p2) != NID_sha1 && 384 EVP_MD_type((const EVP_MD *) p2) != NID_ecdsa_with_SHA1 && 385 EVP_MD_type((const EVP_MD *) p2) != NID_sha224 && 386 EVP_MD_type((const EVP_MD *) p2) != NID_sha256 && 387 EVP_MD_type((const EVP_MD *) p2) != NID_sha384 && 388 EVP_MD_type((const EVP_MD *) p2) != NID_sha512 && 389 EVP_MD_type((const EVP_MD *) p2) != NID_sha3_224 && 390 EVP_MD_type((const EVP_MD *) p2) != NID_sha3_256 && 391 EVP_MD_type((const EVP_MD *) p2) != NID_sha3_384 && 392 EVP_MD_type((const EVP_MD *) p2) != NID_sha3_512) { 393 ECerror(EC_R_INVALID_DIGEST_TYPE); 394 return 0; 395 } 396 dctx->md = p2; 397 return 1; 398 399 case EVP_PKEY_CTRL_GET_MD: 400 *(const EVP_MD **)p2 = dctx->md; 401 return 1; 402 403 case EVP_PKEY_CTRL_PEER_KEY: 404 /* Default behaviour is OK */ 405 case EVP_PKEY_CTRL_DIGESTINIT: 406 case EVP_PKEY_CTRL_PKCS7_SIGN: 407 case EVP_PKEY_CTRL_CMS_SIGN: 408 return 1; 409 410 default: 411 return -2; 412 413 } 414 } 415 416 static int 417 pkey_ec_ctrl_str(EVP_PKEY_CTX *ctx, const char *type, const char *value) 418 { 419 if (!strcmp(type, "ec_paramgen_curve")) { 420 int nid; 421 nid = EC_curve_nist2nid(value); 422 if (nid == NID_undef) 423 nid = OBJ_sn2nid(value); 424 if (nid == NID_undef) 425 nid = OBJ_ln2nid(value); 426 if (nid == NID_undef) { 427 ECerror(EC_R_INVALID_CURVE); 428 return 0; 429 } 430 return EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx, nid); 431 } else if (strcmp(type, "ec_param_enc") == 0) { 432 int param_enc; 433 if (strcmp(value, "explicit") == 0) 434 param_enc = 0; 435 else if (strcmp(value, "named_curve") == 0) 436 param_enc = OPENSSL_EC_NAMED_CURVE; 437 else 438 return -2; 439 return EVP_PKEY_CTX_set_ec_param_enc(ctx, param_enc); 440 } else if (strcmp(type, "ecdh_kdf_md") == 0) { 441 const EVP_MD *md; 442 if ((md = EVP_get_digestbyname(value)) == NULL) { 443 ECerror(EC_R_INVALID_DIGEST); 444 return 0; 445 } 446 return EVP_PKEY_CTX_set_ecdh_kdf_md(ctx, md); 447 } else if (strcmp(type, "ecdh_cofactor_mode") == 0) { 448 int co_mode; 449 co_mode = atoi(value); 450 return EVP_PKEY_CTX_set_ecdh_cofactor_mode(ctx, co_mode); 451 } 452 return -2; 453 } 454 455 static int 456 pkey_ec_paramgen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) 457 { 458 EC_KEY *ec = NULL; 459 EC_PKEY_CTX *dctx = ctx->data; 460 int ret = 0; 461 462 if (dctx->gen_group == NULL) { 463 ECerror(EC_R_NO_PARAMETERS_SET); 464 goto err; 465 } 466 467 if ((ec = EC_KEY_new()) == NULL) 468 goto err; 469 if (!EC_KEY_set_group(ec, dctx->gen_group)) 470 goto err; 471 if (!EVP_PKEY_assign_EC_KEY(pkey, ec)) 472 goto err; 473 ec = NULL; 474 475 ret = 1; 476 477 err: 478 EC_KEY_free(ec); 479 480 return ret; 481 } 482 483 static int 484 pkey_ec_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) 485 { 486 EC_KEY *ec = NULL; 487 EC_PKEY_CTX *dctx = ctx->data; 488 int ret = 0; 489 490 if (ctx->pkey == NULL && dctx->gen_group == NULL) { 491 ECerror(EC_R_NO_PARAMETERS_SET); 492 goto err; 493 } 494 495 if ((ec = EC_KEY_new()) == NULL) 496 goto err; 497 if (!EVP_PKEY_set1_EC_KEY(pkey, ec)) 498 goto err; 499 500 if (ctx->pkey != NULL) { 501 if (!EVP_PKEY_copy_parameters(pkey, ctx->pkey)) 502 goto err; 503 } else { 504 if (!EC_KEY_set_group(ec, dctx->gen_group)) 505 goto err; 506 } 507 508 if (!EC_KEY_generate_key(ec)) 509 goto err; 510 511 ret = 1; 512 513 err: 514 EC_KEY_free(ec); 515 516 return ret; 517 } 518 519 const EVP_PKEY_METHOD ec_pkey_meth = { 520 .pkey_id = EVP_PKEY_EC, 521 522 .init = pkey_ec_init, 523 .copy = pkey_ec_copy, 524 .cleanup = pkey_ec_cleanup, 525 526 .paramgen = pkey_ec_paramgen, 527 528 .keygen = pkey_ec_keygen, 529 530 .sign = pkey_ec_sign, 531 532 .verify = pkey_ec_verify, 533 534 .derive = pkey_ec_kdf_derive, 535 536 .ctrl = pkey_ec_ctrl, 537 .ctrl_str = pkey_ec_ctrl_str 538 }; 539