1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-01-09 09:27:59 +00:00

Use a timing-safe memory compare to verify MACs.

Now that we have modes in which the MAC verification happens before
any other crypto operation and hence will be the only thing seen by an
attacker, it seems like about time we got round to doing it in a
cautious way that tries to prevent the attacker from using our memcmp
as a timing oracle.

So, here's an smemeq() function which has the semantics of !memcmp but
attempts to run in time dependent only on the length parameter. All
the MAC implementations now use this in place of !memcmp to verify the
MAC on input data.
This commit is contained in:
Simon Tatham 2015-04-26 23:31:11 +01:00
parent 183a9ee98b
commit 9d5a164021
5 changed files with 36 additions and 8 deletions

16
misc.c
View File

@ -1019,3 +1019,19 @@ int validate_manual_hostkey(char *key)
return FALSE;
}
int smemeq(const void *av, const void *bv, size_t len)
{
const unsigned char *a = (const unsigned char *)av;
const unsigned char *b = (const unsigned char *)bv;
unsigned val = 0;
while (len-- > 0) {
val |= *a++ ^ *b++;
}
/* Now val is 0 iff we want to return 1, and in the range
* 0x01..0xFF iff we want to return 0. So subtracting from 0x100
* will clear bit 8 iff we want to return 0, and leave it set iff
* we want to return 1, so then we can just shift down. */
return (0x100 - val) >> 8;
}

12
misc.h
View File

@ -64,8 +64,20 @@ int validate_manual_hostkey(char *key);
struct tm ltime(void);
/* Wipe sensitive data out of memory that's about to be freed. Simpler
* than memset because we don't need the fill char parameter; also
* attempts (by fiddly use of volatile) to inhibit the compiler from
* over-cleverly trying to optimise the memset away because it knows
* the variable is going out of scope. */
void smemclr(void *b, size_t len);
/* Compare two fixed-length chunks of memory for equality, without
* data-dependent control flow (so an attacker with a very accurate
* stopwatch can't try to guess where the first mismatching byte was).
* Returns 0 for mismatch or 1 for equality (unlike memcmp), hinted at
* by the 'eq' in the name. */
int smemeq(const void *av, const void *bv, size_t len);
/*
* Debugging functions.
*

View File

@ -287,7 +287,7 @@ static int hmacmd5_verresult(void *handle, unsigned char const *hmac)
{
unsigned char correct[16];
hmacmd5_genresult(handle, correct);
return !memcmp(correct, hmac, 16);
return smemeq(correct, hmac, 16);
}
static void hmacmd5_do_hmac_internal(void *handle,
@ -327,7 +327,7 @@ static int hmacmd5_verify(void *handle, unsigned char *blk, int len,
{
unsigned char correct[16];
hmacmd5_do_hmac_ssh(handle, blk, len, seq, correct);
return !memcmp(correct, blk + len, 16);
return smemeq(correct, blk + len, 16);
}
const struct ssh_mac ssh_hmac_md5 = {

View File

@ -307,7 +307,7 @@ static int hmacsha256_verresult(void *handle, unsigned char const *hmac)
{
unsigned char correct[32];
hmacsha256_genresult(handle, correct);
return !memcmp(correct, hmac, 32);
return smemeq(correct, hmac, 32);
}
static int sha256_verify(void *handle, unsigned char *blk, int len,
@ -315,7 +315,7 @@ static int sha256_verify(void *handle, unsigned char *blk, int len,
{
unsigned char correct[32];
sha256_do_hmac(handle, blk, len, seq, correct);
return !memcmp(correct, blk + len, 32);
return smemeq(correct, blk + len, 32);
}
const struct ssh_mac ssh_hmac_sha256 = {

View File

@ -342,7 +342,7 @@ static int hmacsha1_verresult(void *handle, unsigned char const *hmac)
{
unsigned char correct[20];
hmacsha1_genresult(handle, correct);
return !memcmp(correct, hmac, 20);
return smemeq(correct, hmac, 20);
}
static int sha1_verify(void *handle, unsigned char *blk, int len,
@ -350,7 +350,7 @@ static int sha1_verify(void *handle, unsigned char *blk, int len,
{
unsigned char correct[20];
sha1_do_hmac(handle, blk, len, seq, correct);
return !memcmp(correct, blk + len, 20);
return smemeq(correct, blk + len, 20);
}
static void hmacsha1_96_genresult(void *handle, unsigned char *hmac)
@ -372,7 +372,7 @@ static int hmacsha1_96_verresult(void *handle, unsigned char const *hmac)
{
unsigned char correct[20];
hmacsha1_genresult(handle, correct);
return !memcmp(correct, hmac, 12);
return smemeq(correct, hmac, 12);
}
static int sha1_96_verify(void *handle, unsigned char *blk, int len,
@ -380,7 +380,7 @@ static int sha1_96_verify(void *handle, unsigned char *blk, int len,
{
unsigned char correct[20];
sha1_do_hmac(handle, blk, len, seq, correct);
return !memcmp(correct, blk + len, 12);
return smemeq(correct, blk + len, 12);
}
void hmac_sha1_simple(void *key, int keylen, void *data, int datalen,