diff --git a/src/psa_aead.c b/src/psa_aead.c index d3c6451..0ba7e74 100644 --- a/src/psa_aead.c +++ b/src/psa_aead.c @@ -34,6 +34,7 @@ #include #include #include "psa_aead_internal.h" +#include "psa_size.h" static wolfpsa_aead_ctx_t* wolfpsa_aead_get_ctx(psa_aead_operation_t *operation) { @@ -475,6 +476,11 @@ static psa_status_t wolfpsa_aead_encrypt_final(wolfpsa_aead_ctx_t *ctx, return PSA_ERROR_BUFFER_TOO_SMALL; } + if ((wolfpsa_check_word32_length(ctx->input_length) != PSA_SUCCESS) || + (wolfpsa_check_word32_length(ctx->aad_length) != PSA_SUCCESS)) { + return PSA_ERROR_INVALID_ARGUMENT; + } + if (PSA_ALG_AEAD_EQUAL(ctx->alg, PSA_ALG_GCM)) { Aes aes; ret = wc_AesInit(&aes, NULL, INVALID_DEVID); @@ -575,6 +581,11 @@ static psa_status_t wolfpsa_aead_decrypt_final(wolfpsa_aead_ctx_t *ctx, return PSA_ERROR_INVALID_SIGNATURE; } + if ((wolfpsa_check_word32_length(ctx->input_length) != PSA_SUCCESS) || + (wolfpsa_check_word32_length(ctx->aad_length) != PSA_SUCCESS)) { + return PSA_ERROR_INVALID_ARGUMENT; + } + if (PSA_ALG_AEAD_EQUAL(ctx->alg, PSA_ALG_GCM)) { Aes aes; ret = wc_AesInit(&aes, NULL, INVALID_DEVID); diff --git a/src/psa_asymmetric_api.c b/src/psa_asymmetric_api.c index 3000683..c61f69d 100644 --- a/src/psa_asymmetric_api.c +++ b/src/psa_asymmetric_api.c @@ -452,23 +452,22 @@ psa_status_t psa_sign_message(psa_key_id_t key, hash_alg = 0; hash_length = input_length; if (hash_length > sizeof(hash)) { - wolfpsa_forcezero_free_key_data(key_data, key_data_length); - return PSA_ERROR_INVALID_ARGUMENT; + status = PSA_ERROR_INVALID_ARGUMENT; + goto cleanup; } XMEMCPY(hash, input, hash_length); } else { hash_alg = PSA_ALG_SIGN_GET_HASH(alg); if (hash_alg == 0) { - wolfpsa_forcezero_free_key_data(key_data, key_data_length); - return PSA_ERROR_NOT_SUPPORTED; + status = PSA_ERROR_NOT_SUPPORTED; + goto cleanup; } status = psa_hash_compute(hash_alg, input, input_length, hash, sizeof(hash), &hash_length); if (status != PSA_SUCCESS) { - wolfpsa_forcezero_free_key_data(key_data, key_data_length); - return status; + goto cleanup; } } @@ -517,6 +516,8 @@ psa_status_t psa_sign_message(psa_key_id_t key, status = PSA_ERROR_NOT_SUPPORTED; } +cleanup: + wc_ForceZero(hash, sizeof(hash)); wolfpsa_forcezero_free_key_data(key_data, key_data_length); return status; } @@ -550,23 +551,22 @@ psa_status_t psa_verify_message(psa_key_id_t key, hash_alg = 0; hash_length = input_length; if (hash_length > sizeof(hash)) { - wolfpsa_forcezero_free_key_data(key_data, key_data_length); - return PSA_ERROR_INVALID_ARGUMENT; + status = PSA_ERROR_INVALID_ARGUMENT; + goto cleanup; } XMEMCPY(hash, input, hash_length); } else { hash_alg = PSA_ALG_SIGN_GET_HASH(alg); if (hash_alg == 0) { - wolfpsa_forcezero_free_key_data(key_data, key_data_length); - return PSA_ERROR_NOT_SUPPORTED; + status = PSA_ERROR_NOT_SUPPORTED; + goto cleanup; } status = psa_hash_compute(hash_alg, input, input_length, hash, sizeof(hash), &hash_length); if (status != PSA_SUCCESS) { - wolfpsa_forcezero_free_key_data(key_data, key_data_length); - return status; + goto cleanup; } } @@ -612,6 +612,8 @@ psa_status_t psa_verify_message(psa_key_id_t key, status = PSA_ERROR_NOT_SUPPORTED; } +cleanup: + wc_ForceZero(hash, sizeof(hash)); wolfpsa_forcezero_free_key_data(key_data, key_data_length); return status; } diff --git a/src/psa_chacha20_poly1305.c b/src/psa_chacha20_poly1305.c index 67b731b..c6d136e 100644 --- a/src/psa_chacha20_poly1305.c +++ b/src/psa_chacha20_poly1305.c @@ -28,6 +28,7 @@ #if defined(WOLFSSL_PSA_ENGINE) && defined(HAVE_CHACHA) && defined(HAVE_POLY1305) #include +#include "psa_size.h" #include #include #include @@ -82,6 +83,7 @@ psa_status_t psa_chacha20_poly1305_encrypt( uint8_t *ciphertext, size_t ciphertext_size, size_t *ciphertext_length) { int ret; + size_t required_size; /* Check parameters */ if (key == NULL || key_length != CHACHA20_POLY1305_AEAD_KEYSIZE) { @@ -105,9 +107,18 @@ psa_status_t psa_chacha20_poly1305_encrypt( if (plaintext == NULL && plaintext_length > 0) { return PSA_ERROR_INVALID_ARGUMENT; } + if ((wolfpsa_check_word32_length(additional_data_length) != PSA_SUCCESS) || + (wolfpsa_check_word32_length(plaintext_length) != PSA_SUCCESS)) { + return PSA_ERROR_INVALID_ARGUMENT; + } + if (plaintext_length > SIZE_MAX - CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE) { + return PSA_ERROR_BUFFER_TOO_SMALL; + } + required_size = plaintext_length + CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE; + /* Check output buffer size */ - if (ciphertext_size < plaintext_length + CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE) { + if (ciphertext_size < required_size) { return PSA_ERROR_BUFFER_TOO_SMALL; } @@ -126,7 +137,7 @@ psa_status_t psa_chacha20_poly1305_encrypt( } /* Set output length */ - *ciphertext_length = plaintext_length + CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE; + *ciphertext_length = required_size; return PSA_SUCCESS; } @@ -164,6 +175,11 @@ psa_status_t psa_chacha20_poly1305_decrypt( if (ciphertext_length < CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE) { return PSA_ERROR_INVALID_ARGUMENT; } + if ((wolfpsa_check_word32_length(additional_data_length) != PSA_SUCCESS) || + (wolfpsa_check_word32_length(ciphertext_length - + CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE) != PSA_SUCCESS)) { + return PSA_ERROR_INVALID_ARGUMENT; + } /* Check output buffer size */ if (plaintext_size < ciphertext_length - CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE) { @@ -201,6 +217,7 @@ psa_status_t psa_xchacha20_poly1305_encrypt( uint8_t *ciphertext, size_t ciphertext_size, size_t *ciphertext_length) { int ret; + size_t required_size; /* Check parameters */ if (key == NULL || key_length != CHACHA20_POLY1305_AEAD_KEYSIZE) { @@ -225,8 +242,13 @@ psa_status_t psa_xchacha20_poly1305_encrypt( return PSA_ERROR_INVALID_ARGUMENT; } + if (plaintext_length > SIZE_MAX - CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE) { + return PSA_ERROR_BUFFER_TOO_SMALL; + } + required_size = plaintext_length + CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE; + /* Check output buffer size */ - if (ciphertext_size < plaintext_length + CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE) { + if (ciphertext_size < required_size) { return PSA_ERROR_BUFFER_TOO_SMALL; } @@ -244,7 +266,7 @@ psa_status_t psa_xchacha20_poly1305_encrypt( } /* Set output length */ - *ciphertext_length = plaintext_length + CHACHA20_POLY1305_AEAD_AUTHTAG_SIZE; + *ciphertext_length = required_size; return PSA_SUCCESS; } diff --git a/src/psa_cipher.c b/src/psa_cipher.c index e198865..69fc374 100644 --- a/src/psa_cipher.c +++ b/src/psa_cipher.c @@ -29,6 +29,7 @@ #include #include "psa_trace.h" +#include "psa_size.h" #include #include #include @@ -296,6 +297,11 @@ psa_status_t psa_cipher_encrypt_setup(psa_cipher_operation_t *operation, ctx->block_size = wolfpsa_cipher_block_size(attributes.type); ctx->partial_len = 0; XMEMCPY(ctx->iv, zero_iv, sizeof(ctx->iv)); + if (wolfpsa_check_word32_length(key_data_length) != PSA_SUCCESS) { + wolfpsa_forcezero_free_key_data(key_data, key_data_length); + XFREE(ctx, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return PSA_ERROR_INVALID_ARGUMENT; + } if (ctx->is_chacha) { ret = wc_Chacha_SetKey(&ctx->chacha, key_data, @@ -432,6 +438,11 @@ psa_status_t psa_cipher_decrypt_setup(psa_cipher_operation_t *operation, ctx->block_size = wolfpsa_cipher_block_size(attributes.type); ctx->partial_len = 0; XMEMCPY(ctx->iv, zero_iv, sizeof(ctx->iv)); + if (wolfpsa_check_word32_length(key_data_length) != PSA_SUCCESS) { + wolfpsa_forcezero_free_key_data(key_data, key_data_length); + XFREE(ctx, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return PSA_ERROR_INVALID_ARGUMENT; + } if (ctx->is_chacha) { ret = wc_Chacha_SetKey(&ctx->chacha, key_data, @@ -658,6 +669,9 @@ psa_status_t psa_cipher_update(psa_cipher_operation_t *operation, if (output == NULL && output_size > 0) { return PSA_ERROR_INVALID_ARGUMENT; } + if (wolfpsa_check_word32_length(input_length) != PSA_SUCCESS) { + return PSA_ERROR_INVALID_ARGUMENT; + } if (input_length == 0) { return PSA_SUCCESS; diff --git a/src/psa_ecc.c b/src/psa_ecc.c index e3ece59..d55d20d 100644 --- a/src/psa_ecc.c +++ b/src/psa_ecc.c @@ -28,6 +28,7 @@ #if defined(WOLFSSL_PSA_ENGINE) && defined(HAVE_ECC) #include +#include "psa_size.h" #include #include #include @@ -83,6 +84,10 @@ psa_status_t psa_asymmetric_sign_ecc(psa_key_type_t key_type, if (curve_id == ECC_CURVE_INVALID) { return PSA_ERROR_NOT_SUPPORTED; } + if ((wolfpsa_check_word32_length(key_buffer_size) != PSA_SUCCESS) || + (wolfpsa_check_word32_length(hash_length) != PSA_SUCCESS)) { + return PSA_ERROR_INVALID_ARGUMENT; + } /* Initialize ECC key */ ret = wc_ecc_init(&ecc); @@ -146,12 +151,14 @@ psa_status_t psa_asymmetric_sign_ecc(psa_key_type_t key_type, wc_ecc_free(&ecc); if (ret != 0) { + wc_ForceZero(der_sig, sig_len); XFREE(der_sig, NULL, DYNAMIC_TYPE_TMP_BUFFER); return wc_error_to_psa_status(ret); } rs = (byte*)XMALLOC(raw_sig_len, NULL, DYNAMIC_TYPE_TMP_BUFFER); if (rs == NULL) { + wc_ForceZero(der_sig, sig_len); XFREE(der_sig, NULL, DYNAMIC_TYPE_TMP_BUFFER); return PSA_ERROR_INSUFFICIENT_MEMORY; } @@ -159,12 +166,15 @@ psa_status_t psa_asymmetric_sign_ecc(psa_key_type_t key_type, r_len = (word32)key_bytes; s_len = (word32)key_bytes; ret = wc_ecc_sig_to_rs(der_sig, der_len, rs, &r_len, rs + key_bytes, &s_len); + wc_ForceZero(der_sig, sig_len); XFREE(der_sig, NULL, DYNAMIC_TYPE_TMP_BUFFER); if (ret != 0) { + wc_ForceZero(rs, raw_sig_len); XFREE(rs, NULL, DYNAMIC_TYPE_TMP_BUFFER); return wc_error_to_psa_status(ret); } if (r_len > key_bytes || s_len > key_bytes) { + wc_ForceZero(rs, raw_sig_len); XFREE(rs, NULL, DYNAMIC_TYPE_TMP_BUFFER); return PSA_ERROR_INVALID_SIGNATURE; } @@ -173,6 +183,7 @@ psa_status_t psa_asymmetric_sign_ecc(psa_key_type_t key_type, XMEMCPY(signature + (key_bytes - r_len), rs, r_len); XMEMCPY(signature + key_bytes + (key_bytes - s_len), rs + key_bytes, s_len); + wc_ForceZero(rs, raw_sig_len); XFREE(rs, NULL, DYNAMIC_TYPE_TMP_BUFFER); *signature_length = raw_sig_len; @@ -214,6 +225,10 @@ psa_status_t psa_asymmetric_verify_ecc(psa_key_type_t key_type, if (curve_id == ECC_CURVE_INVALID) { return PSA_ERROR_NOT_SUPPORTED; } + if ((wolfpsa_check_word32_length(key_buffer_size) != PSA_SUCCESS) || + (wolfpsa_check_word32_length(hash_length) != PSA_SUCCESS)) { + return PSA_ERROR_INVALID_ARGUMENT; + } /* Initialize ECC key */ ret = wc_ecc_init(&ecc); @@ -304,6 +319,9 @@ psa_status_t psa_asymmetric_generate_key_ecc(psa_key_type_t key_type, if (curve_id == ECC_CURVE_INVALID) { return PSA_ERROR_NOT_SUPPORTED; } + if (wolfpsa_check_word32_length(public_key_size) != PSA_SUCCESS) { + return PSA_ERROR_INVALID_ARGUMENT; + } /* Initialize ECC key */ ret = wc_ecc_init(&ecc); @@ -388,6 +406,10 @@ psa_status_t psa_asymmetric_export_public_key_ecc(psa_key_type_t key_type, if (curve_id == ECC_CURVE_INVALID) { return PSA_ERROR_NOT_SUPPORTED; } + if ((wolfpsa_check_word32_length(key_buffer_size) != PSA_SUCCESS) || + (wolfpsa_check_word32_length(output_size) != PSA_SUCCESS)) { + return PSA_ERROR_INVALID_ARGUMENT; + } /* Initialize ECC key */ ret = wc_ecc_init(&ecc); diff --git a/src/psa_hash_engine.c b/src/psa_hash_engine.c index c7aacd3..5db9ecd 100644 --- a/src/psa_hash_engine.c +++ b/src/psa_hash_engine.c @@ -29,6 +29,7 @@ #include #include "psa_trace.h" +#include "psa_size.h" #include #include #include @@ -433,6 +434,9 @@ psa_status_t psa_hash_update(psa_hash_operation_t *operation, if (ctx->finalized) { return PSA_ERROR_BAD_STATE; } + if (wolfpsa_check_word32_length(input_length) != PSA_SUCCESS) { + return PSA_ERROR_INVALID_ARGUMENT; + } /* Update the hash context based on algorithm */ switch (ctx->alg) { @@ -640,18 +644,24 @@ psa_status_t psa_hash_verify(psa_hash_operation_t *operation, status = psa_hash_finish(operation, computed_hash, sizeof(computed_hash), &computed_hash_length); if (status != PSA_SUCCESS) { - return status; + goto cleanup; } if (hash_length != computed_hash_length) { - return PSA_ERROR_INVALID_SIGNATURE; + status = PSA_ERROR_INVALID_SIGNATURE; + goto cleanup; } if (ConstantCompare(computed_hash, hash, (int)computed_hash_length) != 0) { - return PSA_ERROR_INVALID_SIGNATURE; + status = PSA_ERROR_INVALID_SIGNATURE; + goto cleanup; } - return PSA_SUCCESS; + status = PSA_SUCCESS; + +cleanup: + wc_ForceZero(computed_hash, sizeof(computed_hash)); + return status; } /* Abort a hash operation */ @@ -866,15 +876,20 @@ psa_status_t psa_hash_compare(psa_algorithm_t alg, status = psa_hash_compute(alg, input, input_length, computed_hash, sizeof(computed_hash), &computed_hash_length); if (status != PSA_SUCCESS) { - return status; + goto cleanup; } /* Compare the computed hash with the reference hash */ if (ConstantCompare(computed_hash, hash, (int)computed_hash_length) != 0) { - return PSA_ERROR_INVALID_SIGNATURE; + status = PSA_ERROR_INVALID_SIGNATURE; + goto cleanup; } - return PSA_SUCCESS; + status = PSA_SUCCESS; + +cleanup: + wc_ForceZero(computed_hash, sizeof(computed_hash)); + return status; } #endif /* WOLFSSL_PSA_ENGINE */ diff --git a/src/psa_key_derivation.c b/src/psa_key_derivation.c index 9a29425..0f8e57c 100644 --- a/src/psa_key_derivation.c +++ b/src/psa_key_derivation.c @@ -29,6 +29,7 @@ #if defined(WOLFSSL_PSA_ENGINE) #include +#include "psa_size.h" #include #include #include @@ -247,7 +248,7 @@ static psa_status_t wolfpsa_kdf_validate_step(wolfpsa_kdf_ctx_t *ctx, return PSA_ERROR_INVALID_ARGUMENT; } if (step == PSA_KEY_DERIVATION_INPUT_SALT) { - if (ctx->steps_set != 0) { + if ((ctx->steps_set & WOLFPSA_KDF_STEP_SECRET) != 0) { return PSA_ERROR_BAD_STATE; } return PSA_SUCCESS; @@ -318,8 +319,7 @@ static psa_status_t wolfpsa_kdf_validate_step(wolfpsa_kdf_ctx_t *ctx, return PSA_ERROR_INVALID_ARGUMENT; } if (step == PSA_KEY_DERIVATION_INPUT_SECRET) { - if ((ctx->steps_set & WOLFPSA_KDF_STEP_SEED) == 0 || - (ctx->steps_set & WOLFPSA_KDF_STEP_OTHER_SECRET) == 0) { + if ((ctx->steps_set & WOLFPSA_KDF_STEP_SEED) == 0) { return PSA_ERROR_BAD_STATE; } } @@ -718,6 +718,10 @@ static psa_status_t wolfpsa_kdf_hkdf(wolfpsa_kdf_ctx_t *ctx, if (hash_len <= 0) { return PSA_ERROR_NOT_SUPPORTED; } + if ((wolfpsa_check_word32_length(ctx->salt_length) != PSA_SUCCESS) || + (wolfpsa_check_word32_length(ctx->secret_length) != PSA_SUCCESS)) { + return PSA_ERROR_INVALID_ARGUMENT; + } if (output_length != (size_t)hash_len) { return PSA_ERROR_INVALID_ARGUMENT; } @@ -729,6 +733,11 @@ static psa_status_t wolfpsa_kdf_hkdf(wolfpsa_kdf_ctx_t *ctx, } if (PSA_ALG_IS_HKDF_EXPAND(ctx->alg)) { + if ((wolfpsa_check_word32_length(ctx->secret_length) != PSA_SUCCESS) || + (wolfpsa_check_word32_length(ctx->info_length) != PSA_SUCCESS) || + (wolfpsa_check_word32_length(output_length) != PSA_SUCCESS)) { + return PSA_ERROR_INVALID_ARGUMENT; + } ret = wc_HKDF_Expand(hash_type, ctx->secret, (word32)ctx->secret_length, ctx->info, (word32)ctx->info_length, @@ -744,6 +753,12 @@ static psa_status_t wolfpsa_kdf_hkdf(wolfpsa_kdf_ctx_t *ctx, if (hash_len <= 0 || (size_t)hash_len > sizeof(prk)) { return PSA_ERROR_NOT_SUPPORTED; } + if ((wolfpsa_check_word32_length(ctx->salt_length) != PSA_SUCCESS) || + (wolfpsa_check_word32_length(ctx->secret_length) != PSA_SUCCESS) || + (wolfpsa_check_word32_length(ctx->info_length) != PSA_SUCCESS) || + (wolfpsa_check_word32_length(output_length) != PSA_SUCCESS)) { + return PSA_ERROR_INVALID_ARGUMENT; + } ret = wc_HKDF_Extract(hash_type, ctx->salt, (word32)ctx->salt_length, ctx->secret, (word32)ctx->secret_length, @@ -780,6 +795,12 @@ static psa_status_t wolfpsa_kdf_tls12_prf(wolfpsa_kdf_ctx_t *ctx, if (hash_type == WC_HASH_TYPE_NONE) { return PSA_ERROR_NOT_SUPPORTED; } + if ((wolfpsa_check_word32_length(output_length) != PSA_SUCCESS) || + (wolfpsa_check_word32_length(ctx->secret_length) != PSA_SUCCESS) || + (wolfpsa_check_word32_length(ctx->label_length) != PSA_SUCCESS) || + (wolfpsa_check_word32_length(ctx->seed_length) != PSA_SUCCESS)) { + return PSA_ERROR_INVALID_ARGUMENT; + } ret = wc_PRF_TLS(output, (word32)output_length, ctx->secret, (word32)ctx->secret_length, ctx->label, (word32)ctx->label_length, @@ -796,6 +817,8 @@ static psa_status_t wolfpsa_kdf_tls12_psk_to_ms(wolfpsa_kdf_ctx_t *ctx, size_t output_length) { int hash_type = wolfpsa_hash_type_from_alg(ctx->alg); + size_t other_secret_length; + const uint8_t *other_secret; uint8_t *premaster = NULL; size_t premaster_len; psa_status_t status; @@ -804,19 +827,38 @@ static psa_status_t wolfpsa_kdf_tls12_psk_to_ms(wolfpsa_kdf_ctx_t *ctx, if (hash_type == WC_HASH_TYPE_NONE) { return PSA_ERROR_NOT_SUPPORTED; } - premaster_len = 2u + ctx->secret_length + 2u + ctx->other_secret_length; + if ((ctx->steps_set & WOLFPSA_KDF_STEP_OTHER_SECRET) == 0) { + other_secret = NULL; + other_secret_length = ctx->secret_length; + } + else { + other_secret = ctx->other_secret; + other_secret_length = ctx->other_secret_length; + } + + premaster_len = 2u + ctx->secret_length + 2u + other_secret_length; + if ((wolfpsa_check_word32_length(output_length) != PSA_SUCCESS) || + (wolfpsa_check_word32_length(premaster_len) != PSA_SUCCESS) || + (wolfpsa_check_word32_length(ctx->seed_length) != PSA_SUCCESS)) { + return PSA_ERROR_INVALID_ARGUMENT; + } premaster = (uint8_t *)XMALLOC(premaster_len, NULL, DYNAMIC_TYPE_TMP_BUFFER); if (premaster == NULL) { return PSA_ERROR_INSUFFICIENT_MEMORY; } - premaster[0] = (uint8_t)((ctx->secret_length >> 8) & 0xff); - premaster[1] = (uint8_t)(ctx->secret_length & 0xff); - XMEMCPY(premaster + 2u, ctx->secret, ctx->secret_length); - premaster[2u + ctx->secret_length] = (uint8_t)((ctx->other_secret_length >> 8) & 0xff); - premaster[3u + ctx->secret_length] = (uint8_t)(ctx->other_secret_length & 0xff); - XMEMCPY(premaster + 4u + ctx->secret_length, ctx->other_secret, - ctx->other_secret_length); + premaster[0] = (uint8_t)((other_secret_length >> 8) & 0xff); + premaster[1] = (uint8_t)(other_secret_length & 0xff); + if (other_secret == NULL) { + XMEMSET(premaster + 2u, 0, other_secret_length); + } + else { + XMEMCPY(premaster + 2u, other_secret, other_secret_length); + } + premaster[2u + other_secret_length] = (uint8_t)((ctx->secret_length >> 8) & 0xff); + premaster[3u + other_secret_length] = (uint8_t)(ctx->secret_length & 0xff); + XMEMCPY(premaster + 4u + other_secret_length, ctx->secret, + ctx->secret_length); ret = wc_PRF_TLS(output, (word32)output_length, premaster, (word32)premaster_len, @@ -872,6 +914,10 @@ static psa_status_t wolfpsa_kdf_pbkdf2(wolfpsa_kdf_ctx_t *ctx, word32 out_sz = WC_AES_BLOCK_SIZE; psa_status_t status = PSA_SUCCESS; + if (wolfpsa_check_word32_length(ctx->password_length) != PSA_SUCCESS) { + return PSA_ERROR_INVALID_ARGUMENT; + } + XMEMSET(zero_key, 0, sizeof(zero_key)); ret = wc_InitCmac(&cmac, zero_key, (word32)sizeof(zero_key), WC_CMAC_AES, NULL); @@ -894,6 +940,10 @@ static psa_status_t wolfpsa_kdf_pbkdf2(wolfpsa_kdf_ctx_t *ctx, } block_input_len = ctx->salt_length + 4; + if (wolfpsa_check_word32_length(block_input_len) != PSA_SUCCESS) { + status = PSA_ERROR_INVALID_ARGUMENT; + goto cleanup; + } block_input = (uint8_t *)XMALLOC(block_input_len, NULL, DYNAMIC_TYPE_TMP_BUFFER); if (block_input == NULL) { @@ -1006,8 +1056,8 @@ psa_status_t psa_key_derivation_output_bytes(psa_key_derivation_operation_t *ope } else if (PSA_ALG_IS_ANY_HKDF(ctx->alg)) { if (PSA_ALG_IS_HKDF_EXTRACT(ctx->alg)) { - if ((ctx->steps_set & WOLFPSA_KDF_STEP_SECRET) == 0 || - (ctx->steps_set & WOLFPSA_KDF_STEP_SALT) == 0) { + if ((ctx->steps_set & WOLFPSA_KDF_STEP_SALT) == 0 || + (ctx->steps_set & WOLFPSA_KDF_STEP_SECRET) == 0) { return PSA_ERROR_BAD_STATE; } } @@ -1033,7 +1083,6 @@ psa_status_t psa_key_derivation_output_bytes(psa_key_derivation_operation_t *ope } else if (PSA_ALG_IS_TLS12_PSK_TO_MS(ctx->alg)) { if ((ctx->steps_set & WOLFPSA_KDF_STEP_SECRET) == 0 || - (ctx->steps_set & WOLFPSA_KDF_STEP_OTHER_SECRET) == 0 || (ctx->steps_set & WOLFPSA_KDF_STEP_SEED) == 0) { return PSA_ERROR_BAD_STATE; } diff --git a/src/psa_lms_xmss.c b/src/psa_lms_xmss.c index 045e650..1cc284b 100644 --- a/src/psa_lms_xmss.c +++ b/src/psa_lms_xmss.c @@ -28,6 +28,7 @@ #if defined(WOLFSSL_PSA_ENGINE) && (defined(WOLFSSL_HAVE_LMS) || defined(WOLFSSL_HAVE_XMSS)) #include +#include "psa_size.h" #include #include #include @@ -53,6 +54,11 @@ psa_status_t psa_lms_generate_key(uint8_t *private_key, word32 priv_len32; word32 pub_len32; + if ((wolfpsa_check_word32_length(private_key_size) != PSA_SUCCESS) || + (wolfpsa_check_word32_length(public_key_size) != PSA_SUCCESS)) { + return PSA_ERROR_INVALID_ARGUMENT; + } + /* Initialize LMS key */ ret = wc_LmsKey_Init(&key, NULL, INVALID_DEVID); if (ret != 0) { @@ -121,6 +127,12 @@ psa_status_t psa_lms_sign(const uint8_t *private_key, LmsKey key; word32 sig_len32; + if ((wolfpsa_check_word32_length(private_key_size) != PSA_SUCCESS) || + (wolfpsa_check_word32_length(message_length) != PSA_SUCCESS) || + (wolfpsa_check_word32_length(signature_size) != PSA_SUCCESS)) { + return PSA_ERROR_INVALID_ARGUMENT; + } + /* Initialize LMS key */ ret = wc_LmsKey_Init(&key, NULL, INVALID_DEVID); if (ret != 0) { @@ -162,6 +174,12 @@ psa_status_t psa_lms_verify(const uint8_t *public_key, LmsKey key; int verify_res = 0; + if ((wolfpsa_check_word32_length(public_key_size) != PSA_SUCCESS) || + (wolfpsa_check_word32_length(message_length) != PSA_SUCCESS) || + (wolfpsa_check_word32_length(signature_length) != PSA_SUCCESS)) { + return PSA_ERROR_INVALID_ARGUMENT; + } + /* Initialize LMS key */ ret = wc_LmsKey_Init(&key, NULL, INVALID_DEVID); if (ret != 0) { @@ -210,6 +228,11 @@ psa_status_t psa_xmss_generate_key(uint8_t *private_key, word32 priv_len32; word32 pub_len32; + if ((wolfpsa_check_word32_length(private_key_size) != PSA_SUCCESS) || + (wolfpsa_check_word32_length(public_key_size) != PSA_SUCCESS)) { + return PSA_ERROR_INVALID_ARGUMENT; + } + /* Initialize XMSS key */ ret = wc_XmssKey_Init(&key, NULL, INVALID_DEVID); if (ret != 0) { @@ -278,6 +301,12 @@ psa_status_t psa_xmss_sign(const uint8_t *private_key, XmssKey key; word32 sig_len32; + if ((wolfpsa_check_word32_length(private_key_size) != PSA_SUCCESS) || + (wolfpsa_check_word32_length(message_length) != PSA_SUCCESS) || + (wolfpsa_check_word32_length(signature_size) != PSA_SUCCESS)) { + return PSA_ERROR_INVALID_ARGUMENT; + } + /* Initialize XMSS key */ ret = wc_XmssKey_Init(&key, NULL, INVALID_DEVID); if (ret != 0) { @@ -319,6 +348,12 @@ psa_status_t psa_xmss_verify(const uint8_t *public_key, XmssKey key; int verify_res = 0; + if ((wolfpsa_check_word32_length(public_key_size) != PSA_SUCCESS) || + (wolfpsa_check_word32_length(message_length) != PSA_SUCCESS) || + (wolfpsa_check_word32_length(signature_length) != PSA_SUCCESS)) { + return PSA_ERROR_INVALID_ARGUMENT; + } + /* Initialize XMSS key */ ret = wc_XmssKey_Init(&key, NULL, INVALID_DEVID); if (ret != 0) { diff --git a/src/psa_mac.c b/src/psa_mac.c index 9b28d70..f59f358 100644 --- a/src/psa_mac.c +++ b/src/psa_mac.c @@ -28,6 +28,7 @@ #if defined(WOLFSSL_PSA_ENGINE) #include +#include "psa_size.h" #include #include #include @@ -241,6 +242,11 @@ static psa_status_t wolfpsa_mac_setup(psa_mac_operation_t *operation, ctx->mac_length = PSA_MAC_LENGTH(attributes.type, attributes.bits, alg); ctx->full_length = PSA_MAC_LENGTH(attributes.type, attributes.bits, PSA_ALG_FULL_LENGTH_MAC(alg)); + if (wolfpsa_check_word32_length(key_data_length) != PSA_SUCCESS) { + wolfpsa_forcezero_free_key_data(key_data, key_data_length); + XFREE(ctx, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return PSA_ERROR_INVALID_ARGUMENT; + } if (PSA_ALG_IS_HMAC(alg)) { int hash_type = wolfpsa_hash_type_from_alg(alg); @@ -322,6 +328,9 @@ psa_status_t psa_mac_update(psa_mac_operation_t *operation, if (input == NULL && input_length > 0) { return PSA_ERROR_INVALID_ARGUMENT; } + if (wolfpsa_check_word32_length(input_length) != PSA_SUCCESS) { + return PSA_ERROR_INVALID_ARGUMENT; + } if (input_length == 0) { return PSA_SUCCESS; diff --git a/src/psa_mldsa.c b/src/psa_mldsa.c index 24c843b..dd5f2f8 100644 --- a/src/psa_mldsa.c +++ b/src/psa_mldsa.c @@ -28,6 +28,7 @@ #if defined(WOLFSSL_PSA_ENGINE) && defined(WOLFSSL_HAVE_DILITHIUM) #include +#include "psa_size.h" #include #include #include @@ -73,6 +74,10 @@ psa_status_t psa_ml_dsa_generate_key(psa_ml_dsa_parameter_t parameter, if (type < 0) { return PSA_ERROR_NOT_SUPPORTED; } + if ((wolfpsa_check_word32_length(private_key_size) != PSA_SUCCESS) || + (wolfpsa_check_word32_length(public_key_size) != PSA_SUCCESS)) { + return PSA_ERROR_INVALID_ARGUMENT; + } /* Initialize ML-DSA key */ ret = wc_dilithium_init_ex(&key, type, NULL, INVALID_DEVID); @@ -139,6 +144,11 @@ psa_status_t psa_ml_dsa_sign(psa_ml_dsa_parameter_t parameter, if (type < 0) { return PSA_ERROR_NOT_SUPPORTED; } + if ((wolfpsa_check_word32_length(private_key_size) != PSA_SUCCESS) || + (wolfpsa_check_word32_length(message_length) != PSA_SUCCESS) || + (wolfpsa_check_word32_length(signature_size) != PSA_SUCCESS)) { + return PSA_ERROR_INVALID_ARGUMENT; + } /* Initialize ML-DSA key */ ret = wc_dilithium_init_ex(&key, type, NULL, INVALID_DEVID); @@ -193,6 +203,11 @@ psa_status_t psa_ml_dsa_verify(psa_ml_dsa_parameter_t parameter, if (type < 0) { return PSA_ERROR_NOT_SUPPORTED; } + if ((wolfpsa_check_word32_length(public_key_size) != PSA_SUCCESS) || + (wolfpsa_check_word32_length(message_length) != PSA_SUCCESS) || + (wolfpsa_check_word32_length(signature_length) != PSA_SUCCESS)) { + return PSA_ERROR_INVALID_ARGUMENT; + } /* Initialize ML-DSA key */ ret = wc_dilithium_init_ex(&key, type, NULL, INVALID_DEVID); diff --git a/src/psa_rsa.c b/src/psa_rsa.c index 5b2b09c..ba2abe1 100644 --- a/src/psa_rsa.c +++ b/src/psa_rsa.c @@ -28,6 +28,7 @@ #if defined(WOLFSSL_PSA_ENGINE) && !defined(NO_RSA) #include +#include "psa_size.h" #include #include #include @@ -113,6 +114,7 @@ psa_status_t psa_asymmetric_sign_rsa(psa_key_type_t key_type, int hash_oid; byte* sig_input = NULL; word32 sig_input_len = 0; + word32 sig_input_alloc_len = 0; WC_RNG rng; (void)key_bits; @@ -121,6 +123,11 @@ psa_status_t psa_asymmetric_sign_rsa(psa_key_type_t key_type, if (key_type != PSA_KEY_TYPE_RSA_KEY_PAIR) { return PSA_ERROR_INVALID_ARGUMENT; } + if ((wolfpsa_check_word32_length(key_buffer_size) != PSA_SUCCESS) || + (wolfpsa_check_word32_length(hash_length) != PSA_SUCCESS) || + (wolfpsa_check_word32_length(signature_size) != PSA_SUCCESS)) { + return PSA_ERROR_INVALID_ARGUMENT; + } /* Initialize RSA key */ ret = wc_InitRsaKey(&rsa_key, NULL); @@ -169,6 +176,7 @@ psa_status_t psa_asymmetric_sign_rsa(psa_key_type_t key_type, wc_FreeRsaKey(&rsa_key); return PSA_ERROR_INSUFFICIENT_MEMORY; } + sig_input_alloc_len = PSA_HASH_MAX_SIZE + 32; sig_input_len = wc_EncodeSignature(sig_input, hash, (word32)hash_length, hash_oid); } @@ -190,6 +198,7 @@ psa_status_t psa_asymmetric_sign_rsa(psa_key_type_t key_type, } if (sig_input != NULL && sig_input != hash) { + wc_ForceZero(sig_input, sig_input_alloc_len); XFREE(sig_input, NULL, DYNAMIC_TYPE_TMP_BUFFER); } wc_FreeRng(&rng); @@ -228,6 +237,11 @@ psa_status_t psa_asymmetric_verify_rsa(psa_key_type_t key_type, key_type != PSA_KEY_TYPE_RSA_KEY_PAIR) { return PSA_ERROR_INVALID_ARGUMENT; } + if ((wolfpsa_check_word32_length(key_buffer_size) != PSA_SUCCESS) || + (wolfpsa_check_word32_length(hash_length) != PSA_SUCCESS) || + (wolfpsa_check_word32_length(signature_length) != PSA_SUCCESS)) { + return PSA_ERROR_INVALID_ARGUMENT; + } /* Initialize RSA key */ ret = wc_InitRsaKey(&rsa_key, NULL); @@ -278,6 +292,7 @@ psa_status_t psa_asymmetric_verify_rsa(psa_key_type_t key_type, ret = SIG_VERIFY_E; } } + wc_ForceZero(decoded, sizeof(decoded)); } else if (padding == WC_RSA_PSS_PAD) { #ifdef WC_RSA_PSS @@ -291,6 +306,7 @@ psa_status_t psa_asymmetric_verify_rsa(psa_key_type_t key_type, #else if (PSA_ALG_IS_RSA_PSS_ANY_SALT(alg)) { ret = NOT_COMPILED_IN; + wc_ForceZero(decoded, sizeof(decoded)); wc_FreeRsaKey(&rsa_key); return wc_error_to_psa_status(ret); } @@ -308,6 +324,7 @@ psa_status_t psa_asymmetric_verify_rsa(psa_key_type_t key_type, ret = (int)hash_length; } } + wc_ForceZero(decoded, sizeof(decoded)); #else ret = NOT_COMPILED_IN; #endif @@ -359,6 +376,12 @@ psa_status_t psa_asymmetric_encrypt_rsa(psa_key_type_t key_type, key_type != PSA_KEY_TYPE_RSA_KEY_PAIR) { return PSA_ERROR_INVALID_ARGUMENT; } + if ((wolfpsa_check_word32_length(key_buffer_size) != PSA_SUCCESS) || + (wolfpsa_check_word32_length(input_length) != PSA_SUCCESS) || + (wolfpsa_check_word32_length(output_size) != PSA_SUCCESS) || + (wolfpsa_check_word32_length(salt_length) != PSA_SUCCESS)) { + return PSA_ERROR_INVALID_ARGUMENT; + } /* Initialize RSA key */ ret = wc_InitRsaKey(&rsa_key, NULL); @@ -460,6 +483,12 @@ psa_status_t psa_asymmetric_decrypt_rsa(psa_key_type_t key_type, if (key_type != PSA_KEY_TYPE_RSA_KEY_PAIR) { return PSA_ERROR_INVALID_ARGUMENT; } + if ((wolfpsa_check_word32_length(key_buffer_size) != PSA_SUCCESS) || + (wolfpsa_check_word32_length(input_length) != PSA_SUCCESS) || + (wolfpsa_check_word32_length(output_size) != PSA_SUCCESS) || + (wolfpsa_check_word32_length(salt_length) != PSA_SUCCESS)) { + return PSA_ERROR_INVALID_ARGUMENT; + } /* Initialize RSA key */ ret = wc_InitRsaKey(&rsa_key, NULL); @@ -549,6 +578,10 @@ psa_status_t psa_asymmetric_generate_key_rsa(psa_key_type_t key_type, if (key_type != PSA_KEY_TYPE_RSA_KEY_PAIR) { return PSA_ERROR_INVALID_ARGUMENT; } + if ((wolfpsa_check_word32_length(private_key_size) != PSA_SUCCESS) || + (wolfpsa_check_word32_length(public_key_size) != PSA_SUCCESS)) { + return PSA_ERROR_INVALID_ARGUMENT; + } /* Initialize RSA key */ ret = wc_InitRsaKey(&rsa_key, NULL); @@ -624,6 +657,10 @@ psa_status_t psa_asymmetric_export_public_key_rsa(psa_key_type_t key_type, key_type != PSA_KEY_TYPE_RSA_PUBLIC_KEY) { return PSA_ERROR_INVALID_ARGUMENT; } + if ((wolfpsa_check_word32_length(key_buffer_size) != PSA_SUCCESS) || + (wolfpsa_check_word32_length(output_size) != PSA_SUCCESS)) { + return PSA_ERROR_INVALID_ARGUMENT; + } /* Initialize RSA key */ ret = wc_InitRsaKey(&rsa_key, NULL); diff --git a/src/psa_size.h b/src/psa_size.h new file mode 100644 index 0000000..059b851 --- /dev/null +++ b/src/psa_size.h @@ -0,0 +1,17 @@ +#ifndef WOLFPSA_SIZE_H +#define WOLFPSA_SIZE_H + +#include + +#include + +static inline psa_status_t wolfpsa_check_word32_length(size_t length) +{ + if (length > UINT32_MAX) { + return PSA_ERROR_INVALID_ARGUMENT; + } + + return PSA_SUCCESS; +} + +#endif /* WOLFPSA_SIZE_H */ diff --git a/src/psa_tls_prf.c b/src/psa_tls_prf.c index b554ec1..57589c2 100644 --- a/src/psa_tls_prf.c +++ b/src/psa_tls_prf.c @@ -28,6 +28,7 @@ #if defined(WOLFSSL_PSA_ENGINE) && defined(WOLFSSL_TLS13) #include +#include "psa_size.h" #include #include #include @@ -74,15 +75,6 @@ static int psa_tls13_get_hash_type(psa_algorithm_t alg, enum wc_HashType* hashTy } } -static psa_status_t psa_tls13_check_word32_length(size_t length) -{ - if (length > UINT32_MAX) { - return PSA_ERROR_INVALID_ARGUMENT; - } - - return PSA_SUCCESS; -} - /* TLS 1.3 PRF (HKDF) */ psa_status_t psa_tls13_prf( psa_algorithm_t alg, @@ -114,10 +106,10 @@ psa_status_t psa_tls13_prf( if (output == NULL || output_length == 0) { return PSA_ERROR_INVALID_ARGUMENT; } - if ((psa_tls13_check_word32_length(secret_length) != PSA_SUCCESS) || - (psa_tls13_check_word32_length(label_length) != PSA_SUCCESS) || - (psa_tls13_check_word32_length(context_length) != PSA_SUCCESS) || - (psa_tls13_check_word32_length(output_length) != PSA_SUCCESS)) { + if ((wolfpsa_check_word32_length(secret_length) != PSA_SUCCESS) || + (wolfpsa_check_word32_length(label_length) != PSA_SUCCESS) || + (wolfpsa_check_word32_length(context_length) != PSA_SUCCESS) || + (wolfpsa_check_word32_length(output_length) != PSA_SUCCESS)) { return PSA_ERROR_INVALID_ARGUMENT; } @@ -171,8 +163,8 @@ psa_status_t psa_tls13_hkdf_extract( if (output == NULL || output_size == 0 || output_length == NULL) { return PSA_ERROR_INVALID_ARGUMENT; } - if ((psa_tls13_check_word32_length(salt_length) != PSA_SUCCESS) || - (psa_tls13_check_word32_length(ikm_length) != PSA_SUCCESS)) { + if ((wolfpsa_check_word32_length(salt_length) != PSA_SUCCESS) || + (wolfpsa_check_word32_length(ikm_length) != PSA_SUCCESS)) { return PSA_ERROR_INVALID_ARGUMENT; } @@ -237,9 +229,9 @@ psa_status_t psa_tls13_hkdf_expand( if (output == NULL || output_length == 0) { return PSA_ERROR_INVALID_ARGUMENT; } - if ((psa_tls13_check_word32_length(prk_length) != PSA_SUCCESS) || - (psa_tls13_check_word32_length(info_length) != PSA_SUCCESS) || - (psa_tls13_check_word32_length(output_length) != PSA_SUCCESS)) { + if ((wolfpsa_check_word32_length(prk_length) != PSA_SUCCESS) || + (wolfpsa_check_word32_length(info_length) != PSA_SUCCESS) || + (wolfpsa_check_word32_length(output_length) != PSA_SUCCESS)) { return PSA_ERROR_INVALID_ARGUMENT; } @@ -295,10 +287,10 @@ psa_status_t psa_tls13_hkdf_expand_label( if (output == NULL || output_length == 0) { return PSA_ERROR_INVALID_ARGUMENT; } - if ((psa_tls13_check_word32_length(secret_length) != PSA_SUCCESS) || - (psa_tls13_check_word32_length(label_length) != PSA_SUCCESS) || - (psa_tls13_check_word32_length(context_length) != PSA_SUCCESS) || - (psa_tls13_check_word32_length(output_length) != PSA_SUCCESS)) { + if ((wolfpsa_check_word32_length(secret_length) != PSA_SUCCESS) || + (wolfpsa_check_word32_length(label_length) != PSA_SUCCESS) || + (wolfpsa_check_word32_length(context_length) != PSA_SUCCESS) || + (wolfpsa_check_word32_length(output_length) != PSA_SUCCESS)) { return PSA_ERROR_INVALID_ARGUMENT; } diff --git a/test/psa_server/psa_api_test.c b/test/psa_server/psa_api_test.c index fb71317..47a5ffb 100644 --- a/test/psa_server/psa_api_test.c +++ b/test/psa_server/psa_api_test.c @@ -19,6 +19,7 @@ #include #include +#include #include #include @@ -608,6 +609,106 @@ static int test_aead_multipart_length_overflow_rejected(void) return ret; } +static int test_aead_finish_verify_word32_overflow_rejected(void) +{ + static const uint8_t key[16] = { + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 + }; + static const uint8_t nonce[12] = { + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00 + }; + static const uint8_t empty_gcm_tag[16] = { + 0x58,0xe2,0xfc,0xce,0xfa,0x7e,0x30,0x61, + 0x36,0x7f,0x1d,0x57,0xa4,0xe7,0x45,0x5a + }; + uint8_t out[1]; + uint8_t tag[sizeof(empty_gcm_tag)]; + size_t out_len = 0; + size_t tag_len = 0; + psa_key_id_t key_id = 0; + psa_key_attributes_t attrs = psa_key_attributes_init(); + psa_aead_operation_t op = psa_aead_operation_init(); + wolfpsa_aead_ctx_t *ctx; + int ret = TEST_OK; + psa_status_t st; + + psa_set_key_type(&attrs, PSA_KEY_TYPE_AES); + psa_set_key_bits(&attrs, 128); + psa_set_key_usage_flags(&attrs, PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT); + psa_set_key_algorithm(&attrs, PSA_ALG_GCM); + + st = psa_import_key(&attrs, key, sizeof(key), &key_id); + if (check_status(st, "psa_import_key(GCM word32 overflow)") != TEST_OK) { + return TEST_FAIL; + } + + st = psa_aead_encrypt_setup(&op, key_id, PSA_ALG_GCM); + if (check_status(st, "psa_aead_encrypt_setup(word32 input)") != TEST_OK) goto cleanup; + st = psa_aead_set_nonce(&op, nonce, sizeof(nonce)); + if (check_status(st, "psa_aead_set_nonce(word32 input)") != TEST_OK) goto cleanup; + ctx = wolfpsa_aead_get_ctx_ptr(&op); + ctx->input = NULL; + ctx->input_length = (size_t)UINT32_MAX + 1u; + st = psa_aead_finish(&op, out, SIZE_MAX, &out_len, tag, sizeof(tag), &tag_len); + if (check_true(st == PSA_ERROR_INVALID_ARGUMENT, + "psa_aead_finish rejects input_length above word32") != TEST_OK) { + ret = TEST_FAIL; + goto cleanup; + } + + st = psa_aead_encrypt_setup(&op, key_id, PSA_ALG_GCM); + if (check_status(st, "psa_aead_encrypt_setup(word32 aad)") != TEST_OK) goto cleanup; + st = psa_aead_set_nonce(&op, nonce, sizeof(nonce)); + if (check_status(st, "psa_aead_set_nonce(word32 aad)") != TEST_OK) goto cleanup; + ctx = wolfpsa_aead_get_ctx_ptr(&op); + ctx->aad = NULL; + ctx->aad_length = (size_t)UINT32_MAX + 1u; + st = psa_aead_finish(&op, out, sizeof(out), &out_len, tag, sizeof(tag), &tag_len); + if (check_true(st == PSA_ERROR_INVALID_ARGUMENT, + "psa_aead_finish rejects aad_length above word32") != TEST_OK) { + ret = TEST_FAIL; + goto cleanup; + } + + st = psa_aead_decrypt_setup(&op, key_id, PSA_ALG_GCM); + if (check_status(st, "psa_aead_decrypt_setup(word32 input)") != TEST_OK) goto cleanup; + st = psa_aead_set_nonce(&op, nonce, sizeof(nonce)); + if (check_status(st, "psa_aead_set_nonce(word32 verify input)") != TEST_OK) goto cleanup; + ctx = wolfpsa_aead_get_ctx_ptr(&op); + ctx->input = NULL; + ctx->input_length = (size_t)UINT32_MAX + 1u; + st = psa_aead_verify(&op, out, SIZE_MAX, &out_len, empty_gcm_tag, sizeof(empty_gcm_tag)); + if (check_true(st == PSA_ERROR_INVALID_ARGUMENT, + "psa_aead_verify rejects input_length above word32") != TEST_OK) { + ret = TEST_FAIL; + goto cleanup; + } + + st = psa_aead_decrypt_setup(&op, key_id, PSA_ALG_GCM); + if (check_status(st, "psa_aead_decrypt_setup(word32 aad)") != TEST_OK) goto cleanup; + st = psa_aead_set_nonce(&op, nonce, sizeof(nonce)); + if (check_status(st, "psa_aead_set_nonce(word32 verify aad)") != TEST_OK) goto cleanup; + ctx = wolfpsa_aead_get_ctx_ptr(&op); + ctx->aad = NULL; + ctx->aad_length = (size_t)UINT32_MAX + 1u; + st = psa_aead_verify(&op, out, sizeof(out), &out_len, empty_gcm_tag, sizeof(empty_gcm_tag)); + if (check_true(st == PSA_ERROR_INVALID_ARGUMENT, + "psa_aead_verify rejects aad_length above word32") != TEST_OK) { + ret = TEST_FAIL; + goto cleanup; + } + +cleanup: + psa_aead_abort(&op); + st = psa_destroy_key(key_id); + if (check_status(st, "psa_destroy_key(GCM word32 overflow)") != TEST_OK) { + return TEST_FAIL; + } + return ret; +} + static int test_chacha20_poly1305_rejects_aes_key(void) { static const uint8_t key[32] = { @@ -903,6 +1004,299 @@ static int test_kdf_null_capacity(void) return TEST_OK; } +static int test_kdf_tls12_psk_to_ms_rfc4279_order(void) +{ + static const uint8_t psk[] = { 0xa1, 0xb2, 0xc3, 0xd4, 0xe5 }; + static const uint8_t other_secret[] = { 0x10, 0x20, 0x30 }; + static const uint8_t seed[] = "clienthello||serverhello"; + uint8_t premaster[2u + sizeof(other_secret) + 2u + sizeof(psk)]; + uint8_t expected[48]; + uint8_t output[sizeof(expected)]; + size_t seed_len = sizeof(seed) - 1u; + psa_key_derivation_operation_t op = psa_key_derivation_operation_init(); + psa_status_t st; + int ret; + + premaster[0] = 0x00; + premaster[1] = (uint8_t)sizeof(other_secret); + memcpy(premaster + 2u, other_secret, sizeof(other_secret)); + premaster[2u + sizeof(other_secret)] = 0x00; + premaster[3u + sizeof(other_secret)] = (uint8_t)sizeof(psk); + memcpy(premaster + 4u + sizeof(other_secret), psk, sizeof(psk)); + + ret = wc_PRF_TLS(expected, (word32)sizeof(expected), + premaster, (word32)sizeof(premaster), + (const byte*)"master secret", 13u, + seed, (word32)seed_len, + 1, WC_HASH_TYPE_SHA256, NULL, INVALID_DEVID); + if (ret != 0) { + printf("FAIL: wc_PRF_TLS(TLS12_PSK_TO_MS reference) (%d)\n", ret); + return TEST_FAIL; + } + + st = psa_key_derivation_setup(&op, PSA_ALG_TLS12_PSK_TO_MS(PSA_ALG_SHA_256)); + if (check_status(st, "psa_key_derivation_setup(TLS12_PSK_TO_MS)") != TEST_OK) { + return TEST_FAIL; + } + st = psa_key_derivation_input_bytes(&op, PSA_KEY_DERIVATION_INPUT_SEED, + seed, seed_len); + if (check_status(st, "psa_key_derivation_input_bytes(SEED)") != TEST_OK) { + (void)psa_key_derivation_abort(&op); + return TEST_FAIL; + } + st = psa_key_derivation_input_bytes(&op, + PSA_KEY_DERIVATION_INPUT_OTHER_SECRET, + other_secret, sizeof(other_secret)); + if (check_status(st, "psa_key_derivation_input_bytes(OTHER_SECRET)") != TEST_OK) { + (void)psa_key_derivation_abort(&op); + return TEST_FAIL; + } + st = psa_key_derivation_input_bytes(&op, PSA_KEY_DERIVATION_INPUT_SECRET, + psk, sizeof(psk)); + if (check_status(st, "psa_key_derivation_input_bytes(SECRET)") != TEST_OK) { + (void)psa_key_derivation_abort(&op); + return TEST_FAIL; + } + st = psa_key_derivation_output_bytes(&op, output, sizeof(output)); + if (check_status(st, "psa_key_derivation_output_bytes(TLS12_PSK_TO_MS)") != TEST_OK) { + (void)psa_key_derivation_abort(&op); + return TEST_FAIL; + } + st = psa_key_derivation_abort(&op); + if (check_status(st, "psa_key_derivation_abort(TLS12_PSK_TO_MS)") != TEST_OK) { + return TEST_FAIL; + } + + if (check_buf_eq("psa_key_derivation_output_bytes(TLS12_PSK_TO_MS RFC4279)", + output, expected, sizeof(expected)) != TEST_OK) { + return TEST_FAIL; + } + + return TEST_OK; +} + +static int test_kdf_tls12_psk_to_ms_plain_psk_optional_other_secret(void) +{ + static const uint8_t psk[] = { 0xa1, 0xb2, 0xc3, 0xd4, 0xe5 }; + static const uint8_t seed[] = "clienthello||serverhello"; + uint8_t premaster[2u + sizeof(psk) + 2u + sizeof(psk)]; + uint8_t expected[48]; + uint8_t output[sizeof(expected)]; + size_t seed_len = sizeof(seed) - 1u; + psa_key_derivation_operation_t op = psa_key_derivation_operation_init(); + psa_status_t st; + int ret; + + premaster[0] = 0x00; + premaster[1] = (uint8_t)sizeof(psk); + memset(premaster + 2u, 0, sizeof(psk)); + premaster[2u + sizeof(psk)] = 0x00; + premaster[3u + sizeof(psk)] = (uint8_t)sizeof(psk); + memcpy(premaster + 4u + sizeof(psk), psk, sizeof(psk)); + + ret = wc_PRF_TLS(expected, (word32)sizeof(expected), + premaster, (word32)sizeof(premaster), + (const byte*)"master secret", 13u, + seed, (word32)seed_len, + 1, WC_HASH_TYPE_SHA256, NULL, INVALID_DEVID); + if (ret != 0) { + printf("FAIL: wc_PRF_TLS(TLS12_PSK_TO_MS plain PSK reference) (%d)\n", ret); + return TEST_FAIL; + } + + st = psa_key_derivation_setup(&op, PSA_ALG_TLS12_PSK_TO_MS(PSA_ALG_SHA_256)); + if (check_status(st, "psa_key_derivation_setup(TLS12_PSK_TO_MS plain PSK)") != TEST_OK) { + return TEST_FAIL; + } + st = psa_key_derivation_input_bytes(&op, PSA_KEY_DERIVATION_INPUT_SEED, + seed, seed_len); + if (check_status(st, "psa_key_derivation_input_bytes(SEED plain PSK)") != TEST_OK) { + (void)psa_key_derivation_abort(&op); + return TEST_FAIL; + } + st = psa_key_derivation_input_bytes(&op, PSA_KEY_DERIVATION_INPUT_SECRET, + psk, sizeof(psk)); + if (check_status(st, "psa_key_derivation_input_bytes(SECRET plain PSK)") != TEST_OK) { + (void)psa_key_derivation_abort(&op); + return TEST_FAIL; + } + st = psa_key_derivation_output_bytes(&op, output, sizeof(output)); + if (check_status(st, "psa_key_derivation_output_bytes(TLS12_PSK_TO_MS plain PSK)") != TEST_OK) { + (void)psa_key_derivation_abort(&op); + return TEST_FAIL; + } + st = psa_key_derivation_abort(&op); + if (check_status(st, "psa_key_derivation_abort(TLS12_PSK_TO_MS plain PSK)") != TEST_OK) { + return TEST_FAIL; + } + + if (check_buf_eq("psa_key_derivation_output_bytes(TLS12_PSK_TO_MS plain PSK RFC4279)", + output, expected, sizeof(expected)) != TEST_OK) { + return TEST_FAIL; + } + + return TEST_OK; +} + +static int test_kdf_hkdf_extract_optional_salt(void) +{ + static const uint8_t secret[] = "hkdf extract secret"; + uint8_t expected[WC_SHA256_DIGEST_SIZE]; + uint8_t output[sizeof(expected)]; + psa_key_derivation_operation_t op = psa_key_derivation_operation_init(); + psa_status_t st; + int ret; + + ret = wc_HKDF_Extract(WC_HASH_TYPE_SHA256, + NULL, 0, + secret, (word32)(sizeof(secret) - 1u), + expected); + if (ret != 0) { + printf("FAIL: wc_HKDF_Extract(HKDF_EXTRACT optional salt reference) (%d)\n", ret); + return TEST_FAIL; + } + + st = psa_key_derivation_setup(&op, PSA_ALG_HKDF_EXTRACT(PSA_ALG_SHA_256)); + if (check_status(st, "psa_key_derivation_setup(HKDF_EXTRACT optional salt)") != TEST_OK) { + return TEST_FAIL; + } + st = psa_key_derivation_input_bytes(&op, PSA_KEY_DERIVATION_INPUT_SALT, NULL, 0); + if (check_status(st, "psa_key_derivation_input_bytes(SALT HKDF_EXTRACT optional salt)") != TEST_OK) { + (void)psa_key_derivation_abort(&op); + return TEST_FAIL; + } + st = psa_key_derivation_input_bytes(&op, PSA_KEY_DERIVATION_INPUT_SECRET, + secret, sizeof(secret) - 1u); + if (check_status(st, "psa_key_derivation_input_bytes(SECRET HKDF_EXTRACT optional salt)") != TEST_OK) { + (void)psa_key_derivation_abort(&op); + return TEST_FAIL; + } + st = psa_key_derivation_output_bytes(&op, output, sizeof(output)); + if (check_status(st, "psa_key_derivation_output_bytes(HKDF_EXTRACT optional salt)") != TEST_OK) { + (void)psa_key_derivation_abort(&op); + return TEST_FAIL; + } + st = psa_key_derivation_abort(&op); + if (check_status(st, "psa_key_derivation_abort(HKDF_EXTRACT optional salt)") != TEST_OK) { + return TEST_FAIL; + } + + if (check_buf_eq("psa_key_derivation_output_bytes(HKDF_EXTRACT optional salt)", + output, expected, sizeof(expected)) != TEST_OK) { + return TEST_FAIL; + } + + return TEST_OK; +} + +static int test_kdf_hkdf_expand_optional_info(void) +{ + static const uint8_t prk[WC_SHA256_DIGEST_SIZE] = { + 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 + }; + uint8_t expected[42]; + uint8_t output[sizeof(expected)]; + psa_key_derivation_operation_t op = psa_key_derivation_operation_init(); + psa_status_t st; + int ret; + + ret = wc_HKDF_Expand(WC_HASH_TYPE_SHA256, + prk, (word32)sizeof(prk), + NULL, 0, + expected, (word32)sizeof(expected)); + if (ret != 0) { + printf("FAIL: wc_HKDF_Expand(HKDF_EXPAND optional info reference) (%d)\n", ret); + return TEST_FAIL; + } + + st = psa_key_derivation_setup(&op, PSA_ALG_HKDF_EXPAND(PSA_ALG_SHA_256)); + if (check_status(st, "psa_key_derivation_setup(HKDF_EXPAND optional info)") != TEST_OK) { + return TEST_FAIL; + } + st = psa_key_derivation_input_bytes(&op, PSA_KEY_DERIVATION_INPUT_SECRET, + prk, sizeof(prk)); + if (check_status(st, "psa_key_derivation_input_bytes(SECRET HKDF_EXPAND optional info)") != TEST_OK) { + (void)psa_key_derivation_abort(&op); + return TEST_FAIL; + } + st = psa_key_derivation_input_bytes(&op, PSA_KEY_DERIVATION_INPUT_INFO, NULL, 0); + if (check_status(st, "psa_key_derivation_input_bytes(INFO HKDF_EXPAND optional info)") != TEST_OK) { + (void)psa_key_derivation_abort(&op); + return TEST_FAIL; + } + st = psa_key_derivation_output_bytes(&op, output, sizeof(output)); + if (check_status(st, "psa_key_derivation_output_bytes(HKDF_EXPAND optional info)") != TEST_OK) { + (void)psa_key_derivation_abort(&op); + return TEST_FAIL; + } + st = psa_key_derivation_abort(&op); + if (check_status(st, "psa_key_derivation_abort(HKDF_EXPAND optional info)") != TEST_OK) { + return TEST_FAIL; + } + + if (check_buf_eq("psa_key_derivation_output_bytes(HKDF_EXPAND optional info)", + output, expected, sizeof(expected)) != TEST_OK) { + return TEST_FAIL; + } + + return TEST_OK; +} + +static int test_kdf_hkdf_optional_info(void) +{ + static const uint8_t secret[] = "hkdf secret"; + uint8_t expected[42]; + uint8_t output[sizeof(expected)]; + psa_key_derivation_operation_t op = psa_key_derivation_operation_init(); + psa_status_t st; + int ret; + + ret = wc_HKDF(WC_HASH_TYPE_SHA256, + secret, (word32)(sizeof(secret) - 1u), + NULL, 0, + NULL, 0, + expected, (word32)sizeof(expected)); + if (ret != 0) { + printf("FAIL: wc_HKDF(HKDF optional info reference) (%d)\n", ret); + return TEST_FAIL; + } + + st = psa_key_derivation_setup(&op, PSA_ALG_HKDF(PSA_ALG_SHA_256)); + if (check_status(st, "psa_key_derivation_setup(HKDF optional info)") != TEST_OK) { + return TEST_FAIL; + } + st = psa_key_derivation_input_bytes(&op, PSA_KEY_DERIVATION_INPUT_SECRET, + secret, sizeof(secret) - 1u); + if (check_status(st, "psa_key_derivation_input_bytes(SECRET HKDF optional info)") != TEST_OK) { + (void)psa_key_derivation_abort(&op); + return TEST_FAIL; + } + st = psa_key_derivation_input_bytes(&op, PSA_KEY_DERIVATION_INPUT_INFO, NULL, 0); + if (check_status(st, "psa_key_derivation_input_bytes(INFO HKDF optional info)") != TEST_OK) { + (void)psa_key_derivation_abort(&op); + return TEST_FAIL; + } + st = psa_key_derivation_output_bytes(&op, output, sizeof(output)); + if (check_status(st, "psa_key_derivation_output_bytes(HKDF optional info)") != TEST_OK) { + (void)psa_key_derivation_abort(&op); + return TEST_FAIL; + } + st = psa_key_derivation_abort(&op); + if (check_status(st, "psa_key_derivation_abort(HKDF optional info)") != TEST_OK) { + return TEST_FAIL; + } + + if (check_buf_eq("psa_key_derivation_output_bytes(HKDF optional info)", + output, expected, sizeof(expected)) != TEST_OK) { + return TEST_FAIL; + } + + return TEST_OK; +} + static int run_named_test(const char* name, test_fn_t fn) { int ret; @@ -960,6 +1354,12 @@ int main(int argc, char** argv) return TEST_FAIL; } } + if (only == NULL || strcmp(only, "aead_word32_overflow") == 0) { + if (run_named_test("aead_word32_overflow", + test_aead_finish_verify_word32_overflow_rejected) == 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) { @@ -987,6 +1387,34 @@ int main(int argc, char** argv) 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; } + if (only == NULL || strcmp(only, "kdf_tls12_psk_to_ms") == 0) { + if (run_named_test("kdf_tls12_psk_to_ms", + test_kdf_tls12_psk_to_ms_rfc4279_order) == TEST_FAIL) { + return TEST_FAIL; + } + if (run_named_test("kdf_tls12_psk_to_ms_plain_psk", + test_kdf_tls12_psk_to_ms_plain_psk_optional_other_secret) == TEST_FAIL) { + return TEST_FAIL; + } + } + if (only == NULL || strcmp(only, "kdf_hkdf_extract_optional_salt") == 0) { + if (run_named_test("kdf_hkdf_extract_optional_salt", + test_kdf_hkdf_extract_optional_salt) == TEST_FAIL) { + return TEST_FAIL; + } + } + if (only == NULL || strcmp(only, "kdf_hkdf_expand_optional_info") == 0) { + if (run_named_test("kdf_hkdf_expand_optional_info", + test_kdf_hkdf_expand_optional_info) == TEST_FAIL) { + return TEST_FAIL; + } + } + if (only == NULL || strcmp(only, "kdf_hkdf_optional_info") == 0) { + if (run_named_test("kdf_hkdf_optional_info", + test_kdf_hkdf_optional_info) == TEST_FAIL) { + return TEST_FAIL; + } + } printf("PSA API test: OK (passed=%d skipped=%d)\n", tests_passed, tests_skipped);