Coverage Report

Created: 2026-03-09 06:55

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/openssl/crypto/hpke/hpke.c
Line
Count
Source
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
/* An OpenSSL-based HPKE implementation of RFC9180 */
11
12
#include <string.h>
13
#include <openssl/rand.h>
14
#include <openssl/kdf.h>
15
#include <openssl/core_names.h>
16
#include <openssl/hpke.h>
17
#include <openssl/sha.h>
18
#include <openssl/evp.h>
19
#include <openssl/err.h>
20
#include "internal/hpke_util.h"
21
#include "internal/nelem.h"
22
#include "internal/common.h"
23
24
/* default buffer size for keys and internal buffers we use */
25
0
#define OSSL_HPKE_MAXSIZE 512
26
27
/* Define HPKE labels from RFC9180 in hex for EBCDIC compatibility */
28
/* "HPKE" - "suite_id" label for section 5.1 */
29
static const char OSSL_HPKE_SEC51LABEL[] = "\x48\x50\x4b\x45";
30
/* "psk_id_hash" - in key_schedule_context */
31
static const char OSSL_HPKE_PSKIDHASH_LABEL[] = "\x70\x73\x6b\x5f\x69\x64\x5f\x68\x61\x73\x68";
32
/*  "info_hash" - in key_schedule_context */
33
static const char OSSL_HPKE_INFOHASH_LABEL[] = "\x69\x6e\x66\x6f\x5f\x68\x61\x73\x68";
34
/*  "base_nonce" - base nonce calc label */
35
static const char OSSL_HPKE_NONCE_LABEL[] = "\x62\x61\x73\x65\x5f\x6e\x6f\x6e\x63\x65";
36
/*  "exp" - internal exporter secret generation label */
37
static const char OSSL_HPKE_EXP_LABEL[] = "\x65\x78\x70";
38
/*  "sec" - external label for exporting secret */
39
static const char OSSL_HPKE_EXP_SEC_LABEL[] = "\x73\x65\x63";
40
/*  "key" - label for use when generating key from shared secret */
41
static const char OSSL_HPKE_KEY_LABEL[] = "\x6b\x65\x79";
42
/*  "secret" - for generating shared secret */
43
static const char OSSL_HPKE_SECRET_LABEL[] = "\x73\x65\x63\x72\x65\x74";
44
45
/**
46
 * @brief sender or receiver context
47
 */
48
struct ossl_hpke_ctx_st {
49
    OSSL_LIB_CTX *libctx; /* library context */
50
    char *propq; /* properties */
51
    int mode; /* HPKE mode */
52
    OSSL_HPKE_SUITE suite; /* suite */
53
    const OSSL_HPKE_KEM_INFO *kem_info;
54
    const OSSL_HPKE_KDF_INFO *kdf_info;
55
    const OSSL_HPKE_AEAD_INFO *aead_info;
56
    EVP_CIPHER *aead_ciph;
57
    int role; /* sender(0) or receiver(1) */
58
    uint64_t seq; /* aead sequence number */
59
    unsigned char *shared_secret; /* KEM output, zz */
60
    size_t shared_secretlen;
61
    unsigned char *key; /* final aead key */
62
    size_t keylen;
63
    unsigned char *nonce; /* aead base nonce */
64
    size_t noncelen;
65
    unsigned char *exportersec; /* exporter secret */
66
    size_t exporterseclen;
67
    char *pskid; /* PSK stuff */
68
    unsigned char *psk;
69
    size_t psklen;
70
    EVP_PKEY *authpriv; /* sender's authentication private key */
71
    unsigned char *authpub; /* auth public key */
72
    size_t authpublen;
73
    unsigned char *ikme; /* IKM for sender deterministic key gen */
74
    size_t ikmelen;
75
};
76
77
/**
78
 * @brief check if KEM uses NIST curve or not
79
 * @param kem_id is the externally supplied kem_id
80
 * @return 1 for NIST curves, 0 for other
81
 */
82
static int hpke_kem_id_nist_curve(uint16_t kem_id)
83
0
{
84
0
    const OSSL_HPKE_KEM_INFO *kem_info;
85
86
0
    kem_info = ossl_HPKE_KEM_INFO_find_id(kem_id);
87
0
    return kem_info != NULL && kem_info->groupname != NULL;
88
0
}
89
90
/**
91
 * @brief wrapper to import NIST curve public key as easily as x25519/x448
92
 * @param libctx is the context to use
93
 * @param propq is a properties string
94
 * @param gname is the curve groupname
95
 * @param buf is the binary buffer with the (uncompressed) public value
96
 * @param buflen is the length of the private key buffer
97
 * @return a working EVP_PKEY * or NULL
98
 *
99
 * Note that this could be a useful function to make public in
100
 * future, but would likely require a name change.
101
 */
102
static EVP_PKEY *evp_pkey_new_raw_nist_public_key(OSSL_LIB_CTX *libctx,
103
    const char *propq,
104
    const char *gname,
105
    const unsigned char *buf,
106
    size_t buflen)
107
0
{
108
0
    OSSL_PARAM params[2];
109
0
    EVP_PKEY *ret = NULL;
110
0
    EVP_PKEY_CTX *cctx = EVP_PKEY_CTX_new_from_name(libctx, "EC", propq);
111
112
0
    params[0] = OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME,
113
0
        (char *)gname, 0);
114
0
    params[1] = OSSL_PARAM_construct_end();
115
0
    if (cctx == NULL
116
0
        || EVP_PKEY_paramgen_init(cctx) <= 0
117
0
        || EVP_PKEY_CTX_set_params(cctx, params) <= 0
118
0
        || EVP_PKEY_paramgen(cctx, &ret) <= 0
119
0
        || EVP_PKEY_set1_encoded_public_key(ret, buf, buflen) != 1) {
120
0
        EVP_PKEY_CTX_free(cctx);
121
0
        EVP_PKEY_free(ret);
122
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
123
0
        return NULL;
124
0
    }
125
0
    EVP_PKEY_CTX_free(cctx);
126
0
    return ret;
127
0
}
128
129
/**
130
 * @brief do the AEAD decryption
131
 * @param hctx is the context to use
132
 * @param iv is the initialisation vector
133
 * @param aad is the additional authenticated data
134
 * @param aadlen is the length of the aad
135
 * @param ct is the ciphertext buffer
136
 * @param ctlen is the ciphertext length (including tag).
137
 * @param pt is the output buffer
138
 * @param ptlen input/output, better be big enough on input, exact on output
139
 * @return 1 on success, 0 otherwise
140
 */
141
static int hpke_aead_dec(OSSL_HPKE_CTX *hctx, const unsigned char *iv,
142
    const unsigned char *aad, size_t aadlen,
143
    const unsigned char *ct, size_t ctlen,
144
    unsigned char *pt, size_t *ptlen)
145
0
{
146
0
    int erv = 0;
147
0
    EVP_CIPHER_CTX *ctx = NULL;
148
0
    int len = 0;
149
0
    size_t taglen;
150
151
0
    taglen = hctx->aead_info->taglen;
152
0
    if (ctlen <= taglen || *ptlen < ctlen - taglen
153
0
        || aadlen > INT_MAX || ctlen > INT_MAX) {
154
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
155
0
        return 0;
156
0
    }
157
    /* Create and initialise the context */
158
0
    if ((ctx = EVP_CIPHER_CTX_new()) == NULL)
159
0
        return 0;
160
    /* Initialise the decryption operation. */
161
0
    if (EVP_DecryptInit_ex(ctx, hctx->aead_ciph, NULL, NULL, NULL) != 1) {
162
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
163
0
        goto err;
164
0
    }
165
0
    if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN,
166
0
            (int)hctx->noncelen, NULL)
167
0
        != 1) {
168
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
169
0
        goto err;
170
0
    }
171
    /* Initialise key and IV */
172
0
    if (EVP_DecryptInit_ex(ctx, NULL, NULL, hctx->key, iv) != 1) {
173
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
174
0
        goto err;
175
0
    }
176
    /* Provide AAD. */
