Merge pull request #5635 from gilles-peskine-arm/psa-test-op-fail

PSA: systematically test operation failure
This commit is contained in:
Gilles Peskine 2022-04-15 10:52:47 +02:00 committed by GitHub
commit 09dc05b880
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 956 additions and 71 deletions

View file

@ -0,0 +1,4 @@
Bugfix
* Declare or use PSA_WANT_ALG_CCM_STAR_NO_TAG following the general
pattern for PSA_WANT_xxx symbols. Previously you had to specify
PSA_WANT_ALG_CCM for PSA_ALG_CCM_STAR_NO_TAG.

View file

@ -50,6 +50,12 @@ extern "C" {
#define PSA_WANT_ALG_ECDSA_ANY PSA_WANT_ALG_ECDSA
#endif
#if defined(PSA_WANT_ALG_CCM_STAR_NO_TAG) && !defined(PSA_WANT_ALG_CCM)
#define PSA_WANT_ALG_CCM PSA_WANT_ALG_CCM_STAR_NO_TAG
#elif !defined(PSA_WANT_ALG_CCM_STAR_NO_TAG) && defined(PSA_WANT_ALG_CCM)
#define PSA_WANT_ALG_CCM_STAR_NO_TAG PSA_WANT_ALG_CCM
#endif
#if defined(PSA_WANT_ALG_RSA_PKCS1V15_SIGN_RAW) && !defined(PSA_WANT_ALG_RSA_PKCS1V15_SIGN)
#define PSA_WANT_ALG_RSA_PKCS1V15_SIGN PSA_WANT_ALG_RSA_PKCS1V15_SIGN_RAW
#elif !defined(PSA_WANT_ALG_RSA_PKCS1V15_SIGN_RAW) && defined(PSA_WANT_ALG_RSA_PKCS1V15_SIGN)
@ -384,7 +390,8 @@ extern "C" {
#endif
#endif /* PSA_WANT_ALG_XTS */
#if defined(PSA_WANT_ALG_ECB_NO_PADDING)
#if defined(PSA_WANT_ALG_ECB_NO_PADDING) && \
!defined(MBEDTLS_PSA_ACCEL_ALG_ECB_NO_PADDING)
#define MBEDTLS_PSA_BUILTIN_ALG_ECB_NO_PADDING 1
#endif
@ -411,6 +418,7 @@ extern "C" {
defined(PSA_HAVE_SOFT_KEY_TYPE_ARIA) || \
defined(PSA_HAVE_SOFT_KEY_TYPE_CAMELLIA)
#define MBEDTLS_PSA_BUILTIN_ALG_CCM 1
#define MBEDTLS_PSA_BUILTIN_ALG_CCM_STAR_NO_TAG 1
#define MBEDTLS_CCM_C
#endif
#endif /* PSA_WANT_ALG_CCM */
@ -545,7 +553,9 @@ extern "C" {
#if defined(MBEDTLS_CCM_C)
#define MBEDTLS_PSA_BUILTIN_ALG_CCM 1
#define MBEDTLS_PSA_BUILTIN_ALG_CCM_STAR_NO_TAG 1
#define PSA_WANT_ALG_CCM 1
#define PSA_WANT_ALG_CCM_STAR_NO_TAG 1
#endif /* MBEDTLS_CCM_C */
#if defined(MBEDTLS_CMAC_C)

View file

@ -2333,6 +2333,20 @@ static psa_status_t psa_mac_finalize_alg_and_key_validation(
return( PSA_ERROR_INVALID_ARGUMENT );
}
if( *mac_size > PSA_MAC_MAX_SIZE )
{
/* PSA_MAC_LENGTH returns the correct length even for a MAC algorithm
* that is disabled in the compile-time configuration. The result can
* therefore be larger than PSA_MAC_MAX_SIZE, which does take the
* configuration into account. In this case, force a return of
* PSA_ERROR_NOT_SUPPORTED here. Otherwise psa_mac_verify(), or
* psa_mac_compute(mac_size=PSA_MAC_MAX_SIZE), would return
* PSA_ERROR_BUFFER_TOO_SMALL for an unsupported algorithm whose MAC size
* is larger than PSA_MAC_MAX_SIZE, which is misleading and which breaks
* systematically generated tests. */
return( PSA_ERROR_NOT_SUPPORTED );
}
return( PSA_SUCCESS );
}
@ -5019,50 +5033,75 @@ psa_status_t psa_key_derivation_output_key( const psa_key_attributes_t *attribut
/****************************************************************/
#if defined(AT_LEAST_ONE_BUILTIN_KDF)
static int is_kdf_alg_supported( psa_algorithm_t kdf_alg )
{
#if defined(MBEDTLS_PSA_BUILTIN_ALG_HKDF)
if( PSA_ALG_IS_HKDF( kdf_alg ) )
return( 1 );
#endif
#if defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_PRF)
if( PSA_ALG_IS_TLS12_PRF( kdf_alg ) )
return( 1 );
#endif
#if defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_PSK_TO_MS)
if( PSA_ALG_IS_TLS12_PSK_TO_MS( kdf_alg ) )
return( 1 );
#endif
return( 0 );
}
static psa_status_t psa_hash_try_support( psa_algorithm_t alg )
{
psa_hash_operation_t operation = PSA_HASH_OPERATION_INIT;
psa_status_t status = psa_hash_setup( &operation, alg );
psa_hash_abort( &operation );
return( status );
}
static psa_status_t psa_key_derivation_setup_kdf(
psa_key_derivation_operation_t *operation,
psa_algorithm_t kdf_alg )
{
int is_kdf_alg_supported;
/* Make sure that operation->ctx is properly zero-initialised. (Macro
* initialisers for this union leave some bytes unspecified.) */
memset( &operation->ctx, 0, sizeof( operation->ctx ) );
/* Make sure that kdf_alg is a supported key derivation algorithm. */
#if defined(MBEDTLS_PSA_BUILTIN_ALG_HKDF)
if( PSA_ALG_IS_HKDF( kdf_alg ) )
is_kdf_alg_supported = 1;
else
#endif
#if defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_PRF)
if( PSA_ALG_IS_TLS12_PRF( kdf_alg ) )
is_kdf_alg_supported = 1;
else
#endif
#if defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_PSK_TO_MS)
if( PSA_ALG_IS_TLS12_PSK_TO_MS( kdf_alg ) )
is_kdf_alg_supported = 1;
else
#endif
is_kdf_alg_supported = 0;
if( ! is_kdf_alg_supported( kdf_alg ) )
return( PSA_ERROR_NOT_SUPPORTED );
if( is_kdf_alg_supported )
/* All currently supported key derivation algorithms are based on a
* hash algorithm. */
psa_algorithm_t hash_alg = PSA_ALG_HKDF_GET_HASH( kdf_alg );
size_t hash_size = PSA_HASH_LENGTH( hash_alg );
if( hash_size == 0 )
return( PSA_ERROR_NOT_SUPPORTED );
/* Make sure that hash_alg is a supported hash algorithm. Otherwise
* we might fail later, which is somewhat unfriendly and potentially
* risk-prone. */
psa_status_t status = psa_hash_try_support( hash_alg );
if( status != PSA_SUCCESS )
return( status );
if( ( PSA_ALG_IS_TLS12_PRF( kdf_alg ) ||
PSA_ALG_IS_TLS12_PSK_TO_MS( kdf_alg ) ) &&
! ( hash_alg == PSA_ALG_SHA_256 || hash_alg == PSA_ALG_SHA_384 ) )
{
psa_algorithm_t hash_alg = PSA_ALG_HKDF_GET_HASH( kdf_alg );
size_t hash_size = PSA_HASH_LENGTH( hash_alg );
if( hash_size == 0 )
return( PSA_ERROR_NOT_SUPPORTED );
if( ( PSA_ALG_IS_TLS12_PRF( kdf_alg ) ||
PSA_ALG_IS_TLS12_PSK_TO_MS( kdf_alg ) ) &&
! ( hash_alg == PSA_ALG_SHA_256 || hash_alg == PSA_ALG_SHA_384 ) )
{
return( PSA_ERROR_NOT_SUPPORTED );
}
operation->capacity = 255 * hash_size;
return( PSA_SUCCESS );
return( PSA_ERROR_NOT_SUPPORTED );
}
operation->capacity = 255 * hash_size;
return( PSA_SUCCESS );
}
static psa_status_t psa_key_agreement_try_support( psa_algorithm_t alg )
{
#if defined(PSA_WANT_ALG_ECDH)
if( alg == PSA_ALG_ECDH )
return( PSA_SUCCESS );
#endif
(void) alg;
return( PSA_ERROR_NOT_SUPPORTED );
}
#endif /* AT_LEAST_ONE_BUILTIN_KDF */
@ -5081,6 +5120,10 @@ psa_status_t psa_key_derivation_setup( psa_key_derivation_operation_t *operation
{
#if defined(AT_LEAST_ONE_BUILTIN_KDF)
psa_algorithm_t kdf_alg = PSA_ALG_KEY_AGREEMENT_GET_KDF( alg );
psa_algorithm_t ka_alg = PSA_ALG_KEY_AGREEMENT_GET_BASE( alg );
status = psa_key_agreement_try_support( ka_alg );
if( status != PSA_SUCCESS )
return( status );
status = psa_key_derivation_setup_kdf( operation, kdf_alg );
#else
return( PSA_ERROR_NOT_SUPPORTED );

View file

@ -47,39 +47,61 @@ const mbedtls_cipher_info_t *mbedtls_cipher_info_from_psa(
{
switch( alg )
{
#if defined(MBEDTLS_PSA_BUILTIN_ALG_STREAM_CIPHER)
case PSA_ALG_STREAM_CIPHER:
mode = MBEDTLS_MODE_STREAM;
break;
#endif
#if defined(MBEDTLS_PSA_BUILTIN_ALG_CTR)
case PSA_ALG_CTR:
mode = MBEDTLS_MODE_CTR;
break;
#endif
#if defined(MBEDTLS_PSA_BUILTIN_ALG_CFB)
case PSA_ALG_CFB:
mode = MBEDTLS_MODE_CFB;
break;
#endif
#if defined(MBEDTLS_PSA_BUILTIN_ALG_OFB)
case PSA_ALG_OFB:
mode = MBEDTLS_MODE_OFB;
break;
#endif
#if defined(MBEDTLS_PSA_BUILTIN_ALG_ECB_NO_PADDING)
case PSA_ALG_ECB_NO_PADDING:
mode = MBEDTLS_MODE_ECB;
break;
#endif
#if defined(MBEDTLS_PSA_BUILTIN_ALG_CBC_NO_PADDING)
case PSA_ALG_CBC_NO_PADDING:
mode = MBEDTLS_MODE_CBC;
break;
#endif
#if defined(MBEDTLS_PSA_BUILTIN_ALG_CBC_PKCS7)
case PSA_ALG_CBC_PKCS7:
mode = MBEDTLS_MODE_CBC;
break;
#endif
#if defined(MBEDTLS_PSA_BUILTIN_ALG_CCM_STAR_NO_TAG)
case PSA_ALG_CCM_STAR_NO_TAG:
mode = MBEDTLS_MODE_CCM_STAR_NO_TAG;
break;
#endif
#if defined(MBEDTLS_PSA_BUILTIN_ALG_CCM)
case PSA_ALG_AEAD_WITH_SHORTENED_TAG( PSA_ALG_CCM, 0 ):
mode = MBEDTLS_MODE_CCM;
break;
#endif
#if defined(MBEDTLS_PSA_BUILTIN_ALG_GCM)
case PSA_ALG_AEAD_WITH_SHORTENED_TAG( PSA_ALG_GCM, 0 ):
mode = MBEDTLS_MODE_GCM;
break;
#endif
#if defined(MBEDTLS_PSA_BUILTIN_ALG_CHACHA20_POLY1305)
case PSA_ALG_AEAD_WITH_SHORTENED_TAG( PSA_ALG_CHACHA20_POLY1305, 0 ):
mode = MBEDTLS_MODE_CHACHAPOLY;
break;
#endif
default:
return( NULL );
}
@ -91,12 +113,17 @@ const mbedtls_cipher_info_t *mbedtls_cipher_info_from_psa(
switch( key_type )
{
#if defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_AES)
case PSA_KEY_TYPE_AES:
cipher_id_tmp = MBEDTLS_CIPHER_ID_AES;
break;
#endif
#if defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_ARIA)
case PSA_KEY_TYPE_ARIA:
cipher_id_tmp = MBEDTLS_CIPHER_ID_ARIA;
break;
#endif
#if defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_DES)
case PSA_KEY_TYPE_DES:
/* key_bits is 64 for Single-DES, 128 for two-key Triple-DES,
* and 192 for three-key Triple-DES. */
@ -110,12 +137,17 @@ const mbedtls_cipher_info_t *mbedtls_cipher_info_from_psa(
if( key_bits == 128 )
key_bits = 192;
break;
#endif
#if defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_CAMELLIA)
case PSA_KEY_TYPE_CAMELLIA:
cipher_id_tmp = MBEDTLS_CIPHER_ID_CAMELLIA;
break;
#endif
#if defined(MBEDTLS_PSA_BUILTIN_KEY_TYPE_CHACHA20)
case PSA_KEY_TYPE_CHACHA20:
cipher_id_tmp = MBEDTLS_CIPHER_ID_CHACHA20;
break;
#endif
default:
return( NULL );
}
@ -239,6 +271,7 @@ psa_status_t mbedtls_psa_cipher_set_iv(
iv, iv_length ) ) );
}
#if defined(MBEDTLS_PSA_BUILTIN_ALG_ECB_NO_PADDING)
/** Process input for which the algorithm is set to ECB mode.
*
* This requires manual processing, since the PSA API is defined as being
@ -342,6 +375,7 @@ static psa_status_t psa_cipher_update_ecb(
exit:
return( status );
}
#endif /* MBEDTLS_PSA_BUILTIN_ALG_ECB_NO_PADDING */
psa_status_t mbedtls_psa_cipher_update(
mbedtls_psa_cipher_operation_t *operation,
@ -369,6 +403,7 @@ psa_status_t mbedtls_psa_cipher_update(
if( output_size < expected_output_size )
return( PSA_ERROR_BUFFER_TOO_SMALL );
#if defined(MBEDTLS_PSA_BUILTIN_ALG_ECB_NO_PADDING)
if( operation->alg == PSA_ALG_ECB_NO_PADDING )
{
/* mbedtls_cipher_update has an API inconsistency: it will only
@ -381,6 +416,7 @@ psa_status_t mbedtls_psa_cipher_update(
output_length );
}
else
#endif /* MBEDTLS_PSA_BUILTIN_ALG_ECB_NO_PADDING */
{
status = mbedtls_to_psa_error(
mbedtls_cipher_update( &operation->ctx.cipher, input,

View file

@ -18,15 +18,45 @@ This module is entirely based on the PSA API.
# See the License for the specific language governing permissions and
# limitations under the License.
import enum
import re
from typing import Dict, Iterable, Optional, Pattern, Tuple
from mbedtls_dev.asymmetric_key_data import ASYMMETRIC_KEY_DATA
BLOCK_CIPHERS = frozenset(['AES', 'ARIA', 'CAMELLIA', 'DES'])
BLOCK_MAC_MODES = frozenset(['CBC_MAC', 'CMAC'])
BLOCK_CIPHER_MODES = frozenset([
'CTR', 'CFB', 'OFB', 'XTS', 'CCM_STAR_NO_TAG',
'ECB_NO_PADDING', 'CBC_NO_PADDING', 'CBC_PKCS7',
])
BLOCK_AEAD_MODES = frozenset(['CCM', 'GCM'])
class EllipticCurveCategory(enum.Enum):
"""Categorization of elliptic curve families.
The category of a curve determines what algorithms are defined over it.
"""
SHORT_WEIERSTRASS = 0
MONTGOMERY = 1
TWISTED_EDWARDS = 2
@staticmethod
def from_family(family: str) -> 'EllipticCurveCategory':
if family == 'PSA_ECC_FAMILY_MONTGOMERY':
return EllipticCurveCategory.MONTGOMERY
if family == 'PSA_ECC_FAMILY_TWISTED_EDWARDS':
return EllipticCurveCategory.TWISTED_EDWARDS
# Default to SW, which most curves belong to.
return EllipticCurveCategory.SHORT_WEIERSTRASS
class KeyType:
"""Knowledge about a PSA key type."""
def __init__(self, name: str, params: Optional[Iterable[str]] = None):
def __init__(self, name: str, params: Optional[Iterable[str]] = None) -> None:
"""Analyze a key type.
The key type must be specified in PSA syntax. In its simplest form,
@ -62,6 +92,11 @@ class KeyType:
if self.params is not None:
self.expression += '(' + ', '.join(self.params) + ')'
m = re.match(r'PSA_KEY_TYPE_(\w+)', self.name)
assert m
self.head = re.sub(r'_(?:PUBLIC_KEY|KEY_PAIR)\Z', r'', m.group(1))
"""The key type macro name, with common prefixes and suffixes stripped."""
self.private_type = re.sub(r'_PUBLIC_KEY\Z', r'_KEY_PAIR', self.name)
"""The key type macro name for the corresponding key pair type.
@ -69,6 +104,10 @@ class KeyType:
`self.name`.
"""
def is_public(self) -> bool:
"""Whether the key type is for public keys."""
return self.name.endswith('_PUBLIC_KEY')
ECC_KEY_SIZES = {
'PSA_ECC_FAMILY_SECP_K1': (192, 224, 256),
'PSA_ECC_FAMILY_SECP_R1': (225, 256, 384, 521),
@ -153,3 +192,210 @@ class KeyType:
"""
# This is just temporaly solution for the implicit usage flags.
return re.match(self.KEY_TYPE_FOR_SIGNATURE[usage], self.name) is not None
def can_do(self, alg: 'Algorithm') -> bool:
"""Whether this key type can be used for operations with the given algorithm.
This function does not currently handle key derivation or PAKE.
"""
#pylint: disable=too-many-return-statements
if alg.is_wildcard:
return False
if self.head == 'HMAC' and alg.head == 'HMAC':
return True
if self.head in BLOCK_CIPHERS and \
alg.head in frozenset.union(BLOCK_MAC_MODES,
BLOCK_CIPHER_MODES,
BLOCK_AEAD_MODES):
return True
if self.head == 'CHACHA20' and alg.head == 'CHACHA20_POLY1305':
return True
if self.head in {'ARC4', 'CHACHA20'} and \
alg.head == 'STREAM_CIPHER':
return True
if self.head == 'RSA' and alg.head.startswith('RSA_'):
return True
if self.head == 'ECC':
assert self.params is not None
eccc = EllipticCurveCategory.from_family(self.params[0])
if alg.head == 'ECDH' and \
eccc in {EllipticCurveCategory.SHORT_WEIERSTRASS,
EllipticCurveCategory.MONTGOMERY}:
return True
if alg.head == 'ECDSA' and \
eccc == EllipticCurveCategory.SHORT_WEIERSTRASS:
return True
if alg.head in {'PURE_EDDSA', 'EDDSA_PREHASH'} and \
eccc == EllipticCurveCategory.TWISTED_EDWARDS:
return True
return False
class AlgorithmCategory(enum.Enum):
"""PSA algorithm categories."""
# The numbers are aligned with the category bits in numerical values of
# algorithms.
HASH = 2
MAC = 3
CIPHER = 4
AEAD = 5
SIGN = 6
ASYMMETRIC_ENCRYPTION = 7
KEY_DERIVATION = 8
KEY_AGREEMENT = 9
PAKE = 10
def requires_key(self) -> bool:
"""Whether operations in this category are set up with a key."""
return self not in {self.HASH, self.KEY_DERIVATION}
def is_asymmetric(self) -> bool:
"""Whether operations in this category involve asymmetric keys."""
return self in {
self.SIGN,
self.ASYMMETRIC_ENCRYPTION,
self.KEY_AGREEMENT
}
class AlgorithmNotRecognized(Exception):
def __init__(self, expr: str) -> None:
super().__init__('Algorithm not recognized: ' + expr)
self.expr = expr
class Algorithm:
"""Knowledge about a PSA algorithm."""
@staticmethod
def determine_base(expr: str) -> str:
"""Return an expression for the "base" of the algorithm.
This strips off variants of algorithms such as MAC truncation.
This function does not attempt to detect invalid inputs.
"""
m = re.match(r'PSA_ALG_(?:'
r'(?:TRUNCATED|AT_LEAST_THIS_LENGTH)_MAC|'
r'AEAD_WITH_(?:SHORTENED|AT_LEAST_THIS_LENGTH)_TAG'
r')\((.*),[^,]+\)\Z', expr)
if m:
expr = m.group(1)
return expr
@staticmethod
def determine_head(expr: str) -> str:
"""Return the head of an algorithm expression.
The head is the first (outermost) constructor, without its PSA_ALG_
prefix, and with some normalization of similar algorithms.
"""
m = re.match(r'PSA_ALG_(?:DETERMINISTIC_)?(\w+)', expr)
if not m:
raise AlgorithmNotRecognized(expr)
head = m.group(1)
if head == 'KEY_AGREEMENT':
m = re.match(r'PSA_ALG_KEY_AGREEMENT\s*\(\s*PSA_ALG_(\w+)', expr)
if not m:
raise AlgorithmNotRecognized(expr)
head = m.group(1)
head = re.sub(r'_ANY\Z', r'', head)
if re.match(r'ED[0-9]+PH\Z', head):
head = 'EDDSA_PREHASH'
return head
CATEGORY_FROM_HEAD = {
'SHA': AlgorithmCategory.HASH,
'SHAKE256_512': AlgorithmCategory.HASH,
'MD': AlgorithmCategory.HASH,
'RIPEMD': AlgorithmCategory.HASH,
'ANY_HASH': AlgorithmCategory.HASH,
'HMAC': AlgorithmCategory.MAC,
'STREAM_CIPHER': AlgorithmCategory.CIPHER,
'CHACHA20_POLY1305': AlgorithmCategory.AEAD,
'DSA': AlgorithmCategory.SIGN,
'ECDSA': AlgorithmCategory.SIGN,
'EDDSA': AlgorithmCategory.SIGN,
'PURE_EDDSA': AlgorithmCategory.SIGN,
'RSA_PSS': AlgorithmCategory.SIGN,
'RSA_PKCS1V15_SIGN': AlgorithmCategory.SIGN,
'RSA_PKCS1V15_CRYPT': AlgorithmCategory.ASYMMETRIC_ENCRYPTION,
'RSA_OAEP': AlgorithmCategory.ASYMMETRIC_ENCRYPTION,
'HKDF': AlgorithmCategory.KEY_DERIVATION,
'TLS12_PRF': AlgorithmCategory.KEY_DERIVATION,
'TLS12_PSK_TO_MS': AlgorithmCategory.KEY_DERIVATION,
'PBKDF': AlgorithmCategory.KEY_DERIVATION,
'ECDH': AlgorithmCategory.KEY_AGREEMENT,
'FFDH': AlgorithmCategory.KEY_AGREEMENT,
# KEY_AGREEMENT(...) is a key derivation with a key agreement component
'KEY_AGREEMENT': AlgorithmCategory.KEY_DERIVATION,
'JPAKE': AlgorithmCategory.PAKE,
}
for x in BLOCK_MAC_MODES:
CATEGORY_FROM_HEAD[x] = AlgorithmCategory.MAC
for x in BLOCK_CIPHER_MODES:
CATEGORY_FROM_HEAD[x] = AlgorithmCategory.CIPHER
for x in BLOCK_AEAD_MODES:
CATEGORY_FROM_HEAD[x] = AlgorithmCategory.AEAD
def determine_category(self, expr: str, head: str) -> AlgorithmCategory:
"""Return the category of the given algorithm expression.
This function does not attempt to detect invalid inputs.
"""
prefix = head
while prefix:
if prefix in self.CATEGORY_FROM_HEAD:
return self.CATEGORY_FROM_HEAD[prefix]
if re.match(r'.*[0-9]\Z', prefix):
prefix = re.sub(r'_*[0-9]+\Z', r'', prefix)
else:
prefix = re.sub(r'_*[^_]*\Z', r'', prefix)
raise AlgorithmNotRecognized(expr)
@staticmethod
def determine_wildcard(expr) -> bool:
"""Whether the given algorithm expression is a wildcard.
This function does not attempt to detect invalid inputs.
"""
if re.search(r'\bPSA_ALG_ANY_HASH\b', expr):
return True
if re.search(r'_AT_LEAST_', expr):
return True
return False
def __init__(self, expr: str) -> None:
"""Analyze an algorithm value.
The algorithm must be expressed as a C expression containing only
calls to PSA algorithm constructor macros and numeric literals.
This class is only programmed to handle valid expressions. Invalid
expressions may result in exceptions or in nonsensical results.
"""
self.expression = re.sub(r'\s+', r'', expr)
self.base_expression = self.determine_base(self.expression)
self.head = self.determine_head(self.base_expression)
self.category = self.determine_category(self.base_expression, self.head)
self.is_wildcard = self.determine_wildcard(self.expression)
def is_key_agreement_with_derivation(self) -> bool:
"""Whether this is a combined key agreement and key derivation algorithm."""
if self.category != AlgorithmCategory.KEY_AGREEMENT:
return False
m = re.match(r'PSA_ALG_KEY_AGREEMENT\(\w+,\s*(.*)\)\Z', self.expression)
if not m:
return False
kdf_alg = m.group(1)
# Assume kdf_alg is either a valid KDF or 0.
return not re.match(r'(?:0[Xx])?0+\s*\Z', kdf_alg)
def can_do(self, category: AlgorithmCategory) -> bool:
"""Whether this algorithm fits the specified operation category."""
if category == self.category:
return True
if category == AlgorithmCategory.KEY_DERIVATION and \
self.is_key_agreement_with_derivation():
return True
return False

View file

@ -46,6 +46,10 @@ if(GEN_FILES)
--directory ${CMAKE_CURRENT_BINARY_DIR}/suites
DEPENDS
${CMAKE_CURRENT_SOURCE_DIR}/../tests/scripts/generate_psa_tests.py
${CMAKE_CURRENT_SOURCE_DIR}/../scripts/mbedtls_dev/crypto_knowledge.py
${CMAKE_CURRENT_SOURCE_DIR}/../scripts/mbedtls_dev/macro_collector.py
${CMAKE_CURRENT_SOURCE_DIR}/../scripts/mbedtls_dev/psa_storage.py
${CMAKE_CURRENT_SOURCE_DIR}/../scripts/mbedtls_dev/test_case.py
${CMAKE_CURRENT_SOURCE_DIR}/../include/psa/crypto_config.h
${CMAKE_CURRENT_SOURCE_DIR}/../include/psa/crypto_values.h
${CMAKE_CURRENT_SOURCE_DIR}/../include/psa/crypto_extra.h

View file

@ -84,6 +84,10 @@ generated_files: $(GENERATED_FILES)
.SECONDARY: generated_psa_test_data
$(GENERATED_DATA_FILES): generated_psa_test_data
generated_psa_test_data: scripts/generate_psa_tests.py
generated_psa_test_data: ../scripts/mbedtls_dev/crypto_knowledge.py
generated_psa_test_data: ../scripts/mbedtls_dev/macro_collector.py
generated_psa_test_data: ../scripts/mbedtls_dev/psa_storage.py
generated_psa_test_data: ../scripts/mbedtls_dev/test_case.py
## The generated file only depends on the options that are present in
## crypto_config.h, not on which options are set. To avoid regenerating this
## file all the time when switching between configurations, don't declare

View file

@ -76,7 +76,7 @@ check()
for FILE in "$@"; do
if [ -e "$FILE" ]; then
cp "$FILE" "$FILE.bak"
cp -p "$FILE" "$FILE.bak"
else
rm -f "$FILE.bak"
fi
@ -86,17 +86,18 @@ check()
# Compare the script output to the old files and remove backups
for FILE in "$@"; do
if ! diff "$FILE" "$FILE.bak" >/dev/null 2>&1; then
if diff "$FILE" "$FILE.bak" >/dev/null 2>&1; then
# Move the original file back so that $FILE's timestamp doesn't
# change (avoids spurious rebuilds with make).
mv "$FILE.bak" "$FILE"
else
echo "'$FILE' was either modified or deleted by '$SCRIPT'"
if [ -z "$UPDATE" ]; then
exit 1
else
rm -f "$FILE.bak"
fi
fi
if [ -z "$UPDATE" ]; then
mv "$FILE.bak" "$FILE"
else
rm -f "$FILE.bak"
fi
done
if [ -n "$directory" ]; then

View file

@ -21,6 +21,7 @@ generate only the specified files.
# limitations under the License.
import argparse
import enum
import os
import posixpath
import re
@ -305,6 +306,145 @@ class KeyGenerate:
kt = crypto_knowledge.KeyType(constr, [curve_family])
yield from self.test_cases_for_key_type_key_generation(kt)
class OpFail:
"""Generate test cases for operations that must fail."""
#pylint: disable=too-few-public-methods
class Reason(enum.Enum):
NOT_SUPPORTED = 0
INVALID = 1
INCOMPATIBLE = 2
PUBLIC = 3
def __init__(self, info: Information) -> None:
self.constructors = info.constructors
key_type_expressions = self.constructors.generate_expressions(
sorted(self.constructors.key_types)
)
self.key_types = [crypto_knowledge.KeyType(kt_expr)
for kt_expr in key_type_expressions]
def make_test_case(
self,
alg: crypto_knowledge.Algorithm,
category: crypto_knowledge.AlgorithmCategory,
reason: 'Reason',
kt: Optional[crypto_knowledge.KeyType] = None,
not_deps: FrozenSet[str] = frozenset(),
) -> test_case.TestCase:
"""Construct a failure test case for a one-key or keyless operation."""
#pylint: disable=too-many-arguments,too-many-locals
tc = test_case.TestCase()
pretty_alg = re.sub(r'PSA_ALG_', r'', alg.expression)
if reason == self.Reason.NOT_SUPPORTED:
short_deps = [re.sub(r'PSA_WANT_ALG_', r'', dep)
for dep in not_deps]
pretty_reason = '!' + '&'.join(sorted(short_deps))
else:
pretty_reason = reason.name.lower()
if kt:
key_type = kt.expression
pretty_type = re.sub(r'PSA_KEY_TYPE_', r'', key_type)
else:
key_type = ''
pretty_type = ''
tc.set_description('PSA {} {}: {}{}'
.format(category.name.lower(),
pretty_alg,
pretty_reason,
' with ' + pretty_type if pretty_type else ''))
dependencies = automatic_dependencies(alg.base_expression, key_type)
for i, dep in enumerate(dependencies):
if dep in not_deps:
dependencies[i] = '!' + dep
tc.set_dependencies(dependencies)
tc.set_function(category.name.lower() + '_fail')
arguments = []
if kt:
key_material = kt.key_material(kt.sizes_to_test()[0])
arguments += [key_type, test_case.hex_string(key_material)]
arguments.append(alg.expression)
if category.is_asymmetric():
arguments.append('1' if reason == self.Reason.PUBLIC else '0')
error = ('NOT_SUPPORTED' if reason == self.Reason.NOT_SUPPORTED else
'INVALID_ARGUMENT')
arguments.append('PSA_ERROR_' + error)
tc.set_arguments(arguments)
return tc
def no_key_test_cases(
self,
alg: crypto_knowledge.Algorithm,
category: crypto_knowledge.AlgorithmCategory,
) -> Iterator[test_case.TestCase]:
"""Generate failure test cases for keyless operations with the specified algorithm."""
if alg.can_do(category):
# Compatible operation, unsupported algorithm
for dep in automatic_dependencies(alg.base_expression):
yield self.make_test_case(alg, category,
self.Reason.NOT_SUPPORTED,
not_deps=frozenset([dep]))
else:
# Incompatible operation, supported algorithm
yield self.make_test_case(alg, category, self.Reason.INVALID)
def one_key_test_cases(
self,
alg: crypto_knowledge.Algorithm,
category: crypto_knowledge.AlgorithmCategory,
) -> Iterator[test_case.TestCase]:
"""Generate failure test cases for one-key operations with the specified algorithm."""
for kt in self.key_types:
key_is_compatible = kt.can_do(alg)
if key_is_compatible and alg.can_do(category):
# Compatible key and operation, unsupported algorithm
for dep in automatic_dependencies(alg.base_expression):
yield self.make_test_case(alg, category,
self.Reason.NOT_SUPPORTED,
kt=kt, not_deps=frozenset([dep]))
# Public key for a private-key operation
if category.is_asymmetric() and kt.is_public():
yield self.make_test_case(alg, category,
self.Reason.PUBLIC,
kt=kt)
elif key_is_compatible:
# Compatible key, incompatible operation, supported algorithm
yield self.make_test_case(alg, category,
self.Reason.INVALID,
kt=kt)
elif alg.can_do(category):
# Incompatible key, compatible operation, supported algorithm
yield self.make_test_case(alg, category,
self.Reason.INCOMPATIBLE,
kt=kt)
else:
# Incompatible key and operation. Don't test cases where
# multiple things are wrong, to keep the number of test
# cases reasonable.
pass
def test_cases_for_algorithm(
self,
alg: crypto_knowledge.Algorithm,
) -> Iterator[test_case.TestCase]:
"""Generate operation failure test cases for the specified algorithm."""
for category in crypto_knowledge.AlgorithmCategory:
if category == crypto_knowledge.AlgorithmCategory.PAKE:
# PAKE operations are not implemented yet
pass
elif category.requires_key():
yield from self.one_key_test_cases(alg, category)
else:
yield from self.no_key_test_cases(alg, category)
def all_test_cases(self) -> Iterator[test_case.TestCase]:
"""Generate all test cases for operations that must fail."""
algorithms = sorted(self.constructors.algorithms)
for expr in self.constructors.generate_expressions(algorithms):
alg = crypto_knowledge.Algorithm(expr)
yield from self.test_cases_for_algorithm(alg)
class StorageKey(psa_storage.Key):
"""Representation of a key for storage format testing."""
@ -443,51 +583,41 @@ class StorageFormat:
continue
yield self.key_for_lifetime(lifetime)
def keys_for_usage_flags(
def key_for_usage_flags(
self,
usage_flags: List[str],
short: Optional[str] = None,
test_implicit_usage: Optional[bool] = False
) -> Iterator[StorageTestData]:
test_implicit_usage: Optional[bool] = True
) -> StorageTestData:
"""Construct a test key for the given key usage."""
usage = ' | '.join(usage_flags) if usage_flags else '0'
if short is None:
short = re.sub(r'\bPSA_KEY_USAGE_', r'', usage)
extra_desc = ' with implication' if test_implicit_usage else ''
extra_desc = ' without implication' if test_implicit_usage else ''
description = 'usage' + extra_desc + ': ' + short
key1 = StorageTestData(version=self.version,
id=1, lifetime=0x00000001,
type='PSA_KEY_TYPE_RAW_DATA', bits=8,
expected_usage=usage,
without_implicit_usage=not test_implicit_usage,
usage=usage, alg=0, alg2=0,
material=b'K',
description=description)
yield key1
if test_implicit_usage:
description = 'usage without implication' + ': ' + short
key2 = StorageTestData(version=self.version,
id=1, lifetime=0x00000001,
type='PSA_KEY_TYPE_RAW_DATA', bits=8,
without_implicit_usage=True,
usage=usage, alg=0, alg2=0,
material=b'K',
description=description)
yield key2
return key1
def generate_keys_for_usage_flags(self, **kwargs) -> Iterator[StorageTestData]:
"""Generate test keys covering usage flags."""
known_flags = sorted(self.constructors.key_usage_flags)
yield from self.keys_for_usage_flags(['0'], **kwargs)
yield self.key_for_usage_flags(['0'], **kwargs)
for usage_flag in known_flags:
yield from self.keys_for_usage_flags([usage_flag], **kwargs)
yield self.key_for_usage_flags([usage_flag], **kwargs)
for flag1, flag2 in zip(known_flags,
known_flags[1:] + [known_flags[0]]):
yield from self.keys_for_usage_flags([flag1, flag2], **kwargs)
yield self.key_for_usage_flags([flag1, flag2], **kwargs)
def generate_key_for_all_usage_flags(self) -> Iterator[StorageTestData]:
known_flags = sorted(self.constructors.key_usage_flags)
yield from self.keys_for_usage_flags(known_flags, short='all known')
yield self.key_for_usage_flags(known_flags, short='all known')
def all_keys_for_usage_flags(self) -> Iterator[StorageTestData]:
yield from self.generate_keys_for_usage_flags()
@ -593,8 +723,8 @@ class StorageFormatV0(StorageFormat):
def all_keys_for_usage_flags(self) -> Iterator[StorageTestData]:
"""Generate test keys covering usage flags."""
yield from self.generate_keys_for_usage_flags(test_implicit_usage=True)
yield from self.generate_key_for_all_usage_flags()
yield from super().all_keys_for_usage_flags()
yield from self.generate_keys_for_usage_flags(test_implicit_usage=False)
def keys_for_implicit_usage(
self,
@ -732,6 +862,8 @@ class TestGenerator:
lambda info: KeyGenerate(info).test_cases_for_key_generation(),
'test_suite_psa_crypto_not_supported.generated':
lambda info: NotSupported(info).test_cases_for_not_supported(),
'test_suite_psa_crypto_op_fail.generated':
lambda info: OpFail(info).all_test_cases(),
'test_suite_psa_crypto_storage_format.current':
lambda info: StorageFormatForward(info, 0).all_test_cases(),
'test_suite_psa_crypto_storage_format.v0':

View file

@ -2160,7 +2160,7 @@ depends_on:PSA_WANT_ALG_CBC_NO_PADDING:PSA_WANT_KEY_TYPE_DES
cipher_encrypt_validation:PSA_ALG_CBC_NO_PADDING:PSA_KEY_TYPE_DES:"01020407080b0d0ec1c2c4c7c8cbcdce31323437383b3d3e":"eda4011239bc3ac9"
PSA symmetric encrypt validation: CCM*-no-tag, 15 bytes, good
depends_on:PSA_WANT_ALG_CCM:PSA_WANT_KEY_TYPE_AES
depends_on:PSA_WANT_ALG_CCM_STAR_NO_TAG:PSA_WANT_KEY_TYPE_AES
cipher_encrypt_validation:PSA_ALG_CCM_STAR_NO_TAG:PSA_KEY_TYPE_AES:"d24a3d3dde8c84830280cb87abad0bb3":"6bc1bee22e409f96e93d7e11739317"
PSA symmetric encrypt multipart: AES-ECB, 0 bytes, good
@ -2224,7 +2224,7 @@ depends_on:PSA_WANT_ALG_ECB_NO_PADDING:PSA_WANT_KEY_TYPE_DES
cipher_encrypt_multipart:PSA_ALG_ECB_NO_PADDING:PSA_KEY_TYPE_DES:"01020407080b0d0ec1c2c4c7c8cbcdce31323437383b3d3e":"":"c78e2b38139610e3":8:8:0:"817ca7d69b80d86a":PSA_SUCCESS
PSA symmetric encrypt multipart: CCM*-no-tag, AES, 24 bytes, good
depends_on:PSA_WANT_ALG_CCM:PSA_WANT_KEY_TYPE_AES
depends_on:PSA_WANT_ALG_CCM_STAR_NO_TAG:PSA_WANT_KEY_TYPE_AES
cipher_encrypt_multipart:PSA_ALG_CCM_STAR_NO_TAG:PSA_KEY_TYPE_AES:"d24a3d3dde8c84830280cb87abad0bb3":"f1100035bb24a8d26004e0e24b":"7c86135ed9c2a515aaae0e9a208133897269220f30870006":10:10:14:"1faeb0ee2ca2cd52f0aa3966578344f24e69b742c4ab37ab":PSA_SUCCESS
PSA cipher decrypt: without initialization
@ -2260,7 +2260,7 @@ depends_on:PSA_WANT_ALG_CBC_NO_PADDING:PSA_WANT_KEY_TYPE_AES
cipher_decrypt_fail:PSA_ALG_CBC_NO_PADDING:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a":"6bc1bee223":PSA_ERROR_INVALID_ARGUMENT
PSA symetric decrypt: CCM*-no-tag, input too short (15 bytes)
depends_on:MBEDTLS_AES_C:MBEDTLS_CCM_C
depends_on:PSA_WANT_ALG_CCM_STAR_NO_TAG:MBEDTLS_AES_C
cipher_decrypt_fail:PSA_ALG_CCM_STAR_NO_TAG:PSA_KEY_TYPE_AES:"19ebfde2d5468ba0a3031bde629b11fd":"5a8aa485c316e9":"2a2a2a2a2a2a2a2a":PSA_ERROR_INVALID_ARGUMENT
PSA symmetric decrypt: AES-ECB, 0 bytes, good
@ -2312,7 +2312,7 @@ depends_on:PSA_WANT_ALG_ECB_NO_PADDING:PSA_WANT_KEY_TYPE_DES
cipher_decrypt:PSA_ALG_ECB_NO_PADDING:PSA_KEY_TYPE_DES:"01020407080b0d0ec1c2c4c7c8cbcdce31323437383b3d3e":"":"817ca7d69b80d86a":"c78e2b38139610e3"
PSA symmetric decrypt: CCM*-no-tag, NIST DVPT AES-128 #15
depends_on:PSA_WANT_ALG_CCM:PSA_WANT_KEY_TYPE_AES
depends_on:PSA_WANT_ALG_CCM_STAR_NO_TAG:PSA_WANT_KEY_TYPE_AES
cipher_decrypt:PSA_ALG_CCM_STAR_NO_TAG:PSA_KEY_TYPE_AES:"90929a4b0ac65b350ad1591611fe4829":"5a8aa485c316e9403aff859fbb":"4bfe4e35784f0a65b545477e5e2f4bae0e1e6fa717eaf2cb":"a16a2e741f1cd9717285b6d882c1fc53655e9773761ad697"
PSA symmetric decrypt multipart: AES-ECB, 0 bytes, good
@ -2376,7 +2376,7 @@ depends_on:PSA_WANT_ALG_ECB_NO_PADDING:PSA_WANT_KEY_TYPE_DES
cipher_decrypt_multipart:PSA_ALG_ECB_NO_PADDING:PSA_KEY_TYPE_DES:"01020407080b0d0ec1c2c4c7c8cbcdce31323437383b3d3e":"":"817ca7d69b80d86a":8:8:0:"c78e2b38139610e3":PSA_SUCCESS
PSA symmetric decrypt multipart: CCM*-no-tag, 24 bytes, good
depends_on:PSA_WANT_ALG_ECB_NO_PADDING:PSA_WANT_KEY_TYPE_DES
depends_on:PSA_WANT_ALG_CCM_STAR_NO_TAG:PSA_WANT_KEY_TYPE_AES
cipher_decrypt_multipart:PSA_ALG_CCM_STAR_NO_TAG:PSA_KEY_TYPE_AES:"197afb02ffbd8f699dacae87094d5243":"5a8aa485c316e9403aff859fbb":"4a550134f94455979ec4bf89ad2bd80d25a77ae94e456134":10:10:14:"a16a2e741f1cd9717285b6d882c1fc53655e9773761ad697":PSA_SUCCESS
PSA symmetric encrypt/decrypt: AES-ECB, 16 bytes, good
@ -2400,19 +2400,19 @@ depends_on:PSA_WANT_ALG_CTR:PSA_WANT_KEY_TYPE_AES
cipher_verify_output:PSA_ALG_CTR:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"6bc1bee22e409f96e93d7e117393172a"
PSA symmetric encrypt/decrypt: CCM*-no-tag, AES
depends_on:PSA_WANT_ALG_CCM:PSA_WANT_KEY_TYPE_AES
depends_on:PSA_WANT_ALG_CCM_STAR_NO_TAG:PSA_WANT_KEY_TYPE_AES
cipher_verify_output:PSA_ALG_CCM_STAR_NO_TAG:PSA_KEY_TYPE_AES:"2b7e151628aed2a6abf7158809cf4f3c":"6bc1bee22e409f96e93d7e117393172a"
CCM*-no-tag encrypt, iv_length = 14, bad
depends_on:PSA_WANT_ALG_CCM:PSA_WANT_KEY_TYPE_AES
depends_on:PSA_WANT_ALG_CCM_STAR_NO_TAG:PSA_WANT_KEY_TYPE_AES
cipher_encrypt_validate_iv_length:PSA_ALG_CCM_STAR_NO_TAG:PSA_KEY_TYPE_AES:"90929a4b0ac65b350ad1591611fe4829":"2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a":14:PSA_ERROR_INVALID_ARGUMENT
CCM*-no-tag encrypt, iv_length = 13, good
depends_on:PSA_WANT_ALG_CCM:PSA_WANT_KEY_TYPE_AES
depends_on:PSA_WANT_ALG_CCM_STAR_NO_TAG:PSA_WANT_KEY_TYPE_AES
cipher_encrypt_validate_iv_length:PSA_ALG_CCM_STAR_NO_TAG:PSA_KEY_TYPE_AES:"90929a4b0ac65b350ad1591611fe4829":"2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a":13:PSA_SUCCESS
CCM*-no-tag encrypt, iv_length = 12, bad
depends_on:PSA_WANT_ALG_CCM:PSA_WANT_KEY_TYPE_AES
depends_on:PSA_WANT_ALG_CCM_STAR_NO_TAG:PSA_WANT_KEY_TYPE_AES
cipher_encrypt_validate_iv_length:PSA_ALG_CCM_STAR_NO_TAG:PSA_KEY_TYPE_AES:"90929a4b0ac65b350ad1591611fe4829":"2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a":12:PSA_ERROR_INVALID_ARGUMENT
PSA symmetric encryption multipart: AES-ECB, 16+16 bytes

View file

@ -0,0 +1,390 @@
/* BEGIN_HEADER */
#include "psa/crypto.h"
#include "test/psa_crypto_helpers.h"
static int test_equal_status( const char *test,
int line_no, const char* filename,
psa_status_t value1,
psa_status_t value2 )
{
if( ( value1 == PSA_ERROR_INVALID_ARGUMENT &&
value2 == PSA_ERROR_NOT_SUPPORTED ) ||
( value1 == PSA_ERROR_NOT_SUPPORTED &&
value2 == PSA_ERROR_INVALID_ARGUMENT ) )
{
return( 1 );
}
return( mbedtls_test_equal( test, line_no, filename, value1, value2 ) );
}
/** Like #TEST_EQUAL, but expects #psa_status_t values and treats
* #PSA_ERROR_INVALID_ARGUMENT and #PSA_ERROR_NOT_SUPPORTED as
* interchangeable.
*
* This test suite currently allows NOT_SUPPORTED and INVALID_ARGUMENT
* to be interchangeable in places where the library's behavior does not
* match the strict expectations of the test case generator. In the long
* run, it would be better to clarify the expectations and reconcile the
* library and the test case generator.
*/
#define TEST_STATUS( expr1, expr2 ) \
do { \
if( ! test_equal_status( #expr1 " == " #expr2, __LINE__, __FILE__, \
expr1, expr2 ) ) \
goto exit; \
} while( 0 )
/* END_HEADER */
/* BEGIN_DEPENDENCIES
* depends_on:MBEDTLS_PSA_CRYPTO_C
* END_DEPENDENCIES
*/
/* BEGIN_CASE */
void hash_fail( int alg_arg, int expected_status_arg )
{
psa_status_t expected_status = expected_status_arg;
psa_algorithm_t alg = alg_arg;
psa_hash_operation_t operation = PSA_HASH_OPERATION_INIT;
uint8_t input[1] = {'A'};
uint8_t output[PSA_HASH_MAX_SIZE] = {0};
size_t length = SIZE_MAX;
PSA_INIT( );
TEST_EQUAL( expected_status,
psa_hash_setup( &operation, alg ) );
TEST_EQUAL( expected_status,
psa_hash_compute( alg, input, sizeof( input ),
output, sizeof( output ), &length ) );
TEST_EQUAL( expected_status,
psa_hash_compare( alg, input, sizeof( input ),
output, sizeof( output ) ) );
exit:
psa_hash_abort( &operation );
PSA_DONE( );
}
/* END_CASE */
/* BEGIN_CASE */
void mac_fail( int key_type_arg, data_t *key_data,
int alg_arg, int expected_status_arg )
{
psa_status_t expected_status = expected_status_arg;
psa_key_type_t key_type = key_type_arg;
psa_algorithm_t alg = alg_arg;
psa_mac_operation_t operation = PSA_MAC_OPERATION_INIT;
psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
mbedtls_svc_key_id_t key_id = MBEDTLS_SVC_KEY_ID_INIT;
uint8_t input[1] = {'A'};
uint8_t output[PSA_MAC_MAX_SIZE] = {0};
size_t length = SIZE_MAX;
PSA_INIT( );
psa_set_key_type( &attributes, key_type );
psa_set_key_usage_flags( &attributes,
PSA_KEY_USAGE_SIGN_HASH |
PSA_KEY_USAGE_VERIFY_HASH );
psa_set_key_algorithm( &attributes, alg );
PSA_ASSERT( psa_import_key( &attributes,
key_data->x, key_data->len,
&key_id ) );
TEST_STATUS( expected_status,
psa_mac_sign_setup( &operation, key_id, alg ) );
TEST_STATUS( expected_status,
psa_mac_verify_setup( &operation, key_id, alg ) );
TEST_STATUS( expected_status,
psa_mac_compute( key_id, alg,
input, sizeof( input ),
output, sizeof( output ), &length ) );
TEST_STATUS( expected_status,
psa_mac_verify( key_id, alg,
input, sizeof( input ),
output, sizeof( output ) ) );
exit:
psa_mac_abort( &operation );
psa_destroy_key( key_id );
psa_reset_key_attributes( &attributes );
PSA_DONE( );
}
/* END_CASE */
/* BEGIN_CASE */
void cipher_fail( int key_type_arg, data_t *key_data,
int alg_arg, int expected_status_arg )
{
psa_status_t expected_status = expected_status_arg;
psa_key_type_t key_type = key_type_arg;
psa_algorithm_t alg = alg_arg;
psa_cipher_operation_t operation = PSA_CIPHER_OPERATION_INIT;
psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
mbedtls_svc_key_id_t key_id = MBEDTLS_SVC_KEY_ID_INIT;
uint8_t input[1] = {'A'};
uint8_t output[64] = {0};
size_t length = SIZE_MAX;
PSA_INIT( );
psa_set_key_type( &attributes, key_type );
psa_set_key_usage_flags( &attributes,
PSA_KEY_USAGE_ENCRYPT |
PSA_KEY_USAGE_DECRYPT );
psa_set_key_algorithm( &attributes, alg );
PSA_ASSERT( psa_import_key( &attributes,
key_data->x, key_data->len,
&key_id ) );
TEST_STATUS( expected_status,
psa_cipher_encrypt_setup( &operation, key_id, alg ) );
TEST_STATUS( expected_status,
psa_cipher_decrypt_setup( &operation, key_id, alg ) );
TEST_STATUS( expected_status,
psa_cipher_encrypt( key_id, alg,
input, sizeof( input ),
output, sizeof( output ), &length ) );
TEST_STATUS( expected_status,
psa_cipher_decrypt( key_id, alg,
input, sizeof( input ),
output, sizeof( output ), &length ) );
exit:
psa_cipher_abort( &operation );
psa_destroy_key( key_id );
psa_reset_key_attributes( &attributes );
PSA_DONE( );
}
/* END_CASE */
/* BEGIN_CASE */
void aead_fail( int key_type_arg, data_t *key_data,
int alg_arg, int expected_status_arg )
{
psa_status_t expected_status = expected_status_arg;
psa_key_type_t key_type = key_type_arg;
psa_algorithm_t alg = alg_arg;
psa_aead_operation_t operation = PSA_AEAD_OPERATION_INIT;
psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
mbedtls_svc_key_id_t key_id = MBEDTLS_SVC_KEY_ID_INIT;
uint8_t input[16] = "ABCDEFGHIJKLMNO";
uint8_t output[64] = {0};
size_t length = SIZE_MAX;
PSA_INIT( );
psa_set_key_type( &attributes, key_type );
psa_set_key_usage_flags( &attributes,
PSA_KEY_USAGE_ENCRYPT |
PSA_KEY_USAGE_DECRYPT );
psa_set_key_algorithm( &attributes, alg );
PSA_ASSERT( psa_import_key( &attributes,
key_data->x, key_data->len,
&key_id ) );
TEST_STATUS( expected_status,
psa_aead_encrypt_setup( &operation, key_id, alg ) );
TEST_STATUS( expected_status,
psa_aead_decrypt_setup( &operation, key_id, alg ) );
TEST_STATUS( expected_status,
psa_aead_encrypt( key_id, alg,
input, sizeof( input ),
NULL, 0, input, sizeof( input ),
output, sizeof( output ), &length ) );
TEST_STATUS( expected_status,
psa_aead_decrypt( key_id, alg,
input, sizeof( input ),
NULL, 0, input, sizeof( input ),
output, sizeof( output ), &length ) );
exit:
psa_aead_abort( &operation );
psa_destroy_key( key_id );
psa_reset_key_attributes( &attributes );
PSA_DONE( );
}
/* END_CASE */
/* BEGIN_CASE */
void sign_fail( int key_type_arg, data_t *key_data,
int alg_arg, int private_only,
int expected_status_arg )
{
psa_status_t expected_status = expected_status_arg;
psa_key_type_t key_type = key_type_arg;
psa_algorithm_t alg = alg_arg;
psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
mbedtls_svc_key_id_t key_id = MBEDTLS_SVC_KEY_ID_INIT;
uint8_t input[1] = {'A'};
uint8_t output[PSA_SIGNATURE_MAX_SIZE] = {0};
size_t length = SIZE_MAX;
PSA_INIT( );
psa_set_key_type( &attributes, key_type );
psa_set_key_usage_flags( &attributes,
PSA_KEY_USAGE_SIGN_HASH |
PSA_KEY_USAGE_VERIFY_HASH );
psa_set_key_algorithm( &attributes, alg );
PSA_ASSERT( psa_import_key( &attributes,
key_data->x, key_data->len,
&key_id ) );
TEST_STATUS( expected_status,
psa_sign_hash( key_id, alg,
input, sizeof( input ),
output, sizeof( output ), &length ) );
if( ! private_only )
{
/* Determine a plausible signature size to avoid an INVALID_SIGNATURE
* error based on this. */
PSA_ASSERT( psa_get_key_attributes( key_id, &attributes ) );
size_t key_bits = psa_get_key_bits( &attributes );
size_t output_length = sizeof( output );
if( PSA_KEY_TYPE_IS_RSA( key_type ) )
output_length = PSA_BITS_TO_BYTES( key_bits );
else if( PSA_KEY_TYPE_IS_ECC( key_type ) )
output_length = 2 * PSA_BITS_TO_BYTES( key_bits );
TEST_ASSERT( output_length <= sizeof( output ) );
TEST_STATUS( expected_status,
psa_verify_hash( key_id, alg,
input, sizeof( input ),
output, output_length ) );
}
exit:
psa_destroy_key( key_id );
psa_reset_key_attributes( &attributes );
PSA_DONE( );
}
/* END_CASE */
/* BEGIN_CASE */
void asymmetric_encryption_fail( int key_type_arg, data_t *key_data,
int alg_arg, int private_only,
int expected_status_arg )
{
psa_status_t expected_status = expected_status_arg;
psa_key_type_t key_type = key_type_arg;
psa_algorithm_t alg = alg_arg;
psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
mbedtls_svc_key_id_t key_id = MBEDTLS_SVC_KEY_ID_INIT;
uint8_t plaintext[PSA_ASYMMETRIC_DECRYPT_OUTPUT_MAX_SIZE] = {0};
uint8_t ciphertext[PSA_ASYMMETRIC_ENCRYPT_OUTPUT_MAX_SIZE] = {0};
size_t length = SIZE_MAX;
PSA_INIT( );
psa_set_key_type( &attributes, key_type );
psa_set_key_usage_flags( &attributes,
PSA_KEY_USAGE_ENCRYPT |
PSA_KEY_USAGE_DECRYPT );
psa_set_key_algorithm( &attributes, alg );
PSA_ASSERT( psa_import_key( &attributes,
key_data->x, key_data->len,
&key_id ) );
if( ! private_only )
{
TEST_STATUS( expected_status,
psa_asymmetric_encrypt( key_id, alg,
plaintext, 1,
NULL, 0,
ciphertext, sizeof( ciphertext ),
&length ) );
}
TEST_STATUS( expected_status,
psa_asymmetric_decrypt( key_id, alg,
ciphertext, sizeof( ciphertext ),
NULL, 0,
plaintext, sizeof( plaintext ),
&length ) );
exit:
psa_destroy_key( key_id );
psa_reset_key_attributes( &attributes );
PSA_DONE( );
}
/* END_CASE */
/* BEGIN_CASE */
void key_derivation_fail( int alg_arg, int expected_status_arg )
{
psa_status_t expected_status = expected_status_arg;
psa_algorithm_t alg = alg_arg;
psa_key_derivation_operation_t operation = PSA_KEY_DERIVATION_OPERATION_INIT;
PSA_INIT( );
TEST_EQUAL( expected_status,
psa_key_derivation_setup( &operation, alg ) );
exit:
psa_key_derivation_abort( &operation );
PSA_DONE( );
}
/* END_CASE */
/* BEGIN_CASE */
void key_agreement_fail( int key_type_arg, data_t *key_data,
int alg_arg, int private_only,
int expected_status_arg )
{
psa_status_t expected_status = expected_status_arg;
psa_key_type_t key_type = key_type_arg;
psa_algorithm_t alg = alg_arg;
psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
mbedtls_svc_key_id_t key_id = MBEDTLS_SVC_KEY_ID_INIT;
uint8_t public_key[PSA_EXPORT_PUBLIC_KEY_MAX_SIZE] = {0};
size_t public_key_length = SIZE_MAX;
uint8_t output[PSA_SIGNATURE_MAX_SIZE] = {0};
size_t length = SIZE_MAX;
psa_key_derivation_operation_t operation = PSA_KEY_DERIVATION_OPERATION_INIT;
PSA_INIT( );
psa_set_key_type( &attributes, key_type );
psa_set_key_usage_flags( &attributes,
PSA_KEY_USAGE_DERIVE );
psa_set_key_algorithm( &attributes, alg );
PSA_ASSERT( psa_import_key( &attributes,
key_data->x, key_data->len,
&key_id ) );
if( PSA_KEY_TYPE_IS_KEY_PAIR( key_type ) ||
PSA_KEY_TYPE_IS_PUBLIC_KEY( key_type ) )
{
PSA_ASSERT( psa_export_public_key( key_id,
public_key, sizeof( public_key ),
&public_key_length ) );
}
TEST_STATUS( expected_status,
psa_raw_key_agreement( alg, key_id,
public_key, public_key_length,
output, sizeof( output ), &length ) );
#if defined(PSA_WANT_ALG_HKDF) && defined(PSA_WANT_ALG_SHA_256)
PSA_ASSERT( psa_key_derivation_setup( &operation,
PSA_ALG_HKDF( PSA_ALG_SHA_256 ) ) );
TEST_STATUS( expected_status,
psa_key_derivation_key_agreement(
&operation,
PSA_KEY_DERIVATION_INPUT_SECRET,
key_id,
public_key, public_key_length ) );
#endif
/* There are no public-key operations. */
(void) private_only;
exit:
psa_key_derivation_abort( &operation );
psa_destroy_key( key_id );
psa_reset_key_attributes( &attributes );
PSA_DONE( );
}
/* END_CASE */

View file

@ -0,0 +1,15 @@
# Most operation failure test cases are automatically generated in
# test_suite_psa_crypto_op_fail.generated.data. The manually written
# test cases in this file are only intended to help with debugging the
# test code.
PSA hash: invalid algorithm
hash_fail:PSA_ALG_ECDSA_ANY:PSA_ERROR_INVALID_ARGUMENT
PSA sign RSA_PSS(SHA_256): incompatible key type
depends_on:PSA_WANT_ALG_RSA_PSS:PSA_WANT_ALG_SHA_256:PSA_WANT_KEY_TYPE_AES
sign_fail:PSA_KEY_TYPE_AES:"48657265006973206b6579a064617461":PSA_ALG_RSA_PSS(PSA_ALG_SHA_256):0:PSA_ERROR_INVALID_ARGUMENT
PSA sign RSA_PSS(SHA_256): RSA_PSS not enabled, key pair
depends_on:!PSA_WANT_ALG_RSA_PSS:PSA_WANT_ALG_SHA_256:PSA_WANT_KEY_TYPE_RSA_KEY_PAIR
sign_fail:PSA_KEY_TYPE_RSA_KEY_PAIR:"3082025e02010002818100af057d396ee84fb75fdbb5c2b13c7fe5a654aa8aa2470b541ee1feb0b12d25c79711531249e1129628042dbbb6c120d1443524ef4c0e6e1d8956eeb2077af12349ddeee54483bc06c2c61948cd02b202e796aebd94d3a7cbf859c2c1819c324cb82b9cd34ede263a2abffe4733f077869e8660f7d6834da53d690ef7985f6bc3020301000102818100874bf0ffc2f2a71d14671ddd0171c954d7fdbf50281e4f6d99ea0e1ebcf82faa58e7b595ffb293d1abe17f110b37c48cc0f36c37e84d876621d327f64bbe08457d3ec4098ba2fa0a319fba411c2841ed7be83196a8cdf9daa5d00694bc335fc4c32217fe0488bce9cb7202e59468b1ead119000477db2ca797fac19eda3f58c1024100e2ab760841bb9d30a81d222de1eb7381d82214407f1b975cbbfe4e1a9467fd98adbd78f607836ca5be1928b9d160d97fd45c12d6b52e2c9871a174c66b488113024100c5ab27602159ae7d6f20c3c2ee851e46dc112e689e28d5fcbbf990a99ef8a90b8bb44fd36467e7fc1789ceb663abda338652c3c73f111774902e840565927091024100b6cdbd354f7df579a63b48b3643e353b84898777b48b15f94e0bfc0567a6ae5911d57ad6409cf7647bf96264e9bd87eb95e263b7110b9a1f9f94acced0fafa4d024071195eec37e8d257decfc672b07ae639f10cbb9b0c739d0c809968d644a94e3fd6ed9287077a14583f379058f76a8aecd43c62dc8c0f41766650d725275ac4a1024100bb32d133edc2e048d463388b7be9cb4be29f4b6250be603e70e3647501c97ddde20a4e71be95fd5e71784e25aca4baf25be5738aae59bbfe1c997781447a2b24":PSA_ALG_RSA_PSS(PSA_ALG_SHA_256):0:PSA_ERROR_NOT_SUPPORTED