Reject invalid MAC and AEAD truncations

Reject algorithms of the form PSA_ALG_TRUNCATED_MAC(...) or
PSA_ALG_AEAD_WITH_SHORTENED_TAG(...) when the truncation length is invalid
or not accepted by policy in Mbed TLS.

This is done in KeyType.can_do, so in generate_psa_tests.py, keys will be
tested for operation failure with this algorithm if the algorithm is
rejected, and for storage if the algorithm is accepted.

Signed-off-by: Gilles Peskine <Gilles.Peskine@arm.com>
This commit is contained in:
Gilles Peskine 2022-03-19 10:37:33 +01:00
parent 2fa829c7dd
commit e3a0890e4f

View File

@ -20,7 +20,7 @@ This module is entirely based on the PSA API.
import enum
import re
from typing import Iterable, List, Optional, Tuple
from typing import FrozenSet, Iterable, List, Optional, Tuple
from mbedtls_dev.asymmetric_key_data import ASYMMETRIC_KEY_DATA
@ -216,6 +216,8 @@ class KeyType:
#pylint: disable=too-many-return-statements
if alg.is_wildcard:
return False
if alg.is_invalid_truncation():
return False
if self.head == 'HMAC' and alg.head == 'HMAC':
return True
if self.head == 'DES':
@ -420,8 +422,55 @@ class Algorithm:
"""
return short_expression(self.expression, level=level)
PERMITTED_TAG_LENGTHS = {
'PSA_ALG_CCM': frozenset([4, 6, 8, 10, 12, 14, 16]),
'PSA_ALG_CHACHA20_POLY1305': frozenset([16]),
'PSA_ALG_GCM': frozenset([4, 8, 12, 13, 14, 15, 16]),
}
MAC_LENGTH = {
'PSA_ALG_CBC_MAC': 16,
'PSA_ALG_CMAC': 16,
'PSA_ALG_HMAC(PSA_ALG_MD5)': 16,
'PSA_ALG_HMAC(PSA_ALG_SHA_1)': 20,
}
HMAC_WITH_NOMINAL_LENGTH_RE = re.compile(r'PSA_ALG_HMAC\(\w+([0-9])+\)\Z')
@classmethod
def mac_or_tag_length(cls, base: str) -> FrozenSet[int]:
"""Return the set of permitted lengths for the given MAC or AEAD tag."""
if base in cls.PERMITTED_TAG_LENGTHS:
return cls.PERMITTED_TAG_LENGTHS[base]
max_length = cls.MAC_LENGTH.get(base, None)
if max_length is None:
m = cls.HMAC_WITH_NOMINAL_LENGTH_RE.match(base)
if m:
max_length = int(m.group(1)) // 8
if max_length is None:
raise ValueError('Unknown permitted lengths for ' + base)
return frozenset(range(4, max_length + 1))
TRUNCATED_ALG_RE = re.compile(
r'(?P<face>PSA_ALG_(?:AEAD_WITH_SHORTENED_TAG|TRUNCATED_MAC))'
r'\((?P<base>.*),'
r'(?P<length>0[Xx][0-9A-Fa-f]+|[1-9][0-9]*|0[0-9]*)[LUlu]*\)\Z')
def is_invalid_truncation(self) -> bool:
"""False for a MAC or AEAD algorithm truncated to an invalid length.
True for a MAC or AEAD algorithm truncated to a valid length or to
a length that cannot be determined. True for anything other than
a truncated MAC or AEAD.
"""
m = self.TRUNCATED_ALG_RE.match(self.expression)
if m:
base = m.group('base')
to_length = int(m.group('length'), 0)
permitted_lengths = self.mac_or_tag_length(base)
if to_length not in permitted_lengths:
return True
return False
def can_do(self, category: AlgorithmCategory) -> bool:
"""Whether this algorithm fits the specified operation category."""
"""Whether this algorithm can perform operations in the given category.
"""
if category == self.category:
return True
if category == AlgorithmCategory.KEY_DERIVATION and \