Add support for truncated MAC algorithms
diff --git a/include/psa/crypto.h b/include/psa/crypto.h
index 62d3920..0269be9 100644
--- a/include/psa/crypto.h
+++ b/include/psa/crypto.h
@@ -756,6 +756,56 @@
(((alg) & (PSA_ALG_CATEGORY_MASK | PSA_ALG_MAC_SUBCATEGORY_MASK)) == \
PSA_ALG_HMAC_BASE)
+#define PSA_ALG_MAC_TRUNCATION_MASK ((psa_algorithm_t)0x00003f00)
+#define PSA_MAC_TRUNCATION_OFFSET 8
+
+/** Macro to build a truncated MAC algorithm.
+ *
+ * A truncated MAC algorithm is identical to the corresponding MAC
+ * algorithm except that the MAC value for the truncated algorithm
+ * consists of only the first \p mac_length bytes of the MAC value
+ * for the untruncated algorithm.
+ *
+ * \note This macro may allow constructing algorithm identifiers that
+ * are not valid, either because the specified length is larger
+ * than the untruncated MAC or because the specified length is
+ * smaller than permitted by the implementation.
+ *
+ * \note It is implementation-defined whether a truncated MAC that
+ * is truncated to the same length as the MAC of the untruncated
+ * algorithm is considered identical to the untruncated algorithm
+ * for policy comparison purposes.
+ *
+ * \param alg A MAC algorithm identifier (value of type
+ * #psa_algorithm_t such that #PSA_ALG_IS_MAC(\p alg)
+ * is true). This may be a truncated or untruncated
+ * MAC algorithm.
+ * \param mac_length Desired length of the truncated MAC in bytes.
+ *
+ * \return The corresponding MAC algorithm with the specified
+ * length.
+ * \return Unspecified if \p alg is not a supported
+ * MAC algorithm or if \p mac_length is too small or
+ * too large for the specified MAC algorithm.
+ */
+#define PSA_ALG_TRUNCATED_MAC(alg, mac_length) \
+ (((alg) & ~PSA_ALG_MAC_TRUNCATION_MASK) | \
+ ((mac_length) << PSA_MAC_TRUNCATION_OFFSET & PSA_ALG_MAC_TRUNCATION_MASK))
+
+/** Length to which a MAC algorithm is truncated.
+ *
+ * \param alg A MAC algorithm identifier (value of type
+ * #psa_algorithm_t such that #PSA_ALG_IS_MAC(\p alg)
+ * is true).
+ *
+ * \return Length of the truncated MAC in bytes.
+ * \return 0 if \p alg is a non-truncated MAC algorithm.
+ * \return Unspecified if \p alg is not a supported
+ * MAC algorithm.
+ */
+#define PSA_MAC_TRUNCATED_LENGTH(alg) \
+ (((alg) & PSA_ALG_MAC_TRUNCATION_MASK) >> PSA_MAC_TRUNCATION_OFFSET)
+
#define PSA_ALG_CIPHER_MAC_BASE ((psa_algorithm_t)0x02c00000)
#define PSA_ALG_CBC_MAC ((psa_algorithm_t)0x02c00001)
#define PSA_ALG_CMAC ((psa_algorithm_t)0x02c00002)
diff --git a/include/psa/crypto_sizes.h b/include/psa/crypto_sizes.h
index edb240b..c058afc 100644
--- a/include/psa/crypto_sizes.h
+++ b/include/psa/crypto_sizes.h
@@ -143,7 +143,8 @@
PSA_VENDOR_ECC_MAX_CURVE_BITS \
)
-
+/** The maximum size of a block cipher supported by the implementation. */
+#define PSA_MAX_BLOCK_CIPHER_BLOCK_SIZE 16
/** The size of the output of psa_mac_sign_finish(), in bytes.
*
@@ -163,7 +164,8 @@
* with the algorithm.
*/
#define PSA_MAC_FINAL_SIZE(key_type, key_bits, alg) \
- (PSA_ALG_IS_HMAC(alg) ? PSA_HASH_SIZE(PSA_ALG_HMAC_GET_HASH(alg)) : \
+ ((alg) & PSA_ALG_MAC_TRUNCATION_MASK ? PSA_MAC_TRUNCATED_LENGTH(alg) : \
+ PSA_ALG_IS_HMAC(alg) ? PSA_HASH_SIZE(PSA_ALG_HMAC_GET_HASH(alg)) : \
PSA_ALG_IS_BLOCK_CIPHER_MAC(alg) ? PSA_BLOCK_CIPHER_BLOCK_SIZE(key_type) : \
((void)(key_type), (void)(key_bits), 0))
diff --git a/library/psa_crypto.c b/library/psa_crypto.c
index 6fd905c..3411cc8 100644
--- a/library/psa_crypto.c
+++ b/library/psa_crypto.c
@@ -1523,8 +1523,10 @@
size_t key_bits;
psa_key_usage_t usage =
is_sign ? PSA_KEY_USAGE_SIGN : PSA_KEY_USAGE_VERIFY;
+ unsigned char truncated = PSA_MAC_TRUNCATED_LENGTH( alg );
+ psa_algorithm_t full_length_alg = alg & ~PSA_ALG_MAC_TRUNCATION_MASK;
- status = psa_mac_init( operation, alg );
+ status = psa_mac_init( operation, full_length_alg );
if( status != PSA_SUCCESS )
return( status );
if( is_sign )
@@ -1536,10 +1538,11 @@
key_bits = psa_get_key_bits( slot );
#if defined(MBEDTLS_CMAC_C)
- if( alg == PSA_ALG_CMAC )
+ if( full_length_alg == PSA_ALG_CMAC )
{
const mbedtls_cipher_info_t *cipher_info =
- mbedtls_cipher_info_from_psa( alg, slot->type, key_bits, NULL );
+ mbedtls_cipher_info_from_psa( full_length_alg,
+ slot->type, key_bits, NULL );
int ret;
if( cipher_info == NULL )
{
@@ -1553,7 +1556,7 @@
else
#endif /* MBEDTLS_CMAC_C */
#if defined(MBEDTLS_MD_C)
- if( PSA_ALG_IS_HMAC( alg ) )
+ if( PSA_ALG_IS_HMAC( full_length_alg ) )
{
psa_algorithm_t hash_alg = PSA_ALG_HMAC_GET_HASH( alg );
if( hash_alg == 0 )
@@ -1588,6 +1591,24 @@
status = PSA_ERROR_NOT_SUPPORTED;
}
+ if( truncated == 0 )
+ {
+ /* The "normal" case: untruncated algorithm. Nothing to do. */
+ }
+ else if( truncated < 4 )
+ {
+ /* Too small to make any sense. Reject. 4 bytes is too small for
+ * security but ancient protocols with 32-bit MACs do exist. */
+ status = PSA_ERROR_NOT_SUPPORTED;
+ }
+ else if( truncated > operation->mac_size )
+ {
+ /* It's impossible to "truncate" to a larger length. */
+ status = PSA_ERROR_INVALID_ARGUMENT;
+ }
+ else
+ operation->mac_size = truncated;
+
exit:
if( status != PSA_SUCCESS )
{
@@ -1682,7 +1703,11 @@
if( status != PSA_SUCCESS )
goto exit;
- status = psa_hash_finish( &hmac->hash_ctx, mac, mac_size, &hash_size );
+ status = psa_hash_finish( &hmac->hash_ctx, tmp, sizeof( tmp ), &hash_size );
+ if( status != PSA_SUCCESS )
+ goto exit;
+
+ memcpy( mac, tmp, mac_size );
exit:
mbedtls_zeroize( tmp, hash_size );
@@ -1705,7 +1730,11 @@
#if defined(MBEDTLS_CMAC_C)
if( operation->alg == PSA_ALG_CMAC )
{
- int ret = mbedtls_cipher_cmac_finish( &operation->ctx.cmac, mac );
+ uint8_t tmp[PSA_MAX_BLOCK_CIPHER_BLOCK_SIZE];
+ int ret = mbedtls_cipher_cmac_finish( &operation->ctx.cmac, tmp );
+ if( ret == 0 )
+ memcpy( mac, tmp, mac_size );
+ mbedtls_zeroize( tmp, sizeof( tmp ) );
return( mbedtls_to_psa_error( ret ) );
}
else
@@ -1714,7 +1743,7 @@
if( PSA_ALG_IS_HMAC( operation->alg ) )
{
return( psa_hmac_finish_internal( &operation->ctx.hmac,
- mac, mac_size ) );
+ mac, operation->mac_size ) );
}
else
#endif /* MBEDTLS_MD_C */
@@ -1793,6 +1822,8 @@
else
psa_mac_abort( operation );
+ mbedtls_zeroize( actual_mac, mac_length );
+
return( status );
}
diff --git a/tests/suites/test_suite_psa_crypto.data b/tests/suites/test_suite_psa_crypto.data
index 913c694..b76f307 100644
--- a/tests/suites/test_suite_psa_crypto.data
+++ b/tests/suites/test_suite_psa_crypto.data
@@ -466,10 +466,86 @@
depends_on:MBEDTLS_MD_C:MBEDTLS_SHA512_C
mac_verify:PSA_KEY_TYPE_HMAC:"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa":PSA_ALG_HMAC(PSA_ALG_SHA_512):"5468697320697320612074657374207573696e672061206c6172676572207468616e20626c6f636b2d73697a65206b657920616e642061206c6172676572207468616e20626c6f636b2d73697a6520646174612e20546865206b6579206e6565647320746f20626520686173686564206265666f7265206265696e6720757365642062792074686520484d414320616c676f726974686d2e":"e37b6a775dc87dbaa4dfa9f96e5e3ffddebd71f8867289865df5a32d20cdc944b6022cac3c4982b10d5eeb55c3e4de15134676fb6de0446065c97440fa8c6a58"
+PSA MAC sign: HMAC-SHA-224, truncated to 28 bytes (actual size)
+depends_on:MBEDTLS_MD_C:MBEDTLS_SHA256_C
+mac_sign:PSA_KEY_TYPE_HMAC:"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b":PSA_ALG_TRUNCATED_MAC(PSA_ALG_HMAC(PSA_ALG_SHA_224), 28):"4869205468657265":"896fb1128abbdf196832107cd49df33f47b4b1169912ba4f53684b22"
+
+PSA MAC verify: HMAC-SHA-224, truncated to 28 bytes (actual size)
+depends_on:MBEDTLS_MD_C:MBEDTLS_SHA256_C
+mac_verify:PSA_KEY_TYPE_HMAC:"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b":PSA_ALG_TRUNCATED_MAC(PSA_ALG_HMAC(PSA_ALG_SHA_224), 28):"4869205468657265":"896fb1128abbdf196832107cd49df33f47b4b1169912ba4f53684b22"
+
+PSA MAC sign: HMAC-SHA-512, truncated to 64 bytes (actual size)
+depends_on:MBEDTLS_MD_C:MBEDTLS_SHA512_C
+mac_sign:PSA_KEY_TYPE_HMAC:"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b":PSA_ALG_TRUNCATED_MAC(PSA_ALG_HMAC(PSA_ALG_SHA_512), 64):"4869205468657265":"87aa7cdea5ef619d4ff0b4241a1d6cb02379f4e2ce4ec2787ad0b30545e17cdedaa833b7d6b8a702038b274eaea3f4e4be9d914eeb61f1702e696c203a126854"
+
+PSA MAC verify: HMAC-SHA-512, truncated to 64 bytes (actual size)
+depends_on:MBEDTLS_MD_C:MBEDTLS_SHA512_C
+mac_verify:PSA_KEY_TYPE_HMAC:"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b":PSA_ALG_TRUNCATED_MAC(PSA_ALG_HMAC(PSA_ALG_SHA_512), 64):"4869205468657265":"87aa7cdea5ef619d4ff0b4241a1d6cb02379f4e2ce4ec2787ad0b30545e17cdedaa833b7d6b8a702038b274eaea3f4e4be9d914eeb61f1702e696c203a126854"
+
+PSA MAC sign: HMAC-SHA-224, truncated to 27 bytes
+depends_on:MBEDTLS_MD_C:MBEDTLS_SHA256_C
+mac_sign:PSA_KEY_TYPE_HMAC:"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b":PSA_ALG_TRUNCATED_MAC(PSA_ALG_HMAC(PSA_ALG_SHA_224), 27):"4869205468657265":"896fb1128abbdf196832107cd49df33f47b4b1169912ba4f53684b"
+
+PSA MAC verify: HMAC-SHA-224, truncated to 27 bytes
+depends_on:MBEDTLS_MD_C:MBEDTLS_SHA256_C
+mac_verify:PSA_KEY_TYPE_HMAC:"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b":PSA_ALG_TRUNCATED_MAC(PSA_ALG_HMAC(PSA_ALG_SHA_224), 27):"4869205468657265":"896fb1128abbdf196832107cd49df33f47b4b1169912ba4f53684b"
+
+PSA MAC sign: HMAC-SHA-512, truncated to 63 bytes
+depends_on:MBEDTLS_MD_C:MBEDTLS_SHA512_C
+mac_sign:PSA_KEY_TYPE_HMAC:"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b":PSA_ALG_TRUNCATED_MAC(PSA_ALG_HMAC(PSA_ALG_SHA_512), 63):"4869205468657265":"87aa7cdea5ef619d4ff0b4241a1d6cb02379f4e2ce4ec2787ad0b30545e17cdedaa833b7d6b8a702038b274eaea3f4e4be9d914eeb61f1702e696c203a1268"
+
+PSA MAC verify: HMAC-SHA-512, truncated to 63 bytes
+depends_on:MBEDTLS_MD_C:MBEDTLS_SHA512_C
+mac_verify:PSA_KEY_TYPE_HMAC:"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b":PSA_ALG_TRUNCATED_MAC(PSA_ALG_HMAC(PSA_ALG_SHA_512), 63):"4869205468657265":"87aa7cdea5ef619d4ff0b4241a1d6cb02379f4e2ce4ec2787ad0b30545e17cdedaa833b7d6b8a702038b274eaea3f4e4be9d914eeb61f1702e696c203a1268"
+
+PSA MAC sign: HMAC-SHA-224, truncated to 4 bytes
+depends_on:MBEDTLS_MD_C:MBEDTLS_SHA256_C
+mac_sign:PSA_KEY_TYPE_HMAC:"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b":PSA_ALG_TRUNCATED_MAC(PSA_ALG_HMAC(PSA_ALG_SHA_224), 4):"4869205468657265":"896fb112"
+
+PSA MAC verify: HMAC-SHA-224, truncated to 4 bytes
+depends_on:MBEDTLS_MD_C:MBEDTLS_SHA256_C
+mac_verify:PSA_KEY_TYPE_HMAC:"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b":PSA_ALG_TRUNCATED_MAC(PSA_ALG_HMAC(PSA_ALG_SHA_224), 4):"4869205468657265":"896fb112"
+
+PSA MAC sign: HMAC-SHA-512, truncated to 4 bytes
+depends_on:MBEDTLS_MD_C:MBEDTLS_SHA512_C
+mac_sign:PSA_KEY_TYPE_HMAC:"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b":PSA_ALG_TRUNCATED_MAC(PSA_ALG_HMAC(PSA_ALG_SHA_512), 4):"4869205468657265":"87aa7cde"
+
+PSA MAC verify: HMAC-SHA-512, truncated to 4 bytes
+depends_on:MBEDTLS_MD_C:MBEDTLS_SHA512_C
+mac_verify:PSA_KEY_TYPE_HMAC:"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b":PSA_ALG_TRUNCATED_MAC(PSA_ALG_HMAC(PSA_ALG_SHA_512), 4):"4869205468657265":"87aa7cde"
+
+PSA MAC sign: CMAC-AES-128
+depends_on:MBEDTLS_CMAC_C:MBEDTLS_AES_C
+mac_sign:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":PSA_ALG_CMAC:"6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411":"dfa66747de9ae63030ca32611497c827"
+
PSA MAC verify: CMAC-AES-128
depends_on:MBEDTLS_CMAC_C:MBEDTLS_AES_C
mac_verify:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":PSA_ALG_CMAC:"6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411":"dfa66747de9ae63030ca32611497c827"
+PSA MAC sign: CMAC-AES-128, truncated to 16 bytes (actual size)
+depends_on:MBEDTLS_CMAC_C:MBEDTLS_AES_C
+mac_sign:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":PSA_ALG_TRUNCATED_MAC(PSA_ALG_CMAC, 16):"6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411":"dfa66747de9ae63030ca32611497c827"
+
+PSA MAC verify: CMAC-AES-128, truncated to 16 bytes (actual size)
+depends_on:MBEDTLS_CMAC_C:MBEDTLS_AES_C
+mac_verify:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":PSA_ALG_TRUNCATED_MAC(PSA_ALG_CMAC, 16):"6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411":"dfa66747de9ae63030ca32611497c827"
+
+PSA MAC sign: CMAC-AES-128, truncated to 15 bytes
+depends_on:MBEDTLS_CMAC_C:MBEDTLS_AES_C
+mac_sign:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":PSA_ALG_TRUNCATED_MAC(PSA_ALG_CMAC, 15):"6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411":"dfa66747de9ae63030ca32611497c8"
+
+PSA MAC verify: CMAC-AES-128, truncated to 15 bytes
+depends_on:MBEDTLS_CMAC_C:MBEDTLS_AES_C
+mac_verify:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":PSA_ALG_TRUNCATED_MAC(PSA_ALG_CMAC, 15):"6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411":"dfa66747de9ae63030ca32611497c8"
+
+PSA MAC sign: CMAC-AES-128, truncated to 4 bytes
+depends_on:MBEDTLS_CMAC_C:MBEDTLS_AES_C
+mac_sign:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":PSA_ALG_TRUNCATED_MAC(PSA_ALG_CMAC, 4):"6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411":"dfa66747"
+
+PSA MAC verify: CMAC-AES-128, truncated to 4 bytes
+depends_on:MBEDTLS_CMAC_C:MBEDTLS_AES_C
+mac_verify:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":PSA_ALG_TRUNCATED_MAC(PSA_ALG_CMAC, 4):"6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411":"dfa66747"
+
PSA cipher setup: good, AES-CTR
depends_on:MBEDTLS_AES_C:MBEDTLS_CIPHER_MODE_CTR
cipher_setup:PSA_KEY_TYPE_AES:"000102030405060708090a0b0c0d0e0f":PSA_ALG_CTR:PSA_SUCCESS