Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/crypto/openssl/providers/implementations/kem/ec_kem.c
48383 views
1
/*
2
* Copyright 2022-2025 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
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 */
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
*/
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
*/
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
*/
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
*/
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
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
ctx->mode = KEM_MODE_DHKEM;
201
202
return ctx;
203
}
204
205
static void eckem_freectx(void *vectx)
206
{
207
PROV_EC_CTX *ctx = (PROV_EC_CTX *)vectx;
208
209
OPENSSL_clear_free(ctx->ikm, ctx->ikmlen);
210
recipient_key_set(ctx, NULL);
211
sender_authkey_set(ctx, NULL);
212
OPENSSL_free(ctx);
213
}
214
215
static int ossl_ec_match_params(const EC_KEY *key1, const EC_KEY *key2)
216
{
217
int ret;
218
BN_CTX *ctx = NULL;
219
const EC_GROUP *group1 = EC_KEY_get0_group(key1);
220
const EC_GROUP *group2 = EC_KEY_get0_group(key2);
221
222
ctx = BN_CTX_new_ex(ossl_ec_key_get_libctx(key1));
223
if (ctx == NULL)
224
return 0;
225
226
ret = group1 != NULL
227
&& group2 != NULL
228
&& EC_GROUP_cmp(group1, group2, ctx) == 0;
229
if (!ret)
230
ERR_raise(ERR_LIB_PROV, PROV_R_MISMATCHING_DOMAIN_PARAMETERS);
231
BN_CTX_free(ctx);
232
return ret;
233
}
234
235
static int eckem_init(void *vctx, int operation, void *vec, void *vauth,
236
const OSSL_PARAM params[])
237
{
238
int rv;
239
PROV_EC_CTX *ctx = (PROV_EC_CTX *)vctx;
240
EC_KEY *ec = vec;
241
EC_KEY *auth = vauth;
242
243
if (!ossl_prov_is_running())
244
return 0;
245
246
if (!eckey_check(ec, operation == EVP_PKEY_OP_DECAPSULATE))
247
return 0;
248
rv = recipient_key_set(ctx, ec);
249
if (rv <= 0)
250
return rv;
251
252
if (auth != NULL) {
253
if (!ossl_ec_match_params(ec, auth)
254
|| !eckey_check(auth, operation == EVP_PKEY_OP_ENCAPSULATE)
255
|| !sender_authkey_set(ctx, auth))
256
return 0;
257
}
258
259
ctx->op = operation;
260
return eckem_set_ctx_params(vctx, params);
261
}
262
263
static int eckem_encapsulate_init(void *vctx, void *vec,
264
const OSSL_PARAM params[])
265
{
266
return eckem_init(vctx, EVP_PKEY_OP_ENCAPSULATE, vec, NULL, params);
267
}
268
269
static int eckem_decapsulate_init(void *vctx, void *vec,
270
const OSSL_PARAM params[])
271
{
272
return eckem_init(vctx, EVP_PKEY_OP_DECAPSULATE, vec, NULL, params);
273
}
274
275
static int eckem_auth_encapsulate_init(void *vctx, void *vecx, void *vauthpriv,
276
const OSSL_PARAM params[])
277
{
278
return eckem_init(vctx, EVP_PKEY_OP_ENCAPSULATE, vecx, vauthpriv, params);
279
}
280
281
static int eckem_auth_decapsulate_init(void *vctx, void *vecx, void *vauthpub,
282
const OSSL_PARAM params[])
283
{
284
return eckem_init(vctx, EVP_PKEY_OP_DECAPSULATE, vecx, vauthpub, params);
285
}
286
287
static int eckem_set_ctx_params(void *vctx, const OSSL_PARAM params[])
288
{
289
PROV_EC_CTX *ctx = (PROV_EC_CTX *)vctx;
290
const OSSL_PARAM *p;
291
int mode;
292
293
if (ossl_param_is_empty(params))
294
return 1;
295
296
p = OSSL_PARAM_locate_const(params, OSSL_KEM_PARAM_IKME);
297
if (p != NULL) {
298
void *tmp = NULL;
299
size_t tmplen = 0;
300
301
if (p->data != NULL && p->data_size != 0) {
302
if (!OSSL_PARAM_get_octet_string(p, &tmp, 0, &tmplen))
303
return 0;
304
}
305
OPENSSL_clear_free(ctx->ikm, ctx->ikmlen);
306
/* Set the ephemeral seed */
307
ctx->ikm = tmp;
308
ctx->ikmlen = tmplen;
309
}
310
311
p = OSSL_PARAM_locate_const(params, OSSL_KEM_PARAM_OPERATION);
312
if (p != NULL) {
313
if (p->data_type != OSSL_PARAM_UTF8_STRING)
314
return 0;
315
mode = ossl_eckem_modename2id(p->data);
316
if (mode == KEM_MODE_UNDEFINED)
317
return 0;
318
ctx->mode = mode;
319
}
320
return 1;
321
}
322
323
static const OSSL_PARAM known_settable_eckem_ctx_params[] = {
324
OSSL_PARAM_utf8_string(OSSL_KEM_PARAM_OPERATION, NULL, 0),
325
OSSL_PARAM_octet_string(OSSL_KEM_PARAM_IKME, NULL, 0),
326
OSSL_PARAM_END
327
};
328
329
static const OSSL_PARAM *eckem_settable_ctx_params(ossl_unused void *vctx,
330
ossl_unused void *provctx)
331
{
332
return known_settable_eckem_ctx_params;
333
}
334
335
/*
336
* See Section 4.1 DH-Based KEM (DHKEM) ExtractAndExpand
337
*/
338
static int dhkem_extract_and_expand(EVP_KDF_CTX *kctx,
339
unsigned char *okm, size_t okmlen,
340
uint16_t kemid,
341
const unsigned char *dhkm, size_t dhkmlen,
342
const unsigned char *kemctx,
343
size_t kemctxlen)
344
{
345
uint8_t suiteid[2];
346
uint8_t prk[EVP_MAX_MD_SIZE];
347
size_t prklen = okmlen;
348
int ret;
349
350
if (prklen > sizeof(prk))
351
return 0;
352
353
suiteid[0] = (kemid >> 8) & 0xff;
354
suiteid[1] = kemid & 0xff;
355
356
ret = ossl_hpke_labeled_extract(kctx, prk, prklen,
357
NULL, 0, LABEL_KEM, suiteid, sizeof(suiteid),
358
OSSL_DHKEM_LABEL_EAE_PRK, dhkm, dhkmlen)
359
&& ossl_hpke_labeled_expand(kctx, okm, okmlen, prk, prklen,
360
LABEL_KEM, suiteid, sizeof(suiteid),
361
OSSL_DHKEM_LABEL_SHARED_SECRET,
362
kemctx, kemctxlen);
363
OPENSSL_cleanse(prk, prklen);
364
return ret;
365
}
366
367
/*
368
* See Section 7.1.3 DeriveKeyPair.
369
*
370
* This function is used by ec keygen.
371
* (For this reason it does not use any of the state stored in PROV_EC_CTX).
372
*
373
* Params:
374
* ec An initialized ec key.
375
* priv The buffer to store the generated private key into (it is assumed
376
* this is of length alg->encodedprivlen).
377
* ikm buffer containing the input key material (seed). This must be set.
378
* ikmlen size of the ikm buffer in bytes
379
* Returns:
380
* 1 if successful or 0 otherwise.
381
*/
382
int ossl_ec_dhkem_derive_private(EC_KEY *ec, BIGNUM *priv,
383
const unsigned char *ikm, size_t ikmlen)
384
{
385
int ret = 0;
386
EVP_KDF_CTX *kdfctx = NULL;
387
uint8_t suiteid[2];
388
unsigned char prk[OSSL_HPKE_MAX_SECRET];
389
unsigned char privbuf[OSSL_HPKE_MAX_PRIVATE];
390
const BIGNUM *order;
391
unsigned char counter = 0;
392
const char *curve = ec_curvename_get0(ec);
393
const OSSL_HPKE_KEM_INFO *info;
394
395
if (curve == NULL)
396
return -2;
397
398
info = ossl_HPKE_KEM_INFO_find_curve(curve);
399
if (info == NULL)
400
return -2;
401
402
kdfctx = ossl_kdf_ctx_create("HKDF", info->mdname,
403
ossl_ec_key_get_libctx(ec),
404
ossl_ec_key_get0_propq(ec));
405
if (kdfctx == NULL)
406
return 0;
407
408
/* ikmlen should have a length of at least Nsk */
409
if (ikmlen < info->Nsk) {
410
ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_INPUT_LENGTH,
411
"ikm length is :%zu, should be at least %zu",
412
ikmlen, info->Nsk);
413
goto err;
414
}
415
416
suiteid[0] = info->kem_id / 256;
417
suiteid[1] = info->kem_id % 256;
418
419
if (!ossl_hpke_labeled_extract(kdfctx, prk, info->Nsecret,
420
NULL, 0, LABEL_KEM, suiteid, sizeof(suiteid),
421
OSSL_DHKEM_LABEL_DKP_PRK, ikm, ikmlen))
422
goto err;
423
424
order = EC_GROUP_get0_order(EC_KEY_get0_group(ec));
425
do {
426
if (!ossl_hpke_labeled_expand(kdfctx, privbuf, info->Nsk,
427
prk, info->Nsecret,
428
LABEL_KEM, suiteid, sizeof(suiteid),
429
OSSL_DHKEM_LABEL_CANDIDATE,
430
&counter, 1))
431
goto err;
432
privbuf[0] &= info->bitmask;
433
if (BN_bin2bn(privbuf, info->Nsk, priv) == NULL)
434
goto err;
435
if (counter == 0xFF) {
436
ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GENERATE_KEY);
437
goto err;
438
}
439
counter++;
440
} while (BN_is_zero(priv) || BN_cmp(priv, order) >= 0);
441
ret = 1;
442
err:
443
OPENSSL_cleanse(prk, sizeof(prk));
444
OPENSSL_cleanse(privbuf, sizeof(privbuf));
445
EVP_KDF_CTX_free(kdfctx);
446
return ret;
447
}
448
449
/*
450
* Do a keygen operation without having to use EVP_PKEY.
451
* Params:
452
* ctx Context object
453
* ikm The seed material - if this is NULL, then a random seed is used.
454
* Returns:
455
* The generated EC key, or NULL on failure.
456
*/
457
static EC_KEY *derivekey(PROV_EC_CTX *ctx,
458
const unsigned char *ikm, size_t ikmlen)
459
{
460
int ret = 0;
461
EC_KEY *key;
462
unsigned char *seed = (unsigned char *)ikm;
463
size_t seedlen = ikmlen;
464
unsigned char tmpbuf[OSSL_HPKE_MAX_PRIVATE];
465
466
key = EC_KEY_new_ex(ctx->libctx, ctx->propq);
467
if (key == NULL)
468
goto err;
469
if (!EC_KEY_set_group(key, EC_KEY_get0_group(ctx->recipient_key)))
470
goto err;
471
472
/* Generate a random seed if there is no input ikm */
473
if (seed == NULL || seedlen == 0) {
474
seedlen = ctx->info->Nsk;
475
if (seedlen > sizeof(tmpbuf))
476
goto err;
477
if (RAND_priv_bytes_ex(ctx->libctx, tmpbuf, seedlen, 0) <= 0)
478
goto err;
479
seed = tmpbuf;
480
}
481
ret = ossl_ec_generate_key_dhkem(key, seed, seedlen);
482
err:
483
if (seed != ikm)
484
OPENSSL_cleanse(seed, seedlen);
485
if (ret <= 0) {
486
EC_KEY_free(key);
487
key = NULL;
488
}
489
return key;
490
}
491
492
/*
493
* Before doing a key exchange the public key of the peer needs to be checked
494
* Note that the group check is not done here as we have already checked
495
* that it only uses one of the approved curve names when the key was set.
496
*
497
* Returns 1 if the public key is valid, or 0 if it fails.
498
*/
499
static int check_publickey(const EC_KEY *pub)
500
{
501
int ret = 0;
502
BN_CTX *bnctx = BN_CTX_new_ex(ossl_ec_key_get_libctx(pub));
503
504
if (bnctx == NULL)
505
return 0;
506
ret = ossl_ec_key_public_check(pub, bnctx);
507
BN_CTX_free(bnctx);
508
509
return ret;
510
}
511
512
/*
513
* Do an ecdh key exchange.
514
* dhkm = DH(sender, peer)
515
*
516
* NOTE: Instead of using EVP_PKEY_derive() API's, we use EC_KEY operations
517
* to avoid messy conversions back to EVP_PKEY.
518
*
519
* Returns the size of the secret if successful, or 0 otherwise,
520
*/
521
static int generate_ecdhkm(const EC_KEY *sender, const EC_KEY *peer,
522
unsigned char *out, size_t maxout,
523
unsigned int secretsz)
524
{
525
const EC_GROUP *group = EC_KEY_get0_group(sender);
526
size_t secretlen = (EC_GROUP_get_degree(group) + 7) / 8;
527
528
if (secretlen != secretsz || secretlen > maxout) {
529
ERR_raise_data(ERR_LIB_PROV, PROV_R_BAD_LENGTH, "secretsz invalid");
530
return 0;
531
}
532
533
if (!check_publickey(peer))
534
return 0;
535
return ECDH_compute_key(out, secretlen, EC_KEY_get0_public_key(peer),
536
sender, NULL) > 0;
537
}
538
539
/*
540
* Derive a secret using ECDH (code is shared by the encap and decap)
541
*
542
* dhkm = Concat(ecdh(privkey1, peerkey1), ecdh(privkey2, peerkey2)
543
* kemctx = Concat(sender_pub, recipient_pub, ctx->sender_authkey)
544
* secret = dhkem_extract_and_expand(kemid, dhkm, kemctx);
545
*
546
* Params:
547
* ctx Object that contains algorithm state and constants.
548
* secret The returned secret (with a length ctx->alg->secretlen bytes).
549
* privkey1 A private key used for ECDH key derivation.
550
* peerkey1 A public key used for ECDH key derivation with privkey1
551
* privkey2 A optional private key used for a second ECDH key derivation.
552
* It can be NULL.
553
* peerkey2 A optional public key used for a second ECDH key derivation
554
* with privkey2,. It can be NULL.
555
* sender_pub The senders public key in encoded form.
556
* recipient_pub The recipients public key in encoded form.
557
* Notes:
558
* The second ecdh() is only used for the HPKE auth modes when both privkey2
559
* and peerkey2 are non NULL (i.e. ctx->sender_authkey is not NULL).
560
*/
561
static int derive_secret(PROV_EC_CTX *ctx, unsigned char *secret,
562
const EC_KEY *privkey1, const EC_KEY *peerkey1,
563
const EC_KEY *privkey2, const EC_KEY *peerkey2,
564
const unsigned char *sender_pub,
565
const unsigned char *recipient_pub)
566
{
567
int ret = 0;
568
EVP_KDF_CTX *kdfctx = NULL;
569
unsigned char sender_authpub[OSSL_HPKE_MAX_PUBLIC];
570
unsigned char dhkm[OSSL_HPKE_MAX_PRIVATE * 2];
571
unsigned char kemctx[OSSL_HPKE_MAX_PUBLIC * 3];
572
size_t sender_authpublen;
573
size_t kemctxlen = 0, dhkmlen = 0;
574
const OSSL_HPKE_KEM_INFO *info = ctx->info;
575
size_t encodedpublen = info->Npk;
576
size_t encodedprivlen = info->Nsk;
577
int auth = ctx->sender_authkey != NULL;
578
579
if (!generate_ecdhkm(privkey1, peerkey1, dhkm, sizeof(dhkm), encodedprivlen))
580
goto err;
581
dhkmlen = encodedprivlen;
582
kemctxlen = 2 * encodedpublen;
583
584
/* Concat the optional second ECDH (used for Auth) */
585
if (auth) {
586
/* Get the public key of the auth sender in encoded form */
587
if (!ecpubkey_todata(ctx->sender_authkey, sender_authpub,
588
&sender_authpublen, sizeof(sender_authpub)))
589
goto err;
590
if (sender_authpublen != encodedpublen) {
591
ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_KEY,
592
"Invalid sender auth public key");
593
goto err;
594
}
595
if (!generate_ecdhkm(privkey2, peerkey2,
596
dhkm + dhkmlen, sizeof(dhkm) - dhkmlen,
597
encodedprivlen))
598
goto err;
599
dhkmlen += encodedprivlen;
600
kemctxlen += encodedpublen;
601
}
602
if (kemctxlen > sizeof(kemctx))
603
goto err;
604
605
/* kemctx is the concat of both sides encoded public key */
606
memcpy(kemctx, sender_pub, info->Npk);
607
memcpy(kemctx + info->Npk, recipient_pub, info->Npk);
608
if (auth)
609
memcpy(kemctx + 2 * encodedpublen, sender_authpub, encodedpublen);
610
kdfctx = ossl_kdf_ctx_create(ctx->kdfname, info->mdname,
611
ctx->libctx, ctx->propq);
612
if (kdfctx == NULL)
613
goto err;
614
if (!dhkem_extract_and_expand(kdfctx, secret, info->Nsecret,
615
info->kem_id, dhkm, dhkmlen,
616
kemctx, kemctxlen))
617
goto err;
618
ret = 1;
619
err:
620
OPENSSL_cleanse(dhkm, dhkmlen);
621
EVP_KDF_CTX_free(kdfctx);
622
return ret;
623
}
624
625
/*
626
* Do a DHKEM encapsulate operation.
627
*
628
* See Section 4.1 Encap() and AuthEncap()
629
*
630
* Params:
631
* ctx A context object holding the recipients public key and the
632
* optional senders auth private key.
633
* enc A buffer to return the senders ephemeral public key.
634
* Setting this to NULL allows the enclen and secretlen to return
635
* values, without calculating the secret.
636
* enclen Passes in the max size of the enc buffer and returns the
637
* encoded public key length.
638
* secret A buffer to return the calculated shared secret.
639
* secretlen Passes in the max size of the secret buffer and returns the
640
* secret length.
641
* Returns: 1 on success or 0 otherwise.
642
*/
643
static int dhkem_encap(PROV_EC_CTX *ctx,
644
unsigned char *enc, size_t *enclen,
645
unsigned char *secret, size_t *secretlen)
646
{
647
int ret = 0;
648
EC_KEY *sender_ephemkey = NULL;
649
unsigned char sender_pub[OSSL_HPKE_MAX_PUBLIC];
650
unsigned char recipient_pub[OSSL_HPKE_MAX_PUBLIC];
651
size_t sender_publen, recipient_publen;
652
const OSSL_HPKE_KEM_INFO *info = ctx->info;
653
654
if (enc == NULL) {
655
if (enclen == NULL && secretlen == NULL)
656
return 0;
657
if (enclen != NULL)
658
*enclen = info->Nenc;
659
if (secretlen != NULL)
660
*secretlen = info->Nsecret;
661
return 1;
662
}
663
664
if (*secretlen < info->Nsecret) {
665
ERR_raise_data(ERR_LIB_PROV, PROV_R_BAD_LENGTH, "*secretlen too small");
666
return 0;
667
}
668
if (*enclen < info->Nenc) {
669
ERR_raise_data(ERR_LIB_PROV, PROV_R_BAD_LENGTH, "*enclen too small");
670
return 0;
671
}
672
673
/* Create an ephemeral key */
674
sender_ephemkey = derivekey(ctx, ctx->ikm, ctx->ikmlen);
675
if (sender_ephemkey == NULL)
676
goto err;
677
if (!ecpubkey_todata(sender_ephemkey, sender_pub, &sender_publen,
678
sizeof(sender_pub))
679
|| !ecpubkey_todata(ctx->recipient_key, recipient_pub,
680
&recipient_publen, sizeof(recipient_pub)))
681
goto err;
682
683
if (sender_publen != info->Npk
684
|| recipient_publen != sender_publen) {
685
ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_KEY, "Invalid public key");
686
goto err;
687
}
688
689
if (!derive_secret(ctx, secret,
690
sender_ephemkey, ctx->recipient_key,
691
ctx->sender_authkey, ctx->recipient_key,
692
sender_pub, recipient_pub))
693
goto err;
694
695
/* Return the senders ephemeral public key in encoded form */
696
memcpy(enc, sender_pub, sender_publen);
697
*enclen = sender_publen;
698
*secretlen = info->Nsecret;
699
ret = 1;
700
err:
701
EC_KEY_free(sender_ephemkey);
702
return ret;
703
}
704
705
/*
706
* Do a DHKEM decapsulate operation.
707
* See Section 4.1 Decap() and Auth Decap()
708
*
709
* Params:
710
* ctx A context object holding the recipients private key and the
711
* optional senders auth public key.
712
* secret A buffer to return the calculated shared secret. Setting this to
713
* NULL can be used to return the secretlen.
714
* secretlen Passes in the max size of the secret buffer and returns the
715
* secret length.
716
* enc A buffer containing the senders ephemeral public key that was returned
717
* from dhkem_encap().
718
* enclen The length in bytes of enc.
719
* Returns: 1 If the shared secret is returned or 0 on error.
720
*/
721
static int dhkem_decap(PROV_EC_CTX *ctx,
722
unsigned char *secret, size_t *secretlen,
723
const unsigned char *enc, size_t enclen)
724
{
725
int ret = 0;
726
EC_KEY *sender_ephempubkey = NULL;
727
const OSSL_HPKE_KEM_INFO *info = ctx->info;
728
unsigned char recipient_pub[OSSL_HPKE_MAX_PUBLIC];
729
size_t recipient_publen;
730
size_t encodedpublen = info->Npk;
731
732
if (secret == NULL) {
733
*secretlen = info->Nsecret;
734
return 1;
735
}
736
737
if (*secretlen < info->Nsecret) {
738
ERR_raise_data(ERR_LIB_PROV, PROV_R_BAD_LENGTH, "*secretlen too small");
739
return 0;
740
}
741
if (enclen != encodedpublen) {
742
ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_KEY, "Invalid enc public key");
743
return 0;
744
}
745
746
sender_ephempubkey = eckey_frompub(ctx->recipient_key, enc, enclen);
747
if (sender_ephempubkey == NULL)
748
goto err;
749
if (!ecpubkey_todata(ctx->recipient_key, recipient_pub, &recipient_publen,
750
sizeof(recipient_pub)))
751
goto err;
752
if (recipient_publen != encodedpublen) {
753
ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_KEY, "Invalid recipient public key");
754
goto err;
755
}
756
757
if (!derive_secret(ctx, secret,
758
ctx->recipient_key, sender_ephempubkey,
759
ctx->recipient_key, ctx->sender_authkey,
760
enc, recipient_pub))
761
goto err;
762
*secretlen = info->Nsecret;
763
ret = 1;
764
err:
765
EC_KEY_free(sender_ephempubkey);
766
return ret;
767
}
768
769
static int eckem_encapsulate(void *vctx, unsigned char *out, size_t *outlen,
770
unsigned char *secret, size_t *secretlen)
771
{
772
PROV_EC_CTX *ctx = (PROV_EC_CTX *)vctx;
773
774
switch (ctx->mode) {
775
case KEM_MODE_DHKEM:
776
return dhkem_encap(ctx, out, outlen, secret, secretlen);
777
default:
778
ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_MODE);
779
return -2;
780
}
781
}
782
783
static int eckem_decapsulate(void *vctx, unsigned char *out, size_t *outlen,
784
const unsigned char *in, size_t inlen)
785
{
786
PROV_EC_CTX *ctx = (PROV_EC_CTX *)vctx;
787
788
switch (ctx->mode) {
789
case KEM_MODE_DHKEM:
790
return dhkem_decap(ctx, out, outlen, in, inlen);
791
default:
792
ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_MODE);
793
return -2;
794
}
795
}
796
797
const OSSL_DISPATCH ossl_ec_asym_kem_functions[] = {
798
{ OSSL_FUNC_KEM_NEWCTX, (void (*)(void))eckem_newctx },
799
{ OSSL_FUNC_KEM_ENCAPSULATE_INIT,
800
(void (*)(void))eckem_encapsulate_init },
801
{ OSSL_FUNC_KEM_ENCAPSULATE, (void (*)(void))eckem_encapsulate },
802
{ OSSL_FUNC_KEM_DECAPSULATE_INIT,
803
(void (*)(void))eckem_decapsulate_init },
804
{ OSSL_FUNC_KEM_DECAPSULATE, (void (*)(void))eckem_decapsulate },
805
{ OSSL_FUNC_KEM_FREECTX, (void (*)(void))eckem_freectx },
806
{ OSSL_FUNC_KEM_SET_CTX_PARAMS,
807
(void (*)(void))eckem_set_ctx_params },
808
{ OSSL_FUNC_KEM_SETTABLE_CTX_PARAMS,
809
(void (*)(void))eckem_settable_ctx_params },
810
{ OSSL_FUNC_KEM_AUTH_ENCAPSULATE_INIT,
811
(void (*)(void))eckem_auth_encapsulate_init },
812
{ OSSL_FUNC_KEM_AUTH_DECAPSULATE_INIT,
813
(void (*)(void))eckem_auth_decapsulate_init },
814
OSSL_DISPATCH_END
815
};
816
817