1 /*
2 * Copyright 2022-2023 The OpenSSL Project Authors. All Rights Reserved.
3 *
4 * Licensed under the Apache License 2.0 (the "License"). You may not use
5 * this file except in compliance with the License. You can obtain a copy
6 * in the file LICENSE in the source distribution or at
7 * https://www.openssl.org/source/license.html
8 */
9
10 /*
11 * The following implementation is part of RFC 9180 related to DHKEM using
12 * EC keys (i.e. P-256, P-384 and P-521)
13 * References to Sections in the comments below refer to RFC 9180.
14 */
15
16 #include "internal/deprecated.h"
17
18 #include <openssl/crypto.h>
19 #include <openssl/evp.h>
20 #include <openssl/core_dispatch.h>
21 #include <openssl/core_names.h>
22 #include <openssl/ec.h>
23 #include <openssl/params.h>
24 #include <openssl/err.h>
25 #include <openssl/proverr.h>
26 #include <openssl/kdf.h>
27 #include <openssl/rand.h>
28 #include "prov/provider_ctx.h"
29 #include "prov/implementations.h"
30 #include "prov/securitycheck.h"
31 #include "prov/providercommon.h"
32
33 #include <openssl/hpke.h>
34 #include "internal/hpke_util.h"
35 #include "crypto/ec.h"
36 #include "prov/ecx.h"
37 #include "eckem.h"
38
39 typedef struct {
40 EC_KEY *recipient_key;
41 EC_KEY *sender_authkey;
42 OSSL_LIB_CTX *libctx;
43 char *propq;
44 unsigned int mode;
45 unsigned int op;
46 unsigned char *ikm;
47 size_t ikmlen;
48 const char *kdfname;
49 const OSSL_HPKE_KEM_INFO *info;
50 } PROV_EC_CTX;
51
52 static OSSL_FUNC_kem_newctx_fn eckem_newctx;
53 static OSSL_FUNC_kem_encapsulate_init_fn eckem_encapsulate_init;
54 static OSSL_FUNC_kem_auth_encapsulate_init_fn eckem_auth_encapsulate_init;
55 static OSSL_FUNC_kem_encapsulate_fn eckem_encapsulate;
56 static OSSL_FUNC_kem_decapsulate_init_fn eckem_decapsulate_init;
57 static OSSL_FUNC_kem_auth_decapsulate_init_fn eckem_auth_decapsulate_init;
58 static OSSL_FUNC_kem_decapsulate_fn eckem_decapsulate;
59 static OSSL_FUNC_kem_freectx_fn eckem_freectx;
60 static OSSL_FUNC_kem_set_ctx_params_fn eckem_set_ctx_params;
61 static OSSL_FUNC_kem_settable_ctx_params_fn eckem_settable_ctx_params;
62
63 /* ASCII: "KEM", in hex for EBCDIC compatibility */
64 static const char LABEL_KEM[] = "\x4b\x45\x4d";
65
eckey_check(const EC_KEY * ec,int requires_privatekey)66 static int eckey_check(const EC_KEY *ec, int requires_privatekey)
67 {
68 int rv = 0;
69 BN_CTX *bnctx = NULL;
70 BIGNUM *rem = NULL;
71 const BIGNUM *priv = EC_KEY_get0_private_key(ec);
72 const EC_POINT *pub = EC_KEY_get0_public_key(ec);
73
74 /* Keys always require a public component */
75 if (pub == NULL) {
76 ERR_raise(ERR_LIB_PROV, PROV_R_NOT_A_PUBLIC_KEY);
77 return 0;
78 }
79 if (priv == NULL) {
80 return (requires_privatekey == 0);
81 } else {
82 /* If there is a private key, check that is non zero (mod order) */
83 const EC_GROUP *group = EC_KEY_get0_group(ec);
84 const BIGNUM *order = EC_GROUP_get0_order(group);
85
86 bnctx = BN_CTX_new_ex(ossl_ec_key_get_libctx(ec));
87 rem = BN_new();
88
89 if (order != NULL && rem != NULL && bnctx != NULL) {
90 rv = BN_mod(rem, priv, order, bnctx)
91 && !BN_is_zero(rem);
92 }
93 }
94 BN_free(rem);
95 BN_CTX_free(bnctx);
96 return rv;
97 }
98
99 /* Returns NULL if the curve is not supported */
ec_curvename_get0(const EC_KEY * ec)100 static const char *ec_curvename_get0(const EC_KEY *ec)
101 {
102 const EC_GROUP *group = EC_KEY_get0_group(ec);
103
104 return EC_curve_nid2nist(EC_GROUP_get_curve_name(group));
105 }
106
107 /*
108 * Set the recipient key, and free any existing key.
109 * ec can be NULL.
110 * The ec key may have only a private or public component
111 * (but it must have a group).
112 */
recipient_key_set(PROV_EC_CTX * ctx,EC_KEY * ec)113 static int recipient_key_set(PROV_EC_CTX *ctx, EC_KEY *ec)
114 {
115 EC_KEY_free(ctx->recipient_key);
116 ctx->recipient_key = NULL;
117
118 if (ec != NULL) {
119 const char *curve = ec_curvename_get0(ec);
120
121 if (curve == NULL)
122 return -2;
123 ctx->info = ossl_HPKE_KEM_INFO_find_curve(curve);
124 if (ctx->info == NULL)
125 return -2;
126 if (!EC_KEY_up_ref(ec))
127 return 0;
128 ctx->recipient_key = ec;
129 ctx->kdfname = "HKDF";
130 }
131 return 1;
132 }
133
134 /*
135 * Set the senders auth key, and free any existing auth key.
136 * ec can be NULL.
137 */
sender_authkey_set(PROV_EC_CTX * ctx,EC_KEY * ec)138 static int sender_authkey_set(PROV_EC_CTX *ctx, EC_KEY *ec)
139 {
140 EC_KEY_free(ctx->sender_authkey);
141 ctx->sender_authkey = NULL;
142
143 if (ec != NULL) {
144 if (!EC_KEY_up_ref(ec))
145 return 0;
146 ctx->sender_authkey = ec;
147 }
148 return 1;
149 }
150
151 /*
152 * Serializes a encoded public key buffer into a EC public key.
153 * Params:
154 * in Contains the group.
155 * pubbuf The encoded public key buffer
156 * Returns: The created public EC key, or NULL if there is an error.
157 */
eckey_frompub(EC_KEY * in,const unsigned char * pubbuf,size_t pubbuflen)158 static EC_KEY *eckey_frompub(EC_KEY *in,
159 const unsigned char *pubbuf, size_t pubbuflen)
160 {
161 EC_KEY *key;
162
163 key = EC_KEY_new_ex(ossl_ec_key_get_libctx(in), ossl_ec_key_get0_propq(in));
164 if (key == NULL)
165 goto err;
166 if (!EC_KEY_set_group(key, EC_KEY_get0_group(in)))
167 goto err;
168 if (!EC_KEY_oct2key(key, pubbuf, pubbuflen, NULL))
169 goto err;
170 return key;
171 err:
172 EC_KEY_free(key);
173 return NULL;
174 }
175
176 /*
177 * Deserialises a EC public key into a encoded byte array.
178 * Returns: 1 if successful or 0 otherwise.
179 */
ecpubkey_todata(const EC_KEY * ec,unsigned char * out,size_t * outlen,size_t maxoutlen)180 static int ecpubkey_todata(const EC_KEY *ec, unsigned char *out, size_t *outlen,
181 size_t maxoutlen)
182 {
183 const EC_POINT *pub;
184 const EC_GROUP *group;
185
186 group = EC_KEY_get0_group(ec);
187 pub = EC_KEY_get0_public_key(ec);
188 *outlen = EC_POINT_point2oct(group, pub, POINT_CONVERSION_UNCOMPRESSED,
189 out, maxoutlen, NULL);
190 return *outlen != 0;
191 }
192
eckem_newctx(void * provctx)193 static void *eckem_newctx(void *provctx)
194 {
195 PROV_EC_CTX *ctx = OPENSSL_zalloc(sizeof(PROV_EC_CTX));
196
197 if (ctx == NULL)
198 return NULL;
199 ctx->libctx = PROV_LIBCTX_OF(provctx);
200
201 return ctx;
202 }
203
eckem_freectx(void * vectx)204 static void eckem_freectx(void *vectx)
205 {
206 PROV_EC_CTX *ctx = (PROV_EC_CTX *)vectx;
207
208 OPENSSL_clear_free(ctx->ikm, ctx->ikmlen);
209 recipient_key_set(ctx, NULL);
210 sender_authkey_set(ctx, NULL);
211 OPENSSL_free(ctx);
212 }
213
ossl_ec_match_params(const EC_KEY * key1,const EC_KEY * key2)214 static int ossl_ec_match_params(const EC_KEY *key1, const EC_KEY *key2)
215 {
216 int ret;
217 BN_CTX *ctx = NULL;
218 const EC_GROUP *group1 = EC_KEY_get0_group(key1);
219 const EC_GROUP *group2 = EC_KEY_get0_group(key2);
220
221 ctx = BN_CTX_new_ex(ossl_ec_key_get_libctx(key1));
222 if (ctx == NULL)
223 return 0;
224
225 ret = group1 != NULL
226 && group2 != NULL
227 && EC_GROUP_cmp(group1, group2, ctx) == 0;
228 if (!ret)
229 ERR_raise(ERR_LIB_PROV, PROV_R_MISMATCHING_DOMAIN_PARAMETERS);
230 BN_CTX_free(ctx);
231 return ret;
232 }
233
eckem_init(void * vctx,int operation,void * vec,void * vauth,const OSSL_PARAM params[])234 static int eckem_init(void *vctx, int operation, void *vec, void *vauth,
235 const OSSL_PARAM params[])
236 {
237 int rv;
238 PROV_EC_CTX *ctx = (PROV_EC_CTX *)vctx;
239 EC_KEY *ec = vec;
240 EC_KEY *auth = vauth;
241
242 if (!ossl_prov_is_running())
243 return 0;
244
245 if (!eckey_check(ec, operation == EVP_PKEY_OP_DECAPSULATE))
246 return 0;
247 rv = recipient_key_set(ctx, ec);
248 if (rv <= 0)
249 return rv;
250
251 if (auth != NULL) {
252 if (!ossl_ec_match_params(ec, auth)
253 || !eckey_check(auth, operation == EVP_PKEY_OP_ENCAPSULATE)
254 || !sender_authkey_set(ctx, auth))
255 return 0;
256 }
257
258 ctx->op = operation;
259 return eckem_set_ctx_params(vctx, params);
260 }
261
eckem_encapsulate_init(void * vctx,void * vec,const OSSL_PARAM params[])262 static int eckem_encapsulate_init(void *vctx, void *vec,
263 const OSSL_PARAM params[])
264 {
265 return eckem_init(vctx, EVP_PKEY_OP_ENCAPSULATE, vec, NULL, params);
266 }
267
eckem_decapsulate_init(void * vctx,void * vec,const OSSL_PARAM params[])268 static int eckem_decapsulate_init(void *vctx, void *vec,
269 const OSSL_PARAM params[])
270 {
271 return eckem_init(vctx, EVP_PKEY_OP_DECAPSULATE, vec, NULL, params);
272 }
273
eckem_auth_encapsulate_init(void * vctx,void * vecx,void * vauthpriv,const OSSL_PARAM params[])274 static int eckem_auth_encapsulate_init(void *vctx, void *vecx, void *vauthpriv,
275 const OSSL_PARAM params[])
276 {
277 return eckem_init(vctx, EVP_PKEY_OP_ENCAPSULATE, vecx, vauthpriv, params);
278 }
279
eckem_auth_decapsulate_init(void * vctx,void * vecx,void * vauthpub,const OSSL_PARAM params[])280 static int eckem_auth_decapsulate_init(void *vctx, void *vecx, void *vauthpub,
281 const OSSL_PARAM params[])
282 {
283 return eckem_init(vctx, EVP_PKEY_OP_DECAPSULATE, vecx, vauthpub, params);
284 }
285
eckem_set_ctx_params(void * vctx,const OSSL_PARAM params[])286 static int eckem_set_ctx_params(void *vctx, const OSSL_PARAM params[])
287 {
288 PROV_EC_CTX *ctx = (PROV_EC_CTX *)vctx;
289 const OSSL_PARAM *p;
290 int mode;
291
292 if (ossl_param_is_empty(params))
293 return 1;
294
295 p = OSSL_PARAM_locate_const(params, OSSL_KEM_PARAM_IKME);
296 if (p != NULL) {
297 void *tmp = NULL;
298 size_t tmplen = 0;
299
300 if (p->data != NULL && p->data_size != 0) {
301 if (!OSSL_PARAM_get_octet_string(p, &tmp, 0, &tmplen))
302 return 0;
303 }
304 OPENSSL_clear_free(ctx->ikm, ctx->ikmlen);
305 /* Set the ephemeral seed */
306 ctx->ikm = tmp;
307 ctx->ikmlen = tmplen;
308 }
309
310 p = OSSL_PARAM_locate_const(params, OSSL_KEM_PARAM_OPERATION);
311 if (p != NULL) {
312 if (p->data_type != OSSL_PARAM_UTF8_STRING)
313 return 0;
314 mode = ossl_eckem_modename2id(p->data);
315 if (mode == KEM_MODE_UNDEFINED)
316 return 0;
317 ctx->mode = mode;
318 }
319 return 1;
320 }
321
322 static const OSSL_PARAM known_settable_eckem_ctx_params[] = {
323 OSSL_PARAM_utf8_string(OSSL_KEM_PARAM_OPERATION, NULL, 0),
324 OSSL_PARAM_octet_string(OSSL_KEM_PARAM_IKME, NULL, 0),
325 OSSL_PARAM_END
326 };
327
eckem_settable_ctx_params(ossl_unused void * vctx,ossl_unused void * provctx)328 static const OSSL_PARAM *eckem_settable_ctx_params(ossl_unused void *vctx,
329 ossl_unused void *provctx)
330 {
331 return known_settable_eckem_ctx_params;
332 }
333
334 /*
335 * See Section 4.1 DH-Based KEM (DHKEM) ExtractAndExpand
336 */
dhkem_extract_and_expand(EVP_KDF_CTX * kctx,unsigned char * okm,size_t okmlen,uint16_t kemid,const unsigned char * dhkm,size_t dhkmlen,const unsigned char * kemctx,size_t kemctxlen)337 static int dhkem_extract_and_expand(EVP_KDF_CTX *kctx,
338 unsigned char *okm, size_t okmlen,
339 uint16_t kemid,
340 const unsigned char *dhkm, size_t dhkmlen,
341 const unsigned char *kemctx,
342 size_t kemctxlen)
343 {
344 uint8_t suiteid[2];
345 uint8_t prk[EVP_MAX_MD_SIZE];
346 size_t prklen = okmlen;
347 int ret;
348
349 if (prklen > sizeof(prk))
350 return 0;
351
352 suiteid[0] = (kemid >> 8) & 0xff;
353 suiteid[1] = kemid & 0xff;
354
355 ret = ossl_hpke_labeled_extract(kctx, prk, prklen,
356 NULL, 0, LABEL_KEM, suiteid, sizeof(suiteid),
357 OSSL_DHKEM_LABEL_EAE_PRK, dhkm, dhkmlen)
358 && ossl_hpke_labeled_expand(kctx, okm, okmlen, prk, prklen,
359 LABEL_KEM, suiteid, sizeof(suiteid),
360 OSSL_DHKEM_LABEL_SHARED_SECRET,
361 kemctx, kemctxlen);
362 OPENSSL_cleanse(prk, prklen);
363 return ret;
364 }
365
366 /*
367 * See Section 7.1.3 DeriveKeyPair.
368 *
369 * This function is used by ec keygen.
370 * (For this reason it does not use any of the state stored in PROV_EC_CTX).
371 *
372 * Params:
373 * ec An initialized ec key.
374 * priv The buffer to store the generated private key into (it is assumed
375 * this is of length alg->encodedprivlen).
376 * ikm buffer containing the input key material (seed). This must be set.
377 * ikmlen size of the ikm buffer in bytes
378 * Returns:
379 * 1 if successful or 0 otherwise.
380 */
ossl_ec_dhkem_derive_private(EC_KEY * ec,BIGNUM * priv,const unsigned char * ikm,size_t ikmlen)381 int ossl_ec_dhkem_derive_private(EC_KEY *ec, BIGNUM *priv,
382 const unsigned char *ikm, size_t ikmlen)
383 {
384 int ret = 0;
385 EVP_KDF_CTX *kdfctx = NULL;
386 uint8_t suiteid[2];
387 unsigned char prk[OSSL_HPKE_MAX_SECRET];
388 unsigned char privbuf[OSSL_HPKE_MAX_PRIVATE];
389 const BIGNUM *order;
390 unsigned char counter = 0;
391 const char *curve = ec_curvename_get0(ec);
392 const OSSL_HPKE_KEM_INFO *info;
393
394 if (curve == NULL)
395 return -2;
396
397 info = ossl_HPKE_KEM_INFO_find_curve(curve);
398 if (info == NULL)
399 return -2;
400
401 kdfctx = ossl_kdf_ctx_create("HKDF", info->mdname,
402 ossl_ec_key_get_libctx(ec),
403 ossl_ec_key_get0_propq(ec));
404 if (kdfctx == NULL)
405 return 0;
406
407 /* ikmlen should have a length of at least Nsk */
408 if (ikmlen < info->Nsecret) {
409 ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_INPUT_LENGTH,
410 "ikm length is :%zu, should be at least %zu",
411 ikmlen, info->Nsecret);
412 goto err;
413 }
414
415 suiteid[0] = info->kem_id / 256;
416 suiteid[1] = info->kem_id % 256;
417
418 if (!ossl_hpke_labeled_extract(kdfctx, prk, info->Nsecret,
419 NULL, 0, LABEL_KEM, suiteid, sizeof(suiteid),
420 OSSL_DHKEM_LABEL_DKP_PRK, ikm, ikmlen))
421 goto err;
422
423 order = EC_GROUP_get0_order(EC_KEY_get0_group(ec));
424 do {
425 if (!ossl_hpke_labeled_expand(kdfctx, privbuf, info->Nsk,
426 prk, info->Nsecret,
427 LABEL_KEM, suiteid, sizeof(suiteid),
428 OSSL_DHKEM_LABEL_CANDIDATE,
429 &counter, 1))
430 goto err;
431 privbuf[0] &= info->bitmask;
432 if (BN_bin2bn(privbuf, info->Nsk, priv) == NULL)
433 goto err;
434 if (counter == 0xFF) {
435 ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GENERATE_KEY);
436 goto err;
437 }
438 counter++;
439 } while (BN_is_zero(priv) || BN_cmp(priv, order) >= 0);
440 ret = 1;
441 err:
442 OPENSSL_cleanse(prk, sizeof(prk));
443 OPENSSL_cleanse(privbuf, sizeof(privbuf));
444 EVP_KDF_CTX_free(kdfctx);
445 return ret;
446 }
447
448 /*
449 * Do a keygen operation without having to use EVP_PKEY.
450 * Params:
451 * ctx Context object
452 * ikm The seed material - if this is NULL, then a random seed is used.
453 * Returns:
454 * The generated EC key, or NULL on failure.
455 */
derivekey(PROV_EC_CTX * ctx,const unsigned char * ikm,size_t ikmlen)456 static EC_KEY *derivekey(PROV_EC_CTX *ctx,
457 const unsigned char *ikm, size_t ikmlen)
458 {
459 int ret = 0;
460 EC_KEY *key;
461 unsigned char *seed = (unsigned char *)ikm;
462 size_t seedlen = ikmlen;
463 unsigned char tmpbuf[OSSL_HPKE_MAX_PRIVATE];
464
465 key = EC_KEY_new_ex(ctx->libctx, ctx->propq);
466 if (key == NULL)
467 goto err;
468 if (!EC_KEY_set_group(key, EC_KEY_get0_group(ctx->recipient_key)))
469 goto err;
470
471 /* Generate a random seed if there is no input ikm */
472 if (seed == NULL || seedlen == 0) {
473 seedlen = ctx->info->Nsk;
474 if (seedlen > sizeof(tmpbuf))
475 goto err;
476 if (RAND_priv_bytes_ex(ctx->libctx, tmpbuf, seedlen, 0) <= 0)
477 goto err;
478 seed = tmpbuf;
479 }
480 ret = ossl_ec_generate_key_dhkem(key, seed, seedlen);
481 err:
482 if (seed != ikm)
483 OPENSSL_cleanse(seed, seedlen);
484 if (ret <= 0) {
485 EC_KEY_free(key);
486 key = NULL;
487 }
488 return key;
489 }
490
491 /*
492 * Before doing a key exchange the public key of the peer needs to be checked
493 * Note that the group check is not done here as we have already checked
494 * that it only uses one of the approved curve names when the key was set.
495 *
496 * Returns 1 if the public key is valid, or 0 if it fails.
497 */
check_publickey(const EC_KEY * pub)498 static int check_publickey(const EC_KEY *pub)
499 {
500 int ret = 0;
501 BN_CTX *bnctx = BN_CTX_new_ex(ossl_ec_key_get_libctx(pub));
502
503 if (bnctx == NULL)
504 return 0;
505 ret = ossl_ec_key_public_check(pub, bnctx);
506 BN_CTX_free(bnctx);
507
508 return ret;
509 }
510
511 /*
512 * Do an ecdh key exchange.
513 * dhkm = DH(sender, peer)
514 *
515 * NOTE: Instead of using EVP_PKEY_derive() API's, we use EC_KEY operations
516 * to avoid messy conversions back to EVP_PKEY.
517 *
518 * Returns the size of the secret if successful, or 0 otherwise,
519 */
generate_ecdhkm(const EC_KEY * sender,const EC_KEY * peer,unsigned char * out,size_t maxout,unsigned int secretsz)520 static int generate_ecdhkm(const EC_KEY *sender, const EC_KEY *peer,
521 unsigned char *out, size_t maxout,
522 unsigned int secretsz)
523 {
524 const EC_GROUP *group = EC_KEY_get0_group(sender);
525 size_t secretlen = (EC_GROUP_get_degree(group) + 7) / 8;
526
527 if (secretlen != secretsz || secretlen > maxout) {
528 ERR_raise_data(ERR_LIB_PROV, PROV_R_BAD_LENGTH, "secretsz invalid");
529 return 0;
530 }
531
532 if (!check_publickey(peer))
533 return 0;
534 return ECDH_compute_key(out, secretlen, EC_KEY_get0_public_key(peer),
535 sender, NULL) > 0;
536 }
537
538 /*
539 * Derive a secret using ECDH (code is shared by the encap and decap)
540 *
541 * dhkm = Concat(ecdh(privkey1, peerkey1), ecdh(privkey2, peerkey2)
542 * kemctx = Concat(sender_pub, recipient_pub, ctx->sender_authkey)
543 * secret = dhkem_extract_and_expand(kemid, dhkm, kemctx);
544 *
545 * Params:
546 * ctx Object that contains algorithm state and constants.
547 * secret The returned secret (with a length ctx->alg->secretlen bytes).
548 * privkey1 A private key used for ECDH key derivation.
549 * peerkey1 A public key used for ECDH key derivation with privkey1
550 * privkey2 A optional private key used for a second ECDH key derivation.
551 * It can be NULL.
552 * peerkey2 A optional public key used for a second ECDH key derivation
553 * with privkey2,. It can be NULL.
554 * sender_pub The senders public key in encoded form.
555 * recipient_pub The recipients public key in encoded form.
556 * Notes:
557 * The second ecdh() is only used for the HPKE auth modes when both privkey2
558 * and peerkey2 are non NULL (i.e. ctx->sender_authkey is not NULL).
559 */
derive_secret(PROV_EC_CTX * ctx,unsigned char * secret,const EC_KEY * privkey1,const EC_KEY * peerkey1,const EC_KEY * privkey2,const EC_KEY * peerkey2,const unsigned char * sender_pub,const unsigned char * recipient_pub)560 static int derive_secret(PROV_EC_CTX *ctx, unsigned char *secret,
561 const EC_KEY *privkey1, const EC_KEY *peerkey1,
562 const EC_KEY *privkey2, const EC_KEY *peerkey2,
563 const unsigned char *sender_pub,
564 const unsigned char *recipient_pub)
565 {
566 int ret = 0;
567 EVP_KDF_CTX *kdfctx = NULL;
568 unsigned char sender_authpub[OSSL_HPKE_MAX_PUBLIC];
569 unsigned char dhkm[OSSL_HPKE_MAX_PRIVATE * 2];
570 unsigned char kemctx[OSSL_HPKE_MAX_PUBLIC * 3];
571 size_t sender_authpublen;
572 size_t kemctxlen = 0, dhkmlen = 0;
573 const OSSL_HPKE_KEM_INFO *info = ctx->info;
574 size_t encodedpublen = info->Npk;
575 size_t encodedprivlen = info->Nsk;
576 int auth = ctx->sender_authkey != NULL;
577
578 if (!generate_ecdhkm(privkey1, peerkey1, dhkm, sizeof(dhkm), encodedprivlen))
579 goto err;
580 dhkmlen = encodedprivlen;
581 kemctxlen = 2 * encodedpublen;
582
583 /* Concat the optional second ECDH (used for Auth) */
584 if (auth) {
585 /* Get the public key of the auth sender in encoded form */
586 if (!ecpubkey_todata(ctx->sender_authkey, sender_authpub,
587 &sender_authpublen, sizeof(sender_authpub)))
588 goto err;
589 if (sender_authpublen != encodedpublen) {
590 ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_KEY,
591 "Invalid sender auth public key");
592 goto err;
593 }
594 if (!generate_ecdhkm(privkey2, peerkey2,
595 dhkm + dhkmlen, sizeof(dhkm) - dhkmlen,
596 encodedprivlen))
597 goto err;
598 dhkmlen += encodedprivlen;
599 kemctxlen += encodedpublen;
600 }
601 if (kemctxlen > sizeof(kemctx))
602 goto err;
603
604 /* kemctx is the concat of both sides encoded public key */
605 memcpy(kemctx, sender_pub, info->Npk);
606 memcpy(kemctx + info->Npk, recipient_pub, info->Npk);
607 if (auth)
608 memcpy(kemctx + 2 * encodedpublen, sender_authpub, encodedpublen);
609 kdfctx = ossl_kdf_ctx_create(ctx->kdfname, info->mdname,
610 ctx->libctx, ctx->propq);
611 if (kdfctx == NULL)
612 goto err;
613 if (!dhkem_extract_and_expand(kdfctx, secret, info->Nsecret,
614 info->kem_id, dhkm, dhkmlen,
615 kemctx, kemctxlen))
616 goto err;
617 ret = 1;
618 err:
619 OPENSSL_cleanse(dhkm, dhkmlen);
620 EVP_KDF_CTX_free(kdfctx);
621 return ret;
622 }
623
624 /*
625 * Do a DHKEM encapsulate operation.
626 *
627 * See Section 4.1 Encap() and AuthEncap()
628 *
629 * Params:
630 * ctx A context object holding the recipients public key and the
631 * optional senders auth private key.
632 * enc A buffer to return the senders ephemeral public key.
633 * Setting this to NULL allows the enclen and secretlen to return
634 * values, without calculating the secret.
635 * enclen Passes in the max size of the enc buffer and returns the
636 * encoded public key length.
637 * secret A buffer to return the calculated shared secret.
638 * secretlen Passes in the max size of the secret buffer and returns the
639 * secret length.
640 * Returns: 1 on success or 0 otherwise.
641 */
dhkem_encap(PROV_EC_CTX * ctx,unsigned char * enc,size_t * enclen,unsigned char * secret,size_t * secretlen)642 static int dhkem_encap(PROV_EC_CTX *ctx,
643 unsigned char *enc, size_t *enclen,
644 unsigned char *secret, size_t *secretlen)
645 {
646 int ret = 0;
647 EC_KEY *sender_ephemkey = NULL;
648 unsigned char sender_pub[OSSL_HPKE_MAX_PUBLIC];
649 unsigned char recipient_pub[OSSL_HPKE_MAX_PUBLIC];
650 size_t sender_publen, recipient_publen;
651 const OSSL_HPKE_KEM_INFO *info = ctx->info;
652
653 if (enc == NULL) {
654 if (enclen == NULL && secretlen == NULL)
655 return 0;
656 if (enclen != NULL)
657 *enclen = info->Nenc;
658 if (secretlen != NULL)
659 *secretlen = info->Nsecret;
660 return 1;
661 }
662
663 if (*secretlen < info->Nsecret) {
664 ERR_raise_data(ERR_LIB_PROV, PROV_R_BAD_LENGTH, "*secretlen too small");
665 return 0;
666 }
667 if (*enclen < info->Nenc) {
668 ERR_raise_data(ERR_LIB_PROV, PROV_R_BAD_LENGTH, "*enclen too small");
669 return 0;
670 }
671
672 /* Create an ephemeral key */
673 sender_ephemkey = derivekey(ctx, ctx->ikm, ctx->ikmlen);
674 if (sender_ephemkey == NULL)
675 goto err;
676 if (!ecpubkey_todata(sender_ephemkey, sender_pub, &sender_publen,
677 sizeof(sender_pub))
678 || !ecpubkey_todata(ctx->recipient_key, recipient_pub,
679 &recipient_publen, sizeof(recipient_pub)))
680 goto err;
681
682 if (sender_publen != info->Npk
683 || recipient_publen != sender_publen) {
684 ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_KEY, "Invalid public key");
685 goto err;
686 }
687
688 if (!derive_secret(ctx, secret,
689 sender_ephemkey, ctx->recipient_key,
690 ctx->sender_authkey, ctx->recipient_key,
691 sender_pub, recipient_pub))
692 goto err;
693
694 /* Return the senders ephemeral public key in encoded form */
695 memcpy(enc, sender_pub, sender_publen);
696 *enclen = sender_publen;
697 *secretlen = info->Nsecret;
698 ret = 1;
699 err:
700 EC_KEY_free(sender_ephemkey);
701 return ret;
702 }
703
704 /*
705 * Do a DHKEM decapsulate operation.
706 * See Section 4.1 Decap() and Auth Decap()
707 *
708 * Params:
709 * ctx A context object holding the recipients private key and the
710 * optional senders auth public key.
711 * secret A buffer to return the calculated shared secret. Setting this to
712 * NULL can be used to return the secretlen.
713 * secretlen Passes in the max size of the secret buffer and returns the
714 * secret length.
715 * enc A buffer containing the senders ephemeral public key that was returned
716 * from dhkem_encap().
717 * enclen The length in bytes of enc.
718 * Returns: 1 If the shared secret is returned or 0 on error.
719 */
dhkem_decap(PROV_EC_CTX * ctx,unsigned char * secret,size_t * secretlen,const unsigned char * enc,size_t enclen)720 static int dhkem_decap(PROV_EC_CTX *ctx,
721 unsigned char *secret, size_t *secretlen,
722 const unsigned char *enc, size_t enclen)
723 {
724 int ret = 0;
725 EC_KEY *sender_ephempubkey = NULL;
726 const OSSL_HPKE_KEM_INFO *info = ctx->info;
727 unsigned char recipient_pub[OSSL_HPKE_MAX_PUBLIC];
728 size_t recipient_publen;
729 size_t encodedpublen = info->Npk;
730
731 if (secret == NULL) {
732 *secretlen = info->Nsecret;
733 return 1;
734 }
735
736 if (*secretlen < info->Nsecret) {
737 ERR_raise_data(ERR_LIB_PROV, PROV_R_BAD_LENGTH, "*secretlen too small");
738 return 0;
739 }
740 if (enclen != encodedpublen) {
741 ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_KEY, "Invalid enc public key");
742 return 0;
743 }
744
745 sender_ephempubkey = eckey_frompub(ctx->recipient_key, enc, enclen);
746 if (sender_ephempubkey == NULL)
747 goto err;
748 if (!ecpubkey_todata(ctx->recipient_key, recipient_pub, &recipient_publen,
749 sizeof(recipient_pub)))
750 goto err;
751 if (recipient_publen != encodedpublen) {
752 ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_KEY, "Invalid recipient public key");
753 goto err;
754 }
755
756 if (!derive_secret(ctx, secret,
757 ctx->recipient_key, sender_ephempubkey,
758 ctx->recipient_key, ctx->sender_authkey,
759 enc, recipient_pub))
760 goto err;
761 *secretlen = info->Nsecret;
762 ret = 1;
763 err:
764 EC_KEY_free(sender_ephempubkey);
765 return ret;
766 }
767
eckem_encapsulate(void * vctx,unsigned char * out,size_t * outlen,unsigned char * secret,size_t * secretlen)768 static int eckem_encapsulate(void *vctx, unsigned char *out, size_t *outlen,
769 unsigned char *secret, size_t *secretlen)
770 {
771 PROV_EC_CTX *ctx = (PROV_EC_CTX *)vctx;
772
773 switch (ctx->mode) {
774 case KEM_MODE_DHKEM:
775 return dhkem_encap(ctx, out, outlen, secret, secretlen);
776 default:
777 ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_MODE);
778 return -2;
779 }
780 }
781
eckem_decapsulate(void * vctx,unsigned char * out,size_t * outlen,const unsigned char * in,size_t inlen)782 static int eckem_decapsulate(void *vctx, unsigned char *out, size_t *outlen,
783 const unsigned char *in, size_t inlen)
784 {
785 PROV_EC_CTX *ctx = (PROV_EC_CTX *)vctx;
786
787 switch (ctx->mode) {
788 case KEM_MODE_DHKEM:
789 return dhkem_decap(ctx, out, outlen, in, inlen);
790 default:
791 ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_MODE);
792 return -2;
793 }
794 }
795
796 const OSSL_DISPATCH ossl_ec_asym_kem_functions[] = {
797 { OSSL_FUNC_KEM_NEWCTX, (void (*)(void))eckem_newctx },
798 { OSSL_FUNC_KEM_ENCAPSULATE_INIT,
799 (void (*)(void))eckem_encapsulate_init },
800 { OSSL_FUNC_KEM_ENCAPSULATE, (void (*)(void))eckem_encapsulate },
801 { OSSL_FUNC_KEM_DECAPSULATE_INIT,
802 (void (*)(void))eckem_decapsulate_init },
803 { OSSL_FUNC_KEM_DECAPSULATE, (void (*)(void))eckem_decapsulate },
804 { OSSL_FUNC_KEM_FREECTX, (void (*)(void))eckem_freectx },
805 { OSSL_FUNC_KEM_SET_CTX_PARAMS,
806 (void (*)(void))eckem_set_ctx_params },
807 { OSSL_FUNC_KEM_SETTABLE_CTX_PARAMS,
808 (void (*)(void))eckem_settable_ctx_params },
809 { OSSL_FUNC_KEM_AUTH_ENCAPSULATE_INIT,
810 (void (*)(void))eckem_auth_encapsulate_init },
811 { OSSL_FUNC_KEM_AUTH_DECAPSULATE_INIT,
812 (void (*)(void))eckem_auth_decapsulate_init },
813 OSSL_DISPATCH_END
814 };
815