Parametrize Diffie-Hellman keys by a group identifier

Parametrize finite-field Diffie-Hellman key types with a DH group
identifier, in the same way elliptic curve keys are parametrized with
an EC curve identifier.

Define the DH groups from the TLS registry (these are the groups from
RFC 7919).

Replicate the macro definitions and the metadata tests from elliptic
curve identifiers to DH group identifiers.

Define PSA_DH_GROUP_CUSTOM as an implementation-specific extension for
which domain parameters are used to specify the group.
diff --git a/tests/scripts/test_psa_constant_names.py b/tests/scripts/test_psa_constant_names.py
index 421cf4e..cbe68b1 100755
--- a/tests/scripts/test_psa_constant_names.py
+++ b/tests/scripts/test_psa_constant_names.py
@@ -58,6 +58,7 @@
         self.statuses = set(['PSA_SUCCESS'])
         self.algorithms = set(['0xffffffff'])
         self.ecc_curves = set(['0xffff'])
+        self.dh_groups = set(['0xffff'])
         self.key_types = set(['0xffffffff'])
         self.key_usage_flags = set(['0x80000000'])
         # Hard-coded value for unknown algorithms
@@ -74,6 +75,7 @@
             'ERROR': self.statuses,
             'ALG': self.algorithms,
             'CURVE': self.ecc_curves,
+            'GROUP': self.dh_groups,
             'KEY_TYPE': self.key_types,
             'KEY_USAGE': self.key_usage_flags,
         }
@@ -94,6 +96,7 @@
         self.arguments_for['kdf_alg'] = sorted(self.kdf_algorithms)
         self.arguments_for['aead_alg'] = sorted(self.aead_algorithms)
         self.arguments_for['curve'] = sorted(self.ecc_curves)
+        self.arguments_for['group'] = sorted(self.dh_groups)
 
     def format_arguments(self, name, arguments):
         '''Format a macro call with arguments..'''
@@ -184,6 +187,8 @@
             self.key_types.add(argument)
         elif function == 'ecc_key_types':
             self.ecc_curves.add(argument)
+        elif function == 'dh_key_types':
+            self.dh_groups.add(argument)
 
     # Regex matching a *.data line containing a test function call and
     # its arguments. The actual definition is partly positional, but this
@@ -299,6 +304,7 @@
     for type, names in [('status', inputs.statuses),
                         ('algorithm', inputs.algorithms),
                         ('ecc_curve', inputs.ecc_curves),
+                        ('dh_group', inputs.dh_groups),
                         ('key_type', inputs.key_types),
                         ('key_usage', inputs.key_usage_flags)]:
         c, e = do_test(options, inputs, type, names)
diff --git a/tests/suites/test_suite_psa_crypto_metadata.data b/tests/suites/test_suite_psa_crypto_metadata.data
index 94b80ac..165b866 100644
--- a/tests/suites/test_suite_psa_crypto_metadata.data
+++ b/tests/suites/test_suite_psa_crypto_metadata.data
@@ -454,3 +454,19 @@
 ECC key types: Curve448
 depends_on:MBEDTLS_ECP_DP_CURVE448_ENABLED
 ecc_key_types:PSA_ECC_CURVE_CURVE448:448
+
+DH group types: FFDHE2048
+dh_key_types:PSA_DH_GROUP_FFDHE2048:2048
+
+DH group types: FFDHE3072
+dh_key_types:PSA_DH_GROUP_FFDHE3072:2048
+
+DH group types: FFDHE4096
+dh_key_types:PSA_DH_GROUP_FFDHE4096:2048
+
+DH group types: FFDHE6144
+dh_key_types:PSA_DH_GROUP_FFDHE6144:2048
+
+DH group types: FFDHE8192
+dh_key_types:PSA_DH_GROUP_FFDHE8192:2048
+
diff --git a/tests/suites/test_suite_psa_crypto_metadata.function b/tests/suites/test_suite_psa_crypto_metadata.function
index e1eb1c5..81b2937 100644
--- a/tests/suites/test_suite_psa_crypto_metadata.function
+++ b/tests/suites/test_suite_psa_crypto_metadata.function
@@ -49,6 +49,7 @@
 #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 TEST_CLASSIFICATION_MACRO( flag, alg, flags )           \
     TEST_ASSERT( PSA_##flag( alg ) == !! ( ( flags ) & flag ) )
@@ -91,6 +92,7 @@
     TEST_CLASSIFICATION_MACRO( KEY_TYPE_IS_KEYPAIR, type, flags );
     TEST_CLASSIFICATION_MACRO( KEY_TYPE_IS_RSA, type, flags );
     TEST_CLASSIFICATION_MACRO( KEY_TYPE_IS_ECC, type, flags );
+    TEST_CLASSIFICATION_MACRO( KEY_TYPE_IS_DH, type, flags );
 
     /* Macros with derived semantics */
     TEST_EQUAL( PSA_KEY_TYPE_IS_ASYMMETRIC( type ),
@@ -102,6 +104,12 @@
     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_KEYPAIR( type ),
+                ( PSA_KEY_TYPE_IS_DH( type ) &&
+                  PSA_KEY_TYPE_IS_KEYPAIR( type ) ) );
+    TEST_EQUAL( PSA_KEY_TYPE_IS_DH_PUBLIC_KEY( type ),
+                ( PSA_KEY_TYPE_IS_DH( type ) &&
+                  PSA_KEY_TYPE_IS_PUBLIC_KEY( type ) ) );
 
 exit: ;
 }
@@ -457,3 +465,22 @@
     TEST_ASSERT( curve_bits <= PSA_VENDOR_ECC_MAX_CURVE_BITS );
 }
 /* END_CASE */
+
+/* BEGIN_CASE depends_on:MBEDTLS_DHM_C */
+void dh_key_types( int group_arg, int group_bits_arg )
+{
+    psa_dh_group_t group = group_arg;
+    size_t group_bits = group_bits_arg;
+    psa_key_type_t public_type = PSA_KEY_TYPE_DH_PUBLIC_KEY( group );
+    psa_key_type_t pair_type = PSA_KEY_TYPE_DH_KEYPAIR( 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_KEYPAIR );
+
+    TEST_EQUAL( PSA_KEY_TYPE_GET_GROUP( public_type ), group );
+    TEST_EQUAL( PSA_KEY_TYPE_GET_GROUP( pair_type ), group );
+
+    /* We have nothing to validate about the group size yet. */
+    (void) group_bits;
+}
+/* END_CASE */