Merge pull request #112 from gilles-peskine-arm/psa-remove_domain_parameters

Remove domain parameters from API 1.0
diff --git a/include/psa/crypto.h b/include/psa/crypto.h
index 84026c9..c6a13ac 100644
--- a/include/psa/crypto.h
+++ b/include/psa/crypto.h
@@ -105,8 +105,7 @@
  *   and its lifetime.
  * - The key's policy, comprising usage flags and a specification of
  *   the permitted algorithm(s).
- * - Information about the key itself: the key type, the key size, and
- *   for some key type additional domain parameters.
+ * - Information about the key itself: the key type and its size.
  * - Implementations may define additional attributes.
  *
  * The actual key material is not considered an attribute of a key.
@@ -167,7 +166,7 @@
  *
  * - lifetime: #PSA_KEY_LIFETIME_VOLATILE.
  * - key identifier: unspecified.
- * - type: \c 0, with no domain parameters.
+ * - type: \c 0.
  * - key size: \c 0.
  * - usage flags: \c 0.
  * - algorithm: \c 0.
@@ -179,8 +178,7 @@
  *    location.
  * -# Set the key policy with psa_set_key_usage_flags() and
  *    psa_set_key_algorithm().
- * -# Set the key type with psa_set_key_type(). If the key type requires
- *    domain parameters, call psa_set_key_domain_parameters() instead.
+ * -# Set the key type with psa_set_key_type().
  *    Skip this step if copying an existing key with psa_copy_key().
  * -# When generating a random key with psa_generate_random_key() or deriving a key
  *    with psa_key_derivation_output_key(), set the desired key size with
@@ -189,11 +187,11 @@
  *    psa_key_derivation_output_key() or psa_copy_key(). This function reads
  *    the attribute structure, creates a key with these attributes, and
  *    outputs a handle to the newly created key.
- * -# The attribute structure is now no longer necessary. If you called
- *    psa_set_key_domain_parameters() earlier, you must call
- *    psa_reset_key_attributes() to free any resources used by the
- *    domain parameters. Otherwise calling psa_reset_key_attributes()
- *    is optional.
+ * -# The attribute structure is now no longer necessary.
+ *    You may call psa_reset_key_attributes(), although this is optional
+ *    with the workflow presented here because the attributes currently
+ *    defined in this specification do not require any additional resources
+ *    beyond the structure itself.
  *
  * A typical sequence to query a key's attributes is as follows:
  * -# Call psa_get_key_attributes().
@@ -349,10 +347,7 @@
 
 /** Declare the type of a key.
  *
- * If a type requires domain parameters, you must call
- * psa_set_key_domain_parameters() instead of this function.
- *
- * This function overwrites any key type and domain parameters
+ * This function overwrites any key type
  * previously set in \p attributes.
  *
  * This function may be declared as `static` (i.e. without external
@@ -403,97 +398,6 @@
  */
 static size_t psa_get_key_bits(const psa_key_attributes_t *attributes);
 