177
0
    if (aadlen != 0 && aad != NULL) {
178
0
        if (EVP_DecryptUpdate(ctx, NULL, &len, aad, (int)aadlen) != 1) {
179
0
            ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
180
0
            goto err;
181
0
        }
182
0
    }
183
0
    if (EVP_DecryptUpdate(ctx, pt, &len, ct, (int)(ctlen - taglen)) != 1) {
184
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
185
0
        goto err;
186
0
    }
187
0
    *ptlen = len;
188
0
    if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG,
189
0
            (int)taglen, (void *)(ct + ctlen - taglen))) {
190
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
191
0
        goto err;
192
0
    }
193
    /* Finalise decryption.  */
194
0
    if (EVP_DecryptFinal_ex(ctx, pt + len, &len) <= 0) {
195
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
196
0
        goto err;
197
0
    }
198
0
    erv = 1;
199
200
0
err:
201
0
    if (erv != 1)
202
0
        OPENSSL_cleanse(pt, *ptlen);
203
0
    EVP_CIPHER_CTX_free(ctx);
204
0
    return erv;
205
0
}
206
207
/**
208
 * @brief do AEAD encryption as per the RFC
209
 * @param hctx is the context to use
210
 * @param iv is the initialisation vector
211
 * @param aad is the additional authenticated data
212
 * @param aadlen is the length of the aad
213
 * @param pt is the plaintext buffer
214
 * @param ptlen is the length of pt
215
 * @param ct is the output buffer
216
 * @param ctlen input/output, needs space for tag on input, exact on output
217
 * @return 1 for success, 0 otherwise
218
 */
219
static int hpke_aead_enc(OSSL_HPKE_CTX *hctx, const unsigned char *iv,
220
    const unsigned char *aad, size_t aadlen,
221
    const unsigned char *pt, size_t ptlen,
222
    unsigned char *ct, size_t *ctlen)
223
0
{
224
0
    int erv = 0;
225
0
    EVP_CIPHER_CTX *ctx = NULL;
226
0
    int len;
227
0
    size_t taglen = 0;
228
0
    unsigned char tag[EVP_MAX_AEAD_TAG_LENGTH];
229
230
0
    taglen = hctx->aead_info->taglen;
231
0
    if (*ctlen <= taglen || ptlen > *ctlen - taglen
232
0
        || aadlen > INT_MAX || ptlen > INT_MAX) {
233
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
234
0
        return 0;
235
0
    }
236
0
    if (!ossl_assert(taglen <= sizeof(tag))) {
237
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
238
0
        return 0;
239
0
    }
240
    /* Create and initialise the context */
241
0
    if ((ctx = EVP_CIPHER_CTX_new()) == NULL)
242
0
        return 0;
243
    /* Initialise the encryption operation. */
244
0
    if (EVP_EncryptInit_ex(ctx, hctx->aead_ciph, NULL, NULL, NULL) != 1) {
245
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
246
0
        goto err;
247
0
    }
248
0
    if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN,
249
0
            (int)hctx->noncelen, NULL)
250
0
        != 1) {
251
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
252
0
        goto err;
253
0
    }
254
    /* Initialise key and IV */
255
0
    if (EVP_EncryptInit_ex(ctx, NULL, NULL, hctx->key, iv) != 1) {
256
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
257
0
        goto err;
258
0
    }
259
    /* Provide any AAD data. */
260
0
    if (aadlen != 0 && aad != NULL) {
261
0
        if (EVP_EncryptUpdate(ctx, NULL, &len, aad, (int)aadlen) != 1) {
262
0
            ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
263
0
            goto err;
264
0
        }
265
0
    }
266
0
    if (EVP_EncryptUpdate(ctx, ct, &len, pt, (int)ptlen) != 1) {
267
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
268
0
        goto err;
269
0
    }
270
0
    *ctlen = len;
271
    /* Finalise the encryption. */
272
0
    if (EVP_EncryptFinal_ex(ctx, ct + len, &len) != 1) {
273
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
274
0
        goto err;
275
0
    }
276
0
    *ctlen += len;
277
    /* Get tag. Not a duplicate so needs to be added to the ciphertext */
278
0
    if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, (int)taglen, tag) != 1) {
279
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
280
0
        goto err;
281
0
    }
282
0
    memcpy(ct + *ctlen, tag, taglen);
283
0
    *ctlen += taglen;
284
0
    erv = 1;
285
286
0
err:
287
0
    if (erv != 1)
288
0
        OPENSSL_cleanse(ct, *ctlen);
289
0
    EVP_CIPHER_CTX_free(ctx);
290
0
    return erv;
291
0
}
292
293
/**
294
 * @brief check mode is in-range and supported
295
 * @param mode is the caller's chosen mode
296
 * @return 1 for good mode, 0 otherwise
297
 */
298
static int hpke_mode_check(unsigned int mode)
299
0
{
300
0
    switch (mode) {
301
0
    case OSSL_HPKE_MODE_BASE:
302
0
    case OSSL_HPKE_MODE_PSK:
303
0
    case OSSL_HPKE_MODE_AUTH:
304
0
    case OSSL_HPKE_MODE_PSKAUTH:
305
0
        break;
306
0
    default:
307
0
        return 0;
308
0
    }
309
0
    return 1;
310
0
}
311
312
/**
313
 * @brief check if a suite is supported locally
314
 * @param suite is the suite to check
315
 * @return 1 for good, 0 otherwise
316
 */
317
static int hpke_suite_check(OSSL_HPKE_SUITE suite,
318
    const OSSL_HPKE_KEM_INFO **kem_info,
319
    const OSSL_HPKE_KDF_INFO **kdf_info,
320
    const OSSL_HPKE_AEAD_INFO **aead_info)
321
0
{
322
0
    const OSSL_HPKE_KEM_INFO *kem_info_;
323
0
    const OSSL_HPKE_KDF_INFO *kdf_info_;
324
0
    const OSSL_HPKE_AEAD_INFO *aead_info_;
325
326
    /* check KEM, KDF and AEAD are supported here */
327
0
    if ((kem_info_ = ossl_HPKE_KEM_INFO_find_id(suite.kem_id)) == NULL)
328
0
        return 0;
329
0
    if ((kdf_info_ = ossl_HPKE_KDF_INFO_find_id(suite.kdf_id)) == NULL)
330
0
        return 0;
331
0
    if ((aead_info_ = ossl_HPKE_AEAD_INFO_find_id(suite.aead_id)) == NULL)
332
0
        return 0;
333
334
0
    if (kem_info != NULL)
335
0
        *kem_info = kem_info_;
336
0
    if (kdf_info != NULL)
337
0
        *kdf_info = kdf_info_;
338
0
    if (aead_info != NULL)
339
0
        *aead_info = aead_info_;
340
341
0
    return 1;
342
0
}
343
344
/*
345
 * @brief randomly pick a suite
346
 * @param libctx is the context to use
347
 * @param propq is a properties string
348
 * @param suite is the result
349
 * @return 1 for success, 0 otherwise
350
 */
351
static int hpke_random_suite(OSSL_LIB_CTX *libctx,
352
    const char *propq,
353
    OSSL_HPKE_SUITE *suite)
354
0
{
355
0
    const OSSL_HPKE_KEM_INFO *kem_info = NULL;
356
0
    const OSSL_HPKE_KDF_INFO *kdf_info = NULL;
357
0
    const OSSL_HPKE_AEAD_INFO *aead_info = NULL;
358
359
    /* random kem, kdf and aead */
360
0
    kem_info = ossl_HPKE_KEM_INFO_find_random(libctx);
361
0
    if (kem_info == NULL)
362
0
        return 0;
363
0
    suite->kem_id = kem_info->kem_id;
364
0
    kdf_info = ossl_HPKE_KDF_INFO_find_random(libctx);
365
0
    if (kdf_info == NULL)
366
0
        return 0;
367
0
    suite->kdf_id = kdf_info->kdf_id;
368
0
    aead_info = ossl_HPKE_AEAD_INFO_find_random(libctx);
369
0
    if (aead_info == NULL)
370
0
        return 0;
371
0
    suite->aead_id = aead_info->aead_id;
372
0
    return 1;
373
0
}
374
375
/*
376
 * @brief tell the caller how big the ciphertext will be
377
 *
378
 * AEAD algorithms add a tag for data authentication.
379
 * Those are almost always, but not always, 16 octets
380
 * long, and who knows what will be true in the future.
381
 * So this function allows a caller to find out how
382
 * much data expansion they will see with a given suite.
383
 *
384
 * "enc" is the name used in RFC9180 for the encapsulated
385
 * public value of the sender, who calls OSSL_HPKE_seal(),
386
 * that is sent to the recipient, who calls OSSL_HPKE_open().
387
 *
388
 * @param suite is the suite to be used
389
 * @param enclen points to what will be enc length
390
 * @param clearlen is the length of plaintext
391
 * @param cipherlen points to what will be ciphertext length (including tag)
392
 * @return 1 for success, 0 otherwise
393
 */
394
static int hpke_expansion(OSSL_HPKE_SUITE suite,
395
    size_t *enclen,
396
    size_t clearlen,
397
    size_t *cipherlen)
398
0
{
399
0
    const OSSL_HPKE_AEAD_INFO *aead_info = NULL;
400
0
    const OSSL_HPKE_KEM_INFO *kem_info = NULL;
401
402
0
    if (cipherlen == NULL || enclen == NULL) {
403
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
404
0
        return 0;
405
0
    }
406
0
    if (hpke_suite_check(suite, &kem_info, NULL, &aead_info) != 1) {
407
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
408
0
        return 0;
409
0
    }
410
0
    *cipherlen = clearlen + aead_info->taglen;
411
0
    *enclen = kem_info->Nenc;
412
0
    return 1;
413
0
}
414
415
/*
416
 * @brief expand and XOR the 64-bit unsigned seq with (nonce) buffer
417
 * @param ctx is the HPKE context
418
 * @param buf is the buffer for the XOR'd seq and nonce
419
 * @param blen is the size of buf
420
 * @return 0 for error, otherwise blen
421
 */
422
static size_t hpke_seqnonce2buf(OSSL_HPKE_CTX *ctx,
423
    unsigned char *buf, size_t blen)
424
0
{
425
0
    size_t i;
426
0
    uint64_t seq_copy;
427
428
0
    if (ctx == NULL || blen < sizeof(seq_copy) || blen != ctx->noncelen)
429
0
        return 0;
430
0
    seq_copy = ctx->seq;
431
0
    memset(buf, 0, blen);
432
0
    for (i = 0; i < sizeof(seq_copy); i++) {
433
0
        buf[blen - i - 1] = seq_copy & 0xff;
434
0
        seq_copy >>= 8;
435
0
    }
436
0
    for (i = 0; i < blen; i++)
437
0
        buf[i] ^= ctx->nonce[i];
438
0
    return blen;
439
0
}
440
441
/*
442
 * @brief call the underlying KEM to encap
443
 * @param ctx is the OSSL_HPKE_CTX
444
 * @param enc is a buffer for the sender's ephemeral public value
445
 * @param enclen is the size of enc on input, number of octets used on output
446
 * @param pub is the recipient's public value
447
 * @param publen is the length of pub
448
 * @return 1 for success, 0 for error
449
 */
450
static int hpke_encap(OSSL_HPKE_CTX *ctx, unsigned char *enc, size_t *enclen,
451
    const unsigned char *pub, size_t publen)
452
0
{
453
0
    int erv = 0;
454
0
    OSSL_PARAM params[3], *p = params;
455
0
    size_t lsslen = 0, lenclen = 0;
456
0
    EVP_PKEY_CTX *pctx = NULL;
457
0
    EVP_PKEY *pkR = NULL;
458
0
    const OSSL_HPKE_KEM_INFO *kem_info = NULL;
459
460
0
    if (ctx == NULL || enc == NULL || enclen == NULL || *enclen == 0
461
0
        || pub == NULL || publen == 0) {
462
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
463
0
        return 0;
464
0
    }
465
0
    if (ctx->shared_secret != NULL) {
466
        /* only run the KEM once per OSSL_HPKE_CTX */
467
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
468
0
        return 0;
469
0
    }
470
0
    kem_info = ossl_HPKE_KEM_INFO_find_id(ctx->suite.kem_id);
471
0
    if (kem_info == NULL) {
472
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
473
0
        return 0;
474
0
    }
475
0
    if (hpke_kem_id_nist_curve(ctx->suite.kem_id) == 1) {
476
0
        pkR = evp_pkey_new_raw_nist_public_key(ctx->libctx, ctx->propq,
477
0
            kem_info->groupname,
478
0
            pub, publen);
479
0
    } else {
480
0
        pkR = EVP_PKEY_new_raw_public_key_ex(ctx->libctx,
481
0
            kem_info->keytype,
482
0
            ctx->propq, pub, publen);
483
0
    }
484
0
    if (pkR == NULL) {
485
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
486
0
        goto err;
487
0
    }
488
0
    pctx = EVP_PKEY_CTX_new_from_pkey(ctx->libctx, pkR, ctx->propq);
489
0
    if (pctx == NULL) {
490
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
491
0
        goto err;
492
0
    }
493
0
    *p++ = OSSL_PARAM_construct_utf8_string(OSSL_KEM_PARAM_OPERATION,
494
0
        OSSL_KEM_PARAM_OPERATION_DHKEM,
495
0
        0);
496
0
    if (ctx->ikme != NULL) {
497
0
        *p++ = OSSL_PARAM_construct_octet_string(OSSL_KEM_PARAM_IKME,
498
0
            ctx->ikme, ctx->ikmelen);
499
0
    }
500
0
    *p = OSSL_PARAM_construct_end();
501
0
    if (ctx->mode == OSSL_HPKE_MODE_AUTH
502
0
        || ctx->mode == OSSL_HPKE_MODE_PSKAUTH) {
503
0
        if (EVP_PKEY_auth_encapsulate_init(pctx, ctx->authpriv,
504
0
                params)
505
0
            != 1) {
506
0
            ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
507
0
            goto err;
508
0
        }
509
0
    } else {
510
0
        if (EVP_PKEY_encapsulate_init(pctx, params) != 1) {
511
0
            ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
512
0
            goto err;
513
0
        }
514
0
    }
515
0
    lenclen = *enclen;
516
0
    if (EVP_PKEY_encapsulate(pctx, NULL, &lenclen, NULL, &lsslen) != 1) {
517
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
518
0
        goto err;
519
0
    }
520
0
    if (lenclen > *enclen) {
521
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
522
0
        goto err;
523
0
    }
524
0
    ctx->shared_secret = OPENSSL_malloc(lsslen);
525
0
    if (ctx->shared_secret == NULL)
526
0
        goto err;
527
0
    ctx->shared_secretlen = lsslen;
528
0
    if (EVP_PKEY_encapsulate(pctx, enc, enclen, ctx->shared_secret,
529
0
            &ctx->shared_secretlen)
530
0
        != 1) {
531
0
        ctx->shared_secretlen = 0;
532
0
        OPENSSL_free(ctx->shared_secret);
533
0
        ctx->shared_secret = NULL;
534
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
535
0
        goto err;
536
0
    }
537
0
    erv = 1;
538
539
0
err:
540
0
    EVP_PKEY_CTX_free(pctx);
541
0
    EVP_PKEY_free(pkR);
542
0
    return erv;
543
0
}
544
545
/*
546
 * @brief call the underlying KEM to decap
547
 * @param ctx is the OSSL_HPKE_CTX
548
 * @param enc is a buffer for the sender's ephemeral public value
549
 * @param enclen is the length of enc
550
 * @param priv is the recipient's private value
551
 * @return 1 for success, 0 for error
552
 */
553
static int hpke_decap(OSSL_HPKE_CTX *ctx,
554
    const unsigned char *enc, size_t enclen,
555
    EVP_PKEY *priv)
