summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordjm@openbsd.org <djm@openbsd.org>2016-07-08 03:44:42 +0000
committerDamien Miller <djm@mindrot.org>2016-07-08 13:50:03 +1000
commit6d31193d0baa3da339c196ac49625b7ba1c2ecc7 (patch)
tree83c1b9c11099ff8577178f702f2cb34765229d9b
parent71f5598f06941f645a451948c4a5125c83828e1c (diff)
upstream commit
Improve crypto ordering for Encrypt-then-MAC (EtM) mode MAC algorithms. Previously we were computing the MAC, decrypting the packet and then checking the MAC. This gave rise to the possibility of creating a side-channel oracle in the decryption step, though no such oracle has been identified. This adds a mac_check() function that computes and checks the MAC in one pass, and uses it to advance MAC checking for EtM algorithms to before payload decryption. Reported by Jean Paul Degabriele, Kenny Paterson, Torben Hansen and Martin Albrecht. feedback and ok markus@ Upstream-ID: 1999bb67cab47dda5b10b80d8155fe83d4a1867b
-rw-r--r--mac.c23
-rw-r--r--mac.h4
-rw-r--r--packet.c35
3 files changed, 41 insertions, 21 deletions
diff --git a/mac.c b/mac.c
index f63fbff09..6b12cd197 100644
--- a/mac.c
+++ b/mac.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: mac.c,v 1.32 2015/01/15 18:32:54 naddy Exp $ */ 1/* $OpenBSD: mac.c,v 1.33 2016/07/08 03:44:42 djm Exp $ */
2/* 2/*
3 * Copyright (c) 2001 Markus Friedl. All rights reserved. 3 * Copyright (c) 2001 Markus Friedl. All rights reserved.
4 * 4 *
@@ -167,7 +167,8 @@ mac_init(struct sshmac *mac)
167} 167}
168 168
169int 169int
170mac_compute(struct sshmac *mac, u_int32_t seqno, const u_char *data, int datalen, 170mac_compute(struct sshmac *mac, u_int32_t seqno,
171 const u_char *data, int datalen,
171 u_char *digest, size_t dlen) 172 u_char *digest, size_t dlen)
172{ 173{
173 static union { 174 static union {
@@ -211,6 +212,24 @@ mac_compute(struct sshmac *mac, u_int32_t seqno, const u_char *data, int datalen
211 return 0; 212 return 0;
212} 213}
213 214
215int
216mac_check(struct sshmac *mac, u_int32_t seqno,
217 const u_char *data, size_t dlen,
218 const u_char *theirmac, size_t mlen)
219{
220 u_char ourmac[SSH_DIGEST_MAX_LENGTH];
221 int r;
222
223 if (mac->mac_len > mlen)
224 return SSH_ERR_INVALID_ARGUMENT;
225 if ((r = mac_compute(mac, seqno, data, dlen,
226 ourmac, sizeof(ourmac))) != 0)
227 return r;
228 if (timingsafe_bcmp(ourmac, theirmac, mac->mac_len) != 0)
229 return SSH_ERR_MAC_INVALID;
230 return 0;
231}
232
214void 233void
215mac_clear(struct sshmac *mac) 234mac_clear(struct sshmac *mac)
216{ 235{
diff --git a/mac.h b/mac.h
index e5f6b84d9..0b119d7a1 100644
--- a/mac.h
+++ b/mac.h
@@ -1,4 +1,4 @@
1/* $OpenBSD: mac.h,v 1.9 2015/01/13 19:31:40 markus Exp $ */ 1/* $OpenBSD: mac.h,v 1.10 2016/07/08 03:44:42 djm Exp $ */
2/* 2/*
3 * Copyright (c) 2001 Markus Friedl. All rights reserved. 3 * Copyright (c) 2001 Markus Friedl. All rights reserved.
4 * 4 *
@@ -46,6 +46,8 @@ int mac_setup(struct sshmac *, char *);
46int mac_init(struct sshmac *); 46int mac_init(struct sshmac *);
47int mac_compute(struct sshmac *, u_int32_t, const u_char *, int, 47int mac_compute(struct sshmac *, u_int32_t, const u_char *, int,
48 u_char *, size_t); 48 u_char *, size_t);
49int mac_check(struct sshmac *, u_int32_t, const u_char *, size_t,
50 const u_char *, size_t);
49void mac_clear(struct sshmac *); 51void mac_clear(struct sshmac *);
50 52
51#endif /* SSHMAC_H */ 53#endif /* SSHMAC_H */
diff --git a/packet.c b/packet.c
index 48111bb15..9839c94dd 100644
--- a/packet.c
+++ b/packet.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: packet.c,v 1.230 2016/03/07 19:02:43 djm Exp $ */ 1/* $OpenBSD: packet.c,v 1.231 2016/07/08 03:44:42 djm 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
@@ -1690,7 +1690,7 @@ ssh_packet_read_poll2(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p)
1690{ 1690{
1691 struct session_state *state = ssh->state; 1691 struct session_state *state = ssh->state;
1692 u_int padlen, need; 1692 u_int padlen, need;
1693 u_char *cp, macbuf[SSH_DIGEST_MAX_LENGTH]; 1693 u_char *cp;
1694 u_int maclen, aadlen = 0, authlen = 0, block_size; 1694 u_int maclen, aadlen = 0, authlen = 0, block_size;
1695 struct sshenc *enc = NULL; 1695 struct sshenc *enc = NULL;
1696 struct sshmac *mac = NULL; 1696 struct sshmac *mac = NULL;
@@ -1790,17 +1790,21 @@ ssh_packet_read_poll2(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p)
1790 * 'maclen' bytes of message authentication code. 1790 * 'maclen' bytes of message authentication code.
1791 */ 1791 */
1792 if (sshbuf_len(state->input) < aadlen + need + authlen + maclen) 1792 if (sshbuf_len(state->input) < aadlen + need + authlen + maclen)
1793 return 0; 1793 return 0; /* packet is incomplete */
1794#ifdef PACKET_DEBUG 1794#ifdef PACKET_DEBUG
1795 fprintf(stderr, "read_poll enc/full: "); 1795 fprintf(stderr, "read_poll enc/full: ");
1796 sshbuf_dump(state->input, stderr); 1796 sshbuf_dump(state->input, stderr);
1797#endif 1797#endif
1798 /* EtM: compute mac over encrypted input */ 1798 /* EtM: check mac over encrypted input */
1799 if (mac && mac->enabled && mac->etm) { 1799 if (mac && mac->enabled && mac->etm) {
1800 if ((r = mac_compute(mac, state->p_read.seqnr, 1800 if ((r = mac_check(mac, state->p_read.seqnr,
1801 sshbuf_ptr(state->input), aadlen + need, 1801 sshbuf_ptr(state->input), aadlen + need,
1802 macbuf, sizeof(macbuf))) != 0) 1802 sshbuf_ptr(state->input) + aadlen + need + authlen,
1803 maclen)) != 0) {
1804 if (r == SSH_ERR_MAC_INVALID)
1805 logit("Corrupted MAC on input.");
1803 goto out; 1806 goto out;
1807 }
1804 } 1808 }
1805 if ((r = sshbuf_reserve(state->incoming_packet, aadlen + need, 1809 if ((r = sshbuf_reserve(state->incoming_packet, aadlen + need,
1806 &cp)) != 0) 1810 &cp)) != 0)
@@ -1810,26 +1814,21 @@ ssh_packet_read_poll2(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p)
1810 goto out; 1814 goto out;
1811 if ((r = sshbuf_consume(state->input, aadlen + need + authlen)) != 0) 1815 if ((r = sshbuf_consume(state->input, aadlen + need + authlen)) != 0)
1812 goto out; 1816 goto out;
1813 /*
1814 * compute MAC over seqnr and packet,
1815 * increment sequence number for incoming packet
1816 */
1817 if (mac && mac->enabled) { 1817 if (mac && mac->enabled) {
1818 if (!mac->etm) 1818 /* Not EtM: check MAC over cleartext */
1819 if ((r = mac_compute(mac, state->p_read.seqnr, 1819 if (!mac->etm && (r = mac_check(mac, state->p_read.seqnr,
1820 sshbuf_ptr(state->incoming_packet), 1820 sshbuf_ptr(state->incoming_packet),
1821 sshbuf_len(state->incoming_packet), 1821 sshbuf_len(state->incoming_packet),
1822 macbuf, sizeof(macbuf))) != 0) 1822 sshbuf_ptr(state->input), maclen)) != 0) {
1823 if (r != SSH_ERR_MAC_INVALID)
1823 goto out; 1824 goto out;
1824 if (timingsafe_bcmp(macbuf, sshbuf_ptr(state->input),
1825 mac->mac_len) != 0) {
1826 logit("Corrupted MAC on input."); 1825 logit("Corrupted MAC on input.");
1827 if (need > PACKET_MAX_SIZE) 1826 if (need > PACKET_MAX_SIZE)
1828 return SSH_ERR_INTERNAL_ERROR; 1827 return SSH_ERR_INTERNAL_ERROR;
1829 return ssh_packet_start_discard(ssh, enc, mac, 1828 return ssh_packet_start_discard(ssh, enc, mac,
1830 state->packlen, PACKET_MAX_SIZE - need); 1829 state->packlen, PACKET_MAX_SIZE - need);
1831 } 1830 }
1832 1831 /* Remove MAC from input buffer */
1833 DBG(debug("MAC #%d ok", state->p_read.seqnr)); 1832 DBG(debug("MAC #%d ok", state->p_read.seqnr));
1834 if ((r = sshbuf_consume(state->input, mac->mac_len)) != 0) 1833 if ((r = sshbuf_consume(state->input, mac->mac_len)) != 0)
1835 goto out; 1834 goto out;