From 24f10f85e2d771d8eccd5b1f5674ac57327e8dc6 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Thu, 16 May 2019 12:18:32 +0200 Subject: [PATCH 1/6] Remove domain parameters from the official API Move psa_get_key_domain_parameters() and psa_set_key_domain_parameters() out of the official API and declare them to be implementation-specific extensions. Expand the documentation of psa_set_key_domain_parameters() a bit to explain how domain parameters are used. Remove all mentions of domain parameters from the documentation of API functions. This leaves DH and DSA effectively unusable. --- include/psa/crypto.h | 138 +++-------------------------------- include/psa/crypto_extra.h | 141 ++++++++++++++++++++++++++++++++++++ include/psa/crypto_sizes.h | 32 -------- include/psa/crypto_struct.h | 7 ++ 4 files changed, 160 insertions(+), 158 deletions(-) diff --git a/include/psa/crypto.h b/include/psa/crypto.h index 84026c91c..487fce822 100644 --- a/include/psa/crypto.h +++ b/include/psa/crypto.h @@ -105,8 +105,7 @@ psa_status_t psa_crypto_init(void); * 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 @@ psa_status_t psa_crypto_init(void); * * - 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 @@ psa_status_t psa_crypto_init(void); * 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_status_t psa_crypto_init(void); * 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 @@ static psa_algorithm_t psa_get_key_algorithm( /** 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 psa_key_type_t psa_get_key_type(const psa_key_attributes_t *attributes); */ 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 @@ psa_status_t psa_close_key(psa_key_handle_t handle); * \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 @@ -910,9 +813,6 @@ psa_status_t psa_export_public_key(psa_key_handle_t handle, * - 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 +836,7 @@ psa_status_t psa_export_public_key(psa_key_handle_t handle, * 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. @@ -3529,20 +3429,6 @@ psa_status_t psa_generate_random(uint8_t *output, * 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(). - * * \param[in] attributes The attributes for the new key. * \param[out] handle On success, a handle to the newly created key. * \c 0 on failure. diff --git a/include/psa/crypto_extra.h b/include/psa/crypto_extra.h index 45655ddfc..5016ba87c 100644 --- a/include/psa/crypto_extra.h +++ b/include/psa/crypto_extra.h @@ -444,6 +444,147 @@ psa_status_t psa_generate_random_key_to_handle(psa_key_handle_t handle, /**@}*/ + +/** \addtogroup 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. 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 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. + * + * \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 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*/) + +/**@}*/ + #ifdef __cplusplus } #endif diff --git a/include/psa/crypto_sizes.h b/include/psa/crypto_sizes.h index cab896e8a..11c73a9de 100644 --- a/include/psa/crypto_sizes.h +++ b/include/psa/crypto_sizes.h @@ -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 01d3069bf..885d90888 100644 --- a/include/psa/crypto_struct.h +++ b/include/psa/crypto_struct.h @@ -331,6 +331,13 @@ static inline psa_algorithm_t psa_get_key_algorithm( 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) { From dcaefae8491d955a230245ffd85b6daaa6630c0f Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Thu, 16 May 2019 12:55:35 +0200 Subject: [PATCH 2/6] 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. --- include/psa/crypto.h | 9 ++-- include/psa/crypto_extra.h | 15 +++++- include/psa/crypto_types.h | 3 ++ include/psa/crypto_values.h | 47 +++++++++++++++---- programs/psa/psa_constant_names.c | 45 ++++++++++++++++++ scripts/generate_psa_constants.py | 40 +++++++++++++++- tests/scripts/test_psa_constant_names.py | 6 +++ .../test_suite_psa_crypto_metadata.data | 16 +++++++ .../test_suite_psa_crypto_metadata.function | 27 +++++++++++ 9 files changed, 193 insertions(+), 15 deletions(-) diff --git a/include/psa/crypto.h b/include/psa/crypto.h index 487fce822..08bdb8468 100644 --- a/include/psa/crypto.h +++ b/include/psa/crypto.h @@ -656,7 +656,8 @@ psa_status_t psa_destroy_key(psa_key_handle_t handle); * 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). @@ -729,7 +730,8 @@ psa_status_t psa_export_key(psa_key_handle_t handle, * 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. @@ -3253,7 +3255,8 @@ psa_status_t psa_key_derivation_output_bytes( * 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), + * - Finite-field Diffie-Hellman keys (#PSA_KEY_TYPE_DH_KEYPAIR(\c group) + * where \c group designates any Diffie-Hellman group), * DSA keys (#PSA_KEY_TYPE_DSA_KEYPAIR), and * ECC keys on a Weierstrass elliptic curve * (#PSA_KEY_TYPE_ECC_KEYPAIR(\c curve) where \c curve designates a diff --git a/include/psa/crypto_extra.h b/include/psa/crypto_extra.h index 5016ba87c..37d9b40b2 100644 --- a/include/psa/crypto_extra.h +++ b/include/psa/crypto_extra.h @@ -449,6 +449,16 @@ psa_status_t psa_generate_random_key_to_handle(psa_key_handle_t handle, * @{ */ +/** 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. * @@ -475,8 +485,9 @@ psa_status_t psa_generate_random_key_to_handle(psa_key_handle_t handle, * g INTEGER * } * ``` - * - For Diffie-Hellman key exchange keys (#PSA_KEY_TYPE_DH_PUBLIC_KEY or - * #PSA_KEY_TYPE_DH_KEYPAIR), the + * - 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 { diff --git a/include/psa/crypto_types.h b/include/psa/crypto_types.h index ced42de1a..02c26788f 100644 --- a/include/psa/crypto_types.h +++ b/include/psa/crypto_types.h @@ -68,6 +68,9 @@ typedef uint32_t psa_key_type_t; /** 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 c54fc9a60..6cd22c840 100644 --- a/include/psa/crypto_values.h +++ b/include/psa/crypto_values.h @@ -492,14 +492,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. * diff --git a/programs/psa/psa_constant_names.c b/programs/psa/psa_constant_names.c index 5240b084a..73692d022 100644 --- a/programs/psa/psa_constant_names.c +++ b/programs/psa/psa_constant_names.c @@ -64,6 +64,7 @@ static void append_integer(char **buffer, size_t buffer_size, /* 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 @@ static void append_with_curve(char **buffer, size_t buffer_size, 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_ecc_curve(char *buffer, size_t buffer_size, } } +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 @@ static void usage(const char *program_name) 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 @@ int process_signed(signed_value_type type, long min, long max, char **argp) typedef enum { TYPE_ALGORITHM, TYPE_ECC_CURVE, + TYPE_DH_GROUP, TYPE_KEY_TYPE, TYPE_KEY_USAGE, } unsigned_value_type; @@ -216,6 +254,10 @@ int process_unsigned(unsigned_value_type type, unsigned long max, char **argp) 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 @@ int main(int argc, char *argv[]) } 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 dac60034d..ab7f1341f 100755 --- a/scripts/generate_psa_constants.py +++ b/scripts/generate_psa_constants.py @@ -22,6 +22,14 @@ static const char *psa_ecc_curve_name(psa_ecc_curve_t curve) } } +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 @@ key_type_from_curve_template = '''if (%(tester)s(type)) { 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 @@ class MacroCollector: 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 @@ class MacroCollector: 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 @@ class MacroCollector: 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 @@ class MacroCollector: '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 @@ class MacroCollector: 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 421cf4e48..cbe68b10d 100755 --- a/tests/scripts/test_psa_constant_names.py +++ b/tests/scripts/test_psa_constant_names.py @@ -58,6 +58,7 @@ when applicable.''' 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 @@ when applicable.''' '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 @@ Call this after parsing all the inputs.''' 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 @@ where each argument takes each possible value at least once.''' 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 @@ not as expected.''' 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 94b80acdd..165b86654 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:PSA_ECC_CURVE_CURVE25519:255 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 e1eb1c526..81b2937fa 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 @@ void key_type_classification( psa_key_type_t type, unsigned flags ) 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 @@ void key_type_classification( psa_key_type_t type, unsigned flags ) 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 @@ void ecc_key_types( int curve_arg, int curve_bits_arg ) 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 */ From e38ab1ac4faef8e69306647cf7b577c5d9c23a02 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Thu, 16 May 2019 13:51:50 +0200 Subject: [PATCH 3/6] Move DSA definitions out of the specification Move DSA-related key types and algorithms to the implementation-specific header file. Not that we actually implement DSA, but with domain parameters, we should be able to. --- include/psa/crypto_extra.h | 67 +++++++++++++++++++++++++++++++++++++ include/psa/crypto_values.h | 55 +----------------------------- 2 files changed, 68 insertions(+), 54 deletions(-) diff --git a/include/psa/crypto_extra.h b/include/psa/crypto_extra.h index 37d9b40b2..5a066146b 100644 --- a/include/psa/crypto_extra.h +++ b/include/psa/crypto_extra.h @@ -445,6 +445,73 @@ psa_status_t psa_generate_random_key_to_handle(psa_key_handle_t handle, /**@}*/ +/** \addtogroup crypto_types + * @{ + */ + +/** 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_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 * @{ */ diff --git a/include/psa/crypto_values.h b/include/psa/crypto_values.h index 6cd22c840..823d04450 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) @@ -1059,51 +1051,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. * @@ -1187,7 +1134,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. * From a130219ac039c93245d5d95949f59076ff7f8e2c Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Thu, 16 May 2019 13:58:24 +0200 Subject: [PATCH 4/6] Move remaining text about DSA out of the specification --- include/psa/crypto.h | 11 +---------- include/psa/crypto_extra.h | 27 +++++++++++++++++++++++++-- include/psa/crypto_values.h | 1 - 3 files changed, 26 insertions(+), 13 deletions(-) diff --git a/include/psa/crypto.h b/include/psa/crypto.h index 08bdb8468..2b95f238f 100644 --- a/include/psa/crypto.h +++ b/include/psa/crypto.h @@ -641,10 +641,6 @@ psa_status_t psa_destroy_key(psa_key_handle_t handle); * 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 @@ -726,10 +722,6 @@ psa_status_t psa_export_key(psa_key_handle_t handle, * - 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 (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 @@ -3256,8 +3248,7 @@ psa_status_t psa_key_derivation_output_bytes( * and continue reading output from the operation to derive the other * two keys). * - Finite-field Diffie-Hellman keys (#PSA_KEY_TYPE_DH_KEYPAIR(\c group) - * where \c group designates any Diffie-Hellman group), - * DSA keys (#PSA_KEY_TYPE_DSA_KEYPAIR), and + * 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). diff --git a/include/psa/crypto_extra.h b/include/psa/crypto_extra.h index 5a066146b..732149dcd 100644 --- a/include/psa/crypto_extra.h +++ b/include/psa/crypto_extra.h @@ -449,10 +449,33 @@ psa_status_t psa_generate_random_key_to_handle(psa_key_handle_t handle, * @{ */ -/** DSA public key. */ +/** 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). */ + +/** 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) diff --git a/include/psa/crypto_values.h b/include/psa/crypto_values.h index 823d04450..bab706339 100644 --- a/include/psa/crypto_values.h +++ b/include/psa/crypto_values.h @@ -690,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: From 20a77aeac728f0d0529cae4261093f149e1593ce Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Thu, 16 May 2019 14:05:56 +0200 Subject: [PATCH 5/6] RSA key generation: require e=65537 --- include/psa/crypto.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/include/psa/crypto.h b/include/psa/crypto.h index 2b95f238f..c6a13acb8 100644 --- a/include/psa/crypto.h +++ b/include/psa/crypto.h @@ -3423,6 +3423,13 @@ psa_status_t psa_generate_random(uint8_t *output, * The key is generated randomly. * Its location, policy, type and size are taken from \p attributes. * + * 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. * \c 0 on failure. From 27a983d93c40bc63e5b74e4552dbe81216e96398 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Thu, 16 May 2019 17:24:53 +0200 Subject: [PATCH 6/6] Grammar fix --- include/psa/crypto_extra.h | 2 +- include/psa/crypto_sizes.h | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/include/psa/crypto_extra.h b/include/psa/crypto_extra.h index 732149dcd..4ffd858e4 100644 --- a/include/psa/crypto_extra.h +++ b/include/psa/crypto_extra.h @@ -669,7 +669,7 @@ psa_status_t psa_get_key_domain_parameters( * 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 + * by the implementation, this macro shall return either a * sensible size or 0. * If the parameters are not valid, the * return value is unspecified. diff --git a/include/psa/crypto_sizes.h b/include/psa/crypto_sizes.h index 11c73a9de..d7eb48272 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.