Add support for key policies in addition to specific algorithms

Initially contributed: minimum-tag-length AEAD and MAC policies.
Includes tests.

Signed-off-by: Steven Cooreman <steven.cooreman@silabs.com>
diff --git a/ChangeLog.d/psa-crypto-key-policies.txt b/ChangeLog.d/psa-crypto-key-policies.txt
new file mode 100644
index 0000000..6fe180a
--- /dev/null
+++ b/ChangeLog.d/psa-crypto-key-policies.txt
@@ -0,0 +1,5 @@
+Features
+   * A key in PSA Crypto can now be defined with a policy instead of a specific
+     algorithm. Policies describe a collection of allowed specific algorithms.
+     Initial policies are PSA_ALG_AEAD_POLICY_WITH_MINIMUM_TAG_LENGTH and
+     PSA_ALG_MAC_POLICY_WITH_MINIMUM_TAG_LENGTH.
diff --git a/include/psa/crypto.h b/include/psa/crypto.h
index b41a20b..58d366b 100644
--- a/include/psa/crypto.h
+++ b/include/psa/crypto.h
@@ -260,6 +260,8 @@
  * - An algorithm value permits this particular algorithm.
  * - An algorithm wildcard built from #PSA_ALG_ANY_HASH allows the specified
  *   signature scheme with any hash algorithm.
+ * - An algorithm with the #PSA_ALG_POLICY_FLAG bit set allows the
+ *   algorithm collection specified by that algorithm policy definition.
  *
  * This function overwrites any algorithm policy
  * previously set in \p attributes.
diff --git a/include/psa/crypto_values.h b/include/psa/crypto_values.h
index 9610d5f..3261b63 100644
--- a/include/psa/crypto_values.h
+++ b/include/psa/crypto_values.h
@@ -608,7 +608,17 @@
  */
 #define PSA_ALG_VENDOR_FLAG                     ((psa_algorithm_t)0x80000000)
 
-#define PSA_ALG_CATEGORY_MASK                   ((psa_algorithm_t)0x7f000000)
+/** Policy-only flag.
+ *
+ * An algorithm defined by this standard can have the #PSA_ALG_POLICY_FLAG bit
+ * set to indicate the value can only be used in a usage policy definition.
+ * The use case is primarily defining key usage policies, where a policy can
+ * encompass more than one specific algorithm, e.g. AEAD or MAC algorithms
+ * with multiple tag lengths.
+ */
+#define PSA_ALG_POLICY_FLAG                     ((psa_algorithm_t)0x40000000)
+
+#define PSA_ALG_CATEGORY_MASK                   ((psa_algorithm_t)0x3f000000)
 #define PSA_ALG_CATEGORY_HASH                   ((psa_algorithm_t)0x02000000)
 #define PSA_ALG_CATEGORY_MAC                    ((psa_algorithm_t)0x03000000)
 #define PSA_ALG_CATEGORY_CIPHER                 ((psa_algorithm_t)0x04000000)
@@ -625,6 +635,13 @@
 #define PSA_ALG_IS_VENDOR_DEFINED(alg)                                  \
     (((alg) & PSA_ALG_VENDOR_FLAG) != 0)
 
+/** Whether an algorithm is a policy (collection of algorithms).
+ *
+ * See also #PSA_ALG_POLICY_FLAG.
+ */
+#define PSA_ALG_IS_POLICY(alg)                                  \
+    (((alg) & PSA_ALG_POLICY_FLAG) != 0)
+
 /** Whether the specified algorithm is a hash algorithm.
  *
  * \param alg An algorithm identifier (value of type #psa_algorithm_t).
@@ -634,7 +651,8 @@
  *         algorithm identifier.
  */
 #define PSA_ALG_IS_HASH(alg)                                            \
-    (((alg) & PSA_ALG_CATEGORY_MASK) == PSA_ALG_CATEGORY_HASH)
+    ((((alg) & PSA_ALG_CATEGORY_MASK) == PSA_ALG_CATEGORY_HASH) &&      \
+      !PSA_ALG_IS_POLICY(alg))
 
 /** Whether the specified algorithm is a MAC algorithm.
  *
@@ -645,7 +663,23 @@
  *         algorithm identifier.
  */
 #define PSA_ALG_IS_MAC(alg)                                             \
