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/programs/psa/psa_constant_names.c b/programs/psa/psa_constant_names.c
index 5240b08..73692d0 100644
--- a/programs/psa/psa_constant_names.c
+++ b/programs/psa/psa_constant_names.c
@@ -64,6 +64,7 @@
 
 /* The code of these function is automatically generated and included below. */
 static const char *psa_ecc_curve_name(psa_ecc_curve_t curve);
+static const char *psa_dh_group_name(psa_dh_group_t group);
 static const char *psa_hash_algorithm_name(psa_algorithm_t hash_alg);
 
 static void append_with_curve(char **buffer, size_t buffer_size,
@@ -84,6 +85,24 @@
     append(buffer, buffer_size, required_size, ")", 1);
 }
 
+static void append_with_group(char **buffer, size_t buffer_size,
+                              size_t *required_size,
+                              const char *string, size_t length,
+                              psa_dh_group_t group)
+{
+    const char *group_name = psa_dh_group_name(group);
+    append(buffer, buffer_size, required_size, string, length);
+    append(buffer, buffer_size, required_size, "(", 1);
+    if (group_name != NULL) {
+        append(buffer, buffer_size, required_size,
+               group_name, strlen(group_name));
+    } else {
+        append_integer(buffer, buffer_size, required_size,
+                       "0x%04x", group);
+    }
+    append(buffer, buffer_size, required_size, ")", 1);
+}
+
 typedef const char *(*psa_get_algorithm_name_func_ptr)(psa_algorithm_t alg);
 
 static void append_with_alg(char **buffer, size_t buffer_size,
@@ -137,6 +156,23 @@
     }
 }
 
+static int psa_snprint_dh_group(char *buffer, size_t buffer_size,
+                                psa_dh_group_t group)
+{
+    const char *name = psa_dh_group_name(group);
+    if (name == NULL) {
+        return snprintf(buffer, buffer_size, "0x%04x", (unsigned) group);
+    } else {
+        size_t length = strlen(name);
+        if (length < buffer_size) {
+            memcpy(buffer, name, length + 1);
+            return (int) length;
+        } else {
+            return (int) buffer_size;
+        }
+    }
+}
+
 static void usage(const char *program_name)
 {
     printf("Usage: %s TYPE VALUE [VALUE...]\n",
@@ -145,6 +181,7 @@
     printf("Supported types (with = between aliases):\n");
     printf("  alg=algorithm         Algorithm (psa_algorithm_t)\n");
     printf("  curve=ecc_curve       Elliptic curve identifier (psa_ecc_curve_t)\n");
+    printf("  group=dh_group        Diffie-Hellman group identifier (psa_dh_group_t)\n");
     printf("  type=key_type         Key type (psa_key_type_t)\n");
     printf("  usage=key_usage       Key usage (psa_key_usage_t)\n");
     printf("  error=status          Status code (psa_status_t)\n");
@@ -188,6 +225,7 @@
 typedef enum {
     TYPE_ALGORITHM,
     TYPE_ECC_CURVE,
+    TYPE_DH_GROUP,
     TYPE_KEY_TYPE,
     TYPE_KEY_USAGE,
 } unsigned_value_type;
@@ -216,6 +254,10 @@
                 psa_snprint_ecc_curve(buffer, sizeof(buffer),
                                       (psa_ecc_curve_t) value);
                 break;
+            case TYPE_DH_GROUP:
+                psa_snprint_dh_group(buffer, sizeof(buffer),
+                                     (psa_dh_group_t) value);
+                break;
             case TYPE_KEY_TYPE:
                 psa_snprint_key_type(buffer, sizeof(buffer),
                                      (psa_key_type_t) value);
@@ -252,6 +294,9 @@
     } else if (!strcmp(argv[1], "curve") || !strcmp(argv[1], "ecc_curve")) {
         return process_unsigned(TYPE_ECC_CURVE, (psa_ecc_curve_t) (-1),
                                 argv + 2);
+    } else if (!strcmp(argv[1], "group") || !strcmp(argv[1], "dh_group")) {
+        return process_unsigned(TYPE_DH_GROUP, (psa_dh_group_t) (-1),
+                                argv + 2);
     } else if (!strcmp(argv[1], "type") || !strcmp(argv[1], "key_type")) {
         return process_unsigned(TYPE_KEY_TYPE, (psa_key_type_t) (-1),
                                 argv + 2);