diff options
author | markus@openbsd.org <markus@openbsd.org> | 2016-07-18 11:35:33 +0000 |
---|---|---|
committer | Damien Miller <djm@mindrot.org> | 2016-07-22 13:36:40 +1000 |
commit | b98a2a8348e907b3d71caafd80f0be8fdd075943 (patch) | |
tree | 5827ba77ced2efb5136bad0b444356271ee1c853 | |
parent | dbf788b4d9d9490a5fff08a7b09888272bb10fcc (diff) |
upstream commit
Reduce timing attack against obsolete CBC modes by always
computing the MAC over a fixed size of data. Reported by Jean Paul
Degabriele, Kenny Paterson, Torben Hansen and Martin Albrecht. ok djm@
Upstream-ID: f20a13279b00ba0afbacbcc1f04e62e9d41c2912
-rw-r--r-- | packet.c | 37 |
1 files changed, 23 insertions, 14 deletions
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: packet.c,v 1.233 2016/07/18 06:08:01 djm Exp $ */ | 1 | /* $OpenBSD: packet.c,v 1.234 2016/07/18 11:35:33 markus Exp $ */ |
2 | /* | 2 | /* |
3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | 4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
@@ -196,6 +196,7 @@ struct session_state { | |||
196 | 196 | ||
197 | /* XXX discard incoming data after MAC error */ | 197 | /* XXX discard incoming data after MAC error */ |
198 | u_int packet_discard; | 198 | u_int packet_discard; |
199 | size_t packet_discard_mac_already; | ||
199 | struct sshmac *packet_discard_mac; | 200 | struct sshmac *packet_discard_mac; |
200 | 201 | ||
201 | /* Used in packet_read_poll2() */ | 202 | /* Used in packet_read_poll2() */ |
@@ -333,16 +334,18 @@ ssh_packet_stop_discard(struct ssh *ssh) | |||
333 | 334 | ||
334 | if (state->packet_discard_mac) { | 335 | if (state->packet_discard_mac) { |
335 | char buf[1024]; | 336 | char buf[1024]; |
337 | size_t dlen = PACKET_MAX_SIZE; | ||
336 | 338 | ||
339 | if (dlen > state->packet_discard_mac_already) | ||
340 | dlen -= state->packet_discard_mac_already; | ||
337 | memset(buf, 'a', sizeof(buf)); | 341 | memset(buf, 'a', sizeof(buf)); |
338 | while (sshbuf_len(state->incoming_packet) < | 342 | while (sshbuf_len(state->incoming_packet) < dlen) |
339 | PACKET_MAX_SIZE) | ||
340 | if ((r = sshbuf_put(state->incoming_packet, buf, | 343 | if ((r = sshbuf_put(state->incoming_packet, buf, |
341 | sizeof(buf))) != 0) | 344 | sizeof(buf))) != 0) |
342 | return r; | 345 | return r; |
343 | (void) mac_compute(state->packet_discard_mac, | 346 | (void) mac_compute(state->packet_discard_mac, |
344 | state->p_read.seqnr, | 347 | state->p_read.seqnr, |
345 | sshbuf_ptr(state->incoming_packet), PACKET_MAX_SIZE, | 348 | sshbuf_ptr(state->incoming_packet), dlen, |
346 | NULL, 0); | 349 | NULL, 0); |
347 | } | 350 | } |
348 | logit("Finished discarding for %.200s port %d", | 351 | logit("Finished discarding for %.200s port %d", |
@@ -352,7 +355,7 @@ ssh_packet_stop_discard(struct ssh *ssh) | |||
352 | 355 | ||
353 | static int | 356 | static int |
354 | ssh_packet_start_discard(struct ssh *ssh, struct sshenc *enc, | 357 | ssh_packet_start_discard(struct ssh *ssh, struct sshenc *enc, |
355 | struct sshmac *mac, u_int packet_length, u_int discard) | 358 | struct sshmac *mac, size_t mac_already, u_int discard) |
356 | { | 359 | { |
357 | struct session_state *state = ssh->state; | 360 | struct session_state *state = ssh->state; |
358 | int r; | 361 | int r; |
@@ -362,11 +365,16 @@ ssh_packet_start_discard(struct ssh *ssh, struct sshenc *enc, | |||
362 | return r; | 365 | return r; |
363 | return SSH_ERR_MAC_INVALID; | 366 | return SSH_ERR_MAC_INVALID; |
364 | } | 367 | } |
365 | if (packet_length != PACKET_MAX_SIZE && mac && mac->enabled) | 368 | /* |
369 | * Record number of bytes over which the mac has already | ||
370 | * been computed in order to minimize timing attacks. | ||
371 | */ | ||
372 | if (mac && mac->enabled) { | ||
366 | state->packet_discard_mac = mac; | 373 | state->packet_discard_mac = mac; |
367 | if (sshbuf_len(state->input) >= discard && | 374 | state->packet_discard_mac_already = mac_already; |
368 | (r = ssh_packet_stop_discard(ssh)) != 0) | 375 | } |
369 | return r; | 376 | if (sshbuf_len(state->input) >= discard) |
377 | return ssh_packet_stop_discard(ssh); | ||
370 | state->packet_discard = discard - sshbuf_len(state->input); | 378 | state->packet_discard = discard - sshbuf_len(state->input); |
371 | return 0; | 379 | return 0; |
372 | } | 380 | } |
@@ -1765,8 +1773,8 @@ ssh_packet_read_poll2(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p) | |||
1765 | sshbuf_dump(state->incoming_packet, stderr); | 1773 | sshbuf_dump(state->incoming_packet, stderr); |
1766 | #endif | 1774 | #endif |
1767 | logit("Bad packet length %u.", state->packlen); | 1775 | logit("Bad packet length %u.", state->packlen); |
1768 | return ssh_packet_start_discard(ssh, enc, mac, | 1776 | return ssh_packet_start_discard(ssh, enc, mac, 0, |
1769 | state->packlen, PACKET_MAX_SIZE); | 1777 | PACKET_MAX_SIZE); |
1770 | } | 1778 | } |
1771 | if ((r = sshbuf_consume(state->input, block_size)) != 0) | 1779 | if ((r = sshbuf_consume(state->input, block_size)) != 0) |
1772 | goto out; | 1780 | goto out; |
@@ -1788,8 +1796,8 @@ ssh_packet_read_poll2(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p) | |||
1788 | if (need % block_size != 0) { | 1796 | if (need % block_size != 0) { |
1789 | logit("padding error: need %d block %d mod %d", | 1797 | logit("padding error: need %d block %d mod %d", |
1790 | need, block_size, need % block_size); | 1798 | need, block_size, need % block_size); |
1791 | return ssh_packet_start_discard(ssh, enc, mac, | 1799 | return ssh_packet_start_discard(ssh, enc, mac, 0, |
1792 | state->packlen, PACKET_MAX_SIZE - block_size); | 1800 | PACKET_MAX_SIZE - block_size); |
1793 | } | 1801 | } |
1794 | /* | 1802 | /* |
1795 | * check if the entire packet has been received and | 1803 | * check if the entire packet has been received and |
@@ -1836,7 +1844,8 @@ ssh_packet_read_poll2(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p) | |||
1836 | if (need > PACKET_MAX_SIZE) | 1844 | if (need > PACKET_MAX_SIZE) |
1837 | return SSH_ERR_INTERNAL_ERROR; | 1845 | return SSH_ERR_INTERNAL_ERROR; |
1838 | return ssh_packet_start_discard(ssh, enc, mac, | 1846 | return ssh_packet_start_discard(ssh, enc, mac, |
1839 | state->packlen, PACKET_MAX_SIZE - need); | 1847 | sshbuf_len(state->incoming_packet), |
1848 | PACKET_MAX_SIZE - need); | ||
1840 | } | 1849 | } |
1841 | /* Remove MAC from input buffer */ | 1850 | /* Remove MAC from input buffer */ |
1842 | DBG(debug("MAC #%d ok", state->p_read.seqnr)); | 1851 | DBG(debug("MAC #%d ok", state->p_read.seqnr)); |