556
0
{
557
0
    int erv = 0;
558
0
    EVP_PKEY_CTX *pctx = NULL;
559
0
    EVP_PKEY *spub = NULL;
560
0
    OSSL_PARAM params[2], *p = params;
561
0
    size_t lsslen = 0;
562
563
0
    if (ctx == NULL || enc == NULL || enclen == 0 || priv == NULL) {
564
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
565
0
        return 0;
566
0
    }
567
0
    if (ctx->shared_secret != NULL) {
568
        /* only run the KEM once per OSSL_HPKE_CTX */
569
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
570
0
        return 0;
571
0
    }
572
0
    pctx = EVP_PKEY_CTX_new_from_pkey(ctx->libctx, priv, ctx->propq);
573
0
    if (pctx == NULL) {
574
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
575
0
        goto err;
576
0
    }
577
0
    *p++ = OSSL_PARAM_construct_utf8_string(OSSL_KEM_PARAM_OPERATION,
578
0
        OSSL_KEM_PARAM_OPERATION_DHKEM,
579
0
        0);
580
0
    *p = OSSL_PARAM_construct_end();
581
0
    if (ctx->mode == OSSL_HPKE_MODE_AUTH
582
0
        || ctx->mode == OSSL_HPKE_MODE_PSKAUTH) {
583
0
        const OSSL_HPKE_KEM_INFO *kem_info = NULL;
584
585
0
        kem_info = ossl_HPKE_KEM_INFO_find_id(ctx->suite.kem_id);
586
0
        if (kem_info == NULL) {
587
0
            ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
588
0
            goto err;
589
0
        }
590
0
        if (hpke_kem_id_nist_curve(ctx->suite.kem_id) == 1) {
591
0
            spub = evp_pkey_new_raw_nist_public_key(ctx->libctx, ctx->propq,
592
0
                kem_info->groupname,
593
0
                ctx->authpub,
594
0
                ctx->authpublen);
595
0
        } else {
596
0
            spub = EVP_PKEY_new_raw_public_key_ex(ctx->libctx,
597
0
                kem_info->keytype,
598
0
                ctx->propq,
599
0
                ctx->authpub,
600
0
                ctx->authpublen);
601
0
        }
602
0
        if (spub == NULL) {
603
0
            ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
604
0
            goto err;
605
0
        }
606
0
        if (EVP_PKEY_auth_decapsulate_init(pctx, spub, params) != 1) {
607
0
            ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
608
0
            goto err;
609
0
        }
610
0
    } else {
611
0
        if (EVP_PKEY_decapsulate_init(pctx, params) != 1) {
612
0
            ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
613
0
            goto err;
614
0
        }
615
0
    }
616
0
    if (EVP_PKEY_decapsulate(pctx, NULL, &lsslen, enc, enclen) != 1) {
617
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
618
0
        goto err;
619
0
    }
620
0
    ctx->shared_secret = OPENSSL_malloc(lsslen);
621
0
    if (ctx->shared_secret == NULL)
622
0
        goto err;
623
0
    if (EVP_PKEY_decapsulate(pctx, ctx->shared_secret, &lsslen,
624
0
            enc, enclen)
625
0
        != 1) {
626
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
627
0
        goto err;
628
0
    }
629
0
    ctx->shared_secretlen = lsslen;
630
0
    erv = 1;
631
632
0
err:
633
0
    EVP_PKEY_CTX_free(pctx);
634
0
    EVP_PKEY_free(spub);
635
0
    if (erv == 0) {
636
0
        OPENSSL_free(ctx->shared_secret);
637
0
        ctx->shared_secret = NULL;
638
0
        ctx->shared_secretlen = 0;
639
0
    }
640
0
    return erv;
641
0
}
642
643
/*
644
 * @brief do "middle" of HPKE, between KEM and AEAD
645
 * @param ctx is the OSSL_HPKE_CTX
646
 * @param info is a buffer for the added binding information
647
 * @param infolen is the length of info
648
 * @return 0 for error, 1 for success
649
 *
650
 * This does all the HPKE extracts and expands as defined in RFC9180
651
 * section 5.1, (badly termed there as a "key schedule") and sets the
652
 * ctx fields for the shared_secret, nonce, key and exporter_secret
653
 */
654
static int hpke_do_middle(OSSL_HPKE_CTX *ctx,
655
    const unsigned char *info, size_t infolen)
656
0
{
657
0
    int erv = 0;
658
0
    size_t ks_contextlen = OSSL_HPKE_MAXSIZE;
659
0
    unsigned char ks_context[OSSL_HPKE_MAXSIZE];
660
0
    size_t halflen = 0;
661
0
    size_t pskidlen = 0;
662
0
    const OSSL_HPKE_AEAD_INFO *aead_info = NULL;
663
0
    const OSSL_HPKE_KDF_INFO *kdf_info = NULL;
664
0
    size_t secretlen = OSSL_HPKE_MAXSIZE;
665
0
    unsigned char secret[OSSL_HPKE_MAXSIZE];
666
0
    EVP_KDF_CTX *kctx = NULL;
667
0
    unsigned char suitebuf[6];
668
0
    const char *mdname = NULL;
669
670
    /* only let this be done once */
671
0
    if (ctx->exportersec != NULL) {
672
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
673
0
        return 0;
674
0
    }
675
0
    if (ossl_HPKE_KEM_INFO_find_id(ctx->suite.kem_id) == NULL) {
676
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
677
0
        return 0;
678
0
    }
679
0
    aead_info = ossl_HPKE_AEAD_INFO_find_id(ctx->suite.aead_id);
680
0
    if (aead_info == NULL) {
681
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
682
0
        return 0;
683
0
    }
684
0
    kdf_info = ossl_HPKE_KDF_INFO_find_id(ctx->suite.kdf_id);
685
0
    if (kdf_info == NULL) {
686
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
687
0
        return 0;
688
0
    }
689
0
    mdname = kdf_info->mdname;
690
    /* create key schedule context */
691
0
    memset(ks_context, 0, sizeof(ks_context));
692
0
    ks_context[0] = (unsigned char)(ctx->mode % 256);
693
0
    ks_contextlen--; /* remaining space */
694
0
    halflen = kdf_info->Nh;
695
0
    if ((2 * halflen) > ks_contextlen) {
696
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
697
0
        return 0;
698
0
    }
699
    /* check a psk was set if in that mode */
700
0
    if (ctx->mode == OSSL_HPKE_MODE_PSK
701
0
        || ctx->mode == OSSL_HPKE_MODE_PSKAUTH) {
702
0
        if (ctx->psk == NULL || ctx->psklen == 0 || ctx->pskid == NULL) {
703
0
            ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
704
0
            return 0;
705
0
        }
706
0
    }
707
0
    kctx = ossl_kdf_ctx_create("HKDF", mdname, ctx->libctx, ctx->propq);
708
0
    if (kctx == NULL) {
709
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
710
0
        return 0;
711
0
    }
712
0
    pskidlen = (ctx->psk == NULL ? 0 : strlen(ctx->pskid));
713
    /* full suite details as per RFC9180 sec 5.1 */
714
0
    suitebuf[0] = ctx->suite.kem_id / 256;
715
0
    suitebuf[1] = ctx->suite.kem_id % 256;
716
0
    suitebuf[2] = ctx->suite.kdf_id / 256;
717
0
    suitebuf[3] = ctx->suite.kdf_id % 256;
718
0
    suitebuf[4] = ctx->suite.aead_id / 256;
719
0
    suitebuf[5] = ctx->suite.aead_id % 256;
720
    /* Extract and Expand variously... */
721
0
    if (ossl_hpke_labeled_extract(kctx, ks_context + 1, halflen,
722
0
            NULL, 0, OSSL_HPKE_SEC51LABEL,
723
0
            suitebuf, sizeof(suitebuf),
724
0
            OSSL_HPKE_PSKIDHASH_LABEL,
725
0
            (unsigned char *)ctx->pskid, pskidlen)
726
0
        != 1) {
727
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
728
0
        goto err;
729
0
    }
730
0
    if (ossl_hpke_labeled_extract(kctx, ks_context + 1 + halflen, halflen,
731
0
            NULL, 0, OSSL_HPKE_SEC51LABEL,
732
0
            suitebuf, sizeof(suitebuf),
733
0
            OSSL_HPKE_INFOHASH_LABEL,
734
0
            (unsigned char *)info, infolen)
735
0
        != 1) {
736
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
737
0
        goto err;
738
0
    }
739
0
    ks_contextlen = 1 + 2 * halflen;
740
0
    secretlen = kdf_info->Nh;
741
0
    if (secretlen > OSSL_HPKE_MAXSIZE) {
742
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
743
0
        goto err;
744
0
    }
745
0
    if (ossl_hpke_labeled_extract(kctx, secret, secretlen,
746
0
            ctx->shared_secret, ctx->shared_secretlen,
747
0
            OSSL_HPKE_SEC51LABEL,
748
0
            suitebuf, sizeof(suitebuf),
749
0
            OSSL_HPKE_SECRET_LABEL,
750
0
            ctx->psk, ctx->psklen)
751
0
        != 1) {
752
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
753
0
        goto err;
754
0
    }
755
0
    if (ctx->suite.aead_id != OSSL_HPKE_AEAD_ID_EXPORTONLY) {
756
        /* we only need nonce/key for non export AEADs */
757
0
        ctx->noncelen = aead_info->Nn;
758
0
        ctx->nonce = OPENSSL_malloc(ctx->noncelen);
759
0
        if (ctx->nonce == NULL)
760
0
            goto err;
761
0
        if (ossl_hpke_labeled_expand(kctx, ctx->nonce, ctx->noncelen,
762
0
                secret, secretlen, OSSL_HPKE_SEC51LABEL,
763
0
                suitebuf, sizeof(suitebuf),
764
0
                OSSL_HPKE_NONCE_LABEL,
765
0
                ks_context, ks_contextlen)
766
0
            != 1) {
767
0
            ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
768
0
            goto err;
769
0
        }
770
0
        ctx->keylen = aead_info->Nk;
771
0
        ctx->key = OPENSSL_malloc(ctx->keylen);
772
0
        if (ctx->key == NULL)
773
0
            goto err;
774
0
        if (ossl_hpke_labeled_expand(kctx, ctx->key, ctx->keylen,
775
0
                secret, secretlen, OSSL_HPKE_SEC51LABEL,
776
0
                suitebuf, sizeof(suitebuf),
777
0
                OSSL_HPKE_KEY_LABEL,
778
0
                ks_context, ks_contextlen)
779
0
            != 1) {
780
0
            ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
781
0
            goto err;
782
0
        }
783
0
    }
784
0
    ctx->exporterseclen = kdf_info->Nh;
785
0
    ctx->exportersec = OPENSSL_malloc(ctx->exporterseclen);
786
0
    if (ctx->exportersec == NULL)
787
0
        goto err;
788
0
    if (ossl_hpke_labeled_expand(kctx, ctx->exportersec, ctx->exporterseclen,
789
0
            secret, secretlen, OSSL_HPKE_SEC51LABEL,
790
0
            suitebuf, sizeof(suitebuf),
791
0
            OSSL_HPKE_EXP_LABEL,
792
0
            ks_context, ks_contextlen)
793
0
        != 1) {
794
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
795
0
        goto err;
796
0
    }
797
0
    erv = 1;
798
799
0
err:
800
0
    OPENSSL_cleanse(ks_context, OSSL_HPKE_MAXSIZE);
801
0
    OPENSSL_cleanse(secret, OSSL_HPKE_MAXSIZE);
802
0
    EVP_KDF_CTX_free(kctx);
803
0
    return erv;
804
0
}
805
806
/*
807
 * externally visible functions from below here, API documentation is
808
 * in doc/man3/OSSL_HPKE_CTX_new.pod to avoid duplication
809
 */
