Skip to content
39 changes: 38 additions & 1 deletion include/wolfprovider/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,44 @@ int wp_provctx_lock_rng(WOLFPROV_CTX* provCtx);
void wp_provctx_unlock_rng(WOLFPROV_CTX* provCtx);

#ifdef HAVE_FIPS
wolfSSL_Mutex *wp_get_cast_mutex(void);
/* CAST self-test algorithm categories */
#define WP_CAST_ALGO_AES 0
#define WP_CAST_ALGO_HMAC 1
#define WP_CAST_ALGO_DRBG 2
#define WP_CAST_ALGO_RSA 3
#define WP_CAST_ALGO_ECDSA 4
#define WP_CAST_ALGO_ECDH 5
#define WP_CAST_ALGO_DH 6
#define WP_CAST_ALGO_COUNT 7

int wp_init_cast(int algo);

/**
* Check FIPS CAST for algorithm. Returns 0 on failure.
* Use at function entry points that return int (1=success, 0=failure).
*/
#define WP_CHECK_FIPS_ALGO(algo) \
do { \
if (wp_init_cast(algo) != 1) { \
return 0; \
} \
} while (0)

/**
* Check FIPS CAST for algorithm. Returns NULL on failure.
* Use at function entry points that return pointers (NULL=failure).
*/
#define WP_CHECK_FIPS_ALGO_PTR(algo) \
do { \
if (wp_init_cast(algo) != 1) { \
return NULL; \
} \
} while (0)

#else
/* Non-FIPS: no-op */
#define WP_CHECK_FIPS_ALGO(algo) do { } while (0)
#define WP_CHECK_FIPS_ALGO_PTR(algo) do { } while (0)
#endif
#endif

Expand Down
3 changes: 3 additions & 0 deletions include/wolfprovider/settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,9 @@
#define WP_HAVE_GMAC
#endif

