1
0
mirror of https://github.com/Mbed-TLS/mbedtls.git synced 2025-07-28 00:21:48 +03:00

Merge pull request #4357 from gabor-mezei-arm/3267_Implement_psa_sign_message_and_verify

Implement psa_sign_message and psa_verify_message
This commit is contained in:
Gilles Peskine
2021-05-17 10:14:46 +02:00
committed by GitHub
14 changed files with 1808 additions and 320 deletions

View File

@ -1543,6 +1543,8 @@ static psa_status_t psa_validate_key_policy( const psa_key_policy_t *policy )
PSA_KEY_USAGE_COPY |
PSA_KEY_USAGE_ENCRYPT |
PSA_KEY_USAGE_DECRYPT |
PSA_KEY_USAGE_SIGN_MESSAGE |
PSA_KEY_USAGE_VERIFY_MESSAGE |
PSA_KEY_USAGE_SIGN_HASH |
PSA_KEY_USAGE_VERIFY_HASH |
PSA_KEY_USAGE_DERIVE ) ) != 0 )
@ -2508,7 +2510,254 @@ cleanup:
/* Asymmetric cryptography */
/****************************************************************/
psa_status_t psa_sign_hash_internal(
static psa_status_t psa_sign_verify_check_alg( int input_is_message,
psa_algorithm_t alg )
{
if( input_is_message )
{
if( ! PSA_ALG_IS_SIGN_MESSAGE( alg ) )
return( PSA_ERROR_INVALID_ARGUMENT );
if ( PSA_ALG_IS_HASH_AND_SIGN( alg ) )
{
if( ! PSA_ALG_IS_HASH( PSA_ALG_SIGN_GET_HASH( alg ) ) )
return( PSA_ERROR_INVALID_ARGUMENT );
}
}
else
{
if( ! PSA_ALG_IS_HASH_AND_SIGN( alg ) )
return( PSA_ERROR_INVALID_ARGUMENT );
}
return( PSA_SUCCESS );
}
static psa_status_t psa_sign_internal( mbedtls_svc_key_id_t key,
int input_is_message,
psa_algorithm_t alg,
const uint8_t * input,
size_t input_length,
uint8_t * signature,
size_t signature_size,
size_t * signature_length )
{
psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
psa_status_t unlock_status = PSA_ERROR_CORRUPTION_DETECTED;
psa_key_slot_t *slot;
*signature_length = 0;
status = psa_sign_verify_check_alg( input_is_message, alg );
if( status != PSA_SUCCESS )
return status;
/* Immediately reject a zero-length signature buffer. This guarantees
* that signature must be a valid pointer. (On the other hand, the input
* buffer can in principle be empty since it doesn't actually have
* to be a hash.) */
if( signature_size == 0 )
return( PSA_ERROR_BUFFER_TOO_SMALL );
status = psa_get_and_lock_key_slot_with_policy(
key, &slot,
input_is_message ? PSA_KEY_USAGE_SIGN_MESSAGE :
PSA_KEY_USAGE_SIGN_HASH,
alg );
if( status != PSA_SUCCESS )
goto exit;
if( ! PSA_KEY_TYPE_IS_KEY_PAIR( slot->attr.type ) )
{
status = PSA_ERROR_INVALID_ARGUMENT;
goto exit;
}
psa_key_attributes_t attributes = {
.core = slot->attr
};
if( input_is_message )
{
status = psa_driver_wrapper_sign_message(
&attributes, slot->key.data, slot->key.bytes,
alg, input, input_length,
signature, signature_size, signature_length );
}
else
{
status = psa_driver_wrapper_sign_hash(
&attributes, slot->key.data, slot->key.bytes,
alg, input, input_length,
signature, signature_size, signature_length );
}
exit:
/* Fill the unused part of the output buffer (the whole buffer on error,
* the trailing part on success) with something that isn't a valid signature
* (barring an attack on the signature and deliberately-crafted input),
* in case the caller doesn't check the return status properly. */
if( status == PSA_SUCCESS )
memset( signature + *signature_length, '!',
signature_size - *signature_length );
else
memset( signature, '!', signature_size );
/* If signature_size is 0 then we have nothing to do. We must not call
* memset because signature may be NULL in this case. */
unlock_status = psa_unlock_key_slot( slot );
return( ( status == PSA_SUCCESS ) ? unlock_status : status );
}
static psa_status_t psa_verify_internal( mbedtls_svc_key_id_t key,
int input_is_message,
psa_algorithm_t alg,
const uint8_t * input,
size_t input_length,
const uint8_t * signature,
size_t signature_length )
{
psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
psa_status_t unlock_status = PSA_ERROR_CORRUPTION_DETECTED;
psa_key_slot_t *slot;
status = psa_sign_verify_check_alg( input_is_message, alg );
if( status != PSA_SUCCESS )
return status;
status = psa_get_and_lock_key_slot_with_policy(
key, &slot,
input_is_message ? PSA_KEY_USAGE_VERIFY_MESSAGE :
PSA_KEY_USAGE_VERIFY_HASH,
alg );
if( status != PSA_SUCCESS )
return( status );
psa_key_attributes_t attributes = {
.core = slot->attr
};
if( input_is_message )
{
status = psa_driver_wrapper_verify_message(
&attributes, slot->key.data, slot->key.bytes,
alg, input, input_length,
signature, signature_length );
}
else
{
status = psa_driver_wrapper_verify_hash(
&attributes, slot->key.data, slot->key.bytes,
alg, input, input_length,
signature, signature_length );
}
unlock_status = psa_unlock_key_slot( slot );
return( ( status == PSA_SUCCESS ) ? unlock_status : status );
}
psa_status_t psa_sign_message_builtin(
const psa_key_attributes_t *attributes,
const uint8_t *key_buffer,
size_t key_buffer_size,
psa_algorithm_t alg,
const uint8_t *input,
size_t input_length,
uint8_t *signature,
size_t signature_size,
size_t *signature_length )
{
psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
if ( PSA_ALG_IS_HASH_AND_SIGN( alg ) )
{
size_t hash_length;
uint8_t hash[PSA_HASH_MAX_SIZE];
status = psa_driver_wrapper_hash_compute(
PSA_ALG_SIGN_GET_HASH( alg ),
input, input_length,
hash, sizeof( hash ), &hash_length );
if( status != PSA_SUCCESS )
return status;
return psa_driver_wrapper_sign_hash(
attributes, key_buffer, key_buffer_size,
alg, hash, hash_length,
signature, signature_size, signature_length );
}
return( PSA_ERROR_NOT_SUPPORTED );
}
psa_status_t psa_sign_message( mbedtls_svc_key_id_t key,
psa_algorithm_t alg,
const uint8_t * input,
size_t input_length,
uint8_t * signature,
size_t signature_size,
size_t * signature_length )
{
return psa_sign_internal(
key, 1, alg, input, input_length,
signature, signature_size, signature_length );
}
psa_status_t psa_verify_message_builtin(
const psa_key_attributes_t *attributes,
const uint8_t *key_buffer,
size_t key_buffer_size,
psa_algorithm_t alg,
const uint8_t *input,
size_t input_length,
const uint8_t *signature,
size_t signature_length )
{
psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
if ( PSA_ALG_IS_HASH_AND_SIGN( alg ) )
{
size_t hash_length;
uint8_t hash[PSA_HASH_MAX_SIZE];
status = psa_driver_wrapper_hash_compute(
PSA_ALG_SIGN_GET_HASH( alg ),
input, input_length,
hash, sizeof( hash ), &hash_length );
if( status != PSA_SUCCESS )
return status;
return psa_driver_wrapper_verify_hash(
attributes, key_buffer, key_buffer_size,
alg, hash, hash_length,
signature, signature_length );
}
return( PSA_ERROR_NOT_SUPPORTED );
}
psa_status_t psa_verify_message( mbedtls_svc_key_id_t key,
psa_algorithm_t alg,
const uint8_t * input,
size_t input_length,
const uint8_t * signature,
size_t signature_length )
{
return psa_verify_internal(
key, 1, alg, input, input_length,
signature, signature_length );
}
psa_status_t psa_sign_hash_builtin(
const psa_key_attributes_t *attributes,
const uint8_t *key_buffer, size_t key_buffer_size,
psa_algorithm_t alg, const uint8_t *hash, size_t hash_length,
@ -2574,57 +2823,12 @@ psa_status_t psa_sign_hash( mbedtls_svc_key_id_t key,
size_t signature_size,
size_t *signature_length )
{
psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
psa_status_t unlock_status = PSA_ERROR_CORRUPTION_DETECTED;
psa_key_slot_t *slot;
*signature_length = signature_size;
/* Immediately reject a zero-length signature buffer. This guarantees
* that signature must be a valid pointer. (On the other hand, the hash
* buffer can in principle be empty since it doesn't actually have
* to be a hash.) */
if( signature_size == 0 )
return( PSA_ERROR_BUFFER_TOO_SMALL );
status = psa_get_and_lock_key_slot_with_policy( key, &slot,
PSA_KEY_USAGE_SIGN_HASH,
alg );
if( status != PSA_SUCCESS )
goto exit;
if( ! PSA_KEY_TYPE_IS_KEY_PAIR( slot->attr.type ) )
{
status = PSA_ERROR_INVALID_ARGUMENT;
goto exit;
}
psa_key_attributes_t attributes = {
.core = slot->attr
};
status = psa_driver_wrapper_sign_hash(
&attributes, slot->key.data, slot->key.bytes,
alg, hash, hash_length,
return psa_sign_internal(
key, 0, alg, hash, hash_length,
signature, signature_size, signature_length );
exit:
/* Fill the unused part of the output buffer (the whole buffer on error,
* the trailing part on success) with something that isn't a valid mac
* (barring an attack on the mac and deliberately-crafted input),
* in case the caller doesn't check the return status properly. */
if( status == PSA_SUCCESS )
memset( signature + *signature_length, '!',
signature_size - *signature_length );
else
memset( signature, '!', signature_size );
/* If signature_size is 0 then we have nothing to do. We must not call
* memset because signature may be NULL in this case. */
unlock_status = psa_unlock_key_slot( slot );
return( ( status == PSA_SUCCESS ) ? unlock_status : status );
}
psa_status_t psa_verify_hash_internal(
psa_status_t psa_verify_hash_builtin(
const psa_key_attributes_t *attributes,
const uint8_t *key_buffer, size_t key_buffer_size,
psa_algorithm_t alg, const uint8_t *hash, size_t hash_length,
@ -2688,28 +2892,9 @@ psa_status_t psa_verify_hash( mbedtls_svc_key_id_t key,
const uint8_t *signature,
size_t signature_length )
{
psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
psa_status_t unlock_status = PSA_ERROR_CORRUPTION_DETECTED;
psa_key_slot_t *slot;
status = psa_get_and_lock_key_slot_with_policy( key, &slot,
PSA_KEY_USAGE_VERIFY_HASH,
alg );
if( status != PSA_SUCCESS )
return( status );
psa_key_attributes_t attributes = {
.core = slot->attr
};
status = psa_driver_wrapper_verify_hash(
&attributes, slot->key.data, slot->key.bytes,
alg, hash, hash_length,
return psa_verify_internal(
key, 0, alg, hash, hash_length,
signature, signature_length );
unlock_status = psa_unlock_key_slot( slot );
return( ( status == PSA_SUCCESS ) ? unlock_status : status );
}
#if defined(MBEDTLS_PSA_BUILTIN_ALG_RSA_OAEP)

View File

@ -378,6 +378,86 @@ psa_status_t psa_generate_key_internal( const psa_key_attributes_t *attributes,
size_t key_buffer_size,
size_t *key_buffer_length );
/** Sign a message with a private key. For hash-and-sign algorithms,
* this includes the hashing step.
*
* \note The signature of this function is that of a PSA driver
* sign_message entry point. This function behaves as a sign_message
* entry point as defined in the PSA driver interface specification for
* transparent drivers.
*
* \note This function will call the driver for psa_sign_hash
* and go through driver dispatch again.
*
* \param[in] attributes The attributes of the key to use for the
* operation.
* \param[in] key_buffer The buffer containing the key context.
* \param[in] key_buffer_size Size of the \p key_buffer buffer in bytes.
* \param[in] alg A signature algorithm that is compatible with
* the type of the key.
* \param[in] input The input message to sign.
* \param[in] input_length Size of the \p input buffer in bytes.
* \param[out] signature Buffer where the signature is to be written.
* \param[in] signature_size Size of the \p signature buffer in bytes.
* \param[out] signature_length On success, the number of bytes
* that make up the returned signature value.
*
* \retval #PSA_SUCCESS
* \retval #PSA_ERROR_BUFFER_TOO_SMALL
* The size of the \p signature buffer is too small. You can
* determine a sufficient buffer size by calling
* #PSA_SIGN_OUTPUT_SIZE(\c key_type, \c key_bits, \p alg)
* where \c key_type and \c key_bits are the type and bit-size
* respectively of the key.
* \retval #PSA_ERROR_NOT_SUPPORTED
* \retval #PSA_ERROR_INVALID_ARGUMENT
* \retval #PSA_ERROR_INSUFFICIENT_MEMORY
* \retval #PSA_ERROR_CORRUPTION_DETECTED
* \retval #PSA_ERROR_INSUFFICIENT_ENTROPY
*/
psa_status_t psa_sign_message_builtin(
const psa_key_attributes_t *attributes,
const uint8_t *key_buffer, size_t key_buffer_size,
psa_algorithm_t alg, const uint8_t *input, size_t input_length,
uint8_t *signature, size_t signature_size, size_t *signature_length );
/** Verify the signature of a message with a public key, using
* a hash-and-sign verification algorithm.
*
* \note The signature of this function is that of a PSA driver
* verify_message entry point. This function behaves as a verify_message
* entry point as defined in the PSA driver interface specification for
* transparent drivers.
*
* \note This function will call the driver for psa_verify_hash
* and go through driver dispatch again.
*
* \param[in] attributes The attributes of the key to use for the
* operation.
* \param[in] key_buffer The buffer containing the key context.
* \param[in] key_buffer_size Size of the \p key_buffer buffer in bytes.
* \param[in] alg A signature algorithm that is compatible with
* the type of the key.
* \param[in] input The message whose signature is to be verified.
* \param[in] input_length Size of the \p input buffer in bytes.
* \param[in] signature Buffer containing the signature to verify.
* \param[in] signature_length Size of the \p signature buffer in bytes.
*
* \retval #PSA_SUCCESS
* The signature is valid.
* \retval #PSA_ERROR_INVALID_SIGNATURE
* The calculation was performed successfully, but the passed
* signature is not a valid signature.
* \retval #PSA_ERROR_NOT_SUPPORTED
* \retval #PSA_ERROR_INVALID_ARGUMENT
* \retval #PSA_ERROR_INSUFFICIENT_MEMORY
*/
psa_status_t psa_verify_message_builtin(
const psa_key_attributes_t *attributes,
const uint8_t *key_buffer, size_t key_buffer_size,
psa_algorithm_t alg, const uint8_t *input, size_t input_length,
const uint8_t *signature, size_t signature_length );
/** Sign an already-calculated hash with a private key.
*
* \note The signature of this function is that of a PSA driver
@ -388,7 +468,6 @@ psa_status_t psa_generate_key_internal( const psa_key_attributes_t *attributes,
* \param[in] attributes The attributes of the key to use for the
* operation.
* \param[in] key_buffer The buffer containing the key context.
* format.
* \param[in] key_buffer_size Size of the \p key_buffer buffer in bytes.
* \param[in] alg A signature algorithm that is compatible with
* the type of the key.
@ -412,7 +491,7 @@ psa_status_t psa_generate_key_internal( const psa_key_attributes_t *attributes,
* \retval #PSA_ERROR_CORRUPTION_DETECTED
* \retval #PSA_ERROR_INSUFFICIENT_ENTROPY
*/
psa_status_t psa_sign_hash_internal(
psa_status_t psa_sign_hash_builtin(
const psa_key_attributes_t *attributes,
const uint8_t *key_buffer, size_t key_buffer_size,
psa_algorithm_t alg, const uint8_t *hash, size_t hash_length,
@ -429,7 +508,6 @@ psa_status_t psa_sign_hash_internal(
* \param[in] attributes The attributes of the key to use for the
* operation.
* \param[in] key_buffer The buffer containing the key context.
* format.
* \param[in] key_buffer_size Size of the \p key_buffer buffer in bytes.
* \param[in] alg A signature algorithm that is compatible with
* the type of the key.
@ -448,7 +526,7 @@ psa_status_t psa_sign_hash_internal(
* \retval #PSA_ERROR_INVALID_ARGUMENT
* \retval #PSA_ERROR_INSUFFICIENT_MEMORY
*/
psa_status_t psa_verify_hash_internal(
psa_status_t psa_verify_hash_builtin(
const psa_key_attributes_t *attributes,
const uint8_t *key_buffer, size_t key_buffer_size,
psa_algorithm_t alg, const uint8_t *hash, size_t hash_length,

View File

@ -65,6 +65,152 @@
#endif
/* Start delegation functions */
psa_status_t psa_driver_wrapper_sign_message(
const psa_key_attributes_t *attributes,
const uint8_t *key_buffer,
size_t key_buffer_size,
psa_algorithm_t alg,
const uint8_t *input,
size_t input_length,
uint8_t *signature,
size_t signature_size,
size_t *signature_length )
{
psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
psa_key_location_t location =
PSA_KEY_LIFETIME_GET_LOCATION( attributes->core.lifetime );
switch( location )
{
case PSA_KEY_LOCATION_LOCAL_STORAGE:
/* Key is stored in the slot in export representation, so
* cycle through all known transparent accelerators */
#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT)
#if defined(PSA_CRYPTO_DRIVER_TEST)
status = mbedtls_test_transparent_signature_sign_message(
attributes,
key_buffer,
key_buffer_size,
alg,
input,
input_length,
signature,
signature_size,
signature_length );
/* Declared with fallback == true */
if( status != PSA_ERROR_NOT_SUPPORTED )
return( status );
#endif /* PSA_CRYPTO_DRIVER_TEST */
#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */
break;
/* Add cases for opaque driver here */
#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT)
#if defined(PSA_CRYPTO_DRIVER_TEST)
case PSA_CRYPTO_TEST_DRIVER_LOCATION:
status = mbedtls_test_opaque_signature_sign_message(
attributes,
key_buffer,
key_buffer_size,
alg,
input,
input_length,
signature,
signature_size,
signature_length );
if( status != PSA_ERROR_NOT_SUPPORTED )
return( status );
break;
#endif /* PSA_CRYPTO_DRIVER_TEST */
#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */
default:
/* Key is declared with a lifetime not known to us */
(void)status;
break;
}
return( psa_sign_message_builtin( attributes,
key_buffer,
key_buffer_size,
alg,
input,
input_length,
signature,
signature_size,
signature_length ) );
}
psa_status_t psa_driver_wrapper_verify_message(
const psa_key_attributes_t *attributes,
const uint8_t *key_buffer,
size_t key_buffer_size,
psa_algorithm_t alg,
const uint8_t *input,
size_t input_length,
const uint8_t *signature,
size_t signature_length )
{
psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
psa_key_location_t location =
PSA_KEY_LIFETIME_GET_LOCATION( attributes->core.lifetime );
switch( location )
{
case PSA_KEY_LOCATION_LOCAL_STORAGE:
/* Key is stored in the slot in export representation, so
* cycle through all known transparent accelerators */
#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT)
#if defined(PSA_CRYPTO_DRIVER_TEST)
status = mbedtls_test_transparent_signature_verify_message(
attributes,
key_buffer,
key_buffer_size,
alg,
input,
input_length,
signature,
signature_length );
/* Declared with fallback == true */
if( status != PSA_ERROR_NOT_SUPPORTED )
return( status );
#endif /* PSA_CRYPTO_DRIVER_TEST */
#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */
break;
/* Add cases for opaque driver here */
#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT)
#if defined(PSA_CRYPTO_DRIVER_TEST)
case PSA_CRYPTO_TEST_DRIVER_LOCATION:
return( mbedtls_test_opaque_signature_verify_message(
attributes,
key_buffer,
key_buffer_size,
alg,
input,
input_length,
signature,
signature_length ) );
if( status != PSA_ERROR_NOT_SUPPORTED )
return( status );
break;
#endif /* PSA_CRYPTO_DRIVER_TEST */
#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */
default:
/* Key is declared with a lifetime not known to us */
(void)status;
break;
}
return( psa_verify_message_builtin( attributes,
key_buffer,
key_buffer_size,
alg,
input,
input_length,
signature,
signature_length ) );
}
psa_status_t psa_driver_wrapper_sign_hash(
const psa_key_attributes_t *attributes,
const uint8_t *key_buffer, size_t key_buffer_size,
@ -117,15 +263,15 @@ psa_status_t psa_driver_wrapper_sign_hash(
#endif /* PSA_CRYPTO_DRIVER_TEST */
#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */
/* Fell through, meaning no accelerator supports this operation */
return( psa_sign_hash_internal( attributes,
key_buffer,
key_buffer_size,
alg,
hash,
hash_length,
signature,
signature_size,
signature_length ) );
return( psa_sign_hash_builtin( attributes,
key_buffer,
key_buffer_size,
alg,
hash,
hash_length,
signature,
signature_size,
signature_length ) );
/* Add cases for opaque driver here */
#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT)
@ -201,14 +347,14 @@ psa_status_t psa_driver_wrapper_verify_hash(
#endif /* PSA_CRYPTO_DRIVER_TEST */
#endif /* PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT */
return( psa_verify_hash_internal( attributes,
key_buffer,
key_buffer_size,
alg,
hash,
hash_length,
signature,
signature_length ) );
return( psa_verify_hash_builtin( attributes,
key_buffer,
key_buffer_size,
alg,
hash,
hash_length,
signature,
signature_length ) );
/* Add cases for opaque driver here */
#if defined(PSA_CRYPTO_ACCELERATOR_DRIVER_PRESENT)

View File

@ -28,6 +28,27 @@
/*
* Signature functions
*/
psa_status_t psa_driver_wrapper_sign_message(
const psa_key_attributes_t *attributes,
const uint8_t *key_buffer,
size_t key_buffer_size,
psa_algorithm_t alg,
const uint8_t *input,
size_t input_length,
uint8_t *signature,
size_t signature_size,
size_t *signature_length );
psa_status_t psa_driver_wrapper_verify_message(
const psa_key_attributes_t *attributes,
const uint8_t *key_buffer,
size_t key_buffer_size,
psa_algorithm_t alg,
const uint8_t *input,
size_t input_length,
const uint8_t *signature,
size_t signature_length );
psa_status_t psa_driver_wrapper_sign_hash(
const psa_key_attributes_t *attributes,
const uint8_t *key_buffer, size_t key_buffer_size,