Split mbedtls_gcm_update_ad out of mbedtls_gcm_starts

The GCM interface now has separate functions to start the operation
and to pass the associated data.

This is in preparation for allowing the associated data to be passed
in chunks with repeatated calls to mbedtls_gcm_update_ad().

Signed-off-by: Gilles Peskine <Gilles.Peskine@arm.com>
This commit is contained in:
Gilles Peskine 2021-04-15 18:32:23 +02:00
parent a56c448636
commit 295fc13ef3
5 changed files with 83 additions and 35 deletions

View File

@ -6,7 +6,9 @@ API changes
The software implementation always produces the full output at each
call to mbedtls_gcm_update(), but alternative implementations activated
by MBEDTLS_GCM_ALT may delay partial blocks to the next call to
mbedtls_gcm_update() or mbedtls_gcm_finish().
mbedtls_gcm_update() or mbedtls_gcm_finish(). Furthermore, applications
no longer pass the associated data to mbedtls_gcm_starts(), but to the
new function mbedtls_gcm_update_ad().
These changes are backward compatible for users of the cipher API.
Features

View File

@ -231,6 +231,26 @@ int mbedtls_gcm_auth_decrypt( mbedtls_gcm_context *ctx,
* \param iv The initialization vector. This must be a readable buffer of
* at least \p iv_len Bytes.
* \param iv_len The length of the IV.
*
* \return \c 0 on success.
*/
int mbedtls_gcm_starts( mbedtls_gcm_context *ctx,
int mode,
const unsigned char *iv,
size_t iv_len );
/**
* \brief This function starts a GCM encryption or decryption
* operation.
*
* \note This function may only be called once per operation:
* you must pass the whole associated data in a single
* call. This limitation will be lifted in a future version
* of Mbed TLS.
*
* \param ctx The GCM context. This must have been started with
* mbedtls_gcm_starts() and must not have yet received
* any input with mbedtls_gcm_update().
* \param add The buffer holding the additional data, or \c NULL
* if \p add_len is \c 0.
* \param add_len The length of the additional data. If \c 0,
@ -238,12 +258,9 @@ int mbedtls_gcm_auth_decrypt( mbedtls_gcm_context *ctx,
*
* \return \c 0 on success.
*/
int mbedtls_gcm_starts( mbedtls_gcm_context *ctx,
int mode,
const unsigned char *iv,
size_t iv_len,
const unsigned char *add,
size_t add_len );
int mbedtls_gcm_update_ad( mbedtls_gcm_context *ctx,
const unsigned char *add,
size_t add_len );
/**
* \brief This function feeds an input buffer into an ongoing GCM

View File

@ -415,6 +415,15 @@ int mbedtls_cipher_set_iv( mbedtls_cipher_context_t *ctx,
}
#endif
#if defined(MBEDTLS_GCM_C)
if( MBEDTLS_MODE_GCM == ctx->cipher_info->mode )
{
return( mbedtls_gcm_starts( (mbedtls_gcm_context *) ctx->cipher_ctx,
ctx->operation,
iv, iv_len ) );
}
#endif
if ( actual_iv_size != 0 )
{
memcpy( ctx->iv, iv, actual_iv_size );
@ -466,8 +475,8 @@ int mbedtls_cipher_update_ad( mbedtls_cipher_context_t *ctx,
#if defined(MBEDTLS_GCM_C)
if( MBEDTLS_MODE_GCM == ctx->cipher_info->mode )
{
return( mbedtls_gcm_starts( (mbedtls_gcm_context *) ctx->cipher_ctx, ctx->operation,
ctx->iv, ctx->iv_size, ad, ad_len ) );
return( mbedtls_gcm_update_ad( (mbedtls_gcm_context *) ctx->cipher_ctx,
ad, ad_len ) );
}
#endif

View File

@ -269,11 +269,8 @@ static void gcm_mult( mbedtls_gcm_context *ctx, const unsigned char x[16],
}
int mbedtls_gcm_starts( mbedtls_gcm_context *ctx,
int mode,
const unsigned char *iv,
size_t iv_len,
const unsigned char *add,
size_t add_len )
int mode,
const unsigned char *iv, size_t iv_len )
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
unsigned char work_buf[16];
@ -283,16 +280,11 @@ int mbedtls_gcm_starts( mbedtls_gcm_context *ctx,
GCM_VALIDATE_RET( ctx != NULL );
GCM_VALIDATE_RET( iv != NULL );
GCM_VALIDATE_RET( add_len == 0 || add != NULL );
/* IV and AD are limited to 2^64 bits, so 2^61 bytes */
/* IV is are limited to 2^64 bits, so 2^61 bytes */
/* IV is not allowed to be zero length */
if( iv_len == 0 ||
( (uint64_t) iv_len ) >> 61 != 0 ||
( (uint64_t) add_len ) >> 61 != 0 )
{
if( iv_len == 0 || (uint64_t) iv_len >> 61 != 0 )
return( MBEDTLS_ERR_GCM_BAD_INPUT );
}
memset( ctx->y, 0x00, sizeof(ctx->y) );
memset( ctx->buf, 0x00, sizeof(ctx->buf) );
@ -337,6 +329,26 @@ int mbedtls_gcm_starts( mbedtls_gcm_context *ctx,
return( ret );
}
return( 0 );
}
int mbedtls_gcm_update_ad( mbedtls_gcm_context *ctx,
const unsigned char *add, size_t add_len )
{
const unsigned char *p;
size_t use_len, i;
GCM_VALIDATE_RET( add_len == 0 || add != NULL );
/* IV is are limited to 2^64 bits, so 2^61 bytes */
if( (uint64_t) add_len >> 61 != 0 )
return( MBEDTLS_ERR_GCM_BAD_INPUT );
/* Calling update_ad multiple times is not yet supported */
if( ctx->add_len != 0 )
return( MBEDTLS_ERR_GCM_BAD_INPUT );
ctx->add_len = add_len;
p = add;
while( add_len > 0 )
@ -546,7 +558,10 @@ int mbedtls_gcm_crypt_and_tag( mbedtls_gcm_context *ctx,
GCM_VALIDATE_RET( length == 0 || output != NULL );
GCM_VALIDATE_RET( tag != NULL );
if( ( ret = mbedtls_gcm_starts( ctx, mode, iv, iv_len, add, add_len ) ) != 0 )
if( ( ret = mbedtls_gcm_starts( ctx, mode, iv, iv_len ) ) != 0 )
return( ret );
if( ( ret = mbedtls_gcm_update_ad( ctx, add, add_len ) ) != 0 )
return( ret );
if( ( ret = mbedtls_gcm_update( ctx, input, length,
@ -961,10 +976,14 @@ int mbedtls_gcm_self_test( int verbose )
goto exit;
ret = mbedtls_gcm_starts( &ctx, MBEDTLS_GCM_ENCRYPT,
iv_test_data[iv_index_test_data[i]],
iv_len_test_data[i],
additional_test_data[add_index_test_data[i]],
add_len_test_data[i] );
iv_test_data[iv_index_test_data[i]],
iv_len_test_data[i] );
if( ret != 0 )
goto exit;
ret = mbedtls_gcm_update_ad( &ctx,
additional_test_data[add_index_test_data[i]],
add_len_test_data[i] );
if( ret != 0 )
goto exit;
@ -1031,8 +1050,11 @@ int mbedtls_gcm_self_test( int verbose )
goto exit;
ret = mbedtls_gcm_starts( &ctx, MBEDTLS_GCM_DECRYPT,
iv_test_data[iv_index_test_data[i]],
iv_len_test_data[i],
iv_test_data[iv_index_test_data[i]],
iv_len_test_data[i] );
if( ret != 0 )
goto exit;
ret = mbedtls_gcm_update_ad( &ctx,
additional_test_data[add_index_test_data[i]],
add_len_test_data[i] );
if( ret != 0 )

View File

@ -23,8 +23,8 @@ static int check_multipart( mbedtls_gcm_context *ctx,
TEST_EQUAL( input->len, expected_output->len );
TEST_EQUAL( 0, mbedtls_gcm_starts( ctx, mode,
iv->x, iv->len,
add->x, add->len ) );
iv->x, iv->len ) );
TEST_EQUAL( 0, mbedtls_gcm_update_ad( ctx, add->x, add->len ) );
/* Allocate a tight buffer for each update call. This way, if the function
* tries to write beyond the advertised required buffer size, this will
@ -300,19 +300,17 @@ void gcm_invalid_param( )
TEST_INVALID_PARAM_RET(
MBEDTLS_ERR_GCM_BAD_INPUT,
mbedtls_gcm_starts( NULL, valid_mode,
valid_buffer, valid_len,
valid_buffer, valid_len ) );
TEST_INVALID_PARAM_RET(
MBEDTLS_ERR_GCM_BAD_INPUT,
mbedtls_gcm_starts( &ctx, valid_mode,
NULL, valid_len,
valid_buffer, valid_len ) );
NULL, valid_len ) );
/* mbedtls_gcm_update_ad() */
TEST_INVALID_PARAM_RET(
MBEDTLS_ERR_GCM_BAD_INPUT,
mbedtls_gcm_starts( &ctx, valid_mode,
valid_buffer, valid_len,
mbedtls_gcm_update_ad( &ctx,
NULL, valid_len ) );
/* mbedtls_gcm_update() */