Home | History | Annotate | Line # | Download | only in kem
      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)
    537         > 0;
    538 }
    539 
    540 /*
    541  * Derive a secret using ECDH (code is shared by the encap and decap)
    542  *
    543  * dhkm = Concat(ecdh(privkey1, peerkey1), ecdh(privkey2, peerkey2)
    544  * kemctx = Concat(sender_pub, recipient_pub, ctx->sender_authkey)
    545  * secret = dhkem_extract_and_expand(kemid, dhkm, kemctx);
    546  *
    547  * Params:
    548  *     ctx Object that contains algorithm state and constants.
    549  *     secret The returned secret (with a length ctx->alg->secretlen bytes).
    550  *     privkey1 A private key used for ECDH key derivation.
    551  *     peerkey1 A public key used for ECDH key derivation with privkey1
    552  *     privkey2 A optional private key used for a second ECDH key derivation.
    553  *              It can be NULL.
    554  *     peerkey2 A optional public key used for a second ECDH key derivation
    555  *              with privkey2,. It can be NULL.
    556  *     sender_pub The senders public key in encoded form.
    557  *     recipient_pub The recipients public key in encoded form.
    558  * Notes:
    559  *     The second ecdh() is only used for the HPKE auth modes when both privkey2
    560  *     and peerkey2 are non NULL (i.e. ctx->sender_authkey is not NULL).
    561  */
    562 static int derive_secret(PROV_EC_CTX *ctx, unsigned char *secret,
    563     const EC_KEY *privkey1, const EC_KEY *peerkey1,
    564     const EC_KEY *privkey2, const EC_KEY *peerkey2,
    565     const unsigned char *sender_pub,
    566     const unsigned char *recipient_pub)
    567 {
    568     int ret = 0;
    569     EVP_KDF_CTX *kdfctx = NULL;
    570     unsigned char sender_authpub[OSSL_HPKE_MAX_PUBLIC];
    571     unsigned char dhkm[OSSL_HPKE_MAX_PRIVATE * 2];
    572     unsigned char kemctx[OSSL_HPKE_MAX_PUBLIC * 3];
    573     size_t sender_authpublen;
    574     size_t kemctxlen = 0, dhkmlen = 0;
    575     const OSSL_HPKE_KEM_INFO *info = ctx->info;
    576     size_t encodedpublen = info->Npk;
    577     size_t encodedprivlen = info->Nsk;
    578     int auth = ctx->sender_authkey != NULL;
    579 
    580     if (!generate_ecdhkm(privkey1, peerkey1, dhkm, sizeof(dhkm), encodedprivlen))
    581         goto err;
    582     dhkmlen = encodedprivlen;
    583     kemctxlen = 2 * encodedpublen;
    584 
    585     /* Concat the optional second ECDH (used for Auth) */
    586     if (auth) {
    587         /* Get the public key of the auth sender in encoded form */
    588         if (!ecpubkey_todata(ctx->sender_authkey, sender_authpub,
    589                 &sender_authpublen, sizeof(sender_authpub)))
    590             goto err;
    591         if (sender_authpublen != encodedpublen) {
    592             ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_KEY,
    593                 "Invalid sender auth public key");
    594             goto err;
    595         }
    596         if (!generate_ecdhkm(privkey2, peerkey2,
    597                 dhkm + dhkmlen, sizeof(dhkm) - dhkmlen,
    598                 encodedprivlen))
    599             goto err;
    600         dhkmlen += encodedprivlen;
    601         kemctxlen += encodedpublen;
    602     }
    603     if (kemctxlen > sizeof(kemctx))
    604         goto err;
    605 
    606     /* kemctx is the concat of both sides encoded public key */
    607     memcpy(kemctx, sender_pub, info->Npk);
    608     memcpy(kemctx + info->Npk, recipient_pub, info->Npk);
    609     if (auth)
    610         memcpy(kemctx + 2 * encodedpublen, sender_authpub, encodedpublen);
    611     kdfctx = ossl_kdf_ctx_create(ctx->kdfname, info->mdname,
    612         ctx->libctx, ctx->propq);
    613     if (kdfctx == NULL)
    614         goto err;
    615     if (!dhkem_extract_and_expand(kdfctx, secret, info->Nsecret,
    616             info->kem_id, dhkm, dhkmlen,
    617             kemctx, kemctxlen))
    618         goto err;
    619     ret = 1;
    620 err:
    621     OPENSSL_cleanse(dhkm, dhkmlen);
    622     EVP_KDF_CTX_free(kdfctx);
    623     return ret;
    624 }
    625 
    626 /*
    627  * Do a DHKEM encapsulate operation.
    628  *
    629  * See Section 4.1 Encap() and AuthEncap()
    630  *
    631  * Params:
    632  *     ctx A context object holding the recipients public key and the
    633  *         optional senders auth private key.
    634  *     enc A buffer to return the senders ephemeral public key.
    635  *         Setting this to NULL allows the enclen and secretlen to return
    636  *         values, without calculating the secret.
    637  *     enclen Passes in the max size of the enc buffer and returns the
    638  *            encoded public key length.
    639  *     secret A buffer to return the calculated shared secret.
    640  *     secretlen Passes in the max size of the secret buffer and returns the
    641  *               secret length.
    642  * Returns: 1 on success or 0 otherwise.
    643  */
    644 static int dhkem_encap(PROV_EC_CTX *ctx,
    645     unsigned char *enc, size_t *enclen,
    646     unsigned char *secret, size_t *secretlen)
    647 {
    648     int ret = 0;
    649     EC_KEY *sender_ephemkey = NULL;
    650     unsigned char sender_pub[OSSL_HPKE_MAX_PUBLIC];
    651     unsigned char recipient_pub[OSSL_HPKE_MAX_PUBLIC];
    652     size_t sender_publen, recipient_publen;
    653     const OSSL_HPKE_KEM_INFO *info = ctx->info;
    654 
    655     if (enc == NULL) {
    656         if (enclen == NULL && secretlen == NULL)
    657             return 0;
    658         if (enclen != NULL)
    659             *enclen = info->Nenc;
    660         if (secretlen != NULL)
    661             *secretlen = info->Nsecret;
    662         return 1;
    663     }
    664 
    665     if (*secretlen < info->Nsecret) {
    666         ERR_raise_data(ERR_LIB_PROV, PROV_R_BAD_LENGTH, "*secretlen too small");
    667         return 0;
    668     }
    669     if (*enclen < info->Nenc) {
    670         ERR_raise_data(ERR_LIB_PROV, PROV_R_BAD_LENGTH, "*enclen too small");
    671         return 0;
    672     }
    673 
    674     /* Create an ephemeral key */
    675     sender_ephemkey = derivekey(ctx, ctx->ikm, ctx->ikmlen);
    676     if (sender_ephemkey == NULL)
    677         goto err;
    678     if (!ecpubkey_todata(sender_ephemkey, sender_pub, &sender_publen,
    679             sizeof(sender_pub))
    680         || !ecpubkey_todata(ctx->recipient_key, recipient_pub,
    681             &recipient_publen, sizeof(recipient_pub)))
    682         goto err;
    683 
    684     if (sender_publen != info->Npk
    685         || recipient_publen != sender_publen) {
    686         ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_KEY, "Invalid public key");
    687         goto err;
    688     }
    689 
    690     if (!derive_secret(ctx, secret,
    691             sender_ephemkey, ctx->recipient_key,
    692             ctx->sender_authkey, ctx->recipient_key,
    693             sender_pub, recipient_pub))
    694         goto err;
    695 
    696     /* Return the senders ephemeral public key in encoded form */
    697     memcpy(enc, sender_pub, sender_publen);
    698     *enclen = sender_publen;
    699     *secretlen = info->Nsecret;
    700     ret = 1;
    701 err:
    702     EC_KEY_free(sender_ephemkey);
    703     return ret;
    704 }
    705 
    706 /*
    707  * Do a DHKEM decapsulate operation.
    708  * See Section 4.1 Decap() and Auth Decap()
    709  *
    710  * Params:
    711  *     ctx A context object holding the recipients private key and the
    712  *         optional senders auth public key.
    713  *     secret A buffer to return the calculated shared secret. Setting this to
    714  *            NULL can be used to return the secretlen.
    715  *     secretlen Passes in the max size of the secret buffer and returns the
    716  *               secret length.
    717  *     enc A buffer containing the senders ephemeral public key that was returned
    718  *         from dhkem_encap().
    719  *     enclen The length in bytes of enc.
    720  * Returns: 1 If the shared secret is returned or 0 on error.
    721  */
    722 static int dhkem_decap(PROV_EC_CTX *ctx,
    723     unsigned char *secret, size_t *secretlen,
    724     const unsigned char *enc, size_t enclen)
    725 {
    726     int ret = 0;
    727     EC_KEY *sender_ephempubkey = NULL;
    728     const OSSL_HPKE_KEM_INFO *info = ctx->info;
    729     unsigned char recipient_pub[OSSL_HPKE_MAX_PUBLIC];
    730     size_t recipient_publen;
    731     size_t encodedpublen = info->Npk;
    732 
    733     if (secret == NULL) {
    734         *secretlen = info->Nsecret;
    735         return 1;
    736     }
    737 
    738     if (*secretlen < info->Nsecret) {
    739         ERR_raise_data(ERR_LIB_PROV, PROV_R_BAD_LENGTH, "*secretlen too small");
    740         return 0;
    741     }
    742     if (enclen != encodedpublen) {
    743         ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_KEY, "Invalid enc public key");
    744         return 0;
    745     }
    746 
    747     sender_ephempubkey = eckey_frompub(ctx->recipient_key, enc, enclen);
    748     if (sender_ephempubkey == NULL)
    749         goto err;
    750     if (!ecpubkey_todata(ctx->recipient_key, recipient_pub, &recipient_publen,
    751             sizeof(recipient_pub)))
    752         goto err;
    753     if (recipient_publen != encodedpublen) {
    754         ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_KEY, "Invalid recipient public key");
    755         goto err;
    756     }
    757 
    758     if (!derive_secret(ctx, secret,
    759             ctx->recipient_key, sender_ephempubkey,
    760             ctx->recipient_key, ctx->sender_authkey,
    761             enc, recipient_pub))
    762         goto err;
    763     *secretlen = info->Nsecret;
    764     ret = 1;
    765 err:
    766     EC_KEY_free(sender_ephempubkey);
    767     return ret;
    768 }
    769 
    770 static int eckem_encapsulate(void *vctx, unsigned char *out, size_t *outlen,
    771     unsigned char *secret, size_t *secretlen)
    772 {
    773     PROV_EC_CTX *ctx = (PROV_EC_CTX *)vctx;
    774 
    775     switch (ctx->mode) {
    776     case KEM_MODE_DHKEM:
    777         return dhkem_encap(ctx, out, outlen, secret, secretlen);
    778     default:
    779         ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_MODE);
    780         return -2;
    781     }
    782 }
    783 
    784 static int eckem_decapsulate(void *vctx, unsigned char *out, size_t *outlen,
    785     const unsigned char *in, size_t inlen)
    786 {
    787     PROV_EC_CTX *ctx = (PROV_EC_CTX *)vctx;
    788 
    789     switch (ctx->mode) {
    790     case KEM_MODE_DHKEM:
    791         return dhkem_decap(ctx, out, outlen, in, inlen);
    792     default:
    793         ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_MODE);
    794         return -2;
    795     }
    796 }
    797 
    798 const OSSL_DISPATCH ossl_ec_asym_kem_functions[] = {
    799     { OSSL_FUNC_KEM_NEWCTX, (void (*)(void))eckem_newctx },
    800     { OSSL_FUNC_KEM_ENCAPSULATE_INIT,
    801         (void (*)(void))eckem_encapsulate_init },
    802     { OSSL_FUNC_KEM_ENCAPSULATE, (void (*)(void))eckem_encapsulate },
    803     { OSSL_FUNC_KEM_DECAPSULATE_INIT,
    804         (void (*)(void))eckem_decapsulate_init },
    805     { OSSL_FUNC_KEM_DECAPSULATE, (void (*)(void))eckem_decapsulate },
    806     { OSSL_FUNC_KEM_FREECTX, (void (*)(void))eckem_freectx },
    807     { OSSL_FUNC_KEM_SET_CTX_PARAMS,
    808         (void (*)(void))eckem_set_ctx_params },
    809     { OSSL_FUNC_KEM_SETTABLE_CTX_PARAMS,
    810         (void (*)(void))eckem_settable_ctx_params },
    811     { OSSL_FUNC_KEM_AUTH_ENCAPSULATE_INIT,
    812         (void (*)(void))eckem_auth_encapsulate_init },
    813     { OSSL_FUNC_KEM_AUTH_DECAPSULATE_INIT,
    814         (void (*)(void))eckem_auth_decapsulate_init },
    815     OSSL_DISPATCH_END
    816 };
    817