810
811
OSSL_HPKE_CTX *OSSL_HPKE_CTX_new(int mode, OSSL_HPKE_SUITE suite, int role,
812
    OSSL_LIB_CTX *libctx, const char *propq)
813
0
{
814
0
    OSSL_HPKE_CTX *ctx = NULL;
815
0
    const OSSL_HPKE_KEM_INFO *kem_info;
816
0
    const OSSL_HPKE_KDF_INFO *kdf_info;
817
0
    const OSSL_HPKE_AEAD_INFO *aead_info;
818
819
0
    if (hpke_mode_check(mode) != 1) {
820
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
821
0
        return NULL;
822
0
    }
823
0
    if (hpke_suite_check(suite, &kem_info, &kdf_info, &aead_info) != 1) {
824
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
825
0
        return NULL;
826
0
    }
827
0
    if (role != OSSL_HPKE_ROLE_SENDER && role != OSSL_HPKE_ROLE_RECEIVER) {
828
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
829
0
        return 0;
830
0
    }
831
0
    ctx = OPENSSL_zalloc(sizeof(*ctx));
832
0
    if (ctx == NULL)
833
0
        return NULL;
834
0
    ctx->libctx = libctx;
835
0
    if (propq != NULL) {
836
0
        ctx->propq = OPENSSL_strdup(propq);
837
0
        if (ctx->propq == NULL)
838
0
            goto err;
839
0
    }
840
0
    if (suite.aead_id != OSSL_HPKE_AEAD_ID_EXPORTONLY) {
841
0
        ctx->aead_ciph = EVP_CIPHER_fetch(libctx, aead_info->name, propq);
842
0
        if (ctx->aead_ciph == NULL) {
843
0
            ERR_raise(ERR_LIB_CRYPTO, ERR_R_FETCH_FAILED);
844
0
            goto err;
845
0
        }
846
0
    }
847
0
    ctx->role = role;
848
0
    ctx->mode = mode;
849
0
    ctx->suite = suite;
850
0
    ctx->kem_info = kem_info;
851
0
    ctx->kdf_info = kdf_info;
852
0
    ctx->aead_info = aead_info;
853
0
    return ctx;
854
855
0
err:
856
0
    EVP_CIPHER_free(ctx->aead_ciph);
857
0
    OPENSSL_free(ctx->propq);
858
0
    OPENSSL_free(ctx);
859
0
    return NULL;
860
0
}
861
862
void OSSL_HPKE_CTX_free(OSSL_HPKE_CTX *ctx)
863
0
{
864
0
    if (ctx == NULL)
865
0
        return;
866
0
    EVP_CIPHER_free(ctx->aead_ciph);
867
0
    OPENSSL_free(ctx->propq);
868
0
    OPENSSL_clear_free(ctx->exportersec, ctx->exporterseclen);
869
0
    OPENSSL_free(ctx->pskid);
870
0
    OPENSSL_clear_free(ctx->psk, ctx->psklen);
871
0
    OPENSSL_clear_free(ctx->key, ctx->keylen);
872
0
    OPENSSL_clear_free(ctx->nonce, ctx->noncelen);
873
0
    OPENSSL_clear_free(ctx->shared_secret, ctx->shared_secretlen);
874
0
    OPENSSL_clear_free(ctx->ikme, ctx->ikmelen);
875
0
    EVP_PKEY_free(ctx->authpriv);
876
0
    OPENSSL_free(ctx->authpub);
877
878
0
    OPENSSL_free(ctx);
879
0
    return;
880
0
}
881
882
int OSSL_HPKE_CTX_set1_psk(OSSL_HPKE_CTX *ctx,
883
    const char *pskid,
884
    const unsigned char *psk, size_t psklen)
