xref: /openbsd/lib/libcrypto/ec/ec_pmeth.c (revision 5dea098c)
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