PSA sign/verify: more uniform error on an unsupported hash
Uniformly return PSA_ERROR_NOT_SUPPORTED if given an algorithm that includes
a hash, but that hash algorithm is not supported. This will make it easier
to have a uniform treatment of unsupported hashes in automatically generated
tests.
Signed-off-by: Gilles Peskine <Gilles.Peskine@arm.com>
diff --git a/library/psa_crypto.c b/library/psa_crypto.c
index f0ccf3d..c28491e 100644
--- a/library/psa_crypto.c
+++ b/library/psa_crypto.c
@@ -2319,6 +2319,58 @@
/* 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 */
@@ -2962,16 +3014,44 @@
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;