Make psa_key_policy_algorithm_intersection MAC-length aware

This makes it more in-line with how psa_key_policy_permits works. It
also adds consistency: the intersection of MAC with default length and
MAC with exact-length is now computed correctly in case the exact length
equals the default length of the algorithm when used with the given
key type.

Signed-off-by: Steven Cooreman <steven.cooreman@silabs.com>
diff --git a/library/psa_crypto.c b/library/psa_crypto.c
index fbde52b..5cbf99d 100644
--- a/library/psa_crypto.c
+++ b/library/psa_crypto.c
@@ -719,6 +719,7 @@
  * Return 0 (which allows no operation) on incompatibility.
  */
 static psa_algorithm_t psa_key_policy_algorithm_intersection(
+    psa_key_type_t key_type,
     psa_algorithm_t alg1,
     psa_algorithm_t alg2 )
 {
@@ -772,8 +773,28 @@
         ( PSA_ALG_FULL_LENGTH_MAC( alg1 ) ==
           PSA_ALG_FULL_LENGTH_MAC( alg2 ) ) )
     {
-        size_t alg1_len = PSA_MAC_TRUNCATED_LENGTH( alg1 );
-        size_t alg2_len = PSA_MAC_TRUNCATED_LENGTH( alg2 );
+        /* Calculate the actual requested output length for both sides. In case
+         * of at-least-this-length wildcard algorithms, the requested output
+         * length is the shortest allowed length. */
+        size_t alg1_len = 0;
+        size_t alg2_len = 0;
+        if( PSA_SUCCESS != psa_get_mac_output_length(
+                                PSA_ALG_TRUNCATED_MAC( alg1,
+                                    PSA_MAC_TRUNCATED_LENGTH( alg1 ) ),
+                                key_type,
+                                &alg1_len ) )
+        {
+            return( 0 );
+        }
+        if( PSA_SUCCESS != psa_get_mac_output_length(
+                                PSA_ALG_TRUNCATED_MAC( alg2,
+                                    PSA_MAC_TRUNCATED_LENGTH( alg2 ) ),
+                                key_type,
+                                &alg2_len ) )
+        {
+            return( 0 );
+        }
+
         size_t max_len = alg1_len > alg2_len ? alg1_len : alg2_len;
 
         /* If both are wildcards, return most restrictive wildcard */
@@ -782,22 +803,26 @@
         {
             return( PSA_ALG_AT_LEAST_THIS_LENGTH_MAC( alg1, max_len ) );
         }
-        /* If only one is a wildcard, return specific algorithm if compatible.
-         * Special case: specific MAC algorithm with '0' as length means full-
-         * length MAC, which is always allowed by a wildcard with the same
-         * base algorithm. */
-        if( ( ( alg1 & PSA_ALG_MAC_AT_LEAST_THIS_LENGTH_FLAG ) != 0 ) &&
-            ( ( alg1_len <= alg2_len ) ||
-              ( alg2 == PSA_ALG_FULL_LENGTH_MAC( alg1 ) ) ) )
+        /* If only one is a wildcard, return specific algorithm if compatible. */
+        if( ( alg1 & PSA_ALG_MAC_AT_LEAST_THIS_LENGTH_FLAG ) != 0 )
         {
-            return( alg2 );
+            if( alg1_len <= alg2_len )
+                return( alg2 );
+            else
+                return( 0 );
         }
-        if( ( ( alg2 & PSA_ALG_MAC_AT_LEAST_THIS_LENGTH_FLAG ) != 0 ) &&
-            ( ( alg2_len <= alg1_len ) ||
-              ( alg1 == PSA_ALG_FULL_LENGTH_MAC( alg2 ) ) ) )
+        if( ( alg2 & PSA_ALG_MAC_AT_LEAST_THIS_LENGTH_FLAG ) != 0 )
         {
-            return( alg1 );
+            if( alg2_len <= alg1_len )
+                return( alg1 );
+            else
+                return( 0 );
         }
+        /* If none of them are wildcards, check whether we can match
+         * default-length with exact-length, and return exact-length in that
+         * case. */
+        if( alg1_len == alg2_len )
+            return( PSA_ALG_TRUNCATED_MAC( alg1, alg1_len ) );
     }
     /* If the policies are incompatible, allow nothing. */
     return( 0 );
@@ -919,6 +944,7 @@
 
 /** Restrict a key policy based on a constraint.
  *
+ * \param[in] key_type      The key type for which to restrict the policy
  * \param[in,out] policy    The policy to restrict.
  * \param[in] constraint    The policy constraint to apply.
  *
@@ -926,17 +952,20 @@
  *         \c *policy contains the intersection of the original value of
  *         \c *policy and \c *constraint.
  * \retval #PSA_ERROR_INVALID_ARGUMENT
- *         \c *policy and \c *constraint are incompatible.
+ *         \c key_type, \c *policy and \c *constraint are incompatible.
  *         \c *policy is unchanged.
  */
 static psa_status_t psa_restrict_key_policy(
+    psa_key_type_t key_type,
     psa_key_policy_t *policy,
     const psa_key_policy_t *constraint )
 {
     psa_algorithm_t intersection_alg =
-        psa_key_policy_algorithm_intersection( policy->alg, constraint->alg );
+        psa_key_policy_algorithm_intersection( key_type, policy->alg,
+                                               constraint->alg );
     psa_algorithm_t intersection_alg2 =
-        psa_key_policy_algorithm_intersection( policy->alg2, constraint->alg2 );
+        psa_key_policy_algorithm_intersection( key_type, policy->alg2,
+                                               constraint->alg2 );
     if( intersection_alg == 0 && policy->alg != 0 && constraint->alg != 0 )
         return( PSA_ERROR_INVALID_ARGUMENT );
     if( intersection_alg2 == 0 && policy->alg2 != 0 && constraint->alg2 != 0 )
@@ -2089,7 +2118,8 @@
     if( status != PSA_SUCCESS )
         goto exit;
 
-    status = psa_restrict_key_policy( &actual_attributes.core.policy,
+    status = psa_restrict_key_policy( source_slot->attr.type,
+                                      &actual_attributes.core.policy,
                                       &source_slot->attr.policy );
     if( status != PSA_SUCCESS )
         goto exit;