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/params.h> 13 #include <openssl/err.h> 14 #include <openssl/proverr.h> 15 #include <openssl/provider.h> 16 #include <openssl/rand.h> 17 #include <openssl/self_test.h> 18 #include <openssl/param_build.h> 19 #include "crypto/ml_kem.h" 20 #include "internal/fips.h" 21 #include "internal/param_build_set.h" 22 #include "prov/implementations.h" 23 #include "prov/providercommon.h" 24 #include "prov/provider_ctx.h" 25 #include "prov/securitycheck.h" 26 #include "prov/ml_kem.h" 27 28 static OSSL_FUNC_keymgmt_new_fn ml_kem_512_new; 29 static OSSL_FUNC_keymgmt_new_fn ml_kem_768_new; 30 static OSSL_FUNC_keymgmt_new_fn ml_kem_1024_new; 31 static OSSL_FUNC_keymgmt_gen_fn ml_kem_gen; 32 static OSSL_FUNC_keymgmt_gen_init_fn ml_kem_512_gen_init; 33 static OSSL_FUNC_keymgmt_gen_init_fn ml_kem_768_gen_init; 34 static OSSL_FUNC_keymgmt_gen_init_fn ml_kem_1024_gen_init; 35 static OSSL_FUNC_keymgmt_gen_cleanup_fn ml_kem_gen_cleanup; 36 static OSSL_FUNC_keymgmt_gen_set_params_fn ml_kem_gen_set_params; 37 static OSSL_FUNC_keymgmt_gen_settable_params_fn ml_kem_gen_settable_params; 38 #ifndef FIPS_MODULE 39 static OSSL_FUNC_keymgmt_load_fn ml_kem_load; 40 #endif 41 static OSSL_FUNC_keymgmt_get_params_fn ml_kem_get_params; 42 static OSSL_FUNC_keymgmt_gettable_params_fn ml_kem_gettable_params; 43 static OSSL_FUNC_keymgmt_set_params_fn ml_kem_set_params; 44 static OSSL_FUNC_keymgmt_settable_params_fn ml_kem_settable_params; 45 static OSSL_FUNC_keymgmt_has_fn ml_kem_has; 46 static OSSL_FUNC_keymgmt_match_fn ml_kem_match; 47 static OSSL_FUNC_keymgmt_validate_fn ml_kem_validate; 48 static OSSL_FUNC_keymgmt_import_fn ml_kem_import; 49 static OSSL_FUNC_keymgmt_export_fn ml_kem_export; 50 static OSSL_FUNC_keymgmt_import_types_fn ml_kem_imexport_types; 51 static OSSL_FUNC_keymgmt_export_types_fn ml_kem_imexport_types; 52 static OSSL_FUNC_keymgmt_dup_fn ml_kem_dup; 53 54 static const int minimal_selection = OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS 55 | OSSL_KEYMGMT_SELECT_PRIVATE_KEY; 56 57 typedef struct ml_kem_gen_ctx_st { 58 PROV_CTX *provctx; 59 char *propq; 60 int selection; 61 int evp_type; 62 uint8_t seedbuf[ML_KEM_SEED_BYTES]; 63 uint8_t *seed; 64 } PROV_ML_KEM_GEN_CTX; 65 66 static int ml_kem_pairwise_test(const ML_KEM_KEY *key, int key_flags) 67 { 68 #ifdef FIPS_MODULE 69 OSSL_SELF_TEST *st = NULL; 70 OSSL_CALLBACK *cb = NULL; 71 void *cbarg = NULL; 72 #endif 73 unsigned char entropy[ML_KEM_RANDOM_BYTES]; 74 unsigned char secret[ML_KEM_SHARED_SECRET_BYTES]; 75 unsigned char out[ML_KEM_SHARED_SECRET_BYTES]; 76 unsigned char *ctext = NULL; 77 const ML_KEM_VINFO *v = ossl_ml_kem_key_vinfo(key); 78 int operation_result = 0; 79 int ret = 0; 80 81 /* Unless we have both a public and private key, we can't do the test */ 82 if (!ossl_ml_kem_have_prvkey(key) 83 || !ossl_ml_kem_have_pubkey(key) 84 || (key_flags & ML_KEM_KEY_PCT_TYPE) == 0) 85 return 1; 86 #ifdef FIPS_MODULE 87 /* During self test, it is a waste to do this test */ 88 if (ossl_fips_self_testing()) 89 return 1; 90 91 /* 92 * The functions `OSSL_SELF_TEST_*` will return directly if parameter `st` 93 * is NULL. 94 */ 95 OSSL_SELF_TEST_get_callback(key->libctx, &cb, &cbarg); 96 97 st = OSSL_SELF_TEST_new(cb, cbarg); 98 if (st == NULL) 99 return 0; 100 101 OSSL_SELF_TEST_onbegin(st, OSSL_SELF_TEST_TYPE_PCT, 102 OSSL_SELF_TEST_DESC_PCT_ML_KEM); 103 #endif /* FIPS_MODULE */ 104 105 ctext = OPENSSL_malloc(v->ctext_bytes); 106 if (ctext == NULL) 107 goto err; 108 109 memset(out, 0, sizeof(out)); 110 111 /* 112 * The pairwise test is skipped unless either RANDOM or FIXED entropy PCTs 113 * are enabled. 114 */ 115 if (key_flags & ML_KEM_KEY_RANDOM_PCT) { 116 operation_result = ossl_ml_kem_encap_rand(ctext, v->ctext_bytes, 117 secret, sizeof(secret), key); 118 } else { 119 memset(entropy, 0125, sizeof(entropy)); 120 operation_result = ossl_ml_kem_encap_seed(ctext, v->ctext_bytes, 121 secret, sizeof(secret), 122 entropy, sizeof(entropy), 123 key); 124 } 125 if (operation_result != 1) 126 goto err; 127 128 #ifdef FIPS_MODULE 129 OSSL_SELF_TEST_oncorrupt_byte(st, ctext); 130 #endif 131 132 operation_result = ossl_ml_kem_decap(out, sizeof(out), ctext, v->ctext_bytes, 133 key); 134 if (operation_result != 1 || memcmp(out, secret, sizeof(out)) != 0) 135 goto err; 136 137 ret = 1; 138 err: 139 #ifdef FIPS_MODULE 140 OSSL_SELF_TEST_onend(st, ret); 141 OSSL_SELF_TEST_free(st); 142 #else 143 if (ret == 0) { 144 ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_KEY, 145 "public part of %s private key fails to match private", 146 v->algorithm_name); 147 } 148 #endif 149 OPENSSL_free(ctext); 150 return ret; 151 } 152 153 ML_KEM_KEY *ossl_prov_ml_kem_new(PROV_CTX *ctx, const char *propq, int evp_type) 154 { 155 ML_KEM_KEY *key; 156 157 if (!ossl_prov_is_running()) 158 return NULL; 159 /* 160 * When decoding, if the key ends up "loaded" into the same provider, these 161 * are the correct config settings, otherwise, new values will be assigned 162 * on import into a different provider. The "load" API does not pass along 163 * the provider context. 164 */ 165 if ((key = ossl_ml_kem_key_new(PROV_LIBCTX_OF(ctx), propq, evp_type)) != NULL) { 166 const char *pct_type = ossl_prov_ctx_get_param( 167 ctx, OSSL_PKEY_PARAM_ML_KEM_IMPORT_PCT_TYPE, "random"); 168 169 if (ossl_prov_ctx_get_bool_param( 170 ctx, OSSL_PKEY_PARAM_ML_KEM_RETAIN_SEED, 1)) 171 key->prov_flags |= ML_KEM_KEY_RETAIN_SEED; 172 else 173 key->prov_flags &= ~ML_KEM_KEY_RETAIN_SEED; 174 if (ossl_prov_ctx_get_bool_param( 175 ctx, OSSL_PKEY_PARAM_ML_KEM_PREFER_SEED, 1)) 176 key->prov_flags |= ML_KEM_KEY_PREFER_SEED; 177 else 178 key->prov_flags &= ~ML_KEM_KEY_PREFER_SEED; 179 if (OPENSSL_strcasecmp(pct_type, "random") == 0) 180 key->prov_flags |= ML_KEM_KEY_RANDOM_PCT; 181 else if (OPENSSL_strcasecmp(pct_type, "fixed") == 0) 182 key->prov_flags |= ML_KEM_KEY_FIXED_PCT; 183 else 184 key->prov_flags &= ~ML_KEM_KEY_PCT_TYPE; 185 } 186 return key; 187 } 188 189 static int ml_kem_has(const void *vkey, int selection) 190 { 191 const ML_KEM_KEY *key = vkey; 192 193 /* A NULL key MUST fail to have anything */ 194 if (!ossl_prov_is_running() || key == NULL) 195 return 0; 196 197 switch (selection & OSSL_KEYMGMT_SELECT_KEYPAIR) { 198 case 0: 199 return 1; 200 case OSSL_KEYMGMT_SELECT_PUBLIC_KEY: 201 return ossl_ml_kem_have_pubkey(key); 202 default: 203 return ossl_ml_kem_have_prvkey(key); 204 } 205 } 206 207 static int ml_kem_match(const void *vkey1, const void *vkey2, int selection) 208 { 209 const ML_KEM_KEY *key1 = vkey1; 210 const ML_KEM_KEY *key2 = vkey2; 211 212 if (!ossl_prov_is_running()) 213 return 0; 214 215 /* All we have that can be compared is key material */ 216 if (!(selection & OSSL_KEYMGMT_SELECT_KEYPAIR)) 217 return 1; 218 219 return ossl_ml_kem_pubkey_cmp(key1, key2); 220 } 221 222 static int ml_kem_validate(const void *vkey, int selection, int check_type) 223 { 224 const ML_KEM_KEY *key = vkey; 225 226 if (!ml_kem_has(key, selection)) 227 return 0; 228 229 if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) == OSSL_KEYMGMT_SELECT_KEYPAIR) 230 return ml_kem_pairwise_test(key, ML_KEM_KEY_RANDOM_PCT); 231 return 1; 232 } 233 234 static int ml_kem_export(void *vkey, int selection, OSSL_CALLBACK *param_cb, 235 void *cbarg) 236 { 237 ML_KEM_KEY *key = vkey; 238 OSSL_PARAM_BLD *tmpl = NULL; 239 OSSL_PARAM *params = NULL; 240 const ML_KEM_VINFO *v; 241 uint8_t *pubenc = NULL, *prvenc = NULL, *seedenc = NULL; 242 size_t prvlen = 0, seedlen = 0; 243 int ret = 0; 244 245 if (!ossl_prov_is_running() || key == NULL) 246 return 0; 247 248 if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) == 0) 249 return 0; 250 251 v = ossl_ml_kem_key_vinfo(key); 252 if (!ossl_ml_kem_have_pubkey(key)) { 253 /* Fail when no key material can be returned */ 254 if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) == 0 255 || !ossl_ml_kem_decoded_key(key)) { 256 ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_KEY); 257 return 0; 258 } 259 } else if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0) { 260 pubenc = OPENSSL_malloc(v->pubkey_bytes); 261 if (pubenc == NULL 262 || !ossl_ml_kem_encode_public_key(pubenc, v->pubkey_bytes, key)) 263 goto err; 264 } 265 266 if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0) { 267 /* 268 * The seed and/or private key material are allocated on the secure 269 * heap if configured, ossl_param_build_set_octet_string(), will then 270 * also use the secure heap. 271 */ 272 if (ossl_ml_kem_have_seed(key)) { 273 seedlen = ML_KEM_SEED_BYTES; 274 if ((seedenc = OPENSSL_secure_zalloc(seedlen)) == NULL 275 || !ossl_ml_kem_encode_seed(seedenc, seedlen, key)) 276 goto err; 277 } 278 if (ossl_ml_kem_have_prvkey(key)) { 279 prvlen = v->prvkey_bytes; 280 if ((prvenc = OPENSSL_secure_zalloc(prvlen)) == NULL 281 || !ossl_ml_kem_encode_private_key(prvenc, prvlen, key)) 282 goto err; 283 } else if (ossl_ml_kem_have_dkenc(key)) { 284 prvlen = v->prvkey_bytes; 285 if ((prvenc = OPENSSL_secure_zalloc(prvlen)) == NULL) 286 goto err; 287 memcpy(prvenc, key->encoded_dk, prvlen); 288 } 289 } 290 291 tmpl = OSSL_PARAM_BLD_new(); 292 if (tmpl == NULL) 293 goto err; 294 295 /* The (d, z) seed, when available and private keys are requested. */ 296 if (seedenc != NULL 297 && !ossl_param_build_set_octet_string( 298 tmpl, params, OSSL_PKEY_PARAM_ML_KEM_SEED, seedenc, seedlen)) 299 goto err; 300 301 /* The private key in the FIPS 203 |dk| format, when requested. */ 302 if (prvenc != NULL 303 && !ossl_param_build_set_octet_string( 304 tmpl, params, OSSL_PKEY_PARAM_PRIV_KEY, prvenc, prvlen)) 305 goto err; 306 307 /* The public key on request; it is always available when either is */ 308 if (pubenc != NULL 309 && !ossl_param_build_set_octet_string( 310 tmpl, params, OSSL_PKEY_PARAM_PUB_KEY, pubenc, v->pubkey_bytes)) 311 goto err; 312 313 params = OSSL_PARAM_BLD_to_param(tmpl); 314 if (params == NULL) 315 goto err; 316 317 ret = param_cb(params, cbarg); 318 OSSL_PARAM_free(params); 319 320 err: 321 OSSL_PARAM_BLD_free(tmpl); 322 OPENSSL_secure_clear_free(seedenc, seedlen); 323 OPENSSL_secure_clear_free(prvenc, prvlen); 324 OPENSSL_free(pubenc); 325 return ret; 326 } 327 328 static const OSSL_PARAM *ml_kem_imexport_types(int selection) 329 { 330 static const OSSL_PARAM key_types[] = { 331 OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_ML_KEM_SEED, NULL, 0), 332 OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_PRIV_KEY, NULL, 0), 333 OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_PUB_KEY, NULL, 0), 334 OSSL_PARAM_END 335 }; 336 337 if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) != 0) 338 return key_types; 339 return NULL; 340 } 341 342 static int check_seed(const uint8_t *seed, const uint8_t *prvenc, 343 ML_KEM_KEY *key) 344 { 345 size_t zlen = ML_KEM_RANDOM_BYTES; 346 347 if (memcmp(seed + ML_KEM_SEED_BYTES - zlen, 348 prvenc + key->vinfo->prvkey_bytes - zlen, zlen) == 0) 349 return 1; 350 ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_KEY, 351 "private %s key implicit rejection secret does" 352 " not match seed", key->vinfo->algorithm_name); 353 return 0; 354 } 355 356 static int check_prvenc(const uint8_t *prvenc, ML_KEM_KEY *key) 357 { 358 size_t len = key->vinfo->prvkey_bytes; 359 uint8_t *buf = OPENSSL_malloc(len); 360 int ret = 0; 361 362 if (buf != NULL 363 && ossl_ml_kem_encode_private_key(buf, len, key)) 364 ret = memcmp(buf, prvenc, len) == 0; 365 OPENSSL_clear_free(buf, len); 366 if (ret) 367 return 1; 368 369 if (buf != NULL) 370 ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_KEY, 371 "explicit %s private key does not match seed", 372 key->vinfo->algorithm_name); 373 ossl_ml_kem_key_reset(key); 374 return 0; 375 } 376 377 static int ml_kem_key_fromdata(ML_KEM_KEY *key, 378 const OSSL_PARAM params[], 379 int include_private) 380 { 381 const OSSL_PARAM *p = NULL; 382 const void *pubenc = NULL, *prvenc = NULL, *seedenc = NULL; 383 size_t publen = 0, prvlen = 0, seedlen = 0, puboff; 384 const ML_KEM_VINFO *v; 385 386 /* Invalid attempt to mutate a key, what is the right error to report? */ 387 if (key == NULL || ossl_ml_kem_have_pubkey(key)) 388 return 0; 389 v = ossl_ml_kem_key_vinfo(key); 390 391 /* 392 * When a private key is provided, without a seed, any public key also 393 * provided will be ignored (apart from length), just as with the seed. 394 */ 395 if (include_private) { 396 /* 397 * When a seed is provided, the private and public keys may be ignored, 398 * after validating just their lengths. Comparing encodings or hashes 399 * when applicable is possible, but not currently implemented. 400 */ 401 p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_ML_KEM_SEED); 402 if (p != NULL 403 && OSSL_PARAM_get_octet_string_ptr(p, &seedenc, &seedlen) != 1) 404 return 0; 405 if (seedlen != 0 && seedlen != ML_KEM_SEED_BYTES) { 406 ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_SEED_LENGTH); 407 return 0; 408 } 409 p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_PRIV_KEY); 410 if (p != NULL 411 && OSSL_PARAM_get_octet_string_ptr(p, &prvenc, &prvlen) != 1) 412 return 0; 413 if (prvlen != 0 && prvlen != v->prvkey_bytes) { 414 ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH); 415 return 0; 416 } 417 } 418 419 /* Used only when no seed or private key is provided. */ 420 p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_PUB_KEY); 421 if (p != NULL 422 && OSSL_PARAM_get_octet_string_ptr(p, &pubenc, &publen) != 1) 423 return 0; 424 if (publen != 0 && publen != v->pubkey_bytes) { 425 ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH); 426 return 0; 427 } 428 429 /* The caller MUST specify at least one of seed, private or public keys. */ 430 if (seedlen == 0 && publen == 0 && prvlen == 0) { 431 ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_KEY); 432 return 0; 433 } 434 435 /* Check any explicit public key against embedded value in private key */ 436 if (publen > 0 && prvlen > 0) { 437 /* point to the ek offset in dk = DKpke||ek||H(ek)||z */ 438 puboff = prvlen - ML_KEM_RANDOM_BYTES - ML_KEM_PKHASH_BYTES - publen; 439 if (memcmp(pubenc, (unsigned char *)prvenc + puboff, publen) != 0) { 440 ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_KEY, 441 "explicit %s public key does not match private", 442 v->algorithm_name); 443 return 0; 444 } 445 } 446 447 if (seedlen != 0 448 && (prvlen == 0 || (key->prov_flags & ML_KEM_KEY_PREFER_SEED))) { 449 if (prvlen != 0 && !check_seed(seedenc, prvenc, key)) 450 return 0; 451 if (!ossl_ml_kem_set_seed(seedenc, seedlen, key) 452 || !ossl_ml_kem_genkey(NULL, 0, key)) 453 return 0; 454 return prvlen == 0 || check_prvenc(prvenc, key); 455 } else if (prvlen != 0) { 456 return ossl_ml_kem_parse_private_key(prvenc, prvlen, key); 457 } 458 return ossl_ml_kem_parse_public_key(pubenc, publen, key); 459 } 460 461 static int ml_kem_import(void *vkey, int selection, const OSSL_PARAM params[]) 462 { 463 ML_KEM_KEY *key = vkey; 464 int include_private; 465 int res; 466 467 if (!ossl_prov_is_running() || key == NULL) 468 return 0; 469 470 if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) == 0) 471 return 0; 472 473 include_private = selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY ? 1 : 0; 474 res = ml_kem_key_fromdata(key, params, include_private); 475 if (res > 0 && include_private 476 && !ml_kem_pairwise_test(key, key->prov_flags)) { 477 #ifdef FIPS_MODULE 478 ossl_set_error_state(OSSL_SELF_TEST_TYPE_PCT); 479 #endif 480 ossl_ml_kem_key_reset(key); 481 res = 0; 482 } 483 return res; 484 } 485 486 static const OSSL_PARAM *ml_kem_gettable_params(void *provctx) 487 { 488 static const OSSL_PARAM arr[] = { 489 OSSL_PARAM_int(OSSL_PKEY_PARAM_BITS, NULL), 490 OSSL_PARAM_int(OSSL_PKEY_PARAM_SECURITY_BITS, NULL), 491 OSSL_PARAM_int(OSSL_PKEY_PARAM_MAX_SIZE, NULL), 492 /* Exported for import */ 493 OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_ML_KEM_SEED, NULL, 0), 494 /* Exported to EVP_PKEY_get_raw_private_key() */ 495 OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_PRIV_KEY, NULL, 0), 496 /* Exported to EVP_PKEY_get_raw_public_key() */ 497 OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_PUB_KEY, NULL, 0), 498 /* Needed by EVP_PKEY_get1_encoded_public_key() */ 499 OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY, NULL, 0), 500 OSSL_PARAM_END 501 }; 502 503 return arr; 504 } 505 506 #ifndef FIPS_MODULE 507 void *ml_kem_load(const void *reference, size_t reference_sz) 508 { 509 ML_KEM_KEY *key = NULL; 510 uint8_t *encoded_dk = NULL; 511 uint8_t seed[ML_KEM_SEED_BYTES]; 512 513 if (ossl_prov_is_running() && reference_sz == sizeof(key)) { 514 /* The contents of the reference is the address to our object */ 515 key = *(ML_KEM_KEY **)reference; 516 encoded_dk = key->encoded_dk; 517 key->encoded_dk = NULL; 518 /* We grabbed, so we detach it */ 519 *(ML_KEM_KEY **)reference = NULL; 520 if (encoded_dk != NULL 521 && ossl_ml_kem_encode_seed(seed, sizeof(seed), key) 522 && !check_seed(seed, encoded_dk, key)) 523 goto err; 524 /* Generate the key now, if it holds only a stashed seed. */ 525 if (ossl_ml_kem_have_seed(key) 526 && (encoded_dk == NULL 527 || (key->prov_flags & ML_KEM_KEY_PREFER_SEED))) { 528 if (!ossl_ml_kem_genkey(NULL, 0, key) 529 || (encoded_dk != NULL && !check_prvenc(encoded_dk, key))) 530 goto err; 531 } else if (encoded_dk != NULL) { 532 if (!ossl_ml_kem_parse_private_key(encoded_dk, 533 key->vinfo->prvkey_bytes, key)) { 534 ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_KEY, 535 "error parsing %s private key", 536 key->vinfo->algorithm_name); 537 goto err; 538 } 539 if (!ml_kem_pairwise_test(key, key->prov_flags)) 540 goto err; 541 } 542 OPENSSL_free(encoded_dk); 543 return key; 544 } 545 546 err: 547 OPENSSL_free(encoded_dk); 548 ossl_ml_kem_key_free(key); 549 return NULL; 550 } 551 #endif 552 553 /* 554 * It is assumed the key is guaranteed non-NULL here, and is from this provider 555 */ 556 static int ml_kem_get_params(void *vkey, OSSL_PARAM params[]) 557 { 558 ML_KEM_KEY *key = vkey; 559 const ML_KEM_VINFO *v = ossl_ml_kem_key_vinfo(key); 560 OSSL_PARAM *p; 561 const char *pubparams[] = { 562 OSSL_PKEY_PARAM_PUB_KEY, 563 OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY 564 }; 565 int i; 566 567 p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_BITS); 568 if (p != NULL) 569 if (!OSSL_PARAM_set_int(p, v->bits)) 570 return 0; 571 572 p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_SECURITY_BITS); 573 if (p != NULL) 574 if (!OSSL_PARAM_set_int(p, v->secbits)) 575 return 0; 576 577 p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_MAX_SIZE); 578 if (p != NULL) 579 if (!OSSL_PARAM_set_int(p, v->ctext_bytes)) 580 return 0; 581 582 if (ossl_ml_kem_have_pubkey(key)) { 583 uint8_t *pubenc = NULL; 584 585 for (i = 0; i < 2; ++i) { 586 p = OSSL_PARAM_locate(params, pubparams[i]); 587 if (p == NULL) 588 continue; 589 if (p->data_type != OSSL_PARAM_OCTET_STRING) 590 return 0; 591 p->return_size = v->pubkey_bytes; 592 if (p->data == NULL) 593 continue; 594 if (p->data_size < p->return_size) 595 return 0; 596 if (pubenc != NULL) { 597 memcpy(p->data, pubenc, p->return_size); 598 continue; 599 } 600 if (!ossl_ml_kem_encode_public_key(p->data, p->return_size, key)) 601 return 0; 602 pubenc = p->data; 603 } 604 } 605 606 p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_PRIV_KEY); 607 if (p != NULL && ossl_ml_kem_have_prvkey(key)) { 608 if (p->data_type != OSSL_PARAM_OCTET_STRING) 609 return 0; 610 p->return_size = v->prvkey_bytes; 611 if (p->data != NULL) { 612 if (p->data_size < p->return_size) 613 return 0; 614 if (!ossl_ml_kem_encode_private_key(p->data, p->return_size, key)) 615 return 0; 616 } 617 } 618 619 p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_ML_KEM_SEED); 620 if (p != NULL && ossl_ml_kem_have_seed(key)) { 621 if (p->data_type != OSSL_PARAM_OCTET_STRING) 622 return 0; 623 p->return_size = ML_KEM_SEED_BYTES; 624 if (p->data != NULL) { 625 if (p->data_size < p->return_size) 626 return 0; 627 if (!ossl_ml_kem_encode_seed(p->data, p->return_size, key)) 628 return 0; 629 } 630 } 631 632 return 1; 633 } 634 635 static const OSSL_PARAM *ml_kem_settable_params(void *provctx) 636 { 637 static const OSSL_PARAM arr[] = { 638 /* Used in TLS via EVP_PKEY_set1_encoded_public_key(). */ 639 OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY, NULL, 0), 640 OSSL_PARAM_END 641 }; 642 643 return arr; 644 } 645 646 static int ml_kem_set_params(void *vkey, const OSSL_PARAM params[]) 647 { 648 ML_KEM_KEY *key = vkey; 649 const OSSL_PARAM *p; 650 const void *pubenc = NULL; 651 size_t publen = 0; 652 653 if (ossl_param_is_empty(params)) 654 return 1; 655 656 p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY); 657 if (p != NULL 658 && (OSSL_PARAM_get_octet_string_ptr(p, &pubenc, &publen) != 1 659 || publen != key->vinfo->pubkey_bytes)) { 660 ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY); 661 return 0; 662 } 663 664 if (publen == 0) 665 return 1; 666 667 /* Key mutation is reportedly generally not allowed */ 668 if (ossl_ml_kem_have_pubkey(key)) { 669 ERR_raise_data(ERR_LIB_PROV, 670 PROV_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE, 671 "ML-KEM keys cannot be mutated"); 672 return 0; 673 } 674 675 return ossl_ml_kem_parse_public_key(pubenc, publen, key); 676 } 677 678 static int ml_kem_gen_set_params(void *vgctx, const OSSL_PARAM params[]) 679 { 680 PROV_ML_KEM_GEN_CTX *gctx = vgctx; 681 const OSSL_PARAM *p; 682 683 if (gctx == NULL) 684 return 0; 685 if (ossl_param_is_empty(params)) 686 return 1; 687 688 p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_PROPERTIES); 689 if (p != NULL) { 690 if (p->data_type != OSSL_PARAM_UTF8_STRING) 691 return 0; 692 OPENSSL_free(gctx->propq); 693 if ((gctx->propq = OPENSSL_strdup(p->data)) == NULL) 694 return 0; 695 } 696 697 p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_ML_KEM_SEED); 698 if (p != NULL) { 699 size_t len = ML_KEM_SEED_BYTES; 700 701 gctx->seed = gctx->seedbuf; 702 if (OSSL_PARAM_get_octet_string(p, (void **)&gctx->seed, len, &len) 703 && len == ML_KEM_SEED_BYTES) 704 return 1; 705 706 /* Possibly, but less likely wrong data type */ 707 ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_SEED_LENGTH); 708 gctx->seed = NULL; 709 return 0; 710 } 711 712 return 1; 713 } 714 715 static void *ml_kem_gen_init(void *provctx, int selection, 716 const OSSL_PARAM params[], int evp_type) 717 { 718 PROV_ML_KEM_GEN_CTX *gctx = NULL; 719 720 /* 721 * We can only generate private keys, check that the selection is 722 * appropriate. 723 */ 724 if (!ossl_prov_is_running() 725 || (selection & minimal_selection) == 0 726 || (gctx = OPENSSL_zalloc(sizeof(*gctx))) == NULL) 727 return NULL; 728 729 gctx->selection = selection; 730 gctx->evp_type = evp_type; 731 gctx->provctx = provctx; 732 if (ml_kem_gen_set_params(gctx, params)) 733 return gctx; 734 735 ml_kem_gen_cleanup(gctx); 736 return NULL; 737 } 738 739 static const OSSL_PARAM *ml_kem_gen_settable_params(ossl_unused void *vgctx, 740 ossl_unused void *provctx) 741 { 742 static OSSL_PARAM settable[] = { 743 OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_ML_KEM_SEED, NULL, 0), 744 OSSL_PARAM_END 745 }; 746 return settable; 747 } 748 749 static void *ml_kem_gen(void *vgctx, OSSL_CALLBACK *osslcb, void *cbarg) 750 { 751 PROV_ML_KEM_GEN_CTX *gctx = vgctx; 752 ML_KEM_KEY *key; 753 uint8_t *nopub = NULL; 754 uint8_t *seed; 755 int genok = 0; 756 757 if (gctx == NULL 758 || (gctx->selection & OSSL_KEYMGMT_SELECT_KEYPAIR) == 759 OSSL_KEYMGMT_SELECT_PUBLIC_KEY) 760 return NULL; 761 seed = gctx->seed; 762 key = ossl_prov_ml_kem_new(gctx->provctx, gctx->propq, gctx->evp_type); 763 if (key == NULL) 764 return NULL; 765 766 if ((gctx->selection & OSSL_KEYMGMT_SELECT_KEYPAIR) == 0) 767 return key; 768 769 if (seed != NULL && !ossl_ml_kem_set_seed(seed, ML_KEM_SEED_BYTES, key)) 770 return NULL; 771 genok = ossl_ml_kem_genkey(nopub, 0, key); 772 773 /* Erase the single-use seed */ 774 if (seed != NULL) 775 OPENSSL_cleanse(seed, ML_KEM_SEED_BYTES); 776 gctx->seed = NULL; 777 778 if (genok) { 779 #ifdef FIPS_MODULE 780 if (!ml_kem_pairwise_test(key, ML_KEM_KEY_FIXED_PCT)) { 781 ossl_set_error_state(OSSL_SELF_TEST_TYPE_PCT); 782 ossl_ml_kem_key_free(key); 783 return NULL; 784 } 785 #endif /* FIPS_MODULE */ 786 return key; 787 } 788 789 ossl_ml_kem_key_free(key); 790 return NULL; 791 } 792 793 static void ml_kem_gen_cleanup(void *vgctx) 794 { 795 PROV_ML_KEM_GEN_CTX *gctx = vgctx; 796 797 if (gctx == NULL) 798 return; 799 800 if (gctx->seed != NULL) 801 OPENSSL_cleanse(gctx->seed, ML_KEM_RANDOM_BYTES); 802 OPENSSL_free(gctx->propq); 803 OPENSSL_free(gctx); 804 } 805 806 static void *ml_kem_dup(const void *vkey, int selection) 807 { 808 const ML_KEM_KEY *key = vkey; 809 810 if (!ossl_prov_is_running()) 811 return NULL; 812 813 return ossl_ml_kem_key_dup(key, selection); 814 } 815 816 #ifndef FIPS_MODULE 817 # define DISPATCH_LOAD_FN \ 818 { OSSL_FUNC_KEYMGMT_LOAD, (OSSL_FUNC) ml_kem_load }, 819 #else 820 # define DISPATCH_LOAD_FN /* Non-FIPS only */ 821 #endif 822 823 #define DECLARE_VARIANT(bits) \ 824 static void *ml_kem_##bits##_new(void *provctx) \ 825 { \ 826 return ossl_prov_ml_kem_new(provctx, NULL, EVP_PKEY_ML_KEM_##bits); \ 827 } \ 828 static void *ml_kem_##bits##_gen_init(void *provctx, int selection, \ 829 const OSSL_PARAM params[]) \ 830 { \ 831 return ml_kem_gen_init(provctx, selection, params, \ 832 EVP_PKEY_ML_KEM_##bits); \ 833 } \ 834 const OSSL_DISPATCH ossl_ml_kem_##bits##_keymgmt_functions[] = { \ 835 { OSSL_FUNC_KEYMGMT_NEW, (OSSL_FUNC) ml_kem_##bits##_new }, \ 836 { OSSL_FUNC_KEYMGMT_FREE, (OSSL_FUNC) ossl_ml_kem_key_free }, \ 837 { OSSL_FUNC_KEYMGMT_GET_PARAMS, (OSSL_FUNC) ml_kem_get_params }, \ 838 { OSSL_FUNC_KEYMGMT_GETTABLE_PARAMS, (OSSL_FUNC) ml_kem_gettable_params }, \ 839 { OSSL_FUNC_KEYMGMT_SET_PARAMS, (OSSL_FUNC) ml_kem_set_params }, \ 840 { OSSL_FUNC_KEYMGMT_SETTABLE_PARAMS, (OSSL_FUNC) ml_kem_settable_params }, \ 841 { OSSL_FUNC_KEYMGMT_HAS, (OSSL_FUNC) ml_kem_has }, \ 842 { OSSL_FUNC_KEYMGMT_MATCH, (OSSL_FUNC) ml_kem_match }, \ 843 { OSSL_FUNC_KEYMGMT_VALIDATE, (OSSL_FUNC) ml_kem_validate }, \ 844 { OSSL_FUNC_KEYMGMT_GEN_INIT, (OSSL_FUNC) ml_kem_##bits##_gen_init }, \ 845 { OSSL_FUNC_KEYMGMT_GEN_SET_PARAMS, (OSSL_FUNC) ml_kem_gen_set_params }, \ 846 { OSSL_FUNC_KEYMGMT_GEN_SETTABLE_PARAMS, (OSSL_FUNC) ml_kem_gen_settable_params }, \ 847 { OSSL_FUNC_KEYMGMT_GEN, (OSSL_FUNC) ml_kem_gen }, \ 848 { OSSL_FUNC_KEYMGMT_GEN_CLEANUP, (OSSL_FUNC) ml_kem_gen_cleanup }, \ 849 DISPATCH_LOAD_FN \ 850 { OSSL_FUNC_KEYMGMT_DUP, (OSSL_FUNC) ml_kem_dup }, \ 851 { OSSL_FUNC_KEYMGMT_IMPORT, (OSSL_FUNC) ml_kem_import }, \ 852 { OSSL_FUNC_KEYMGMT_IMPORT_TYPES, (OSSL_FUNC) ml_kem_imexport_types }, \ 853 { OSSL_FUNC_KEYMGMT_EXPORT, (OSSL_FUNC) ml_kem_export }, \ 854 { OSSL_FUNC_KEYMGMT_EXPORT_TYPES, (OSSL_FUNC) ml_kem_imexport_types }, \ 855 OSSL_DISPATCH_END \ 856 } 857 DECLARE_VARIANT(512); 858 DECLARE_VARIANT(768); 859 DECLARE_VARIANT(1024); 860