1 /* 2 * Copyright 2024-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 #include <openssl/core_dispatch.h> 11 #include <openssl/core_names.h> 12 #include <openssl/err.h> 13 #include <openssl/param_build.h> 14 #include <openssl/params.h> 15 #include <openssl/proverr.h> 16 #include <openssl/rand.h> 17 #include <openssl/self_test.h> 18 #include "internal/nelem.h" 19 #include "internal/param_build_set.h" 20 #include "prov/implementations.h" 21 #include "prov/mlx_kem.h" 22 #include "prov/provider_ctx.h" 23 #include "prov/providercommon.h" 24 #include "prov/securitycheck.h" 25 26 static OSSL_FUNC_keymgmt_gen_fn mlx_kem_gen; 27 static OSSL_FUNC_keymgmt_gen_cleanup_fn mlx_kem_gen_cleanup; 28 static OSSL_FUNC_keymgmt_gen_set_params_fn mlx_kem_gen_set_params; 29 static OSSL_FUNC_keymgmt_gen_settable_params_fn mlx_kem_gen_settable_params; 30 static OSSL_FUNC_keymgmt_get_params_fn mlx_kem_get_params; 31 static OSSL_FUNC_keymgmt_gettable_params_fn mlx_kem_gettable_params; 32 static OSSL_FUNC_keymgmt_set_params_fn mlx_kem_set_params; 33 static OSSL_FUNC_keymgmt_settable_params_fn mlx_kem_settable_params; 34 static OSSL_FUNC_keymgmt_has_fn mlx_kem_has; 35 static OSSL_FUNC_keymgmt_match_fn mlx_kem_match; 36 static OSSL_FUNC_keymgmt_import_fn mlx_kem_import; 37 static OSSL_FUNC_keymgmt_export_fn mlx_kem_export; 38 static OSSL_FUNC_keymgmt_import_types_fn mlx_kem_imexport_types; 39 static OSSL_FUNC_keymgmt_export_types_fn mlx_kem_imexport_types; 40 static OSSL_FUNC_keymgmt_dup_fn mlx_kem_dup; 41 42 static const int minimal_selection = OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS 43 | OSSL_KEYMGMT_SELECT_PRIVATE_KEY; 44 45 /* Must match DECLARE_DISPATCH invocations at the end of the file */ 46 static const ECDH_VINFO hybrid_vtable[] = { 47 { "EC", "P-256", 65, 32, 32, 1, EVP_PKEY_ML_KEM_768 }, 48 { "EC", "P-384", 97, 48, 48, 1, EVP_PKEY_ML_KEM_1024 }, 49 #if !defined(OPENSSL_NO_ECX) 50 { "X25519", NULL, 32, 32, 32, 0, EVP_PKEY_ML_KEM_768 }, 51 { "X448", NULL, 56, 56, 56, 0, EVP_PKEY_ML_KEM_1024 }, 52 #endif 53 }; 54 55 typedef struct mlx_kem_gen_ctx_st { 56 OSSL_LIB_CTX *libctx; 57 char *propq; 58 int selection; 59 unsigned int evp_type; 60 } PROV_ML_KEM_GEN_CTX; 61 62 static void mlx_kem_key_free(void *vkey) 63 { 64 MLX_KEY *key = vkey; 65 66 if (key == NULL) 67 return; 68 OPENSSL_free(key->propq); 69 EVP_PKEY_free(key->mkey); 70 EVP_PKEY_free(key->xkey); 71 OPENSSL_free(key); 72 } 73 74 /* Takes ownership of propq */ 75 static void * 76 mlx_kem_key_new(unsigned int v, OSSL_LIB_CTX *libctx, char *propq) 77 { 78 MLX_KEY *key = NULL; 79 unsigned int ml_kem_variant; 80 81 if (!ossl_prov_is_running() 82 || v >= OSSL_NELEM(hybrid_vtable) 83 || (key = OPENSSL_malloc(sizeof(*key))) == NULL) 84 goto err; 85 86 ml_kem_variant = hybrid_vtable[v].ml_kem_variant; 87 key->libctx = libctx; 88 key->minfo = ossl_ml_kem_get_vinfo(ml_kem_variant); 89 key->xinfo = &hybrid_vtable[v]; 90 key->xkey = key->mkey = NULL; 91 key->state = MLX_HAVE_NOKEYS; 92 key->propq = propq; 93 return key; 94 95 err: 96 OPENSSL_free(propq); 97 return NULL; 98 } 99 100 101 static int mlx_kem_has(const void *vkey, int selection) 102 { 103 const MLX_KEY *key = vkey; 104 105 /* A NULL key MUST fail to have anything */ 106 if (!ossl_prov_is_running() || key == NULL) 107 return 0; 108 109 switch (selection & OSSL_KEYMGMT_SELECT_KEYPAIR) { 110 case 0: 111 return 1; 112 case OSSL_KEYMGMT_SELECT_PUBLIC_KEY: 113 return mlx_kem_have_pubkey(key); 114 default: 115 return mlx_kem_have_prvkey(key); 116 } 117 } 118 119 static int mlx_kem_match(const void *vkey1, const void *vkey2, int selection) 120 { 121 const MLX_KEY *key1 = vkey1; 122 const MLX_KEY *key2 = vkey2; 123 int have_pub1 = mlx_kem_have_pubkey(key1); 124 int have_pub2 = mlx_kem_have_pubkey(key2); 125 126 if (!ossl_prov_is_running()) 127 return 0; 128 129 /* Compare domain parameters */ 130 if (key1->xinfo != key2->xinfo) 131 return 0; 132 133 if (!(selection & OSSL_KEYMGMT_SELECT_KEYPAIR)) 134 return 1; 135 136 if (have_pub1 ^ have_pub2) 137 return 0; 138 139 /* As in other providers, equal when both have no key material. */ 140 if (!have_pub1) 141 return 1; 142 143 return EVP_PKEY_eq(key1->mkey, key2->mkey) 144 && EVP_PKEY_eq(key1->xkey, key2->xkey); 145 } 146 147 typedef struct export_cb_arg_st { 148 const char *algorithm_name; 149 uint8_t *pubenc; 150 uint8_t *prvenc; 151 int pubcount; 152 int prvcount; 153 size_t puboff; 154 size_t prvoff; 155 size_t publen; 156 size_t prvlen; 157 } EXPORT_CB_ARG; 158 159 /* Copy any exported key material into its storage slot */ 160 static int export_sub_cb(const OSSL_PARAM *params, void *varg) 161 { 162 EXPORT_CB_ARG *sub_arg = varg; 163 const OSSL_PARAM *p = NULL; 164 size_t len; 165 166 /* 167 * The caller will decide whether anything essential is missing, but, if 168 * some key material was returned, it should have the right (parameter) 169 * data type and length. 170 */ 171 if (ossl_param_is_empty(params)) 172 return 1; 173 if (sub_arg->pubenc != NULL 174 && (p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_PUB_KEY)) != NULL) { 175 void *pub = sub_arg->pubenc + sub_arg->puboff; 176 177 if (OSSL_PARAM_get_octet_string(p, &pub, sub_arg->publen, &len) != 1) 178 return 0; 179 if (len != sub_arg->publen) { 180 ERR_raise_data(ERR_LIB_PROV, ERR_R_INTERNAL_ERROR, 181 "Unexpected %s public key length %lu != %lu", 182 sub_arg->algorithm_name, (unsigned long) len, 183 sub_arg->publen); 184 return 0; 185 } 186 ++sub_arg->pubcount; 187 } 188 if (sub_arg->prvenc != NULL 189 && (p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_PRIV_KEY)) != NULL) { 190 void *prv = sub_arg->prvenc + sub_arg->prvoff; 191 192 if (OSSL_PARAM_get_octet_string(p, &prv, sub_arg->prvlen, &len) != 1) 193 return 0; 194 if (len != sub_arg->prvlen) { 195 ERR_raise_data(ERR_LIB_PROV, ERR_R_INTERNAL_ERROR, 196 "Unexpected %s private key length %lu != %lu", 197 sub_arg->algorithm_name, (unsigned long) len, 198 (unsigned long) sub_arg->publen); 199 return 0; 200 } 201 ++sub_arg->prvcount; 202 } 203 return 1; 204 } 205 206 static int 207 export_sub(EXPORT_CB_ARG *sub_arg, int selection, MLX_KEY *key) 208 { 209 int slot; 210 211 /* 212 * The caller is responsible for initialising only the pubenc and prvenc 213 * pointer fields, the rest are set here or in the callback. 214 */ 215 sub_arg->pubcount = 0; 216 sub_arg->prvcount = 0; 217 218 for (slot = 0; slot < 2; ++slot) { 219 int ml_kem_slot = key->xinfo->ml_kem_slot; 220 EVP_PKEY *pkey; 221 222 /* Export the parts of each component into its storage slot */ 223 if (slot == ml_kem_slot) { 224 pkey = key->mkey; 225 sub_arg->algorithm_name = key->minfo->algorithm_name; 226 sub_arg->puboff = slot * key->xinfo->pubkey_bytes; 227 sub_arg->prvoff = slot * key->xinfo->prvkey_bytes; 228 sub_arg->publen = key->minfo->pubkey_bytes; 229 sub_arg->prvlen = key->minfo->prvkey_bytes; 230 } else { 231 pkey = key->xkey; 232 sub_arg->algorithm_name = key->xinfo->algorithm_name; 233 sub_arg->puboff = (1 - ml_kem_slot) * key->minfo->pubkey_bytes; 234 sub_arg->prvoff = (1 - ml_kem_slot) * key->minfo->prvkey_bytes; 235 sub_arg->publen = key->xinfo->pubkey_bytes; 236 sub_arg->prvlen = key->xinfo->prvkey_bytes; 237 } 238 if (!EVP_PKEY_export(pkey, selection, export_sub_cb, (void *)sub_arg)) 239 return 0; 240 } 241 return 1; 242 } 243 244 static int mlx_kem_export(void *vkey, int selection, OSSL_CALLBACK *param_cb, 245 void *cbarg) 246 { 247 MLX_KEY *key = vkey; 248 OSSL_PARAM_BLD *tmpl = NULL; 249 OSSL_PARAM *params = NULL; 250 size_t publen; 251 size_t prvlen; 252 int ret = 0; 253 EXPORT_CB_ARG sub_arg; 254 255 if (!ossl_prov_is_running() || key == NULL) 256 return 0; 257 258 if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) == 0) 259 return 0; 260 261 /* Fail when no key material has yet been provided */ 262 if (!mlx_kem_have_pubkey(key)) { 263 ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_KEY); 264 return 0; 265 } 266 publen = key->minfo->pubkey_bytes + key->xinfo->pubkey_bytes; 267 prvlen = key->minfo->prvkey_bytes + key->xinfo->prvkey_bytes; 268 memset(&sub_arg, 0, sizeof(sub_arg)); 269 270 if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0) { 271 sub_arg.pubenc = OPENSSL_malloc(publen); 272 if (sub_arg.pubenc == NULL) 273 goto err; 274 } 275 276 if (mlx_kem_have_prvkey(key) 277 && (selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0) { 278 /* 279 * Allocated on the secure heap if configured, this is detected in 280 * ossl_param_build_set_octet_string(), which will then also use the 281 * secure heap. 282 */ 283 sub_arg.prvenc = OPENSSL_secure_zalloc(prvlen); 284 if (sub_arg.prvenc == NULL) 285 goto err; 286 } 287 288 tmpl = OSSL_PARAM_BLD_new(); 289 if (tmpl == NULL) 290 goto err; 291 292 /* Extract sub-component key material */ 293 if (!export_sub(&sub_arg, selection, key)) 294 goto err; 295 296 if (sub_arg.pubenc != NULL && sub_arg.pubcount == 2 297 && !ossl_param_build_set_octet_string( 298 tmpl, NULL, OSSL_PKEY_PARAM_PUB_KEY, sub_arg.pubenc, publen)) 299 goto err; 300 301 if (sub_arg.prvenc != NULL && sub_arg.prvcount == 2 302 && !ossl_param_build_set_octet_string( 303 tmpl, NULL, OSSL_PKEY_PARAM_PRIV_KEY, sub_arg.prvenc, prvlen)) 304 goto err; 305 306 params = OSSL_PARAM_BLD_to_param(tmpl); 307 if (params == NULL) 308 goto err; 309 310 ret = param_cb(params, cbarg); 311 OSSL_PARAM_free(params); 312 313 err: 314 OSSL_PARAM_BLD_free(tmpl); 315 OPENSSL_secure_clear_free(sub_arg.prvenc, prvlen); 316 OPENSSL_free(sub_arg.pubenc); 317 return ret; 318 } 319 320 static const OSSL_PARAM *mlx_kem_imexport_types(int selection) 321 { 322 static const OSSL_PARAM key_types[] = { 323 OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_PUB_KEY, NULL, 0), 324 OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_PRIV_KEY, NULL, 0), 325 OSSL_PARAM_END 326 }; 327 328 if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) != 0) 329 return key_types; 330 return NULL; 331 } 332 333 static int 334 load_slot(OSSL_LIB_CTX *libctx, const char *propq, const char *pname, 335 int selection, MLX_KEY *key, int slot, const uint8_t *in, 336 int mbytes, int xbytes) 337 { 338 EVP_PKEY_CTX *ctx; 339 EVP_PKEY **ppkey; 340 OSSL_PARAM parr[] = { OSSL_PARAM_END, OSSL_PARAM_END, OSSL_PARAM_END }; 341 const char *alg; 342 char *group = NULL; 343 size_t off, len; 344 void *val; 345 int ml_kem_slot = key->xinfo->ml_kem_slot; 346 int ret = 0; 347 348 if (slot == ml_kem_slot) { 349 alg = key->minfo->algorithm_name; 350 ppkey = &key->mkey; 351 off = slot * xbytes; 352 len = mbytes; 353 } else { 354 alg = key->xinfo->algorithm_name; 355 group = (char *) key->xinfo->group_name; 356 ppkey = &key->xkey; 357 off = (1 - ml_kem_slot) * mbytes; 358 len = xbytes; 359 } 360 val = (void *)(in + off); 361 362 if ((ctx = EVP_PKEY_CTX_new_from_name(libctx, alg, propq)) == NULL 363 || EVP_PKEY_fromdata_init(ctx) <= 0) 364 goto err; 365 parr[0] = OSSL_PARAM_construct_octet_string(pname, val, len); 366 if (group != NULL) 367 parr[1] = OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME, 368 group, 0); 369 if (EVP_PKEY_fromdata(ctx, ppkey, selection, parr) > 0) 370 ret = 1; 371 372 err: 373 EVP_PKEY_CTX_free(ctx); 374 return ret; 375 } 376 377 static int 378 load_keys(MLX_KEY *key, 379 const uint8_t *pubenc, size_t publen, 380 const uint8_t *prvenc, size_t prvlen) 381 { 382 int slot; 383 384 for (slot = 0; slot < 2; ++slot) { 385 if (prvlen) { 386 /* Ignore public keys when private provided */ 387 if (!load_slot(key->libctx, key->propq, OSSL_PKEY_PARAM_PRIV_KEY, 388 minimal_selection, key, slot, prvenc, 389 key->minfo->prvkey_bytes, key->xinfo->prvkey_bytes)) 390 goto err; 391 } else if (publen) { 392 /* Absent private key data, import public keys */ 393 if (!load_slot(key->libctx, key->propq, OSSL_PKEY_PARAM_PUB_KEY, 394 minimal_selection, key, slot, pubenc, 395 key->minfo->pubkey_bytes, key->xinfo->pubkey_bytes)) 396 goto err; 397 } 398 } 399 key->state = prvlen ? MLX_HAVE_PRVKEY : MLX_HAVE_PUBKEY; 400 return 1; 401 402 err: 403 EVP_PKEY_free(key->mkey); 404 EVP_PKEY_free(key->xkey); 405 key->xkey = key->mkey = NULL; 406 key->state = MLX_HAVE_NOKEYS; 407 return 0; 408 } 409 410 static int mlx_kem_key_fromdata(MLX_KEY *key, 411 const OSSL_PARAM params[], 412 int include_private) 413 { 414 const OSSL_PARAM *param_prv_key = NULL, *param_pub_key; 415 const void *pubenc = NULL, *prvenc = NULL; 416 size_t pubkey_bytes, prvkey_bytes; 417 size_t publen = 0, prvlen = 0; 418 419 /* Invalid attempt to mutate a key, what is the right error to report? */ 420 if (key == NULL || mlx_kem_have_pubkey(key)) 421 return 0; 422 pubkey_bytes = key->minfo->pubkey_bytes + key->xinfo->pubkey_bytes; 423 prvkey_bytes = key->minfo->prvkey_bytes + key->xinfo->prvkey_bytes; 424 425 /* What does the caller want to set? */ 426 param_pub_key = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_PUB_KEY); 427 if (param_pub_key != NULL && 428 OSSL_PARAM_get_octet_string_ptr(param_pub_key, &pubenc, &publen) != 1) 429 return 0; 430 if (include_private) 431 param_prv_key = OSSL_PARAM_locate_const(params, 432 OSSL_PKEY_PARAM_PRIV_KEY); 433 if (param_prv_key != NULL && 434 OSSL_PARAM_get_octet_string_ptr(param_prv_key, &prvenc, &prvlen) != 1) 435 return 0; 436 437 /* The caller MUST specify at least one of the public or private keys. */ 438 if (publen == 0 && prvlen == 0) { 439 ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_KEY); 440 return 0; 441 } 442 443 /* 444 * When a pubkey is provided, its length MUST be correct, if a private key 445 * is also provided, the public key will be otherwise ignored. We could 446 * look for a matching encoded block, but unclear this is useful. 447 */ 448 if (publen != 0 && publen != pubkey_bytes) { 449 ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH); 450 return 0; 451 } 452 if (prvlen != 0 && prvlen != prvkey_bytes) { 453 ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH); 454 return 0; 455 } 456 457 return load_keys(key, pubenc, publen, prvenc, prvlen); 458 } 459 460 static int mlx_kem_import(void *vkey, int selection, const OSSL_PARAM params[]) 461 { 462 MLX_KEY *key = vkey; 463 int include_private; 464 465 if (!ossl_prov_is_running() || key == NULL) 466 return 0; 467 468 if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) == 0) 469 return 0; 470 471 include_private = selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY ? 1 : 0; 472 return mlx_kem_key_fromdata(key, params, include_private); 473 } 474 475 static const OSSL_PARAM *mlx_kem_gettable_params(void *provctx) 476 { 477 static const OSSL_PARAM arr[] = { 478 OSSL_PARAM_int(OSSL_PKEY_PARAM_BITS, NULL), 479 OSSL_PARAM_int(OSSL_PKEY_PARAM_SECURITY_BITS, NULL), 480 OSSL_PARAM_int(OSSL_PKEY_PARAM_MAX_SIZE, NULL), 481 OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY, NULL, 0), 482 OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_PRIV_KEY, NULL, 0), 483 OSSL_PARAM_END 484 }; 485 486 return arr; 487 } 488 489 /* 490 * It is assumed the key is guaranteed non-NULL here, and is from this provider 491 */ 492 static int mlx_kem_get_params(void *vkey, OSSL_PARAM params[]) 493 { 494 MLX_KEY *key = vkey; 495 OSSL_PARAM *p, *pub, *prv = NULL; 496 EXPORT_CB_ARG sub_arg; 497 int selection; 498 size_t publen = key->minfo->pubkey_bytes + key->xinfo->pubkey_bytes; 499 size_t prvlen = key->minfo->prvkey_bytes + key->xinfo->prvkey_bytes; 500 501 /* The reported "bit" count is those of the ML-KEM key */ 502 p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_BITS); 503 if (p != NULL) 504 if (!OSSL_PARAM_set_int(p, key->minfo->bits)) 505 return 0; 506 507 /* The reported security bits are those of the ML-KEM key */ 508 p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_SECURITY_BITS); 509 if (p != NULL) 510 if (!OSSL_PARAM_set_int(p, key->minfo->secbits)) 511 return 0; 512 513 /* The ciphertext sizes are additive */ 514 p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_MAX_SIZE); 515 if (p != NULL) 516 if (!OSSL_PARAM_set_int(p, key->minfo->ctext_bytes + key->xinfo->pubkey_bytes)) 517 return 0; 518 519 if (!mlx_kem_have_pubkey(key)) 520 return 1; 521 522 memset(&sub_arg, 0, sizeof(sub_arg)); 523 pub = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY); 524 if (pub != NULL) { 525 if (pub->data_type != OSSL_PARAM_OCTET_STRING) 526 return 0; 527 pub->return_size = publen; 528 if (pub->data == NULL) { 529 pub = NULL; 530 } else if (pub->data_size < publen) { 531 ERR_raise_data(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL, 532 "public key output buffer too short: %lu < %lu", 533 (unsigned long) pub->data_size, 534 (unsigned long) publen); 535 return 0; 536 } else { 537 sub_arg.pubenc = pub->data; 538 } 539 } 540 if (mlx_kem_have_prvkey(key)) { 541 prv = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_PRIV_KEY); 542 if (prv != NULL) { 543 if (prv->data_type != OSSL_PARAM_OCTET_STRING) 544 return 0; 545 prv->return_size = prvlen; 546 if (prv->data == NULL) { 547 prv = NULL; 548 } else if (prv->data_size < prvlen) { 549 ERR_raise_data(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL, 550 "private key output buffer too short: %lu < %lu", 551 (unsigned long) prv->data_size, 552 (unsigned long) prvlen); 553 return 0; 554 } else { 555 sub_arg.prvenc = prv->data; 556 } 557 } 558 } 559 if (pub == NULL && prv == NULL) 560 return 1; 561 562 selection = prv == NULL ? 0 : OSSL_KEYMGMT_SELECT_PRIVATE_KEY; 563 selection |= pub == NULL ? 0 : OSSL_KEYMGMT_SELECT_PUBLIC_KEY; 564 if (key->xinfo->group_name != NULL) 565 selection |= OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS; 566 567 /* Extract sub-component key material */ 568 if (!export_sub(&sub_arg, selection, key)) 569 return 0; 570 571 if ((pub != NULL && sub_arg.pubcount != 2) 572 || (prv != NULL && sub_arg.prvcount != 2)) 573 return 0; 574 575 return 1; 576 } 577 578 static const OSSL_PARAM *mlx_kem_settable_params(void *provctx) 579 { 580 static const OSSL_PARAM arr[] = { 581 OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY, NULL, 0), 582 OSSL_PARAM_END 583 }; 584 585 return arr; 586 } 587 588 static int mlx_kem_set_params(void *vkey, const OSSL_PARAM params[]) 589 { 590 MLX_KEY *key = vkey; 591 const OSSL_PARAM *p; 592 const void *pubenc = NULL; 593 size_t publen = 0; 594 595 if (ossl_param_is_empty(params)) 596 return 1; 597 598 /* Only one settable parameter is supported */ 599 p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY); 600 if (p == NULL) 601 return 1; 602 603 /* Key mutation is reportedly generally not allowed */ 604 if (mlx_kem_have_pubkey(key)) { 605 ERR_raise_data(ERR_LIB_PROV, 606 PROV_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE, 607 "keys cannot be mutated"); 608 return 0; 609 } 610 /* An unlikely failure mode is the parameter having some unexpected type */ 611 if (!OSSL_PARAM_get_octet_string_ptr(p, &pubenc, &publen)) 612 return 0; 613 614 p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_PROPERTIES); 615 if (p != NULL) { 616 OPENSSL_free(key->propq); 617 key->propq = NULL; 618 if (!OSSL_PARAM_get_utf8_string(p, &key->propq, 0)) 619 return 0; 620 } 621 622 if (publen != key->minfo->pubkey_bytes + key->xinfo->pubkey_bytes) { 623 ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY); 624 return 0; 625 } 626 627 return load_keys(key, pubenc, publen, NULL, 0); 628 } 629 630 static int mlx_kem_gen_set_params(void *vgctx, const OSSL_PARAM params[]) 631 { 632 PROV_ML_KEM_GEN_CTX *gctx = vgctx; 633 const OSSL_PARAM *p; 634 635 if (gctx == NULL) 636 return 0; 637 if (ossl_param_is_empty(params)) 638 return 1; 639 640 p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_PROPERTIES); 641 if (p != NULL) { 642 if (p->data_type != OSSL_PARAM_UTF8_STRING) 643 return 0; 644 OPENSSL_free(gctx->propq); 645 if ((gctx->propq = OPENSSL_strdup(p->data)) == NULL) 646 return 0; 647 } 648 return 1; 649 } 650 651 static void *mlx_kem_gen_init(int evp_type, OSSL_LIB_CTX *libctx, 652 int selection, const OSSL_PARAM params[]) 653 { 654 PROV_ML_KEM_GEN_CTX *gctx = NULL; 655 656 /* 657 * We can only generate private keys, check that the selection is 658 * appropriate. 659 */ 660 if (!ossl_prov_is_running() 661 || (selection & minimal_selection) == 0 662 || (gctx = OPENSSL_zalloc(sizeof(*gctx))) == NULL) 663 return NULL; 664 665 gctx->evp_type = evp_type; 666 gctx->libctx = libctx; 667 gctx->selection = selection; 668 if (mlx_kem_gen_set_params(gctx, params)) 669 return gctx; 670 671 mlx_kem_gen_cleanup(gctx); 672 return NULL; 673 } 674 675 static const OSSL_PARAM *mlx_kem_gen_settable_params(ossl_unused void *vgctx, 676 ossl_unused void *provctx) 677 { 678 static OSSL_PARAM settable[] = { 679 OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_PROPERTIES, NULL, 0), 680 OSSL_PARAM_END 681 }; 682 683 return settable; 684 } 685 686 static void *mlx_kem_gen(void *vgctx, OSSL_CALLBACK *osslcb, void *cbarg) 687 { 688 PROV_ML_KEM_GEN_CTX *gctx = vgctx; 689 MLX_KEY *key; 690 char *propq; 691 692 if (gctx == NULL 693 || (gctx->selection & OSSL_KEYMGMT_SELECT_KEYPAIR) == 694 OSSL_KEYMGMT_SELECT_PUBLIC_KEY) 695 return NULL; 696 697 /* Lose ownership of propq */ 698 propq = gctx->propq; 699 gctx->propq = NULL; 700 if ((key = mlx_kem_key_new(gctx->evp_type, gctx->libctx, propq)) == NULL) 701 return NULL; 702 703 if ((gctx->selection & OSSL_KEYMGMT_SELECT_KEYPAIR) == 0) 704 return key; 705 706 /* For now, using the same "propq" for all components */ 707 key->mkey = EVP_PKEY_Q_keygen(key->libctx, key->propq, 708 key->minfo->algorithm_name); 709 key->xkey = EVP_PKEY_Q_keygen(key->libctx, key->propq, 710 key->xinfo->algorithm_name, 711 key->xinfo->group_name); 712 if (key->mkey != NULL && key->xkey != NULL) { 713 key->state = MLX_HAVE_PRVKEY; 714 return key; 715 } 716 717 mlx_kem_key_free(key); 718 return NULL; 719 } 720 721 static void mlx_kem_gen_cleanup(void *vgctx) 722 { 723 PROV_ML_KEM_GEN_CTX *gctx = vgctx; 724 725 if (gctx == NULL) 726 return; 727 OPENSSL_free(gctx->propq); 728 OPENSSL_free(gctx); 729 } 730 731 static void *mlx_kem_dup(const void *vkey, int selection) 732 { 733 const MLX_KEY *key = vkey; 734 MLX_KEY *ret; 735 736 if (!ossl_prov_is_running() 737 || (ret = OPENSSL_memdup(key, sizeof(*ret))) == NULL) 738 return NULL; 739 740 if (ret->propq != NULL 741 && (ret->propq = OPENSSL_strdup(ret->propq)) == NULL) { 742 OPENSSL_free(ret); 743 return NULL; 744 } 745 746 /* Absent key material, nothing left to do */ 747 if (ret->mkey == NULL) { 748 if (ret->xkey == NULL) 749 return ret; 750 /* Fail if the source key is an inconsistent state */ 751 OPENSSL_free(ret); 752 return NULL; 753 } 754 755 switch (selection & OSSL_KEYMGMT_SELECT_KEYPAIR) { 756 case 0: 757 ret->xkey = ret->mkey = NULL; 758 return ret; 759 case OSSL_KEYMGMT_SELECT_KEYPAIR: 760 ret->mkey = EVP_PKEY_dup(key->mkey); 761 ret->xkey = EVP_PKEY_dup(key->xkey); 762 if (ret->xkey != NULL && ret->mkey != NULL) 763 return ret; 764 break; 765 default: 766 ERR_raise_data(ERR_LIB_PROV, PROV_R_UNSUPPORTED_SELECTION, 767 "duplication of partial key material not supported"); 768 break; 769 } 770 771 mlx_kem_key_free(ret); 772 return NULL; 773 } 774 775 #define DECLARE_DISPATCH(name, variant) \ 776 static OSSL_FUNC_keymgmt_new_fn mlx_##name##_kem_new; \ 777 static void *mlx_##name##_kem_new(void *provctx) \ 778 { \ 779 OSSL_LIB_CTX *libctx; \ 780 \ 781 libctx = provctx == NULL ? NULL : PROV_LIBCTX_OF(provctx); \ 782 return mlx_kem_key_new(variant, libctx, NULL); \ 783 } \ 784 static OSSL_FUNC_keymgmt_gen_init_fn mlx_##name##_kem_gen_init; \ 785 static void *mlx_##name##_kem_gen_init(void *provctx, int selection, \ 786 const OSSL_PARAM params[]) \ 787 { \ 788 OSSL_LIB_CTX *libctx; \ 789 \ 790 libctx = provctx == NULL ? NULL : PROV_LIBCTX_OF(provctx); \ 791 return mlx_kem_gen_init(variant, libctx, selection, params); \ 792 } \ 793 const OSSL_DISPATCH ossl_mlx_##name##_kem_kmgmt_functions[] = { \ 794 { OSSL_FUNC_KEYMGMT_NEW, (OSSL_FUNC) mlx_##name##_kem_new }, \ 795 { OSSL_FUNC_KEYMGMT_FREE, (OSSL_FUNC) mlx_kem_key_free }, \ 796 { OSSL_FUNC_KEYMGMT_GET_PARAMS, (OSSL_FUNC) mlx_kem_get_params }, \ 797 { OSSL_FUNC_KEYMGMT_GETTABLE_PARAMS, (OSSL_FUNC) mlx_kem_gettable_params }, \ 798 { OSSL_FUNC_KEYMGMT_SET_PARAMS, (OSSL_FUNC) mlx_kem_set_params }, \ 799 { OSSL_FUNC_KEYMGMT_SETTABLE_PARAMS, (OSSL_FUNC) mlx_kem_settable_params }, \ 800 { OSSL_FUNC_KEYMGMT_HAS, (OSSL_FUNC) mlx_kem_has }, \ 801 { OSSL_FUNC_KEYMGMT_MATCH, (OSSL_FUNC) mlx_kem_match }, \ 802 { OSSL_FUNC_KEYMGMT_GEN_INIT, (OSSL_FUNC) mlx_##name##_kem_gen_init }, \ 803 { OSSL_FUNC_KEYMGMT_GEN_SET_PARAMS, (OSSL_FUNC) mlx_kem_gen_set_params }, \ 804 { OSSL_FUNC_KEYMGMT_GEN_SETTABLE_PARAMS, (OSSL_FUNC) mlx_kem_gen_settable_params }, \ 805 { OSSL_FUNC_KEYMGMT_GEN, (OSSL_FUNC) mlx_kem_gen }, \ 806 { OSSL_FUNC_KEYMGMT_GEN_CLEANUP, (OSSL_FUNC) mlx_kem_gen_cleanup }, \ 807 { OSSL_FUNC_KEYMGMT_DUP, (OSSL_FUNC) mlx_kem_dup }, \ 808 { OSSL_FUNC_KEYMGMT_IMPORT, (OSSL_FUNC) mlx_kem_import }, \ 809 { OSSL_FUNC_KEYMGMT_IMPORT_TYPES, (OSSL_FUNC) mlx_kem_imexport_types }, \ 810 { OSSL_FUNC_KEYMGMT_EXPORT, (OSSL_FUNC) mlx_kem_export }, \ 811 { OSSL_FUNC_KEYMGMT_EXPORT_TYPES, (OSSL_FUNC) mlx_kem_imexport_types }, \ 812 OSSL_DISPATCH_END \ 813 } 814 /* See |hybrid_vtable| above */ 815 DECLARE_DISPATCH(p256, 0); 816 DECLARE_DISPATCH(p384, 1); 817 #if !defined(OPENSSL_NO_ECX) 818 DECLARE_DISPATCH(x25519, 2); 819 DECLARE_DISPATCH(x448, 3); 820 #endif 821