diff --git a/include/psa/crypto.h b/include/psa/crypto.h index 2c3288ef84..1045cd4c76 100644 --- a/include/psa/crypto.h +++ b/include/psa/crypto.h @@ -332,6 +332,85 @@ 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, you can use this function to choose a non-default + * public exponent when generating a key. The public exponent is + * represented as a big-endian integer with no leading zeros. + * When importing a key, the public exponent is read from the imported + * key data and the exponent recorded in the attribute structure is ignored. + * - For DSA public keys (#PSA_KEY_TYPE_DSA_PUBLIC_KEY), + * 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), 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 + * } + * ``` + * + * \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. + * \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 @@ -542,106 +621,6 @@ psa_status_t psa_import_key(const psa_key_attributes_t *attributes, */ psa_status_t psa_destroy_key(psa_key_handle_t handle); -/** - * \brief Set domain parameters for a key. - * - * Some key types require additional domain parameters to be set before import - * or generation of the key. The domain parameters can be set with this - * function or, for key generation, through the \c extra parameter of - * psa_generate_key(). - * - * The format for the required domain parameters varies by the key type. - * - For DSA public keys (#PSA_KEY_TYPE_DSA_PUBLIC_KEY), - * 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), 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 - * } - * ``` - * - * \param handle Handle to the slot where the key will be stored. - * This must be a valid slot for a key of the chosen - * type: it must have been obtained by calling - * psa_allocate_key() or psa_create_key() with the - * correct \p type and with a maximum size that is - * compatible with \p data. It must not contain - * key material yet. - * \param type Key type (a \c PSA_KEY_TYPE_XXX value). When - * subsequently creating key material into \p handle, - * the type must be compatible. - * \param[in] data Buffer containing the key domain parameters. The content - * of this buffer is interpreted according to \p type. of - * psa_export_key() or psa_export_public_key() for the - * chosen type. - * \param data_length Size of the \p data buffer in bytes. - * - * \retval #PSA_SUCCESS - * \retval #PSA_ERROR_INVALID_HANDLE - * \retval #PSA_ERROR_OCCUPIED_SLOT - * There is already a key in the specified slot. - * \retval #PSA_ERROR_INVALID_ARGUMENT - * \retval #PSA_ERROR_COMMUNICATION_FAILURE - * \retval #PSA_ERROR_HARDWARE_FAILURE - * \retval #PSA_ERROR_TAMPERING_DETECTED - * \retval #PSA_ERROR_BAD_STATE - * The library has not been previously initialized by psa_crypto_init(). - * It is implementation-dependent whether a failure to initialize - * results in this error code. - */ -psa_status_t psa_set_key_domain_parameters(psa_key_handle_t handle, - 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 handle Handle to the key to get domain parameters from. - * \param[out] data On success, the key domain parameters. - * \param data_size Size of the \p data buffer in bytes. - * \param[out] data_length On success, the number of bytes - * that make up the key domain parameters data. - * - * \retval #PSA_SUCCESS - * \retval #PSA_ERROR_INVALID_HANDLE - * \retval #PSA_ERROR_EMPTY_SLOT - * There is no key in the specified slot. - * \retval #PSA_ERROR_INVALID_ARGUMENT - * \retval #PSA_ERROR_NOT_SUPPORTED - * \retval #PSA_ERROR_COMMUNICATION_FAILURE - * \retval #PSA_ERROR_HARDWARE_FAILURE - * \retval #PSA_ERROR_TAMPERING_DETECTED - * \retval #PSA_ERROR_BAD_STATE - * The library has not been previously initialized by psa_crypto_init(). - * It is implementation-dependent whether a failure to initialize - * results in this error code. - */ -psa_status_t psa_get_key_domain_parameters(psa_key_handle_t handle, - uint8_t *data, - size_t data_size, - size_t *data_length); - /** * \brief Export a key in binary format. * diff --git a/include/psa/crypto_struct.h b/include/psa/crypto_struct.h index f89073b16b..f6bec2cf5f 100644 --- a/include/psa/crypto_struct.h +++ b/include/psa/crypto_struct.h @@ -268,9 +268,11 @@ struct psa_key_attributes_s psa_key_policy_t policy; psa_key_type_t type; size_t bits; + void *domain_parameters; + size_t domain_parameters_size; }; -#define PSA_KEY_ATTRIBUTES_INIT {0, 0, {0, 0}, 0, 0} +#define PSA_KEY_ATTRIBUTES_INIT {0, 0, {0, 0}, 0, 0, NULL, 0} static inline struct psa_key_attributes_s psa_key_attributes_init( void ) { const struct psa_key_attributes_s v = PSA_KEY_ATTRIBUTES_INIT; @@ -324,7 +326,19 @@ static inline psa_algorithm_t psa_get_key_algorithm( static inline void psa_set_key_type(psa_key_attributes_t *attributes, psa_key_type_t type) { - attributes->type = type; + if( attributes->domain_parameters == NULL ) + { + /* Common case: quick path */ + attributes->type = type; + } + else + { + /* Call the bigger function to free the old domain paramteres. + * Ignore any errors which may arise due to type requiring + * non-default domain parameters, since this function can't + * report errors. */ + (void) psa_set_key_domain_parameters( attributes, type, NULL, 0 ); + } } static inline psa_key_type_t psa_get_key_type( diff --git a/library/psa_crypto.c b/library/psa_crypto.c index c1e3a3f1bd..fba1936475 100644 --- a/library/psa_crypto.c +++ b/library/psa_crypto.c @@ -983,9 +983,89 @@ static size_t psa_get_key_slot_bits( const psa_key_slot_t *slot ) void psa_reset_key_attributes( psa_key_attributes_t *attributes ) { + mbedtls_free( attributes->domain_parameters ); memset( attributes, 0, sizeof( *attributes ) ); } +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 ) +{ + uint8_t *copy = NULL; + + if( data_length != 0 ) + { + copy = mbedtls_calloc( 1, data_length ); + if( copy == NULL ) + return( PSA_ERROR_INSUFFICIENT_MEMORY ); + memcpy( copy, data, data_length ); + } + /* After this point, this function is guaranteed to succeed, so it + * can start modifying `*attributes`. */ + + if( attributes->domain_parameters != NULL ) + { + mbedtls_free( attributes->domain_parameters ); + attributes->domain_parameters = NULL; + attributes->domain_parameters_size = 0; + } + + attributes->domain_parameters = copy; + attributes->domain_parameters_size = data_length; + attributes->type = type; + return( PSA_SUCCESS ); +} + +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 ) +{ + if( attributes->domain_parameters_size > data_size ) + return( PSA_ERROR_BUFFER_TOO_SMALL ); + *data_length = attributes->domain_parameters_size; + if( attributes->domain_parameters_size != 0 ) + memcpy( data, attributes->domain_parameters, + attributes->domain_parameters_size ); + return( PSA_SUCCESS ); +} + +#if defined(MBEDTLS_RSA_C) +static psa_status_t psa_get_rsa_public_exponent( + const mbedtls_rsa_context *rsa, + psa_key_attributes_t *attributes ) +{ + mbedtls_mpi mpi; + int ret; + uint8_t *buffer = NULL; + size_t buflen; + mbedtls_mpi_init( &mpi ); + + ret = mbedtls_rsa_export( rsa, NULL, NULL, NULL, NULL, &mpi ); + if( ret != 0 ) + goto exit; + + buflen = mbedtls_mpi_size( &mpi ); + buffer = mbedtls_calloc( 1, buflen ); + if( buffer == NULL ) + { + ret = MBEDTLS_ERR_MPI_ALLOC_FAILED; + goto exit; + } + ret = mbedtls_mpi_write_binary( &mpi, buffer, buflen ); + if( ret != 0 ) + goto exit; + attributes->domain_parameters = buffer; + attributes->domain_parameters_size = buflen; + +exit: + mbedtls_mpi_free( &mpi ); + if( ret != 0 ) + mbedtls_free( buffer ); + return( mbedtls_to_psa_error( ret ) ); +} +#endif /* MBEDTLS_RSA_C */ + psa_status_t psa_get_key_attributes( psa_key_handle_t handle, psa_key_attributes_t *attributes ) { @@ -1003,7 +1083,23 @@ psa_status_t psa_get_key_attributes( psa_key_handle_t handle, attributes->policy = slot->policy; attributes->type = slot->type; attributes->bits = psa_get_key_slot_bits( slot ); - return( PSA_SUCCESS ); + + switch( slot->type ) + { +#if defined(MBEDTLS_RSA_C) + case PSA_KEY_TYPE_RSA_KEYPAIR: + case PSA_KEY_TYPE_RSA_PUBLIC_KEY: + status = psa_get_rsa_public_exponent( slot->data.rsa, attributes ); + break; +#endif + default: + /* Nothing else to do. */ + break; + } + + if( status != PSA_SUCCESS ) + psa_reset_key_attributes( attributes ); + return( status ); } psa_status_t psa_get_key_information( psa_key_handle_t handle,