diff --git a/ChangeLog.d/crypto_config_ccm_star.txt b/ChangeLog.d/crypto_config_ccm_star.txt new file mode 100644 index 000000000..947014ae3 --- /dev/null +++ b/ChangeLog.d/crypto_config_ccm_star.txt @@ -0,0 +1,3 @@ +Bugfix + * List PSA_WANT_ALG_CCM_STAR_NO_TAG in psa/crypto_config.h so that it can + be toggled with config.py. diff --git a/ChangeLog.d/psa_alg_tls12_ecjpake_to_pms-reject_ka.txt b/ChangeLog.d/psa_alg_tls12_ecjpake_to_pms-reject_ka.txt new file mode 100644 index 000000000..cfea66136 --- /dev/null +++ b/ChangeLog.d/psa_alg_tls12_ecjpake_to_pms-reject_ka.txt @@ -0,0 +1,4 @@ +Bugfix + * The key derivation algorithm PSA_ALG_TLS12_ECJPAKE_TO_PMS cannot be + used on a shared secret from a key agreement since its input must be + an ECC public key. Reject this properly. diff --git a/include/mbedtls/config_psa.h b/include/mbedtls/config_psa.h index 09bc32c73..48b2d3209 100644 --- a/include/mbedtls/config_psa.h +++ b/include/mbedtls/config_psa.h @@ -843,6 +843,8 @@ extern "C" { /* These features are always enabled. */ #define PSA_WANT_KEY_TYPE_DERIVE 1 +#define PSA_WANT_KEY_TYPE_PASSWORD 1 +#define PSA_WANT_KEY_TYPE_PASSWORD_HASH 1 #define PSA_WANT_KEY_TYPE_RAW_DATA 1 #ifdef __cplusplus diff --git a/include/psa/crypto_config.h b/include/psa/crypto_config.h index 5ab4fdef3..e68fac8b4 100644 --- a/include/psa/crypto_config.h +++ b/include/psa/crypto_config.h @@ -57,6 +57,7 @@ #define PSA_WANT_ALG_CBC_NO_PADDING 1 #define PSA_WANT_ALG_CBC_PKCS7 1 #define PSA_WANT_ALG_CCM 1 +#define PSA_WANT_ALG_CCM_STAR_NO_TAG 1 #define PSA_WANT_ALG_CMAC 1 #define PSA_WANT_ALG_CFB 1 #define PSA_WANT_ALG_CHACHA20_POLY1305 1 @@ -115,6 +116,8 @@ #define PSA_WANT_ECC_SECP_R1_521 1 #define PSA_WANT_KEY_TYPE_DERIVE 1 +#define PSA_WANT_KEY_TYPE_PASSWORD 1 +#define PSA_WANT_KEY_TYPE_PASSWORD_HASH 1 #define PSA_WANT_KEY_TYPE_HMAC 1 #define PSA_WANT_KEY_TYPE_AES 1 #define PSA_WANT_KEY_TYPE_ARIA 1 diff --git a/library/psa_crypto.c b/library/psa_crypto.c index 0a8949fda..a683fdb8f 100644 --- a/library/psa_crypto.c +++ b/library/psa_crypto.c @@ -5168,6 +5168,18 @@ static psa_status_t psa_key_agreement_try_support(psa_algorithm_t alg) (void) alg; return PSA_ERROR_NOT_SUPPORTED; } + +static int psa_key_derivation_allows_free_form_secret_input( + psa_algorithm_t kdf_alg) +{ +#if defined(PSA_WANT_ALG_TLS12_ECJPAKE_TO_PMS) + if (kdf_alg == PSA_ALG_TLS12_ECJPAKE_TO_PMS) { + return 0; + } +#endif + (void) kdf_alg; + return 1; +} #endif /* AT_LEAST_ONE_BUILTIN_KDF */ psa_status_t psa_key_derivation_setup(psa_key_derivation_operation_t *operation, @@ -5189,6 +5201,9 @@ psa_status_t psa_key_derivation_setup(psa_key_derivation_operation_t *operation, if (status != PSA_SUCCESS) { return status; } + if (!psa_key_derivation_allows_free_form_secret_input(kdf_alg)) { + return PSA_ERROR_INVALID_ARGUMENT; + } status = psa_key_derivation_setup_kdf(operation, kdf_alg); #else return PSA_ERROR_NOT_SUPPORTED; diff --git a/scripts/mbedtls_dev/crypto_knowledge.py b/scripts/mbedtls_dev/crypto_knowledge.py index 4dac33fb9..819d92afb 100644 --- a/scripts/mbedtls_dev/crypto_knowledge.py +++ b/scripts/mbedtls_dev/crypto_knowledge.py @@ -214,9 +214,7 @@ class KeyType: This function does not currently handle key derivation or PAKE. """ #pylint: disable=too-many-branches,too-many-return-statements - if alg.is_wildcard: - return False - if alg.is_invalid_truncation(): + if not alg.is_valid_for_operation(): return False if self.head == 'HMAC' and alg.head == 'HMAC': return True @@ -248,6 +246,8 @@ class KeyType: # So a public key object with a key agreement algorithm is not # a valid combination. return False + if alg.is_invalid_key_agreement_with_derivation(): + return False if self.head == 'ECC': assert self.params is not None eccc = EllipticCurveCategory.from_family(self.params[0]) @@ -414,17 +414,38 @@ class Algorithm: 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.""" + def get_key_agreement_derivation(self) -> Optional[str]: + """For a combined key agreement and key derivation algorithm, get the derivation part. + + For anything else, return None. + """ if self.category != AlgorithmCategory.KEY_AGREEMENT: - return False + return None m = re.match(r'PSA_ALG_KEY_AGREEMENT\(\w+,\s*(.*)\)\Z', self.expression) if not m: - return False + return None 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) + if re.match(r'(?:0[Xx])?0+\s*\Z', kdf_alg): + return None + return kdf_alg + KEY_DERIVATIONS_INCOMPATIBLE_WITH_AGREEMENT = frozenset([ + 'PSA_ALG_TLS12_ECJPAKE_TO_PMS', # secret input in specific format + ]) + def is_valid_key_agreement_with_derivation(self) -> bool: + """Whether this is a valid combined key agreement and key derivation algorithm.""" + kdf_alg = self.get_key_agreement_derivation() + if kdf_alg is None: + return False + return kdf_alg not in self.KEY_DERIVATIONS_INCOMPATIBLE_WITH_AGREEMENT + + def is_invalid_key_agreement_with_derivation(self) -> bool: + """Whether this is an invalid combined key agreement and key derivation algorithm.""" + kdf_alg = self.get_key_agreement_derivation() + if kdf_alg is None: + return False + return kdf_alg in self.KEY_DERIVATIONS_INCOMPATIBLE_WITH_AGREEMENT def short_expression(self, level: int = 0) -> str: """Abbreviate the expression, keeping it human-readable. @@ -498,13 +519,26 @@ class Algorithm: return True return False + def is_valid_for_operation(self) -> bool: + """Whether this algorithm construction is valid for an operation. + + This function assumes that the algorithm is constructed in a + "grammatically" correct way, and only rejects semantically invalid + combinations. + """ + if self.is_wildcard: + return False + if self.is_invalid_truncation(): + return False + return True + def can_do(self, category: AlgorithmCategory) -> bool: """Whether this algorithm can perform operations in the given category. """ if category == self.category: return True if category == AlgorithmCategory.KEY_DERIVATION and \ - self.is_key_agreement_with_derivation(): + self.is_valid_key_agreement_with_derivation(): return True return False diff --git a/tests/scripts/generate_psa_tests.py b/tests/scripts/generate_psa_tests.py index b02ee05ac..752e7cae7 100755 --- a/tests/scripts/generate_psa_tests.py +++ b/tests/scripts/generate_psa_tests.py @@ -151,14 +151,16 @@ def test_case_for_key_type_not_supported( tc.set_arguments([key_type] + list(args)) return tc -class NotSupported: - """Generate test cases for when something is not supported.""" +class KeyTypeNotSupported: + """Generate test cases for when a key type is not supported.""" def __init__(self, info: Information) -> None: self.constructors = info.constructors ALWAYS_SUPPORTED = frozenset([ 'PSA_KEY_TYPE_DERIVE', + 'PSA_KEY_TYPE_PASSWORD', + 'PSA_KEY_TYPE_PASSWORD_HASH', 'PSA_KEY_TYPE_RAW_DATA', 'PSA_KEY_TYPE_HMAC' ]) @@ -522,7 +524,7 @@ class StorageFormat: key_type: psa_storage.Expr, bits: int, alg: psa_storage.Expr ) -> bool: - """Whether to the given key with the given algorithm. + """Whether to exercise the given key with the given algorithm. Normally only the type and algorithm matter for compatibility, and this is handled in crypto_knowledge.KeyType.can_do(). This function @@ -900,7 +902,7 @@ class PSATestGenerator(test_data_generation.TestGenerator): 'test_suite_psa_crypto_generate_key.generated': 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(), + lambda info: KeyTypeNotSupported(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': diff --git a/tests/suites/test_suite_psa_crypto.data b/tests/suites/test_suite_psa_crypto.data index 9ced77c2b..c3561420b 100644 --- a/tests/suites/test_suite_psa_crypto.data +++ b/tests/suites/test_suite_psa_crypto.data @@ -5080,6 +5080,22 @@ PSA key derivation: ECDH on P256 with HKDF-SHA256, missing info depends_on:PSA_WANT_ALG_ECDH:PSA_WANT_ALG_HKDF:PSA_WANT_ALG_SHA_256:PSA_WANT_KEY_TYPE_ECC_KEY_PAIR:MBEDTLS_PK_PARSE_C:PSA_WANT_ECC_SECP_R1_256 derive_input:PSA_ALG_KEY_AGREEMENT(PSA_ALG_ECDH, PSA_ALG_HKDF(PSA_ALG_SHA_256)):PSA_KEY_DERIVATION_INPUT_SALT:PSA_KEY_TYPE_NONE:"":PSA_SUCCESS:PSA_KEY_DERIVATION_INPUT_SECRET:PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1):"c88f01f510d9ac3f70a292daa2316de544e9aab8afe84049c62a9c57862d1433":PSA_SUCCESS:0:UNUSED:"":UNUSED:PSA_KEY_TYPE_NONE:PSA_ERROR_BAD_STATE +PSA key derivation: TLS12_ECJPAKE_TO_PMS, good input, output too short +depends_on:PSA_WANT_ALG_TLS12_ECJPAKE_TO_PMS +derive_input:PSA_ALG_TLS12_ECJPAKE_TO_PMS:PSA_KEY_DERIVATION_INPUT_SECRET:PSA_KEY_TYPE_NONE:"04aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa":PSA_SUCCESS:0:UNUSED:"":UNUSED:0:UNUSED:"":UNUSED:PSA_KEY_TYPE_NONE:PSA_ERROR_INVALID_ARGUMENT + +PSA key derivation: TLS12_ECJPAKE_TO_PMS, input[0]=0x02 +depends_on:PSA_WANT_ALG_TLS12_ECJPAKE_TO_PMS +derive_input:PSA_ALG_TLS12_ECJPAKE_TO_PMS:PSA_KEY_DERIVATION_INPUT_SECRET:PSA_KEY_TYPE_NONE:"02aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa":PSA_ERROR_INVALID_ARGUMENT:0:UNUSED:"":UNUSED:0:UNUSED:"":UNUSED:PSA_KEY_TYPE_NONE:PSA_ERROR_BAD_STATE + +PSA key derivation: TLS12_ECJPAKE_TO_PMS, input too short +depends_on:PSA_WANT_ALG_TLS12_ECJPAKE_TO_PMS +derive_input:PSA_ALG_TLS12_ECJPAKE_TO_PMS:PSA_KEY_DERIVATION_INPUT_SECRET:PSA_KEY_TYPE_NONE:"04aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa":PSA_ERROR_INVALID_ARGUMENT:0:UNUSED:"":UNUSED:0:UNUSED:"":UNUSED:PSA_KEY_TYPE_NONE:PSA_ERROR_BAD_STATE + +PSA key derivation: TLS12_ECJPAKE_TO_PMS, input too long +depends_on:PSA_WANT_ALG_TLS12_ECJPAKE_TO_PMS +derive_input:PSA_ALG_TLS12_ECJPAKE_TO_PMS:PSA_KEY_DERIVATION_INPUT_SECRET:PSA_KEY_TYPE_NONE:"04aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa":PSA_ERROR_INVALID_ARGUMENT:0:UNUSED:"":UNUSED:0:UNUSED:"":UNUSED:PSA_KEY_TYPE_NONE:PSA_ERROR_BAD_STATE + PSA key derivation over capacity: HKDF depends_on:PSA_WANT_ALG_HKDF:PSA_WANT_ALG_SHA_256 derive_over_capacity:PSA_ALG_HKDF(PSA_ALG_SHA_256) diff --git a/tests/suites/test_suite_psa_crypto_metadata.data b/tests/suites/test_suite_psa_crypto_metadata.data index bf5f04e4f..bbd501785 100644 --- a/tests/suites/test_suite_psa_crypto_metadata.data +++ b/tests/suites/test_suite_psa_crypto_metadata.data @@ -118,6 +118,10 @@ Cipher: XTS depends_on:PSA_WANT_ALG_XTS:MBEDTLS_CIPHER_C cipher_algorithm:PSA_ALG_XTS:0 +Cipher: CCM* +depends_on:PSA_WANT_ALG_CCM_STAR_NO_TAG +cipher_algorithm:PSA_ALG_CCM_STAR_NO_TAG:ALG_IS_STREAM_CIPHER + AEAD: CCM-AES-128 depends_on:PSA_WANT_KEY_TYPE_AES:PSA_WANT_ALG_CCM aead_algorithm:PSA_ALG_CCM:ALG_IS_AEAD_ON_BLOCK_CIPHER:16:PSA_KEY_TYPE_AES:128 @@ -286,6 +290,10 @@ Key derivation: HKDF-Expand using SHA-384 depends_on:PSA_WANT_ALG_HKDF_EXPAND:PSA_WANT_ALG_SHA_384 key_derivation_algorithm:PSA_ALG_HKDF_EXPAND( PSA_ALG_SHA_384 ):ALG_IS_HKDF_EXPAND +Key derivation: TLS1.2 ECJPAKE-to-PMS +depends_on:PSA_WANT_ALG_TLS12_ECJPAKE_TO_PMS +key_derivation_algorithm:PSA_ALG_TLS12_ECJPAKE_TO_PMS:0 + Key derivation: TLS 1.2 PRF using SHA-256 depends_on:PSA_WANT_ALG_SHA_256:PSA_WANT_ALG_TLS12_PRF key_derivation_algorithm:PSA_ALG_TLS12_PRF( PSA_ALG_SHA_256 ):ALG_IS_TLS12_PRF @@ -339,6 +347,12 @@ key_type:PSA_KEY_TYPE_HMAC:KEY_TYPE_IS_UNSTRUCTURED Key type: secret for key derivation key_type:PSA_KEY_TYPE_DERIVE:KEY_TYPE_IS_UNSTRUCTURED +Key type: password +key_type:PSA_KEY_TYPE_PASSWORD:KEY_TYPE_IS_UNSTRUCTURED + +Key type: password hash +key_type:PSA_KEY_TYPE_PASSWORD_HASH:KEY_TYPE_IS_UNSTRUCTURED + Block cipher key type: AES depends_on:PSA_WANT_KEY_TYPE_AES block_cipher_key_type:PSA_KEY_TYPE_AES:16