wolfssl: Unlock keys if necessary when using FIPS module

Wrap the functions that require it in PRIVATE_KEY_UNLOCK/PRIVATE_KEY_LOCK.
This can't be done at plugin initialization because it needs to be done
for every thread. strongSwan currently doesn't provide on-thread-create
callbacks for plugins so we need to wrap each direct call. Another reason
to do so is that some functions we call (e.g. wc_EccKeyToDer) internally
call PRIVATE_KEY_UNLOCK/PRIVATE_KEY_LOCK and would leave the keys locked
for that particular thread.
This commit is contained in:
Juliusz Sosinowicz
2025-06-02 09:15:05 +02:00
committed by Tobias Brunner
parent 85eb5c7812
commit f38bb91654
3 changed files with 38 additions and 16 deletions
@@ -90,12 +90,17 @@ METHOD(key_exchange_t, get_shared_secret, bool,
private_wolfssl_diffie_hellman_t *this, chunk_t *secret) private_wolfssl_diffie_hellman_t *this, chunk_t *secret)
{ {
word32 len; word32 len;
int ret;
if (!this->shared_secret.len) if (!this->shared_secret.len)
{ {
this->shared_secret = chunk_alloc(this->len); this->shared_secret = chunk_alloc(this->len);
if (wc_DhAgree(&this->dh, this->shared_secret.ptr, &len, this->priv.ptr, PRIVATE_KEY_UNLOCK();
this->priv.len, this->other.ptr, this->other.len) != 0) ret = wc_DhAgree(&this->dh, this->shared_secret.ptr, &len,
this->priv.ptr, this->priv.len, this->other.ptr,
this->other.len);
PRIVATE_KEY_LOCK();
if (ret != 0)
{ {
DBG1(DBG_LIB, "DH shared secret computation failed"); DBG1(DBG_LIB, "DH shared secret computation failed");
chunk_free(&this->shared_secret); chunk_free(&this->shared_secret);
@@ -132,6 +137,7 @@ METHOD(key_exchange_t, set_seed, bool,
bool success = FALSE; bool success = FALSE;
chunk_t g; chunk_t g;
word32 len; word32 len;
int ret;
chunk_clear(&this->priv); chunk_clear(&this->priv);
this->priv = chunk_clone(value); this->priv = chunk_clone(value);
@@ -140,8 +146,11 @@ METHOD(key_exchange_t, set_seed, bool,
if (wolfssl_mp2chunk(&this->dh.g, &g)) if (wolfssl_mp2chunk(&this->dh.g, &g))
{ {
len = this->pub.len; len = this->pub.len;
if (wc_DhAgree(&this->dh, this->pub.ptr, &len, this->priv.ptr, PRIVATE_KEY_UNLOCK();
this->priv.len, g.ptr, g.len) == 0) ret = wc_DhAgree(&this->dh, this->pub.ptr, &len, this->priv.ptr,
this->priv.len, g.ptr, g.len);
PRIVATE_KEY_LOCK();
if (ret == 0)
{ {
this->pub.len = len; this->pub.len = len;
success = TRUE; success = TRUE;
@@ -220,6 +229,7 @@ static wolfssl_diffie_hellman_t *create_generic(key_exchange_method_t group,
private_wolfssl_diffie_hellman_t *this; private_wolfssl_diffie_hellman_t *this;
word32 privLen, pubLen; word32 privLen, pubLen;
WC_RNG rng; WC_RNG rng;
int ret;
INIT(this, INIT(this,
.public = { .public = {
@@ -262,8 +272,11 @@ static wolfssl_diffie_hellman_t *create_generic(key_exchange_method_t group,
privLen = this->priv.len; privLen = this->priv.len;
pubLen = this->pub.len; pubLen = this->pub.len;
/* generate my public and private values */ /* generate my public and private values */
if (wc_DhGenerateKeyPair(&this->dh, &rng, this->priv.ptr, &privLen, PRIVATE_KEY_UNLOCK();
this->pub.ptr, &pubLen) != 0) ret = wc_DhGenerateKeyPair(&this->dh, &rng, this->priv.ptr, &privLen,
this->pub.ptr, &pubLen);
PRIVATE_KEY_LOCK();
if (ret != 0)
{ {
wc_FreeRng(&rng); wc_FreeRng(&rng);
destroy(this); destroy(this);
@@ -219,6 +219,7 @@ METHOD(key_exchange_t, set_seed, bool,
static bool compute_shared_key(private_wolfssl_ec_diffie_hellman_t *this) static bool compute_shared_key(private_wolfssl_ec_diffie_hellman_t *this)
{ {
word32 len; word32 len;
int ret;
#ifdef USE_RNG_FOR_TIMING_RESISTANCE #ifdef USE_RNG_FOR_TIMING_RESISTANCE
WC_RNG rng; WC_RNG rng;
@@ -237,8 +238,11 @@ static bool compute_shared_key(private_wolfssl_ec_diffie_hellman_t *this)
this->shared_secret = chunk_alloc(this->keysize); this->shared_secret = chunk_alloc(this->keysize);
len = this->shared_secret.len; len = this->shared_secret.len;
if (wc_ecc_shared_secret(&this->key, &this->pubkey, this->shared_secret.ptr, PRIVATE_KEY_UNLOCK();
&len) != 0) ret = wc_ecc_shared_secret(&this->key, &this->pubkey,
this->shared_secret.ptr, &len);
PRIVATE_KEY_LOCK();
if (ret != 0)
{ {
DBG1(DBG_LIB, "ECDH shared secret computation failed"); DBG1(DBG_LIB, "ECDH shared secret computation failed");
chunk_clear(&this->shared_secret); chunk_clear(&this->shared_secret);
@@ -82,22 +82,27 @@ METHOD(kdf_t, get_length, size_t,
METHOD(kdf_t, get_bytes, bool, METHOD(kdf_t, get_bytes, bool,
private_kdf_t *this, size_t out_len, uint8_t *buffer) private_kdf_t *this, size_t out_len, uint8_t *buffer)
{ {
int ret;
if (this->type == KDF_PRF) if (this->type == KDF_PRF)
{ {
if (out_len != get_length(this) || if (out_len != get_length(this))
wc_HKDF_Extract(this->hash, this->salt.ptr, this->salt.len,
this->key.ptr, this->key.len, buffer))
{ {
return FALSE; return FALSE;
} }
return TRUE; PRIVATE_KEY_UNLOCK();
ret = wc_HKDF_Extract(this->hash, this->salt.ptr, this->salt.len,
this->key.ptr, this->key.len, buffer);
PRIVATE_KEY_LOCK();
} }
if (wc_HKDF_Expand(this->hash, this->key.ptr, this->key.len, else
this->salt.ptr, this->salt.len, buffer, out_len))
{ {
return FALSE; PRIVATE_KEY_UNLOCK();
ret = wc_HKDF_Expand(this->hash, this->key.ptr, this->key.len,
this->salt.ptr, this->salt.len, buffer, out_len);
PRIVATE_KEY_LOCK();
} }
return TRUE; return ret == 0;
} }
METHOD(kdf_t, allocate_bytes, bool, METHOD(kdf_t, allocate_bytes, bool,