#ifndef NO_AES
#define WP_HAVE_AES
#endif
#ifdef HAVE_AES_ECB
#define WP_HAVE_AESECB
#endif
Expand Down
9 changes: 9 additions & 0 deletions src/wp_aes_aead.c
Original file line number Diff line number Diff line change
Expand Up @@ -1022,6 +1022,9 @@ static int wp_aesgcm_einit(wp_AeadCtx* ctx, const unsigned char *key,
if (!wolfssl_prov_is_running()) {
ok = 0;
}
if (ok) {
WP_CHECK_FIPS_ALGO(WP_CAST_ALGO_AES);
}
#ifdef WOLFSSL_AESGCM_STREAM
if (ok) {
int rc;
Expand Down Expand Up @@ -1108,6 +1111,9 @@ static int wp_aesgcm_dinit(wp_AeadCtx *ctx, const unsigned char *key,
if (!wolfssl_prov_is_running()) {
ok = 0;
}
if (ok) {
WP_CHECK_FIPS_ALGO(WP_CAST_ALGO_AES);
}
#ifdef WOLFSSL_AESGCM_STREAM
if (ok && key != NULL) {
int rc = wc_AesGcmDecryptInit(aes, key, (word32)keyLen, iv, (word32)ivLen);
Expand Down Expand Up @@ -1754,6 +1760,9 @@ static int wp_aesccm_init(wp_AeadCtx* ctx, const unsigned char *key,
if (!wolfssl_prov_is_running()) {
ok = 0;
}
if (ok) {
WP_CHECK_FIPS_ALGO(WP_CAST_ALGO_AES);
}
if (ok && (key != NULL)) {
rc = wc_AesCcmSetKey(&ctx->aes, key, (word32)keyLen);
if (rc != 0) {
Expand Down
4 changes: 3 additions & 1 deletion src/wp_aes_block.c
Original file line number Diff line number Diff line change
Expand Up @@ -328,7 +328,9 @@ static int wp_aes_block_init(wp_AesBlockCtx *ctx, const unsigned char *key,
ok = 0;
}
if (ok) {
int rc = wc_AesSetKey(&ctx->aes, key, (word32)ctx->keyLen, ctx->iv,
int rc;
WP_CHECK_FIPS_ALGO(WP_CAST_ALGO_AES);
rc = wc_AesSetKey(&ctx->aes, key, (word32)ctx->keyLen, ctx->iv,
enc ? AES_ENCRYPTION : AES_DECRYPTION);
if (rc != 0) {
WOLFPROV_MSG_DEBUG_RETCODE(WP_LOG_LEVEL_DEBUG, "wc_AesSetKey", rc);
Expand Down
4 changes: 3 additions & 1 deletion src/wp_aes_stream.c
Original file line number Diff line number Diff line change
Expand Up @@ -314,12 +314,14 @@ static int wp_aes_stream_init(wp_AesStreamCtx *ctx, const unsigned char *key,
ok = 0;
}
if (ok) {
int rc;
#if defined(WP_HAVE_AESCTS)
if (ctx->mode == EVP_CIPH_CBC_MODE && !enc) {
dir = AES_DECRYPTION;
}
#endif
int rc = wc_AesSetKey(&ctx->aes, key, (word32)ctx->keyLen, iv,
WP_CHECK_FIPS_ALGO(WP_CAST_ALGO_AES);
rc = wc_AesSetKey(&ctx->aes, key, (word32)ctx->keyLen, iv,
dir);
if (rc != 0) {
WOLFPROV_MSG_DEBUG_RETCODE(WP_LOG_LEVEL_DEBUG, "wc_AesSetKey", rc);
Expand Down
4 changes: 3 additions & 1 deletion src/wp_aes_wrap.c
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,9 @@ static int wp_aes_wrap_init(wp_AesWrapCtx *ctx, const unsigned char *key,
}
if (ok) {
#if LIBWOLFSSL_VERSION_HEX >= 0x05000000
int rc = wc_AesSetKey(&ctx->aes, key, (word32)ctx->keyLen, iv,
int rc;
WP_CHECK_FIPS_ALGO(WP_CAST_ALGO_AES);
rc = wc_AesSetKey(&ctx->aes, key, (word32)ctx->keyLen, iv,
wrap ? AES_ENCRYPTION : AES_DECRYPTION);
if (rc != 0) {
WOLFPROV_MSG_DEBUG_RETCODE(WP_LOG_LEVEL_DEBUG, "wc_AesSetKey", rc);
Expand Down
9 changes: 9 additions & 0 deletions src/wp_dh_kmgmt.c
Original file line number Diff line number Diff line change
Expand Up @@ -1156,6 +1156,9 @@ static int wp_dh_import(wp_Dh* dh, int selection, const OSSL_PARAM params[])
if (!wolfssl_prov_is_running()) {
ok = 0;
}
if (ok) {
WP_CHECK_FIPS_ALGO(WP_CAST_ALGO_DH);
}
if (ok && (dh == NULL)) {
ok = 0;
}
Expand Down Expand Up @@ -1832,6 +1835,8 @@ static wp_Dh* wp_dh_gen(wp_DhGenCtx *ctx, OSSL_CALLBACK *cb, void *cbArg)
(void)cb;
(void)cbArg;

WP_CHECK_FIPS_ALGO_PTR(WP_CAST_ALGO_DH);

/* Create a new DH key object to hold generated data. */
dh = wp_dh_new(ctx->provCtx);
if (dh != NULL) {
Expand Down Expand Up @@ -2064,6 +2069,8 @@ static int wp_dh_decode_spki(wp_Dh* dh, unsigned char* data, word32 len)

WOLFPROV_ENTER_SILENT(WP_LOG_COMP_DH, WOLFPROV_FUNC_NAME);

WP_CHECK_FIPS_ALGO(WP_CAST_ALGO_DH);

rc = wc_DhPublicKeyDecode(data, &idx, &dh->key, len);
if (rc != 0) {
ok = 0;
Expand Down Expand Up @@ -2127,6 +2134,8 @@ static int wp_dh_decode_pki(wp_Dh* dh, unsigned char* data, word32 len)

WOLFPROV_ENTER_SILENT(WP_LOG_COMP_DH, WOLFPROV_FUNC_NAME);

WP_CHECK_FIPS_ALGO(WP_CAST_ALGO_DH);

rc = wc_DhKeyDecode(data, &idx, &dh->key, len);
if (rc != 0) {
ok = 0;
Expand Down
3 changes: 3 additions & 0 deletions src/wp_ecc_kmgmt.c
Original file line number Diff line number Diff line change
Expand Up @@ -1768,6 +1768,9 @@ static wp_Ecc* wp_ecc_gen(wp_EccGenCtx *ctx, OSSL_CALLBACK *cb, void *cbArg)
(void)cb;
(void)cbArg;

WP_CHECK_FIPS_ALGO_PTR(WP_CAST_ALGO_ECDSA);
WP_CHECK_FIPS_ALGO_PTR(WP_CAST_ALGO_ECDH);

if (ctx->curveName[0] != '\0') {
ecc = wp_ecc_new(ctx->provCtx);
}
Expand Down
3 changes: 3 additions & 0 deletions src/wp_ecdh_exch.c
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,9 @@ static int wp_ecdh_init(wp_EcdhCtx* ctx, wp_Ecc* ecc, const OSSL_PARAM params[])
if (!wolfssl_prov_is_running()) {
ok = 0;
}
if (ok) {
WP_CHECK_FIPS_ALGO(WP_CAST_ALGO_ECDH);
}
if (ok && (ctx->key != ecc)) {
/* Free old key and up reference new key. */
wp_ecc_free(ctx->key);
Expand Down
5 changes: 4 additions & 1 deletion src/wp_ecdsa_sig.c
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,10 @@ static int wp_ecdsa_signverify_init(wp_EcdsaSigCtx *ctx, wp_Ecc* ecc,
if (ctx == NULL || (ecc == NULL && ctx->ecc == NULL)) {
ok = 0;
}
else if (ecc != NULL) {
if (ok) {
WP_CHECK_FIPS_ALGO(WP_CAST_ALGO_ECDSA);
}
if (ok && (ecc != NULL)) {
if (!wp_ecc_up_ref(ecc)) {
ok = 0;
}
Expand Down
2 changes: 2 additions & 0 deletions src/wp_hmac.c
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,8 @@ static int wp_hmac_set_key(wp_HmacCtx* macCtx, const unsigned char* key,

WOLFPROV_ENTER(WP_LOG_COMP_MAC, "wp_hmac_set_key");

WP_CHECK_FIPS_ALGO(WP_CAST_ALGO_HMAC);

if (macCtx->keyLen > 0) {
OPENSSL_secure_clear_free(macCtx->key, macCtx->keyLen);
}
Expand Down
127 changes: 119 additions & 8 deletions src/wp_internal.c
Original file line number Diff line number Diff line change
Expand Up @@ -60,28 +60,139 @@ wolfSSL_Mutex *wp_get_urandom_mutex(void)
#endif /* WP_HAVE_SEED_SRC && WP_HAVE_RANDOM */

#ifdef HAVE_FIPS
static wolfSSL_Mutex castMutex;
/**
* Structure to hold CAST self-test state for each algorithm.
*/
typedef struct wp_cast_algo_state {
/** Mutex for the algorithm's CAST self-test. */
wolfSSL_Mutex mutex;
/** Initialization state: 0 = not initialized, 1 = initialized. */
int init;
} wp_cast_algo_state;

static wp_cast_algo_state castAlgos[WP_CAST_ALGO_COUNT];

/**
* Initialize the cast mutex on library load.
* Initialize the cast mutexes on library load.
*
* This constructor runs when libwolfprov.so is loaded via dlopen() or at
* program startup. It ensures the castMutex is initialized under lock.
* program startup. It ensures the castAlgos are initialized before any
* wolfProvider functions are called.
*/
__attribute__((constructor))
static void wolfprov_init_cast_mutex(void)
{
wc_InitMutex(&castMutex);
int i;
for (i = 0; i < WP_CAST_ALGO_COUNT; i++) {
wc_InitMutex(&castAlgos[i].mutex);
castAlgos[i].init = 0;
}
}

/**
* Get the FIPS CAST mutex.
* Initialize a CAST self-test for a specific algorithm.
*
* Runs the algorithm-specific CAST self-test if not already initialized.
* Uses mutex to ensure thread safety.
*
* @return Pointer to the CAST mutex.
* @param [in] algo Algorithm category (WP_CAST_ALGO_*).
* @return 1 on success or already initialized.
* @return 0 on failure.
*/
wolfSSL_Mutex *wp_get_cast_mutex(void)
int wp_init_cast(int algo)
{
return &castMutex;
int ok = 1;

if (algo < 0 || algo >= WP_CAST_ALGO_COUNT) {
WOLFPROV_ERROR_MSG(WP_LOG_COMP_PROVIDER,
"FIPS CAST initialization failed: invalid algorithm");
return 0;
}

if (castAlgos[algo].init == 0) {
if (wp_lock(&castAlgos[algo].mutex) != 1) {
WOLFPROV_ERROR_MSG(WP_LOG_COMP_PROVIDER,
"FIPS CAST initialization failed: unable to acquire lock");
return 0;
}
/* Make sure another thread did not complete already while we waited
* to acquire per algo lock */
if (castAlgos[algo].init == 0) {
switch (algo) {
#ifdef WP_HAVE_AES
case WP_CAST_ALGO_AES:
if (wc_RunCast_fips(FIPS_CAST_AES_CBC) != 0 ||
wc_RunCast_fips(FIPS_CAST_AES_GCM) != 0) {
ok = 0;
}
break;
#endif
#ifdef WP_HAVE_HMAC
case WP_CAST_ALGO_HMAC:
if (wc_RunCast_fips(FIPS_CAST_HMAC_SHA1) != 0 ||
wc_RunCast_fips(FIPS_CAST_HMAC_SHA2_256) != 0 ||
wc_RunCast_fips(FIPS_CAST_HMAC_SHA2_512) != 0 ||
wc_RunCast_fips(FIPS_CAST_HMAC_SHA3_256) != 0) {
ok = 0;
}
break;
#endif
#ifdef WP_HAVE_RSA
case WP_CAST_ALGO_RSA:
if (wc_RunCast_fips(FIPS_CAST_RSA_SIGN_PKCS1v15) != 0) {
ok = 0;
}
break;
#endif
#ifdef WP_HAVE_ECDSA
case WP_CAST_ALGO_ECDSA:
if (wc_RunCast_fips(FIPS_CAST_ECDSA) != 0) {
ok = 0;
}
break;
#endif
#ifdef WP_HAVE_ECDH
case WP_CAST_ALGO_ECDH:
if (wc_RunCast_fips(FIPS_CAST_ECC_CDH) != 0 ||
wc_RunCast_fips(FIPS_CAST_ECC_PRIMITIVE_Z) != 0) {
ok = 0;
}
break;
#endif
#ifdef WP_HAVE_DH
case WP_CAST_ALGO_DH:
if (wc_RunCast_fips(FIPS_CAST_DH_PRIMITIVE_Z) != 0) {
ok = 0;
}
break;
#endif
#ifdef WP_HAVE_RANDOM
case WP_CAST_ALGO_DRBG:
if (wc_RunCast_fips(FIPS_CAST_DRBG) != 0) {
ok = 0;
}
break;
#endif
default:
ok = 0;
break;
}

if (ok) {
castAlgos[algo].init = 1;
}
}
if (wp_unlock(&castAlgos[algo].mutex) != 1) {
ok = 0;
}
}

if (!ok) {
WOLFPROV_ERROR_MSG(WP_LOG_COMP_PROVIDER,
"FIPS CAST initialization failed");
}

return ok;
}
#endif /* HAVE_FIPS */
#endif /* !WP_SINGLE_THREADED */
Expand Down
2 changes: 2 additions & 0 deletions src/wp_rsa_asym.c
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,8 @@ static int wp_rsaa_init(wp_RsaAsymCtx* ctx, wp_Rsa* rsa,

WOLFPROV_ENTER(WP_LOG_COMP_RSA, "wp_rsaa_init");

WP_CHECK_FIPS_ALGO(WP_CAST_ALGO_RSA);

if (ctx->rsa != rsa) {
if (wp_rsa_get_type(rsa) != RSA_FLAG_TYPE_RSA) {
ERR_raise_data(ERR_LIB_PROV,
Expand Down
2 changes: 2 additions & 0 deletions src/wp_rsa_kem.c
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,8 @@ static int wp_rsakem_init(wp_RsaKemCtx* ctx, wp_Rsa* rsa,
/* TODO: check key type and size with operation. */
(void)operation;

WP_CHECK_FIPS_ALGO(WP_CAST_ALGO_RSA);

if (rsa != ctx->rsa) {
wp_rsa_free(ctx->rsa);
ctx->rsa = NULL;
Expand Down
3 changes: 1 addition & 2 deletions src/wp_rsa_kmgmt.c
Original file line number Diff line number Diff line change
Expand Up @@ -1513,6 +1513,7 @@ static wp_Rsa* wp_rsa_gen(wp_RsaGenCtx* ctx, OSSL_CALLBACK* cb, void* cbArg)
(void)cbArg;

if (wolfssl_prov_is_running() && wp_rsagen_check_key_size(ctx)) {
WP_CHECK_FIPS_ALGO_PTR(WP_CAST_ALGO_RSA);
rsa = wp_rsa_base_new(ctx->provCtx, ctx->type);
if (rsa != NULL) {
/* wolfCrypt FIPS RSA keygen has a small chance it simply will not
Expand Down Expand Up @@ -2236,7 +2237,6 @@ static int wp_rsa_decode_spki(wp_Rsa* rsa, unsigned char* data, word32 len)
if (!wolfssl_prov_is_running()) {
ok = 0;
}

if (ok) {
rc = wc_RsaPublicKeyDecode(data, &idx, &rsa->key, len);
if (rc != 0) {
Expand Down Expand Up @@ -2283,7 +2283,6 @@ static int wp_rsa_decode_pki(wp_Rsa* rsa, unsigned char* data, word32 len)
if (!wolfssl_prov_is_running()) {
ok = 0;
}

if (ok) {
rc = wc_RsaPrivateKeyDecode(data, &idx, &rsa->key, len);
if (rc != 0) {
Expand Down
Loading
Loading