885
0
{
886
0
    if (ctx == NULL || pskid == NULL || psk == NULL || psklen == 0) {
887
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
888
0
        return 0;
889
0
    }
890
0
    if (psklen > OSSL_HPKE_MAX_PARMLEN) {
891
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
892
0
        return 0;
893
0
    }
894
0
    if (psklen < OSSL_HPKE_MIN_PSKLEN) {
895
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
896
0
        return 0;
897
0
    }
898
0
    if (strlen(pskid) > OSSL_HPKE_MAX_PARMLEN) {
899
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
900
0
        return 0;
901
0
    }
902
0
    if (strlen(pskid) == 0) {
903
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
904
0
        return 0;
905
0
    }
906
0
    if (ctx->mode != OSSL_HPKE_MODE_PSK
907
0
        && ctx->mode != OSSL_HPKE_MODE_PSKAUTH) {
908
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
909
0
        return 0;
910
0
    }
911
    /* free previous values if any */
912
0
    OPENSSL_clear_free(ctx->psk, ctx->psklen);
913
0
    ctx->psk = OPENSSL_memdup(psk, psklen);
914
0
    if (ctx->psk == NULL)
915
0
        return 0;
916
0
    ctx->psklen = psklen;
917
0
    OPENSSL_free(ctx->pskid);
918
0
    ctx->pskid = OPENSSL_strdup(pskid);
919
0
    if (ctx->pskid == NULL) {
920
0
        OPENSSL_clear_free(ctx->psk, ctx->psklen);
921
0
        ctx->psk = NULL;
922
0
        ctx->psklen = 0;
923
0
        return 0;
924
0
    }
925
0
    return 1;
926
0
}
927
928
int OSSL_HPKE_CTX_set1_ikme(OSSL_HPKE_CTX *ctx,
929
    const unsigned char *ikme, size_t ikmelen)
930
0
{
931
0
    if (ctx == NULL || ikme == NULL) {
932
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_NULL_PARAMETER);
933
0
        return 0;
934
0
    }
935
0
    if (ikmelen == 0 || ikmelen > OSSL_HPKE_MAX_PARMLEN) {
936
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
937
0
        return 0;
938
0
    }
939
0
    if (ctx->role != OSSL_HPKE_ROLE_SENDER) {
940
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
941
0
        return 0;
942
0
    }
943
0
    OPENSSL_clear_free(ctx->ikme, ctx->ikmelen);
944
0
    ctx->ikme = OPENSSL_memdup(ikme, ikmelen);
945
0
    if (ctx->ikme == NULL)
946
0
        return 0;
947
0
    ctx->ikmelen = ikmelen;
948
0
    return 1;
949
0
}
950
951
int OSSL_HPKE_CTX_set1_authpriv(OSSL_HPKE_CTX *ctx, EVP_PKEY *priv)
952
0
{
953
0
    if (ctx == NULL || priv == NULL) {
954
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_NULL_PARAMETER);
955
0
        return 0;
956
0
    }
957
0
    if (ctx->mode != OSSL_HPKE_MODE_AUTH
958
0
        && ctx->mode != OSSL_HPKE_MODE_PSKAUTH) {
959
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
960
0
        return 0;
961
0
    }
962
0
    if (ctx->role != OSSL_HPKE_ROLE_SENDER) {
963
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
964
0
        return 0;
965
0
    }
966
0
    EVP_PKEY_free(ctx->authpriv);
967
0
    ctx->authpriv = EVP_PKEY_dup(priv);
968
0
    if (ctx->authpriv == NULL)
969
0
        return 0;
970
0
    return 1;
971
0
}
972
973
int OSSL_HPKE_CTX_set1_authpub(OSSL_HPKE_CTX *ctx,
974
    const unsigned char *pub, size_t publen)
975
0
{
976
0
    int erv = 0;
977
0
    EVP_PKEY *pubp = NULL;
978
0
    unsigned char *lpub = NULL;
979
0
    size_t lpublen = 0;
980
0
    const OSSL_HPKE_KEM_INFO *kem_info = NULL;
981
982
0
    if (ctx == NULL || pub == NULL || publen == 0) {
983
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_NULL_PARAMETER);
984
0
        return 0;
985
0
    }
986
0
    if (ctx->mode != OSSL_HPKE_MODE_AUTH
987
0
        && ctx->mode != OSSL_HPKE_MODE_PSKAUTH) {
988
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
989
0
        return 0;
990
0
    }
991
0
    if (ctx->role != OSSL_HPKE_ROLE_RECEIVER) {
992
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
993
0
        return 0;
994
0
    }
995
    /* check the value seems like a good public key for this kem */
996
0
    kem_info = ossl_HPKE_KEM_INFO_find_id(ctx->suite.kem_id);
997
0
    if (kem_info == NULL)
998
0
        return 0;
999
0
    if (hpke_kem_id_nist_curve(ctx->suite.kem_id) == 1) {
1000
0
        pubp = evp_pkey_new_raw_nist_public_key(ctx->libctx, ctx->propq,
1001
0
            kem_info->groupname,
1002
0
            pub, publen);
1003
0
    } else {
1004
0
        pubp = EVP_PKEY_new_raw_public_key_ex(ctx->libctx,
1005
0
            kem_info->keytype,
1006
0
            ctx->propq,
1007
0
            pub, publen);
1008
0
    }
1009
0
    if (pubp == NULL) {
1010
        /* can happen based on external input - buffer value may be garbage */
1011
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
1012
0
        goto err;
1013
0
    }
1014
    /*
1015
     * extract out the public key in encoded form so we
1016
     * should be fine even if given compressed form
1017
     */
1018
0
    lpub = OPENSSL_malloc(OSSL_HPKE_MAXSIZE);
1019
0
    if (lpub == NULL)
1020
0
        goto err;
1021
0
    if (EVP_PKEY_get_octet_string_param(pubp,
1022
0
            OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY,
1023
0
            lpub, OSSL_HPKE_MAXSIZE, &lpublen)
1024
0
        != 1) {
1025
0
        OPENSSL_free(lpub);
1026
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
1027
0
        goto err;
1028
0
    }
1029
    /* free up old value */
1030
0
    OPENSSL_free(ctx->authpub);
1031
0
    ctx->authpub = lpub;
1032
0
    ctx->authpublen = lpublen;
1033
0
    erv = 1;
1034
1035
0
err:
1036
0
    EVP_PKEY_free(pubp);
1037
0
    return erv;
1038
0
}
1039
1040
int OSSL_HPKE_CTX_get_seq(OSSL_HPKE_CTX *ctx, uint64_t *seq)
1041
0
{
1042
0
    if (ctx == NULL || seq == NULL) {
1043
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_NULL_PARAMETER);
1044
0
        return 0;
1045
0
    }
1046
0
    *seq = ctx->seq;
1047
0
    return 1;
1048
0
}
1049
1050
int OSSL_HPKE_CTX_set_seq(OSSL_HPKE_CTX *ctx, uint64_t seq)
1051
0
{
1052
0
    if (ctx == NULL) {
1053
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_NULL_PARAMETER);
1054
0
        return 0;
1055
0
    }
1056
    /*
1057
     * We disallow senders from doing this as it's dangerous
1058
     * Receivers are ok to use this, as no harm should ensue
1059
     * if they go wrong.
1060
     */
1061
0
    if (ctx->role == OSSL_HPKE_ROLE_SENDER) {
1062
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
1063
0
        return 0;
1064
0
    }
1065
0
    ctx->seq = seq;
1066
0
    return 1;
1067
0
}
1068
1069
int OSSL_HPKE_encap(OSSL_HPKE_CTX *ctx,
1070
    unsigned char *enc, size_t *enclen,
1071
    const unsigned char *pub, size_t publen,
1072
    const unsigned char *info, size_t infolen)
1073
0
{
1074
0
    int erv = 1;
1075
0
    size_t minenc = 0;
1076
1077
0
    if (ctx == NULL || enc == NULL || enclen == NULL || *enclen == 0
1078
0
        || pub == NULL || publen == 0) {
1079
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
1080
0
        return 0;
1081
0
    }
1082
0
    if (ctx->role != OSSL_HPKE_ROLE_SENDER) {
1083
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
1084
0
        return 0;
1085
0
    }
1086
0
    if (infolen > OSSL_HPKE_MAX_INFOLEN) {
1087
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
1088
0
        return 0;
1089
0
    }
1090
0
    if (infolen > 0 && info == NULL) {
1091
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
1092
0
        return 0;
1093
0
    }
1094
0
    minenc = OSSL_HPKE_get_public_encap_size(ctx->suite);
1095
0
    if (minenc == 0 || minenc > *enclen) {
1096
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
1097
0
        return 0;
1098
0
    }
1099
0
    if (ctx->shared_secret != NULL) {
1100
        /* only allow one encap per OSSL_HPKE_CTX */
1101
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
1102
0
        return 0;
1103
0
    }
1104
0
    if (hpke_encap(ctx, enc, enclen, pub, publen) != 1) {
1105
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
1106
0
        return 0;
1107
0
    }
1108
    /*
1109
     * note that the info is not part of the context as it
1110
     * only needs to be used once here so doesn't need to
1111
     * be stored
1112
     */
1113
0
    erv = hpke_do_middle(ctx, info, infolen);
1114
0
    return erv;
1115
0
}
1116
1117
int OSSL_HPKE_decap(OSSL_HPKE_CTX *ctx,
1118
    const unsigned char *enc, size_t enclen,
1119
    EVP_PKEY *recippriv,
1120
    const unsigned char *info, size_t infolen)
