Skip to content

Commit 39f14b8

Browse files
willco007Will Cosgrove
andauthored
transport.c: use constant time function for MAC memcmp() (libssh2#1824)
Notes: libssh2 uses a non-constant-time memcmp() call at transport.c:229 to verify SSH MAC tags. An on-path attacker can measure per-byte rejection latency to iteratively recover the correct MAC value without knowledge of the secret key, enabling MAC forgery. Empirical testing on macOS with libssh2 1.11.1_1 yields a t-statistic of 106.78 (threshold >2), confirming the oracle is real and practical (estimated 445,659 probes for full 32-byte HMAC-SHA2-256 forgery under lab conditions). Credit: [Pramod Kumar](https://github.com/infosecninja) --------- Co-authored-by: Will Cosgrove <will@everydaysoftware.net>
1 parent e7e0383 commit 39f14b8

3 files changed

Lines changed: 16 additions & 1 deletion

File tree

src/misc.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -966,3 +966,14 @@ int _libssh2_eob(struct string_buf *buf)
966966
unsigned char *endp = &buf->data[buf->len];
967967
return buf->dataptr >= endp;
968968
}
969+
970+
int _libssh2_timingsafe_bcmp(const void *b1, const void *b2, size_t n)
971+
{
972+
const unsigned char *p1 = (const unsigned char *)b1;
973+
const unsigned char *p2 = (const unsigned char *)b2;
974+
int ret = 0;
975+
976+
for(; n > 0; n--)
977+
ret |= *p1++ ^ *p2++;
978+
return (ret != 0);
979+
}

src/misc.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,4 +141,6 @@ void _libssh2_xor_data(unsigned char *output,
141141
const unsigned char *input2,
142142
size_t length);
143143

144+
int _libssh2_timingsafe_bcmp(const void *b1, const void *b2, size_t n);
145+
144146
#endif /* LIBSSH2_MISC_H */

src/transport.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,9 @@ fullpacket(LIBSSH2_SESSION * session, int encrypted /* 1 or 0 */ )
226226
* buffer. Note that 'payload_len' here is the packet_length
227227
* field which includes the padding but not the MAC.
228228
*/
229-
if(memcmp(macbuf, p->payload + p->total_num - mac_len, mac_len)) {
229+
if(_libssh2_timingsafe_bcmp(macbuf,
230+
p->payload + p->total_num - mac_len,
231+
mac_len)) {
230232
_libssh2_debug((session, LIBSSH2_TRACE_SOCKET,
231233
"Failed MAC check"));
232234
session->fullpacket_macstate = LIBSSH2_MAC_INVALID;

0 commit comments

Comments
 (0)