Merge pull request #6802 from gilles-peskine-arm/test_suite_psa_crypto_metadata-20221215

Add metadata tests for CCM* and TLS1.2-ECJPAKE-to-PMS
diff --git a/ChangeLog.d/crypto_config_ccm_star.txt b/ChangeLog.d/crypto_config_ccm_star.txt
new file mode 100644
index 0000000..947014a
--- /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 0000000..cfea661
--- /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 09bc32c..48b2d32 100644
--- a/include/mbedtls/config_psa.h
+++ b/include/mbedtls/config_psa.h
@@ -843,6 +843,8 @@
 
 /* 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 5ab4fde..e68fac8 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 0a8949f..a683fdb 100644
--- a/library/psa_crypto.c
+++ b/library/psa_crypto.c
@@ -5168,6 +5168,18 @@
     (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 @@
         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 4dac33f..819d92a 100644
--- a/scripts/mbedtls_dev/crypto_knowledge.py
+++ b/scripts/mbedtls_dev/crypto_knowledge.py
@@ -214,9 +214,7 @@
         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 @@
             # 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 @@
         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 @@
                 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 b02ee05..752e7ca 100755
--- a/tests/scripts/generate_psa_tests.py
+++ b/tests/scripts/generate_psa_tests.py
@@ -151,14 +151,16 @@
     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 @@
             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 @@
         '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 9ced77c..c356142 100644
--- a/tests/suites/test_suite_psa_crypto.data
+++ b/tests/suites/test_suite_psa_crypto.data
@@ -5080,6 +5080,22 @@
 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 bf5f04e..bbd5017 100644
--- a/tests/suites/test_suite_psa_crypto_metadata.data
+++ b/tests/suites/test_suite_psa_crypto_metadata.data
@@ -118,6 +118,10 @@
 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 @@
 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: 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