1121
0
{
1122
0
    int erv = 1;
1123
0
    size_t minenc = 0;
1124
1125
0
    if (ctx == NULL || enc == NULL || enclen == 0 || recippriv == NULL) {
1126
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
1127
0
        return 0;
1128
0
    }
1129
0
    if (ctx->role != OSSL_HPKE_ROLE_RECEIVER) {
1130
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
1131
0
        return 0;
1132
0
    }
1133
0
    if (infolen > OSSL_HPKE_MAX_INFOLEN) {
1134
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
1135
0
        return 0;
1136
0
    }
1137
0
    if (infolen > 0 && info == NULL) {
1138
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
1139
0
        return 0;
1140
0
    }
1141
0
    minenc = OSSL_HPKE_get_public_encap_size(ctx->suite);
1142
0
    if (minenc == 0 || minenc > enclen) {
1143
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
1144
0
        return 0;
1145
0
    }
1146
0
    if (ctx->shared_secret != NULL) {
1147
        /* only allow one encap per OSSL_HPKE_CTX */
1148
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
1149
0
        return 0;
1150
0
    }
1151
0
    erv = hpke_decap(ctx, enc, enclen, recippriv);
1152
0
    if (erv != 1) {
1153
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
1154
0
        return 0;
1155
0
    }
1156
    /*
1157
     * note that the info is not part of the context as it
1158
     * only needs to be used once here so doesn't need to
1159
     * be stored
1160
     */
1161
0
    erv = hpke_do_middle(ctx, info, infolen);
1162
0
    return erv;
1163
0
}
1164
1165
int OSSL_HPKE_seal(OSSL_HPKE_CTX *ctx,
1166
    unsigned char *ct, size_t *ctlen,
1167
    const unsigned char *aad, size_t aadlen,
1168
    const unsigned char *pt, size_t ptlen)
1169
0
{
1170
0
    unsigned char seqbuf[OSSL_HPKE_MAX_NONCELEN];
1171
0
    size_t seqlen = 0;
1172
1173
0
    if (ctx == NULL || ct == NULL || ctlen == NULL || *ctlen == 0
1174
0
        || pt == NULL || ptlen == 0) {
1175
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
1176
0
        return 0;
1177
0
    }
1178
0
    if (ctx->role != OSSL_HPKE_ROLE_SENDER) {
1179
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
1180
0
        return 0;
1181
0
    }
1182
0
    if ((ctx->seq + 1) == 0) { /* wrap around imminent !!! */
1183
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
1184
0
        return 0;
1185
0
    }
1186
0
    if (ctx->key == NULL || ctx->nonce == NULL) {
1187
        /* need to have done an encap first, info can be NULL */
1188
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
1189
0
        return 0;
1190
0
    }
1191
0
    seqlen = hpke_seqnonce2buf(ctx, seqbuf, sizeof(seqbuf));
1192
0
    if (seqlen == 0) {
1193
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
1194
0
        return 0;
1195
0
    }
1196
0
    if (hpke_aead_enc(ctx, seqbuf, aad, aadlen, pt, ptlen, ct, ctlen) != 1) {
1197
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
1198
0
        OPENSSL_cleanse(seqbuf, sizeof(seqbuf));
1199
0
        return 0;
1200
0
    } else {
1201
0
        ctx->seq++;
1202
0
    }
1203
0
    OPENSSL_cleanse(seqbuf, sizeof(seqbuf));
1204
0
    return 1;
1205
0
}
1206
1207
int OSSL_HPKE_open(OSSL_HPKE_CTX *ctx,
1208
    unsigned char *pt, size_t *ptlen,
1209
    const unsigned char *aad, size_t aadlen,
1210
    const unsigned char *ct, size_t ctlen)
1211
0
{
1212
0
    unsigned char seqbuf[OSSL_HPKE_MAX_NONCELEN];
1213
0
    size_t seqlen = 0;
1214
1215
0
    if (ctx == NULL || pt == NULL || ptlen == NULL || *ptlen == 0
1216
0
        || ct == NULL || ctlen == 0) {
1217
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
1218
0
        return 0;
1219
0
    }
1220
0
    if (ctx->role != OSSL_HPKE_ROLE_RECEIVER) {
1221
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
1222
0
        return 0;
1223
0
    }
1224
0
    if ((ctx->seq + 1) == 0) { /* wrap around imminent !!! */
1225
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
1226
0
        return 0;
1227
0
    }
1228
0
    if (ctx->key == NULL || ctx->nonce == NULL) {
1229
        /* need to have done an encap first, info can be NULL */
1230
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
1231
0
        return 0;
1232
0
    }
1233
0
    seqlen = hpke_seqnonce2buf(ctx, seqbuf, sizeof(seqbuf));
1234
0
    if (seqlen == 0) {
1235
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
1236
0
        return 0;
1237
0
    }
1238
0
    if (hpke_aead_dec(ctx, seqbuf, aad, aadlen, ct, ctlen, pt, ptlen) != 1) {
1239
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
1240
0
        OPENSSL_cleanse(seqbuf, sizeof(seqbuf));
1241
0
        return 0;
1242
0
    }
1243
0
    ctx->seq++;
1244
0
    OPENSSL_cleanse(seqbuf, sizeof(seqbuf));
1245
0
    return 1;
1246
0
}
1247
1248
int OSSL_HPKE_export(OSSL_HPKE_CTX *ctx,
1249
    unsigned char *secret, size_t secretlen,
1250
    const unsigned char *label, size_t labellen)
1251
0
{
1252
0
    int erv = 0;
1253
0
    EVP_KDF_CTX *kctx = NULL;
1254
0
    unsigned char suitebuf[6];
1255
0
    const char *mdname = NULL;
1256
0
    const OSSL_HPKE_KDF_INFO *kdf_info = NULL;
1257
1258
0
    if (ctx == NULL || secret == NULL || secretlen == 0) {
1259
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
1260
0
        return 0;
1261
0
    }
1262
0
    if (labellen > OSSL_HPKE_MAX_PARMLEN) {
1263
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
1264
0
        return 0;
1265
0
    }
1266
0
    if (labellen > 0 && label == NULL) {
1267
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
1268
0
        return 0;
1269
0
    }
1270
0
    if (ctx->exportersec == NULL) {
1271
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
1272
0
        return 0;
1273
0
    }
1274
0
    kdf_info = ossl_HPKE_KDF_INFO_find_id(ctx->suite.kdf_id);
1275
0
    if (kdf_info == NULL) {
1276
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
1277
0
        return 0;
1278
0
    }
1279
0
    mdname = kdf_info->mdname;
1280
0
    kctx = ossl_kdf_ctx_create("HKDF", mdname, ctx->libctx, ctx->propq);
1281
0
    if (kctx == NULL) {
1282
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
1283
0
        return 0;
1284
0
    }
1285
    /* full suiteid as per RFC9180 sec 5.3 */
1286
0
    suitebuf[0] = ctx->suite.kem_id / 256;
1287
0
    suitebuf[1] = ctx->suite.kem_id % 256;
1288
0
    suitebuf[2] = ctx->suite.kdf_id / 256;
1289
0
    suitebuf[3] = ctx->suite.kdf_id % 256;
1290
0
    suitebuf[4] = ctx->suite.aead_id / 256;
1291
0
    suitebuf[5] = ctx->suite.aead_id % 256;
1292
0
    erv = ossl_hpke_labeled_expand(kctx, secret, secretlen,
1293
0
        ctx->exportersec, ctx->exporterseclen,
1294
0
        OSSL_HPKE_SEC51LABEL,
1295
0
        suitebuf, sizeof(suitebuf),
1296
0
        OSSL_HPKE_EXP_SEC_LABEL,
1297
0
        label, labellen);
1298
0
    EVP_KDF_CTX_free(kctx);
1299
0
    if (erv != 1)
1300
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
1301
0
    return erv;
1302
0
}
1303
1304
int OSSL_HPKE_keygen(OSSL_HPKE_SUITE suite,
1305
    unsigned char *pub, size_t *publen, EVP_PKEY **priv,
1306
    const unsigned char *ikm, size_t ikmlen,
1307
    OSSL_LIB_CTX *libctx, const char *propq)
