diff --git a/misc.c b/misc.c index 63de9d11..94b5ac8a 100644 --- a/misc.c +++ b/misc.c @@ -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; +} diff --git a/misc.h b/misc.h index a361d706..c38266d0 100644 --- a/misc.h +++ b/misc.h @@ -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. * diff --git a/sshmd5.c b/sshmd5.c index af139690..b7a03b5e 100644 --- a/sshmd5.c +++ b/sshmd5.c @@ -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 = { diff --git a/sshsh256.c b/sshsh256.c index 7ea25fbe..fdc8a3a5 100644 --- a/sshsh256.c +++ b/sshsh256.c @@ -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 = { diff --git a/sshsha.c b/sshsha.c index f22035fe..579bf4de 100644 --- a/sshsha.c +++ b/sshsha.c @@ -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,