-/**
- * \brief Set domain parameters for a key.
- *
- * Some key types require additional domain parameters in addition to
- * the key type identifier and the key size.
- * The format for the required domain parameters varies by the key type.
- *
- * - For RSA keys (#PSA_KEY_TYPE_RSA_PUBLIC_KEY or #PSA_KEY_TYPE_RSA_KEYPAIR),
- *   the domain parameter data consists of the public exponent,
- *   represented as a big-endian integer with no leading zeros.
- *   This information is used when generating an RSA key pair.
- *   When importing a key, the public exponent is read from the imported
- *   key data and the exponent recorded in the attribute structure is ignored.
- *   As an exception, the public exponent 65537 is represented by an empty
- *   byte string.
- * - For DSA keys (#PSA_KEY_TYPE_DSA_PUBLIC_KEY or #PSA_KEY_TYPE_DSA_KEYPAIR),
- *   the `Dss-Parms` format as defined by RFC 3279 §2.3.2.
- *   ```
- *   Dss-Parms ::= SEQUENCE  {
- *      p       INTEGER,
- *      q       INTEGER,
- *      g       INTEGER
- *   }
- *   ```
- * - For Diffie-Hellman key exchange keys (#PSA_KEY_TYPE_DH_PUBLIC_KEY or
- *   #PSA_KEY_TYPE_DH_KEYPAIR), the
- *   `DomainParameters` format as defined by RFC 3279 §2.3.3.
- *   ```
- *   DomainParameters ::= SEQUENCE {
- *      p               INTEGER,                    -- odd prime, p=jq +1
- *      g               INTEGER,                    -- generator, g
- *      q               INTEGER,                    -- factor of p-1
- *      j               INTEGER OPTIONAL,           -- subgroup factor
- *      validationParms ValidationParms OPTIONAL
- *   }
- *   ValidationParms ::= SEQUENCE {
- *      seed            BIT STRING,
- *      pgenCounter     INTEGER
- *   }
- *   ```
- *
- * \note This function may allocate memory or other resources.
- *       Once you have called this function on an attribute structure,
- *       you must call psa_reset_key_attributes() to free these resources.
- *
- * \param[in,out] attributes    Attribute structure where the specified domain
- *                              parameters will be stored.
- *                              If this function fails, the content of
- *                              \p attributes is not modified.
- * \param type                  Key type (a \c PSA_KEY_TYPE_XXX value).
- * \param[in] data              Buffer containing the key domain parameters.
- *                              The content of this buffer is interpreted
- *                              according to \p type as described above.
- * \param data_length           Size of the \p data buffer in bytes.
- *
- * \retval #PSA_SUCCESS
- * \retval #PSA_ERROR_INVALID_ARGUMENT
- * \retval #PSA_ERROR_NOT_SUPPORTED
- * \retval #PSA_ERROR_INSUFFICIENT_MEMORY
- */
-psa_status_t psa_set_key_domain_parameters(psa_key_attributes_t *attributes,
-                                           psa_key_type_t type,
-                                           const uint8_t *data,
-                                           size_t data_length);
-
-/**
- * \brief Get domain parameters for a key.
- *
- * Get the domain parameters for a key with this function, if any. The format
- * of the domain parameters written to \p data is specified in the
- * documentation for psa_set_key_domain_parameters().
- *
- * \param[in] attributes        The key attribute structure to query.
- * \param[out] data             On success, the key domain parameters.
- * \param data_size             Size of the \p data buffer in bytes.
- *                              The buffer is guaranteed to be large
- *                              enough if its size in bytes is at least
- *                              the value given by
- *                              PSA_KEY_DOMAIN_PARAMETERS_SIZE().
- * \param[out] data_length      On success, the number of bytes
- *                              that make up the key domain parameters data.
- *
- * \retval #PSA_SUCCESS
- * \retval #PSA_ERROR_BUFFER_TOO_SMALL
- */
-psa_status_t psa_get_key_domain_parameters(
-    const psa_key_attributes_t *attributes,
-    uint8_t *data,
-    size_t data_size,
-    size_t *data_length);
-
 /** Retrieve the attributes of a key.
  *
  * This function first resets the attribute structure as with
@@ -617,9 +521,8 @@
  * \param[out] handle       On success, a handle to the newly created key.
  *                          \c 0 on failure.
  * \param[in] data    Buffer containing the key data. The content of this
- *                    buffer is interpreted according to the type and,
- *                    if applicable, domain parameters declared in
- *                    \p attributes.
+ *                    buffer is interpreted according to the type declared
+ *                    in \p attributes.
  *                    All implementations must support at least the format
  *                    described in the documentation
  *                    of psa_export_key() or psa_export_public_key() for
@@ -738,10 +641,6 @@
  *       coefficient         INTEGER,  -- (inverse of q) mod p
  *   }
  *   ```
- * - For DSA private keys (#PSA_KEY_TYPE_DSA_KEYPAIR), the format is the
- *   representation of the private key `x` as a big-endian byte string. The
- *   length of the byte string is the private key size in bytes (leading zeroes
- *   are not stripped).
  * - For elliptic curve key pairs (key types for which
  *   #PSA_KEY_TYPE_IS_ECC_KEYPAIR is true), the format is
  *   a representation of the private value as a `ceiling(m/8)`-byte string
@@ -753,7 +652,8 @@
  *   and `PSA_ECC_CURVE_BRAINPOOL_PXXX`).
  *   This is the content of the `privateKey` field of the `ECPrivateKey`
  *   format defined by RFC 5915.
- * - For Diffie-Hellman key exchange key pairs (#PSA_KEY_TYPE_DH_KEYPAIR), the
+ * - For Diffie-Hellman key exchange key pairs (key types for which
+ *   #PSA_KEY_TYPE_IS_DH_KEYPAIR is true), the
  *   format is the representation of the private key `x` as a big-endian byte
  *   string. The length of the byte string is the private key size in bytes
  *   (leading zeroes are not stripped).
@@ -822,11 +722,8 @@
  *      - The byte 0x04;
  *      - `x_P` as a `ceiling(m/8)`-byte string, big-endian;
  *      - `y_P` as a `ceiling(m/8)`-byte string, big-endian.
- * - For DSA public keys (#PSA_KEY_TYPE_DSA_PUBLIC_KEY), the format is the
- *   representation of the public key `y = g^x mod p` as a big-endian byte
- *   string. The length of the byte string is the length of the base prime `p`
- *   in bytes.
- * - For Diffie-Hellman key exchange public keys (#PSA_KEY_TYPE_DH_PUBLIC_KEY),
+ * - For Diffie-Hellman key exchange public keys (key types for which
+ *   #PSA_KEY_TYPE_IS_DH_PUBLIC_KEY is true),
  *   the format is the representation of the public key `y = g^x mod p` as a
  *   big-endian byte string. The length of the byte string is the length of the
  *   base prime `p` in bytes.
@@ -910,9 +807,6 @@
  *                          - The key type and size may be 0. If either is
  *                            nonzero, it must match the corresponding
  *                            attribute of the source key.
- *                          - If \p attributes contains domain parameters,
- *                            they must match the domain parameters of
- *                            the source key.
  *                          - The key location (the lifetime and, for
  *                            persistent keys, the key identifier) is
  *                            used directly.
@@ -936,7 +830,7 @@
  *         The policy constraints on the source and specified in
  *         \p attributes are incompatible.
  * \retval #PSA_ERROR_INVALID_ARGUMENT
- *         \p attributes specifies a key type, domain parameters or key size
+ *         \p attributes specifies a key type or key size
  *         which does not match the attributes of the source key.
  * \retval #PSA_ERROR_NOT_PERMITTED
  *         The source key does not have the #PSA_KEY_USAGE_COPY usage flag.
@@ -3353,8 +3247,8 @@
  *       discard the first 8 bytes, use the next 8 bytes as the first key,
  *       and continue reading output from the operation to derive the other
  *       two keys).
- *     - Finite-field Diffie-Hellman keys (#PSA_KEY_TYPE_DH_KEYPAIR),
- *       DSA keys (#PSA_KEY_TYPE_DSA_KEYPAIR), and
+ *     - Finite-field Diffie-Hellman keys (#PSA_KEY_TYPE_DH_KEYPAIR(\c group)
+ *       where \c group designates any Diffie-Hellman group) and
  *       ECC keys on a Weierstrass elliptic curve
  *       (#PSA_KEY_TYPE_ECC_KEYPAIR(\c curve) where \c curve designates a
  *       Weierstrass curve).
@@ -3529,19 +3423,12 @@
  * The key is generated randomly.
  * Its location, policy, type and size are taken from \p attributes.
  *
- * If the type requires additional domain parameters, these are taken
- * from \p attributes as well. The following types use domain parameters:
- * - When generating an RSA key (#PSA_KEY_TYPE_RSA_KEYPAIR),
- *   the default public exponent is 65537. This value is used if
- *   \p attributes was set with psa_set_key_type() or by passing an empty
- *   byte string as domain parameters to psa_set_key_domain_parameters().
- *   If psa_set_key_domain_parameters() was used to set a non-empty
- *   domain parameter string in \p attributes, this string is read as
- *   a big-endian integer which is used as the public exponent.
- * - When generating a DSA key (#PSA_KEY_TYPE_DSA_KEYPAIR) or a
- *   Diffie-Hellman key (#PSA_KEY_TYPE_DH_KEYPAIR), the domain parameters
- *   from \p attributes are interpreted as described for
- *   psa_set_key_domain_parameters().
+ * The following type-specific considerations apply:
+ * - For RSA keys (#PSA_KEY_TYPE_RSA_KEYPAIR),
+ *   the public exponent is 65537.
+ *   The modulus is a product of two probabilistic primes
+ *   between 2^{n-1} and 2^n where n is the bit size specified in the
+ *   attributes.
  *
  * \param[in] attributes    The attributes for the new key.
  * \param[out] handle       On success, a handle to the newly created key.
diff --git a/include/psa/crypto_extra.h b/include/psa/crypto_extra.h
index 45655dd..4ffd858 100644
--- a/include/psa/crypto_extra.h
+++ b/include/psa/crypto_extra.h
@@ -444,6 +444,248 @@
 
 /**@}*/
 
+
+/** \addtogroup crypto_types
+ * @{
+ */
+
+/** DSA public key.
+ *
+ * The import and export format is the
+ * representation of the public key `y = g^x mod p` as a big-endian byte
+ * string. The length of the byte string is the length of the base prime `p`
+ * in bytes.
+ */
+#define PSA_KEY_TYPE_DSA_PUBLIC_KEY             ((psa_key_type_t)0x60020000)
+
+/** DSA key pair (private and public key).
+ *
+ * The import and export format is the
+ * representation of the private key `x` as a big-endian byte string. The
+ * length of the byte string is the private key size in bytes (leading zeroes
+ * are not stripped).
+ *
+ * Determinstic DSA key derivation with psa_generate_derived_key follows
+ * FIPS 186-4 §B.1.2: interpret the byte string as integer
+ * in big-endian order. Discard it if it is not in the range
+ * [0, *N* - 2] where *N* is the boundary of the private key domain
+ * (the prime *p* for Diffie-Hellman, the subprime *q* for DSA,
+ * or the order of the curve's base point for ECC).
+ * Add 1 to the resulting integer and use this as the private key *x*.
+ *
+ */
+#define PSA_KEY_TYPE_DSA_KEYPAIR                ((psa_key_type_t)0x70020000)
+
+/** Whether a key type is an DSA key (pair or public-only). */
+#define PSA_KEY_TYPE_IS_DSA(type)                                       \
+    (PSA_KEY_TYPE_PUBLIC_KEY_OF_KEYPAIR(type) == PSA_KEY_TYPE_DSA_PUBLIC_KEY)
+
+#define PSA_ALG_DSA_BASE                        ((psa_algorithm_t)0x10040000)
+/** DSA signature with hashing.
+ *
+ * This is the signature scheme defined by FIPS 186-4,
+ * with a random per-message secret number (*k*).
+ *
+ * \param hash_alg      A hash algorithm (\c PSA_ALG_XXX value such that
+ *                      #PSA_ALG_IS_HASH(\p hash_alg) is true).
+ *                      This includes #PSA_ALG_ANY_HASH
+ *                      when specifying the algorithm in a usage policy.
+ *
+ * \return              The corresponding DSA signature algorithm.
+ * \return              Unspecified if \p hash_alg is not a supported
+ *                      hash algorithm.
+ */
+#define PSA_ALG_DSA(hash_alg)                             \
+    (PSA_ALG_DSA_BASE | ((hash_alg) & PSA_ALG_HASH_MASK))
+#define PSA_ALG_DETERMINISTIC_DSA_BASE          ((psa_algorithm_t)0x10050000)
+#define PSA_ALG_DSA_DETERMINISTIC_FLAG          ((psa_algorithm_t)0x00010000)
+/** Deterministic DSA signature with hashing.
+ *
+ * This is the deterministic variant defined by RFC 6979 of
+ * the signature scheme defined by FIPS 186-4.
+ *
+ * \param hash_alg      A hash algorithm (\c PSA_ALG_XXX value such that
+ *                      #PSA_ALG_IS_HASH(\p hash_alg) is true).
+ *                      This includes #PSA_ALG_ANY_HASH
+ *                      when specifying the algorithm in a usage policy.
+ *
+ * \return              The corresponding DSA signature algorithm.
+ * \return              Unspecified if \p hash_alg is not a supported
+ *                      hash algorithm.
+ */
+#define PSA_ALG_DETERMINISTIC_DSA(hash_alg)                             \
+    (PSA_ALG_DETERMINISTIC_DSA_BASE | ((hash_alg) & PSA_ALG_HASH_MASK))
+#define PSA_ALG_IS_DSA(alg)                                             \
+    (((alg) & ~PSA_ALG_HASH_MASK & ~PSA_ALG_DSA_DETERMINISTIC_FLAG) ==  \
+     PSA_ALG_DSA_BASE)
+#define PSA_ALG_DSA_IS_DETERMINISTIC(alg)               \
+    (((alg) & PSA_ALG_DSA_DETERMINISTIC_FLAG) != 0)
+#define PSA_ALG_IS_DETERMINISTIC_DSA(alg)                       \
+    (PSA_ALG_IS_DSA(alg) && PSA_ALG_DSA_IS_DETERMINISTIC(alg))
+#define PSA_ALG_IS_RANDOMIZED_DSA(alg)                          \
+    (PSA_ALG_IS_DSA(alg) && !PSA_ALG_DSA_IS_DETERMINISTIC(alg))
+
+
+/* We need to expand the sample definition of this macro from
+ * the API definition. */
+#undef PSA_ALG_IS_HASH_AND_SIGN
+#define PSA_ALG_IS_HASH_AND_SIGN(alg)                                   \
+    (PSA_ALG_IS_RSA_PSS(alg) || PSA_ALG_IS_RSA_PKCS1V15_SIGN(alg) ||    \
+     PSA_ALG_IS_DSA(alg) || PSA_ALG_IS_ECDSA(alg))
+
+/**@}*/
+
+/** \addtogroup attributes
+ * @{
+ */
+
+/** Custom Diffie-Hellman group.
+ *
+ * For keys of type #PSA_KEY_TYPE_DH_PUBLIC_KEY(#PSA_DH_GROUP_CUSTOM) or
+ * #PSA_KEY_TYPE_DH_KEYPAIR(#PSA_DH_GROUP_CUSTOM), the group data comes
+ * from domain parameters set by psa_set_key_domain_parameters().
+ */
+/* This value is reserved for private use in the TLS named group registry. */
+#define PSA_DH_GROUP_CUSTOM             ((psa_dh_group_t) 0x01fc)
+
+
+/**
+ * \brief Set domain parameters for a key.
+ *
+ * Some key types require additional domain parameters in addition to
+ * the key type identifier and the key size. Use this function instead
+ * of psa_set_key_type() when you need to specify domain parameters.
+ *
+ * The format for the required domain parameters varies based on the key type.
+ *
+ * - For RSA keys (#PSA_KEY_TYPE_RSA_PUBLIC_KEY or #PSA_KEY_TYPE_RSA_KEYPAIR),
+ *   the domain parameter data consists of the public exponent,
+ *   represented as a big-endian integer with no leading zeros.
+ *   This information is used when generating an RSA key pair.
+ *   When importing a key, the public exponent is read from the imported
+ *   key data and the exponent recorded in the attribute structure is ignored.
+ *   As an exception, the public exponent 65537 is represented by an empty
+ *   byte string.
+ * - For DSA keys (#PSA_KEY_TYPE_DSA_PUBLIC_KEY or #PSA_KEY_TYPE_DSA_KEYPAIR),
+ *   the `Dss-Parms` format as defined by RFC 3279 §2.3.2.
+ *   ```
+ *   Dss-Parms ::= SEQUENCE  {
+ *      p       INTEGER,
+ *      q       INTEGER,
+ *      g       INTEGER
+ *   }
+ *   ```
+ * - For Diffie-Hellman key exchange keys
+ *   (#PSA_KEY_TYPE_DH_PUBLIC_KEY(#PSA_DH_GROUP_CUSTOM) or
+ *   #PSA_KEY_TYPE_DH_KEYPAIR(#PSA_DH_GROUP_CUSTOM)), the
+ *   `DomainParameters` format as defined by RFC 3279 §2.3.3.
+ *   ```
+ *   DomainParameters ::= SEQUENCE {
+ *      p               INTEGER,                    -- odd prime, p=jq +1
+ *      g               INTEGER,                    -- generator, g
+ *      q               INTEGER,                    -- factor of p-1
+ *      j               INTEGER OPTIONAL,           -- subgroup factor
+ *      validationParms ValidationParms OPTIONAL
+ *   }
+ *   ValidationParms ::= SEQUENCE {
+ *      seed            BIT STRING,
+ *      pgenCounter     INTEGER
+ *   }
+ *   ```
+ *
+ * \note This function may allocate memory or other resources.
+ *       Once you have called this function on an attribute structure,
+ *       you must call psa_reset_key_attributes() to free these resources.
+ *
+ * \note This is an experimental extension to the interface. It may change
+ *       in future versions of the library.
+ *
+ * \param[in,out] attributes    Attribute structure where the specified domain
+ *                              parameters will be stored.
+ *                              If this function fails, the content of
+ *                              \p attributes is not modified.
+ * \param type                  Key type (a \c PSA_KEY_TYPE_XXX value).
+ * \param[in] data              Buffer containing the key domain parameters.
+ *                              The content of this buffer is interpreted
+ *                              according to \p type as described above.
+ * \param data_length           Size of the \p data buffer in bytes.
+ *
+ * \retval #PSA_SUCCESS
+ * \retval #PSA_ERROR_INVALID_ARGUMENT
+ * \retval #PSA_ERROR_NOT_SUPPORTED
+ * \retval #PSA_ERROR_INSUFFICIENT_MEMORY
+ */
+psa_status_t psa_set_key_domain_parameters(psa_key_attributes_t *attributes,
+                                           psa_key_type_t type,
+                                           const uint8_t *data,
+                                           size_t data_length);
+
+/**
+ * \brief Get domain parameters for a key.
+ *
+ * Get the domain parameters for a key with this function, if any. The format
+ * of the domain parameters written to \p data is specified in the
+ * documentation for psa_set_key_domain_parameters().
+ *
+ * \note This is an experimental extension to the interface. It may change
+ *       in future versions of the library.
+ *
+ * \param[in] attributes        The key attribute structure to query.
+ * \param[out] data             On success, the key domain parameters.
+ * \param data_size             Size of the \p data buffer in bytes.
+ *                              The buffer is guaranteed to be large
+ *                              enough if its size in bytes is at least
+ *                              the value given by
+ *                              PSA_KEY_DOMAIN_PARAMETERS_SIZE().
+ * \param[out] data_length      On success, the number of bytes
+ *                              that make up the key domain parameters data.
+ *
+ * \retval #PSA_SUCCESS
+ * \retval #PSA_ERROR_BUFFER_TOO_SMALL
+ */
+psa_status_t psa_get_key_domain_parameters(
+    const psa_key_attributes_t *attributes,
+    uint8_t *data,
+    size_t data_size,
+    size_t *data_length);
+
+/** Safe output buffer size for psa_get_key_domain_parameters().
+ *
+ * This macro returns a compile-time constant if its arguments are
+ * compile-time constants.
+ *
+ * \warning This function may call its arguments multiple times or
+ *          zero times, so you should not pass arguments that contain
+ *          side effects.
+ *
+ * \note This is an experimental extension to the interface. It may change
+ *       in future versions of the library.
+ *
+ * \param key_type  A supported key type.
+ * \param key_bits  The size of the key in bits.
+ *
+ * \return If the parameters are valid and supported, return
+ *         a buffer size in bytes that guarantees that
+ *         psa_get_key_domain_parameters() will not fail with
+ *         #PSA_ERROR_BUFFER_TOO_SMALL.
+ *         If the parameters are a valid combination that is not supported
+ *         by the implementation, this macro shall return either a
+ *         sensible size or 0.
+ *         If the parameters are not valid, the
+ *         return value is unspecified.
+ */
+#define PSA_KEY_DOMAIN_PARAMETERS_SIZE(key_type, key_bits)              \
+    (PSA_KEY_TYPE_IS_RSA(key_type) ? sizeof(int) :                      \
+     PSA_KEY_TYPE_IS_DH(key_type) ? PSA_DH_KEY_DOMAIN_PARAMETERS_SIZE(key_bits) : \
+     PSA_KEY_TYPE_IS_DSA(key_type) ? PSA_DSA_KEY_DOMAIN_PARAMETERS_SIZE(key_bits) : \
+     0)
+#define PSA_DH_KEY_DOMAIN_PARAMETERS_SIZE(key_bits)     \
+    (4 + (PSA_BITS_TO_BYTES(key_bits) + 5) * 3 /*without optional parts*/)
+#define PSA_DSA_KEY_DOMAIN_PARAMETERS_SIZE(key_bits)    \
+    (4 + (PSA_BITS_TO_BYTES(key_bits) + 5) * 2 /*p, g*/ + 34 /*q*/)
+
+/**@}*/
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/psa/crypto_sizes.h b/include/psa/crypto_sizes.h
index cab896e..d7eb482 100644
--- a/include/psa/crypto_sizes.h
+++ b/include/psa/crypto_sizes.h
@@ -447,7 +447,7 @@
  *         psa_asymmetric_sign() will not fail with
  *         #PSA_ERROR_BUFFER_TOO_SMALL.
  *         If the parameters are a valid combination that is not supported
- *         by the implementation, this macro either shall return either a
+ *         by the implementation, this macro shall return either a
  *         sensible size or 0.
  *         If the parameters are not valid, the
  *         return value is unspecified.
@@ -478,7 +478,7 @@
  *         psa_asymmetric_encrypt() will not fail with
  *         #PSA_ERROR_BUFFER_TOO_SMALL.
  *         If the parameters are a valid combination that is not supported
- *         by the implementation, this macro either shall return either a
+ *         by the implementation, this macro shall return either a
  *         sensible size or 0.
  *         If the parameters are not valid, the
  *         return value is unspecified.
@@ -509,7 +509,7 @@
  *         psa_asymmetric_decrypt() will not fail with
  *         #PSA_ERROR_BUFFER_TOO_SMALL.
  *         If the parameters are a valid combination that is not supported
- *         by the implementation, this macro either shall return either a
+ *         by the implementation, this macro shall return either a
  *         sensible size or 0.
  *         If the parameters are not valid, the
  *         return value is unspecified.
@@ -680,7 +680,7 @@
  *         psa_asymmetric_sign() will not fail with
  *         #PSA_ERROR_BUFFER_TOO_SMALL.
  *         If the parameters are a valid combination that is not supported
- *         by the implementation, this macro either shall return either a
+ *         by the implementation, this macro shall return either a
  *         sensible size or 0.
  *         If the parameters are not valid, the
  *         return value is unspecified.
