diff --git a/ChangeLog.d/gcm-update.txt b/ChangeLog.d/gcm-update.txt index 10d53efd7..0fffd094d 100644 --- a/ChangeLog.d/gcm-update.txt +++ b/ChangeLog.d/gcm-update.txt @@ -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 diff --git a/include/mbedtls/gcm.h b/include/mbedtls/gcm.h index 0bd6e1e0f..7218081e3 100644 --- a/include/mbedtls/gcm.h +++ b/include/mbedtls/gcm.h @@ -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 diff --git a/library/cipher.c b/library/cipher.c index 7e6d0e02c..e09130ac5 100644 --- a/library/cipher.c +++ b/library/cipher.c @@ -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 diff --git a/library/gcm.c b/library/gcm.c index 13e729643..ee10093c0 100644 --- a/library/gcm.c +++ b/library/gcm.c @@ -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 ) diff --git a/tests/suites/test_suite_gcm.function b/tests/suites/test_suite_gcm.function index da6aea899..9733eb235 100644 --- a/tests/suites/test_suite_gcm.function +++ b/tests/suites/test_suite_gcm.function @@ -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() */