1308
0
{
1309
0
    int erv = 0; /* Our error return value - 1 is success */
1310
0
    EVP_PKEY_CTX *pctx = NULL;
1311
0
    EVP_PKEY *skR = NULL;
1312
0
    const OSSL_HPKE_KEM_INFO *kem_info = NULL;
1313
0
    OSSL_PARAM params[3], *p = params;
1314
1315
0
    if (pub == NULL || publen == NULL || *publen == 0 || priv == NULL) {
1316
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
1317
0
        return 0;
1318
0
    }
1319
0
    if (hpke_suite_check(suite, &kem_info, NULL, NULL) != 1) {
1320
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
1321
0
        return 0;
1322
0
    }
1323
0
    if ((ikmlen > 0 && ikm == NULL)
1324
0
        || (ikmlen == 0 && ikm != NULL)
1325
0
        || ikmlen > OSSL_HPKE_MAX_PARMLEN) {
1326
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
1327
0
        return 0;
1328
0
    }
1329
1330
0
    if (hpke_kem_id_nist_curve(suite.kem_id) == 1) {
1331
0
        *p++ = OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME,
1332
0
            (char *)kem_info->groupname, 0);
1333
0
        pctx = EVP_PKEY_CTX_new_from_name(libctx, "EC", propq);
1334
0
    } else {
1335
0
        pctx = EVP_PKEY_CTX_new_from_name(libctx, kem_info->keytype, propq);
1336
0
    }
1337
0
    if (pctx == NULL
1338
0
        || EVP_PKEY_keygen_init(pctx) <= 0) {
1339
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
1340
0
        goto err;
1341
0
    }
1342
0
    if (ikm != NULL)
1343
0
        *p++ = OSSL_PARAM_construct_octet_string(OSSL_PKEY_PARAM_DHKEM_IKM,
1344
0
            (char *)ikm, ikmlen);
1345
0
    *p = OSSL_PARAM_construct_end();
1346
0
    if (EVP_PKEY_CTX_set_params(pctx, params) <= 0) {
1347
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
1348
0
        goto err;
1349
0
    }
1350
0
    if (EVP_PKEY_generate(pctx, &skR) <= 0) {
1351
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
1352
0
        goto err;
1353
0
    }
1354
0
    EVP_PKEY_CTX_free(pctx);
1355
0
    pctx = NULL;
1356
0
    if (EVP_PKEY_get_octet_string_param(skR, OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY,
1357
0
            pub, *publen, publen)
1358
0
        != 1) {
1359
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
1360
0
        goto err;
1361
0
    }
1362
0
    *priv = skR;
1363
0
    erv = 1;
1364
1365
0
err:
1366
0
    if (erv != 1)
1367
0
        EVP_PKEY_free(skR);
1368
0
    EVP_PKEY_CTX_free(pctx);
1369
0
    return erv;
1370
0
}
1371
1372
int OSSL_HPKE_suite_check(OSSL_HPKE_SUITE suite)
1373
0
{
1374
0
    return hpke_suite_check(suite, NULL, NULL, NULL);
1375
0
}
1376
1377
int OSSL_HPKE_get_grease_value(const OSSL_HPKE_SUITE *suite_in,
1378
    OSSL_HPKE_SUITE *suite,
1379
    unsigned char *enc, size_t *enclen,
1380
    unsigned char *ct, size_t ctlen,
1381
    OSSL_LIB_CTX *libctx, const char *propq)
1382
0
{
1383
0
    OSSL_HPKE_SUITE chosen;
1384
0
    size_t plen = 0;
1385
0
    const OSSL_HPKE_KEM_INFO *kem_info = NULL;
1386
0
    const OSSL_HPKE_AEAD_INFO *aead_info = NULL;
1387
0
    EVP_PKEY *fakepriv = NULL;
1388
1389
0
    if (enc == NULL || enclen == 0
1390
0
        || ct == NULL || ctlen == 0 || suite == NULL) {
1391
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_PASSED_INVALID_ARGUMENT);
1392
0
        return 0;
1393
0
    }
1394
0
    if (suite_in == NULL) {
1395
        /* choose a random suite */
1396
0
        if (hpke_random_suite(libctx, propq, &chosen) != 1) {
1397
0
            ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
1398
0
            goto err;
1399
0
        }
1400
0
    } else {
1401
0
        chosen = *suite_in;
1402
0
    }
1403
0
    if (hpke_suite_check(chosen, &kem_info, NULL, &aead_info) != 1) {
1404
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
1405
0
        goto err;
1406
0
    }
1407
0
    *suite = chosen;
1408
    /* make sure room for tag and one plaintext octet */
1409
0
    if (aead_info->taglen >= ctlen) {
1410
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
1411
0
        goto err;
1412
0
    }
1413
    /* publen */
1414
0
    plen = kem_info->Npk;
1415
0
    if (plen > *enclen) {
1416
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
1417
0
        goto err;
1418
0
    }
1419
    /*
1420
     * In order for our enc to look good for sure, we generate and then
1421
     * delete a real key for that curve - bit OTT but it ensures we do
1422
     * get the encoding right (e.g. 0x04 as 1st octet for NIST curves in
1423
     * uncompressed form) and that the value really does map to a point on
1424
     * the relevant curve.
1425
     */
1426
0
    if (OSSL_HPKE_keygen(chosen, enc, enclen, &fakepriv, NULL, 0,
1427
0
            libctx, propq)
1428
0
        != 1) {
1429
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
1430
0
        goto err;
1431
0
    }
1432
0
    EVP_PKEY_free(fakepriv);
1433
0
    if (RAND_bytes_ex(libctx, ct, ctlen, 0) <= 0) {
1434
0
        ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
1435
0
        goto err;
1436
0
    }
1437
0
    return 1;
1438
0
err:
1439
0
    return 0;
1440
0
}
1441
1442
int OSSL_HPKE_str2suite(const char *str, OSSL_HPKE_SUITE *suite)
1443
0
{
1444
0
    return ossl_hpke_str2suite(str, suite);
1445
0
}
1446
1447
size_t OSSL_HPKE_get_ciphertext_size(OSSL_HPKE_SUITE suite, size_t clearlen)
1448
0
{
1449
0
    size_t enclen = 0;
1450
0
    size_t cipherlen = 0;
1451
1452
0
    if (hpke_expansion(suite, &enclen, clearlen, &cipherlen) != 1)
1453
0
        return 0;
1454
0
    return cipherlen;
1455
0
}
1456
1457
size_t OSSL_HPKE_get_public_encap_size(OSSL_HPKE_SUITE suite)
1458
0
{
1459
0
    size_t enclen = 0;
1460
0
    size_t cipherlen = 0;
1461
0
    size_t clearlen = 16;
1462
1463
0
    if (hpke_expansion(suite, &enclen, clearlen, &cipherlen) != 1)
1464
0
        return 0;
1465
0
    return enclen;
1466
0
}
1467
1468
size_t OSSL_HPKE_get_recommended_ikmelen(OSSL_HPKE_SUITE suite)
1469
0
{
1470
0
    const OSSL_HPKE_KEM_INFO *kem_info = NULL;
1471
1472
0
    if (hpke_suite_check(suite, &kem_info, NULL, NULL) != 1)
1473
0
        return 0;
1474
0
    if (kem_info == NULL)
1475
0
        return 0;
1476
1477
0
    return kem_info->Nsk;
1478
0
}