diff options
author | Damien Miller <djm@mindrot.org> | 2009-01-28 16:38:41 +1100 |
---|---|---|
committer | Damien Miller <djm@mindrot.org> | 2009-01-28 16:38:41 +1100 |
commit | 13ae44ce5865b720708aae9cb1d2e2f08a0d90cb (patch) | |
tree | b9acd30c2e1edfa1a4b7dcc26b8c11f8ea77b855 /packet.c | |
parent | 9aa72ba57af907af8f7228f64fca8a474797898f (diff) |
- markus@cvs.openbsd.org 2009/01/26 09:58:15
[cipher.c cipher.h packet.c]
Work around the CPNI-957037 Plaintext Recovery Attack by always
reading 256K of data on packet size or HMAC errors (in CBC mode only).
Help, feedback and ok djm@
Feedback from Martin Albrecht and Paterson Kenny
Diffstat (limited to 'packet.c')
-rw-r--r-- | packet.c | 72 |
1 files changed, 65 insertions, 7 deletions
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: packet.c,v 1.158 2008/11/21 15:47:38 markus Exp $ */ | 1 | /* $OpenBSD: packet.c,v 1.159 2009/01/26 09:58:15 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 |
@@ -84,6 +84,8 @@ | |||
84 | #define DBG(x) | 84 | #define DBG(x) |
85 | #endif | 85 | #endif |
86 | 86 | ||
87 | #define PACKET_MAX_SIZE (256 * 1024) | ||
88 | |||
87 | /* | 89 | /* |
88 | * This variable contains the file descriptors used for communicating with | 90 | * This variable contains the file descriptors used for communicating with |
89 | * the other side. connection_in is used for reading; connection_out for | 91 | * the other side. connection_in is used for reading; connection_out for |
@@ -160,6 +162,10 @@ static u_int ssh1_keylen; | |||
160 | /* roundup current message to extra_pad bytes */ | 162 | /* roundup current message to extra_pad bytes */ |
161 | static u_char extra_pad = 0; | 163 | static u_char extra_pad = 0; |
162 | 164 | ||
165 | /* XXX discard incoming data after MAC error */ | ||
166 | static u_int packet_discard = 0; | ||
167 | static Mac *packet_discard_mac = NULL; | ||
168 | |||
163 | struct packet { | 169 | struct packet { |
164 | TAILQ_ENTRY(packet) next; | 170 | TAILQ_ENTRY(packet) next; |
165 | u_char type; | 171 | u_char type; |
@@ -209,6 +215,36 @@ packet_set_timeout(int timeout, int count) | |||
209 | packet_timeout_ms = timeout * count * 1000; | 215 | packet_timeout_ms = timeout * count * 1000; |
210 | } | 216 | } |
211 | 217 | ||
218 | static void | ||
219 | packet_stop_discard(void) | ||
220 | { | ||
221 | if (packet_discard_mac) { | ||
222 | char buf[1024]; | ||
223 | |||
224 | memset(buf, 'a', sizeof(buf)); | ||
225 | while (buffer_len(&incoming_packet) < PACKET_MAX_SIZE) | ||
226 | buffer_append(&incoming_packet, buf, sizeof(buf)); | ||
227 | (void) mac_compute(packet_discard_mac, | ||
228 | p_read.seqnr, | ||
229 | buffer_ptr(&incoming_packet), | ||
230 | PACKET_MAX_SIZE); | ||
231 | } | ||
232 | logit("Finished discarding for %.200s", get_remote_ipaddr()); | ||
233 | cleanup_exit(255); | ||
234 | } | ||
235 | |||
236 | static void | ||
237 | packet_start_discard(Enc *enc, Mac *mac, u_int packet_length, u_int discard) | ||
238 | { | ||
239 | if (!cipher_is_cbc(enc->cipher)) | ||
240 | packet_disconnect("Packet corrupt"); | ||
241 | if (packet_length != PACKET_MAX_SIZE && mac && mac->enabled) | ||
242 | packet_discard_mac = mac; | ||
243 | if (buffer_len(&input) >= discard) | ||
244 | packet_stop_discard(); | ||
245 | packet_discard = discard - buffer_len(&input); | ||
246 | } | ||
247 | |||
212 | /* Returns 1 if remote host is connected via socket, 0 if not. */ | 248 | /* Returns 1 if remote host is connected via socket, 0 if not. */ |
213 | 249 | ||
214 | int | 250 | int |
@@ -1127,6 +1163,9 @@ packet_read_poll2(u_int32_t *seqnr_p) | |||
1127 | Mac *mac = NULL; | 1163 | Mac *mac = NULL; |
1128 | Comp *comp = NULL; | 1164 | Comp *comp = NULL; |
1129 | 1165 | ||
1166 | if (packet_discard) | ||
1167 | return SSH_MSG_NONE; | ||
1168 | |||
1130 | if (newkeys[MODE_IN] != NULL) { | 1169 | if (newkeys[MODE_IN] != NULL) { |
1131 | enc = &newkeys[MODE_IN]->enc; | 1170 | enc = &newkeys[MODE_IN]->enc; |
1132 | mac = &newkeys[MODE_IN]->mac; | 1171 | mac = &newkeys[MODE_IN]->mac; |
@@ -1148,12 +1187,14 @@ packet_read_poll2(u_int32_t *seqnr_p) | |||
1148 | block_size); | 1187 | block_size); |
1149 | cp = buffer_ptr(&incoming_packet); | 1188 | cp = buffer_ptr(&incoming_packet); |
1150 | packet_length = get_u32(cp); | 1189 | packet_length = get_u32(cp); |
1151 | if (packet_length < 1 + 4 || packet_length > 256 * 1024) { | 1190 | if (packet_length < 1 + 4 || packet_length > PACKET_MAX_SIZE) { |
1152 | #ifdef PACKET_DEBUG | 1191 | #ifdef PACKET_DEBUG |
1153 | buffer_dump(&incoming_packet); | 1192 | buffer_dump(&incoming_packet); |
1154 | #endif | 1193 | #endif |
1155 | packet_disconnect("Bad packet length %-10u", | 1194 | logit("Bad packet length %u.", packet_length); |
1156 | packet_length); | 1195 | packet_start_discard(enc, mac, packet_length, |
1196 | PACKET_MAX_SIZE); | ||
1197 | return SSH_MSG_NONE; | ||
1157 | } | 1198 | } |
1158 | DBG(debug("input: packet len %u", packet_length+4)); | 1199 | DBG(debug("input: packet len %u", packet_length+4)); |
1159 | buffer_consume(&input, block_size); | 1200 | buffer_consume(&input, block_size); |
@@ -1165,7 +1206,9 @@ packet_read_poll2(u_int32_t *seqnr_p) | |||
1165 | if (need % block_size != 0) { | 1206 | if (need % block_size != 0) { |
1166 | logit("padding error: need %d block %d mod %d", | 1207 | logit("padding error: need %d block %d mod %d", |
1167 | need, block_size, need % block_size); | 1208 | need, block_size, need % block_size); |
1168 | packet_disconnect("Bad packet length %-10u", packet_length); | 1209 | packet_start_discard(enc, mac, packet_length, |
1210 | PACKET_MAX_SIZE - block_size); | ||
1211 | return SSH_MSG_NONE; | ||
1169 | } | 1212 | } |
1170 | /* | 1213 | /* |
1171 | * check if the entire packet has been received and | 1214 | * check if the entire packet has been received and |
@@ -1188,11 +1231,19 @@ packet_read_poll2(u_int32_t *seqnr_p) | |||
1188 | macbuf = mac_compute(mac, p_read.seqnr, | 1231 | macbuf = mac_compute(mac, p_read.seqnr, |
1189 | buffer_ptr(&incoming_packet), | 1232 | buffer_ptr(&incoming_packet), |
1190 | buffer_len(&incoming_packet)); | 1233 | buffer_len(&incoming_packet)); |
1191 | if (memcmp(macbuf, buffer_ptr(&input), mac->mac_len) != 0) | 1234 | if (memcmp(macbuf, buffer_ptr(&input), mac->mac_len) != 0) { |
1192 | packet_disconnect("Corrupted MAC on input."); | 1235 | logit("Corrupted MAC on input."); |
1236 | if (need > PACKET_MAX_SIZE) | ||
1237 | fatal("internal error need %d", need); | ||
1238 | packet_start_discard(enc, mac, packet_length, | ||
1239 | PACKET_MAX_SIZE - need); | ||
1240 | return SSH_MSG_NONE; | ||
1241 | } | ||
1242 | |||
1193 | DBG(debug("MAC #%d ok", p_read.seqnr)); | 1243 | DBG(debug("MAC #%d ok", p_read.seqnr)); |
1194 | buffer_consume(&input, mac->mac_len); | 1244 | buffer_consume(&input, mac->mac_len); |
1195 | } | 1245 | } |
1246 | /* XXX now it's safe to use fatal/packet_disconnect */ | ||
1196 | if (seqnr_p != NULL) | 1247 | if (seqnr_p != NULL) |
1197 | *seqnr_p = p_read.seqnr; | 1248 | *seqnr_p = p_read.seqnr; |
1198 | if (++p_read.seqnr == 0) | 1249 | if (++p_read.seqnr == 0) |
@@ -1325,6 +1376,13 @@ packet_read_poll(void) | |||
1325 | void | 1376 | void |
1326 | packet_process_incoming(const char *buf, u_int len) | 1377 | packet_process_incoming(const char *buf, u_int len) |
1327 | { | 1378 | { |
1379 | if (packet_discard) { | ||
1380 | keep_alive_timeouts = 0; /* ?? */ | ||
1381 | if (len >= packet_discard) | ||
1382 | packet_stop_discard(); | ||
1383 | packet_discard -= len; | ||
1384 | return; | ||
1385 | } | ||
1328 | buffer_append(&input, buf, len); | 1386 | buffer_append(&input, buf, len); |
1329 | } | 1387 | } |
1330 | 1388 | ||