449bd8303e
Signed-off-by: Gilles Peskine <Gilles.Peskine@arm.com>
737 lines
31 KiB
C
737 lines
31 KiB
C
/* BEGIN_HEADER */
|
|
/* Test macros that provide metadata about algorithms and key types.
|
|
* This test suite only contains tests that don't require executing
|
|
* code. Other test suites validate macros that require creating a key
|
|
* and using it. */
|
|
|
|
#if defined(MBEDTLS_PSA_CRYPTO_SPM)
|
|
#include "spm/psa_defs.h"
|
|
#endif
|
|
|
|
#include "psa/crypto.h"
|
|
#include "psa_crypto_invasive.h"
|
|
|
|
/* Flags for algorithm classification macros. There is a flag for every
|
|
* algorithm classification macro PSA_ALG_IS_xxx except for the
|
|
* category test macros, which are hard-coded in each
|
|
* category-specific function. The name of the flag is the name of the
|
|
* classification macro without the PSA_ prefix. */
|
|
#define ALG_IS_VENDOR_DEFINED (1u << 0)
|
|
#define ALG_IS_HMAC (1u << 1)
|
|
#define ALG_IS_BLOCK_CIPHER_MAC (1u << 2)
|
|
#define ALG_IS_STREAM_CIPHER (1u << 3)
|
|
#define ALG_IS_RSA_PKCS1V15_SIGN (1u << 4)
|
|
#define ALG_IS_RSA_PSS (1u << 5)
|
|
#define ALG_IS_RSA_PSS_ANY_SALT (1u << 6)
|
|
#define ALG_IS_RSA_PSS_STANDARD_SALT (1u << 7)
|
|
#define ALG_IS_DSA (1u << 8)
|
|
#define ALG_DSA_IS_DETERMINISTIC (1u << 9)
|
|
#define ALG_IS_DETERMINISTIC_DSA (1u << 10)
|
|
#define ALG_IS_RANDOMIZED_DSA (1u << 11)
|
|
#define ALG_IS_ECDSA (1u << 12)
|
|
#define ALG_ECDSA_IS_DETERMINISTIC (1u << 13)
|
|
#define ALG_IS_DETERMINISTIC_ECDSA (1u << 14)
|
|
#define ALG_IS_RANDOMIZED_ECDSA (1u << 15)
|
|
#define ALG_IS_HASH_EDDSA (1u << 16)
|
|
#define ALG_IS_SIGN_HASH (1u << 17)
|
|
#define ALG_IS_HASH_AND_SIGN (1u << 18)
|
|
#define ALG_IS_RSA_OAEP (1u << 19)
|
|
#define ALG_IS_HKDF (1u << 20)
|
|
#define ALG_IS_HKDF_EXTRACT (1u << 21)
|
|
#define ALG_IS_HKDF_EXPAND (1u << 22)
|
|
#define ALG_IS_FFDH (1u << 23)
|
|
#define ALG_IS_ECDH (1u << 24)
|
|
#define ALG_IS_WILDCARD (1u << 25)
|
|
#define ALG_IS_RAW_KEY_AGREEMENT (1u << 26)
|
|
#define ALG_IS_AEAD_ON_BLOCK_CIPHER (1u << 27)
|
|
#define ALG_IS_TLS12_PRF (1u << 28)
|
|
#define ALG_IS_TLS12_PSK_TO_MS (1u << 29)
|
|
#define ALG_FLAG_MASK_PLUS_ONE (1u << 30) /* must be last! */
|
|
|
|
/* Flags for key type classification macros. There is a flag for every
|
|
* key type classification macro PSA_KEY_TYPE_IS_xxx except for some that
|
|
* are tested as derived from other macros. The name of the flag is
|
|
* the name of the classification macro without the PSA_ prefix. */
|
|
#define KEY_TYPE_IS_VENDOR_DEFINED (1u << 0)
|
|
#define KEY_TYPE_IS_UNSTRUCTURED (1u << 1)
|
|
#define KEY_TYPE_IS_PUBLIC_KEY (1u << 2)
|
|
#define KEY_TYPE_IS_KEY_PAIR (1u << 3)
|
|
#define KEY_TYPE_IS_RSA (1u << 4)
|
|
#define KEY_TYPE_IS_DSA (1u << 5)
|
|
#define KEY_TYPE_IS_ECC (1u << 6)
|
|
#define KEY_TYPE_IS_DH (1u << 7)
|
|
#define KEY_TYPE_FLAG_MASK_PLUS_ONE (1u << 8) /* must be last! */
|
|
|
|
/* Flags for lifetime classification macros. There is a flag for every
|
|
* lifetime classification macro PSA_KEY_LIFETIME_IS_xxx. The name of the
|
|
* flag is the name of the classification macro without the PSA_ prefix. */
|
|
#define KEY_LIFETIME_IS_VOLATILE (1u << 0)
|
|
#define KEY_LIFETIME_IS_READ_ONLY (1u << 1)
|
|
#define KEY_LIFETIME_FLAG_MASK_PLUS_ONE (1u << 2) /* must be last! */
|
|
|
|
/* Check that in the value of flags, the bit flag (which should be a macro
|
|
* expanding to a number of the form 1 << k) is set if and only if
|
|
* PSA_##flag(alg) is true.
|
|
*
|
|
* Only perform this check if cond is true. Typically cond is 1, but it can
|
|
* be different if the value of the flag bit is only specified under specific
|
|
* conditions.
|
|
*
|
|
* Unconditionally mask flag into the ambient variable
|
|
* classification_flags_tested.
|
|
*/
|
|
#define TEST_CLASSIFICATION_MACRO(cond, flag, alg, flags) \
|
|
do \
|
|
{ \
|
|
if (cond) \
|
|
{ \
|
|
if ((flags) & (flag)) \
|
|
TEST_ASSERT(PSA_##flag(alg)); \
|
|
else \
|
|
TEST_ASSERT(!PSA_##flag(alg)); \
|
|
} \
|
|
classification_flags_tested |= (flag); \
|
|
} \
|
|
while (0)
|
|
|
|
/* Check the parity of value.
|
|
*
|
|
* There are several numerical encodings for which the PSA Cryptography API
|
|
* specification deliberately defines encodings that all have the same
|
|
* parity. This way, a data glitch that flips one bit in the data cannot
|
|
* possibly turn a valid encoding into another valid encoding. Here in
|
|
* the tests, we check that the values (including Mbed TLS vendor-specific
|
|
* values) have the expected parity.
|
|
*
|
|
* The expected parity is even so that 0 is considered a valid encoding.
|
|
*
|
|
* Return a nonzero value if value has even parity and 0 otherwise. */
|
|
int has_even_parity(uint32_t value)
|
|
{
|
|
value ^= value >> 16;
|
|
value ^= value >> 8;
|
|
value ^= value >> 4;
|
|
return 0x9669 & 1 << (value & 0xf);
|
|
}
|
|
#define TEST_PARITY(value) \
|
|
TEST_ASSERT(has_even_parity(value))
|
|
|
|
void algorithm_classification(psa_algorithm_t alg, unsigned flags)
|
|
{
|
|
unsigned classification_flags_tested = 0;
|
|
TEST_CLASSIFICATION_MACRO(1, ALG_IS_VENDOR_DEFINED, alg, flags);
|
|
TEST_CLASSIFICATION_MACRO(1, ALG_IS_HMAC, alg, flags);
|
|
TEST_CLASSIFICATION_MACRO(1, ALG_IS_BLOCK_CIPHER_MAC, alg, flags);
|
|
TEST_CLASSIFICATION_MACRO(1, ALG_IS_STREAM_CIPHER, alg, flags);
|
|
TEST_CLASSIFICATION_MACRO(1, ALG_IS_RSA_PKCS1V15_SIGN, alg, flags);
|
|
TEST_CLASSIFICATION_MACRO(1, ALG_IS_RSA_PSS, alg, flags);
|
|
TEST_CLASSIFICATION_MACRO(1, ALG_IS_RSA_PSS_ANY_SALT, alg, flags);
|
|
TEST_CLASSIFICATION_MACRO(1, ALG_IS_RSA_PSS_STANDARD_SALT, alg, flags);
|
|
TEST_CLASSIFICATION_MACRO(1, ALG_IS_DSA, alg, flags);
|
|
TEST_CLASSIFICATION_MACRO(PSA_ALG_IS_DSA(alg),
|
|
ALG_DSA_IS_DETERMINISTIC, alg, flags);
|
|
TEST_CLASSIFICATION_MACRO(1, ALG_IS_DETERMINISTIC_DSA, alg, flags);
|
|
TEST_CLASSIFICATION_MACRO(1, ALG_IS_RANDOMIZED_DSA, alg, flags);
|
|
TEST_CLASSIFICATION_MACRO(1, ALG_IS_ECDSA, alg, flags);
|
|
TEST_CLASSIFICATION_MACRO(PSA_ALG_IS_ECDSA(alg),
|
|
ALG_ECDSA_IS_DETERMINISTIC, alg, flags);
|
|
TEST_CLASSIFICATION_MACRO(1, ALG_IS_DETERMINISTIC_ECDSA, alg, flags);
|
|
TEST_CLASSIFICATION_MACRO(1, ALG_IS_RANDOMIZED_ECDSA, alg, flags);
|
|
TEST_CLASSIFICATION_MACRO(1, ALG_IS_HASH_EDDSA, alg, flags);
|
|
TEST_CLASSIFICATION_MACRO(1, ALG_IS_SIGN_HASH, alg, flags);
|
|
TEST_CLASSIFICATION_MACRO(1, ALG_IS_HASH_AND_SIGN, alg, flags);
|
|
TEST_CLASSIFICATION_MACRO(1, ALG_IS_RSA_OAEP, alg, flags);
|
|
TEST_CLASSIFICATION_MACRO(1, ALG_IS_HKDF, alg, flags);
|
|
TEST_CLASSIFICATION_MACRO(1, ALG_IS_HKDF_EXTRACT, alg, flags);
|
|
TEST_CLASSIFICATION_MACRO(1, ALG_IS_HKDF_EXPAND, alg, flags);
|
|
TEST_CLASSIFICATION_MACRO(1, ALG_IS_WILDCARD, alg, flags);
|
|
TEST_CLASSIFICATION_MACRO(1, ALG_IS_ECDH, alg, flags);
|
|
TEST_CLASSIFICATION_MACRO(1, ALG_IS_FFDH, alg, flags);
|
|
TEST_CLASSIFICATION_MACRO(1, ALG_IS_RAW_KEY_AGREEMENT, alg, flags);
|
|
TEST_CLASSIFICATION_MACRO(1, ALG_IS_AEAD_ON_BLOCK_CIPHER, alg, flags);
|
|
TEST_CLASSIFICATION_MACRO(1, ALG_IS_TLS12_PRF, alg, flags);
|
|
TEST_CLASSIFICATION_MACRO(1, ALG_IS_TLS12_PSK_TO_MS, alg, flags);
|
|
TEST_EQUAL(classification_flags_tested, ALG_FLAG_MASK_PLUS_ONE - 1);
|
|
exit:;
|
|
}
|
|
|
|
void key_type_classification(psa_key_type_t type, unsigned flags)
|
|
{
|
|
unsigned classification_flags_tested = 0;
|
|
|
|
/* Macros tested based on the test case parameter */
|
|
TEST_CLASSIFICATION_MACRO(1, KEY_TYPE_IS_VENDOR_DEFINED, type, flags);
|
|
TEST_CLASSIFICATION_MACRO(1, KEY_TYPE_IS_UNSTRUCTURED, type, flags);
|
|
TEST_CLASSIFICATION_MACRO(1, KEY_TYPE_IS_PUBLIC_KEY, type, flags);
|
|
TEST_CLASSIFICATION_MACRO(1, KEY_TYPE_IS_KEY_PAIR, type, flags);
|
|
TEST_CLASSIFICATION_MACRO(1, KEY_TYPE_IS_RSA, type, flags);
|
|
TEST_CLASSIFICATION_MACRO(1, KEY_TYPE_IS_DSA, type, flags);
|
|
TEST_CLASSIFICATION_MACRO(1, KEY_TYPE_IS_ECC, type, flags);
|
|
TEST_CLASSIFICATION_MACRO(1, KEY_TYPE_IS_DH, type, flags);
|
|
TEST_EQUAL(classification_flags_tested, KEY_TYPE_FLAG_MASK_PLUS_ONE - 1);
|
|
|
|
/* Macros with derived semantics */
|
|
TEST_EQUAL(PSA_KEY_TYPE_IS_ASYMMETRIC(type),
|
|
(PSA_KEY_TYPE_IS_PUBLIC_KEY(type) ||
|
|
PSA_KEY_TYPE_IS_KEY_PAIR(type)));
|
|
TEST_EQUAL(PSA_KEY_TYPE_IS_ECC_KEY_PAIR(type),
|
|
(PSA_KEY_TYPE_IS_ECC(type) &&
|
|
PSA_KEY_TYPE_IS_KEY_PAIR(type)));
|
|
TEST_EQUAL(PSA_KEY_TYPE_IS_ECC_PUBLIC_KEY(type),
|
|
(PSA_KEY_TYPE_IS_ECC(type) &&
|
|
PSA_KEY_TYPE_IS_PUBLIC_KEY(type)));
|
|
TEST_EQUAL(PSA_KEY_TYPE_IS_DH_KEY_PAIR(type),
|
|
(PSA_KEY_TYPE_IS_DH(type) &&
|
|
PSA_KEY_TYPE_IS_KEY_PAIR(type)));
|
|
TEST_EQUAL(PSA_KEY_TYPE_IS_DH_PUBLIC_KEY(type),
|
|
(PSA_KEY_TYPE_IS_DH(type) &&
|
|
PSA_KEY_TYPE_IS_PUBLIC_KEY(type)));
|
|
|
|
TEST_PARITY(type);
|
|
|
|
exit:;
|
|
}
|
|
|
|
void mac_algorithm_core(psa_algorithm_t alg, int classification_flags,
|
|
psa_key_type_t key_type, size_t key_bits,
|
|
size_t length)
|
|
{
|
|
/* Algorithm classification */
|
|
TEST_ASSERT(!PSA_ALG_IS_HASH(alg));
|
|
TEST_ASSERT(PSA_ALG_IS_MAC(alg));
|
|
TEST_ASSERT(!PSA_ALG_IS_CIPHER(alg));
|
|
TEST_ASSERT(!PSA_ALG_IS_AEAD(alg));
|
|
TEST_ASSERT(!PSA_ALG_IS_SIGN(alg));
|
|
TEST_ASSERT(!PSA_ALG_IS_ASYMMETRIC_ENCRYPTION(alg));
|
|
TEST_ASSERT(!PSA_ALG_IS_KEY_AGREEMENT(alg));
|
|
TEST_ASSERT(!PSA_ALG_IS_KEY_DERIVATION(alg));
|
|
TEST_ASSERT(!PSA_ALG_IS_PAKE(alg));
|
|
algorithm_classification(alg, classification_flags);
|
|
|
|
/* Length */
|
|
TEST_EQUAL(length, PSA_MAC_LENGTH(key_type, key_bits, alg));
|
|
|
|
#if defined(MBEDTLS_TEST_HOOKS) && defined(MBEDTLS_PSA_CRYPTO_C)
|
|
PSA_ASSERT(psa_mac_key_can_do(alg, key_type));
|
|
#endif
|
|
|
|
exit:;
|
|
}
|
|
|
|
void aead_algorithm_core(psa_algorithm_t alg, int classification_flags,
|
|
psa_key_type_t key_type, size_t key_bits,
|
|
size_t tag_length)
|
|
{
|
|
/* Algorithm classification */
|
|
TEST_ASSERT(!PSA_ALG_IS_HASH(alg));
|
|
TEST_ASSERT(!PSA_ALG_IS_MAC(alg));
|
|
TEST_ASSERT(!PSA_ALG_IS_CIPHER(alg));
|
|
TEST_ASSERT(PSA_ALG_IS_AEAD(alg));
|
|
TEST_ASSERT(!PSA_ALG_IS_SIGN(alg));
|
|
TEST_ASSERT(!PSA_ALG_IS_ASYMMETRIC_ENCRYPTION(alg));
|
|
TEST_ASSERT(!PSA_ALG_IS_KEY_AGREEMENT(alg));
|
|
TEST_ASSERT(!PSA_ALG_IS_KEY_DERIVATION(alg));
|
|
TEST_ASSERT(!PSA_ALG_IS_PAKE(alg));
|
|
algorithm_classification(alg, classification_flags);
|
|
|
|
/* Tag length */
|
|
TEST_EQUAL(tag_length, PSA_AEAD_TAG_LENGTH(key_type, key_bits, alg));
|
|
|
|
exit:;
|
|
}
|
|
|
|
/* END_HEADER */
|
|
|
|
/* BEGIN_DEPENDENCIES
|
|
* depends_on:MBEDTLS_PSA_CRYPTO_CLIENT
|
|
* END_DEPENDENCIES
|
|
*/
|
|
|
|
/* BEGIN_CASE */
|
|
void hash_algorithm(int alg_arg, int length_arg)
|
|
{
|
|
psa_algorithm_t alg = alg_arg;
|
|
size_t length = length_arg;
|
|
psa_algorithm_t hmac_alg = PSA_ALG_HMAC(alg);
|
|
psa_algorithm_t rsa_pkcs1v15_sign_alg = PSA_ALG_RSA_PKCS1V15_SIGN(alg);
|
|
psa_algorithm_t rsa_pss_alg = PSA_ALG_RSA_PSS(alg);
|
|
psa_algorithm_t dsa_alg = PSA_ALG_DSA(alg);
|
|
psa_algorithm_t deterministic_dsa_alg = PSA_ALG_DETERMINISTIC_DSA(alg);
|
|
psa_algorithm_t ecdsa_alg = PSA_ALG_ECDSA(alg);
|
|
psa_algorithm_t deterministic_ecdsa_alg = PSA_ALG_DETERMINISTIC_ECDSA(alg);
|
|
psa_algorithm_t rsa_oaep_alg = PSA_ALG_RSA_OAEP(alg);
|
|
psa_algorithm_t hkdf_alg = PSA_ALG_HKDF(alg);
|
|
|
|
/* Algorithm classification */
|
|
TEST_ASSERT(PSA_ALG_IS_HASH(alg));
|
|
TEST_ASSERT(!PSA_ALG_IS_MAC(alg));
|
|
TEST_ASSERT(!PSA_ALG_IS_CIPHER(alg));
|
|
TEST_ASSERT(!PSA_ALG_IS_AEAD(alg));
|
|
TEST_ASSERT(!PSA_ALG_IS_SIGN(alg));
|
|
TEST_ASSERT(!PSA_ALG_IS_ASYMMETRIC_ENCRYPTION(alg));
|
|
TEST_ASSERT(!PSA_ALG_IS_KEY_AGREEMENT(alg));
|
|
TEST_ASSERT(!PSA_ALG_IS_KEY_DERIVATION(alg));
|
|
TEST_ASSERT(!PSA_ALG_IS_PAKE(alg));
|
|
algorithm_classification(alg, 0);
|
|
|
|
/* Dependent algorithms */
|
|
TEST_EQUAL(PSA_ALG_HMAC_GET_HASH(hmac_alg), alg);
|
|
TEST_EQUAL(PSA_ALG_SIGN_GET_HASH(rsa_pkcs1v15_sign_alg), alg);
|
|
TEST_EQUAL(PSA_ALG_SIGN_GET_HASH(rsa_pss_alg), alg);
|
|
TEST_EQUAL(PSA_ALG_SIGN_GET_HASH(dsa_alg), alg);
|
|
TEST_EQUAL(PSA_ALG_SIGN_GET_HASH(deterministic_dsa_alg), alg);
|
|
TEST_EQUAL(PSA_ALG_SIGN_GET_HASH(ecdsa_alg), alg);
|
|
TEST_EQUAL(PSA_ALG_SIGN_GET_HASH(deterministic_ecdsa_alg), alg);
|
|
TEST_EQUAL(PSA_ALG_RSA_OAEP_GET_HASH(rsa_oaep_alg), alg);
|
|
TEST_EQUAL(PSA_ALG_HKDF_GET_HASH(hkdf_alg), alg);
|
|
|
|
/* Hash length */
|
|
TEST_EQUAL(length, PSA_HASH_LENGTH(alg));
|
|
TEST_ASSERT(length <= PSA_HASH_MAX_SIZE);
|
|
}
|
|
/* END_CASE */
|
|
|
|
/* BEGIN_CASE */
|
|
void mac_algorithm(int alg_arg, int classification_flags,
|
|
int length_arg,
|
|
int key_type_arg, int key_bits_arg)
|
|
{
|
|
psa_algorithm_t alg = alg_arg;
|
|
size_t length = length_arg;
|
|
size_t n;
|
|
size_t key_type = key_type_arg;
|
|
size_t key_bits = key_bits_arg;
|
|
|
|
mac_algorithm_core(alg, classification_flags,
|
|
key_type, key_bits, length);
|
|
TEST_EQUAL(PSA_ALG_FULL_LENGTH_MAC(alg), alg);
|
|
TEST_ASSERT(length <= PSA_MAC_MAX_SIZE);
|
|
|
|
/* Truncated versions */
|
|
for (n = 1; n <= length; n++) {
|
|
psa_algorithm_t truncated_alg = PSA_ALG_TRUNCATED_MAC(alg, n);
|
|
mac_algorithm_core(truncated_alg, classification_flags,
|
|
key_type, key_bits, n);
|
|
TEST_EQUAL(PSA_ALG_FULL_LENGTH_MAC(truncated_alg), alg);
|
|
/* Check that calling PSA_ALG_TRUNCATED_MAC twice gives the length
|
|
* of the outer truncation (even if the outer length is smaller than
|
|
* the inner length). */
|
|
TEST_EQUAL(PSA_ALG_TRUNCATED_MAC(truncated_alg, 1),
|
|
PSA_ALG_TRUNCATED_MAC(alg, 1));
|
|
TEST_EQUAL(PSA_ALG_TRUNCATED_MAC(truncated_alg, length - 1),
|
|
PSA_ALG_TRUNCATED_MAC(alg, length - 1));
|
|
TEST_EQUAL(PSA_ALG_TRUNCATED_MAC(truncated_alg, length),
|
|
PSA_ALG_TRUNCATED_MAC(alg, length));
|
|
|
|
/* Check that calling PSA_ALG_TRUNCATED_MAC on an algorithm
|
|
* earlier constructed with PSA_ALG_AT_LEAST_THIS_LENGTH_MAC gives the
|
|
* length of the outer truncation (even if the outer length is smaller
|
|
* than the inner length). */
|
|
TEST_EQUAL(PSA_ALG_TRUNCATED_MAC(
|
|
PSA_ALG_AT_LEAST_THIS_LENGTH_MAC(truncated_alg, n), 1),
|
|
PSA_ALG_TRUNCATED_MAC(alg, 1));
|
|
TEST_EQUAL(PSA_ALG_TRUNCATED_MAC(
|
|
PSA_ALG_AT_LEAST_THIS_LENGTH_MAC(truncated_alg, n), length - 1),
|
|
PSA_ALG_TRUNCATED_MAC(alg, length - 1));
|
|
TEST_EQUAL(PSA_ALG_TRUNCATED_MAC(
|
|
PSA_ALG_AT_LEAST_THIS_LENGTH_MAC(truncated_alg, n), length),
|
|
PSA_ALG_TRUNCATED_MAC(alg, length));
|
|
}
|
|
|
|
/* At-leat-this-length versions */
|
|
for (n = 1; n <= length; n++) {
|
|
psa_algorithm_t policy_alg = PSA_ALG_AT_LEAST_THIS_LENGTH_MAC(alg, n);
|
|
mac_algorithm_core(policy_alg, classification_flags | ALG_IS_WILDCARD,
|
|
key_type, key_bits, n);
|
|
TEST_EQUAL(PSA_ALG_FULL_LENGTH_MAC(policy_alg), alg);
|
|
/* Check that calling PSA_ALG_AT_LEAST_THIS_LENGTH_MAC twice gives the
|
|
* length of the outer truncation (even if the outer length is smaller
|
|
* than the inner length). */
|
|
TEST_EQUAL(PSA_ALG_AT_LEAST_THIS_LENGTH_MAC(policy_alg, 1),
|
|
PSA_ALG_AT_LEAST_THIS_LENGTH_MAC(alg, 1));
|
|
TEST_EQUAL(PSA_ALG_AT_LEAST_THIS_LENGTH_MAC(policy_alg, length - 1),
|
|
PSA_ALG_AT_LEAST_THIS_LENGTH_MAC(alg, length - 1));
|
|
TEST_EQUAL(PSA_ALG_AT_LEAST_THIS_LENGTH_MAC(policy_alg, length),
|
|
PSA_ALG_AT_LEAST_THIS_LENGTH_MAC(alg, length));
|
|
|
|
/* Check that calling PSA_ALG_AT_LEAST_THIS_LENGTH_MAC on an algorithm
|
|
* earlier constructed with PSA_ALG_TRUNCATED_MAC gives the length of
|
|
* the outer truncation (even if the outer length is smaller than the
|
|
* inner length). */
|
|
TEST_EQUAL(PSA_ALG_AT_LEAST_THIS_LENGTH_MAC(
|
|
PSA_ALG_TRUNCATED_MAC(policy_alg, n), 1),
|
|
PSA_ALG_AT_LEAST_THIS_LENGTH_MAC(alg, 1));
|
|
TEST_EQUAL(PSA_ALG_AT_LEAST_THIS_LENGTH_MAC(
|
|
PSA_ALG_TRUNCATED_MAC(policy_alg, n), length - 1),
|
|
PSA_ALG_AT_LEAST_THIS_LENGTH_MAC(alg, length - 1));
|
|
TEST_EQUAL(PSA_ALG_AT_LEAST_THIS_LENGTH_MAC(
|
|
PSA_ALG_TRUNCATED_MAC(policy_alg, n), length),
|
|
PSA_ALG_AT_LEAST_THIS_LENGTH_MAC(alg, length));
|
|
}
|
|
}
|
|
/* END_CASE */
|
|
|
|
/* BEGIN_CASE */
|
|
void hmac_algorithm(int alg_arg,
|
|
int length_arg,
|
|
int block_size_arg)
|
|
{
|
|
psa_algorithm_t alg = alg_arg;
|
|
psa_algorithm_t hash_alg = PSA_ALG_HMAC_GET_HASH(alg);
|
|
size_t block_size = block_size_arg;
|
|
size_t length = length_arg;
|
|
size_t n;
|
|
|
|
TEST_ASSERT(PSA_ALG_IS_HASH(hash_alg));
|
|
TEST_EQUAL(PSA_ALG_HMAC(hash_alg), alg);
|
|
|
|
TEST_ASSERT(block_size == PSA_HASH_BLOCK_LENGTH(alg));
|
|
TEST_ASSERT(block_size <= PSA_HMAC_MAX_HASH_BLOCK_SIZE);
|
|
|
|
test_mac_algorithm(alg_arg, ALG_IS_HMAC, length,
|
|
PSA_KEY_TYPE_HMAC, PSA_BYTES_TO_BITS(length));
|
|
|
|
for (n = 1; n <= length; n++) {
|
|
psa_algorithm_t truncated_alg = PSA_ALG_TRUNCATED_MAC(alg, n);
|
|
TEST_EQUAL(PSA_ALG_HMAC_GET_HASH(truncated_alg), hash_alg);
|
|
}
|
|
}
|
|
/* END_CASE */
|
|
|
|
/* BEGIN_CASE */
|
|
void cipher_algorithm(int alg_arg, int classification_flags)
|
|
{
|
|
psa_algorithm_t alg = alg_arg;
|
|
|
|
/* Algorithm classification */
|
|
TEST_ASSERT(!PSA_ALG_IS_HASH(alg));
|
|
TEST_ASSERT(!PSA_ALG_IS_MAC(alg));
|
|
TEST_ASSERT(PSA_ALG_IS_CIPHER(alg));
|
|
TEST_ASSERT(!PSA_ALG_IS_AEAD(alg));
|
|
TEST_ASSERT(!PSA_ALG_IS_SIGN(alg));
|
|
TEST_ASSERT(!PSA_ALG_IS_ASYMMETRIC_ENCRYPTION(alg));
|
|
TEST_ASSERT(!PSA_ALG_IS_KEY_AGREEMENT(alg));
|
|
TEST_ASSERT(!PSA_ALG_IS_KEY_DERIVATION(alg));
|
|
TEST_ASSERT(!PSA_ALG_IS_PAKE(alg));
|
|
algorithm_classification(alg, classification_flags);
|
|
}
|
|
/* END_CASE */
|
|
|
|
/* BEGIN_CASE */
|
|
void aead_algorithm(int alg_arg, int classification_flags,
|
|
int tag_length_arg,
|
|
int key_type_arg, int key_bits_arg)
|
|
{
|
|
psa_algorithm_t alg = alg_arg;
|
|
size_t tag_length = tag_length_arg;
|
|
size_t n;
|
|
psa_key_type_t key_type = key_type_arg;
|
|
size_t key_bits = key_bits_arg;
|
|
|
|
aead_algorithm_core(alg, classification_flags,
|
|
key_type, key_bits, tag_length);
|
|
|
|
/* Truncated versions */
|
|
for (n = 1; n <= tag_length; n++) {
|
|
psa_algorithm_t truncated_alg = PSA_ALG_AEAD_WITH_SHORTENED_TAG(alg, n);
|
|
aead_algorithm_core(truncated_alg, classification_flags,
|
|
key_type, key_bits, n);
|
|
TEST_EQUAL(PSA_ALG_AEAD_WITH_DEFAULT_LENGTH_TAG(truncated_alg),
|
|
alg);
|
|
/* Check that calling PSA_ALG_AEAD_WITH_SHORTENED_TAG twice gives
|
|
* the length of the outer truncation (even if the outer length is
|
|
* smaller than the inner length). */
|
|
TEST_EQUAL(PSA_ALG_AEAD_WITH_SHORTENED_TAG(truncated_alg, 1),
|
|
PSA_ALG_AEAD_WITH_SHORTENED_TAG(alg, 1));
|
|
TEST_EQUAL(PSA_ALG_AEAD_WITH_SHORTENED_TAG(truncated_alg, tag_length - 1),
|
|
PSA_ALG_AEAD_WITH_SHORTENED_TAG(alg, tag_length - 1));
|
|
TEST_EQUAL(PSA_ALG_AEAD_WITH_SHORTENED_TAG(truncated_alg, tag_length),
|
|
PSA_ALG_AEAD_WITH_SHORTENED_TAG(alg, tag_length));
|
|
|
|
/* Check that calling PSA_ALG_AEAD_WITH_SHORTENED_TAG on an algorithm
|
|
* earlier constructed with PSA_ALG_AEAD_WITH_AT_LEAST_THIS_LENGTH_TAG
|
|
* gives the length of the outer truncation (even if the outer length is
|
|
* smaller than the inner length). */
|
|
TEST_EQUAL(PSA_ALG_AEAD_WITH_SHORTENED_TAG(
|
|
PSA_ALG_AEAD_WITH_AT_LEAST_THIS_LENGTH_TAG(truncated_alg, n), 1),
|
|
PSA_ALG_AEAD_WITH_SHORTENED_TAG(alg, 1));
|
|
TEST_EQUAL(PSA_ALG_AEAD_WITH_SHORTENED_TAG(
|
|
PSA_ALG_AEAD_WITH_AT_LEAST_THIS_LENGTH_TAG(truncated_alg,
|
|
n), tag_length - 1),
|
|
PSA_ALG_AEAD_WITH_SHORTENED_TAG(alg, tag_length - 1));
|
|
TEST_EQUAL(PSA_ALG_AEAD_WITH_SHORTENED_TAG(
|
|
PSA_ALG_AEAD_WITH_AT_LEAST_THIS_LENGTH_TAG(truncated_alg, n), tag_length),
|
|
PSA_ALG_AEAD_WITH_SHORTENED_TAG(alg, tag_length));
|
|
}
|
|
|
|
/* At-leat-this-length versions */
|
|
for (n = 1; n <= tag_length; n++) {
|
|
psa_algorithm_t policy_alg = PSA_ALG_AEAD_WITH_AT_LEAST_THIS_LENGTH_TAG(alg, n);
|
|
aead_algorithm_core(policy_alg, classification_flags | ALG_IS_WILDCARD,
|
|
key_type, key_bits, n);
|
|
TEST_EQUAL(PSA_ALG_AEAD_WITH_DEFAULT_LENGTH_TAG(policy_alg),
|
|
alg);
|
|
/* Check that calling PSA_ALG_AEAD_WITH_AT_LEAST_THIS_LENGTH_TAG twice
|
|
* gives the length of the outer truncation (even if the outer length is
|
|
* smaller than the inner length). */
|
|
TEST_EQUAL(PSA_ALG_AEAD_WITH_AT_LEAST_THIS_LENGTH_TAG(policy_alg, 1),
|
|
PSA_ALG_AEAD_WITH_AT_LEAST_THIS_LENGTH_TAG(alg, 1));
|
|
TEST_EQUAL(PSA_ALG_AEAD_WITH_AT_LEAST_THIS_LENGTH_TAG(policy_alg, tag_length - 1),
|
|
PSA_ALG_AEAD_WITH_AT_LEAST_THIS_LENGTH_TAG(alg, tag_length - 1));
|
|
TEST_EQUAL(PSA_ALG_AEAD_WITH_AT_LEAST_THIS_LENGTH_TAG(policy_alg, tag_length),
|
|
PSA_ALG_AEAD_WITH_AT_LEAST_THIS_LENGTH_TAG(alg, tag_length));
|
|
|
|
/* Check that calling PSA_ALG_AEAD_WITH_AT_LEAST_THIS_LENGTH_TAG on an
|
|
* algorithm earlier constructed with PSA_ALG_AEAD_WITH_SHORTENED_TAG
|
|
* gives the length of the outer truncation (even if the outer length is
|
|
* smaller than the inner length). */
|
|
TEST_EQUAL(PSA_ALG_AEAD_WITH_AT_LEAST_THIS_LENGTH_TAG(
|
|
PSA_ALG_AEAD_WITH_SHORTENED_TAG(policy_alg, n), 1),
|
|
PSA_ALG_AEAD_WITH_AT_LEAST_THIS_LENGTH_TAG(alg, 1));
|
|
TEST_EQUAL(PSA_ALG_AEAD_WITH_AT_LEAST_THIS_LENGTH_TAG(
|
|
PSA_ALG_AEAD_WITH_SHORTENED_TAG(policy_alg, n), tag_length - 1),
|
|
PSA_ALG_AEAD_WITH_AT_LEAST_THIS_LENGTH_TAG(alg, tag_length - 1));
|
|
TEST_EQUAL(PSA_ALG_AEAD_WITH_AT_LEAST_THIS_LENGTH_TAG(
|
|
PSA_ALG_AEAD_WITH_SHORTENED_TAG(policy_alg, n), tag_length),
|
|
PSA_ALG_AEAD_WITH_AT_LEAST_THIS_LENGTH_TAG(alg, tag_length));
|
|
}
|
|
}
|
|
/* END_CASE */
|
|
|
|
/* BEGIN_CASE */
|
|
void asymmetric_signature_algorithm(int alg_arg, int classification_flags)
|
|
{
|
|
psa_algorithm_t alg = alg_arg;
|
|
|
|
/* Algorithm classification */
|
|
TEST_ASSERT(!PSA_ALG_IS_HASH(alg));
|
|
TEST_ASSERT(!PSA_ALG_IS_MAC(alg));
|
|
TEST_ASSERT(!PSA_ALG_IS_CIPHER(alg));
|
|
TEST_ASSERT(!PSA_ALG_IS_AEAD(alg));
|
|
TEST_ASSERT(PSA_ALG_IS_SIGN(alg));
|
|
TEST_ASSERT(!PSA_ALG_IS_ASYMMETRIC_ENCRYPTION(alg));
|
|
TEST_ASSERT(!PSA_ALG_IS_KEY_AGREEMENT(alg));
|
|
TEST_ASSERT(!PSA_ALG_IS_KEY_DERIVATION(alg));
|
|
TEST_ASSERT(!PSA_ALG_IS_PAKE(alg));
|
|
algorithm_classification(alg, classification_flags);
|
|
}
|
|
/* END_CASE */
|
|
|
|
/* BEGIN_CASE */
|
|
void asymmetric_signature_wildcard(int alg_arg, int classification_flags)
|
|
{
|
|
classification_flags |= ALG_IS_WILDCARD;
|
|
classification_flags |= ALG_IS_SIGN_HASH;
|
|
classification_flags |= ALG_IS_HASH_AND_SIGN;
|
|
test_asymmetric_signature_algorithm(alg_arg, classification_flags);
|
|
/* Any failure of this test function comes from
|
|
* asymmetric_signature_algorithm. Pacify -Werror=unused-label. */
|
|
goto exit;
|
|
}
|
|
/* END_CASE */
|
|
|
|
/* BEGIN_CASE */
|
|
void asymmetric_encryption_algorithm(int alg_arg, int classification_flags)
|
|
{
|
|
psa_algorithm_t alg = alg_arg;
|
|
|
|
/* Algorithm classification */
|
|
TEST_ASSERT(!PSA_ALG_IS_HASH(alg));
|
|
TEST_ASSERT(!PSA_ALG_IS_MAC(alg));
|
|
TEST_ASSERT(!PSA_ALG_IS_CIPHER(alg));
|
|
TEST_ASSERT(!PSA_ALG_IS_AEAD(alg));
|
|
TEST_ASSERT(!PSA_ALG_IS_SIGN(alg));
|
|
TEST_ASSERT(PSA_ALG_IS_ASYMMETRIC_ENCRYPTION(alg));
|
|
TEST_ASSERT(!PSA_ALG_IS_KEY_AGREEMENT(alg));
|
|
TEST_ASSERT(!PSA_ALG_IS_KEY_DERIVATION(alg));
|
|
TEST_ASSERT(!PSA_ALG_IS_PAKE(alg));
|
|
algorithm_classification(alg, classification_flags);
|
|
}
|
|
/* END_CASE */
|
|
|
|
/* BEGIN_CASE */
|
|
void key_derivation_algorithm(int alg_arg, int classification_flags)
|
|
{
|
|
psa_algorithm_t alg = alg_arg;
|
|
psa_algorithm_t ecdh_alg = PSA_ALG_KEY_AGREEMENT(PSA_ALG_ECDH, alg);
|
|
psa_algorithm_t ffdh_alg = PSA_ALG_KEY_AGREEMENT(PSA_ALG_FFDH, alg);
|
|
|
|
/* Algorithm classification */
|
|
TEST_ASSERT(!PSA_ALG_IS_HASH(alg));
|
|
TEST_ASSERT(!PSA_ALG_IS_MAC(alg));
|
|
TEST_ASSERT(!PSA_ALG_IS_CIPHER(alg));
|
|
TEST_ASSERT(!PSA_ALG_IS_AEAD(alg));
|
|
TEST_ASSERT(!PSA_ALG_IS_SIGN(alg));
|
|
TEST_ASSERT(!PSA_ALG_IS_ASYMMETRIC_ENCRYPTION(alg));
|
|
TEST_ASSERT(!PSA_ALG_IS_KEY_AGREEMENT(alg));
|
|
TEST_ASSERT(PSA_ALG_IS_KEY_DERIVATION(alg));
|
|
TEST_ASSERT(!PSA_ALG_IS_PAKE(alg));
|
|
algorithm_classification(alg, classification_flags);
|
|
|
|
/* Check combinations with key agreements */
|
|
TEST_ASSERT(PSA_ALG_IS_KEY_AGREEMENT(ecdh_alg));
|
|
TEST_ASSERT(PSA_ALG_IS_KEY_AGREEMENT(ffdh_alg));
|
|
TEST_EQUAL(PSA_ALG_KEY_AGREEMENT_GET_KDF(ecdh_alg), alg);
|
|
TEST_EQUAL(PSA_ALG_KEY_AGREEMENT_GET_KDF(ffdh_alg), alg);
|
|
}
|
|
/* END_CASE */
|
|
|
|
/* BEGIN_CASE */
|
|
void key_agreement_algorithm(int alg_arg, int classification_flags,
|
|
int ka_alg_arg, int kdf_alg_arg)
|
|
{
|
|
psa_algorithm_t alg = alg_arg;
|
|
psa_algorithm_t actual_ka_alg = PSA_ALG_KEY_AGREEMENT_GET_BASE(alg);
|
|
psa_algorithm_t expected_ka_alg = ka_alg_arg;
|
|
psa_algorithm_t actual_kdf_alg = PSA_ALG_KEY_AGREEMENT_GET_KDF(alg);
|
|
psa_algorithm_t expected_kdf_alg = kdf_alg_arg;
|
|
|
|
/* Algorithm classification */
|
|
TEST_ASSERT(!PSA_ALG_IS_HASH(alg));
|
|
TEST_ASSERT(!PSA_ALG_IS_MAC(alg));
|
|
TEST_ASSERT(!PSA_ALG_IS_CIPHER(alg));
|
|
TEST_ASSERT(!PSA_ALG_IS_AEAD(alg));
|
|
TEST_ASSERT(!PSA_ALG_IS_SIGN(alg));
|
|
TEST_ASSERT(!PSA_ALG_IS_ASYMMETRIC_ENCRYPTION(alg));
|
|
TEST_ASSERT(PSA_ALG_IS_KEY_AGREEMENT(alg));
|
|
TEST_ASSERT(!PSA_ALG_IS_KEY_DERIVATION(alg));
|
|
TEST_ASSERT(!PSA_ALG_IS_PAKE(alg));
|
|
algorithm_classification(alg, classification_flags);
|
|
|
|
/* Shared secret derivation properties */
|
|
TEST_EQUAL(actual_ka_alg, expected_ka_alg);
|
|
TEST_EQUAL(actual_kdf_alg, expected_kdf_alg);
|
|
}
|
|
/* END_CASE */
|
|
|
|
/* BEGIN_CASE */
|
|
void pake_algorithm(int alg_arg)
|
|
{
|
|
psa_algorithm_t alg = alg_arg;
|
|
|
|
/* Algorithm classification */
|
|
TEST_ASSERT(!PSA_ALG_IS_HASH(alg));
|
|
TEST_ASSERT(!PSA_ALG_IS_MAC(alg));
|
|
TEST_ASSERT(!PSA_ALG_IS_CIPHER(alg));
|
|
TEST_ASSERT(!PSA_ALG_IS_AEAD(alg));
|
|
TEST_ASSERT(!PSA_ALG_IS_SIGN(alg));
|
|
TEST_ASSERT(!PSA_ALG_IS_ASYMMETRIC_ENCRYPTION(alg));
|
|
TEST_ASSERT(!PSA_ALG_IS_KEY_AGREEMENT(alg));
|
|
TEST_ASSERT(!PSA_ALG_IS_KEY_DERIVATION(alg));
|
|
TEST_ASSERT(PSA_ALG_IS_PAKE(alg));
|
|
}
|
|
|
|
/* END_CASE */
|
|
/* BEGIN_CASE */
|
|
void key_type(int type_arg, int classification_flags)
|
|
{
|
|
psa_key_type_t type = type_arg;
|
|
|
|
key_type_classification(type, classification_flags);
|
|
|
|
/* For asymmetric types, check the corresponding pair/public type */
|
|
if (classification_flags & KEY_TYPE_IS_PUBLIC_KEY) {
|
|
psa_key_type_t pair_type = PSA_KEY_TYPE_KEY_PAIR_OF_PUBLIC_KEY(type);
|
|
TEST_EQUAL(PSA_KEY_TYPE_PUBLIC_KEY_OF_KEY_PAIR(pair_type), type);
|
|
key_type_classification(pair_type,
|
|
(classification_flags
|
|
& ~KEY_TYPE_IS_PUBLIC_KEY)
|
|
| KEY_TYPE_IS_KEY_PAIR);
|
|
TEST_EQUAL(PSA_KEY_TYPE_PUBLIC_KEY_OF_KEY_PAIR(type), type);
|
|
}
|
|
if (classification_flags & KEY_TYPE_IS_KEY_PAIR) {
|
|
psa_key_type_t public_type = PSA_KEY_TYPE_PUBLIC_KEY_OF_KEY_PAIR(type);
|
|
TEST_EQUAL(PSA_KEY_TYPE_KEY_PAIR_OF_PUBLIC_KEY(public_type), type);
|
|
key_type_classification(public_type,
|
|
(classification_flags
|
|
& ~KEY_TYPE_IS_KEY_PAIR)
|
|
| KEY_TYPE_IS_PUBLIC_KEY);
|
|
TEST_EQUAL(PSA_KEY_TYPE_KEY_PAIR_OF_PUBLIC_KEY(type), type);
|
|
}
|
|
}
|
|
/* END_CASE */
|
|
|
|
/* BEGIN_CASE */
|
|
void block_cipher_key_type(int type_arg, int block_size_arg)
|
|
{
|
|
psa_key_type_t type = type_arg;
|
|
size_t block_size = block_size_arg;
|
|
|
|
test_key_type(type_arg, KEY_TYPE_IS_UNSTRUCTURED);
|
|
|
|
TEST_EQUAL(type & PSA_KEY_TYPE_CATEGORY_MASK,
|
|
PSA_KEY_TYPE_CATEGORY_SYMMETRIC);
|
|
TEST_EQUAL(PSA_BLOCK_CIPHER_BLOCK_LENGTH(type), block_size);
|
|
|
|
/* Check that the block size is a power of 2. This is required, at least,
|
|
for PSA_ROUND_UP_TO_MULTIPLE(block_size, length) in crypto_sizes.h. */
|
|
TEST_ASSERT(((block_size - 1) & block_size) == 0);
|
|
}
|
|
/* END_CASE */
|
|
|
|
/* BEGIN_CASE */
|
|
void stream_cipher_key_type(int type_arg)
|
|
{
|
|
psa_key_type_t type = type_arg;
|
|
|
|
test_key_type(type_arg, KEY_TYPE_IS_UNSTRUCTURED);
|
|
|
|
TEST_EQUAL(type & PSA_KEY_TYPE_CATEGORY_MASK,
|
|
PSA_KEY_TYPE_CATEGORY_SYMMETRIC);
|
|
TEST_EQUAL(PSA_BLOCK_CIPHER_BLOCK_LENGTH(type), 1);
|
|
}
|
|
/* END_CASE */
|
|
|
|
/* BEGIN_CASE depends_on:PSA_KEY_TYPE_ECC_PUBLIC_KEY:PSA_KEY_TYPE_ECC_KEY_PAIR */
|
|
void ecc_key_family(int curve_arg)
|
|
{
|
|
psa_ecc_family_t curve = curve_arg;
|
|
psa_key_type_t public_type = PSA_KEY_TYPE_ECC_PUBLIC_KEY(curve);
|
|
psa_key_type_t pair_type = PSA_KEY_TYPE_ECC_KEY_PAIR(curve);
|
|
|
|
TEST_PARITY(curve);
|
|
|
|
test_key_type(public_type, KEY_TYPE_IS_ECC | KEY_TYPE_IS_PUBLIC_KEY);
|
|
test_key_type(pair_type, KEY_TYPE_IS_ECC | KEY_TYPE_IS_KEY_PAIR);
|
|
|
|
TEST_EQUAL(PSA_KEY_TYPE_ECC_GET_FAMILY(public_type), curve);
|
|
TEST_EQUAL(PSA_KEY_TYPE_ECC_GET_FAMILY(pair_type), curve);
|
|
}
|
|
/* END_CASE */
|
|
|
|
/* BEGIN_CASE depends_on:MBEDTLS_DHM_C */
|
|
void dh_key_family(int group_arg)
|
|
{
|
|
psa_dh_family_t group = group_arg;
|
|
psa_key_type_t public_type = PSA_KEY_TYPE_DH_PUBLIC_KEY(group);
|
|
psa_key_type_t pair_type = PSA_KEY_TYPE_DH_KEY_PAIR(group);
|
|
|
|
TEST_PARITY(group);
|
|
|
|
test_key_type(public_type, KEY_TYPE_IS_DH | KEY_TYPE_IS_PUBLIC_KEY);
|
|
test_key_type(pair_type, KEY_TYPE_IS_DH | KEY_TYPE_IS_KEY_PAIR);
|
|
|
|
TEST_EQUAL(PSA_KEY_TYPE_DH_GET_FAMILY(public_type), group);
|
|
TEST_EQUAL(PSA_KEY_TYPE_DH_GET_FAMILY(pair_type), group);
|
|
}
|
|
/* END_CASE */
|
|
|
|
/* BEGIN_CASE */
|
|
void lifetime(int lifetime_arg, int classification_flags,
|
|
int persistence_arg, int location_arg)
|
|
{
|
|
psa_key_lifetime_t lifetime = lifetime_arg;
|
|
psa_key_persistence_t persistence = persistence_arg;
|
|
psa_key_location_t location = location_arg;
|
|
unsigned flags = classification_flags;
|
|
unsigned classification_flags_tested = 0;
|
|
|
|
TEST_CLASSIFICATION_MACRO(1, KEY_LIFETIME_IS_VOLATILE, lifetime, flags);
|
|
TEST_CLASSIFICATION_MACRO(1, KEY_LIFETIME_IS_READ_ONLY, lifetime, flags);
|
|
TEST_EQUAL(classification_flags_tested,
|
|
KEY_LIFETIME_FLAG_MASK_PLUS_ONE - 1);
|
|
|
|
TEST_EQUAL(PSA_KEY_LIFETIME_GET_PERSISTENCE(lifetime), persistence);
|
|
TEST_EQUAL(PSA_KEY_LIFETIME_GET_LOCATION(lifetime), location);
|
|
}
|
|
/* END_CASE */
|