-    (((alg) & PSA_ALG_CATEGORY_MASK) == PSA_ALG_CATEGORY_MAC)
+    ((((alg) & PSA_ALG_CATEGORY_MASK) == PSA_ALG_CATEGORY_MAC) &&       \
+      !PSA_ALG_IS_POLICY(alg))
+
+/** Whether the specified algorithm is a policy containing a MAC
+ * algorithm collection, sharing the same base algorithm but multiple
+ * allowed tag lengths.
+ *
+ * \param alg An algorithm identifier (value of type #psa_algorithm_t).
+ *
+ * \return 1 if \p alg is a MAC algorithm policy with minimum tag length,
+ *         0 otherwise.
+ *         This macro may return either 0 or 1 if \p alg is not a supported
+ *         algorithm identifier.
+ */
+#define PSA_ALG_IS_MAC_POLICY_WITH_MINIMUM_TAG_LENGTH(alg)                                             \
+    ((((alg) & PSA_ALG_CATEGORY_MASK) == PSA_ALG_CATEGORY_MAC) &&       \
+      PSA_ALG_IS_POLICY(alg))
 
 /** Whether the specified algorithm is a symmetric cipher algorithm.
  *
@@ -656,7 +690,8 @@
  *         algorithm identifier.
  */
 #define PSA_ALG_IS_CIPHER(alg)                                          \
-    (((alg) & PSA_ALG_CATEGORY_MASK) == PSA_ALG_CATEGORY_CIPHER)
+    ((((alg) & PSA_ALG_CATEGORY_MASK) == PSA_ALG_CATEGORY_CIPHER) &&    \
+      !PSA_ALG_IS_POLICY(alg))
 
 /** Whether the specified algorithm is an authenticated encryption
  * with associated data (AEAD) algorithm.
@@ -668,7 +703,23 @@
  *         algorithm identifier.
  */
 #define PSA_ALG_IS_AEAD(alg)                                            \
-    (((alg) & PSA_ALG_CATEGORY_MASK) == PSA_ALG_CATEGORY_AEAD)
+    ((((alg) & PSA_ALG_CATEGORY_MASK) == PSA_ALG_CATEGORY_AEAD) &&      \
+      !PSA_ALG_IS_POLICY(alg))
+
+/** Whether the specified algorithm is a policy containing an authenticated
+ * encryption with associated data (AEAD) algorithm collection, sharing the
+ * same base algorithm but multiple allowed tag lengths.
+ *
+ * \param alg An algorithm identifier (value of type #psa_algorithm_t).
+ *
+ * \return 1 if \p alg is an AEAD algorithm policy with minimum tag length,
+ *         0 otherwise.
+ *         This macro may return either 0 or 1 if \p alg is not a supported
+ *         algorithm identifier.
+ */
+#define PSA_ALG_IS_AEAD_POLICY_WITH_MINIMUM_TAG_LENGTH(alg)             \
+    ((((alg) & PSA_ALG_CATEGORY_MASK) == PSA_ALG_CATEGORY_AEAD) &&      \
+      PSA_ALG_IS_POLICY(alg))
 
 /** Whether the specified algorithm is an asymmetric signature algorithm,
  * also known as public-key signature algorithm.
@@ -680,7 +731,8 @@
  *         algorithm identifier.
  */
 #define PSA_ALG_IS_SIGN(alg)                                            \
-    (((alg) & PSA_ALG_CATEGORY_MASK) == PSA_ALG_CATEGORY_SIGN)
+    ((((alg) & PSA_ALG_CATEGORY_MASK) == PSA_ALG_CATEGORY_SIGN) &&      \
+      !PSA_ALG_IS_POLICY(alg))
 
 /** Whether the specified algorithm is an asymmetric encryption algorithm,
  * also known as public-key encryption algorithm.
@@ -692,7 +744,8 @@
  *         algorithm identifier.
  */
 #define PSA_ALG_IS_ASYMMETRIC_ENCRYPTION(alg)                           \
-    (((alg) & PSA_ALG_CATEGORY_MASK) == PSA_ALG_CATEGORY_ASYMMETRIC_ENCRYPTION)
+    ((((alg) & PSA_ALG_CATEGORY_MASK) == PSA_ALG_CATEGORY_ASYMMETRIC_ENCRYPTION) && \
+      !PSA_ALG_IS_POLICY(alg))
 
 /** Whether the specified algorithm is a key agreement algorithm.
  *
@@ -702,8 +755,9 @@
  *         This macro may return either 0 or 1 if \p alg is not a supported
  *         algorithm identifier.
  */
