Fix Lucky 13 cache attack on MD/SHA padding
The basis for the Lucky 13 family of attacks is for an attacker to be able to distinguish between (long) valid TLS-CBC padding and invalid TLS-CBC padding. Since our code sets padlen = 0 for invalid padding, the length of the input to the HMAC function gives information about that. Information about this length (modulo the MD/SHA block size) can be deduced from how much MD/SHA padding (this is distinct from TLS-CBC padding) is used. If MD/SHA padding is read from a (static) buffer, a local attacker could get information about how much is used via a cache attack targeting that buffer. Let's get rid of this buffer. Now the only buffer used is the internal MD/SHA one, which is always read fully by the process() function.
This commit is contained in:
parent
104d85865d
commit
1cc1fb0599
5 changed files with 141 additions and 81 deletions
|
@ -16,6 +16,13 @@ Security
|
|||
caused by a miscalculation (for SHA-384) in a countermeasure to the
|
||||
original Lucky 13 attack. Found by Kenny Paterson, Eyal Ronen and Adi
|
||||
Shamir.
|
||||
* Fix a vulnerability in TLS ciphersuites based on CBC, in (D)TLS 1.0 to
|
||||
1.2, that allowed a local attacker, able to execute code on the local
|
||||
machine as well as manipulate network packets, to partially recover the
|
||||
plaintext of messages under some conditions (see previous entry) by using
|
||||
a cache attack targetting an internal MD/SHA buffer. Connections using
|
||||
GCM or CCM instead of CBC or using Encrypt-then-Mac (RFC 7366) were not
|
||||
affected. Found by Kenny Paterson, Eyal Ronen and Adi Shamir.
|
||||
|
||||
API Changes
|
||||
* Extend the platform module with a util component that contains
|
||||
|
|
|
@ -309,14 +309,6 @@ void mbedtls_md5_update( mbedtls_md5_context *ctx,
|
|||
}
|
||||
#endif
|
||||
|
||||
static const unsigned char md5_padding[64] =
|
||||
{
|
||||
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
|
||||
/*
|
||||
* MD5 final digest
|
||||
*/
|
||||
|
@ -324,26 +316,48 @@ int mbedtls_md5_finish_ret( mbedtls_md5_context *ctx,
|
|||
unsigned char output[16] )
|
||||
{
|
||||
int ret;
|
||||
uint32_t last, padn;
|
||||
uint32_t used;
|
||||
uint32_t high, low;
|
||||
unsigned char msglen[8];
|
||||
|
||||
/*
|
||||
* Add padding: 0x80 then 0x00 until 8 bytes remain for the length
|
||||
*/
|
||||
used = ctx->total[0] & 0x3F;
|
||||
|
||||
ctx->buffer[used++] = 0x80;
|
||||
|
||||
if( used <= 56 )
|
||||
{
|
||||
/* Enough room for padding + length in current block */
|
||||
memset( ctx->buffer + used, 0, 56 - used );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We'll need an extra block */
|
||||
memset( ctx->buffer + used, 0, 64 - used );
|
||||
|
||||
if( ( ret = mbedtls_internal_md5_process( ctx, ctx->buffer ) ) != 0 )
|
||||
return( ret );
|
||||
|
||||
memset( ctx->buffer, 0, 56 );
|
||||
}
|
||||
|
||||
/*
|
||||
* Add message length
|
||||
*/
|
||||
high = ( ctx->total[0] >> 29 )
|
||||
| ( ctx->total[1] << 3 );
|
||||
low = ( ctx->total[0] << 3 );
|
||||
|
||||
PUT_UINT32_LE( low, msglen, 0 );
|
||||
PUT_UINT32_LE( high, msglen, 4 );
|
||||
PUT_UINT32_LE( low, ctx->buffer, 56 );
|
||||
PUT_UINT32_LE( high, ctx->buffer, 60 );
|
||||
|
||||
last = ctx->total[0] & 0x3F;
|
||||
padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last );
|
||||
|
||||
if( ( ret = mbedtls_md5_update_ret( ctx, md5_padding, padn ) ) != 0 )
|
||||
return( ret );
|
||||
|
||||
if( ( ret = mbedtls_md5_update_ret( ctx, msglen, 8 ) ) != 0 )
|
||||
if( ( ret = mbedtls_internal_md5_process( ctx, ctx->buffer ) ) != 0 )
|
||||
return( ret );
|
||||
|
||||
/*
|
||||
* Output final state
|
||||
*/
|
||||
PUT_UINT32_LE( ctx->state[0], output, 0 );
|
||||
PUT_UINT32_LE( ctx->state[1], output, 4 );
|
||||
PUT_UINT32_LE( ctx->state[2], output, 8 );
|
||||
|
|
|
@ -342,14 +342,6 @@ void mbedtls_sha1_update( mbedtls_sha1_context *ctx,
|
|||
}
|
||||
#endif
|
||||
|
||||
static const unsigned char sha1_padding[64] =
|
||||
{
|
||||
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
|
||||
/*
|
||||
* SHA-1 final digest
|
||||
*/
|
||||
|
@ -357,25 +349,48 @@ int mbedtls_sha1_finish_ret( mbedtls_sha1_context *ctx,
|
|||
unsigned char output[20] )
|
||||
{
|
||||
int ret;
|
||||
uint32_t last, padn;
|
||||
uint32_t used;
|
||||
uint32_t high, low;
|
||||
unsigned char msglen[8];
|
||||
|
||||
/*
|
||||
* Add padding: 0x80 then 0x00 until 8 bytes remain for the length
|
||||
*/
|
||||
used = ctx->total[0] & 0x3F;
|
||||
|
||||
ctx->buffer[used++] = 0x80;
|
||||
|
||||
if( used <= 56 )
|
||||
{
|
||||
/* Enough room for padding + length in current block */
|
||||
memset( ctx->buffer + used, 0, 56 - used );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We'll need an extra block */
|
||||
memset( ctx->buffer + used, 0, 64 - used );
|
||||
|
||||
if( ( ret = mbedtls_internal_sha1_process( ctx, ctx->buffer ) ) != 0 )
|
||||
return( ret );
|
||||
|
||||
memset( ctx->buffer, 0, 56 );
|
||||
}
|
||||
|
||||
/*
|
||||
* Add message length
|
||||
*/
|
||||
high = ( ctx->total[0] >> 29 )
|
||||
| ( ctx->total[1] << 3 );
|
||||
low = ( ctx->total[0] << 3 );
|
||||
|
||||
PUT_UINT32_BE( high, msglen, 0 );
|
||||
PUT_UINT32_BE( low, msglen, 4 );
|
||||
PUT_UINT32_BE( high, ctx->buffer, 56 );
|
||||
PUT_UINT32_BE( low, ctx->buffer, 60 );
|
||||
|
||||
last = ctx->total[0] & 0x3F;
|
||||
padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last );
|
||||
|
||||
if( ( ret = mbedtls_sha1_update_ret( ctx, sha1_padding, padn ) ) != 0 )
|
||||
return( ret );
|
||||
if( ( ret = mbedtls_sha1_update_ret( ctx, msglen, 8 ) ) != 0 )
|
||||
if( ( ret = mbedtls_internal_sha1_process( ctx, ctx->buffer ) ) != 0 )
|
||||
return( ret );
|
||||
|
||||
/*
|
||||
* Output final state
|
||||
*/
|
||||
PUT_UINT32_BE( ctx->state[0], output, 0 );
|
||||
PUT_UINT32_BE( ctx->state[1], output, 4 );
|
||||
PUT_UINT32_BE( ctx->state[2], output, 8 );
|
||||
|
|
|
@ -311,14 +311,6 @@ void mbedtls_sha256_update( mbedtls_sha256_context *ctx,
|
|||
}
|
||||
#endif
|
||||
|
||||
static const unsigned char sha256_padding[64] =
|
||||
{
|
||||
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
|
||||
/*
|
||||
* SHA-256 final digest
|
||||
*/
|
||||
|
@ -326,26 +318,48 @@ int mbedtls_sha256_finish_ret( mbedtls_sha256_context *ctx,
|
|||
unsigned char output[32] )
|
||||
{
|
||||
int ret;
|
||||
uint32_t last, padn;
|
||||
uint32_t used;
|
||||
uint32_t high, low;
|
||||
unsigned char msglen[8];
|
||||
|
||||
/*
|
||||
* Add padding: 0x80 then 0x00 until 8 bytes remain for the length
|
||||
*/
|
||||
used = ctx->total[0] & 0x3F;
|
||||
|
||||
ctx->buffer[used++] = 0x80;
|
||||
|
||||
if( used <= 56 )
|
||||
{
|
||||
/* Enough room for padding + length in current block */
|
||||
memset( ctx->buffer + used, 0, 56 - used );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We'll need an extra block */
|
||||
memset( ctx->buffer + used, 0, 64 - used );
|
||||
|
||||
if( ( ret = mbedtls_internal_sha256_process( ctx, ctx->buffer ) ) != 0 )
|
||||
return( ret );
|
||||
|
||||
memset( ctx->buffer, 0, 56 );
|
||||
}
|
||||
|
||||
/*
|
||||
* Add message length
|
||||
*/
|
||||
high = ( ctx->total[0] >> 29 )
|
||||
| ( ctx->total[1] << 3 );
|
||||
low = ( ctx->total[0] << 3 );
|
||||
|
||||
PUT_UINT32_BE( high, msglen, 0 );
|
||||
PUT_UINT32_BE( low, msglen, 4 );
|
||||
PUT_UINT32_BE( high, ctx->buffer, 56 );
|
||||
PUT_UINT32_BE( low, ctx->buffer, 60 );
|
||||
|
||||
last = ctx->total[0] & 0x3F;
|
||||
padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last );
|
||||
|
||||
if( ( ret = mbedtls_sha256_update_ret( ctx, sha256_padding, padn ) ) != 0 )
|
||||
return( ret );
|
||||
|
||||
if( ( ret = mbedtls_sha256_update_ret( ctx, msglen, 8 ) ) != 0 )
|
||||
if( ( ret = mbedtls_internal_sha256_process( ctx, ctx->buffer ) ) != 0 )
|
||||
return( ret );
|
||||
|
||||
/*
|
||||
* Output final state
|
||||
*/
|
||||
PUT_UINT32_BE( ctx->state[0], output, 0 );
|
||||
PUT_UINT32_BE( ctx->state[1], output, 4 );
|
||||
PUT_UINT32_BE( ctx->state[2], output, 8 );
|
||||
|
|
|
@ -341,18 +341,6 @@ void mbedtls_sha512_update( mbedtls_sha512_context *ctx,
|
|||
}
|
||||
#endif
|
||||
|
||||
static const unsigned char sha512_padding[128] =
|
||||
{
|
||||
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
|
||||
/*
|
||||
* SHA-512 final digest
|
||||
*/
|
||||
|
@ -360,26 +348,48 @@ int mbedtls_sha512_finish_ret( mbedtls_sha512_context *ctx,
|
|||
unsigned char output[64] )
|
||||
{
|
||||
int ret;
|
||||
size_t last, padn;
|
||||
unsigned used;
|
||||
uint64_t high, low;
|
||||
unsigned char msglen[16];
|
||||
|
||||
/*
|
||||
* Add padding: 0x80 then 0x00 until 16 bytes remain for the length
|
||||
*/
|
||||
used = ctx->total[0] & 0x7F;
|
||||
|
||||
ctx->buffer[used++] = 0x80;
|
||||
|
||||
if( used <= 112 )
|
||||
{
|
||||
/* Enough room for padding + length in current block */
|
||||
memset( ctx->buffer + used, 0, 112 - used );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We'll need an extra block */
|
||||
memset( ctx->buffer + used, 0, 128 - used );
|
||||
|
||||
if( ( ret = mbedtls_internal_sha512_process( ctx, ctx->buffer ) ) != 0 )
|
||||
return( ret );
|
||||
|
||||
memset( ctx->buffer, 0, 112 );
|
||||
}
|
||||
|
||||
/*
|
||||
* Add message length
|
||||
*/
|
||||
high = ( ctx->total[0] >> 61 )
|
||||
| ( ctx->total[1] << 3 );
|
||||
low = ( ctx->total[0] << 3 );
|
||||
|
||||
PUT_UINT64_BE( high, msglen, 0 );
|
||||
PUT_UINT64_BE( low, msglen, 8 );
|
||||
PUT_UINT64_BE( high, ctx->buffer, 112 );
|
||||
PUT_UINT64_BE( low, ctx->buffer, 120 );
|
||||
|
||||
last = (size_t)( ctx->total[0] & 0x7F );
|
||||
padn = ( last < 112 ) ? ( 112 - last ) : ( 240 - last );
|
||||
|
||||
if( ( ret = mbedtls_sha512_update_ret( ctx, sha512_padding, padn ) ) != 0 )
|
||||
return( ret );
|
||||
|
||||
if( ( ret = mbedtls_sha512_update_ret( ctx, msglen, 16 ) ) != 0 )
|
||||
if( ( ret = mbedtls_internal_sha512_process( ctx, ctx->buffer ) ) != 0 )
|
||||
return( ret );
|
||||
|
||||
/*
|
||||
* Output final state
|
||||
*/
|
||||
PUT_UINT64_BE( ctx->state[0], output, 0 );
|
||||
PUT_UINT64_BE( ctx->state[1], output, 8 );
|
||||
PUT_UINT64_BE( ctx->state[2], output, 16 );
|
||||
|
|
Loading…
Reference in a new issue