@@ -695,36 +695,4 @@
      PSA_KEY_TYPE_IS_ECC_PUBLIC_KEY(key_type) ? PSA_KEY_EXPORT_ECC_PUBLIC_KEY_MAX_SIZE(key_bits) : \
      0)
 
-/** Safe output buffer size for psa_get_key_domain_parameters().
- *
- * This macro returns a compile-time constant if its arguments are
- * compile-time constants.
- *
- * \warning This function may call its arguments multiple times or
- *          zero times, so you should not pass arguments that contain
- *          side effects.
- *
- * \param key_type  A supported key type.
- * \param key_bits  The size of the key in bits.
- *
- * \return If the parameters are valid and supported, return
- *         a buffer size in bytes that guarantees that
- *         psa_get_key_domain_parameters() will not fail with
- *         #PSA_ERROR_BUFFER_TOO_SMALL.
- *         If the parameters are a valid combination that is not supported
- *         by the implementation, this macro either shall return either a
- *         sensible size or 0.
- *         If the parameters are not valid, the
- *         return value is unspecified.
- */
-#define PSA_KEY_DOMAIN_PARAMETERS_SIZE(key_type, key_bits)              \
-    (PSA_KEY_TYPE_IS_RSA(key_type) ? sizeof(int) :                      \
-     PSA_KEY_TYPE_IS_DH(key_type) ? PSA_DH_KEY_DOMAIN_PARAMETERS_SIZE(key_bits) : \
-     PSA_KEY_TYPE_IS_DSA(key_type) ? PSA_DSA_KEY_DOMAIN_PARAMETERS_SIZE(key_bits) : \
-     0)
-#define PSA_DH_KEY_DOMAIN_PARAMETERS_SIZE(key_bits)     \
-    (4 + (PSA_BITS_TO_BYTES(key_bits) + 5) * 3 /*without optional parts*/)
-#define PSA_DSA_KEY_DOMAIN_PARAMETERS_SIZE(key_bits)    \
-    (4 + (PSA_BITS_TO_BYTES(key_bits) + 5) * 2 /*p, g*/ + 34 /*q*/)
-
 #endif /* PSA_CRYPTO_SIZES_H */