-#define PSA_ALG_IS_KEY_AGREEMENT(alg)                                   \
-    (((alg) & PSA_ALG_CATEGORY_MASK) == PSA_ALG_CATEGORY_KEY_AGREEMENT)
+#define PSA_ALG_IS_KEY_AGREEMENT(alg)                                       \
+    ((((alg) & PSA_ALG_CATEGORY_MASK) == PSA_ALG_CATEGORY_KEY_AGREEMENT) && \
+      !PSA_ALG_IS_POLICY(alg))
 
 /** Whether the specified algorithm is a key derivation algorithm.
  *
@@ -713,8 +767,9 @@
  *         This macro may return either 0 or 1 if \p alg is not a supported
  *         algorithm identifier.
  */
-#define PSA_ALG_IS_KEY_DERIVATION(alg)                                  \
-    (((alg) & PSA_ALG_CATEGORY_MASK) == PSA_ALG_CATEGORY_KEY_DERIVATION)
+#define PSA_ALG_IS_KEY_DERIVATION(alg)                                        \
+    ((((alg) & PSA_ALG_CATEGORY_MASK) == PSA_ALG_CATEGORY_KEY_DERIVATION) &&  \
+      !PSA_ALG_IS_POLICY(alg))
 
 #define PSA_ALG_HASH_MASK                       ((psa_algorithm_t)0x000000ff)
 /** MD2 */
@@ -914,6 +969,27 @@
     (((alg) & (PSA_ALG_CATEGORY_MASK | PSA_ALG_MAC_SUBCATEGORY_MASK)) == \
      PSA_ALG_CIPHER_MAC_BASE)
 
+/** Macro to build a MAC minimum-tag-length algorithm policy.
+ *
+ * A mininimum-tag-length MAC algorithm policy contains all MAC algorithms
+ * sharing the same base algorithm, and where the tag length of the specific
+ * algorithm is equal to or larger then the policy's minimum tag length.
+ *
+ * \param mac_alg       A MAC algorithm identifier (value of type
+ *                      #psa_algorithm_t such that #PSA_ALG_IS_MAC(\p alg)
+ *                      is true).
+ * \param tag_length    Desired minimum length of the authentication tag in
+ *                      bytes.
+ *
+ * \return              The corresponding MAC algorithm policy with the
+ *                      specified minimum length.
+ * \return              Unspecified if \p alg is not a supported
+ *                      MAC algorithm or if \p tag_length is not valid
+ *                      for the specified MAC algorithm.
+ */
+#define PSA_ALG_MAC_POLICY_WITH_MINIMUM_TAG_LENGTH(mac_alg, tag_length) \
+    ( PSA_ALG_TRUNCATED_MAC(mac_alg, tag_length) | PSA_ALG_POLICY_FLAG )
+
 #define PSA_ALG_CIPHER_STREAM_FLAG              ((psa_algorithm_t)0x00800000)
 #define PSA_ALG_CIPHER_FROM_BLOCK_FLAG          ((psa_algorithm_t)0x00400000)
 
@@ -1075,6 +1151,21 @@
      ((tag_length) << PSA_AEAD_TAG_LENGTH_OFFSET &                      \
       PSA_ALG_AEAD_TAG_LENGTH_MASK))
 
+/** Retrieve the tag length of a specified AEAD algorithm
+ *
+ * \param aead_alg      An AEAD algorithm identifier (value of type
+ *                      #psa_algorithm_t such that #PSA_ALG_IS_AEAD(\p alg)
+ *                      is true).
+ *
+ * \return              The tag length specified by the input algorithm.
+ * \return              Unspecified if \p alg is not a supported
+ *                      AEAD algorithm or if \p tag_length is not valid
+ *                      for the specified AEAD algorithm.
+ */
+#define PSA_ALG_AEAD_GET_TAG_LENGTH(aead_alg)                           \
+    (((aead_alg) & PSA_ALG_AEAD_TAG_LENGTH_MASK) >>                     \
+      PSA_AEAD_TAG_LENGTH_OFFSET )
+
 /** Calculate the corresponding AEAD algorithm with the default tag length.
  *
  * \param aead_alg      An AEAD algorithm (\c PSA_ALG_XXX value such that
@@ -1094,6 +1185,28 @@
     PSA_ALG_AEAD_WITH_TAG_LENGTH(ref, 0) ?                               \
     ref :
 
+/** Macro to build an AEAD minimum-tag-length algorithm policy.
+ *
+ * A mininimum-tag-length AEAD algorithm policy contains all AEAD algorithms
+ * sharing the same base algorithm, and where the tag length of the specific
+ * algorithm is equal to or larger then the policy's minimum tag length.
+ *
+ * \param aead_alg      An AEAD algorithm identifier (value of type
+ *                      #psa_algorithm_t such that #PSA_ALG_IS_AEAD(\p alg)
+ *                      is true).
+ * \param tag_length    Desired minimum length of the authentication tag in
+ *                      bytes.
+ *
+ * \return              The corresponding AEAD algorithm policy with the
+ *                      specified minimum length.
+ * \return              Unspecified if \p alg is not a supported
+ *                      AEAD algorithm or if \p tag_length is not valid
+ *                      for the specified AEAD algorithm.
+ */
+#define PSA_ALG_AEAD_POLICY_WITH_MINIMUM_TAG_LENGTH(aead_alg, tag_length) \
+    ( PSA_ALG_AEAD_WITH_TAG_LENGTH(aead_alg, tag_length) |                \
+      PSA_ALG_POLICY_FLAG )
+
 #define PSA_ALG_RSA_PKCS1V15_SIGN_BASE          ((psa_algorithm_t)0x06000200)
 /** RSA PKCS#1 v1.5 signature with hashing.
  *
diff --git a/library/psa_crypto.c b/library/psa_crypto.c
index 7ea2a1a..51e8bbb 100644
--- a/library/psa_crypto.c
+++ b/library/psa_crypto.c
@@ -1179,6 +1179,9 @@
 static int psa_key_algorithm_permits( psa_algorithm_t policy_alg,
                                       psa_algorithm_t requested_alg )
 {
+    /* A requested algorithm cannot be a collection. */
+    if( PSA_ALG_IS_POLICY( requested_alg ) )
+        return( 0 );
     /* Common case: the policy only allows requested_alg. */
     if( requested_alg == policy_alg )
         return( 1 );
@@ -1200,6 +1203,26 @@
         return( PSA_ALG_KEY_AGREEMENT_GET_BASE( requested_alg ) ==
                 policy_alg );
     }
+    /* If policy_alg is a policy, then special rules apply. */
+    if( PSA_ALG_IS_POLICY( policy_alg ) )
+    {
+        if( PSA_ALG_IS_AEAD_POLICY_WITH_MINIMUM_TAG_LENGTH( policy_alg ) &&
+            PSA_ALG_IS_AEAD( requested_alg ) &&
+            ( PSA_ALG_AEAD_POLICY_WITH_MINIMUM_TAG_LENGTH( requested_alg, 0 ) ==
+              PSA_ALG_AEAD_POLICY_WITH_MINIMUM_TAG_LENGTH( policy_alg, 0 ) ) )
+        {
+            return( PSA_ALG_AEAD_GET_TAG_LENGTH( policy_alg ) <=
+                    PSA_ALG_AEAD_GET_TAG_LENGTH( requested_alg ) );
+        }
+        if( PSA_ALG_IS_MAC_POLICY_WITH_MINIMUM_TAG_LENGTH( policy_alg ) &&
+            PSA_ALG_IS_MAC( requested_alg ) &&
+            ( PSA_ALG_MAC_POLICY_WITH_MINIMUM_TAG_LENGTH( requested_alg, 0 ) ==
+              PSA_ALG_MAC_POLICY_WITH_MINIMUM_TAG_LENGTH( policy_alg, 0 ) ) )
+        {
+            return( PSA_MAC_TRUNCATED_LENGTH( policy_alg ) <=
+                    PSA_MAC_TRUNCATED_LENGTH( requested_alg ) );
+        }
+    }
     /* If it isn't permitted, it's forbidden. */
     return( 0 );
 }
diff --git a/tests/suites/test_suite_psa_crypto.data b/tests/suites/test_suite_psa_crypto.data
index f267c15..fe589db 100644
--- a/tests/suites/test_suite_psa_crypto.data
+++ b/tests/suites/test_suite_psa_crypto.data
@@ -393,31 +393,51 @@
 
 PSA key policy: MAC, sign | verify
 depends_on:MBEDTLS_SHA256_C
-mac_key_policy:PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_VERIFY_HASH:PSA_ALG_HMAC(PSA_ALG_SHA_256):PSA_KEY_TYPE_HMAC:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa":PSA_ALG_HMAC(PSA_ALG_SHA_256)
+mac_key_policy:PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_VERIFY_HASH:PSA_ALG_HMAC(PSA_ALG_SHA_256):PSA_KEY_TYPE_HMAC:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa":PSA_ALG_HMAC(PSA_ALG_SHA_256):PSA_SUCCESS
 
 PSA key policy: MAC, wrong algorithm
 depends_on:MBEDTLS_SHA256_C
-mac_key_policy:PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_VERIFY_HASH:PSA_ALG_HMAC(PSA_ALG_SHA_256):PSA_KEY_TYPE_HMAC:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa":PSA_ALG_HMAC(PSA_ALG_SHA_224)
+mac_key_policy:PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_VERIFY_HASH:PSA_ALG_HMAC(PSA_ALG_SHA_256):PSA_KEY_TYPE_HMAC:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa":PSA_ALG_HMAC(PSA_ALG_SHA_224):PSA_ERROR_NOT_PERMITTED
 
 PSA key policy: MAC, alg=0 in policy
 depends_on:MBEDTLS_SHA256_C
-mac_key_policy:PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_VERIFY_HASH:0:PSA_KEY_TYPE_HMAC:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa":PSA_ALG_HMAC(PSA_ALG_SHA_256)
+mac_key_policy:PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_VERIFY_HASH:0:PSA_KEY_TYPE_HMAC:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa":PSA_ALG_HMAC(PSA_ALG_SHA_256):PSA_ERROR_NOT_PERMITTED
 
 PSA key policy: MAC, ANY_HASH in policy is not meaningful
 depends_on:MBEDTLS_SHA256_C
-mac_key_policy:PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_VERIFY_HASH:PSA_ALG_HMAC(PSA_ALG_ANY_HASH):PSA_KEY_TYPE_HMAC:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa":PSA_ALG_HMAC(PSA_ALG_SHA_256)
+mac_key_policy:PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_VERIFY_HASH:PSA_ALG_HMAC(PSA_ALG_ANY_HASH):PSA_KEY_TYPE_HMAC:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa":PSA_ALG_HMAC(PSA_ALG_SHA_256):PSA_ERROR_NOT_PERMITTED
 
 PSA key policy: MAC, sign but not verify
 depends_on:MBEDTLS_SHA256_C
-mac_key_policy:PSA_KEY_USAGE_SIGN_HASH:PSA_ALG_HMAC(PSA_ALG_SHA_256):PSA_KEY_TYPE_HMAC:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa":PSA_ALG_HMAC(PSA_ALG_SHA_256)
+mac_key_policy:PSA_KEY_USAGE_SIGN_HASH:PSA_ALG_HMAC(PSA_ALG_SHA_256):PSA_KEY_TYPE_HMAC:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa":PSA_ALG_HMAC(PSA_ALG_SHA_256):PSA_SUCCESS
 
 PSA key policy: MAC, verify but not sign
 depends_on:MBEDTLS_SHA256_C
-mac_key_policy:PSA_KEY_USAGE_VERIFY_HASH:PSA_ALG_HMAC(PSA_ALG_SHA_256):PSA_KEY_TYPE_HMAC:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa":PSA_ALG_HMAC(PSA_ALG_SHA_256)
+mac_key_policy:PSA_KEY_USAGE_VERIFY_HASH:PSA_ALG_HMAC(PSA_ALG_SHA_256):PSA_KEY_TYPE_HMAC:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa":PSA_ALG_HMAC(PSA_ALG_SHA_256):PSA_SUCCESS
 
 PSA key policy: MAC, neither sign nor verify
 depends_on:MBEDTLS_SHA256_C
-mac_key_policy:0:PSA_ALG_HMAC(PSA_ALG_SHA_256):PSA_KEY_TYPE_HMAC:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa":PSA_ALG_HMAC(PSA_ALG_SHA_256)
+mac_key_policy:0:PSA_ALG_HMAC(PSA_ALG_SHA_256):PSA_KEY_TYPE_HMAC:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa":PSA_ALG_HMAC(PSA_ALG_SHA_256):PSA_ERROR_NOT_PERMITTED
+
+PSA key policy: MAC, sign-verify, policy smaller than alg
+depends_on:MBEDTLS_SHA256_C
+mac_key_policy:PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_VERIFY_HASH:PSA_ALG_MAC_POLICY_WITH_MINIMUM_TAG_LENGTH(PSA_ALG_HMAC(PSA_ALG_SHA_256), 20):PSA_KEY_TYPE_HMAC:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa":PSA_ALG_TRUNCATED_MAC(PSA_ALG_HMAC(PSA_ALG_SHA_256), 30):PSA_SUCCESS
+
+PSA key policy: MAC, sign-verify, policy same-length as alg
+depends_on:MBEDTLS_SHA256_C
+mac_key_policy:PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_VERIFY_HASH:PSA_ALG_MAC_POLICY_WITH_MINIMUM_TAG_LENGTH(PSA_ALG_HMAC(PSA_ALG_SHA_256), 20):PSA_KEY_TYPE_HMAC:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa":PSA_ALG_TRUNCATED_MAC(PSA_ALG_HMAC(PSA_ALG_SHA_256), 20):PSA_SUCCESS
+
+PSA key policy: MAC, sign-verify, policy larger than alg
+depends_on:MBEDTLS_SHA256_C
+mac_key_policy:PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_VERIFY_HASH:PSA_ALG_MAC_POLICY_WITH_MINIMUM_TAG_LENGTH(PSA_ALG_HMAC(PSA_ALG_SHA_256), 20):PSA_KEY_TYPE_HMAC:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa":PSA_ALG_TRUNCATED_MAC(PSA_ALG_HMAC(PSA_ALG_SHA_256), 10):PSA_ERROR_NOT_PERMITTED
+
+PSA key policy: MAC, sign-verify, policy alg does not match base alg
+depends_on:MBEDTLS_SHA256_C:MBEDTLS_CMAC_C
+mac_key_policy:PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_VERIFY_HASH:PSA_ALG_MAC_POLICY_WITH_MINIMUM_TAG_LENGTH(PSA_ALG_HMAC(PSA_ALG_SHA_256), 20):PSA_KEY_TYPE_HMAC:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa":PSA_ALG_TRUNCATED_MAC(PSA_ALG_CMAC, 20):PSA_ERROR_NOT_PERMITTED
+
+PSA key policy: MAC, sign-verify, exercise with policy
+depends_on:MBEDTLS_SHA256_C
+mac_key_policy:PSA_KEY_USAGE_SIGN_HASH | PSA_KEY_USAGE_VERIFY_HASH:PSA_ALG_MAC_POLICY_WITH_MINIMUM_TAG_LENGTH(PSA_ALG_HMAC(PSA_ALG_SHA_256), 20):PSA_KEY_TYPE_HMAC:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa":PSA_ALG_MAC_POLICY_WITH_MINIMUM_TAG_LENGTH(PSA_ALG_HMAC(PSA_ALG_SHA_256), 20):PSA_ERROR_NOT_PERMITTED
 
 PSA key policy: cipher, encrypt | decrypt
 depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CTR
@@ -445,27 +465,47 @@
 
 PSA key policy: AEAD, encrypt | decrypt
 depends_on:MBEDTLS_AES_C:MBEDTLS_CCM_C
-aead_key_policy:PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT:PSA_ALG_CCM:PSA_KEY_TYPE_AES:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa":13:16:PSA_ALG_CCM
+aead_key_policy:PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT:PSA_ALG_CCM:PSA_KEY_TYPE_AES:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa":13:16:PSA_ALG_CCM:PSA_SUCCESS
 
 PSA key policy: AEAD, wrong algorithm
 depends_on:MBEDTLS_AES_C:MBEDTLS_CCM_C:MBEDTLS_GCM_C
-aead_key_policy:PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT:PSA_ALG_CCM:PSA_KEY_TYPE_AES:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa":16:16:PSA_ALG_GCM
+aead_key_policy:PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT:PSA_ALG_CCM:PSA_KEY_TYPE_AES:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa":16:16:PSA_ALG_GCM:PSA_ERROR_NOT_PERMITTED
 
 PSA key policy: AEAD, alg=0 in policy
 depends_on:MBEDTLS_AES_C:MBEDTLS_CCM_C
