Path: blob/main/crypto/openssl/providers/implementations/keymgmt/mlx_kmgmt.c
108775 views
/*1* Copyright 2024-2025 The OpenSSL Project Authors. All Rights Reserved.2*3* Licensed under the Apache License 2.0 (the "License"). You may not use4* this file except in compliance with the License. You can obtain a copy5* in the file LICENSE in the source distribution or at6* https://www.openssl.org/source/license.html7*/89#include <openssl/core_dispatch.h>10#include <openssl/core_names.h>11#include <openssl/err.h>12#include <openssl/param_build.h>13#include <openssl/params.h>14#include <openssl/proverr.h>15#include <openssl/rand.h>16#include <openssl/self_test.h>17#include "internal/nelem.h"18#include "internal/param_build_set.h"19#include "prov/implementations.h"20#include "prov/mlx_kem.h"21#include "prov/provider_ctx.h"22#include "prov/providercommon.h"23#include "prov/securitycheck.h"2425static OSSL_FUNC_keymgmt_gen_fn mlx_kem_gen;26static OSSL_FUNC_keymgmt_gen_cleanup_fn mlx_kem_gen_cleanup;27static OSSL_FUNC_keymgmt_gen_set_params_fn mlx_kem_gen_set_params;28static OSSL_FUNC_keymgmt_gen_settable_params_fn mlx_kem_gen_settable_params;29static OSSL_FUNC_keymgmt_get_params_fn mlx_kem_get_params;30static OSSL_FUNC_keymgmt_gettable_params_fn mlx_kem_gettable_params;31static OSSL_FUNC_keymgmt_set_params_fn mlx_kem_set_params;32static OSSL_FUNC_keymgmt_settable_params_fn mlx_kem_settable_params;33static OSSL_FUNC_keymgmt_has_fn mlx_kem_has;34static OSSL_FUNC_keymgmt_match_fn mlx_kem_match;35static OSSL_FUNC_keymgmt_import_fn mlx_kem_import;36static OSSL_FUNC_keymgmt_export_fn mlx_kem_export;37static OSSL_FUNC_keymgmt_import_types_fn mlx_kem_imexport_types;38static OSSL_FUNC_keymgmt_export_types_fn mlx_kem_imexport_types;39static OSSL_FUNC_keymgmt_dup_fn mlx_kem_dup;4041static const int minimal_selection = OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS42| OSSL_KEYMGMT_SELECT_PRIVATE_KEY;4344/* Must match DECLARE_DISPATCH invocations at the end of the file */45static const ECDH_VINFO hybrid_vtable[] = {46{ "EC", "P-256", 65, 32, 32, 1, EVP_PKEY_ML_KEM_768 },47{ "EC", "P-384", 97, 48, 48, 1, EVP_PKEY_ML_KEM_1024 },48#if !defined(OPENSSL_NO_ECX)49{ "X25519", NULL, 32, 32, 32, 0, EVP_PKEY_ML_KEM_768 },50{ "X448", NULL, 56, 56, 56, 0, EVP_PKEY_ML_KEM_1024 },51#endif52};5354typedef struct mlx_kem_gen_ctx_st {55OSSL_LIB_CTX *libctx;56char *propq;57int selection;58unsigned int evp_type;59} PROV_ML_KEM_GEN_CTX;6061static void mlx_kem_key_free(void *vkey)62{63MLX_KEY *key = vkey;6465if (key == NULL)66return;67OPENSSL_free(key->propq);68EVP_PKEY_free(key->mkey);69EVP_PKEY_free(key->xkey);70OPENSSL_free(key);71}7273/* Takes ownership of propq */74static void *75mlx_kem_key_new(unsigned int v, OSSL_LIB_CTX *libctx, char *propq)76{77MLX_KEY *key = NULL;78unsigned int ml_kem_variant;7980if (!ossl_prov_is_running()81|| v >= OSSL_NELEM(hybrid_vtable)82|| (key = OPENSSL_malloc(sizeof(*key))) == NULL)83goto err;8485ml_kem_variant = hybrid_vtable[v].ml_kem_variant;86key->libctx = libctx;87key->minfo = ossl_ml_kem_get_vinfo(ml_kem_variant);88key->xinfo = &hybrid_vtable[v];89key->xkey = key->mkey = NULL;90key->state = MLX_HAVE_NOKEYS;91key->propq = propq;92return key;9394err:95OPENSSL_free(propq);96return NULL;97}9899static int mlx_kem_has(const void *vkey, int selection)100{101const MLX_KEY *key = vkey;102103/* A NULL key MUST fail to have anything */104if (!ossl_prov_is_running() || key == NULL)105return 0;106107switch (selection & OSSL_KEYMGMT_SELECT_KEYPAIR) {108case 0:109return 1;110case OSSL_KEYMGMT_SELECT_PUBLIC_KEY:111return mlx_kem_have_pubkey(key);112default:113return mlx_kem_have_prvkey(key);114}115}116117static int mlx_kem_match(const void *vkey1, const void *vkey2, int selection)118{119const MLX_KEY *key1 = vkey1;120const MLX_KEY *key2 = vkey2;121int have_pub1 = mlx_kem_have_pubkey(key1);122int have_pub2 = mlx_kem_have_pubkey(key2);123124if (!ossl_prov_is_running())125return 0;126127/* Compare domain parameters */128if (key1->xinfo != key2->xinfo)129return 0;130131if (!(selection & OSSL_KEYMGMT_SELECT_KEYPAIR))132return 1;133134if (have_pub1 ^ have_pub2)135return 0;136137/* As in other providers, equal when both have no key material. */138if (!have_pub1)139return 1;140141return EVP_PKEY_eq(key1->mkey, key2->mkey)142&& EVP_PKEY_eq(key1->xkey, key2->xkey);143}144145typedef struct export_cb_arg_st {146const char *algorithm_name;147uint8_t *pubenc;148uint8_t *prvenc;149int pubcount;150int prvcount;151size_t puboff;152size_t prvoff;153size_t publen;154size_t prvlen;155} EXPORT_CB_ARG;156157/* Copy any exported key material into its storage slot */158static int export_sub_cb(const OSSL_PARAM *params, void *varg)159{160EXPORT_CB_ARG *sub_arg = varg;161const OSSL_PARAM *p = NULL;162size_t len;163164/*165* The caller will decide whether anything essential is missing, but, if166* some key material was returned, it should have the right (parameter)167* data type and length.168*/169if (ossl_param_is_empty(params))170return 1;171if (sub_arg->pubenc != NULL172&& (p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_PUB_KEY)) != NULL) {173void *pub = sub_arg->pubenc + sub_arg->puboff;174175if (OSSL_PARAM_get_octet_string(p, &pub, sub_arg->publen, &len) != 1)176return 0;177if (len != sub_arg->publen) {178ERR_raise_data(ERR_LIB_PROV, ERR_R_INTERNAL_ERROR,179"Unexpected %s public key length %lu != %lu",180sub_arg->algorithm_name, (unsigned long)len,181sub_arg->publen);182return 0;183}184++sub_arg->pubcount;185}186if (sub_arg->prvenc != NULL187&& (p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_PRIV_KEY)) != NULL) {188void *prv = sub_arg->prvenc + sub_arg->prvoff;189190if (OSSL_PARAM_get_octet_string(p, &prv, sub_arg->prvlen, &len) != 1)191return 0;192if (len != sub_arg->prvlen) {193ERR_raise_data(ERR_LIB_PROV, ERR_R_INTERNAL_ERROR,194"Unexpected %s private key length %lu != %lu",195sub_arg->algorithm_name, (unsigned long)len,196(unsigned long)sub_arg->publen);197return 0;198}199++sub_arg->prvcount;200}201return 1;202}203204static int205export_sub(EXPORT_CB_ARG *sub_arg, int selection, MLX_KEY *key)206{207int slot;208209/*210* The caller is responsible for initialising only the pubenc and prvenc211* pointer fields, the rest are set here or in the callback.212*/213sub_arg->pubcount = 0;214sub_arg->prvcount = 0;215216for (slot = 0; slot < 2; ++slot) {217int ml_kem_slot = key->xinfo->ml_kem_slot;218EVP_PKEY *pkey;219220/* Export the parts of each component into its storage slot */221if (slot == ml_kem_slot) {222pkey = key->mkey;223sub_arg->algorithm_name = key->minfo->algorithm_name;224sub_arg->puboff = slot * key->xinfo->pubkey_bytes;225sub_arg->prvoff = slot * key->xinfo->prvkey_bytes;226sub_arg->publen = key->minfo->pubkey_bytes;227sub_arg->prvlen = key->minfo->prvkey_bytes;228} else {229pkey = key->xkey;230sub_arg->algorithm_name = key->xinfo->algorithm_name;231sub_arg->puboff = (1 - ml_kem_slot) * key->minfo->pubkey_bytes;232sub_arg->prvoff = (1 - ml_kem_slot) * key->minfo->prvkey_bytes;233sub_arg->publen = key->xinfo->pubkey_bytes;234sub_arg->prvlen = key->xinfo->prvkey_bytes;235}236if (!EVP_PKEY_export(pkey, selection, export_sub_cb, (void *)sub_arg))237return 0;238}239return 1;240}241242static int mlx_kem_export(void *vkey, int selection, OSSL_CALLBACK *param_cb,243void *cbarg)244{245MLX_KEY *key = vkey;246OSSL_PARAM_BLD *tmpl = NULL;247OSSL_PARAM *params = NULL;248size_t publen;249size_t prvlen;250int ret = 0;251EXPORT_CB_ARG sub_arg;252253if (!ossl_prov_is_running() || key == NULL)254return 0;255256if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) == 0)257return 0;258259/* Fail when no key material has yet been provided */260if (!mlx_kem_have_pubkey(key)) {261ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_KEY);262return 0;263}264publen = key->minfo->pubkey_bytes + key->xinfo->pubkey_bytes;265prvlen = key->minfo->prvkey_bytes + key->xinfo->prvkey_bytes;266memset(&sub_arg, 0, sizeof(sub_arg));267268if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0) {269sub_arg.pubenc = OPENSSL_malloc(publen);270if (sub_arg.pubenc == NULL)271goto err;272}273274if (mlx_kem_have_prvkey(key)275&& (selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0) {276/*277* Allocated on the secure heap if configured, this is detected in278* ossl_param_build_set_octet_string(), which will then also use the279* secure heap.280*/281sub_arg.prvenc = OPENSSL_secure_zalloc(prvlen);282if (sub_arg.prvenc == NULL)283goto err;284}285286tmpl = OSSL_PARAM_BLD_new();287if (tmpl == NULL)288goto err;289290/* Extract sub-component key material */291if (!export_sub(&sub_arg, selection, key))292goto err;293294if (sub_arg.pubenc != NULL && sub_arg.pubcount == 2295&& !ossl_param_build_set_octet_string(296tmpl, NULL, OSSL_PKEY_PARAM_PUB_KEY, sub_arg.pubenc, publen))297goto err;298299if (sub_arg.prvenc != NULL && sub_arg.prvcount == 2300&& !ossl_param_build_set_octet_string(301tmpl, NULL, OSSL_PKEY_PARAM_PRIV_KEY, sub_arg.prvenc, prvlen))302goto err;303304params = OSSL_PARAM_BLD_to_param(tmpl);305if (params == NULL)306goto err;307308ret = param_cb(params, cbarg);309OSSL_PARAM_free(params);310311err:312OSSL_PARAM_BLD_free(tmpl);313OPENSSL_secure_clear_free(sub_arg.prvenc, prvlen);314OPENSSL_free(sub_arg.pubenc);315return ret;316}317318static const OSSL_PARAM *mlx_kem_imexport_types(int selection)319{320static const OSSL_PARAM key_types[] = {321OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_PUB_KEY, NULL, 0),322OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_PRIV_KEY, NULL, 0),323OSSL_PARAM_END324};325326if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) != 0)327return key_types;328return NULL;329}330331static int332load_slot(OSSL_LIB_CTX *libctx, const char *propq, const char *pname,333int selection, MLX_KEY *key, int slot, const uint8_t *in,334int mbytes, int xbytes)335{336EVP_PKEY_CTX *ctx;337EVP_PKEY **ppkey;338OSSL_PARAM parr[] = { OSSL_PARAM_END, OSSL_PARAM_END, OSSL_PARAM_END };339const char *alg;340char *group = NULL;341size_t off, len;342void *val;343int ml_kem_slot = key->xinfo->ml_kem_slot;344int ret = 0;345346if (slot == ml_kem_slot) {347alg = key->minfo->algorithm_name;348ppkey = &key->mkey;349off = slot * xbytes;350len = mbytes;351} else {352alg = key->xinfo->algorithm_name;353group = (char *)key->xinfo->group_name;354ppkey = &key->xkey;355off = (1 - ml_kem_slot) * mbytes;356len = xbytes;357}358val = (void *)(in + off);359360if ((ctx = EVP_PKEY_CTX_new_from_name(libctx, alg, propq)) == NULL361|| EVP_PKEY_fromdata_init(ctx) <= 0)362goto err;363parr[0] = OSSL_PARAM_construct_octet_string(pname, val, len);364if (group != NULL)365parr[1] = OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME,366group, 0);367if (EVP_PKEY_fromdata(ctx, ppkey, selection, parr) > 0)368ret = 1;369370err:371EVP_PKEY_CTX_free(ctx);372return ret;373}374375static int376load_keys(MLX_KEY *key,377const uint8_t *pubenc, size_t publen,378const uint8_t *prvenc, size_t prvlen)379{380int slot;381382for (slot = 0; slot < 2; ++slot) {383if (prvlen) {384/* Ignore public keys when private provided */385if (!load_slot(key->libctx, key->propq, OSSL_PKEY_PARAM_PRIV_KEY,386minimal_selection, key, slot, prvenc,387key->minfo->prvkey_bytes, key->xinfo->prvkey_bytes))388goto err;389} else if (publen) {390/* Absent private key data, import public keys */391if (!load_slot(key->libctx, key->propq, OSSL_PKEY_PARAM_PUB_KEY,392minimal_selection, key, slot, pubenc,393key->minfo->pubkey_bytes, key->xinfo->pubkey_bytes))394goto err;395}396}397key->state = prvlen ? MLX_HAVE_PRVKEY : MLX_HAVE_PUBKEY;398return 1;399400err:401EVP_PKEY_free(key->mkey);402EVP_PKEY_free(key->xkey);403key->xkey = key->mkey = NULL;404key->state = MLX_HAVE_NOKEYS;405return 0;406}407408static int mlx_kem_key_fromdata(MLX_KEY *key,409const OSSL_PARAM params[],410int include_private)411{412const OSSL_PARAM *param_prv_key = NULL, *param_pub_key;413const void *pubenc = NULL, *prvenc = NULL;414size_t pubkey_bytes, prvkey_bytes;415size_t publen = 0, prvlen = 0;416417/* Invalid attempt to mutate a key, what is the right error to report? */418if (key == NULL || mlx_kem_have_pubkey(key))419return 0;420pubkey_bytes = key->minfo->pubkey_bytes + key->xinfo->pubkey_bytes;421prvkey_bytes = key->minfo->prvkey_bytes + key->xinfo->prvkey_bytes;422423/* What does the caller want to set? */424param_pub_key = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_PUB_KEY);425if (param_pub_key != NULL && OSSL_PARAM_get_octet_string_ptr(param_pub_key, &pubenc, &publen) != 1)426return 0;427if (include_private)428param_prv_key = OSSL_PARAM_locate_const(params,429OSSL_PKEY_PARAM_PRIV_KEY);430if (param_prv_key != NULL && OSSL_PARAM_get_octet_string_ptr(param_prv_key, &prvenc, &prvlen) != 1)431return 0;432433/* The caller MUST specify at least one of the public or private keys. */434if (publen == 0 && prvlen == 0) {435ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_KEY);436return 0;437}438439/*440* When a pubkey is provided, its length MUST be correct, if a private key441* is also provided, the public key will be otherwise ignored. We could442* look for a matching encoded block, but unclear this is useful.443*/444if (publen != 0 && publen != pubkey_bytes) {445ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH);446return 0;447}448if (prvlen != 0 && prvlen != prvkey_bytes) {449ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH);450return 0;451}452453return load_keys(key, pubenc, publen, prvenc, prvlen);454}455456static int mlx_kem_import(void *vkey, int selection, const OSSL_PARAM params[])457{458MLX_KEY *key = vkey;459int include_private;460461if (!ossl_prov_is_running() || key == NULL)462return 0;463464if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) == 0)465return 0;466467include_private = selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY ? 1 : 0;468return mlx_kem_key_fromdata(key, params, include_private);469}470471static const OSSL_PARAM *mlx_kem_gettable_params(void *provctx)472{473static const OSSL_PARAM arr[] = {474OSSL_PARAM_int(OSSL_PKEY_PARAM_BITS, NULL),475OSSL_PARAM_int(OSSL_PKEY_PARAM_SECURITY_BITS, NULL),476OSSL_PARAM_int(OSSL_PKEY_PARAM_MAX_SIZE, NULL),477OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY, NULL, 0),478OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_PRIV_KEY, NULL, 0),479OSSL_PARAM_END480};481482return arr;483}484485/*486* It is assumed the key is guaranteed non-NULL here, and is from this provider487*/488static int mlx_kem_get_params(void *vkey, OSSL_PARAM params[])489{490MLX_KEY *key = vkey;491OSSL_PARAM *p, *pub, *prv = NULL;492EXPORT_CB_ARG sub_arg;493int selection;494size_t publen = key->minfo->pubkey_bytes + key->xinfo->pubkey_bytes;495size_t prvlen = key->minfo->prvkey_bytes + key->xinfo->prvkey_bytes;496497/* The reported "bit" count is those of the ML-KEM key */498p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_BITS);499if (p != NULL)500if (!OSSL_PARAM_set_int(p, key->minfo->bits))501return 0;502503/* The reported security bits are those of the ML-KEM key */504p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_SECURITY_BITS);505if (p != NULL)506if (!OSSL_PARAM_set_int(p, key->minfo->secbits))507return 0;508509/* The ciphertext sizes are additive */510p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_MAX_SIZE);511if (p != NULL)512if (!OSSL_PARAM_set_int(p, key->minfo->ctext_bytes + key->xinfo->pubkey_bytes))513return 0;514515if (!mlx_kem_have_pubkey(key))516return 1;517518memset(&sub_arg, 0, sizeof(sub_arg));519pub = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY);520if (pub != NULL) {521if (pub->data_type != OSSL_PARAM_OCTET_STRING)522return 0;523pub->return_size = publen;524if (pub->data == NULL) {525pub = NULL;526} else if (pub->data_size < publen) {527ERR_raise_data(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL,528"public key output buffer too short: %lu < %lu",529(unsigned long)pub->data_size,530(unsigned long)publen);531return 0;532} else {533sub_arg.pubenc = pub->data;534}535}536if (mlx_kem_have_prvkey(key)) {537prv = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_PRIV_KEY);538if (prv != NULL) {539if (prv->data_type != OSSL_PARAM_OCTET_STRING)540return 0;541prv->return_size = prvlen;542if (prv->data == NULL) {543prv = NULL;544} else if (prv->data_size < prvlen) {545ERR_raise_data(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL,546"private key output buffer too short: %lu < %lu",547(unsigned long)prv->data_size,548(unsigned long)prvlen);549return 0;550} else {551sub_arg.prvenc = prv->data;552}553}554}555if (pub == NULL && prv == NULL)556return 1;557558selection = prv == NULL ? 0 : OSSL_KEYMGMT_SELECT_PRIVATE_KEY;559selection |= pub == NULL ? 0 : OSSL_KEYMGMT_SELECT_PUBLIC_KEY;560if (key->xinfo->group_name != NULL)561selection |= OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS;562563/* Extract sub-component key material */564if (!export_sub(&sub_arg, selection, key))565return 0;566567if ((pub != NULL && sub_arg.pubcount != 2)568|| (prv != NULL && sub_arg.prvcount != 2))569return 0;570571return 1;572}573574static const OSSL_PARAM *mlx_kem_settable_params(void *provctx)575{576static const OSSL_PARAM arr[] = {577OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY, NULL, 0),578OSSL_PARAM_END579};580581return arr;582}583584static int mlx_kem_set_params(void *vkey, const OSSL_PARAM params[])585{586MLX_KEY *key = vkey;587const OSSL_PARAM *p;588const void *pubenc = NULL;589size_t publen = 0;590591if (ossl_param_is_empty(params))592return 1;593594/* Only one settable parameter is supported */595p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY);596if (p == NULL)597return 1;598599/* Key mutation is reportedly generally not allowed */600if (mlx_kem_have_pubkey(key)) {601ERR_raise_data(ERR_LIB_PROV,602PROV_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE,603"keys cannot be mutated");604return 0;605}606/* An unlikely failure mode is the parameter having some unexpected type */607if (!OSSL_PARAM_get_octet_string_ptr(p, &pubenc, &publen))608return 0;609610p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_PROPERTIES);611if (p != NULL) {612OPENSSL_free(key->propq);613key->propq = NULL;614if (!OSSL_PARAM_get_utf8_string(p, &key->propq, 0))615return 0;616}617618if (publen != key->minfo->pubkey_bytes + key->xinfo->pubkey_bytes) {619ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY);620return 0;621}622623return load_keys(key, pubenc, publen, NULL, 0);624}625626static int mlx_kem_gen_set_params(void *vgctx, const OSSL_PARAM params[])627{628PROV_ML_KEM_GEN_CTX *gctx = vgctx;629const OSSL_PARAM *p;630631if (gctx == NULL)632return 0;633if (ossl_param_is_empty(params))634return 1;635636p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_PROPERTIES);637if (p != NULL) {638if (p->data_type != OSSL_PARAM_UTF8_STRING)639return 0;640OPENSSL_free(gctx->propq);641if ((gctx->propq = OPENSSL_strdup(p->data)) == NULL)642return 0;643}644return 1;645}646647static void *mlx_kem_gen_init(int evp_type, OSSL_LIB_CTX *libctx,648int selection, const OSSL_PARAM params[])649{650PROV_ML_KEM_GEN_CTX *gctx = NULL;651652/*653* We can only generate private keys, check that the selection is654* appropriate.655*/656if (!ossl_prov_is_running()657|| (selection & minimal_selection) == 0658|| (gctx = OPENSSL_zalloc(sizeof(*gctx))) == NULL)659return NULL;660661gctx->evp_type = evp_type;662gctx->libctx = libctx;663gctx->selection = selection;664if (mlx_kem_gen_set_params(gctx, params))665return gctx;666667mlx_kem_gen_cleanup(gctx);668return NULL;669}670671static const OSSL_PARAM *mlx_kem_gen_settable_params(ossl_unused void *vgctx,672ossl_unused void *provctx)673{674static OSSL_PARAM settable[] = {675OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_PROPERTIES, NULL, 0),676OSSL_PARAM_END677};678679return settable;680}681682static void *mlx_kem_gen(void *vgctx, OSSL_CALLBACK *osslcb, void *cbarg)683{684PROV_ML_KEM_GEN_CTX *gctx = vgctx;685MLX_KEY *key;686char *propq;687688if (gctx == NULL689|| (gctx->selection & OSSL_KEYMGMT_SELECT_KEYPAIR) == OSSL_KEYMGMT_SELECT_PUBLIC_KEY)690return NULL;691692/* Lose ownership of propq */693propq = gctx->propq;694gctx->propq = NULL;695if ((key = mlx_kem_key_new(gctx->evp_type, gctx->libctx, propq)) == NULL)696return NULL;697698if ((gctx->selection & OSSL_KEYMGMT_SELECT_KEYPAIR) == 0)699return key;700701/* For now, using the same "propq" for all components */702key->mkey = EVP_PKEY_Q_keygen(key->libctx, key->propq,703key->minfo->algorithm_name);704key->xkey = EVP_PKEY_Q_keygen(key->libctx, key->propq,705key->xinfo->algorithm_name,706key->xinfo->group_name);707if (key->mkey != NULL && key->xkey != NULL) {708key->state = MLX_HAVE_PRVKEY;709return key;710}711712mlx_kem_key_free(key);713return NULL;714}715716static void mlx_kem_gen_cleanup(void *vgctx)717{718PROV_ML_KEM_GEN_CTX *gctx = vgctx;719720if (gctx == NULL)721return;722OPENSSL_free(gctx->propq);723OPENSSL_free(gctx);724}725726static void *mlx_kem_dup(const void *vkey, int selection)727{728const MLX_KEY *key = vkey;729MLX_KEY *ret;730731if (!ossl_prov_is_running()732|| (ret = OPENSSL_memdup(key, sizeof(*ret))) == NULL)733return NULL;734735if (ret->propq != NULL736&& (ret->propq = OPENSSL_strdup(ret->propq)) == NULL) {737OPENSSL_free(ret);738return NULL;739}740741/* Absent key material, nothing left to do */742if (ret->mkey == NULL) {743if (ret->xkey == NULL)744return ret;745/* Fail if the source key is an inconsistent state */746OPENSSL_free(ret->propq);747OPENSSL_free(ret);748return NULL;749}750751switch (selection & OSSL_KEYMGMT_SELECT_KEYPAIR) {752case 0:753ret->xkey = ret->mkey = NULL;754ret->state = MLX_HAVE_NOKEYS;755return ret;756case OSSL_KEYMGMT_SELECT_KEYPAIR:757ret->mkey = EVP_PKEY_dup(key->mkey);758ret->xkey = EVP_PKEY_dup(key->xkey);759if (ret->xkey != NULL && ret->mkey != NULL)760return ret;761break;762default:763ERR_raise_data(ERR_LIB_PROV, PROV_R_UNSUPPORTED_SELECTION,764"duplication of partial key material not supported");765break;766}767768mlx_kem_key_free(ret);769return NULL;770}771772#define DECLARE_DISPATCH(name, variant) \773static OSSL_FUNC_keymgmt_new_fn mlx_##name##_kem_new; \774static void *mlx_##name##_kem_new(void *provctx) \775{ \776OSSL_LIB_CTX *libctx; \777\778libctx = provctx == NULL ? NULL : PROV_LIBCTX_OF(provctx); \779return mlx_kem_key_new(variant, libctx, NULL); \780} \781static OSSL_FUNC_keymgmt_gen_init_fn mlx_##name##_kem_gen_init; \782static void *mlx_##name##_kem_gen_init(void *provctx, int selection, \783const OSSL_PARAM params[]) \784{ \785OSSL_LIB_CTX *libctx; \786\787libctx = provctx == NULL ? NULL : PROV_LIBCTX_OF(provctx); \788return mlx_kem_gen_init(variant, libctx, selection, params); \789} \790const OSSL_DISPATCH ossl_mlx_##name##_kem_kmgmt_functions[] = { \791{ OSSL_FUNC_KEYMGMT_NEW, (OSSL_FUNC)mlx_##name##_kem_new }, \792{ OSSL_FUNC_KEYMGMT_FREE, (OSSL_FUNC)mlx_kem_key_free }, \793{ OSSL_FUNC_KEYMGMT_GET_PARAMS, (OSSL_FUNC)mlx_kem_get_params }, \794{ OSSL_FUNC_KEYMGMT_GETTABLE_PARAMS, (OSSL_FUNC)mlx_kem_gettable_params }, \795{ OSSL_FUNC_KEYMGMT_SET_PARAMS, (OSSL_FUNC)mlx_kem_set_params }, \796{ OSSL_FUNC_KEYMGMT_SETTABLE_PARAMS, (OSSL_FUNC)mlx_kem_settable_params }, \797{ OSSL_FUNC_KEYMGMT_HAS, (OSSL_FUNC)mlx_kem_has }, \798{ OSSL_FUNC_KEYMGMT_MATCH, (OSSL_FUNC)mlx_kem_match }, \799{ OSSL_FUNC_KEYMGMT_GEN_INIT, (OSSL_FUNC)mlx_##name##_kem_gen_init }, \800{ OSSL_FUNC_KEYMGMT_GEN_SET_PARAMS, (OSSL_FUNC)mlx_kem_gen_set_params }, \801{ OSSL_FUNC_KEYMGMT_GEN_SETTABLE_PARAMS, (OSSL_FUNC)mlx_kem_gen_settable_params }, \802{ OSSL_FUNC_KEYMGMT_GEN, (OSSL_FUNC)mlx_kem_gen }, \803{ OSSL_FUNC_KEYMGMT_GEN_CLEANUP, (OSSL_FUNC)mlx_kem_gen_cleanup }, \804{ OSSL_FUNC_KEYMGMT_DUP, (OSSL_FUNC)mlx_kem_dup }, \805{ OSSL_FUNC_KEYMGMT_IMPORT, (OSSL_FUNC)mlx_kem_import }, \806{ OSSL_FUNC_KEYMGMT_IMPORT_TYPES, (OSSL_FUNC)mlx_kem_imexport_types }, \807{ OSSL_FUNC_KEYMGMT_EXPORT, (OSSL_FUNC)mlx_kem_export }, \808{ OSSL_FUNC_KEYMGMT_EXPORT_TYPES, (OSSL_FUNC)mlx_kem_imexport_types }, \809OSSL_DISPATCH_END \810}811/* See |hybrid_vtable| above */812DECLARE_DISPATCH(p256, 0);813DECLARE_DISPATCH(p384, 1);814#if !defined(OPENSSL_NO_ECX)815DECLARE_DISPATCH(x25519, 2);816DECLARE_DISPATCH(x448, 3);817#endif818819820