Refactor AEAD setup into a common function
There was a lot of repetition between psa_aead_encrypt and
psa_aead_decrypt. Refactor the code into a new function psa_aead_setup.
The new code should behave identically except that in some cases where
multiple error conditions apply, the code may now return a different
error code.
Internally, I rearranged some of the code:
* I removed a check that the key type was in CATEGORY_SYMMETRIC because
it's redundant with mbedtls_cipher_info_from_psa which enumerates
supported key types explicitly.
* The order of some validations is different to allow the split between
setup and data processing. The code now calls a more robust function
psa_aead_abort in case of any error after the early stage of the setup.
diff --git a/library/psa_crypto.c b/library/psa_crypto.c
index 3411cc8..82af920 100644
--- a/library/psa_crypto.c
+++ b/library/psa_crypto.c
@@ -2821,6 +2821,102 @@
/* AEAD */
/****************************************************************/
+typedef struct
+{
+ key_slot_t *slot;
+ const mbedtls_cipher_info_t *cipher_info;
+ union
+ {
+#if defined(MBEDTLS_CCM_C)
+ mbedtls_ccm_context ccm;
+#endif /* MBEDTLS_CCM_C */
+#if defined(MBEDTLS_GCM_C)
+ mbedtls_gcm_context gcm;
+#endif /* MBEDTLS_GCM_C */
+ } ctx;
+ uint8_t tag_length;
+} aead_operation_t;
+
+static void psa_aead_abort( aead_operation_t *operation,
+ psa_algorithm_t alg )
+{
+ switch( alg )
+ {
+#if defined(MBEDTLS_CCM_C)
+ case PSA_ALG_CCM:
+ mbedtls_ccm_free( &operation->ctx.ccm );
+ break;
+#endif /* MBEDTLS_CCM_C */
+#if defined(MBEDTLS_CCM_C)
+ case PSA_ALG_GCM:
+ mbedtls_gcm_free( &operation->ctx.gcm );
+ break;
+#endif /* MBEDTLS_GCM_C */
+ }
+}
+
+static psa_status_t psa_aead_setup( aead_operation_t *operation,
+ psa_key_slot_t key,
+ psa_key_usage_t usage,
+ psa_algorithm_t alg )
+{
+ psa_status_t status;
+ size_t key_bits;
+ mbedtls_cipher_id_t cipher_id;
+
+ status = psa_get_key_from_slot( key, &operation->slot, usage, alg );
+ if( status != PSA_SUCCESS )
+ return( status );
+
+ key_bits = psa_get_key_bits( operation->slot );
+
+ operation->cipher_info =
+ mbedtls_cipher_info_from_psa( alg, operation->slot->type, key_bits,
+ &cipher_id );
+ if( operation->cipher_info == NULL )
+ return( PSA_ERROR_NOT_SUPPORTED );
+
+ switch( alg )
+ {
+#if defined(MBEDTLS_CCM_C)
+ case PSA_ALG_CCM:
+ operation->tag_length = 16;
+ if( PSA_BLOCK_CIPHER_BLOCK_SIZE( operation->slot->type ) != 16 )
+ return( PSA_ERROR_INVALID_ARGUMENT );
+ mbedtls_ccm_init( &operation->ctx.ccm );
+ status = mbedtls_to_psa_error(
+ mbedtls_ccm_setkey( &operation->ctx.ccm, cipher_id,
+ operation->slot->data.raw.data,
+ (unsigned int) key_bits ) );
+ if( status != 0 )
+ goto cleanup;
+ break;
+#endif /* MBEDTLS_CCM_C */
+
+#if defined(MBEDTLS_GCM_C)
+ case PSA_ALG_GCM:
+ operation->tag_length = 16;
+ if( PSA_BLOCK_CIPHER_BLOCK_SIZE( operation->slot->type ) != 16 )
+ return( PSA_ERROR_INVALID_ARGUMENT );
+ mbedtls_gcm_init( &operation->ctx.gcm );
+ status = mbedtls_to_psa_error(
+ mbedtls_gcm_setkey( &operation->ctx.gcm, cipher_id,
+ operation->slot->data.raw.data,
+ (unsigned int) key_bits ) );
+ break;
+#endif /* MBEDTLS_GCM_C */
+
+ default:
+ return( PSA_ERROR_NOT_SUPPORTED );
+ }
+
+ return( PSA_SUCCESS );
+
+cleanup:
+ psa_aead_abort( operation, alg );
+ return( status );
+}
+
psa_status_t psa_aead_encrypt( psa_key_slot_t key,
psa_algorithm_t alg,
const uint8_t *nonce,
@@ -2833,113 +2929,60 @@
size_t ciphertext_size,
size_t *ciphertext_length )
{
- int ret;
psa_status_t status;
- key_slot_t *slot;
- size_t key_bits;
+ aead_operation_t operation;
uint8_t *tag;
- size_t tag_length;
- mbedtls_cipher_id_t cipher_id;
- const mbedtls_cipher_info_t *cipher_info = NULL;
*ciphertext_length = 0;
- status = psa_get_key_from_slot( key, &slot, PSA_KEY_USAGE_ENCRYPT, alg );
+ status = psa_aead_setup( &operation, key, PSA_KEY_USAGE_ENCRYPT, alg );
if( status != PSA_SUCCESS )
return( status );
- key_bits = psa_get_key_bits( slot );
- cipher_info = mbedtls_cipher_info_from_psa( alg, slot->type,
- key_bits, &cipher_id );
- if( cipher_info == NULL )
- return( PSA_ERROR_NOT_SUPPORTED );
-
- if( ( slot->type & PSA_KEY_TYPE_CATEGORY_MASK ) !=
- PSA_KEY_TYPE_CATEGORY_SYMMETRIC )
- return( PSA_ERROR_INVALID_ARGUMENT );
+ /* For all currently supported modes, the tag is at the end of the
+ * ciphertext. */
+ if( ciphertext_size < ( plaintext_length + operation.tag_length ) )
+ {
+ status = PSA_ERROR_BUFFER_TOO_SMALL;
+ goto exit;
+ }
+ tag = ciphertext + plaintext_length;
if( alg == PSA_ALG_GCM )
{
- mbedtls_gcm_context gcm;
- tag_length = 16;
-
- if( PSA_BLOCK_CIPHER_BLOCK_SIZE( slot->type ) != 16 )
- return( PSA_ERROR_INVALID_ARGUMENT );
-
- //make sure we have place to hold the tag in the ciphertext buffer
- if( ciphertext_size < ( plaintext_length + tag_length ) )
- return( PSA_ERROR_BUFFER_TOO_SMALL );
-
- //update the tag pointer to point to the end of the ciphertext_length
- tag = ciphertext + plaintext_length;
-
- mbedtls_gcm_init( &gcm );
- ret = mbedtls_gcm_setkey( &gcm, cipher_id,
- slot->data.raw.data,
- (unsigned int) key_bits );
- if( ret != 0 )
- {
- mbedtls_gcm_free( &gcm );
- return( mbedtls_to_psa_error( ret ) );
- }
- ret = mbedtls_gcm_crypt_and_tag( &gcm, MBEDTLS_GCM_ENCRYPT,
- plaintext_length, nonce,
- nonce_length, additional_data,
- additional_data_length, plaintext,
- ciphertext, tag_length, tag );
- mbedtls_gcm_free( &gcm );
+ status = mbedtls_to_psa_error(
+ mbedtls_gcm_crypt_and_tag( &operation.ctx.gcm,
+ MBEDTLS_GCM_ENCRYPT,
+ plaintext_length,
+ nonce, nonce_length,
+ additional_data, additional_data_length,
+ plaintext, ciphertext,
+ operation.tag_length, tag ) );
}
else if( alg == PSA_ALG_CCM )
{
- mbedtls_ccm_context ccm;
- tag_length = 16;
-
- if( PSA_BLOCK_CIPHER_BLOCK_SIZE( slot->type ) != 16 )
- return( PSA_ERROR_INVALID_ARGUMENT );
-
- if( nonce_length < 7 || nonce_length > 13 )
- return( PSA_ERROR_INVALID_ARGUMENT );
-
- //make sure we have place to hold the tag in the ciphertext buffer
- if( ciphertext_size < ( plaintext_length + tag_length ) )
- return( PSA_ERROR_BUFFER_TOO_SMALL );
-
- //update the tag pointer to point to the end of the ciphertext_length
- tag = ciphertext + plaintext_length;
-
- mbedtls_ccm_init( &ccm );
- ret = mbedtls_ccm_setkey( &ccm, cipher_id,
- slot->data.raw.data,
- (unsigned int) key_bits );
- if( ret != 0 )
- {
- mbedtls_ccm_free( &ccm );
- return( mbedtls_to_psa_error( ret ) );
- }
- ret = mbedtls_ccm_encrypt_and_tag( &ccm, plaintext_length,
- nonce, nonce_length,
- additional_data,
- additional_data_length,
- plaintext, ciphertext,
- tag, tag_length );
- mbedtls_ccm_free( &ccm );
+ status = mbedtls_to_psa_error(
+ mbedtls_ccm_encrypt_and_tag( &operation.ctx.ccm,
+ plaintext_length,
+ nonce, nonce_length,
+ additional_data,
+ additional_data_length,
+ plaintext, ciphertext,
+ tag, operation.tag_length ) );
}
else
{
return( PSA_ERROR_NOT_SUPPORTED );
}
- if( ret != 0 )
- {
- /* If ciphertext_size is 0 then ciphertext may be NULL and then the
- * call to memset would have undefined behavior. */
- if( ciphertext_size != 0 )
- memset( ciphertext, 0, ciphertext_size );
- return( mbedtls_to_psa_error( ret ) );
- }
+ if( status != PSA_SUCCESS && ciphertext_size != 0 )
+ memset( ciphertext, 0, ciphertext_size );
- *ciphertext_length = plaintext_length + tag_length;
- return( PSA_SUCCESS );
+exit:
+ psa_aead_abort( &operation, alg );
+ if( status == PSA_SUCCESS )
+ *ciphertext_length = plaintext_length + operation.tag_length;
+ return( status );
}
/* Locate the tag in a ciphertext buffer containing the encrypted data
@@ -2975,108 +3018,63 @@
size_t plaintext_size,
size_t *plaintext_length )
{
- int ret;
psa_status_t status;
- key_slot_t *slot;
- size_t key_bits;
- const uint8_t *tag;
- size_t tag_length;
- mbedtls_cipher_id_t cipher_id;
- const mbedtls_cipher_info_t *cipher_info = NULL;
+ aead_operation_t operation;
+ const uint8_t *tag = NULL;
*plaintext_length = 0;
- status = psa_get_key_from_slot( key, &slot, PSA_KEY_USAGE_DECRYPT, alg );
+ status = psa_aead_setup( &operation, key, PSA_KEY_USAGE_DECRYPT, alg );
if( status != PSA_SUCCESS )
return( status );
- key_bits = psa_get_key_bits( slot );
-
- cipher_info = mbedtls_cipher_info_from_psa( alg, slot->type,
- key_bits, &cipher_id );
- if( cipher_info == NULL )
- return( PSA_ERROR_NOT_SUPPORTED );
-
- if( ( slot->type & PSA_KEY_TYPE_CATEGORY_MASK ) !=
- PSA_KEY_TYPE_CATEGORY_SYMMETRIC )
- return( PSA_ERROR_INVALID_ARGUMENT );
if( alg == PSA_ALG_GCM )
{
- mbedtls_gcm_context gcm;
-
- tag_length = 16;
- status = psa_aead_unpadded_locate_tag( tag_length,
+ status = psa_aead_unpadded_locate_tag( operation.tag_length,
ciphertext, ciphertext_length,
plaintext_size, &tag );
if( status != PSA_SUCCESS )
- return( status );
+ goto exit;
- mbedtls_gcm_init( &gcm );
- ret = mbedtls_gcm_setkey( &gcm, cipher_id,
- slot->data.raw.data,
- (unsigned int) key_bits );
- if( ret != 0 )
- {
- mbedtls_gcm_free( &gcm );
- return( mbedtls_to_psa_error( ret ) );
- }
-
- ret = mbedtls_gcm_auth_decrypt( &gcm,
- ciphertext_length - tag_length,
- nonce, nonce_length,
- additional_data,
- additional_data_length,
- tag, tag_length,
- ciphertext, plaintext );
- mbedtls_gcm_free( &gcm );
+ status = mbedtls_to_psa_error(
+ mbedtls_gcm_auth_decrypt( &operation.ctx.gcm,
+ ciphertext_length - operation.tag_length,
+ nonce, nonce_length,
+ additional_data,
+ additional_data_length,
+ tag, operation.tag_length,
+ ciphertext, plaintext ) );
}
else if( alg == PSA_ALG_CCM )
{
- mbedtls_ccm_context ccm;
-
- if( nonce_length < 7 || nonce_length > 13 )
- return( PSA_ERROR_INVALID_ARGUMENT );
-
- tag_length = 16;
- status = psa_aead_unpadded_locate_tag( tag_length,
+ status = psa_aead_unpadded_locate_tag( operation.tag_length,
ciphertext, ciphertext_length,
plaintext_size, &tag );
if( status != PSA_SUCCESS )
- return( status );
+ goto exit;
- mbedtls_ccm_init( &ccm );
- ret = mbedtls_ccm_setkey( &ccm, cipher_id,
- slot->data.raw.data,
- (unsigned int) key_bits );
- if( ret != 0 )
- {
- mbedtls_ccm_free( &ccm );
- return( mbedtls_to_psa_error( ret ) );
- }
- ret = mbedtls_ccm_auth_decrypt( &ccm, ciphertext_length - tag_length,
- nonce, nonce_length,
- additional_data,
- additional_data_length,
- ciphertext, plaintext,
- tag, tag_length );
- mbedtls_ccm_free( &ccm );
+ status = mbedtls_to_psa_error(
+ mbedtls_ccm_auth_decrypt( &operation.ctx.ccm,
+ ciphertext_length - operation.tag_length,
+ nonce, nonce_length,
+ additional_data,
+ additional_data_length,
+ ciphertext, plaintext,
+ tag, operation.tag_length ) );
}
else
{
return( PSA_ERROR_NOT_SUPPORTED );
}
- if( ret != 0 )
- {
- /* If plaintext_size is 0 then plaintext may be NULL and then the
- * call to memset has undefined behavior. */
- if( plaintext_size != 0 )
- memset( plaintext, 0, plaintext_size );
- }
- else
- *plaintext_length = ciphertext_length - tag_length;
+ if( status != PSA_SUCCESS && plaintext_size != 0 )
+ memset( plaintext, 0, plaintext_size );
- return( mbedtls_to_psa_error( ret ) );
+exit:
+ psa_aead_abort( &operation, alg );
+ if( status == PSA_SUCCESS )
+ *plaintext_length = ciphertext_length - operation.tag_length;
+ return( status );
}