-aead_key_policy:PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT:0:PSA_KEY_TYPE_AES:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa":16:16:PSA_ALG_CCM
+aead_key_policy:PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT:0:PSA_KEY_TYPE_AES:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa":16:16:PSA_ALG_CCM:PSA_ERROR_NOT_PERMITTED
 
 PSA key policy: AEAD, encrypt but not decrypt
 depends_on:MBEDTLS_AES_C:MBEDTLS_CCM_C
-aead_key_policy:PSA_KEY_USAGE_ENCRYPT:PSA_ALG_CCM:PSA_KEY_TYPE_AES:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa":13:16:PSA_ALG_CCM
+aead_key_policy:PSA_KEY_USAGE_ENCRYPT:PSA_ALG_CCM:PSA_KEY_TYPE_AES:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa":13:16:PSA_ALG_CCM:PSA_SUCCESS
 
 PSA key policy: AEAD, decrypt but not encrypt
 depends_on:MBEDTLS_AES_C:MBEDTLS_CCM_C
-aead_key_policy:PSA_KEY_USAGE_DECRYPT:PSA_ALG_CCM:PSA_KEY_TYPE_AES:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa":13:16:PSA_ALG_CCM
+aead_key_policy:PSA_KEY_USAGE_DECRYPT:PSA_ALG_CCM:PSA_KEY_TYPE_AES:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa":13:16:PSA_ALG_CCM:PSA_SUCCESS
 
 PSA key policy: AEAD, neither encrypt nor decrypt
 depends_on:MBEDTLS_AES_C:MBEDTLS_CCM_C
-aead_key_policy:0:PSA_ALG_CCM:PSA_KEY_TYPE_AES:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa":13:16:PSA_ALG_CCM
+aead_key_policy:0:PSA_ALG_CCM:PSA_KEY_TYPE_AES:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa":13:16:PSA_ALG_CCM:PSA_ERROR_NOT_PERMITTED
+
+PSA key policy: AEAD, exercise policy with larger tag length alg
+depends_on:MBEDTLS_AES_C:MBEDTLS_CCM_C
+aead_key_policy:PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT:PSA_ALG_AEAD_POLICY_WITH_MINIMUM_TAG_LENGTH(PSA_ALG_CCM, 4):PSA_KEY_TYPE_AES:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa":13:8:PSA_ALG_AEAD_WITH_TAG_LENGTH(PSA_ALG_CCM, 8):PSA_SUCCESS
+
+PSA key policy: AEAD, exercise policy with same-length alg
+depends_on:MBEDTLS_AES_C:MBEDTLS_CCM_C
+aead_key_policy:PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT:PSA_ALG_AEAD_POLICY_WITH_MINIMUM_TAG_LENGTH(PSA_ALG_CCM, 4):PSA_KEY_TYPE_AES:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa":13:4:PSA_ALG_AEAD_WITH_TAG_LENGTH(PSA_ALG_CCM, 4):PSA_SUCCESS
+
+PSA key policy: AEAD, exercise policy with lesser-length alg
+depends_on:MBEDTLS_AES_C:MBEDTLS_CCM_C
+aead_key_policy:PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT:PSA_ALG_AEAD_POLICY_WITH_MINIMUM_TAG_LENGTH(PSA_ALG_CCM, 8):PSA_KEY_TYPE_AES:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa":13:4:PSA_ALG_AEAD_WITH_TAG_LENGTH(PSA_ALG_CCM, 4):PSA_ERROR_NOT_PERMITTED
+
+PSA key policy: AEAD, exercise policy with different base alg
+depends_on:MBEDTLS_AES_C:MBEDTLS_CCM_C:MBEDTLS_GCM_C
+aead_key_policy:PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT:PSA_ALG_AEAD_POLICY_WITH_MINIMUM_TAG_LENGTH(PSA_ALG_CCM, 4):PSA_KEY_TYPE_AES:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa":13:4:PSA_ALG_AEAD_WITH_TAG_LENGTH(PSA_ALG_GCM, 4):PSA_ERROR_NOT_PERMITTED
+
+PSA key policy: AEAD, exercise algorithm with a policy
+depends_on:MBEDTLS_AES_C:MBEDTLS_CCM_C
+aead_key_policy:PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT:PSA_ALG_AEAD_POLICY_WITH_MINIMUM_TAG_LENGTH(PSA_ALG_CCM, 8):PSA_KEY_TYPE_AES:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa":13:8:PSA_ALG_AEAD_POLICY_WITH_MINIMUM_TAG_LENGTH(PSA_ALG_CCM, 8):PSA_ERROR_NOT_PERMITTED
 
 PSA key policy: asymmetric encryption, encrypt | decrypt
 depends_on:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V15