diff --git a/include/psa/crypto_struct.h b/include/psa/crypto_struct.h
index 01d3069..885d908 100644
--- a/include/psa/crypto_struct.h
+++ b/include/psa/crypto_struct.h
@@ -331,6 +331,13 @@
     return( attributes->policy.alg );
 }
 
+/* This function is declared in crypto_extra.h, which comes after this
+ * header file, but we need the function here, so repeat the declaration. */
+psa_status_t psa_set_key_domain_parameters(psa_key_attributes_t *attributes,
+                                           psa_key_type_t type,
+                                           const uint8_t *data,
+                                           size_t data_length);
+
 static inline void psa_set_key_type(psa_key_attributes_t *attributes,
                                     psa_key_type_t type)
 {
diff --git a/include/psa/crypto_types.h b/include/psa/crypto_types.h
index ced42de..02c2678 100644
--- a/include/psa/crypto_types.h
+++ b/include/psa/crypto_types.h
@@ -68,6 +68,9 @@
 /** The type of PSA elliptic curve identifiers. */
 typedef uint16_t psa_ecc_curve_t;
 
+/** The type of PSA Diffie-Hellman group identifiers. */
+typedef uint16_t psa_dh_group_t;
+
 /** \brief Encoding of a cryptographic algorithm.
  *
  * For algorithms that can be applied to multiple key types, this type
diff --git a/include/psa/crypto_values.h b/include/psa/crypto_values.h
index c54fc9a..bab7063 100644
--- a/include/psa/crypto_values.h
+++ b/include/psa/crypto_values.h
@@ -419,14 +419,6 @@
 #define PSA_KEY_TYPE_IS_RSA(type)                                       \
     (PSA_KEY_TYPE_PUBLIC_KEY_OF_KEYPAIR(type) == PSA_KEY_TYPE_RSA_PUBLIC_KEY)
 
-/** DSA public key. */
-#define PSA_KEY_TYPE_DSA_PUBLIC_KEY             ((psa_key_type_t)0x60020000)
-/** DSA key pair (private and public key). */
-#define PSA_KEY_TYPE_DSA_KEYPAIR                ((psa_key_type_t)0x70020000)
-/** Whether a key type is an DSA key (pair or public-only). */
-#define PSA_KEY_TYPE_IS_DSA(type)                                       \
-    (PSA_KEY_TYPE_PUBLIC_KEY_OF_KEYPAIR(type) == PSA_KEY_TYPE_DSA_PUBLIC_KEY)
-
 #define PSA_KEY_TYPE_ECC_PUBLIC_KEY_BASE        ((psa_key_type_t)0x60030000)
 #define PSA_KEY_TYPE_ECC_KEYPAIR_BASE           ((psa_key_type_t)0x70030000)
 #define PSA_KEY_TYPE_ECC_CURVE_MASK             ((psa_key_type_t)0x0000ffff)
@@ -492,14 +484,45 @@
 #define PSA_ECC_CURVE_CURVE25519        ((psa_ecc_curve_t) 0x001d)
 #define PSA_ECC_CURVE_CURVE448          ((psa_ecc_curve_t) 0x001e)
 
-/** Diffie-Hellman key exchange public key. */
-#define PSA_KEY_TYPE_DH_PUBLIC_KEY             ((psa_key_type_t)0x60040000)
-/** Diffie-Hellman key exchange key pair (private and public key). */
-#define PSA_KEY_TYPE_DH_KEYPAIR                ((psa_key_type_t)0x70040000)
-/** Whether a key type is a Diffie-Hellman key exchange key (pair or
- * public-only). */
-#define PSA_KEY_TYPE_IS_DH(type)                                       \
-    (PSA_KEY_TYPE_PUBLIC_KEY_OF_KEYPAIR(type) == PSA_KEY_TYPE_DH_PUBLIC_KEY)
+#define PSA_KEY_TYPE_DH_PUBLIC_KEY_BASE         ((psa_key_type_t)0x60040000)
+#define PSA_KEY_TYPE_DH_KEYPAIR_BASE            ((psa_key_type_t)0x70040000)
+#define PSA_KEY_TYPE_DH_GROUP_MASK              ((psa_key_type_t)0x0000ffff)
+/** Diffie-Hellman key pair. */
+#define PSA_KEY_TYPE_DH_KEYPAIR(group)          \
+    (PSA_KEY_TYPE_DH_KEYPAIR_BASE | (group))
+/** Diffie-Hellman public key. */
+#define PSA_KEY_TYPE_DH_PUBLIC_KEY(group)               \
+    (PSA_KEY_TYPE_DH_PUBLIC_KEY_BASE | (group))
+
+/** Whether a key type is a Diffie-Hellman key (pair or public-only). */
+#define PSA_KEY_TYPE_IS_DH(type)                                        \
+    ((PSA_KEY_TYPE_PUBLIC_KEY_OF_KEYPAIR(type) &                        \
+      ~PSA_KEY_TYPE_DH_GROUP_MASK) == PSA_KEY_TYPE_DH_PUBLIC_KEY_BASE)
+/** Whether a key type is a Diffie-Hellman key pair. */
+#define PSA_KEY_TYPE_IS_DH_KEYPAIR(type)                               \
+    (((type) & ~PSA_KEY_TYPE_DH_GROUP_MASK) ==                         \
+     PSA_KEY_TYPE_DH_KEYPAIR_BASE)
+/** Whether a key type is a Diffie-Hellman public key. */
+#define PSA_KEY_TYPE_IS_DH_PUBLIC_KEY(type)                            \
+    (((type) & ~PSA_KEY_TYPE_DH_GROUP_MASK) ==                         \
+     PSA_KEY_TYPE_DH_PUBLIC_KEY_BASE)
+
+/** Extract the group from a Diffie-Hellman key type. */
+#define PSA_KEY_TYPE_GET_GROUP(type)                            \
+    ((psa_dh_group_t) (PSA_KEY_TYPE_IS_DH(type) ?               \
+                       ((type) & PSA_KEY_TYPE_DH_GROUP_MASK) :  \
+                       0))
+
+/* The encoding of group identifiers is currently aligned with the
+ * TLS Supported Groups Registry (formerly known as the
+ * TLS EC Named Curve Registry)
+ * https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-8
+ * The values are defined by RFC 7919. */
+#define PSA_DH_GROUP_FFDHE2048          ((psa_dh_group_t) 0x0100)
+#define PSA_DH_GROUP_FFDHE3072          ((psa_dh_group_t) 0x0101)
+#define PSA_DH_GROUP_FFDHE4096          ((psa_dh_group_t) 0x0102)
+#define PSA_DH_GROUP_FFDHE6144          ((psa_dh_group_t) 0x0103)
+#define PSA_DH_GROUP_FFDHE8192          ((psa_dh_group_t) 0x0104)
 
 /** The block size of a block cipher.
  *
@@ -667,7 +690,6 @@
  *
  * That is, suppose that `PSA_xxx_SIGNATURE` is one of the following macros:
  * - #PSA_ALG_RSA_PKCS1V15_SIGN, #PSA_ALG_RSA_PSS,
- * - #PSA_ALG_DSA, #PSA_ALG_DETERMINISTIC_DSA,
  * - #PSA_ALG_ECDSA, #PSA_ALG_DETERMINISTIC_ECDSA.
  * Then you may create and use a key as follows:
  * - Set the key usage field using #PSA_ALG_ANY_HASH, for example:
@@ -1028,51 +1050,6 @@
 #define PSA_ALG_IS_RSA_PSS(alg)                                 \
     (((alg) & ~PSA_ALG_HASH_MASK) == PSA_ALG_RSA_PSS_BASE)
 
-#define PSA_ALG_DSA_BASE                        ((psa_algorithm_t)0x10040000)
-/** DSA signature with hashing.
- *
- * This is the signature scheme defined by FIPS 186-4,
- * with a random per-message secret number (*k*).
- *
- * \param hash_alg      A hash algorithm (\c PSA_ALG_XXX value such that
- *                      #PSA_ALG_IS_HASH(\p hash_alg) is true).
- *                      This includes #PSA_ALG_ANY_HASH
- *                      when specifying the algorithm in a usage policy.
- *
- * \return              The corresponding DSA signature algorithm.
- * \return              Unspecified if \p hash_alg is not a supported
- *                      hash algorithm.
- */
-#define PSA_ALG_DSA(hash_alg)                             \
-    (PSA_ALG_DSA_BASE | ((hash_alg) & PSA_ALG_HASH_MASK))
-#define PSA_ALG_DETERMINISTIC_DSA_BASE          ((psa_algorithm_t)0x10050000)
-#define PSA_ALG_DSA_DETERMINISTIC_FLAG          ((psa_algorithm_t)0x00010000)
-/** Deterministic DSA signature with hashing.
- *
- * This is the deterministic variant defined by RFC 6979 of
- * the signature scheme defined by FIPS 186-4.
- *
- * \param hash_alg      A hash algorithm (\c PSA_ALG_XXX value such that
- *                      #PSA_ALG_IS_HASH(\p hash_alg) is true).
- *                      This includes #PSA_ALG_ANY_HASH
- *                      when specifying the algorithm in a usage policy.
- *
- * \return              The corresponding DSA signature algorithm.
- * \return              Unspecified if \p hash_alg is not a supported
- *                      hash algorithm.
- */
-#define PSA_ALG_DETERMINISTIC_DSA(hash_alg)                             \
-    (PSA_ALG_DETERMINISTIC_DSA_BASE | ((hash_alg) & PSA_ALG_HASH_MASK))
-#define PSA_ALG_IS_DSA(alg)                                             \
-    (((alg) & ~PSA_ALG_HASH_MASK & ~PSA_ALG_DSA_DETERMINISTIC_FLAG) ==  \
-     PSA_ALG_DSA_BASE)
-#define PSA_ALG_DSA_IS_DETERMINISTIC(alg)               \
-    (((alg) & PSA_ALG_DSA_DETERMINISTIC_FLAG) != 0)
-#define PSA_ALG_IS_DETERMINISTIC_DSA(alg)                       \
-    (PSA_ALG_IS_DSA(alg) && PSA_ALG_DSA_IS_DETERMINISTIC(alg))
-#define PSA_ALG_IS_RANDOMIZED_DSA(alg)                          \
-    (PSA_ALG_IS_DSA(alg) && !PSA_ALG_DSA_IS_DETERMINISTIC(alg))
-
 #define PSA_ALG_ECDSA_BASE                      ((psa_algorithm_t)0x10060000)
 /** ECDSA signature with hashing.
  *
@@ -1156,7 +1133,7 @@
  */
 #define PSA_ALG_IS_HASH_AND_SIGN(alg)                                   \
     (PSA_ALG_IS_RSA_PSS(alg) || PSA_ALG_IS_RSA_PKCS1V15_SIGN(alg) ||    \
-     PSA_ALG_IS_DSA(alg) || PSA_ALG_IS_ECDSA(alg))
+     PSA_ALG_IS_ECDSA(alg))
 
 /** Get the hash used by a hash-and-sign signature algorithm.
  *
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);
diff --git a/scripts/generate_psa_constants.py b/scripts/generate_psa_constants.py
index dac6003..ab7f134 100755
--- a/scripts/generate_psa_constants.py
+++ b/scripts/generate_psa_constants.py
@@ -22,6 +22,14 @@
     }
 }
 
+static const char *psa_dh_group_name(psa_dh_group_t group)
+{
+    switch (group) {
+    %(dh_group_cases)s
+    default: return NULL;
+    }
+}
+
 static const char *psa_hash_algorithm_name(psa_algorithm_t hash_alg)
 {
     switch (hash_alg) {
@@ -145,6 +153,12 @@
                               PSA_KEY_TYPE_GET_CURVE(type));
         } else '''
 
+key_type_from_group_template = '''if (%(tester)s(type)) {
+            append_with_group(&buffer, buffer_size, &required_size,
+                              "%(builder)s", %(builder_length)s,
+                              PSA_KEY_TYPE_GET_GROUP(type));
+        } else '''
+
 algorithm_from_hash_template = '''if (%(tester)s(core_alg)) {
             append(&buffer, buffer_size, &required_size,
                    "%(builder)s(", %(builder_length)s + 1);
@@ -169,7 +183,9 @@
         self.statuses = set()
         self.key_types = set()
         self.key_types_from_curve = {}
+        self.key_types_from_group = {}
         self.ecc_curves = set()
+        self.dh_groups = set()
         self.algorithms = set()
         self.hash_algorithms = set()
         self.ka_algorithms = set()
@@ -206,8 +222,12 @@
             self.key_types.add(name)
         elif name.startswith('PSA_KEY_TYPE_') and parameter == 'curve':
             self.key_types_from_curve[name] = name[:13] + 'IS_' + name[13:]
+        elif name.startswith('PSA_KEY_TYPE_') and parameter == 'group':
+            self.key_types_from_group[name] = name[:13] + 'IS_' + name[13:]
         elif name.startswith('PSA_ECC_CURVE_') and not parameter:
             self.ecc_curves.add(name)
+        elif name.startswith('PSA_DH_GROUP_') and not parameter:
+            self.dh_groups.add(name)
         elif name.startswith('PSA_ALG_') and not parameter:
             if name in ['PSA_ALG_ECDSA_BASE',
                         'PSA_ALG_RSA_PKCS1V15_SIGN_BASE']:
@@ -265,6 +285,10 @@
         return '\n    '.join(map(self.make_return_case,
                                  sorted(self.ecc_curves)))
 
+    def make_dh_group_cases(self):
+        return '\n    '.join(map(self.make_return_case,
+                                 sorted(self.dh_groups)))
+
     def make_key_type_cases(self):
         return '\n    '.join(map(self.make_append_case,
                                  sorted(self.key_types)))
@@ -274,11 +298,21 @@
                                                'builder_length': len(builder),
                                                'tester': tester}
 
-    def make_key_type_code(self):
+    def make_key_type_from_group_code(self, builder, tester):
+        return key_type_from_group_template % {'builder': builder,
+                                               'builder_length': len(builder),
+                                               'tester': tester}
+
+    def make_ecc_key_type_code(self):
         d = self.key_types_from_curve
         make = self.make_key_type_from_curve_code
         return ''.join([make(k, d[k]) for k in sorted(d.keys())])
 
+    def make_dh_key_type_code(self):
+        d = self.key_types_from_group
+        make = self.make_key_type_from_group_code
+        return ''.join([make(k, d[k]) for k in sorted(d.keys())])
+
     def make_hash_algorithm_cases(self):
         return '\n    '.join(map(self.make_return_case,
                                  sorted(self.hash_algorithms)))
@@ -309,8 +343,10 @@
         data = {}
         data['status_cases'] = self.make_status_cases()
         data['ecc_curve_cases'] = self.make_ecc_curve_cases()
+        data['dh_group_cases'] = self.make_dh_group_cases()
         data['key_type_cases'] = self.make_key_type_cases()
-        data['key_type_code'] = self.make_key_type_code()
+        data['key_type_code'] = (self.make_ecc_key_type_code() +
+                                 self.make_dh_key_type_code())
         data['hash_algorithm_cases'] = self.make_hash_algorithm_cases()
         data['ka_algorithm_cases'] = self.make_ka_algorithm_cases()
         data['algorithm_cases'] = self.make_algorithm_cases()
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 */