Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/crypto/openssl/providers/implementations/kem/ecx_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
* ECX keys (i.e. X25519 and X448)
13
* References to Sections in the comments below refer to RFC 9180.
14
*/
15
16
#include "internal/deprecated.h"
17
18
#include <string.h>
19
#include <openssl/crypto.h>
20
#include <openssl/evp.h>
21
#include <openssl/core_dispatch.h>
22
#include <openssl/core_names.h>
23
#include <openssl/params.h>
24
#include <openssl/kdf.h>
25
#include <openssl/err.h>
26
#include <openssl/sha.h>
27
#include <openssl/rand.h>
28
#include <openssl/proverr.h>
29
#include "prov/provider_ctx.h"
30
#include "prov/implementations.h"
31
#include "prov/securitycheck.h"
32
#include "prov/providercommon.h"
33
#include "prov/ecx.h"
34
#include "crypto/ecx.h"
35
#include <openssl/hpke.h>
36
#include "internal/hpke_util.h"
37
#include "eckem.h"
38
39
#define MAX_ECX_KEYLEN X448_KEYLEN
40
41
/* KEM identifiers from Section 7.1 "Table 2 KEM IDs" */
42
#define KEMID_X25519_HKDF_SHA256 0x20
43
#define KEMID_X448_HKDF_SHA512 0x21
44
45
/* ASCII: "KEM", in hex for EBCDIC compatibility */
46
static const char LABEL_KEM[] = "\x4b\x45\x4d";
47
48
typedef struct {
49
ECX_KEY *recipient_key;
50
ECX_KEY *sender_authkey;
51
OSSL_LIB_CTX *libctx;
52
char *propq;
53
unsigned int mode;
54
unsigned int op;
55
unsigned char *ikm;
56
size_t ikmlen;
57
const char *kdfname;
58
const OSSL_HPKE_KEM_INFO *info;
59
} PROV_ECX_CTX;
60
61
static OSSL_FUNC_kem_newctx_fn ecxkem_newctx;
62
static OSSL_FUNC_kem_encapsulate_init_fn ecxkem_encapsulate_init;
63
static OSSL_FUNC_kem_encapsulate_fn ecxkem_encapsulate;
64
static OSSL_FUNC_kem_decapsulate_init_fn ecxkem_decapsulate_init;
65
static OSSL_FUNC_kem_decapsulate_fn ecxkem_decapsulate;
66
static OSSL_FUNC_kem_freectx_fn ecxkem_freectx;
67
static OSSL_FUNC_kem_set_ctx_params_fn ecxkem_set_ctx_params;
68
static OSSL_FUNC_kem_auth_encapsulate_init_fn ecxkem_auth_encapsulate_init;
69
static OSSL_FUNC_kem_auth_decapsulate_init_fn ecxkem_auth_decapsulate_init;
70
71
/*
72
* Set KEM values as specified in Section 7.1 "Table 2 KEM IDs"
73
* There is only one set of values for X25519 and X448.
74
* Additional values could be set via set_params if required.
75
*/
76
static const OSSL_HPKE_KEM_INFO *get_kem_info(ECX_KEY *ecx)
77
{
78
const char *name = NULL;
79
80
if (ecx->type == ECX_KEY_TYPE_X25519)
81
name = SN_X25519;
82
else
83
name = SN_X448;
84
return ossl_HPKE_KEM_INFO_find_curve(name);
85
}
86
87
/*
88
* Set the recipient key, and free any existing key.
89
* ecx can be NULL. The ecx key may have only a private or public component.
90
*/
91
static int recipient_key_set(PROV_ECX_CTX *ctx, ECX_KEY *ecx)
92
{
93
ossl_ecx_key_free(ctx->recipient_key);
94
ctx->recipient_key = NULL;
95
if (ecx != NULL) {
96
ctx->info = get_kem_info(ecx);
97
if (ctx->info == NULL)
98
return -2;
99
ctx->kdfname = "HKDF";
100
if (!ossl_ecx_key_up_ref(ecx))
101
return 0;
102
ctx->recipient_key = ecx;
103
}
104
return 1;
105
}
106
107
/*
108
* Set the senders auth key, and free any existing auth key.
109
* ecx can be NULL.
110
*/
111
static int sender_authkey_set(PROV_ECX_CTX *ctx, ECX_KEY *ecx)
112
{
113
ossl_ecx_key_free(ctx->sender_authkey);
114
ctx->sender_authkey = NULL;
115
116
if (ecx != NULL) {
117
if (!ossl_ecx_key_up_ref(ecx))
118
return 0;
119
ctx->sender_authkey = ecx;
120
}
121
return 1;
122
}
123
124
/*
125
* Serialize a public key from byte array's for the encoded public keys.
126
* ctx is used to access the key type.
127
* Returns: The created ECX_KEY or NULL on error.
128
*/
129
static ECX_KEY *ecxkey_pubfromdata(PROV_ECX_CTX *ctx,
130
const unsigned char *pubbuf, size_t pubbuflen)
131
{
132
ECX_KEY *ecx = NULL;
133
OSSL_PARAM params[2], *p = params;
134
135
*p++ = OSSL_PARAM_construct_octet_string(OSSL_PKEY_PARAM_PUB_KEY,
136
(char *)pubbuf, pubbuflen);
137
*p = OSSL_PARAM_construct_end();
138
139
ecx = ossl_ecx_key_new(ctx->libctx, ctx->recipient_key->type, 1, ctx->propq);
140
if (ecx == NULL)
141
return NULL;
142
if (ossl_ecx_key_fromdata(ecx, params, 0) <= 0) {
143
ossl_ecx_key_free(ecx);
144
ecx = NULL;
145
}
146
return ecx;
147
}
148
149
static unsigned char *ecx_pubkey(ECX_KEY *ecx)
150
{
151
if (ecx == NULL || !ecx->haspubkey) {
152
ERR_raise(ERR_LIB_PROV, PROV_R_NOT_A_PUBLIC_KEY);
153
return 0;
154
}
155
return ecx->pubkey;
156
}
157
158
static void *ecxkem_newctx(void *provctx)
159
{
160
PROV_ECX_CTX *ctx = OPENSSL_zalloc(sizeof(PROV_ECX_CTX));
161
162
if (ctx == NULL)
163
return NULL;
164
ctx->libctx = PROV_LIBCTX_OF(provctx);
165
ctx->mode = KEM_MODE_DHKEM;
166
167
return ctx;
168
}
169
170
static void ecxkem_freectx(void *vectx)
171
{
172
PROV_ECX_CTX *ctx = (PROV_ECX_CTX *)vectx;
173
174
OPENSSL_clear_free(ctx->ikm, ctx->ikmlen);
175
recipient_key_set(ctx, NULL);
176
sender_authkey_set(ctx, NULL);
177
OPENSSL_free(ctx);
178
}
179
180
static int ecx_match_params(const ECX_KEY *key1, const ECX_KEY *key2)
181
{
182
return (key1->type == key2->type && key1->keylen == key2->keylen);
183
}
184
185
static int ecx_key_check(const ECX_KEY *ecx, int requires_privatekey)
186
{
187
if (ecx->privkey == NULL)
188
return (requires_privatekey == 0);
189
return 1;
190
}
191
192
static int ecxkem_init(void *vecxctx, int operation, void *vecx, void *vauth,
193
ossl_unused const OSSL_PARAM params[])
194
{
195
int rv;
196
PROV_ECX_CTX *ctx = (PROV_ECX_CTX *)vecxctx;
197
ECX_KEY *ecx = vecx;
198
ECX_KEY *auth = vauth;
199
200
if (!ossl_prov_is_running())
201
return 0;
202
203
if (!ecx_key_check(ecx, operation == EVP_PKEY_OP_DECAPSULATE))
204
return 0;
205
rv = recipient_key_set(ctx, ecx);
206
if (rv <= 0)
207
return rv;
208
209
if (auth != NULL) {
210
if (!ecx_match_params(auth, ctx->recipient_key)
211
|| !ecx_key_check(auth, operation == EVP_PKEY_OP_ENCAPSULATE)
212
|| !sender_authkey_set(ctx, auth))
213
return 0;
214
}
215
216
ctx->op = operation;
217
return ecxkem_set_ctx_params(vecxctx, params);
218
}
219
220
static int ecxkem_encapsulate_init(void *vecxctx, void *vecx,
221
const OSSL_PARAM params[])
222
{
223
return ecxkem_init(vecxctx, EVP_PKEY_OP_ENCAPSULATE, vecx, NULL, params);
224
}
225
226
static int ecxkem_decapsulate_init(void *vecxctx, void *vecx,
227
const OSSL_PARAM params[])
228
{
229
return ecxkem_init(vecxctx, EVP_PKEY_OP_DECAPSULATE, vecx, NULL, params);
230
}
231
232
static int ecxkem_auth_encapsulate_init(void *vctx, void *vecx, void *vauthpriv,
233
const OSSL_PARAM params[])
234
{
235
return ecxkem_init(vctx, EVP_PKEY_OP_ENCAPSULATE, vecx, vauthpriv, params);
236
}
237
238
static int ecxkem_auth_decapsulate_init(void *vctx, void *vecx, void *vauthpub,
239
const OSSL_PARAM params[])
240
{
241
return ecxkem_init(vctx, EVP_PKEY_OP_DECAPSULATE, vecx, vauthpub, params);
242
}
243
244
static int ecxkem_set_ctx_params(void *vctx, const OSSL_PARAM params[])
245
{
246
PROV_ECX_CTX *ctx = (PROV_ECX_CTX *)vctx;
247
const OSSL_PARAM *p;
248
int mode;
249
250
if (ctx == NULL)
251
return 0;
252
if (ossl_param_is_empty(params))
253
return 1;
254
255
p = OSSL_PARAM_locate_const(params, OSSL_KEM_PARAM_IKME);
256
if (p != NULL) {
257
void *tmp = NULL;
258
size_t tmplen = 0;
259
260
if (p->data != NULL && p->data_size != 0) {
261
if (!OSSL_PARAM_get_octet_string(p, &tmp, 0, &tmplen))
262
return 0;
263
}
264
OPENSSL_clear_free(ctx->ikm, ctx->ikmlen);
265
ctx->ikm = tmp;
266
ctx->ikmlen = tmplen;
267
}
268
p = OSSL_PARAM_locate_const(params, OSSL_KEM_PARAM_OPERATION);
269
if (p != NULL) {
270
if (p->data_type != OSSL_PARAM_UTF8_STRING)
271
return 0;
272
mode = ossl_eckem_modename2id(p->data);
273
if (mode == KEM_MODE_UNDEFINED)
274
return 0;
275
ctx->mode = mode;
276
}
277
return 1;
278
}
279
280
static const OSSL_PARAM known_settable_ecxkem_ctx_params[] = {
281
OSSL_PARAM_utf8_string(OSSL_KEM_PARAM_OPERATION, NULL, 0),
282
OSSL_PARAM_octet_string(OSSL_KEM_PARAM_IKME, NULL, 0),
283
OSSL_PARAM_END
284
};
285
286
static const OSSL_PARAM *ecxkem_settable_ctx_params(ossl_unused void *vctx,
287
ossl_unused void *provctx)
288
{
289
return known_settable_ecxkem_ctx_params;
290
}
291
292
/*
293
* See Section 4.1 DH-Based KEM (DHKEM) ExtractAndExpand
294
*/
295
static int dhkem_extract_and_expand(EVP_KDF_CTX *kctx,
296
unsigned char *okm, size_t okmlen,
297
uint16_t kemid,
298
const unsigned char *dhkm, size_t dhkmlen,
299
const unsigned char *kemctx,
300
size_t kemctxlen)
301
{
302
uint8_t suiteid[2];
303
uint8_t prk[EVP_MAX_MD_SIZE];
304
size_t prklen = okmlen; /* Nh */
305
int ret;
306
307
if (prklen > sizeof(prk))
308
return 0;
309
310
suiteid[0] = (kemid >> 8) &0xff;
311
suiteid[1] = kemid & 0xff;
312
313
ret = ossl_hpke_labeled_extract(kctx, prk, prklen,
314
NULL, 0, LABEL_KEM, suiteid, sizeof(suiteid),
315
OSSL_DHKEM_LABEL_EAE_PRK, dhkm, dhkmlen)
316
&& ossl_hpke_labeled_expand(kctx, okm, okmlen, prk, prklen,
317
LABEL_KEM, suiteid, sizeof(suiteid),
318
OSSL_DHKEM_LABEL_SHARED_SECRET,
319
kemctx, kemctxlen);
320
OPENSSL_cleanse(prk, prklen);
321
return ret;
322
}
323
324
/*
325
* See Section 7.1.3 DeriveKeyPair.
326
*
327
* This function is used by ecx keygen.
328
* (For this reason it does not use any of the state stored in PROV_ECX_CTX).
329
*
330
* Params:
331
* ecx An initialized ecx key.
332
* privout The buffer to store the generated private key into (it is assumed
333
* this is of length ecx->keylen).
334
* ikm buffer containing the input key material (seed). This must be non NULL.
335
* ikmlen size of the ikm buffer in bytes
336
* Returns:
337
* 1 if successful or 0 otherwise.
338
*/
339
int ossl_ecx_dhkem_derive_private(ECX_KEY *ecx, unsigned char *privout,
340
const unsigned char *ikm, size_t ikmlen)
341
{
342
int ret = 0;
343
EVP_KDF_CTX *kdfctx = NULL;
344
unsigned char prk[EVP_MAX_MD_SIZE];
345
uint8_t suiteid[2];
346
const OSSL_HPKE_KEM_INFO *info = get_kem_info(ecx);
347
348
/* ikmlen should have a length of at least Nsk */
349
if (ikmlen < info->Nsk) {
350
ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_INPUT_LENGTH,
351
"ikm length is :%zu, should be at least %zu",
352
ikmlen, info->Nsk);
353
goto err;
354
}
355
356
kdfctx = ossl_kdf_ctx_create("HKDF", info->mdname, ecx->libctx, ecx->propq);
357
if (kdfctx == NULL)
358
return 0;
359
360
suiteid[0] = info->kem_id / 256;
361
suiteid[1] = info->kem_id % 256;
362
363
if (!ossl_hpke_labeled_extract(kdfctx, prk, info->Nsecret,
364
NULL, 0, LABEL_KEM, suiteid, sizeof(suiteid),
365
OSSL_DHKEM_LABEL_DKP_PRK, ikm, ikmlen))
366
goto err;
367
368
if (!ossl_hpke_labeled_expand(kdfctx, privout, info->Nsk, prk, info->Nsecret,
369
LABEL_KEM, suiteid, sizeof(suiteid),
370
OSSL_DHKEM_LABEL_SK, NULL, 0))
371
goto err;
372
ret = 1;
373
err:
374
OPENSSL_cleanse(prk, sizeof(prk));
375
EVP_KDF_CTX_free(kdfctx);
376
return ret;
377
}
378
379
/*
380
* Do a keygen operation without having to use EVP_PKEY.
381
* Params:
382
* ctx Context object
383
* ikm The seed material - if this is NULL, then a random seed is used.
384
* Returns:
385
* The generated ECX key, or NULL on failure.
386
*/
387
static ECX_KEY *derivekey(PROV_ECX_CTX *ctx,
388
const unsigned char *ikm, size_t ikmlen)
389
{
390
int ok = 0;
391
ECX_KEY *key;
392
unsigned char *privkey;
393
unsigned char *seed = (unsigned char *)ikm;
394
size_t seedlen = ikmlen;
395
unsigned char tmpbuf[OSSL_HPKE_MAX_PRIVATE];
396
const OSSL_HPKE_KEM_INFO *info = ctx->info;
397
398
key = ossl_ecx_key_new(ctx->libctx, ctx->recipient_key->type, 0, ctx->propq);
399
if (key == NULL)
400
return NULL;
401
privkey = ossl_ecx_key_allocate_privkey(key);
402
if (privkey == NULL)
403
goto err;
404
405
/* Generate a random seed if there is no input ikm */
406
if (seed == NULL || seedlen == 0) {
407
if (info->Nsk > sizeof(tmpbuf))
408
goto err;
409
if (RAND_priv_bytes_ex(ctx->libctx, tmpbuf, info->Nsk, 0) <= 0)
410
goto err;
411
seed = tmpbuf;
412
seedlen = info->Nsk;
413
}
414
if (!ossl_ecx_dhkem_derive_private(key, privkey, seed, seedlen))
415
goto err;
416
if (!ossl_ecx_public_from_private(key))
417
goto err;
418
key->haspubkey = 1;
419
ok = 1;
420
err:
421
if (!ok) {
422
ossl_ecx_key_free(key);
423
key = NULL;
424
}
425
if (seed != ikm)
426
OPENSSL_cleanse(seed, seedlen);
427
return key;
428
}
429
430
/*
431
* Do an ecxdh key exchange.
432
* dhkm = DH(sender, peer)
433
*
434
* NOTE: Instead of using EVP_PKEY_derive() API's, we use ECX_KEY operations
435
* to avoid messy conversions back to EVP_PKEY.
436
*
437
* Returns the size of the secret if successful, or 0 otherwise,
438
*/
439
static int generate_ecxdhkm(const ECX_KEY *sender, const ECX_KEY *peer,
440
unsigned char *out, size_t maxout,
441
unsigned int secretsz)
442
{
443
size_t len = 0;
444
445
/* NOTE: ossl_ecx_compute_key checks for shared secret being all zeros */
446
return ossl_ecx_compute_key((ECX_KEY *)peer, (ECX_KEY *)sender,
447
sender->keylen, out, &len, maxout);
448
}
449
450
/*
451
* Derive a secret using ECXDH (code is shared by the encap and decap)
452
*
453
* dhkm = Concat(ecxdh(privkey1, peerkey1), ecdh(privkey2, peerkey2)
454
* kemctx = Concat(sender_pub, recipient_pub, ctx->sender_authkey)
455
* secret = dhkem_extract_and_expand(kemid, dhkm, kemctx);
456
*
457
* Params:
458
* ctx Object that contains algorithm state and constants.
459
* secret The returned secret (with a length ctx->alg->secretlen bytes).
460
* privkey1 A private key used for ECXDH key derivation.
461
* peerkey1 A public key used for ECXDH key derivation with privkey1
462
* privkey2 A optional private key used for a second ECXDH key derivation.
463
* It can be NULL.
464
* peerkey2 A optional public key used for a second ECXDH key derivation
465
* with privkey2,. It can be NULL.
466
* sender_pub The senders public key in encoded form.
467
* recipient_pub The recipients public key in encoded form.
468
* Notes:
469
* The second ecdh() is only used for the HPKE auth modes when both privkey2
470
* and peerkey2 are non NULL (i.e. ctx->sender_authkey is not NULL).
471
*/
472
static int derive_secret(PROV_ECX_CTX *ctx, unsigned char *secret,
473
const ECX_KEY *privkey1, const ECX_KEY *peerkey1,
474
const ECX_KEY *privkey2, const ECX_KEY *peerkey2,
475
const unsigned char *sender_pub,
476
const unsigned char *recipient_pub)
477
{
478
int ret = 0;
479
EVP_KDF_CTX *kdfctx = NULL;
480
unsigned char *sender_authpub = NULL;
481
unsigned char dhkm[MAX_ECX_KEYLEN * 2];
482
unsigned char kemctx[MAX_ECX_KEYLEN * 3];
483
size_t kemctxlen = 0, dhkmlen = 0;
484
const OSSL_HPKE_KEM_INFO *info = ctx->info;
485
int auth = ctx->sender_authkey != NULL;
486
size_t encodedkeylen = info->Npk;
487
488
if (!generate_ecxdhkm(privkey1, peerkey1, dhkm, sizeof(dhkm), encodedkeylen))
489
goto err;
490
dhkmlen = encodedkeylen;
491
492
/* Concat the optional second ECXDH (used for Auth) */
493
if (auth) {
494
if (!generate_ecxdhkm(privkey2, peerkey2,
495
dhkm + dhkmlen, sizeof(dhkm) - dhkmlen,
496
encodedkeylen))
497
goto err;
498
/* Get the public key of the auth sender in encoded form */
499
sender_authpub = ecx_pubkey(ctx->sender_authkey);
500
if (sender_authpub == NULL)
501
goto err;
502
dhkmlen += encodedkeylen;
503
}
504
kemctxlen = encodedkeylen + dhkmlen;
505
if (kemctxlen > sizeof(kemctx))
506
goto err;
507
508
/* kemctx is the concat of both sides encoded public key */
509
memcpy(kemctx, sender_pub, encodedkeylen);
510
memcpy(kemctx + encodedkeylen, recipient_pub, encodedkeylen);
511
if (auth)
512
memcpy(kemctx + 2 * encodedkeylen, sender_authpub, encodedkeylen);
513
kdfctx = ossl_kdf_ctx_create(ctx->kdfname, info->mdname,
514
ctx->libctx, ctx->propq);
515
if (kdfctx == NULL)
516
goto err;
517
if (!dhkem_extract_and_expand(kdfctx, secret, info->Nsecret,
518
info->kem_id, dhkm, dhkmlen,
519
kemctx, kemctxlen))
520
goto err;
521
ret = 1;
522
err:
523
OPENSSL_cleanse(dhkm, dhkmlen);
524
EVP_KDF_CTX_free(kdfctx);
525
return ret;
526
}
527
528
/*
529
* Do a DHKEM encapsulate operation.
530
*
531
* See Section 4.1 Encap() and AuthEncap()
532
*
533
* Params:
534
* ctx A context object holding the recipients public key and the
535
* optional senders auth private key.
536
* enc A buffer to return the senders ephemeral public key.
537
* Setting this to NULL allows the enclen and secretlen to return
538
* values, without calculating the secret.
539
* enclen Passes in the max size of the enc buffer and returns the
540
* encoded public key length.
541
* secret A buffer to return the calculated shared secret.
542
* secretlen Passes in the max size of the secret buffer and returns the
543
* secret length.
544
* Returns: 1 on success or 0 otherwise.
545
*/
546
static int dhkem_encap(PROV_ECX_CTX *ctx,
547
unsigned char *enc, size_t *enclen,
548
unsigned char *secret, size_t *secretlen)
549
{
550
int ret = 0;
551
ECX_KEY *sender_ephemkey = NULL;
552
unsigned char *sender_ephempub, *recipient_pub;
553
const OSSL_HPKE_KEM_INFO *info = ctx->info;
554
555
if (enc == NULL) {
556
if (enclen == NULL && secretlen == NULL)
557
return 0;
558
if (enclen != NULL)
559
*enclen = info->Nenc;
560
if (secretlen != NULL)
561
*secretlen = info->Nsecret;
562
return 1;
563
}
564
565
if (*secretlen < info->Nsecret) {
566
ERR_raise_data(ERR_LIB_PROV, PROV_R_BAD_LENGTH, "*secretlen too small");
567
return 0;
568
}
569
if (*enclen < info->Nenc) {
570
ERR_raise_data(ERR_LIB_PROV, PROV_R_BAD_LENGTH, "*enclen too small");
571
return 0;
572
}
573
574
/* Create an ephemeral key */
575
sender_ephemkey = derivekey(ctx, ctx->ikm, ctx->ikmlen);
576
577
sender_ephempub = ecx_pubkey(sender_ephemkey);
578
recipient_pub = ecx_pubkey(ctx->recipient_key);
579
if (sender_ephempub == NULL || recipient_pub == NULL)
580
goto err;
581
582
if (!derive_secret(ctx, secret,
583
sender_ephemkey, ctx->recipient_key,
584
ctx->sender_authkey, ctx->recipient_key,
585
sender_ephempub, recipient_pub))
586
goto err;
587
588
/* Return the public part of the ephemeral key */
589
memcpy(enc, sender_ephempub, info->Nenc);
590
*enclen = info->Nenc;
591
*secretlen = info->Nsecret;
592
ret = 1;
593
err:
594
ossl_ecx_key_free(sender_ephemkey);
595
return ret;
596
}
597
598
/*
599
* Do a DHKEM decapsulate operation.
600
* See Section 4.1 Decap() and Auth Decap()
601
*
602
* Params:
603
* ctx A context object holding the recipients private key and the
604
* optional senders auth public key.
605
* secret A buffer to return the calculated shared secret. Setting this to
606
* NULL can be used to return the secretlen.
607
* secretlen Passes in the max size of the secret buffer and returns the
608
* secret length.
609
* enc A buffer containing the senders ephemeral public key that was returned
610
* from dhkem_encap().
611
* enclen The length in bytes of enc.
612
* Returns: 1 If the shared secret is returned or 0 on error.
613
*/
614
static int dhkem_decap(PROV_ECX_CTX *ctx,
615
unsigned char *secret, size_t *secretlen,
616
const unsigned char *enc, size_t enclen)
617
{
618
int ret = 0;
619
ECX_KEY *recipient_privkey = ctx->recipient_key;
620
ECX_KEY *sender_ephempubkey = NULL;
621
const OSSL_HPKE_KEM_INFO *info = ctx->info;
622
unsigned char *recipient_pub;
623
624
if (secret == NULL) {
625
*secretlen = info->Nsecret;
626
return 1;
627
}
628
if (*secretlen < info->Nsecret) {
629
ERR_raise_data(ERR_LIB_PROV, PROV_R_BAD_LENGTH, "*secretlen too small");
630
return 0;
631
}
632
if (enclen != info->Nenc) {
633
ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_KEY, "Invalid enc public key");
634
return 0;
635
}
636
637
/* Get the public part of the ephemeral key created by encap */
638
sender_ephempubkey = ecxkey_pubfromdata(ctx, enc, enclen);
639
if (sender_ephempubkey == NULL)
640
goto err;
641
642
recipient_pub = ecx_pubkey(recipient_privkey);
643
if (recipient_pub == NULL)
644
goto err;
645
646
if (!derive_secret(ctx, secret,
647
ctx->recipient_key, sender_ephempubkey,
648
ctx->recipient_key, ctx->sender_authkey,
649
enc, recipient_pub))
650
goto err;
651
652
*secretlen = info->Nsecret;
653
ret = 1;
654
err:
655
ossl_ecx_key_free(sender_ephempubkey);
656
return ret;
657
}
658
659
static int ecxkem_encapsulate(void *vctx, unsigned char *out, size_t *outlen,
660
unsigned char *secret, size_t *secretlen)
661
{
662
PROV_ECX_CTX *ctx = (PROV_ECX_CTX *)vctx;
663
664
switch (ctx->mode) {
665
case KEM_MODE_DHKEM:
666
return dhkem_encap(ctx, out, outlen, secret, secretlen);
667
default:
668
ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_MODE);
669
return -2;
670
}
671
}
672
673
static int ecxkem_decapsulate(void *vctx, unsigned char *out, size_t *outlen,
674
const unsigned char *in, size_t inlen)
675
{
676
PROV_ECX_CTX *ctx = (PROV_ECX_CTX *)vctx;
677
678
switch (ctx->mode) {
679
case KEM_MODE_DHKEM:
680
return dhkem_decap(vctx, out, outlen, in, inlen);
681
default:
682
ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_MODE);
683
return -2;
684
}
685
}
686
687
const OSSL_DISPATCH ossl_ecx_asym_kem_functions[] = {
688
{ OSSL_FUNC_KEM_NEWCTX, (void (*)(void))ecxkem_newctx },
689
{ OSSL_FUNC_KEM_ENCAPSULATE_INIT,
690
(void (*)(void))ecxkem_encapsulate_init },
691
{ OSSL_FUNC_KEM_ENCAPSULATE, (void (*)(void))ecxkem_encapsulate },
692
{ OSSL_FUNC_KEM_DECAPSULATE_INIT,
693
(void (*)(void))ecxkem_decapsulate_init },
694
{ OSSL_FUNC_KEM_DECAPSULATE, (void (*)(void))ecxkem_decapsulate },
695
{ OSSL_FUNC_KEM_FREECTX, (void (*)(void))ecxkem_freectx },
696
{ OSSL_FUNC_KEM_SET_CTX_PARAMS,
697
(void (*)(void))ecxkem_set_ctx_params },
698
{ OSSL_FUNC_KEM_SETTABLE_CTX_PARAMS,
699
(void (*)(void))ecxkem_settable_ctx_params },
700
{ OSSL_FUNC_KEM_AUTH_ENCAPSULATE_INIT,
701
(void (*)(void))ecxkem_auth_encapsulate_init },
702
{ OSSL_FUNC_KEM_AUTH_DECAPSULATE_INIT,
703
(void (*)(void))ecxkem_auth_decapsulate_init },
704
OSSL_DISPATCH_END
705
};
706
707