diff --git a/tests/suites/test_suite_psa_crypto.function b/tests/suites/test_suite_psa_crypto.function
index 8e71610..88d9d66 100644
--- a/tests/suites/test_suite_psa_crypto.function
+++ b/tests/suites/test_suite_psa_crypto.function
@@ -1956,12 +1956,14 @@
                      int policy_alg,
                      int key_type,
                      data_t *key_data,
-                     int exercise_alg )
+                     int exercise_alg,
+                     int expected_status_arg )
 {
     mbedtls_svc_key_id_t key = MBEDTLS_SVC_KEY_ID_INIT;
     psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
     psa_mac_operation_t operation = PSA_MAC_OPERATION_INIT;
     psa_status_t status;
+    psa_status_t expected_status = expected_status_arg;
     unsigned char mac[PSA_MAC_MAX_SIZE];
 
     PSA_ASSERT( psa_crypto_init( ) );
@@ -1974,20 +1976,19 @@
                                 &key ) );
 
     status = psa_mac_sign_setup( &operation, key, exercise_alg );
-    if( policy_alg == exercise_alg &&
-        ( policy_usage & PSA_KEY_USAGE_SIGN_HASH ) != 0 )
-        PSA_ASSERT( status );
-    else
+    if( ( policy_usage & PSA_KEY_USAGE_SIGN_HASH ) == 0 )
         TEST_EQUAL( status, PSA_ERROR_NOT_PERMITTED );
+    else
+        TEST_EQUAL( status, expected_status );
+
     psa_mac_abort( &operation );
 
     memset( mac, 0, sizeof( mac ) );
     status = psa_mac_verify_setup( &operation, key, exercise_alg );
-    if( policy_alg == exercise_alg &&
-        ( policy_usage & PSA_KEY_USAGE_VERIFY_HASH ) != 0 )
-        PSA_ASSERT( status );
-    else
+    if( ( policy_usage & PSA_KEY_USAGE_VERIFY_HASH ) == 0 )
         TEST_EQUAL( status, PSA_ERROR_NOT_PERMITTED );
+    else
+        TEST_EQUAL( status, expected_status );
 
 exit:
     psa_mac_abort( &operation );
@@ -2046,11 +2047,13 @@
                       data_t *key_data,
                       int nonce_length_arg,
                       int tag_length_arg,
-                      int exercise_alg )
+                      int exercise_alg,
+                      int expected_status_arg )
 {
     mbedtls_svc_key_id_t key = MBEDTLS_SVC_KEY_ID_INIT;
     psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
     psa_status_t status;
+    psa_status_t expected_status = expected_status_arg;
     unsigned char nonce[16] = {0};
     size_t nonce_length = nonce_length_arg;
     unsigned char tag[16];
@@ -2075,9 +2078,8 @@
                                NULL, 0,
                                tag, tag_length,
                                &output_length );
-    if( policy_alg == exercise_alg &&
-        ( policy_usage & PSA_KEY_USAGE_ENCRYPT ) != 0 )
-        PSA_ASSERT( status );
+    if( ( policy_usage & PSA_KEY_USAGE_ENCRYPT ) != 0 )
+        TEST_EQUAL( status, expected_status );
     else
         TEST_EQUAL( status, PSA_ERROR_NOT_PERMITTED );
 
@@ -2088,11 +2090,12 @@
                                tag, tag_length,
                                NULL, 0,
                                &output_length );
-    if( policy_alg == exercise_alg &&
-        ( policy_usage & PSA_KEY_USAGE_DECRYPT ) != 0 )
+    if( ( policy_usage & PSA_KEY_USAGE_DECRYPT ) == 0 )
+        TEST_EQUAL( status, PSA_ERROR_NOT_PERMITTED );
+    else if( expected_status == PSA_SUCCESS )
         TEST_EQUAL( status, PSA_ERROR_INVALID_SIGNATURE );
     else
-        TEST_EQUAL( status, PSA_ERROR_NOT_PERMITTED );
+        TEST_EQUAL( status, expected_status );
 
 exit:
     psa_destroy_key( key );