Remove extra parameter from psa_generate_key

Read extra data from the domain parameters in the attribute structure
instead of taking an argument on the function call.

Implement this for RSA key generation, where the public exponent can
be set as a domain parameter.

Add tests that generate RSA keys with various public exponents.
This commit is contained in:
Gilles Peskine 2019-04-26 17:34:02 +02:00
parent 772c8b16b4
commit e56e878207
7 changed files with 205 additions and 88 deletions

View file

@ -510,7 +510,7 @@ Generate a piece of random 128-bit AES data:
psa_set_key_policy(slot, &policy);
/* Generate a key */
psa_generate_key(slot, PSA_KEY_TYPE_AES, bits, NULL, 0);
psa_generate_key(slot, PSA_KEY_TYPE_AES, bits);
psa_export_key(slot, exported, exported_size, &exported_length)

View file

@ -339,12 +339,15 @@ static size_t psa_get_key_bits(const psa_key_attributes_t *attributes);
* 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
* - 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.
* - For DSA public keys (#PSA_KEY_TYPE_DSA_PUBLIC_KEY),
* 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 {
@ -353,7 +356,8 @@ static size_t psa_get_key_bits(const psa_key_attributes_t *attributes);
* g INTEGER
* }
* ```
* - For Diffie-Hellman key exchange keys (#PSA_KEY_TYPE_DH_PUBLIC_KEY), the
* - 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 {
@ -3354,57 +3358,29 @@ psa_status_t psa_key_agreement_raw_shared_secret(psa_algorithm_t alg,
psa_status_t psa_generate_random(uint8_t *output,
size_t output_size);
/** Extra parameters for RSA key generation.
*
* You may pass a pointer to a structure of this type as the \c extra
* parameter to psa_generate_key().
*/
typedef struct {
uint32_t e; /**< Public exponent value. Default: 65537. */
} psa_generate_key_extra_rsa;
/**
* \brief Generate a key or key pair.
*
* 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.
* \param[in] extra Extra parameters for key generation. The
* interpretation of this parameter depends on
* the key type \c type. All types support \c NULL to
* use default parameters. Implementation that support
* the generation of vendor-specific key types
* that allow extra parameters shall document
* the format of these extra parameters and
* the default values. For standard parameters,
* the meaning of \p extra is as follows:
* - For a symmetric key type (a type such
* that #PSA_KEY_TYPE_IS_ASYMMETRIC(\c type) is
* false), \p extra must be \c NULL.
* - For an elliptic curve key type (a type
* such that #PSA_KEY_TYPE_IS_ECC(\c type) is
* false), \p extra must be \c NULL.
* - For an RSA key (\c type is
* #PSA_KEY_TYPE_RSA_KEYPAIR), \p extra is an
* optional #psa_generate_key_extra_rsa structure
* specifying the public exponent. The
* default public exponent used when \p extra
* is \c NULL is 65537.
* - For an DSA key (\c type is
* #PSA_KEY_TYPE_DSA_KEYPAIR), \p extra is an
* optional structure specifying the key domain
* parameters. The key domain parameters can also be
* provided by psa_set_key_domain_parameters(),
* which documents the format of the structure.
* - For a DH key (\c type is
* #PSA_KEY_TYPE_DH_KEYPAIR), the \p extra is an
* optional structure specifying the key domain
* parameters. The key domain parameters can also be
* provided by psa_set_key_domain_parameters(),
* which documents the format of the structure.
* \param extra_size Size of the buffer that \p extra
* points to, in bytes. Note that if \p extra is
* \c NULL then \p extra_size must be zero.
*
* \retval #PSA_SUCCESS
* Success.
@ -3426,9 +3402,7 @@ typedef struct {
* results in this error code.
*/
psa_status_t psa_generate_key(const psa_key_attributes_t *attributes,
psa_key_handle_t *handle,
const void *extra,
size_t extra_size);
psa_key_handle_t *handle);
/**@}*/

View file

@ -5098,14 +5098,41 @@ psa_status_t mbedtls_psa_inject_entropy( const unsigned char *seed,
}
#endif /* MBEDTLS_PSA_INJECT_ENTROPY */
static psa_status_t psa_generate_key_internal( psa_key_slot_t *slot,
size_t bits,
const void *extra,
size_t extra_size )
#if defined(MBEDTLS_RSA_C) && defined(MBEDTLS_GENPRIME)
static psa_status_t psa_read_rsa_exponent( const uint8_t *domain_parameters,
size_t domain_parameters_size,
int *exponent )
{
size_t i;
uint32_t acc = 0;
if( domain_parameters_size == 0 )
{
*exponent = 65537;
return( PSA_SUCCESS );
}
/* Mbed TLS encodes the public exponent as an int. For simplicity, only
* support values that fit in a 32-bit integer, which is larger than
* int on just about every platform anyway. */
if( domain_parameters_size > sizeof( acc ) )
return( PSA_ERROR_NOT_SUPPORTED );
for( i = 0; i < domain_parameters_size; i++ )
acc = ( acc << 8 ) | domain_parameters[i];
if( acc > INT_MAX )
return( PSA_ERROR_NOT_SUPPORTED );
*exponent = acc;
return( PSA_SUCCESS );
}
#endif /* MBEDTLS_RSA_C && MBEDTLS_GENPRIME */
static psa_status_t psa_generate_key_internal(
psa_key_slot_t *slot, size_t bits,
const uint8_t *domain_parameters, size_t domain_parameters_size )
{
psa_key_type_t type = slot->type;
if( extra == NULL && extra_size != 0 )
if( domain_parameters == NULL && domain_parameters_size != 0 )
return( PSA_ERROR_INVALID_ARGUMENT );
if( key_type_is_raw_bytes( type ) )
@ -5134,26 +5161,19 @@ static psa_status_t psa_generate_key_internal( psa_key_slot_t *slot,
{
mbedtls_rsa_context *rsa;
int ret;
int exponent = 65537;
int exponent;
psa_status_t status;
if( bits > PSA_VENDOR_RSA_MAX_KEY_BITS )
return( PSA_ERROR_NOT_SUPPORTED );
/* Accept only byte-aligned keys, for the same reasons as
* in psa_import_rsa_key(). */
if( bits % 8 != 0 )
return( PSA_ERROR_NOT_SUPPORTED );
if( extra != NULL )
{
const psa_generate_key_extra_rsa *p = extra;
if( extra_size != sizeof( *p ) )
return( PSA_ERROR_INVALID_ARGUMENT );
#if INT_MAX < 0xffffffff
/* Check that the uint32_t value passed by the caller fits
* in the range supported by this implementation. */
if( p->e > INT_MAX )
return( PSA_ERROR_NOT_SUPPORTED );
#endif
exponent = p->e;
}
status = psa_read_rsa_exponent( domain_parameters,
domain_parameters_size,
&exponent );
if( status != PSA_SUCCESS )
return( status );
rsa = mbedtls_calloc( 1, sizeof( *rsa ) );
if( rsa == NULL )
return( PSA_ERROR_INSUFFICIENT_MEMORY );
@ -5183,7 +5203,7 @@ static psa_status_t psa_generate_key_internal( psa_key_slot_t *slot,
mbedtls_ecp_curve_info_from_grp_id( grp_id );
mbedtls_ecp_keypair *ecp;
int ret;
if( extra != NULL )
if( domain_parameters_size != 0 )
return( PSA_ERROR_NOT_SUPPORTED );
if( grp_id == MBEDTLS_ECP_DP_NONE || curve_info == NULL )
return( PSA_ERROR_NOT_SUPPORTED );
@ -5221,6 +5241,12 @@ psa_status_t psa_generate_key_to_handle( psa_key_handle_t handle,
psa_key_slot_t *slot;
psa_status_t status;
#if defined(MBEDTLS_RSA_C) && defined(MBEDTLS_GENPRIME)
/* The old public exponent encoding is no longer supported. */
if( extra_size != 0 )
return( PSA_ERROR_NOT_SUPPORTED );
#endif
status = psa_get_empty_key_slot( handle, &slot );
if( status != PSA_SUCCESS )
return( status );
@ -5241,17 +5267,16 @@ psa_status_t psa_generate_key_to_handle( psa_key_handle_t handle,
}
psa_status_t psa_generate_key( const psa_key_attributes_t *attributes,
psa_key_handle_t *handle,
const void *extra,
size_t extra_size )
psa_key_handle_t *handle )
{
psa_status_t status;
psa_key_slot_t *slot = NULL;
status = psa_start_key_creation( attributes, handle, &slot );
if( status == PSA_SUCCESS )
{
status = psa_generate_key_internal( slot, attributes->bits,
extra, extra_size );
status = psa_generate_key_internal(
slot, attributes->bits,
attributes->domain_parameters, attributes->domain_parameters_size );
}
if( status == PSA_SUCCESS )
status = psa_finish_key_creation( slot );

View file

@ -164,7 +164,7 @@ cipher_example_encrypt_decrypt_aes_cbc_nopad_1_block( void )
psa_set_key_type( &attributes, PSA_KEY_TYPE_AES );
psa_set_key_bits( &attributes, key_bits );
status = psa_generate_key( &attributes, &key_handle, NULL, 0 );
status = psa_generate_key( &attributes, &key_handle );
ASSERT_STATUS( status, PSA_SUCCESS );
status = cipher_encrypt( key_handle, alg, iv, sizeof( iv ),
@ -215,7 +215,7 @@ static psa_status_t cipher_example_encrypt_decrypt_aes_cbc_pkcs7_multi( void )
psa_set_key_type( &attributes, PSA_KEY_TYPE_AES );
psa_set_key_bits( &attributes, key_bits );
status = psa_generate_key( &attributes, &key_handle, NULL, 0 );
status = psa_generate_key( &attributes, &key_handle );
ASSERT_STATUS( status, PSA_SUCCESS );
status = cipher_encrypt( key_handle, alg, iv, sizeof( iv ),
@ -262,7 +262,7 @@ static psa_status_t cipher_example_encrypt_decrypt_aes_ctr_multi( void )
psa_set_key_type( &attributes, PSA_KEY_TYPE_AES );
psa_set_key_bits( &attributes, key_bits );
status = psa_generate_key( &attributes, &key_handle, NULL, 0 );
status = psa_generate_key( &attributes, &key_handle );
ASSERT_STATUS( status, PSA_SUCCESS );
status = cipher_encrypt( key_handle, alg, iv, sizeof( iv ),

View file

@ -208,7 +208,7 @@ static psa_status_t generate( const char *key_file_name )
psa_set_key_type( &attributes, PSA_KEY_TYPE_DERIVE );
psa_set_key_bits( &attributes, PSA_BYTES_TO_BITS( KEY_SIZE_BYTES ) );
PSA_CHECK( psa_generate_key( &attributes, &key_handle, NULL, 0 ) );
PSA_CHECK( psa_generate_key( &attributes, &key_handle ) );
PSA_CHECK( save_key( key_handle, key_file_name ) );

View file

@ -2036,6 +2036,24 @@ PSA generate key: ECC, SECP256R1, incorrect bit size
depends_on:MBEDTLS_ECP_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_ECDSA_C
generate_key:PSA_KEY_TYPE_ECC_KEYPAIR(PSA_ECC_CURVE_SECP256R1):128:PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_SIGN | PSA_KEY_USAGE_VERIFY:PSA_ALG_ECDSA_ANY:PSA_ERROR_INVALID_ARGUMENT
PSA generate key: RSA, default e
generate_key_rsa:512:"":PSA_SUCCESS
PSA generate key: RSA, e=3
generate_key_rsa:512:"03":PSA_SUCCESS
PSA generate key: RSA, e=65537
generate_key_rsa:512:"010001":PSA_SUCCESS
PSA generate key: RSA, e=513
generate_key_rsa:512:"0201":PSA_SUCCESS
PSA generate key: RSA, e=1
generate_key_rsa:512:"01":PSA_ERROR_INVALID_ARGUMENT
PSA generate key: RSA, e=2
generate_key_rsa:512:"01":PSA_ERROR_INVALID_ARGUMENT
PSA import persistent key: raw data, 0 bits
depends_on:MBEDTLS_PK_C:MBEDTLS_PK_PARSE_C:MBEDTLS_RSA_C:MBEDTLS_PSA_CRYPTO_STORAGE_C
persistent_key_load_key_from_storage:"":PSA_KEY_TYPE_RAW_DATA:0:PSA_KEY_USAGE_EXPORT:0:IMPORT_KEY

View file

@ -4684,8 +4684,6 @@ void generate_key( int type_arg,
size_t bits = bits_arg;
psa_algorithm_t alg = alg_arg;
psa_status_t expected_status = expected_status_arg;
psa_status_t expected_info_status =
expected_status == PSA_SUCCESS ? PSA_SUCCESS : PSA_ERROR_DOES_NOT_EXIST;
psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
psa_key_attributes_t got_attributes = PSA_KEY_ATTRIBUTES_INIT;
@ -4697,9 +4695,8 @@ void generate_key( int type_arg,
psa_set_key_bits( &attributes, bits );
/* Generate a key */
TEST_EQUAL( psa_generate_key( &attributes, &handle, NULL, 0 ),
expected_status );
if( expected_info_status != PSA_SUCCESS )
TEST_EQUAL( psa_generate_key( &attributes, &handle ), expected_status );
if( expected_status != PSA_SUCCESS )
goto exit;
/* Test the key information */
@ -4718,6 +4715,109 @@ exit:
}
/* END_CASE */
/* BEGIN_CASE depends_on:MBEDTLS_RSA_C:MBEDTLS_GENPRIME:MBEDTLS_PKCS1_V15 */
void generate_key_rsa( int bits_arg,
data_t *e_arg,
int expected_status_arg )
{
psa_key_handle_t handle = 0;
psa_key_type_t type = PSA_KEY_TYPE_RSA_KEYPAIR;
size_t bits = bits_arg;
psa_key_usage_t usage = PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT;
psa_algorithm_t alg = PSA_ALG_RSA_PKCS1V15_SIGN_RAW;
psa_status_t expected_status = expected_status_arg;
psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
uint8_t *exported = NULL;
size_t exported_size =
PSA_KEY_EXPORT_MAX_SIZE( PSA_KEY_TYPE_RSA_PUBLIC_KEY, bits );
size_t exported_length = SIZE_MAX;
uint8_t *e_read_buffer = NULL;
int is_default_public_exponent = 0;
size_t e_read_size = e_arg->len;
size_t e_read_length = SIZE_MAX;
if( e_arg->len == 0 ||
( e_arg->len == 3 &&
e_arg->x[0] == 1 && e_arg->x[1] == 0 && e_arg->x[2] == 1 ) )
{
is_default_public_exponent = 1;
e_read_size = 0;
}
ASSERT_ALLOC( e_read_buffer, e_read_size );
ASSERT_ALLOC( exported, exported_size );
PSA_ASSERT( psa_crypto_init( ) );
psa_set_key_usage_flags( &attributes, usage );
psa_set_key_algorithm( &attributes, alg );
PSA_ASSERT( psa_set_key_domain_parameters( &attributes, type,
e_arg->x, e_arg->len ) );
psa_set_key_bits( &attributes, bits );
/* Generate a key */
TEST_EQUAL( psa_generate_key( &attributes, &handle ), expected_status );
if( expected_status != PSA_SUCCESS )
goto exit;
/* Test the key information */
PSA_ASSERT( psa_get_key_attributes( handle, &attributes ) );
TEST_EQUAL( psa_get_key_type( &attributes ), type );
TEST_EQUAL( psa_get_key_bits( &attributes ), bits );
PSA_ASSERT( psa_get_key_domain_parameters( &attributes,
e_read_buffer, e_read_size,
&e_read_length ) );
if( is_default_public_exponent )
TEST_EQUAL( e_read_length, 0 );
else
ASSERT_COMPARE( e_read_buffer, e_read_length, e_arg->x, e_arg->len );
/* Do something with the key according to its type and permitted usage. */
if( ! exercise_key( handle, usage, alg ) )
goto exit;
/* Export the key and check the public exponent. */
PSA_ASSERT( psa_export_public_key( handle,
exported, exported_size,
&exported_length ) );
{
uint8_t *p = exported;
uint8_t *end = exported + exported_length;
size_t len;
/* RSAPublicKey ::= SEQUENCE {
* modulus INTEGER, -- n
* publicExponent INTEGER } -- e
*/
TEST_EQUAL( 0, mbedtls_asn1_get_tag( &p, end, &len,
MBEDTLS_ASN1_SEQUENCE |
MBEDTLS_ASN1_CONSTRUCTED ) );
TEST_ASSERT( asn1_skip_integer( &p, end, bits, bits, 1 ) );
TEST_EQUAL( 0, mbedtls_asn1_get_tag( &p, end, &len,
MBEDTLS_ASN1_INTEGER ) );
if( len >= 1 && p[0] == 0 )
{
++p;
--len;
}
if( e_arg->len == 0 )
{
TEST_EQUAL( len, 3 );
TEST_EQUAL( p[0], 1 );
TEST_EQUAL( p[1], 0 );
TEST_EQUAL( p[2], 1 );
}
else
ASSERT_COMPARE( p, len, e_arg->x, e_arg->len );
}
exit:
psa_reset_key_attributes( &attributes );
psa_destroy_key( handle );
mbedtls_psa_crypto_free( );
mbedtls_free( e_read_buffer );
mbedtls_free( exported );
}
/* END_CASE */
/* BEGIN_CASE depends_on:MBEDTLS_PSA_CRYPTO_STORAGE_C */
void persistent_key_load_key_from_storage( data_t *data,
int type_arg, int bits_arg,
@ -4763,7 +4863,7 @@ void persistent_key_load_key_from_storage( data_t *data,
case GENERATE_KEY:
/* Generate a key */
PSA_ASSERT( psa_generate_key( &attributes, &handle, NULL, 0 ) );
PSA_ASSERT( psa_generate_key( &attributes, &handle ) );
break;
case DERIVE_KEY: