diff --git a/tf-psa-crypto/core/psa_crypto.c b/tf-psa-crypto/core/psa_crypto.c index 359d622728..b24634500c 100644 --- a/tf-psa-crypto/core/psa_crypto.c +++ b/tf-psa-crypto/core/psa_crypto.c @@ -2437,6 +2437,58 @@ exit: /* Message digests */ /****************************************************************/ +static int is_hash_supported(psa_algorithm_t alg) +{ + switch (alg) { +#if defined(PSA_WANT_ALG_MD5) + case PSA_ALG_MD5: + return 1; +#endif +#if defined(PSA_WANT_ALG_RIPEMD160) + case PSA_ALG_RIPEMD160: + return 1; +#endif +#if defined(PSA_WANT_ALG_SHA_1) + case PSA_ALG_SHA_1: + return 1; +#endif +#if defined(PSA_WANT_ALG_SHA_224) + case PSA_ALG_SHA_224: + return 1; +#endif +#if defined(PSA_WANT_ALG_SHA_256) + case PSA_ALG_SHA_256: + return 1; +#endif +#if defined(PSA_WANT_ALG_SHA_384) + case PSA_ALG_SHA_384: + return 1; +#endif +#if defined(PSA_WANT_ALG_SHA_512) + case PSA_ALG_SHA_512: + return 1; +#endif +#if defined(PSA_WANT_ALG_SHA3_224) + case PSA_ALG_SHA3_224: + return 1; +#endif +#if defined(PSA_WANT_ALG_SHA3_256) + case PSA_ALG_SHA3_256: + return 1; +#endif +#if defined(PSA_WANT_ALG_SHA3_384) + case PSA_ALG_SHA3_384: + return 1; +#endif +#if defined(PSA_WANT_ALG_SHA3_512) + case PSA_ALG_SHA3_512: + return 1; +#endif + default: + return 0; + } +} + psa_status_t psa_hash_abort(psa_hash_operation_t *operation) { /* Aborting a non-active operation is allowed */ @@ -3080,16 +3132,44 @@ static psa_status_t psa_sign_verify_check_alg(int input_is_message, if (!PSA_ALG_IS_SIGN_MESSAGE(alg)) { return PSA_ERROR_INVALID_ARGUMENT; } + } - if (PSA_ALG_IS_SIGN_HASH(alg)) { - if (!PSA_ALG_IS_HASH(PSA_ALG_SIGN_GET_HASH(alg))) { - return PSA_ERROR_INVALID_ARGUMENT; - } - } - } else { - if (!PSA_ALG_IS_SIGN_HASH(alg)) { - return PSA_ERROR_INVALID_ARGUMENT; - } + psa_algorithm_t hash_alg = 0; + if (PSA_ALG_IS_SIGN_HASH(alg)) { + hash_alg = PSA_ALG_SIGN_GET_HASH(alg); + } + + /* Now hash_alg==0 if alg by itself doesn't need a hash. + * This is good enough for sign-hash, but a guaranteed failure for + * sign-message which needs to hash first for all algorithms + * supported at the moment. */ + + if (hash_alg == 0 && input_is_message) { + return PSA_ERROR_INVALID_ARGUMENT; + } + if (hash_alg == PSA_ALG_ANY_HASH) { + return PSA_ERROR_INVALID_ARGUMENT; + } + /* Give up immediately if the hash is not supported. This has + * several advantages: + * - For mechanisms that don't use the hash at all (e.g. + * ECDSA verification, randomized ECDSA signature), without + * this check, the operation would succeed even though it has + * been given an invalid argument. This would not be insecure + * since the hash was not necessary, but it would be weird. + * - For mechanisms that do use the hash, we avoid an error + * deep inside the execution. In principle this doesn't matter, + * but there is a little more risk of a bug in error handling + * deep inside than in this preliminary check. + * - When calling a driver, the driver might be capable of using + * a hash that the core doesn't support. This could potentially + * result in a buffer overflow if the hash is larger than the + * maximum hash size assumed by the core. + * - Returning a consistent error makes it possible to test + * not-supported hashes in a consistent way. + */ + if (hash_alg != 0 && !is_hash_supported(hash_alg)) { + return PSA_ERROR_NOT_SUPPORTED; } return PSA_SUCCESS;