/*
+ * Copyright (C) 2025 Tobias Brunner
* Copyright (C) 2024 Gerardo Ravago
*
* Copyright (C) secunet Security Networks AG
#include <openssl/evp.h>
+#if (OPENSSL_VERSION_NUMBER >= 0x30500000L && !defined(OPENSSL_NO_ML_KEM)) || \
+ defined(OPENSSL_IS_AWSLC)
+
#ifdef OPENSSL_IS_AWSLC
#include <openssl/experimental/kem_deterministic_api.h>
+#define NID_ML_KEM_512 NID_MLKEM512
+#define NID_ML_KEM_768 NID_MLKEM768
+#define NID_ML_KEM_1024 NID_MLKEM1024
+#else
+#include <openssl/core_names.h>
+#endif
+
+/**
+ * Length of seeds (d, z and m).
+ */
+#define ML_KEM_SEED_LEN 32
+
typedef struct private_key_exchange_t private_key_exchange_t;
/**
switch (this->group)
{
case ML_KEM_512:
- return NID_MLKEM512;
+ return NID_ML_KEM_512;
case ML_KEM_768:
- return NID_MLKEM768;
+ return NID_ML_KEM_768;
case ML_KEM_1024:
- return NID_MLKEM1024;
+ return NID_ML_KEM_1024;
default:
return NID_undef;
}
*/
static bool openssl_kem_generate_pkey(private_key_exchange_t *this)
{
- EVP_PKEY_CTX *ctx = NULL;
- size_t seed_length = 0;
+ EVP_PKEY_CTX *ctx;
chunk_t seed = chunk_empty;
+#ifdef OPENSSL_IS_AWSLC
ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_KEM, NULL);
if (!ctx)
{
EVP_PKEY_CTX_free(ctx);
return FALSE;
}
+#else /* OPENSSL_IS_AWSLC */
+ ctx = EVP_PKEY_CTX_new_id(openssl_kem_get_nid(this), NULL);
+ if (!ctx)
+ {
+ return FALSE;
+ }
+#endif /* OPENSSL_IS_AWSLC */
if (!EVP_PKEY_keygen_init(ctx))
{
EVP_PKEY_CTX_free(ctx);
}
if (this->drbg)
{
- if (!EVP_PKEY_keygen_deterministic(ctx, NULL, NULL, &seed_length))
+ seed = chunk_alloc(2*ML_KEM_SEED_LEN);
+ if (!this->drbg->generate(this->drbg, seed.len, seed.ptr))
{
EVP_PKEY_CTX_free(ctx);
return FALSE;
}
- seed = chunk_alloc(seed_length);
- if (!this->drbg->generate(this->drbg, seed.len, seed.ptr))
+#ifdef OPENSSL_IS_AWSLC
+ if (!EVP_PKEY_keygen_deterministic(ctx, &this->pkey, seed.ptr,
+ &seed.len))
{
EVP_PKEY_CTX_free(ctx);
+ chunk_clear(&seed);
return FALSE;
}
- if (!EVP_PKEY_keygen_deterministic(ctx, &this->pkey, seed.ptr,
- &seed.len))
+#else /* OPENSSL_IS_AWSLC */
+ OSSL_PARAM params[] = {
+ OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_ML_KEM_SEED,
+ seed.ptr, seed.len),
+ OSSL_PARAM_END,
+ };
+ if (!EVP_PKEY_CTX_set_params(ctx, params) ||
+ EVP_PKEY_keygen(ctx, &this->pkey) <= 0)
{
EVP_PKEY_CTX_free(ctx);
chunk_clear(&seed);
return FALSE;
}
+#endif /* OPENSSL_IS_AWSLC */
}
- else if (!EVP_PKEY_keygen(ctx, &this->pkey))
+ else if (EVP_PKEY_keygen(ctx, &this->pkey) <= 0)
{
EVP_PKEY_CTX_free(ctx);
return FALSE;
{
return FALSE;
}
- if (!EVP_PKEY_decapsulate(ctx, NULL, &shared_secret_length, ciphertext.ptr,
- ciphertext.len))
+#ifndef OPENSSL_IS_AWSLC
+ if (EVP_PKEY_decapsulate_init(ctx, NULL) <= 0)
+ {
+ EVP_PKEY_CTX_free(ctx);
+ return FALSE;
+ }
+#endif /* !OPENSSL_IS_AWSLC */
+ if (EVP_PKEY_decapsulate(ctx, NULL, &shared_secret_length, ciphertext.ptr,
+ ciphertext.len) <= 0)
{
EVP_PKEY_CTX_free(ctx);
return FALSE;
}
this->shared_secret = chunk_alloc(shared_secret_length);
- if (!EVP_PKEY_decapsulate(ctx, this->shared_secret.ptr,
- &this->shared_secret.len, ciphertext.ptr,
- ciphertext.len))
+ if (EVP_PKEY_decapsulate(ctx, this->shared_secret.ptr,
+ &this->shared_secret.len, ciphertext.ptr,
+ ciphertext.len) <= 0)
{
EVP_PKEY_CTX_free(ctx);
chunk_clear(&this->shared_secret);
EVP_PKEY *pkey;
size_t shared_secret_length = 0;
size_t ciphertext_length = 0;
- size_t seed_length = 0;
+ size_t seed_length = ML_KEM_SEED_LEN;
chunk_t seed = chunk_empty;
+#ifdef OPENSSL_IS_AWSLC
pkey = EVP_PKEY_kem_new_raw_public_key(openssl_kem_get_nid(this),
public_key.ptr, public_key.len);
+#else
+ pkey = EVP_PKEY_new_raw_public_key(openssl_kem_get_nid(this), NULL,
+ public_key.ptr, public_key.len);
+#endif
if (!pkey)
{
return FALSE;
EVP_PKEY_free(pkey);
return FALSE;
}
+#ifdef OPENSSL_IS_AWSLC
if (this->drbg)
{
if (!EVP_PKEY_encapsulate_deterministic(ctx, NULL, &ciphertext_length,
chunk_clear(&seed);
return FALSE;
}
+ chunk_clear(&seed);
}
else
+#endif /* OPENSSL_IS_AWSLC */
{
- if (!EVP_PKEY_encapsulate(ctx, NULL, &ciphertext_length, NULL,
- &shared_secret_length))
+#ifndef OPENSSL_IS_AWSLC
+ OSSL_PARAM params[] = {
+ OSSL_PARAM_END,
+ OSSL_PARAM_END,
+ };
+ if (this->drbg)
+ {
+ seed = chunk_alloc(seed_length);
+ if (!this->drbg->generate(this->drbg, seed.len, seed.ptr))
+ {
+ EVP_PKEY_free(pkey);
+ EVP_PKEY_CTX_free(ctx);
+ return FALSE;
+ }
+ params[0] = OSSL_PARAM_construct_octet_string(OSSL_KEM_PARAM_IKME,
+ seed.ptr, seed.len);
+ }
+ if (EVP_PKEY_encapsulate_init(ctx, params) <= 0)
+ {
+ EVP_PKEY_free(pkey);
+ EVP_PKEY_CTX_free(ctx);
+ chunk_clear(&seed);
+ return FALSE;
+ }
+ chunk_clear(&seed);
+#endif /* !OPENSSL_IS_AWSLC */
+ if (EVP_PKEY_encapsulate(ctx, NULL, &ciphertext_length, NULL,
+ &shared_secret_length) <= 0)
{
EVP_PKEY_free(pkey);
EVP_PKEY_CTX_free(ctx);
}
this->shared_secret = chunk_alloc(shared_secret_length);
this->ciphertext = chunk_alloc(ciphertext_length);
- if (!EVP_PKEY_encapsulate(ctx, this->ciphertext.ptr, &this->ciphertext.len,
- this->shared_secret.ptr,
- &this->shared_secret.len))
+ if (EVP_PKEY_encapsulate(ctx, this->ciphertext.ptr, &this->ciphertext.len,
+ this->shared_secret.ptr,
+ &this->shared_secret.len) <= 0)
{
EVP_PKEY_free(pkey);
EVP_PKEY_CTX_free(ctx);
}
EVP_PKEY_free(pkey);
EVP_PKEY_CTX_free(ctx);
- chunk_clear(&seed);
return TRUE;
}
#endif /* TESTABLE_KE */
-METHOD(key_exchange_t, destroy, void, private_key_exchange_t *this)
+METHOD(key_exchange_t, destroy, void,
+ private_key_exchange_t *this)
{
EVP_PKEY_free(this->pkey);
chunk_clear(&this->shared_secret);
return &this->public;
}
-#endif /* OPENSSL_IS_AWSLC */
+
+#endif /* OPENSSL_VERSION || OPENSSL_IS_AWSLC */