mirror of
https://github.com/yuzu-emu/mbedtls.git
synced 2024-11-25 19:35:39 +01:00
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
@ -16,6 +16,13 @@ Security
|
|||||||
caused by a miscalculation (for SHA-384) in a countermeasure to the
|
caused by a miscalculation (for SHA-384) in a countermeasure to the
|
||||||
original Lucky 13 attack. Found by Kenny Paterson, Eyal Ronen and Adi
|
original Lucky 13 attack. Found by Kenny Paterson, Eyal Ronen and Adi
|
||||||
Shamir.
|
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
|
API Changes
|
||||||
* Extend the platform module with a util component that contains
|
* Extend the platform module with a util component that contains
|
||||||
|
@ -309,14 +309,6 @@ void mbedtls_md5_update( mbedtls_md5_context *ctx,
|
|||||||
}
|
}
|
||||||
#endif
|
#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
|
* MD5 final digest
|
||||||
*/
|
*/
|
||||||
@ -324,26 +316,48 @@ int mbedtls_md5_finish_ret( mbedtls_md5_context *ctx,
|
|||||||
unsigned char output[16] )
|
unsigned char output[16] )
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
uint32_t last, padn;
|
uint32_t used;
|
||||||
uint32_t high, low;
|
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 )
|
high = ( ctx->total[0] >> 29 )
|
||||||
| ( ctx->total[1] << 3 );
|
| ( ctx->total[1] << 3 );
|
||||||
low = ( ctx->total[0] << 3 );
|
low = ( ctx->total[0] << 3 );
|
||||||
|
|
||||||
PUT_UINT32_LE( low, msglen, 0 );
|
PUT_UINT32_LE( low, ctx->buffer, 56 );
|
||||||
PUT_UINT32_LE( high, msglen, 4 );
|
PUT_UINT32_LE( high, ctx->buffer, 60 );
|
||||||
|
|
||||||
last = ctx->total[0] & 0x3F;
|
if( ( ret = mbedtls_internal_md5_process( ctx, ctx->buffer ) ) != 0 )
|
||||||
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 )
|
|
||||||
return( ret );
|
return( ret );
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Output final state
|
||||||
|
*/
|
||||||
PUT_UINT32_LE( ctx->state[0], output, 0 );
|
PUT_UINT32_LE( ctx->state[0], output, 0 );
|
||||||
PUT_UINT32_LE( ctx->state[1], output, 4 );
|
PUT_UINT32_LE( ctx->state[1], output, 4 );
|
||||||
PUT_UINT32_LE( ctx->state[2], output, 8 );
|
PUT_UINT32_LE( ctx->state[2], output, 8 );
|
||||||
|
@ -342,14 +342,6 @@ void mbedtls_sha1_update( mbedtls_sha1_context *ctx,
|
|||||||
}
|
}
|
||||||
#endif
|
#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
|
* SHA-1 final digest
|
||||||
*/
|
*/
|
||||||
@ -357,25 +349,48 @@ int mbedtls_sha1_finish_ret( mbedtls_sha1_context *ctx,
|
|||||||
unsigned char output[20] )
|
unsigned char output[20] )
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
uint32_t last, padn;
|
uint32_t used;
|
||||||
uint32_t high, low;
|
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 )
|
high = ( ctx->total[0] >> 29 )
|
||||||
| ( ctx->total[1] << 3 );
|
| ( ctx->total[1] << 3 );
|
||||||
low = ( ctx->total[0] << 3 );
|
low = ( ctx->total[0] << 3 );
|
||||||
|
|
||||||
PUT_UINT32_BE( high, msglen, 0 );
|
PUT_UINT32_BE( high, ctx->buffer, 56 );
|
||||||
PUT_UINT32_BE( low, msglen, 4 );
|
PUT_UINT32_BE( low, ctx->buffer, 60 );
|
||||||
|
|
||||||
last = ctx->total[0] & 0x3F;
|
if( ( ret = mbedtls_internal_sha1_process( ctx, ctx->buffer ) ) != 0 )
|
||||||
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 )
|
|
||||||
return( ret );
|
return( ret );
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Output final state
|
||||||
|
*/
|
||||||
PUT_UINT32_BE( ctx->state[0], output, 0 );
|
PUT_UINT32_BE( ctx->state[0], output, 0 );
|
||||||
PUT_UINT32_BE( ctx->state[1], output, 4 );
|
PUT_UINT32_BE( ctx->state[1], output, 4 );
|
||||||
PUT_UINT32_BE( ctx->state[2], output, 8 );
|
PUT_UINT32_BE( ctx->state[2], output, 8 );
|
||||||
|
@ -311,14 +311,6 @@ void mbedtls_sha256_update( mbedtls_sha256_context *ctx,
|
|||||||
}
|
}
|
||||||
#endif
|
#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
|
* SHA-256 final digest
|
||||||
*/
|
*/
|
||||||
@ -326,26 +318,48 @@ int mbedtls_sha256_finish_ret( mbedtls_sha256_context *ctx,
|
|||||||
unsigned char output[32] )
|
unsigned char output[32] )
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
uint32_t last, padn;
|
uint32_t used;
|
||||||
uint32_t high, low;
|
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 )
|
high = ( ctx->total[0] >> 29 )
|
||||||
| ( ctx->total[1] << 3 );
|
| ( ctx->total[1] << 3 );
|
||||||
low = ( ctx->total[0] << 3 );
|
low = ( ctx->total[0] << 3 );
|
||||||
|
|
||||||
PUT_UINT32_BE( high, msglen, 0 );
|
PUT_UINT32_BE( high, ctx->buffer, 56 );
|
||||||
PUT_UINT32_BE( low, msglen, 4 );
|
PUT_UINT32_BE( low, ctx->buffer, 60 );
|
||||||
|
|
||||||
last = ctx->total[0] & 0x3F;
|
if( ( ret = mbedtls_internal_sha256_process( ctx, ctx->buffer ) ) != 0 )
|
||||||
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 )
|
|
||||||
return( ret );
|
return( ret );
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Output final state
|
||||||
|
*/
|
||||||
PUT_UINT32_BE( ctx->state[0], output, 0 );
|
PUT_UINT32_BE( ctx->state[0], output, 0 );
|
||||||
PUT_UINT32_BE( ctx->state[1], output, 4 );
|
PUT_UINT32_BE( ctx->state[1], output, 4 );
|
||||||
PUT_UINT32_BE( ctx->state[2], output, 8 );
|
PUT_UINT32_BE( ctx->state[2], output, 8 );
|
||||||
|
@ -341,18 +341,6 @@ void mbedtls_sha512_update( mbedtls_sha512_context *ctx,
|
|||||||
}
|
}
|
||||||
#endif
|
#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
|
* SHA-512 final digest
|
||||||
*/
|
*/
|
||||||
@ -360,26 +348,48 @@ int mbedtls_sha512_finish_ret( mbedtls_sha512_context *ctx,
|
|||||||
unsigned char output[64] )
|
unsigned char output[64] )
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
size_t last, padn;
|
unsigned used;
|
||||||
uint64_t high, low;
|
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 )
|
high = ( ctx->total[0] >> 61 )
|
||||||
| ( ctx->total[1] << 3 );
|
| ( ctx->total[1] << 3 );
|
||||||
low = ( ctx->total[0] << 3 );
|
low = ( ctx->total[0] << 3 );
|
||||||
|
|
||||||
PUT_UINT64_BE( high, msglen, 0 );
|
PUT_UINT64_BE( high, ctx->buffer, 112 );
|
||||||
PUT_UINT64_BE( low, msglen, 8 );
|
PUT_UINT64_BE( low, ctx->buffer, 120 );
|
||||||
|
|
||||||
last = (size_t)( ctx->total[0] & 0x7F );
|
if( ( ret = mbedtls_internal_sha512_process( ctx, ctx->buffer ) ) != 0 )
|
||||||
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 )
|
|
||||||
return( ret );
|
return( ret );
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Output final state
|
||||||
|
*/
|
||||||
PUT_UINT64_BE( ctx->state[0], output, 0 );
|
PUT_UINT64_BE( ctx->state[0], output, 0 );
|
||||||
PUT_UINT64_BE( ctx->state[1], output, 8 );
|
PUT_UINT64_BE( ctx->state[1], output, 8 );
|
||||||
PUT_UINT64_BE( ctx->state[2], output, 16 );
|
PUT_UINT64_BE( ctx->state[2], output, 16 );
|
||||||
|
Loading…
Reference in New Issue
Block a user