diff --git a/src/misc_impl.c b/src/misc_impl.c new file mode 100644 index 0000000..b3c64e7 --- /dev/null +++ b/src/misc_impl.c @@ -0,0 +1,15 @@ +/* misc_impl.c + * + * Provide misc.c helper implementations for NO_INLINE builds. + */ + +#ifdef HAVE_CONFIG_H + #include +#endif + +#include + +#if defined(WOLFSSL_PSA_ENGINE) && defined(NO_INLINE) + #define WOLFSSL_MISC_INCLUDED + #include +#endif diff --git a/src/psa_aead.c b/src/psa_aead.c index 42990ab..9ef5222 100644 --- a/src/psa_aead.c +++ b/src/psa_aead.c @@ -66,12 +66,18 @@ static psa_status_t wolfpsa_aead_append(uint8_t **buf, size_t *len, { uint8_t *new_buf; + if (buf == NULL || len == NULL) { + return PSA_ERROR_INVALID_ARGUMENT; + } if (data == NULL && data_length > 0) { return PSA_ERROR_INVALID_ARGUMENT; } if (data_length == 0) { return PSA_SUCCESS; } + if (*len > SIZE_MAX - data_length) { + return PSA_ERROR_INSUFFICIENT_MEMORY; + } new_buf = (uint8_t *)XMALLOC(*len + data_length, NULL, DYNAMIC_TYPE_TMP_BUFFER); @@ -81,6 +87,7 @@ static psa_status_t wolfpsa_aead_append(uint8_t **buf, size_t *len, if (*buf != NULL) { XMEMCPY(new_buf, *buf, *len); + wc_ForceZero(*buf, *len); XFREE(*buf, NULL, DYNAMIC_TYPE_TMP_BUFFER); } @@ -124,8 +131,7 @@ static psa_status_t wolfpsa_aead_check_key(psa_key_id_t key, } } else if (PSA_ALG_AEAD_EQUAL(alg, PSA_ALG_CHACHA20_POLY1305)) { - if (attributes->type != PSA_KEY_TYPE_CHACHA20 && - attributes->type != PSA_KEY_TYPE_AES) { + if (attributes->type != PSA_KEY_TYPE_CHACHA20) { wolfpsa_free_key_data(*key_data); *key_data = NULL; *key_data_length = 0; @@ -859,6 +865,7 @@ psa_status_t psa_aead_abort(psa_aead_operation_t *operation) XFREE(ctx->input, NULL, DYNAMIC_TYPE_TMP_BUFFER); } if (ctx->key != NULL) { + wc_ForceZero(ctx->key, ctx->key_length); XFREE(ctx->key, NULL, DYNAMIC_TYPE_TMP_BUFFER); } XFREE(ctx, NULL, DYNAMIC_TYPE_TMP_BUFFER); diff --git a/src/psa_ed25519_ed448.c b/src/psa_ed25519_ed448.c index a573321..cb85617 100644 --- a/src/psa_ed25519_ed448.c +++ b/src/psa_ed25519_ed448.c @@ -59,6 +59,7 @@ psa_status_t psa_asymmetric_sign_ed25519(psa_key_type_t key_type, { int ret; ed25519_key ed_key; + word32 sig_len32; if (alg != PSA_ALG_ED25519 && alg != PSA_ALG_ED25519PH) { return PSA_ERROR_NOT_SUPPORTED; @@ -85,15 +86,16 @@ psa_status_t psa_asymmetric_sign_ed25519(psa_key_type_t key_type, } /* Sign message */ + sig_len32 = (word32)signature_size; if (alg == PSA_ALG_ED25519PH) { /* Sign hash */ ret = wc_ed25519ph_sign_hash(hash, (word32)hash_length, signature, - (word32*)signature_length, &ed_key, NULL, 0); + &sig_len32, &ed_key, NULL, 0); } else if (alg == PSA_ALG_ED25519) { /* Sign message */ ret = wc_ed25519_sign_msg(hash, (word32)hash_length, signature, - (word32*)signature_length, &ed_key); + &sig_len32, &ed_key); } wc_ed25519_free(&ed_key); @@ -101,6 +103,8 @@ psa_status_t psa_asymmetric_sign_ed25519(psa_key_type_t key_type, if (ret != 0) { return wc_error_to_psa_status(ret); } + + *signature_length = (size_t)sig_len32; return PSA_SUCCESS; } @@ -184,6 +188,8 @@ psa_status_t psa_asymmetric_generate_key_ed25519(psa_key_type_t key_type, int ret; ed25519_key ed_key; WC_RNG rng; + word32 priv_len32; + word32 pub_len32; /* Check if key type is ED25519 key pair */ if (key_type != PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_TWISTED_EDWARDS) || @@ -213,7 +219,8 @@ psa_status_t psa_asymmetric_generate_key_ed25519(psa_key_type_t key_type, } /* Export private key */ - ret = wc_ed25519_export_private_only(&ed_key, private_key, (word32*)private_key_length); + priv_len32 = (word32)private_key_size; + ret = wc_ed25519_export_private_only(&ed_key, private_key, &priv_len32); if (ret != 0) { wc_FreeRng(&rng); wc_ed25519_free(&ed_key); @@ -221,7 +228,8 @@ psa_status_t psa_asymmetric_generate_key_ed25519(psa_key_type_t key_type, } /* Export public key */ - ret = wc_ed25519_export_public(&ed_key, public_key, (word32*)public_key_length); + pub_len32 = (word32)public_key_size; + ret = wc_ed25519_export_public(&ed_key, public_key, &pub_len32); if (ret != 0) { wc_FreeRng(&rng); wc_ed25519_free(&ed_key); @@ -230,6 +238,9 @@ psa_status_t psa_asymmetric_generate_key_ed25519(psa_key_type_t key_type, wc_FreeRng(&rng); wc_ed25519_free(&ed_key); + + *private_key_length = (size_t)priv_len32; + *public_key_length = (size_t)pub_len32; return PSA_SUCCESS; } @@ -245,6 +256,7 @@ psa_status_t psa_asymmetric_export_public_key_ed25519(psa_key_type_t key_type, { int ret; ed25519_key ed_key; + word32 out_len32; /* Check if key type is ED25519 */ if ((key_type != PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_TWISTED_EDWARDS) && @@ -274,13 +286,16 @@ psa_status_t psa_asymmetric_export_public_key_ed25519(psa_key_type_t key_type, } /* Export public key */ - ret = wc_ed25519_export_public(&ed_key, output, (word32*)output_length); + out_len32 = (word32)output_size; + ret = wc_ed25519_export_public(&ed_key, output, &out_len32); wc_ed25519_free(&ed_key); if (ret != 0) { return wc_error_to_psa_status(ret); } + + *output_length = (size_t)out_len32; return PSA_SUCCESS; } @@ -301,6 +316,7 @@ psa_status_t psa_asymmetric_sign_ed448(psa_key_type_t key_type, { int ret; ed448_key ed_key; + word32 sig_len32; if (alg != PSA_ALG_ED448 && alg != PSA_ALG_ED448PH) { return PSA_ERROR_NOT_SUPPORTED; @@ -327,15 +343,16 @@ psa_status_t psa_asymmetric_sign_ed448(psa_key_type_t key_type, } /* Sign message */ + sig_len32 = (word32)signature_size; if (alg == PSA_ALG_ED448PH) { /* Sign hash */ ret = wc_ed448ph_sign_hash(hash, (word32)hash_length, signature, - (word32*)signature_length, &ed_key, NULL, 0); + &sig_len32, &ed_key, NULL, 0); } else if (alg == PSA_ALG_ED448) { /* Sign message */ ret = wc_ed448_sign_msg(hash, (word32)hash_length, signature, - (word32*)signature_length, &ed_key, NULL, 0); + &sig_len32, &ed_key, NULL, 0); } wc_ed448_free(&ed_key); @@ -343,6 +360,8 @@ psa_status_t psa_asymmetric_sign_ed448(psa_key_type_t key_type, if (ret != 0) { return wc_error_to_psa_status(ret); } + + *signature_length = (size_t)sig_len32; return PSA_SUCCESS; } @@ -426,6 +445,8 @@ psa_status_t psa_asymmetric_generate_key_ed448(psa_key_type_t key_type, int ret; ed448_key ed_key; WC_RNG rng; + word32 priv_len32; + word32 pub_len32; /* Check if key type is ED448 key pair */ if (key_type != PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_TWISTED_EDWARDS) || @@ -455,7 +476,8 @@ psa_status_t psa_asymmetric_generate_key_ed448(psa_key_type_t key_type, } /* Export private key */ - ret = wc_ed448_export_private_only(&ed_key, private_key, (word32*)private_key_length); + priv_len32 = (word32)private_key_size; + ret = wc_ed448_export_private_only(&ed_key, private_key, &priv_len32); if (ret != 0) { wc_FreeRng(&rng); wc_ed448_free(&ed_key); @@ -463,7 +485,8 @@ psa_status_t psa_asymmetric_generate_key_ed448(psa_key_type_t key_type, } /* Export public key */ - ret = wc_ed448_export_public(&ed_key, public_key, (word32*)public_key_length); + pub_len32 = (word32)public_key_size; + ret = wc_ed448_export_public(&ed_key, public_key, &pub_len32); if (ret != 0) { wc_FreeRng(&rng); wc_ed448_free(&ed_key); @@ -472,6 +495,9 @@ psa_status_t psa_asymmetric_generate_key_ed448(psa_key_type_t key_type, wc_FreeRng(&rng); wc_ed448_free(&ed_key); + + *private_key_length = (size_t)priv_len32; + *public_key_length = (size_t)pub_len32; return PSA_SUCCESS; } @@ -487,6 +513,7 @@ psa_status_t psa_asymmetric_export_public_key_ed448(psa_key_type_t key_type, { int ret; ed448_key ed_key; + word32 out_len32; /* Check if key type is ED448 */ if ((key_type != PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_TWISTED_EDWARDS) && @@ -516,13 +543,16 @@ psa_status_t psa_asymmetric_export_public_key_ed448(psa_key_type_t key_type, } /* Export public key */ - ret = wc_ed448_export_public(&ed_key, output, (word32*)output_length); + out_len32 = (word32)output_size; + ret = wc_ed448_export_public(&ed_key, output, &out_len32); wc_ed448_free(&ed_key); if (ret != 0) { return wc_error_to_psa_status(ret); } + + *output_length = (size_t)out_len32; return PSA_SUCCESS; } diff --git a/src/psa_hash_engine.c b/src/psa_hash_engine.c index 55be777..c7aacd3 100644 --- a/src/psa_hash_engine.c +++ b/src/psa_hash_engine.c @@ -36,6 +36,11 @@ #include #include #include +#include +#ifndef NO_INLINE + #define WOLFSSL_MISC_INCLUDED + #include +#endif #ifdef WOLFSSL_MD5 #include @@ -642,7 +647,7 @@ psa_status_t psa_hash_verify(psa_hash_operation_t *operation, return PSA_ERROR_INVALID_SIGNATURE; } - if (XMEMCMP(computed_hash, hash, computed_hash_length) != 0) { + if (ConstantCompare(computed_hash, hash, (int)computed_hash_length) != 0) { return PSA_ERROR_INVALID_SIGNATURE; } @@ -865,7 +870,7 @@ psa_status_t psa_hash_compare(psa_algorithm_t alg, } /* Compare the computed hash with the reference hash */ - if (XMEMCMP(computed_hash, hash, computed_hash_length) != 0) { + if (ConstantCompare(computed_hash, hash, (int)computed_hash_length) != 0) { return PSA_ERROR_INVALID_SIGNATURE; } diff --git a/src/psa_key_derivation.c b/src/psa_key_derivation.c index 43a0c07..041543e 100644 --- a/src/psa_key_derivation.c +++ b/src/psa_key_derivation.c @@ -23,6 +23,7 @@ #include #endif +#include #include #if defined(WOLFSSL_PSA_ENGINE) @@ -36,6 +37,11 @@ #include #include #include +#include +#ifndef NO_INLINE + #define WOLFSSL_MISC_INCLUDED + #include +#endif typedef struct wolfpsa_kdf_ctx { psa_algorithm_t alg; @@ -82,6 +88,7 @@ static wolfpsa_kdf_ctx_t* wolfpsa_kdf_get_ctx(psa_key_derivation_operation_t *op static void wolfpsa_kdf_free_buf(uint8_t **buf, size_t *len) { if (buf != NULL && *buf != NULL) { + wc_ForceZero(*buf, len != NULL ? *len : 0); XFREE(*buf, NULL, DYNAMIC_TYPE_TMP_BUFFER); *buf = NULL; } @@ -95,6 +102,9 @@ static psa_status_t wolfpsa_kdf_append(uint8_t **buf, size_t *len, { uint8_t *new_buf; + if (buf == NULL || len == NULL) { + return PSA_ERROR_INVALID_ARGUMENT; + } if (data == NULL && data_length > 0) { return PSA_ERROR_INVALID_ARGUMENT; } @@ -102,6 +112,9 @@ static psa_status_t wolfpsa_kdf_append(uint8_t **buf, size_t *len, if (data_length == 0) { return PSA_SUCCESS; } + if (*len > SIZE_MAX - data_length) { + return PSA_ERROR_INSUFFICIENT_MEMORY; + } new_buf = (uint8_t *)XMALLOC(*len + data_length, NULL, DYNAMIC_TYPE_TMP_BUFFER); @@ -111,6 +124,7 @@ static psa_status_t wolfpsa_kdf_append(uint8_t **buf, size_t *len, if (*buf != NULL) { XMEMCPY(new_buf, *buf, *len); + wc_ForceZero(*buf, *len); XFREE(*buf, NULL, DYNAMIC_TYPE_TMP_BUFFER); } @@ -440,12 +454,13 @@ psa_status_t psa_key_derivation_set_capacity(psa_key_derivation_operation_t *ope psa_status_t psa_key_derivation_get_capacity(const psa_key_derivation_operation_t *operation, size_t *capacity) { - const wolfpsa_kdf_ctx_t *ctx = (const wolfpsa_kdf_ctx_t *)(uintptr_t)operation->opaque; + const wolfpsa_kdf_ctx_t *ctx; if (operation == NULL || capacity == NULL) { return PSA_ERROR_INVALID_ARGUMENT; } + ctx = (const wolfpsa_kdf_ctx_t *)(uintptr_t)operation->opaque; if (ctx == NULL) { return PSA_ERROR_BAD_STATE; } @@ -1094,17 +1109,25 @@ psa_status_t psa_key_derivation_verify_bytes(psa_key_derivation_operation_t *ope status = psa_key_derivation_output_bytes(operation, buffer, expected_length); if (status != PSA_SUCCESS) { + wc_ForceZero(buffer, expected_length); XFREE(buffer, NULL, DYNAMIC_TYPE_TMP_BUFFER); return status; } - if (XMEMCMP(buffer, expected, expected_length) != 0) { + if (expected_length > INT_MAX) { + wc_ForceZero(buffer, expected_length); + XFREE(buffer, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return PSA_ERROR_INVALID_ARGUMENT; + } + + if (ConstantCompare(buffer, expected, (int)expected_length) != 0) { status = PSA_ERROR_INVALID_SIGNATURE; } else { status = PSA_SUCCESS; } + wc_ForceZero(buffer, expected_length); XFREE(buffer, NULL, DYNAMIC_TYPE_TMP_BUFFER); return status; } diff --git a/src/psa_key_storage.c b/src/psa_key_storage.c index eafd5d2..469037b 100644 --- a/src/psa_key_storage.c +++ b/src/psa_key_storage.c @@ -1134,6 +1134,9 @@ psa_status_t psa_export_public_key( if (!PSA_KEY_TYPE_IS_RSA(attributes.type) && !PSA_KEY_TYPE_IS_ECC(attributes.type)) { + if (use_volatile) { + wolfpsa_free_key_data(key_data); + } return PSA_ERROR_INVALID_ARGUMENT; } diff --git a/src/psa_lms_xmss.c b/src/psa_lms_xmss.c index 1d7c367..045e650 100644 --- a/src/psa_lms_xmss.c +++ b/src/psa_lms_xmss.c @@ -50,6 +50,8 @@ psa_status_t psa_lms_generate_key(uint8_t *private_key, int ret; LmsKey key; WC_RNG rng; + word32 priv_len32; + word32 pub_len32; /* Initialize LMS key */ ret = wc_LmsKey_Init(&key, NULL, INVALID_DEVID); @@ -80,7 +82,8 @@ psa_status_t psa_lms_generate_key(uint8_t *private_key, } /* Export private key */ - ret = wc_LmsKey_ExportPrivate(&key, private_key, (word32*)private_key_length); + priv_len32 = (word32)private_key_size; + ret = wc_LmsKey_ExportPrivate(&key, private_key, &priv_len32); if (ret != 0) { wc_FreeRng(&rng); wc_LmsKey_Free(&key); @@ -88,7 +91,8 @@ psa_status_t psa_lms_generate_key(uint8_t *private_key, } /* Export public key */ - ret = wc_LmsKey_ExportPublic(&key, public_key, (word32*)public_key_length); + pub_len32 = (word32)public_key_size; + ret = wc_LmsKey_ExportPublic(&key, public_key, &pub_len32); if (ret != 0) { wc_FreeRng(&rng); wc_LmsKey_Free(&key); @@ -97,6 +101,9 @@ psa_status_t psa_lms_generate_key(uint8_t *private_key, wc_FreeRng(&rng); wc_LmsKey_Free(&key); + + *private_key_length = (size_t)priv_len32; + *public_key_length = (size_t)pub_len32; return PSA_SUCCESS; } @@ -112,6 +119,7 @@ psa_status_t psa_lms_sign(const uint8_t *private_key, { int ret; LmsKey key; + word32 sig_len32; /* Initialize LMS key */ ret = wc_LmsKey_Init(&key, NULL, INVALID_DEVID); @@ -127,7 +135,8 @@ psa_status_t psa_lms_sign(const uint8_t *private_key, } /* Sign message */ - ret = wc_LmsKey_Sign(&key, signature, (word32*)signature_length, + sig_len32 = (word32)signature_size; + ret = wc_LmsKey_Sign(&key, signature, &sig_len32, message, (word32)message_length); if (ret != 0) { wc_LmsKey_Free(&key); @@ -135,6 +144,8 @@ psa_status_t psa_lms_sign(const uint8_t *private_key, } wc_LmsKey_Free(&key); + + *signature_length = (size_t)sig_len32; return PSA_SUCCESS; } @@ -196,6 +207,8 @@ psa_status_t psa_xmss_generate_key(uint8_t *private_key, int ret; XmssKey key; WC_RNG rng; + word32 priv_len32; + word32 pub_len32; /* Initialize XMSS key */ ret = wc_XmssKey_Init(&key, NULL, INVALID_DEVID); @@ -226,7 +239,8 @@ psa_status_t psa_xmss_generate_key(uint8_t *private_key, } /* Export private key */ - ret = wc_XmssKey_ExportPrivate(&key, private_key, (word32*)private_key_length); + priv_len32 = (word32)private_key_size; + ret = wc_XmssKey_ExportPrivate(&key, private_key, &priv_len32); if (ret != 0) { wc_FreeRng(&rng); wc_XmssKey_Free(&key); @@ -234,7 +248,8 @@ psa_status_t psa_xmss_generate_key(uint8_t *private_key, } /* Export public key */ - ret = wc_XmssKey_ExportPublic(&key, public_key, (word32*)public_key_length); + pub_len32 = (word32)public_key_size; + ret = wc_XmssKey_ExportPublic(&key, public_key, &pub_len32); if (ret != 0) { wc_FreeRng(&rng); wc_XmssKey_Free(&key); @@ -243,6 +258,9 @@ psa_status_t psa_xmss_generate_key(uint8_t *private_key, wc_FreeRng(&rng); wc_XmssKey_Free(&key); + + *private_key_length = (size_t)priv_len32; + *public_key_length = (size_t)pub_len32; return PSA_SUCCESS; } @@ -258,6 +276,7 @@ psa_status_t psa_xmss_sign(const uint8_t *private_key, { int ret; XmssKey key; + word32 sig_len32; /* Initialize XMSS key */ ret = wc_XmssKey_Init(&key, NULL, INVALID_DEVID); @@ -273,7 +292,8 @@ psa_status_t psa_xmss_sign(const uint8_t *private_key, } /* Sign message */ - ret = wc_XmssKey_Sign(&key, signature, (word32*)signature_length, + sig_len32 = (word32)signature_size; + ret = wc_XmssKey_Sign(&key, signature, &sig_len32, message, (word32)message_length); if (ret != 0) { wc_XmssKey_Free(&key); @@ -281,6 +301,8 @@ psa_status_t psa_xmss_sign(const uint8_t *private_key, } wc_XmssKey_Free(&key); + + *signature_length = (size_t)sig_len32; return PSA_SUCCESS; } diff --git a/src/psa_mac.c b/src/psa_mac.c index af6da24..3f51ea4 100644 --- a/src/psa_mac.c +++ b/src/psa_mac.c @@ -33,6 +33,11 @@ #include #include #include +#include +#ifndef NO_INLINE + #define WOLFSSL_MISC_INCLUDED + #include +#endif typedef enum { WOLFPSA_MAC_NONE = 0, @@ -451,7 +456,7 @@ psa_status_t psa_mac_verify_finish(psa_mac_operation_t *operation, return PSA_ERROR_INVALID_SIGNATURE; } - if (XMEMCMP(computed, mac, mac_length) != 0) { + if (ConstantCompare(computed, mac, (int)mac_length) != 0) { return PSA_ERROR_INVALID_SIGNATURE; } diff --git a/src/psa_mldsa.c b/src/psa_mldsa.c index d0a329d..24c843b 100644 --- a/src/psa_mldsa.c +++ b/src/psa_mldsa.c @@ -65,6 +65,8 @@ psa_status_t psa_ml_dsa_generate_key(psa_ml_dsa_parameter_t parameter, dilithium_key key; int type; WC_RNG rng; + word32 priv_len; + word32 pub_len; /* Convert parameter to wolfCrypt key type */ type = psa_ml_dsa_parameter_to_type(parameter); @@ -93,20 +95,23 @@ psa_status_t psa_ml_dsa_generate_key(psa_ml_dsa_parameter_t parameter, return wc_error_to_psa_status(ret); } - /* Check buffer sizes */ - if (private_key_size < key.priv_key_len || public_key_size < key.pub_key_len) { + priv_len = (word32)private_key_size; + ret = wc_dilithium_export_private(&key, private_key, &priv_len); + if (ret != 0) { wc_FreeRng(&rng); wc_dilithium_free(&key); - return PSA_ERROR_BUFFER_TOO_SMALL; + return wc_error_to_psa_status(ret); } - - /* Export private key */ - XMEMCPY(private_key, key.k, key.priv_key_len); - *private_key_length = key.priv_key_len; - - /* Export public key */ - XMEMCPY(public_key, key.p, key.pub_key_len); - *public_key_length = key.pub_key_len; + + pub_len = (word32)public_key_size; + ret = wc_dilithium_export_public(&key, public_key, &pub_len); + if (ret != 0) { + wc_FreeRng(&rng); + wc_dilithium_free(&key); + return wc_error_to_psa_status(ret); + } + *private_key_length = priv_len; + *public_key_length = pub_len; wc_FreeRng(&rng); wc_dilithium_free(&key); diff --git a/src/psa_pq.c b/src/psa_pq.c index 9668364..0128fef 100644 --- a/src/psa_pq.c +++ b/src/psa_pq.c @@ -52,6 +52,7 @@ psa_status_t psa_pq_check_key_type_supported(psa_key_type_t type) #endif #if defined(WOLFSSL_HAVE_LMS) && defined(PSA_KEY_TYPE_LMS_KEY_PAIR) case PSA_KEY_TYPE_LMS_KEY_PAIR: + return PSA_SUCCESS; #endif #if defined(WOLFSSL_HAVE_LMS) && defined(PSA_KEY_TYPE_LMS_PUBLIC_KEY) case PSA_KEY_TYPE_LMS_PUBLIC_KEY: @@ -59,6 +60,7 @@ psa_status_t psa_pq_check_key_type_supported(psa_key_type_t type) #endif #if defined(WOLFSSL_HAVE_XMSS) && defined(PSA_KEY_TYPE_XMSS_KEY_PAIR) case PSA_KEY_TYPE_XMSS_KEY_PAIR: + return PSA_SUCCESS; #endif #if defined(WOLFSSL_HAVE_XMSS) && defined(PSA_KEY_TYPE_XMSS_PUBLIC_KEY) case PSA_KEY_TYPE_XMSS_PUBLIC_KEY: @@ -96,6 +98,8 @@ psa_status_t psa_pq_check_key_size_valid(psa_key_type_t type, size_t bits) #endif #if defined(WOLFSSL_HAVE_LMS) && defined(PSA_KEY_TYPE_LMS_KEY_PAIR) case PSA_KEY_TYPE_LMS_KEY_PAIR: + /* LMS doesn't have specific key sizes in the same way */ + return PSA_SUCCESS; #endif #if defined(WOLFSSL_HAVE_LMS) && defined(PSA_KEY_TYPE_LMS_PUBLIC_KEY) case PSA_KEY_TYPE_LMS_PUBLIC_KEY: @@ -104,6 +108,8 @@ psa_status_t psa_pq_check_key_size_valid(psa_key_type_t type, size_t bits) #endif #if defined(WOLFSSL_HAVE_XMSS) && defined(PSA_KEY_TYPE_XMSS_KEY_PAIR) case PSA_KEY_TYPE_XMSS_KEY_PAIR: + /* XMSS doesn't have specific key sizes in the same way */ + return PSA_SUCCESS; #endif #if defined(WOLFSSL_HAVE_XMSS) && defined(PSA_KEY_TYPE_XMSS_PUBLIC_KEY) case PSA_KEY_TYPE_XMSS_PUBLIC_KEY: diff --git a/src/psa_rsa.c b/src/psa_rsa.c index 1cc85d3..5b2b09c 100644 --- a/src/psa_rsa.c +++ b/src/psa_rsa.c @@ -35,8 +35,13 @@ #include #include #include +#include #include #include +#ifndef NO_INLINE + #define WOLFSSL_MISC_INCLUDED + #include +#endif int wc_psa_get_rsa_padding(psa_algorithm_t alg); int wc_psa_get_hash_type(psa_algorithm_t alg); @@ -63,6 +68,31 @@ static int wc_psa_get_mgf(int hash_type) } } +#ifdef WC_RSA_PSS +static int wc_psa_rsa_pss_check_padding(const byte* hash, word32 hash_length, + const byte* encoded, word32 encoded_length, + int hash_type, int salt_len, + RsaKey* rsa_key) +{ +#if (defined(HAVE_SELFTEST) && \ + (!defined(HAVE_SELFTEST_VERSION) || (HAVE_SELFTEST_VERSION < 2))) || \ + (defined(HAVE_FIPS) && defined(HAVE_FIPS_VERSION) && \ + (HAVE_FIPS_VERSION < 2)) + return wc_RsaPSS_CheckPadding_ex(hash, hash_length, encoded, + encoded_length, hash_type, salt_len); +#elif (defined(HAVE_SELFTEST) && (HAVE_SELFTEST_VERSION == 2)) || \ + (defined(HAVE_FIPS) && defined(HAVE_FIPS_VERSION) && \ + (HAVE_FIPS_VERSION == 2)) + return wc_RsaPSS_CheckPadding_ex(hash, hash_length, encoded, + encoded_length, hash_type, salt_len, 0); +#else + return wc_RsaPSS_CheckPadding_ex2(hash, hash_length, encoded, + encoded_length, hash_type, salt_len, + mp_count_bits(&rsa_key->n), NULL); +#endif +} +#endif + /* Sign a hash or short message with an RSA private key */ psa_status_t psa_asymmetric_sign_rsa(psa_key_type_t key_type, size_t key_bits, @@ -150,7 +180,7 @@ psa_status_t psa_asymmetric_sign_rsa(psa_key_type_t key_type, #ifdef WC_RSA_PSS ret = wc_RsaPSS_Sign(hash, (word32)hash_length, signature, (word32)signature_size, hash_type, - WC_MGF1NONE, &rsa_key, &rng); + wc_psa_get_mgf(hash_type), &rsa_key, &rng); #else ret = NOT_COMPILED_IN; #endif @@ -244,14 +274,14 @@ psa_status_t psa_asymmetric_verify_rsa(psa_key_type_t key_type, if (ret > 0) { if ((size_t)ret != hash_length || - XMEMCMP(decoded, hash, hash_length) != 0) { + ConstantCompare(decoded, hash, (int)hash_length) != 0) { ret = SIG_VERIFY_E; } } } else if (padding == WC_RSA_PSS_PAD) { #ifdef WC_RSA_PSS - byte decoded[PSA_HASH_MAX_SIZE]; + byte decoded[RSA_MAX_SIZE/8]; int salt_len = RSA_PSS_SALT_LEN_DEFAULT; #ifdef WOLFSSL_PSS_SALT_LEN_DISCOVER @@ -268,11 +298,14 @@ psa_status_t psa_asymmetric_verify_rsa(psa_key_type_t key_type, ret = wc_RsaPSS_Verify_ex(signature, (word32)signature_length, decoded, (word32)sizeof(decoded), - hash_type, WC_MGF1NONE, salt_len, &rsa_key); + hash_type, wc_psa_get_mgf(hash_type), + salt_len, &rsa_key); if (ret > 0) { - if ((size_t)ret != hash_length || - XMEMCMP(decoded, hash, hash_length) != 0) { - ret = SIG_VERIFY_E; + ret = wc_psa_rsa_pss_check_padding(hash, (word32)hash_length, + decoded, (word32)ret, + hash_type, salt_len, &rsa_key); + if (ret == 0) { + ret = (int)hash_length; } } #else diff --git a/test/Makefile b/test/Makefile index 46e7bf9..1e85e69 100644 --- a/test/Makefile +++ b/test/Makefile @@ -55,13 +55,14 @@ WOLFSSL_LOCAL_SYMBOLS := $(if $(WOLFSSL_LOCAL_LIB),$(shell \ $(NM) $(WOLFSSL_LOCAL_LIB) 2>/dev/null)) WOLFSSL_HAS_PSA_TLS := $(findstring wolfSSL_CTX_psa_enable,$(WOLFSSL_LOCAL_SYMBOLS)) -BINARIES = psa_api_test psa_tls_client wolfcrypt-psa-benchmark +BINARIES = psa_api_test psa_rsa_pss_interop_test psa_tls_client wolfcrypt-psa-benchmark ifdef WOLFSSL_HAS_PSA_TLS BINARIES += psa_tls_server endif PSA_API_TEST_OBJS = psa_server/psa_api_test.o +PSA_RSA_PSS_TEST_OBJS = psa_server/psa_rsa_pss_interop_test.o .PHONY: all clean rebuild-wolfssl-psa require-wolfssl-lib @@ -77,6 +78,9 @@ endif psa_api_test: require-wolfssl-lib $(PSA_API_TEST_OBJS) $(CC) $(CFLAGS) -o $@ $(PSA_API_TEST_OBJS) $(LDFLAGS) $(LDLIBS) $(RPATH_WOLFPSA) $(RPATH_WOLFSSL) +psa_rsa_pss_interop_test: require-wolfssl-lib $(PSA_RSA_PSS_TEST_OBJS) + $(CC) $(CFLAGS) -o $@ $(PSA_RSA_PSS_TEST_OBJS) $(LDFLAGS) $(LDLIBS) $(RPATH_WOLFPSA) $(RPATH_WOLFSSL) + ifdef WOLFSSL_HAS_PSA_TLS psa_tls_server: psa_server/psa_tls_server.o $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) $(LDLIBS) $(RPATH_WOLFPSA) $(RPATH_WOLFSSL) diff --git a/test/psa_server/psa_api_test.c b/test/psa_server/psa_api_test.c index da263ce..da19dea 100644 --- a/test/psa_server/psa_api_test.c +++ b/test/psa_server/psa_api_test.c @@ -27,9 +27,13 @@ #define TEST_OK 0 #define TEST_FAIL 1 +#define TEST_SKIPPED 2 typedef int (*test_fn_t)(void); +static int tests_passed = 0; +static int tests_skipped = 0; + static int check_status(psa_status_t st, const char* what) { if (st != PSA_SUCCESS) { @@ -298,6 +302,57 @@ static int test_aead_gcm(void) return TEST_OK; } +static int test_chacha20_poly1305_rejects_aes_key(void) +{ + static const uint8_t key[32] = { + 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, + 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f, + 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17, + 0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f + }; + static const uint8_t nonce[12] = { + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00 + }; + static const uint8_t plaintext[16] = { + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 + }; + uint8_t out[sizeof(plaintext) + 16]; + size_t out_len = 0; + psa_key_id_t key_id = 0; + psa_key_attributes_t attrs = psa_key_attributes_init(); + psa_status_t st; + + psa_set_key_type(&attrs, PSA_KEY_TYPE_AES); + psa_set_key_bits(&attrs, 256); + psa_set_key_usage_flags(&attrs, PSA_KEY_USAGE_ENCRYPT); + psa_set_key_algorithm(&attrs, PSA_ALG_GCM); + + /* + * Import a valid AES AEAD key first, then prove that the ChaCha20-Poly1305 + * path rejects it when the operation algorithm does not match the key type. + */ + st = psa_import_key(&attrs, key, sizeof(key), &key_id); + if (check_status(st, "psa_import_key(AES for GCM)") != TEST_OK) return TEST_FAIL; + + st = psa_aead_encrypt(key_id, PSA_ALG_CHACHA20_POLY1305, + nonce, sizeof(nonce), + NULL, 0, + plaintext, sizeof(plaintext), + out, sizeof(out), &out_len); + if (check_true(st == PSA_ERROR_INVALID_ARGUMENT, + "psa_aead_encrypt(AES key with ChaCha20) rejected") != TEST_OK) { + (void)psa_destroy_key(key_id); + return TEST_FAIL; + } + + st = psa_destroy_key(key_id); + if (check_status(st, "psa_destroy_key(AES for GCM)") != TEST_OK) return TEST_FAIL; + + return TEST_OK; +} + static int test_asym_ecc(void) { static const uint8_t msg[] = "psa ecc sign"; @@ -388,10 +443,96 @@ static int test_asym_ecc(void) return TEST_OK; } +static int test_ed25519_signature_length(void) +{ + static const uint8_t hash[64] = { + 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, + 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f, + 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17, + 0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f, + 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27, + 0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f, + 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37, + 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f + }; + uint8_t sig[128]; + /* + * The original bug cast `size_t*` to `word32*`. On 64-bit builds that can + * update only the low 32 bits, leaving the upper 32 bits stale. Seed + * `sig_len` with the low half clear and the upper half all ones so a + * truncated store becomes a large non-64 value instead of accidentally + * looking correct. + */ + size_t sig_len = ~((size_t)UINT32_MAX); + psa_key_id_t key_id = 0; + psa_key_attributes_t attrs = psa_key_attributes_init(); + psa_status_t st; + + psa_set_key_type(&attrs, PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_TWISTED_EDWARDS)); + psa_set_key_bits(&attrs, 255); + psa_set_key_usage_flags(&attrs, + PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_VERIFY_HASH); + psa_set_key_algorithm(&attrs, PSA_ALG_ED25519PH); + + st = psa_generate_key(&attrs, &key_id); + if (st == PSA_ERROR_NOT_SUPPORTED) { + return TEST_SKIPPED; + } + if (check_status(st, "psa_generate_key(ED25519)") != TEST_OK) return TEST_FAIL; + + st = psa_sign_hash(key_id, PSA_ALG_ED25519PH, + hash, sizeof(hash), + sig, sizeof(sig), &sig_len); + if (check_status(st, "psa_sign_hash(ED25519PH)") != TEST_OK) { + (void)psa_destroy_key(key_id); + return TEST_FAIL; + } + if (check_true(sig_len == 64u, "psa_sign_hash(ED25519PH) length") != TEST_OK) { + (void)psa_destroy_key(key_id); + return TEST_FAIL; + } + + st = psa_verify_hash(key_id, PSA_ALG_ED25519PH, + hash, sizeof(hash), sig, sig_len); + if (check_status(st, "psa_verify_hash(ED25519PH)") != TEST_OK) { + (void)psa_destroy_key(key_id); + return TEST_FAIL; + } + + st = psa_destroy_key(key_id); + if (check_status(st, "psa_destroy_key(ED25519)") != TEST_OK) return TEST_FAIL; + + return TEST_OK; +} + +static int test_kdf_null_capacity(void) +{ + size_t capacity = 0; + psa_status_t st; + + st = psa_key_derivation_get_capacity(NULL, &capacity); + if (check_true(st == PSA_ERROR_INVALID_ARGUMENT, + "psa_key_derivation_get_capacity(NULL)") != TEST_OK) { + return TEST_FAIL; + } + + return TEST_OK; +} + static int run_named_test(const char* name, test_fn_t fn) { + int ret; + fprintf(stderr, "RUN %s\n", name); - return fn(); + ret = fn(); + if (ret == TEST_OK) { + tests_passed++; + } + else if (ret == TEST_SKIPPED) { + tests_skipped++; + fprintf(stderr, "SKIP %s\n", name); + } + return ret; } int main(int argc, char** argv) @@ -403,24 +544,39 @@ int main(int argc, char** argv) if (check_status(st, "psa_crypto_init") != TEST_OK) return TEST_FAIL; if (only == NULL || strcmp(only, "random") == 0) { - if (run_named_test("random", test_random) != TEST_OK) return TEST_FAIL; + if (run_named_test("random", test_random) == TEST_FAIL) return TEST_FAIL; } if (only == NULL || strcmp(only, "hash") == 0) { - if (run_named_test("hash", test_hash) != TEST_OK) return TEST_FAIL; + if (run_named_test("hash", test_hash) == TEST_FAIL) return TEST_FAIL; } if (only == NULL || strcmp(only, "hmac") == 0) { - if (run_named_test("hmac", test_hmac) != TEST_OK) return TEST_FAIL; + if (run_named_test("hmac", test_hmac) == TEST_FAIL) return TEST_FAIL; } if (only == NULL || strcmp(only, "cipher_cbc") == 0) { - if (run_named_test("cipher_cbc", test_cipher_cbc) != TEST_OK) return TEST_FAIL; + if (run_named_test("cipher_cbc", test_cipher_cbc) == TEST_FAIL) return TEST_FAIL; } if (only == NULL || strcmp(only, "aead_gcm") == 0) { - if (run_named_test("aead_gcm", test_aead_gcm) != TEST_OK) return TEST_FAIL; + if (run_named_test("aead_gcm", test_aead_gcm) == TEST_FAIL) return TEST_FAIL; + } + if (only == NULL || strcmp(only, "chacha20_aes_reject") == 0) { + if (run_named_test("chacha20_aes_reject", + test_chacha20_poly1305_rejects_aes_key) == TEST_FAIL) { + return TEST_FAIL; + } } if (only == NULL || strcmp(only, "asym_ecc") == 0) { - if (run_named_test("asym_ecc", test_asym_ecc) != TEST_OK) return TEST_FAIL; + if (run_named_test("asym_ecc", test_asym_ecc) == TEST_FAIL) return TEST_FAIL; + } + if (only == NULL || strcmp(only, "ed25519_sig_len") == 0) { + if (run_named_test("ed25519_sig_len", test_ed25519_signature_length) == TEST_FAIL) { + return TEST_FAIL; + } + } + if (only == NULL || strcmp(only, "kdf_null_capacity") == 0) { + if (run_named_test("kdf_null_capacity", test_kdf_null_capacity) == TEST_FAIL) return TEST_FAIL; } - printf("PSA API test: OK\n"); + printf("PSA API test: OK (passed=%d skipped=%d)\n", + tests_passed, tests_skipped); return TEST_OK; } diff --git a/test/psa_server/psa_rsa_pss_interop_test.c b/test/psa_server/psa_rsa_pss_interop_test.c new file mode 100644 index 0000000..692d859 --- /dev/null +++ b/test/psa_server/psa_rsa_pss_interop_test.c @@ -0,0 +1,211 @@ +#include + +#include +#include +#include + +#include + +#include +#include + +#ifndef INVALID_DEVID +#define INVALID_DEVID -2 +#endif + +#define WOLFSSL_CERTS_DIR "../../wolfssl/certs" +#define RSA_PRIVATE_KEY_PATH WOLFSSL_CERTS_DIR "/server-key.der" + +static int load_file(const char* path, uint8_t** data, size_t* len) +{ + FILE* f; + long size; + uint8_t* buf; + + if (data == NULL || len == NULL) { + return -1; + } + + f = fopen(path, "rb"); + if (f == NULL) { + return -1; + } + if (fseek(f, 0, SEEK_END) != 0) { + fclose(f); + return -1; + } + size = ftell(f); + if (size < 0) { + fclose(f); + return -1; + } + rewind(f); + + buf = (uint8_t*)malloc((size_t)size); + if (buf == NULL) { + fclose(f); + return -1; + } + if (fread(buf, 1, (size_t)size, f) != (size_t)size) { + free(buf); + fclose(f); + return -1; + } + fclose(f); + + *data = buf; + *len = (size_t)size; + return 0; +} + +static int check_status(const char* what, psa_status_t st) +{ + if (st != PSA_SUCCESS) { + printf("FAIL: %s (status=%d)\n", what, (int)st); + return 1; + } + return 0; +} + +static int check_pss_padding(const uint8_t* hash, size_t hash_len, + const uint8_t* encoded, size_t encoded_len, + RsaKey* rsa_key) +{ +#if (defined(HAVE_SELFTEST) && \ + (!defined(HAVE_SELFTEST_VERSION) || (HAVE_SELFTEST_VERSION < 2))) || \ + (defined(HAVE_FIPS) && defined(HAVE_FIPS_VERSION) && \ + (HAVE_FIPS_VERSION < 2)) + return wc_RsaPSS_CheckPadding_ex(hash, (word32)hash_len, encoded, + (word32)encoded_len, + WC_HASH_TYPE_SHA256, + RSA_PSS_SALT_LEN_DEFAULT); +#elif (defined(HAVE_SELFTEST) && (HAVE_SELFTEST_VERSION == 2)) || \ + (defined(HAVE_FIPS) && defined(HAVE_FIPS_VERSION) && \ + (HAVE_FIPS_VERSION == 2)) + return wc_RsaPSS_CheckPadding_ex(hash, (word32)hash_len, encoded, + (word32)encoded_len, + WC_HASH_TYPE_SHA256, + RSA_PSS_SALT_LEN_DEFAULT, 0); +#else + return wc_RsaPSS_CheckPadding_ex2(hash, (word32)hash_len, encoded, + (word32)encoded_len, + WC_HASH_TYPE_SHA256, + RSA_PSS_SALT_LEN_DEFAULT, + wc_RsaEncryptSize(rsa_key) * 8, NULL); +#endif +} + +int main(void) +{ +#ifndef WC_RSA_PSS + puts("SKIP: WC_RSA_PSS not enabled"); + return 0; +#else + static const uint8_t hash[32] = { + 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, + 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f, + 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17, + 0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f + }; + psa_key_attributes_t priv_attrs = psa_key_attributes_init(); + psa_key_id_t priv_key = 0; + uint8_t* priv_der = NULL; + size_t priv_der_len = 0; + uint8_t psa_sig[256]; + size_t psa_sig_len = 0; + byte wc_sig[256]; + int wc_sig_len; + byte decoded[256]; + RsaKey rsa_key; + WC_RNG rng; + word32 idx = 0; + int ret; + psa_status_t st; + + st = psa_crypto_init(); + if (check_status("psa_crypto_init", st) != 0) return 1; + + if (load_file(RSA_PRIVATE_KEY_PATH, &priv_der, &priv_der_len) != 0) { + printf("FAIL: load %s\n", RSA_PRIVATE_KEY_PATH); + return 1; + } + psa_set_key_type(&priv_attrs, PSA_KEY_TYPE_RSA_KEY_PAIR); + psa_set_key_bits(&priv_attrs, 2048); + psa_set_key_usage_flags(&priv_attrs, + PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_VERIFY_HASH); + psa_set_key_algorithm(&priv_attrs, PSA_ALG_RSA_PSS(PSA_ALG_SHA_256)); + st = psa_import_key(&priv_attrs, priv_der, priv_der_len, &priv_key); + if (check_status("psa_import_key(private)", st) != 0) goto fail; + + ret = wc_InitRsaKey(&rsa_key, NULL); + if (ret != 0) { + printf("FAIL: wc_InitRsaKey (%d)\n", ret); + goto fail; + } + ret = wc_InitRng(&rng); + if (ret != 0) { + printf("FAIL: wc_InitRng (%d)\n", ret); + wc_FreeRsaKey(&rsa_key); + goto fail; + } + ret = wc_RsaPrivateKeyDecode(priv_der, &idx, &rsa_key, (word32)priv_der_len); + if (ret != 0) { + printf("FAIL: wc_RsaPrivateKeyDecode (%d)\n", ret); + wc_FreeRng(&rng); + wc_FreeRsaKey(&rsa_key); + goto fail; + } + + wc_sig_len = wc_RsaPSS_Sign(hash, (word32)sizeof(hash), wc_sig, (word32)sizeof(wc_sig), + WC_HASH_TYPE_SHA256, WC_MGF1SHA256, &rsa_key, &rng); + if (wc_sig_len <= 0) { + printf("FAIL: wc_RsaPSS_Sign (%d)\n", wc_sig_len); + wc_FreeRng(&rng); + wc_FreeRsaKey(&rsa_key); + goto fail; + } + + st = psa_verify_hash(priv_key, PSA_ALG_RSA_PSS(PSA_ALG_SHA_256), + hash, sizeof(hash), wc_sig, (size_t)wc_sig_len); + if (check_status("psa_verify_hash(private)", st) != 0) { + wc_FreeRng(&rng); + wc_FreeRsaKey(&rsa_key); + goto fail; + } + + st = psa_sign_hash(priv_key, PSA_ALG_RSA_PSS(PSA_ALG_SHA_256), + hash, sizeof(hash), psa_sig, sizeof(psa_sig), &psa_sig_len); + if (check_status("psa_sign_hash(private)", st) != 0) { + wc_FreeRng(&rng); + wc_FreeRsaKey(&rsa_key); + goto fail; + } + + ret = wc_RsaPSS_Verify_ex(psa_sig, (word32)psa_sig_len, decoded, + (word32)sizeof(decoded), WC_HASH_TYPE_SHA256, + WC_MGF1SHA256, RSA_PSS_SALT_LEN_DEFAULT, + &rsa_key); + if (ret <= 0 || + check_pss_padding(hash, sizeof(hash), decoded, (size_t)ret, + &rsa_key) != 0) { + printf("FAIL: wc_RsaPSS_Verify_ex mismatch (%d)\n", ret); + wc_FreeRng(&rng); + wc_FreeRsaKey(&rsa_key); + goto fail; + } + + wc_FreeRng(&rng); + wc_FreeRsaKey(&rsa_key); + (void)psa_destroy_key(priv_key); + free(priv_der); + puts("RSA-PSS interop: OK"); + return 0; + +fail: + if (priv_key != 0) { + (void)psa_destroy_key(priv_key); + } + free(priv_der); + return 1; +#endif +}