A key agreement cannot be chained with PSA_ALG_TLS12_ECJPAKE_TO_PMS

Test accordingly.

Signed-off-by: Gilles Peskine <Gilles.Peskine@arm.com>
diff --git a/scripts/mbedtls_dev/crypto_knowledge.py b/scripts/mbedtls_dev/crypto_knowledge.py
index a56c863..3029c80 100644
--- a/scripts/mbedtls_dev/crypto_knowledge.py
+++ b/scripts/mbedtls_dev/crypto_knowledge.py
@@ -246,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])
@@ -412,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.
@@ -515,7 +538,7 @@
         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