diff --git a/ChangeLog.d/gcm-update.txt b/ChangeLog.d/gcm-update.txt index 4511fec32..d38455102 100644 --- a/ChangeLog.d/gcm-update.txt +++ b/ChangeLog.d/gcm-update.txt @@ -1,3 +1,13 @@ +API changes + * The interface of the GCM module has changed to remove restrictions on + how the input to multipart operations is broken down. mbedtls_gcm_finish() + now takes an extra output parameter for the last partial output block. + 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(). + These changes are backward compatible for users of the cipher API. + Features * The multi-part GCM interface (mbedtls_gcm_update() or mbedtls_cipher_update()) no longer requires the size of partial inputs to diff --git a/include/mbedtls/gcm.h b/include/mbedtls/gcm.h index 8a26ebb96..951ee00c4 100644 --- a/include/mbedtls/gcm.h +++ b/include/mbedtls/gcm.h @@ -282,13 +282,23 @@ int mbedtls_gcm_update( mbedtls_gcm_context *ctx, * buffer of at least \p tag_len Bytes. * \param tag_len The length of the tag to generate. This must be at least * four. + * \param output The buffer for the final output. + * This must be a writable buffer of at least \p output_len + * bytes. + * With the built-in implementation, there is no final + * output and this can be \p NULL. + * Alternative implementations may return a partial block + * of output. + * \param output_len The size of the \p output buffer in bytes. + * With the built-in implementation, this can be \c 0. + * Alternative implementations may require a 15-byte buffer. * * \return \c 0 on success. * \return #MBEDTLS_ERR_GCM_BAD_INPUT on failure. */ int mbedtls_gcm_finish( mbedtls_gcm_context *ctx, - unsigned char *tag, - size_t tag_len ); + unsigned char *output, size_t output_len, + unsigned char *tag, size_t tag_len ); /** * \brief This function clears a GCM context and the underlying diff --git a/library/cipher.c b/library/cipher.c index c88d6666d..63eaba88f 100644 --- a/library/cipher.c +++ b/library/cipher.c @@ -1101,6 +1101,7 @@ int mbedtls_cipher_write_tag( mbedtls_cipher_context_t *ctx, #if defined(MBEDTLS_GCM_C) if( MBEDTLS_MODE_GCM == ctx->cipher_info->mode ) return( mbedtls_gcm_finish( (mbedtls_gcm_context *) ctx->cipher_ctx, + NULL, 0, tag, tag_len ) ); #endif @@ -1153,6 +1154,7 @@ int mbedtls_cipher_check_tag( mbedtls_cipher_context_t *ctx, if( 0 != ( ret = mbedtls_gcm_finish( (mbedtls_gcm_context *) ctx->cipher_ctx, + NULL, 0, check_tag, tag_len ) ) ) { return( ret ); diff --git a/library/gcm.c b/library/gcm.c index b3105d80d..de766bc76 100644 --- a/library/gcm.c +++ b/library/gcm.c @@ -471,8 +471,8 @@ int mbedtls_gcm_update( mbedtls_gcm_context *ctx, } int mbedtls_gcm_finish( mbedtls_gcm_context *ctx, - unsigned char *tag, - size_t tag_len ) + unsigned char *output, size_t output_len, + unsigned char *tag, size_t tag_len ) { unsigned char work_buf[16]; size_t i; @@ -482,6 +482,11 @@ int mbedtls_gcm_finish( mbedtls_gcm_context *ctx, GCM_VALIDATE_RET( ctx != NULL ); GCM_VALIDATE_RET( tag != NULL ); + /* We never pass any output in finish(). The output parameter exists only + * for the sake of alternative implementations. */ + (void) output; + (void) output_len; + orig_len = ctx->len * 8; orig_add_len = ctx->add_len * 8; @@ -541,7 +546,7 @@ int mbedtls_gcm_crypt_and_tag( mbedtls_gcm_context *ctx, if( ( ret = mbedtls_gcm_update( ctx, length, input, output ) ) != 0 ) return( ret ); - if( ( ret = mbedtls_gcm_finish( ctx, tag, tag_len ) ) != 0 ) + if( ( ret = mbedtls_gcm_finish( ctx, NULL, 0, tag, tag_len ) ) != 0 ) return( ret ); return( 0 ); @@ -979,7 +984,7 @@ int mbedtls_gcm_self_test( int verbose ) goto exit; } - ret = mbedtls_gcm_finish( &ctx, tag_buf, 16 ); + ret = mbedtls_gcm_finish( &ctx, NULL, 0, tag_buf, 16 ); if( ret != 0 ) goto exit; @@ -1039,7 +1044,7 @@ int mbedtls_gcm_self_test( int verbose ) goto exit; } - ret = mbedtls_gcm_finish( &ctx, tag_buf, 16 ); + ret = mbedtls_gcm_finish( &ctx, NULL, 0, tag_buf, 16 ); if( ret != 0 ) goto exit; diff --git a/tests/suites/test_suite_gcm.function b/tests/suites/test_suite_gcm.function index d4dce9398..965d15482 100644 --- a/tests/suites/test_suite_gcm.function +++ b/tests/suites/test_suite_gcm.function @@ -41,7 +41,7 @@ static int check_multipart( mbedtls_gcm_context *ctx, output = NULL; ASSERT_ALLOC( output, tag->len ); - TEST_EQUAL( 0, mbedtls_gcm_finish( ctx, output, tag->len ) ); + TEST_EQUAL( 0, mbedtls_gcm_finish( ctx, NULL, 0, output, tag->len ) ); ASSERT_COMPARE( output, tag->len, tag->x, tag->len ); mbedtls_free( output ); output = NULL; @@ -326,10 +326,10 @@ void gcm_invalid_param( ) /* mbedtls_gcm_finish() */ TEST_INVALID_PARAM_RET( MBEDTLS_ERR_GCM_BAD_INPUT, - mbedtls_gcm_finish( NULL, valid_buffer, valid_len ) ); + mbedtls_gcm_finish( NULL, NULL, 0, valid_buffer, valid_len ) ); TEST_INVALID_PARAM_RET( MBEDTLS_ERR_GCM_BAD_INPUT, - mbedtls_gcm_finish( &ctx, NULL, valid_len ) ); + mbedtls_gcm_finish( &ctx, NULL, 0, NULL, valid_len ) ); exit: mbedtls_gcm_free( &ctx );