mirror of https://github.com/wolfSSL/wolfssl.git
Merge pull request #11204 from padelsbach/falcon-cb-free
Add CB_FREE mode for Falconpull/11090/head
commit
f8b140f511
|
|
@ -71,6 +71,15 @@
|
|||
"--enable-dilithium=yes,no-ctx", "--enable-dual-alg-certs",
|
||||
"--disable-qt",
|
||||
"CPPFLAGS=-pedantic -Wdeclaration-after-statement -Wnull-dereference -DWOLFCRYPT_TEST_LINT -DNO_WOLFSSL_CIPHER_SUITE_TEST -DTEST_LIBWOLFSSL_SOURCES_INCLUSION_SEQUENCE"]},
|
||||
{"name": "pq-cryptocbutils", "minutes": 3,
|
||||
"comment": "The only config pairing --enable-cryptocbutils with the PQC algorithms. --enable-all already turns cryptocb on, but the utility callbacks (copy, free, setkey, export) default to off, so without this entry WOLF_CRYPTO_CB_FREE is never compiled alongside a PQC algorithm and the free-callback tests for ML-DSA, SLH-DSA and ML-KEM all skip. Falcon and FrodoKEM are named explicitly: experimental only auto-enables them under --enable-all-quantum-crypto, which nothing here sets.",
|
||||
"configure": ["--enable-intelasm", "--enable-sp-asm",
|
||||
"--enable-all", "--enable-testcert", "--enable-experimental",
|
||||
"--enable-mlkem=yes,kyber,ml-kem", "--enable-slhdsa",
|
||||
"--enable-dilithium", "--enable-falcon", "--enable-frodokem",
|
||||
"--enable-cryptocb", "--enable-cryptocbutils",
|
||||
"--disable-qt",
|
||||
"CPPFLAGS=-pedantic -Wdeclaration-after-statement -Wnull-dereference -DWOLFCRYPT_TEST_LINT -DNO_WOLFSSL_CIPHER_SUITE_TEST -DTEST_LIBWOLFSSL_SOURCES_INCLUSION_SEQUENCE"]},
|
||||
{"name": "pq-asynccrypt-dual-alg", "minutes": 2.5,
|
||||
"comment": "Async crypto with dual-algorithm certs and PQC signatures. WOLFSSL_ASYNC_CRYPT turns off the streaming CertificateVerify path, so this is the only config that compiles the in-place fragmented send and the async args holder that Scv13Args must fit.",
|
||||
"configure": ["--enable-asynccrypt-sw", "--enable-dual-alg-certs",
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@
|
|||
#include <wolfssl/wolfcrypt/random.h>
|
||||
#include <wolfssl/wolfcrypt/asn.h>
|
||||
#include <wolfssl/wolfcrypt/asn_public.h>
|
||||
#include <wolfssl/wolfcrypt/cryptocb.h>
|
||||
#include <tests/api/api.h>
|
||||
#include <tests/api/test_falcon.h>
|
||||
|
||||
|
|
@ -1035,3 +1036,105 @@ int test_wc_FalconDecisionCoverage(void)
|
|||
#endif /* HAVE_FALCON */
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
|
||||
#if defined(HAVE_FALCON) && defined(WOLF_CRYPTO_CB) && \
|
||||
defined(WOLF_CRYPTO_CB_FREE)
|
||||
#define TEST_FALCON_CB_FREE
|
||||
#define TEST_FALCON_CB_FREE_DEVID 0x46414C43
|
||||
#endif
|
||||
|
||||
#ifdef TEST_FALCON_CB_FREE
|
||||
/* What the free callback saw, so the test can check the contract rather than
|
||||
* just that something fired. */
|
||||
typedef struct {
|
||||
int frees; /* matching free callbacks seen */
|
||||
int badObj; /* callback was handed the wrong object */
|
||||
int wiped; /* callback saw a key already cleaned up */
|
||||
int ret; /* what the callback returns */
|
||||
const void* obj; /* object the free is expected to name */
|
||||
} FalconCbFreeCtx;
|
||||
|
||||
/* Stands in for a device holding state for the key. Counting the call proves
|
||||
* wc_falcon_free told the device rather than only cleaning up in software,
|
||||
* which would leave the device side of the key behind. */
|
||||
static int falcon_cb_free_cb(int devIdArg, wc_CryptoInfo* info, void* ctx)
|
||||
{
|
||||
FalconCbFreeCtx* seen = (FalconCbFreeCtx*)ctx;
|
||||
|
||||
(void)devIdArg;
|
||||
|
||||
if ((seen != NULL) && (info != NULL) &&
|
||||
(info->algo_type == WC_ALGO_TYPE_FREE) &&
|
||||
(info->free.algo == WC_ALGO_TYPE_PK) &&
|
||||
(info->free.type == WC_PK_TYPE_PQC_SIG_KEYGEN) &&
|
||||
(info->free.subType == WC_PQC_SIG_TYPE_FALCON)) {
|
||||
const falcon_key* fk = (const falcon_key*)info->free.obj;
|
||||
|
||||
seen->frees++;
|
||||
if ((fk == NULL) || ((const void*)fk != seen->obj)) {
|
||||
seen->badObj++;
|
||||
}
|
||||
/* The device gets the key while it is still whole: it may need to
|
||||
* read it to release the right resource, so the software wipe has
|
||||
* to come after this call, not before. */
|
||||
else if (fk->devId != TEST_FALCON_CB_FREE_DEVID) {
|
||||
seen->wiped++;
|
||||
}
|
||||
return seen->ret;
|
||||
}
|
||||
|
||||
return WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE);
|
||||
}
|
||||
#endif /* TEST_FALCON_CB_FREE */
|
||||
|
||||
/* Freeing a key that names a device has to tell that device, so it can
|
||||
* release what it holds. A key with no device must not, and neither must a
|
||||
* second free of a key already freed: a freed key names no device. A device
|
||||
* that reports an error does not stop the software cleanup. */
|
||||
int test_falcon_cb_free(void)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
#ifdef TEST_FALCON_CB_FREE
|
||||
falcon_key key;
|
||||
FalconCbFreeCtx seen;
|
||||
|
||||
XMEMSET(&key, 0, sizeof(key));
|
||||
XMEMSET(&seen, 0, sizeof(seen));
|
||||
seen.obj = &key;
|
||||
|
||||
/* No key to free, and nothing to tell a device about. */
|
||||
wc_falcon_free(NULL);
|
||||
|
||||
ExpectIntEQ(wc_CryptoCb_RegisterDevice(TEST_FALCON_CB_FREE_DEVID,
|
||||
falcon_cb_free_cb, &seen), 0);
|
||||
|
||||
ExpectIntEQ(wc_falcon_init_ex(&key, NULL, TEST_FALCON_CB_FREE_DEVID), 0);
|
||||
wc_falcon_free(&key);
|
||||
ExpectIntEQ(seen.frees, 1);
|
||||
ExpectIntEQ(seen.badObj, 0);
|
||||
ExpectIntEQ(seen.wiped, 0);
|
||||
ExpectIntEQ(key.devId, INVALID_DEVID);
|
||||
|
||||
wc_falcon_free(&key);
|
||||
ExpectIntEQ(seen.frees, 1);
|
||||
|
||||
/* A device that fails still leaves the key cleaned up locally. */
|
||||
seen.ret = WC_NO_ERR_TRACE(WC_HW_E);
|
||||
XMEMSET(&key, 0, sizeof(key));
|
||||
ExpectIntEQ(wc_falcon_init_ex(&key, NULL, TEST_FALCON_CB_FREE_DEVID), 0);
|
||||
ExpectIntEQ(wc_falcon_set_level(&key, 1), 0);
|
||||
wc_falcon_free(&key);
|
||||
ExpectIntEQ(seen.frees, 2);
|
||||
ExpectIntEQ(key.devId, INVALID_DEVID);
|
||||
ExpectIntEQ(key.level, 0);
|
||||
seen.ret = 0;
|
||||
|
||||
XMEMSET(&key, 0, sizeof(key));
|
||||
ExpectIntEQ(wc_falcon_init_ex(&key, NULL, INVALID_DEVID), 0);
|
||||
wc_falcon_free(&key);
|
||||
ExpectIntEQ(seen.frees, 2);
|
||||
|
||||
wc_CryptoCb_UnRegisterDevice(TEST_FALCON_CB_FREE_DEVID);
|
||||
#endif
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ int test_wc_falcon_check_key(void);
|
|||
int test_wc_falcon_der(void);
|
||||
int test_wc_falcon_error_paths(void);
|
||||
int test_wc_FalconDecisionCoverage(void);
|
||||
int test_falcon_cb_free(void);
|
||||
|
||||
#define TEST_FALCON_DECLS \
|
||||
TEST_DECL_GROUP("falcon", test_wc_falcon_sizes), \
|
||||
|
|
@ -41,6 +42,7 @@ int test_wc_FalconDecisionCoverage(void);
|
|||
TEST_DECL_GROUP("falcon", test_wc_falcon_check_key), \
|
||||
TEST_DECL_GROUP("falcon", test_wc_falcon_der), \
|
||||
TEST_DECL_GROUP("falcon", test_wc_falcon_error_paths), \
|
||||
TEST_DECL_GROUP("falcon", test_wc_FalconDecisionCoverage)
|
||||
TEST_DECL_GROUP("falcon", test_wc_FalconDecisionCoverage), \
|
||||
TEST_DECL_GROUP("falcon", test_falcon_cb_free)
|
||||
|
||||
#endif /* WOLFCRYPT_TEST_FALCON_H */
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@
|
|||
#endif
|
||||
|
||||
#include <wolfssl/wolfcrypt/asn_public.h>
|
||||
#include <wolfssl/wolfcrypt/cryptocb.h>
|
||||
#ifdef WOLFSSL_HAVE_MLDSA
|
||||
#include <wolfssl/wolfcrypt/wc_mldsa.h>
|
||||
#endif
|
||||
|
|
@ -31401,3 +31402,105 @@ int test_wc_MldsaDerDecisionCoverage(void)
|
|||
#endif /* WOLFSSL_HAVE_MLDSA && WOLFSSL_MLDSA_NO_ASN1 && ... */
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
|
||||
#if defined(WOLFSSL_HAVE_MLDSA) && defined(WOLF_CRYPTO_CB) && \
|
||||
defined(WOLF_CRYPTO_CB_FREE)
|
||||
#define TEST_MLDSA_CB_FREE
|
||||
#define TEST_MLDSA_CB_FREE_DEVID 0x4D4C4453
|
||||
#endif
|
||||
|
||||
#ifdef TEST_MLDSA_CB_FREE
|
||||
/* What the free callback saw, so the test can check the contract rather than
|
||||
* just that something fired. */
|
||||
typedef struct {
|
||||
int frees; /* matching free callbacks seen */
|
||||
int badObj; /* callback was handed the wrong object */
|
||||
int wiped; /* callback saw a key already cleaned up */
|
||||
int ret; /* what the callback returns */
|
||||
const void* obj; /* object the free is expected to name */
|
||||
} MlDsaCbFreeCtx;
|
||||
|
||||
/* Stands in for a device holding state for the key. Counting the call proves
|
||||
* wc_MlDsaKey_Free told the device rather than only cleaning up in software,
|
||||
* which would leave the device side of the key behind. */
|
||||
static int mldsa_cb_free_cb(int devIdArg, wc_CryptoInfo* info, void* ctx)
|
||||
{
|
||||
MlDsaCbFreeCtx* seen = (MlDsaCbFreeCtx*)ctx;
|
||||
|
||||
(void)devIdArg;
|
||||
|
||||
if ((seen != NULL) && (info != NULL) &&
|
||||
(info->algo_type == WC_ALGO_TYPE_FREE) &&
|
||||
(info->free.algo == WC_ALGO_TYPE_PK) &&
|
||||
(info->free.type == WC_PK_TYPE_PQC_SIG_KEYGEN) &&
|
||||
(info->free.subType == WC_PQC_SIG_TYPE_MLDSA)) {
|
||||
const wc_MlDsaKey* dil = (const wc_MlDsaKey*)info->free.obj;
|
||||
|
||||
seen->frees++;
|
||||
if ((dil == NULL) || ((const void*)dil != seen->obj)) {
|
||||
seen->badObj++;
|
||||
}
|
||||
/* The device gets the key while it is still whole: it may need to
|
||||
* read it to release the right resource, so the software wipe has
|
||||
* to come after this call, not before. */
|
||||
else if (dil->devId != TEST_MLDSA_CB_FREE_DEVID) {
|
||||
seen->wiped++;
|
||||
}
|
||||
return seen->ret;
|
||||
}
|
||||
|
||||
return WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE);
|
||||
}
|
||||
#endif /* TEST_MLDSA_CB_FREE */
|
||||
|
||||
/* Freeing a key that names a device has to tell that device, so it can
|
||||
* release what it holds. A key with no device must not, and neither must a
|
||||
* second free of a key already freed: a freed key names no device. A device
|
||||
* that reports an error does not stop the software cleanup. */
|
||||
int test_mldsa_cb_free(void)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
#ifdef TEST_MLDSA_CB_FREE
|
||||
wc_MlDsaKey* key = NULL;
|
||||
MlDsaCbFreeCtx seen;
|
||||
|
||||
XMEMSET(&seen, 0, sizeof(seen));
|
||||
|
||||
ExpectIntEQ(wc_CryptoCb_RegisterDevice(TEST_MLDSA_CB_FREE_DEVID,
|
||||
mldsa_cb_free_cb, &seen), 0);
|
||||
|
||||
ExpectNotNull(key = (wc_MlDsaKey*)XMALLOC(sizeof(wc_MlDsaKey), NULL,
|
||||
DYNAMIC_TYPE_TMP_BUFFER));
|
||||
seen.obj = key;
|
||||
ExpectIntEQ(wc_MlDsaKey_Init(key, NULL, TEST_MLDSA_CB_FREE_DEVID), 0);
|
||||
wc_MlDsaKey_Free(key);
|
||||
ExpectIntEQ(seen.frees, 1);
|
||||
ExpectIntEQ(seen.badObj, 0);
|
||||
ExpectIntEQ(seen.wiped, 0);
|
||||
if (key != NULL) {
|
||||
ExpectIntEQ(key->devId, INVALID_DEVID);
|
||||
ExpectIntEQ(key->shake.devId, INVALID_DEVID);
|
||||
}
|
||||
|
||||
wc_MlDsaKey_Free(key);
|
||||
ExpectIntEQ(seen.frees, 1);
|
||||
|
||||
/* A device that fails still leaves the key cleaned up locally. */
|
||||
seen.ret = WC_NO_ERR_TRACE(WC_HW_E);
|
||||
ExpectIntEQ(wc_MlDsaKey_Init(key, NULL, TEST_MLDSA_CB_FREE_DEVID), 0);
|
||||
wc_MlDsaKey_Free(key);
|
||||
ExpectIntEQ(seen.frees, 2);
|
||||
if (key != NULL) {
|
||||
ExpectIntEQ(key->devId, INVALID_DEVID);
|
||||
}
|
||||
seen.ret = 0;
|
||||
|
||||
ExpectIntEQ(wc_MlDsaKey_Init(key, NULL, INVALID_DEVID), 0);
|
||||
wc_MlDsaKey_Free(key);
|
||||
ExpectIntEQ(seen.frees, 2);
|
||||
|
||||
XFREE(key, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
wc_CryptoCb_UnRegisterDevice(TEST_MLDSA_CB_FREE_DEVID);
|
||||
#endif
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -68,6 +68,7 @@ int test_wc_MldsaFeatureCoverage(void);
|
|||
int test_mldsa_legacy_shim(void);
|
||||
int test_wc_MldsaDecisionCoverage2(void);
|
||||
int test_wc_MldsaDerDecisionCoverage(void);
|
||||
int test_mldsa_cb_free(void);
|
||||
|
||||
#define TEST_MLDSA_DECLS \
|
||||
TEST_DECL_GROUP("mldsa", test_mldsa), \
|
||||
|
|
@ -99,6 +100,7 @@ int test_wc_MldsaDerDecisionCoverage(void);
|
|||
TEST_DECL_GROUP("mldsa", test_wc_MldsaFeatureCoverage), \
|
||||
TEST_DECL_GROUP("mldsa", test_mldsa_legacy_shim), \
|
||||
TEST_DECL_GROUP("mldsa", test_wc_MldsaDecisionCoverage2), \
|
||||
TEST_DECL_GROUP("mldsa", test_wc_MldsaDerDecisionCoverage)
|
||||
TEST_DECL_GROUP("mldsa", test_wc_MldsaDerDecisionCoverage), \
|
||||
TEST_DECL_GROUP("mldsa", test_mldsa_cb_free)
|
||||
|
||||
#endif /* WOLFCRYPT_TEST_MLDSA_H */
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@
|
|||
#include <wolfssl/wolfcrypt/wc_mlkem.h>
|
||||
#endif
|
||||
#include <wolfssl/wolfcrypt/types.h>
|
||||
#include <wolfssl/wolfcrypt/cryptocb.h>
|
||||
#include <tests/api/api.h>
|
||||
#include <tests/api/test_mlkem.h>
|
||||
|
||||
|
|
@ -4648,3 +4649,129 @@ int test_wc_mlkem_encode_key_len_decision(void)
|
|||
#endif
|
||||
return EXPECT_RESULT();
|
||||
} /* END test_wc_mlkem_encode_key_len_decision */
|
||||
|
||||
#if defined(WOLFSSL_HAVE_MLKEM) && !defined(WOLFSSL_NO_ML_KEM) && \
|
||||
defined(WOLF_CRYPTO_CB) && defined(WOLF_CRYPTO_CB_FREE)
|
||||
#define TEST_MLKEM_CB_FREE
|
||||
#define TEST_MLKEM_CB_FREE_DEVID 0x4D4C4B4D
|
||||
#ifndef WOLFSSL_NO_ML_KEM_512
|
||||
#define TEST_MLKEM_CB_FREE_TYPE WC_ML_KEM_512
|
||||
#elif !defined(WOLFSSL_NO_ML_KEM_768)
|
||||
#define TEST_MLKEM_CB_FREE_TYPE WC_ML_KEM_768
|
||||
#elif !defined(WOLFSSL_NO_ML_KEM_1024)
|
||||
#define TEST_MLKEM_CB_FREE_TYPE WC_ML_KEM_1024
|
||||
#else
|
||||
#undef TEST_MLKEM_CB_FREE
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef TEST_MLKEM_CB_FREE
|
||||
/* What the free callback saw, so the test can check the contract rather than
|
||||
* just that something fired. */
|
||||
typedef struct {
|
||||
int frees; /* matching free callbacks seen */
|
||||
int badObj; /* callback was handed the wrong object */
|
||||
int wiped; /* callback saw a key already cleaned up */
|
||||
int ret; /* what the callback returns */
|
||||
const void* obj; /* object the free is expected to name */
|
||||
} MlKemCbFreeCtx;
|
||||
|
||||
/* Stands in for a device holding state for the key. Counting the call proves
|
||||
* wc_MlKemKey_Free told the device rather than only cleaning up in software,
|
||||
* which would leave the device side of the key behind. */
|
||||
static int mlkem_cb_free_cb(int devIdArg, wc_CryptoInfo* info, void* ctx)
|
||||
{
|
||||
MlKemCbFreeCtx* seen = (MlKemCbFreeCtx*)ctx;
|
||||
|
||||
(void)devIdArg;
|
||||
|
||||
if ((seen != NULL) && (info != NULL) &&
|
||||
(info->algo_type == WC_ALGO_TYPE_FREE) &&
|
||||
(info->free.algo == WC_ALGO_TYPE_PK) &&
|
||||
(info->free.type == WC_PK_TYPE_PQC_KEM_KEYGEN) &&
|
||||
(info->free.subType == WC_PQC_KEM_TYPE_MLKEM)) {
|
||||
const MlKemKey* mk = (const MlKemKey*)info->free.obj;
|
||||
|
||||
seen->frees++;
|
||||
if ((mk == NULL) || ((const void*)mk != seen->obj)) {
|
||||
seen->badObj++;
|
||||
}
|
||||
/* The device gets the key while it is still whole: it may need to
|
||||
* read it to release the right resource, so the software wipe has
|
||||
* to come after this call, not before. */
|
||||
else if (mk->devId != TEST_MLKEM_CB_FREE_DEVID) {
|
||||
seen->wiped++;
|
||||
}
|
||||
return seen->ret;
|
||||
}
|
||||
|
||||
return WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE);
|
||||
}
|
||||
#endif /* TEST_MLKEM_CB_FREE */
|
||||
|
||||
/* Freeing a key that names a device has to tell that device, so it can
|
||||
* release what it holds. A key with no device must not, and neither must a
|
||||
* second free of a key already freed: neither the key nor the hash and PRF
|
||||
* objects inside it name a device once freed. A device that reports an error
|
||||
* does not stop the software cleanup. */
|
||||
int test_wc_mlkem_cb_free(void)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
#ifdef TEST_MLKEM_CB_FREE
|
||||
MlKemKey* key = NULL;
|
||||
MlKemCbFreeCtx seen;
|
||||
int freeRet;
|
||||
|
||||
XMEMSET(&seen, 0, sizeof(seen));
|
||||
|
||||
/* No key to free, and nothing to tell a device about. */
|
||||
ExpectIntEQ(wc_MlKemKey_Free(NULL), 0);
|
||||
|
||||
ExpectIntEQ(wc_CryptoCb_RegisterDevice(TEST_MLKEM_CB_FREE_DEVID,
|
||||
mlkem_cb_free_cb, &seen), 0);
|
||||
|
||||
ExpectNotNull(key = (MlKemKey*)XMALLOC(sizeof(MlKemKey), NULL,
|
||||
DYNAMIC_TYPE_TMP_BUFFER));
|
||||
seen.obj = key;
|
||||
ExpectIntEQ(wc_MlKemKey_Init(key, TEST_MLKEM_CB_FREE_TYPE, NULL,
|
||||
TEST_MLKEM_CB_FREE_DEVID), 0);
|
||||
/* Freed outside the assertion so the hash and PRF objects are always
|
||||
* disposed of, even once an earlier check has failed. */
|
||||
freeRet = wc_MlKemKey_Free(key);
|
||||
ExpectIntEQ(freeRet, 0);
|
||||
ExpectIntEQ(seen.frees, 1);
|
||||
ExpectIntEQ(seen.badObj, 0);
|
||||
ExpectIntEQ(seen.wiped, 0);
|
||||
if (key != NULL) {
|
||||
ExpectIntEQ(key->devId, INVALID_DEVID);
|
||||
ExpectIntEQ(key->hash.devId, INVALID_DEVID);
|
||||
ExpectIntEQ(key->prf.devId, INVALID_DEVID);
|
||||
}
|
||||
|
||||
freeRet = wc_MlKemKey_Free(key);
|
||||
ExpectIntEQ(freeRet, 0);
|
||||
ExpectIntEQ(seen.frees, 1);
|
||||
|
||||
/* A device that fails still leaves the key cleaned up locally. */
|
||||
seen.ret = WC_NO_ERR_TRACE(WC_HW_E);
|
||||
ExpectIntEQ(wc_MlKemKey_Init(key, TEST_MLKEM_CB_FREE_TYPE, NULL,
|
||||
TEST_MLKEM_CB_FREE_DEVID), 0);
|
||||
freeRet = wc_MlKemKey_Free(key);
|
||||
ExpectIntEQ(freeRet, 0);
|
||||
ExpectIntEQ(seen.frees, 2);
|
||||
if (key != NULL) {
|
||||
ExpectIntEQ(key->devId, INVALID_DEVID);
|
||||
}
|
||||
seen.ret = 0;
|
||||
|
||||
ExpectIntEQ(wc_MlKemKey_Init(key, TEST_MLKEM_CB_FREE_TYPE, NULL,
|
||||
INVALID_DEVID), 0);
|
||||
freeRet = wc_MlKemKey_Free(key);
|
||||
ExpectIntEQ(freeRet, 0);
|
||||
ExpectIntEQ(seen.frees, 2);
|
||||
|
||||
XFREE(key, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
wc_CryptoCb_UnRegisterDevice(TEST_MLKEM_CB_FREE_DEVID);
|
||||
#endif
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ int test_wc_mlkem_init_id_decision(void);
|
|||
int test_wc_mlkem_init_label_decision(void);
|
||||
int test_wc_mlkem_encapsulate_pubkey_unset_decision(void);
|
||||
int test_wc_mlkem_encode_key_len_decision(void);
|
||||
int test_wc_mlkem_cb_free(void);
|
||||
|
||||
#define TEST_MLKEM_DECLS \
|
||||
TEST_DECL_GROUP("mlkem", test_wc_mlkem_make_key_kats), \
|
||||
|
|
@ -49,6 +50,7 @@ int test_wc_mlkem_encode_key_len_decision(void);
|
|||
TEST_DECL_GROUP("mlkem", test_wc_mlkem_init_id_decision), \
|
||||
TEST_DECL_GROUP("mlkem", test_wc_mlkem_init_label_decision), \
|
||||
TEST_DECL_GROUP("mlkem", test_wc_mlkem_encapsulate_pubkey_unset_decision), \
|
||||
TEST_DECL_GROUP("mlkem", test_wc_mlkem_encode_key_len_decision)
|
||||
TEST_DECL_GROUP("mlkem", test_wc_mlkem_encode_key_len_decision), \
|
||||
TEST_DECL_GROUP("mlkem", test_wc_mlkem_cb_free)
|
||||
|
||||
#endif /* WOLFCRYPT_TEST_MLKEM_H */
|
||||
|
|
|
|||
|
|
@ -3871,3 +3871,106 @@ int test_slhdsa_get_sigalg_info(void)
|
|||
#endif /* WOLFSSL_HAVE_SLHDSA && OPENSSL_EXTRA */
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
|
||||
#if defined(WOLFSSL_HAVE_SLHDSA) && defined(WOLF_CRYPTO_CB) && \
|
||||
defined(WOLF_CRYPTO_CB_FREE)
|
||||
#define TEST_SLHDSA_CB_FREE
|
||||
#define TEST_SLHDSA_CB_FREE_DEVID 0x534C4844
|
||||
#endif
|
||||
|
||||
#ifdef TEST_SLHDSA_CB_FREE
|
||||
/* What the free callback saw, so the test can check the contract rather than
|
||||
* just that something fired. */
|
||||
typedef struct {
|
||||
int frees; /* matching free callbacks seen */
|
||||
int badObj; /* callback was handed the wrong object */
|
||||
int wiped; /* callback saw a key already cleaned up */
|
||||
int ret; /* what the callback returns */
|
||||
const void* obj; /* object the free is expected to name */
|
||||
} SlhDsaCbFreeCtx;
|
||||
|
||||
/* Stands in for a device holding state for the key. Counting the call proves
|
||||
* wc_SlhDsaKey_Free told the device rather than only cleaning up in software,
|
||||
* which would leave the device side of the key behind. */
|
||||
static int slhdsa_cb_free_cb(int devIdArg, wc_CryptoInfo* info, void* ctx)
|
||||
{
|
||||
SlhDsaCbFreeCtx* seen = (SlhDsaCbFreeCtx*)ctx;
|
||||
|
||||
(void)devIdArg;
|
||||
|
||||
if ((seen != NULL) && (info != NULL) &&
|
||||
(info->algo_type == WC_ALGO_TYPE_FREE) &&
|
||||
(info->free.algo == WC_ALGO_TYPE_PK) &&
|
||||
(info->free.type == WC_PK_TYPE_PQC_SIG_KEYGEN) &&
|
||||
(info->free.subType == WC_PQC_SIG_TYPE_SLHDSA)) {
|
||||
const SlhDsaKey* slh = (const SlhDsaKey*)info->free.obj;
|
||||
|
||||
seen->frees++;
|
||||
if ((slh == NULL) || ((const void*)slh != seen->obj)) {
|
||||
seen->badObj++;
|
||||
}
|
||||
/* The device gets the key while it is still whole: it may need to
|
||||
* read it to release the right resource, so the software wipe has
|
||||
* to come after this call, not before. */
|
||||
else if ((slh->devId != TEST_SLHDSA_CB_FREE_DEVID) ||
|
||||
(slh->params == NULL)) {
|
||||
seen->wiped++;
|
||||
}
|
||||
return seen->ret;
|
||||
}
|
||||
|
||||
return WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE);
|
||||
}
|
||||
#endif /* TEST_SLHDSA_CB_FREE */
|
||||
|
||||
/* Freeing a key that names a device has to tell that device, so it can
|
||||
* release what it holds. A key with no device must not, and neither must a
|
||||
* second free of a key already freed: a freed key names no device. A device
|
||||
* that reports an error does not stop the software cleanup. */
|
||||
int test_slhdsa_cb_free(void)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
#ifdef TEST_SLHDSA_CB_FREE
|
||||
SlhDsaKey key;
|
||||
SlhDsaCbFreeCtx seen;
|
||||
|
||||
XMEMSET(&key, 0, sizeof(key));
|
||||
XMEMSET(&seen, 0, sizeof(seen));
|
||||
seen.obj = &key;
|
||||
|
||||
ExpectIntEQ(wc_CryptoCb_RegisterDevice(TEST_SLHDSA_CB_FREE_DEVID,
|
||||
slhdsa_cb_free_cb, &seen), 0);
|
||||
|
||||
ExpectIntEQ(wc_SlhDsaKey_Init(&key, WC_SLHDSA_DEFAULT_PARAM, NULL,
|
||||
TEST_SLHDSA_CB_FREE_DEVID), 0);
|
||||
wc_SlhDsaKey_Free(&key);
|
||||
ExpectIntEQ(seen.frees, 1);
|
||||
ExpectIntEQ(seen.badObj, 0);
|
||||
ExpectIntEQ(seen.wiped, 0);
|
||||
ExpectIntEQ(key.devId, INVALID_DEVID);
|
||||
ExpectNull(key.params);
|
||||
|
||||
wc_SlhDsaKey_Free(&key);
|
||||
ExpectIntEQ(seen.frees, 1);
|
||||
|
||||
/* A device that fails still leaves the key cleaned up locally. */
|
||||
seen.ret = WC_NO_ERR_TRACE(WC_HW_E);
|
||||
XMEMSET(&key, 0, sizeof(key));
|
||||
ExpectIntEQ(wc_SlhDsaKey_Init(&key, WC_SLHDSA_DEFAULT_PARAM, NULL,
|
||||
TEST_SLHDSA_CB_FREE_DEVID), 0);
|
||||
wc_SlhDsaKey_Free(&key);
|
||||
ExpectIntEQ(seen.frees, 2);
|
||||
ExpectIntEQ(key.devId, INVALID_DEVID);
|
||||
ExpectNull(key.params);
|
||||
seen.ret = 0;
|
||||
|
||||
XMEMSET(&key, 0, sizeof(key));
|
||||
ExpectIntEQ(wc_SlhDsaKey_Init(&key, WC_SLHDSA_DEFAULT_PARAM, NULL,
|
||||
INVALID_DEVID), 0);
|
||||
wc_SlhDsaKey_Free(&key);
|
||||
ExpectIntEQ(seen.frees, 2);
|
||||
|
||||
wc_CryptoCb_UnRegisterDevice(TEST_SLHDSA_CB_FREE_DEVID);
|
||||
#endif
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ int test_slhdsa_tls13_certverify_multi_stall(void);
|
|||
int test_mldsa_tls13_certverify_maxfrag_stream(void);
|
||||
int test_slhdsa_dev_private_key(void);
|
||||
int test_slhdsa_tls13_certverify_bad_signature(void);
|
||||
int test_slhdsa_cb_free(void);
|
||||
|
||||
#define TEST_SLHDSA_DECLS \
|
||||
TEST_DECL_GROUP("slhdsa", test_wc_slhdsa), \
|
||||
|
|
@ -75,6 +76,7 @@ int test_slhdsa_tls13_certverify_bad_signature(void);
|
|||
TEST_DECL_GROUP("slhdsa", test_slhdsa_tls13_certverify_multi_stall), \
|
||||
TEST_DECL_GROUP("slhdsa", test_mldsa_tls13_certverify_maxfrag_stream), \
|
||||
TEST_DECL_GROUP("slhdsa", test_slhdsa_dev_private_key), \
|
||||
TEST_DECL_GROUP("slhdsa", test_slhdsa_tls13_certverify_bad_signature)
|
||||
TEST_DECL_GROUP("slhdsa", test_slhdsa_tls13_certverify_bad_signature), \
|
||||
TEST_DECL_GROUP("slhdsa", test_slhdsa_cb_free)
|
||||
|
||||
#endif /* WOLFCRYPT_TEST_SLHDSA_H */
|
||||
|
|
|
|||
|
|
@ -9046,7 +9046,21 @@ int wc_falcon_get_level(falcon_key* key, byte* level)
|
|||
void wc_falcon_free(falcon_key* key)
|
||||
{
|
||||
if (key != NULL) {
|
||||
#if defined(WOLF_CRYPTO_CB) && defined(WOLF_CRYPTO_CB_FREE)
|
||||
if (key->devId != INVALID_DEVID) {
|
||||
(void)wc_CryptoCb_Free(key->devId, WC_ALGO_TYPE_PK,
|
||||
WC_PK_TYPE_PQC_SIG_KEYGEN,
|
||||
WC_PQC_SIG_TYPE_FALCON,
|
||||
(void*)key);
|
||||
/* always continue to software cleanup */
|
||||
}
|
||||
#endif
|
||||
ForceZero(key, sizeof(*key));
|
||||
#ifdef WOLF_CRYPTO_CB
|
||||
/* Zeroing leaves devId at 0, which is a usable device id. Mark the
|
||||
* key as having no device so a second free does not call out again. */
|
||||
key->devId = INVALID_DEVID;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12185,6 +12185,13 @@ void wc_MlDsaKey_Free(wc_MlDsaKey* key)
|
|||
#endif
|
||||
/* Ensure all private data is zeroized. */
|
||||
ForceZero(key, sizeof(*key));
|
||||
#ifdef WOLF_CRYPTO_CB
|
||||
/* Zeroing leaves devId at 0, which is a usable device id. Mark the
|
||||
* key and the SHAKE object inside it as having no device: a second
|
||||
* free runs the SHAKE free again and would otherwise call out. */
|
||||
key->devId = INVALID_DEVID;
|
||||
key->shake.devId = INVALID_DEVID;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -591,6 +591,10 @@ int wc_MlKemKey_Free(MlKemKey* key)
|
|||
/* Ensure all private data is zeroed. */
|
||||
ForceZero(&key->hash, sizeof(key->hash));
|
||||
ForceZero(&key->prf, sizeof(key->prf));
|
||||
#ifdef WOLF_CRYPTO_CB
|
||||
key->hash.devId = INVALID_DEVID;
|
||||
key->prf.devId = INVALID_DEVID;
|
||||
#endif
|
||||
#ifdef WOLFSSL_MLKEM_DYNAMIC_KEYS
|
||||
if (key->priv != NULL) {
|
||||
ForceZero(key->priv, key->privAllocSz);
|
||||
|
|
@ -615,6 +619,12 @@ int wc_MlKemKey_Free(MlKemKey* key)
|
|||
|
||||
/* Clear flags as values are no longer set. */
|
||||
key->flags = 0;
|
||||
#ifdef WOLF_CRYPTO_CB
|
||||
/* Mark the key as having no device so a second free does not call
|
||||
* out to it again. */
|
||||
key->devCtx = NULL;
|
||||
key->devId = INVALID_DEVID;
|
||||
#endif
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -82685,7 +82685,8 @@ static int myCryptoDevCb(int devIdArg, wc_CryptoInfo* info, void* ctx)
|
|||
break;
|
||||
}
|
||||
#endif
|
||||
#if defined(WOLFSSL_HAVE_MLDSA) || defined(WOLFSSL_HAVE_SLHDSA)
|
||||
#if defined(WOLFSSL_HAVE_MLDSA) || defined(WOLFSSL_HAVE_SLHDSA) || \
|
||||
defined(HAVE_FALCON)
|
||||
case WC_PK_TYPE_PQC_SIG_KEYGEN:
|
||||
{
|
||||
#ifdef WOLFSSL_HAVE_MLDSA
|
||||
|
|
@ -82703,6 +82704,14 @@ static int myCryptoDevCb(int devIdArg, wc_CryptoInfo* info, void* ctx)
|
|||
wc_SlhDsaKey_Free(slh);
|
||||
ret = 0;
|
||||
}
|
||||
#endif
|
||||
#ifdef HAVE_FALCON
|
||||
if (info->free.subType == WC_PQC_SIG_TYPE_FALCON) {
|
||||
falcon_key* fk = (falcon_key*)info->free.obj;
|
||||
fk->devId = INVALID_DEVID;
|
||||
wc_falcon_free(fk);
|
||||
ret = 0;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue