diff options
author | Damien Miller <djm@mindrot.org> | 2012-12-12 10:46:31 +1100 |
---|---|---|
committer | Damien Miller <djm@mindrot.org> | 2012-12-12 10:46:31 +1100 |
commit | af43a7ac2d77c57112b48f34c7a72be2adb761bc (patch) | |
tree | 4381616492fbbca62d39c042f16221f681c1d37f | |
parent | 6a1937eac5da5bdcf33aaa922ce5de0c764e37ed (diff) |
- markus@cvs.openbsd.org 2012/12/11 22:31:18
[PROTOCOL authfile.c cipher.c cipher.h kex.h mac.c myproposal.h]
[packet.c ssh_config.5 sshd_config.5]
add encrypt-then-mac (EtM) modes to openssh by defining new mac algorithms
that change the packet format and compute the MAC over the encrypted
message (including the packet size) instead of the plaintext data;
these EtM modes are considered more secure and used by default.
feedback and ok djm@
-rw-r--r-- | ChangeLog | 8 | ||||
-rw-r--r-- | PROTOCOL | 29 | ||||
-rw-r--r-- | authfile.c | 6 | ||||
-rw-r--r-- | cipher.c | 22 | ||||
-rw-r--r-- | cipher.h | 4 | ||||
-rw-r--r-- | kex.h | 3 | ||||
-rw-r--r-- | mac.c | 40 | ||||
-rw-r--r-- | myproposal.h | 11 | ||||
-rw-r--r-- | packet.c | 113 | ||||
-rw-r--r-- | ssh_config.5 | 13 | ||||
-rw-r--r-- | sshd_config.5 | 13 |
11 files changed, 196 insertions, 66 deletions
@@ -4,6 +4,14 @@ | |||
4 | [monitor.c] | 4 | [monitor.c] |
5 | drain the log messages after receiving the keystate from the unpriv | 5 | drain the log messages after receiving the keystate from the unpriv |
6 | child. otherwise it might block while sending. ok djm@ | 6 | child. otherwise it might block while sending. ok djm@ |
7 | - markus@cvs.openbsd.org 2012/12/11 22:31:18 | ||
8 | [PROTOCOL authfile.c cipher.c cipher.h kex.h mac.c myproposal.h] | ||
9 | [packet.c ssh_config.5 sshd_config.5] | ||
10 | add encrypt-then-mac (EtM) modes to openssh by defining new mac algorithms | ||
11 | that change the packet format and compute the MAC over the encrypted | ||
12 | message (including the packet size) instead of the plaintext data; | ||
13 | these EtM modes are considered more secure and used by default. | ||
14 | feedback and ok djm@ | ||
7 | 15 | ||
8 | 20121207 | 16 | 20121207 |
9 | - (dtucker) OpenBSD CVS Sync | 17 | - (dtucker) OpenBSD CVS Sync |
@@ -51,6 +51,33 @@ and ecdsa-sha2-nistp521 curves over GF(p) are supported. Elliptic | |||
51 | curve points encoded using point compression are NOT accepted or | 51 | curve points encoded using point compression are NOT accepted or |
52 | generated. | 52 | generated. |
53 | 53 | ||
54 | 1.5 transport: Protocol 2 Encrypt-then-MAC MAC algorithms | ||
55 | |||
56 | OpenSSH supports MAC algorithms, whose names contain "-etm", that | ||
57 | perform the calculations in a different order to that defined in RFC | ||
58 | 4253. These variants use the so-called "encrypt then MAC" ordering, | ||
59 | calculating the MAC over the packet ciphertext rather than the | ||
60 | plaintext. This ordering closes a security flaw in the SSH transport | ||
61 | protocol, where decryption of unauthenticated ciphertext provided a | ||
62 | "decryption oracle" that could, in conjunction with cipher flaws, reveal | ||
63 | session plaintext. | ||
64 | |||
65 | Specifically, the "-etm" MAC algorithms modify the transport protocol | ||
66 | to calculate the MAC over the packet ciphertext and to send the packet | ||
67 | length unencrypted. This is necessary for the transport to obtain the | ||
68 | length of the packet and location of the MAC tag so that it may be | ||
69 | verified without decrypting unauthenticated data. | ||
70 | |||
71 | As such, the MAC covers: | ||
72 | |||
73 | mac = MAC(key, sequence_number || encrypted_packet) | ||
74 | |||
75 | where "encrypted_packet" contains: | ||
76 | |||
77 | byte padding_length | ||
78 | byte[n1] payload; n1 = packet_length - padding_length - 1 | ||
79 | byte[n2] random padding; n2 = padding_length | ||
80 | |||
54 | 2. Connection protocol changes | 81 | 2. Connection protocol changes |
55 | 82 | ||
56 | 2.1. connection: Channel write close extension "eow@openssh.com" | 83 | 2.1. connection: Channel write close extension "eow@openssh.com" |
@@ -291,4 +318,4 @@ link(oldpath, newpath) and will respond with a SSH_FXP_STATUS message. | |||
291 | This extension is advertised in the SSH_FXP_VERSION hello with version | 318 | This extension is advertised in the SSH_FXP_VERSION hello with version |
292 | "1". | 319 | "1". |
293 | 320 | ||
294 | $OpenBSD: PROTOCOL,v 1.17 2010/12/04 00:18:01 djm Exp $ | 321 | $OpenBSD: PROTOCOL,v 1.18 2012/12/11 22:31:18 markus Exp $ |
diff --git a/authfile.c b/authfile.c index 7dd449690..d9ee4ca65 100644 --- a/authfile.c +++ b/authfile.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: authfile.c,v 1.93 2012/01/25 19:36:31 markus Exp $ */ | 1 | /* $OpenBSD: authfile.c,v 1.94 2012/12/11 22:31:18 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 |
@@ -150,7 +150,7 @@ key_private_rsa1_to_blob(Key *key, Buffer *blob, const char *passphrase, | |||
150 | cipher_set_key_string(&ciphercontext, cipher, passphrase, | 150 | cipher_set_key_string(&ciphercontext, cipher, passphrase, |
151 | CIPHER_ENCRYPT); | 151 | CIPHER_ENCRYPT); |
152 | cipher_crypt(&ciphercontext, cp, | 152 | cipher_crypt(&ciphercontext, cp, |
153 | buffer_ptr(&buffer), buffer_len(&buffer)); | 153 | buffer_ptr(&buffer), buffer_len(&buffer), 0); |
154 | cipher_cleanup(&ciphercontext); | 154 | cipher_cleanup(&ciphercontext); |
155 | memset(&ciphercontext, 0, sizeof(ciphercontext)); | 155 | memset(&ciphercontext, 0, sizeof(ciphercontext)); |
156 | 156 | ||
@@ -474,7 +474,7 @@ key_parse_private_rsa1(Buffer *blob, const char *passphrase, char **commentp) | |||
474 | cipher_set_key_string(&ciphercontext, cipher, passphrase, | 474 | cipher_set_key_string(&ciphercontext, cipher, passphrase, |
475 | CIPHER_DECRYPT); | 475 | CIPHER_DECRYPT); |
476 | cipher_crypt(&ciphercontext, cp, | 476 | cipher_crypt(&ciphercontext, cp, |
477 | buffer_ptr(©), buffer_len(©)); | 477 | buffer_ptr(©), buffer_len(©), 0); |
478 | cipher_cleanup(&ciphercontext); | 478 | cipher_cleanup(&ciphercontext); |
479 | memset(&ciphercontext, 0, sizeof(ciphercontext)); | 479 | memset(&ciphercontext, 0, sizeof(ciphercontext)); |
480 | buffer_free(©); | 480 | buffer_free(©); |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: cipher.c,v 1.82 2009/01/26 09:58:15 markus Exp $ */ | 1 | /* $OpenBSD: cipher.c,v 1.83 2012/12/11 22:31:18 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 |
@@ -273,13 +273,25 @@ cipher_init(CipherContext *cc, Cipher *cipher, | |||
273 | } | 273 | } |
274 | } | 274 | } |
275 | 275 | ||
276 | /* | ||
277 | * cipher_crypt() operates as following: | ||
278 | * Copy 'aadlen' bytes (without en/decryption) from 'src' to 'dest'. | ||
279 | * Theses bytes are treated as additional authenticated data for | ||
280 | * authenticated encryption modes. | ||
281 | * En/Decrypt 'len' bytes at offset 'aadlen' from 'src' to 'dest'. | ||
282 | * Both 'aadlen' and 'authlen' can be set to 0. | ||
283 | */ | ||
276 | void | 284 | void |
277 | cipher_crypt(CipherContext *cc, u_char *dest, const u_char *src, u_int len) | 285 | cipher_crypt(CipherContext *cc, u_char *dest, const u_char *src, |
286 | u_int len, u_int aadlen) | ||
278 | { | 287 | { |
288 | if (aadlen) | ||
289 | memcpy(dest, src, aadlen); | ||
279 | if (len % cc->cipher->block_size) | 290 | if (len % cc->cipher->block_size) |
280 | fatal("cipher_encrypt: bad plaintext length %d", len); | 291 | fatal("%s: bad plaintext length %d", __func__, len); |
281 | if (EVP_Cipher(&cc->evp, dest, (u_char *)src, len) == 0) | 292 | if (EVP_Cipher(&cc->evp, dest + aadlen, (u_char *)src + aadlen, |
282 | fatal("evp_crypt: EVP_Cipher failed"); | 293 | len) < 0) |
294 | fatal("%s: EVP_Cipher failed", __func__); | ||
283 | } | 295 | } |
284 | 296 | ||
285 | void | 297 | void |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: cipher.h,v 1.37 2009/01/26 09:58:15 markus Exp $ */ | 1 | /* $OpenBSD: cipher.h,v 1.38 2012/12/11 22:31:18 markus Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 4 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
@@ -76,7 +76,7 @@ char *cipher_name(int); | |||
76 | int ciphers_valid(const char *); | 76 | int ciphers_valid(const char *); |
77 | void cipher_init(CipherContext *, Cipher *, const u_char *, u_int, | 77 | void cipher_init(CipherContext *, Cipher *, const u_char *, u_int, |
78 | const u_char *, u_int, int); | 78 | const u_char *, u_int, int); |
79 | void cipher_crypt(CipherContext *, u_char *, const u_char *, u_int); | 79 | void cipher_crypt(CipherContext *, u_char *, const u_char *, u_int, u_int); |
80 | void cipher_cleanup(CipherContext *); | 80 | void cipher_cleanup(CipherContext *); |
81 | void cipher_set_key_string(CipherContext *, Cipher *, const char *, int); | 81 | void cipher_set_key_string(CipherContext *, Cipher *, const char *, int); |
82 | u_int cipher_blocksize(const Cipher *); | 82 | u_int cipher_blocksize(const Cipher *); |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: kex.h,v 1.52 2010/09/22 05:01:29 djm Exp $ */ | 1 | /* $OpenBSD: kex.h,v 1.53 2012/12/11 22:31:18 markus Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. | 4 | * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. |
@@ -100,6 +100,7 @@ struct Mac { | |||
100 | u_char *key; | 100 | u_char *key; |
101 | u_int key_len; | 101 | u_int key_len; |
102 | int type; | 102 | int type; |
103 | int etm; /* Encrypt-then-MAC */ | ||
103 | const EVP_MD *evp_md; | 104 | const EVP_MD *evp_md; |
104 | HMAC_CTX evp_ctx; | 105 | HMAC_CTX evp_ctx; |
105 | struct umac_ctx *umac_ctx; | 106 | struct umac_ctx *umac_ctx; |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: mac.c,v 1.19 2012/10/04 13:21:50 markus Exp $ */ | 1 | /* $OpenBSD: mac.c,v 1.20 2012/12/11 22:31:18 markus Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2001 Markus Friedl. All rights reserved. | 3 | * Copyright (c) 2001 Markus Friedl. All rights reserved. |
4 | * | 4 | * |
@@ -58,19 +58,34 @@ struct { | |||
58 | int key_len; /* just for UMAC */ | 58 | int key_len; /* just for UMAC */ |
59 | int len; /* just for UMAC */ | 59 | int len; /* just for UMAC */ |
60 | } macs[] = { | 60 | } macs[] = { |
61 | { "hmac-sha1", SSH_EVP, EVP_sha1, 0, -1, -1 }, | 61 | /* Encrypt-and-MAC (encrypt-and-authenticate) variants */ |
62 | { "hmac-sha1-96", SSH_EVP, EVP_sha1, 96, -1, -1 }, | 62 | { "hmac-sha1", SSH_EVP, EVP_sha1, 0, 0, 0, 0 }, |
63 | { "hmac-sha1-96", SSH_EVP, EVP_sha1, 96, 0, 0, 0 }, | ||
63 | #ifdef HAVE_EVP_SHA256 | 64 | #ifdef HAVE_EVP_SHA256 |
64 | { "hmac-sha2-256", SSH_EVP, EVP_sha256, 0, -1, -1 }, | 65 | { "hmac-sha2-256", SSH_EVP, EVP_sha256, 0, 0, 0, 0 }, |
65 | { "hmac-sha2-512", SSH_EVP, EVP_sha512, 0, -1, -1 }, | 66 | { "hmac-sha2-512", SSH_EVP, EVP_sha512, 0, 0, 0, 0 }, |
66 | #endif | 67 | #endif |
67 | { "hmac-md5", SSH_EVP, EVP_md5, 0, -1, -1 }, | 68 | { "hmac-md5", SSH_EVP, EVP_md5, 0, 0, 0, 0 }, |
68 | { "hmac-md5-96", SSH_EVP, EVP_md5, 96, -1, -1 }, | 69 | { "hmac-md5-96", SSH_EVP, EVP_md5, 96, 0, 0, 0 }, |
69 | { "hmac-ripemd160", SSH_EVP, EVP_ripemd160, 0, -1, -1 }, | 70 | { "hmac-ripemd160", SSH_EVP, EVP_ripemd160, 0, 0, 0, 0 }, |
70 | { "hmac-ripemd160@openssh.com", SSH_EVP, EVP_ripemd160, 0, -1, -1 }, | 71 | { "hmac-ripemd160@openssh.com", SSH_EVP, EVP_ripemd160, 0, 0, 0, 0 }, |
71 | { "umac-64@openssh.com", SSH_UMAC, NULL, 0, 128, 64 }, | 72 | { "umac-64@openssh.com", SSH_UMAC, NULL, 0, 128, 64, 0 }, |
72 | { "umac-128@openssh.com", SSH_UMAC128, NULL, 0, 128, 128 }, | 73 | { "umac-128@openssh.com", SSH_UMAC128, NULL, 0, 128, 128, 0 }, |
73 | { NULL, 0, NULL, 0, -1, -1 } | 74 | |
75 | /* Encrypt-then-MAC variants */ | ||
76 | { "hmac-sha1-etm@openssh.com", SSH_EVP, EVP_sha1, 0, 0, 0, 1 }, | ||
77 | { "hmac-sha1-96-etm@openssh.com", SSH_EVP, EVP_sha1, 96, 0, 0, 1 }, | ||
78 | #ifdef HAVE_EVP_SHA256 | ||
79 | { "hmac-sha2-256-etm@openssh.com", SSH_EVP, EVP_sha256, 0, 0, 0, 1 }, | ||
80 | { "hmac-sha2-512-etm@openssh.com", SSH_EVP, EVP_sha512, 0, 0, 0, 1 }, | ||
81 | #endif | ||
82 | { "hmac-md5-etm@openssh.com", SSH_EVP, EVP_md5, 0, 0, 0, 1 }, | ||
83 | { "hmac-md5-96-etm@openssh.com", SSH_EVP, EVP_md5, 96, 0, 0, 1 }, | ||
84 | { "hmac-ripemd160-tem@openssh.com", SSH_EVP, EVP_ripemd160, 0, 0, 0, 1 }, | ||
85 | { "umac-64-etm@openssh.com", SSH_UMAC, NULL, 0, 128, 64, 1 }, | ||
86 | { "umac-128-etm@openssh.com", SSH_UMAC128, NULL, 0, 128, 128, 1 }, | ||
87 | |||
88 | { NULL, 0, NULL, 0, 0, 0, 0 } | ||
74 | }; | 89 | }; |
75 | 90 | ||
76 | static void | 91 | static void |
@@ -90,6 +105,7 @@ mac_setup_by_id(Mac *mac, int which) | |||
90 | } | 105 | } |
91 | if (macs[which].truncatebits != 0) | 106 | if (macs[which].truncatebits != 0) |
92 | mac->mac_len = macs[which].truncatebits / 8; | 107 | mac->mac_len = macs[which].truncatebits / 8; |
108 | mac->etm = macs[which].etm; | ||
93 | } | 109 | } |
94 | 110 | ||
95 | int | 111 | int |
diff --git a/myproposal.h b/myproposal.h index 5e2b99857..d98f4b051 100644 --- a/myproposal.h +++ b/myproposal.h | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: myproposal.h,v 1.30 2012/10/04 13:21:50 markus Exp $ */ | 1 | /* $OpenBSD: myproposal.h,v 1.31 2012/12/11 22:31:18 markus Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Copyright (c) 2000 Markus Friedl. All rights reserved. | 4 | * Copyright (c) 2000 Markus Friedl. All rights reserved. |
@@ -83,6 +83,15 @@ | |||
83 | # define SHA2_HMAC_MODES | 83 | # define SHA2_HMAC_MODES |
84 | #endif | 84 | #endif |
85 | #define KEX_DEFAULT_MAC \ | 85 | #define KEX_DEFAULT_MAC \ |
86 | "hmac-md5-etm@openssh.com," \ | ||
87 | "hmac-sha1-etm@openssh.com," \ | ||
88 | "umac-64-etm@openssh.com," \ | ||
89 | "umac-128-etm@openssh.com," \ | ||
90 | "hmac-sha2-256-etm@openssh.com," \ | ||
91 | "hmac-sha2-512-etm@openssh.com," \ | ||
92 | "hmac-ripemd160-etm@openssh.com," \ | ||
93 | "hmac-sha1-96-etm@openssh.com," \ | ||
94 | "hmac-md5-96-etm@openssh.com," \ | ||
86 | "hmac-md5," \ | 95 | "hmac-md5," \ |
87 | "hmac-sha1," \ | 96 | "hmac-sha1," \ |
88 | "umac-64@openssh.com," \ | 97 | "umac-64@openssh.com," \ |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: packet.c,v 1.177 2012/09/17 13:04:11 markus Exp $ */ | 1 | /* $OpenBSD: packet.c,v 1.178 2012/12/11 22:31:18 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 |
@@ -275,7 +275,7 @@ packet_stop_discard(void) | |||
275 | static void | 275 | static void |
276 | packet_start_discard(Enc *enc, Mac *mac, u_int packet_length, u_int discard) | 276 | packet_start_discard(Enc *enc, Mac *mac, u_int packet_length, u_int discard) |
277 | { | 277 | { |
278 | if (enc == NULL || !cipher_is_cbc(enc->cipher)) | 278 | if (enc == NULL || !cipher_is_cbc(enc->cipher) || (mac && mac->etm)) |
279 | packet_disconnect("Packet corrupt"); | 279 | packet_disconnect("Packet corrupt"); |
280 | if (packet_length != PACKET_MAX_SIZE && mac && mac->enabled) | 280 | if (packet_length != PACKET_MAX_SIZE && mac && mac->enabled) |
281 | active_state->packet_discard_mac = mac; | 281 | active_state->packet_discard_mac = mac; |
@@ -709,7 +709,7 @@ packet_send1(void) | |||
709 | buffer_len(&active_state->outgoing_packet)); | 709 | buffer_len(&active_state->outgoing_packet)); |
710 | cipher_crypt(&active_state->send_context, cp, | 710 | cipher_crypt(&active_state->send_context, cp, |
711 | buffer_ptr(&active_state->outgoing_packet), | 711 | buffer_ptr(&active_state->outgoing_packet), |
712 | buffer_len(&active_state->outgoing_packet)); | 712 | buffer_len(&active_state->outgoing_packet), 0); |
713 | 713 | ||
714 | #ifdef PACKET_DEBUG | 714 | #ifdef PACKET_DEBUG |
715 | fprintf(stderr, "encrypted: "); | 715 | fprintf(stderr, "encrypted: "); |
@@ -845,9 +845,8 @@ static void | |||
845 | packet_send2_wrapped(void) | 845 | packet_send2_wrapped(void) |
846 | { | 846 | { |
847 | u_char type, *cp, *macbuf = NULL; | 847 | u_char type, *cp, *macbuf = NULL; |
848 | u_char padlen, pad; | 848 | u_char padlen, pad = 0; |
849 | u_int packet_length = 0; | 849 | u_int i, len, aadlen = 0; |
850 | u_int i, len; | ||
851 | u_int32_t rnd = 0; | 850 | u_int32_t rnd = 0; |
852 | Enc *enc = NULL; | 851 | Enc *enc = NULL; |
853 | Mac *mac = NULL; | 852 | Mac *mac = NULL; |
@@ -860,6 +859,7 @@ packet_send2_wrapped(void) | |||
860 | comp = &active_state->newkeys[MODE_OUT]->comp; | 859 | comp = &active_state->newkeys[MODE_OUT]->comp; |
861 | } | 860 | } |
862 | block_size = enc ? enc->block_size : 8; | 861 | block_size = enc ? enc->block_size : 8; |
862 | aadlen = mac && mac->enabled && mac->etm ? 4 : 0; | ||
863 | 863 | ||
864 | cp = buffer_ptr(&active_state->outgoing_packet); | 864 | cp = buffer_ptr(&active_state->outgoing_packet); |
865 | type = cp[5]; | 865 | type = cp[5]; |
@@ -892,6 +892,7 @@ packet_send2_wrapped(void) | |||
892 | * calc size of padding, alloc space, get random data, | 892 | * calc size of padding, alloc space, get random data, |
893 | * minimum padding is 4 bytes | 893 | * minimum padding is 4 bytes |
894 | */ | 894 | */ |
895 | len -= aadlen; /* packet length is not encrypted for EtM modes */ | ||
895 | padlen = block_size - (len % block_size); | 896 | padlen = block_size - (len % block_size); |
896 | if (padlen < 4) | 897 | if (padlen < 4) |
897 | padlen += block_size; | 898 | padlen += block_size; |
@@ -919,29 +920,37 @@ packet_send2_wrapped(void) | |||
919 | /* clear padding */ | 920 | /* clear padding */ |
920 | memset(cp, 0, padlen); | 921 | memset(cp, 0, padlen); |
921 | } | 922 | } |
922 | /* packet_length includes payload, padding and padding length field */ | 923 | /* sizeof (packet_len + pad_len + payload + padding) */ |
923 | packet_length = buffer_len(&active_state->outgoing_packet) - 4; | 924 | len = buffer_len(&active_state->outgoing_packet); |
924 | cp = buffer_ptr(&active_state->outgoing_packet); | 925 | cp = buffer_ptr(&active_state->outgoing_packet); |
925 | put_u32(cp, packet_length); | 926 | /* packet_length includes payload, padding and padding length field */ |
927 | put_u32(cp, len - 4); | ||
926 | cp[4] = padlen; | 928 | cp[4] = padlen; |
927 | DBG(debug("send: len %d (includes padlen %d)", packet_length+4, padlen)); | 929 | DBG(debug("send: len %d (includes padlen %d, aadlen %d)", |
930 | len, padlen, aadlen)); | ||
928 | 931 | ||
929 | /* compute MAC over seqnr and packet(length fields, payload, padding) */ | 932 | /* compute MAC over seqnr and packet(length fields, payload, padding) */ |
930 | if (mac && mac->enabled) { | 933 | if (mac && mac->enabled && !mac->etm) { |
931 | macbuf = mac_compute(mac, active_state->p_send.seqnr, | 934 | macbuf = mac_compute(mac, active_state->p_send.seqnr, |
932 | buffer_ptr(&active_state->outgoing_packet), | 935 | buffer_ptr(&active_state->outgoing_packet), len); |
933 | buffer_len(&active_state->outgoing_packet)); | ||
934 | DBG(debug("done calc MAC out #%d", active_state->p_send.seqnr)); | 936 | DBG(debug("done calc MAC out #%d", active_state->p_send.seqnr)); |
935 | } | 937 | } |
936 | /* encrypt packet and append to output buffer. */ | 938 | /* encrypt packet and append to output buffer. */ |
937 | cp = buffer_append_space(&active_state->output, | 939 | cp = buffer_append_space(&active_state->output, len); |
938 | buffer_len(&active_state->outgoing_packet)); | ||
939 | cipher_crypt(&active_state->send_context, cp, | 940 | cipher_crypt(&active_state->send_context, cp, |
940 | buffer_ptr(&active_state->outgoing_packet), | 941 | buffer_ptr(&active_state->outgoing_packet), |
941 | buffer_len(&active_state->outgoing_packet)); | 942 | len - aadlen, aadlen); |
942 | /* append unencrypted MAC */ | 943 | /* append unencrypted MAC */ |
943 | if (mac && mac->enabled) | 944 | if (mac && mac->enabled) { |
945 | if (mac->etm) { | ||
946 | /* EtM: compute mac over aadlen + cipher text */ | ||
947 | macbuf = mac_compute(mac, | ||
948 | active_state->p_send.seqnr, cp, len); | ||
949 | DBG(debug("done calc MAC(EtM) out #%d", | ||
950 | active_state->p_send.seqnr)); | ||
951 | } | ||
944 | buffer_append(&active_state->output, macbuf, mac->mac_len); | 952 | buffer_append(&active_state->output, macbuf, mac->mac_len); |
953 | } | ||
945 | #ifdef PACKET_DEBUG | 954 | #ifdef PACKET_DEBUG |
946 | fprintf(stderr, "encrypted: "); | 955 | fprintf(stderr, "encrypted: "); |
947 | buffer_dump(&active_state->output); | 956 | buffer_dump(&active_state->output); |
@@ -952,8 +961,8 @@ packet_send2_wrapped(void) | |||
952 | if (++active_state->p_send.packets == 0) | 961 | if (++active_state->p_send.packets == 0) |
953 | if (!(datafellows & SSH_BUG_NOREKEY)) | 962 | if (!(datafellows & SSH_BUG_NOREKEY)) |
954 | fatal("XXX too many packets with same key"); | 963 | fatal("XXX too many packets with same key"); |
955 | active_state->p_send.blocks += (packet_length + 4) / block_size; | 964 | active_state->p_send.blocks += len / block_size; |
956 | active_state->p_send.bytes += packet_length + 4; | 965 | active_state->p_send.bytes += len; |
957 | buffer_clear(&active_state->outgoing_packet); | 966 | buffer_clear(&active_state->outgoing_packet); |
958 | 967 | ||
959 | if (type == SSH2_MSG_NEWKEYS) | 968 | if (type == SSH2_MSG_NEWKEYS) |
@@ -1190,7 +1199,7 @@ packet_read_poll1(void) | |||
1190 | buffer_clear(&active_state->incoming_packet); | 1199 | buffer_clear(&active_state->incoming_packet); |
1191 | cp = buffer_append_space(&active_state->incoming_packet, padded_len); | 1200 | cp = buffer_append_space(&active_state->incoming_packet, padded_len); |
1192 | cipher_crypt(&active_state->receive_context, cp, | 1201 | cipher_crypt(&active_state->receive_context, cp, |
1193 | buffer_ptr(&active_state->input), padded_len); | 1202 | buffer_ptr(&active_state->input), padded_len, 0); |
1194 | 1203 | ||
1195 | buffer_consume(&active_state->input, padded_len); | 1204 | buffer_consume(&active_state->input, padded_len); |
1196 | 1205 | ||
@@ -1238,8 +1247,8 @@ static int | |||
1238 | packet_read_poll2(u_int32_t *seqnr_p) | 1247 | packet_read_poll2(u_int32_t *seqnr_p) |
1239 | { | 1248 | { |
1240 | u_int padlen, need; | 1249 | u_int padlen, need; |
1241 | u_char *macbuf, *cp, type; | 1250 | u_char *macbuf = NULL, *cp, type; |
1242 | u_int maclen, block_size; | 1251 | u_int maclen, aadlen = 0, block_size; |
1243 | Enc *enc = NULL; | 1252 | Enc *enc = NULL; |
1244 | Mac *mac = NULL; | 1253 | Mac *mac = NULL; |
1245 | Comp *comp = NULL; | 1254 | Comp *comp = NULL; |
@@ -1254,8 +1263,22 @@ packet_read_poll2(u_int32_t *seqnr_p) | |||
1254 | } | 1263 | } |
1255 | maclen = mac && mac->enabled ? mac->mac_len : 0; | 1264 | maclen = mac && mac->enabled ? mac->mac_len : 0; |
1256 | block_size = enc ? enc->block_size : 8; | 1265 | block_size = enc ? enc->block_size : 8; |
1266 | aadlen = mac && mac->enabled && mac->etm ? 4 : 0; | ||
1257 | 1267 | ||
1258 | if (active_state->packlen == 0) { | 1268 | if (aadlen && active_state->packlen == 0) { |
1269 | if (buffer_len(&active_state->input) < 4) | ||
1270 | return SSH_MSG_NONE; | ||
1271 | cp = buffer_ptr(&active_state->input); | ||
1272 | active_state->packlen = get_u32(cp); | ||
1273 | if (active_state->packlen < 1 + 4 || | ||
1274 | active_state->packlen > PACKET_MAX_SIZE) { | ||
1275 | #ifdef PACKET_DEBUG | ||
1276 | buffer_dump(&active_state->input); | ||
1277 | #endif | ||
1278 | logit("Bad packet length %u.", active_state->packlen); | ||
1279 | packet_disconnect("Packet corrupt"); | ||
1280 | } | ||
1281 | } else if (active_state->packlen == 0) { | ||
1259 | /* | 1282 | /* |
1260 | * check if input size is less than the cipher block size, | 1283 | * check if input size is less than the cipher block size, |
1261 | * decrypt first block and extract length of incoming packet | 1284 | * decrypt first block and extract length of incoming packet |
@@ -1266,7 +1289,7 @@ packet_read_poll2(u_int32_t *seqnr_p) | |||
1266 | cp = buffer_append_space(&active_state->incoming_packet, | 1289 | cp = buffer_append_space(&active_state->incoming_packet, |
1267 | block_size); | 1290 | block_size); |
1268 | cipher_crypt(&active_state->receive_context, cp, | 1291 | cipher_crypt(&active_state->receive_context, cp, |
1269 | buffer_ptr(&active_state->input), block_size); | 1292 | buffer_ptr(&active_state->input), block_size, 0); |
1270 | cp = buffer_ptr(&active_state->incoming_packet); | 1293 | cp = buffer_ptr(&active_state->incoming_packet); |
1271 | active_state->packlen = get_u32(cp); | 1294 | active_state->packlen = get_u32(cp); |
1272 | if (active_state->packlen < 1 + 4 || | 1295 | if (active_state->packlen < 1 + 4 || |
@@ -1279,13 +1302,21 @@ packet_read_poll2(u_int32_t *seqnr_p) | |||
1279 | PACKET_MAX_SIZE); | 1302 | PACKET_MAX_SIZE); |
1280 | return SSH_MSG_NONE; | 1303 | return SSH_MSG_NONE; |
1281 | } | 1304 | } |
1282 | DBG(debug("input: packet len %u", active_state->packlen+4)); | ||
1283 | buffer_consume(&active_state->input, block_size); | 1305 | buffer_consume(&active_state->input, block_size); |
1284 | } | 1306 | } |
1285 | /* we have a partial packet of block_size bytes */ | 1307 | DBG(debug("input: packet len %u", active_state->packlen+4)); |
1286 | need = 4 + active_state->packlen - block_size; | 1308 | if (aadlen) { |
1287 | DBG(debug("partial packet %d, need %d, maclen %d", block_size, | 1309 | /* only the payload is encrypted */ |
1288 | need, maclen)); | 1310 | need = active_state->packlen; |
1311 | } else { | ||
1312 | /* | ||
1313 | * the payload size and the payload are encrypted, but we | ||
1314 | * have a partial packet of block_size bytes | ||
1315 | */ | ||
1316 | need = 4 + active_state->packlen - block_size; | ||
1317 | } | ||
1318 | DBG(debug("partial packet: block %d, need %d, maclen %d, aadlen %d", | ||
1319 | block_size, need, maclen, aadlen)); | ||
1289 | if (need % block_size != 0) { | 1320 | if (need % block_size != 0) { |
1290 | logit("padding error: need %d block %d mod %d", | 1321 | logit("padding error: need %d block %d mod %d", |
1291 | need, block_size, need % block_size); | 1322 | need, block_size, need % block_size); |
@@ -1295,26 +1326,34 @@ packet_read_poll2(u_int32_t *seqnr_p) | |||
1295 | } | 1326 | } |
1296 | /* | 1327 | /* |
1297 | * check if the entire packet has been received and | 1328 | * check if the entire packet has been received and |
1298 | * decrypt into incoming_packet | 1329 | * decrypt into incoming_packet: |
1330 | * 'aadlen' bytes are unencrypted, but authenticated. | ||
1331 | * 'need' bytes are encrypted, followed by | ||
1332 | * 'maclen' bytes of message authentication code. | ||
1299 | */ | 1333 | */ |
1300 | if (buffer_len(&active_state->input) < need + maclen) | 1334 | if (buffer_len(&active_state->input) < aadlen + need + maclen) |
1301 | return SSH_MSG_NONE; | 1335 | return SSH_MSG_NONE; |
1302 | #ifdef PACKET_DEBUG | 1336 | #ifdef PACKET_DEBUG |
1303 | fprintf(stderr, "read_poll enc/full: "); | 1337 | fprintf(stderr, "read_poll enc/full: "); |
1304 | buffer_dump(&active_state->input); | 1338 | buffer_dump(&active_state->input); |
1305 | #endif | 1339 | #endif |
1306 | cp = buffer_append_space(&active_state->incoming_packet, need); | 1340 | /* EtM: compute mac over encrypted input */ |
1341 | if (mac && mac->enabled && mac->etm) | ||
1342 | macbuf = mac_compute(mac, active_state->p_read.seqnr, | ||
1343 | buffer_ptr(&active_state->input), aadlen + need); | ||
1344 | cp = buffer_append_space(&active_state->incoming_packet, aadlen + need); | ||
1307 | cipher_crypt(&active_state->receive_context, cp, | 1345 | cipher_crypt(&active_state->receive_context, cp, |
1308 | buffer_ptr(&active_state->input), need); | 1346 | buffer_ptr(&active_state->input), need, aadlen); |
1309 | buffer_consume(&active_state->input, need); | 1347 | buffer_consume(&active_state->input, aadlen + need); |
1310 | /* | 1348 | /* |
1311 | * compute MAC over seqnr and packet, | 1349 | * compute MAC over seqnr and packet, |
1312 | * increment sequence number for incoming packet | 1350 | * increment sequence number for incoming packet |
1313 | */ | 1351 | */ |
1314 | if (mac && mac->enabled) { | 1352 | if (mac && mac->enabled) { |
1315 | macbuf = mac_compute(mac, active_state->p_read.seqnr, | 1353 | if (!mac->etm) |
1316 | buffer_ptr(&active_state->incoming_packet), | 1354 | macbuf = mac_compute(mac, active_state->p_read.seqnr, |
1317 | buffer_len(&active_state->incoming_packet)); | 1355 | buffer_ptr(&active_state->incoming_packet), |
1356 | buffer_len(&active_state->incoming_packet)); | ||
1318 | if (timingsafe_bcmp(macbuf, buffer_ptr(&active_state->input), | 1357 | if (timingsafe_bcmp(macbuf, buffer_ptr(&active_state->input), |
1319 | mac->mac_len) != 0) { | 1358 | mac->mac_len) != 0) { |
1320 | logit("Corrupted MAC on input."); | 1359 | logit("Corrupted MAC on input."); |
diff --git a/ssh_config.5 b/ssh_config.5 index 09a3cf035..ee466d800 100644 --- a/ssh_config.5 +++ b/ssh_config.5 | |||
@@ -33,8 +33,8 @@ | |||
33 | .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | 33 | .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
34 | .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 34 | .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
35 | .\" | 35 | .\" |
36 | .\" $OpenBSD: ssh_config.5,v 1.159 2012/12/02 20:26:10 djm Exp $ | 36 | .\" $OpenBSD: ssh_config.5,v 1.160 2012/12/11 22:31:18 markus Exp $ |
37 | .Dd $Mdocdate: December 2 2012 $ | 37 | .Dd $Mdocdate: December 11 2012 $ |
38 | .Dt SSH_CONFIG 5 | 38 | .Dt SSH_CONFIG 5 |
39 | .Os | 39 | .Os |
40 | .Sh NAME | 40 | .Sh NAME |
@@ -792,8 +792,17 @@ in order of preference. | |||
792 | The MAC algorithm is used in protocol version 2 | 792 | The MAC algorithm is used in protocol version 2 |
793 | for data integrity protection. | 793 | for data integrity protection. |
794 | Multiple algorithms must be comma-separated. | 794 | Multiple algorithms must be comma-separated. |
795 | The algorithms that contain | ||
796 | .Dq -etm | ||
797 | calculate the MAC after encryption (encrypt-then-mac). | ||
798 | These are considered safer and their use recommended. | ||
795 | The default is: | 799 | The default is: |
796 | .Bd -literal -offset indent | 800 | .Bd -literal -offset indent |
801 | hmac-md5-etm@openssh.com,hmac-sha1-etm@openssh.com, | ||
802 | umac-64-etm@openssh.com,umac-128-etm@openssh.com, | ||
803 | hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com, | ||
804 | hmac-ripemd160-etm@openssh.com,hmac-sha1-96-etm@openssh.com, | ||
805 | hmac-md5-96-etm@openssh.com, | ||
797 | hmac-md5,hmac-sha1,umac-64@openssh.com,umac-128@openssh.com, | 806 | hmac-md5,hmac-sha1,umac-64@openssh.com,umac-128@openssh.com, |
798 | hmac-sha2-256,hmac-sha2-512,hmac-ripemd160, | 807 | hmac-sha2-256,hmac-sha2-512,hmac-ripemd160, |
799 | hmac-sha1-96,hmac-md5-96 | 808 | hmac-sha1-96,hmac-md5-96 |
diff --git a/sshd_config.5 b/sshd_config.5 index ad3692b38..0f4aa639d 100644 --- a/sshd_config.5 +++ b/sshd_config.5 | |||
@@ -33,8 +33,8 @@ | |||
33 | .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | 33 | .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
34 | .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 34 | .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
35 | .\" | 35 | .\" |
36 | .\" $OpenBSD: sshd_config.5,v 1.151 2012/12/03 08:33:03 jmc Exp $ | 36 | .\" $OpenBSD: sshd_config.5,v 1.152 2012/12/11 22:31:18 markus Exp $ |
37 | .Dd $Mdocdate: December 3 2012 $ | 37 | .Dd $Mdocdate: December 11 2012 $ |
38 | .Dt SSHD_CONFIG 5 | 38 | .Dt SSHD_CONFIG 5 |
39 | .Os | 39 | .Os |
40 | .Sh NAME | 40 | .Sh NAME |
@@ -706,8 +706,17 @@ Specifies the available MAC (message authentication code) algorithms. | |||
706 | The MAC algorithm is used in protocol version 2 | 706 | The MAC algorithm is used in protocol version 2 |
707 | for data integrity protection. | 707 | for data integrity protection. |
708 | Multiple algorithms must be comma-separated. | 708 | Multiple algorithms must be comma-separated. |
709 | The algorithms that contain | ||
710 | .Dq -etm | ||
711 | calculate the MAC after encryption (encrypt-then-mac). | ||
712 | These are considered safer and their use recommended. | ||
709 | The default is: | 713 | The default is: |
710 | .Bd -literal -offset indent | 714 | .Bd -literal -offset indent |
715 | hmac-md5-etm@openssh.com,hmac-sha1-etm@openssh.com, | ||
716 | umac-64-etm@openssh.com,umac-128-etm@openssh.com, | ||
717 | hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com, | ||
718 | hmac-ripemd160-etm@openssh.com,hmac-sha1-96-etm@openssh.com, | ||
719 | hmac-md5-96-etm@openssh.com, | ||
711 | hmac-md5,hmac-sha1,umac-64@openssh.com,umac-128@openssh.com, | 720 | hmac-md5,hmac-sha1,umac-64@openssh.com,umac-128@openssh.com, |
712 | hmac-sha2-256,hmac-sha2-512,hmac-ripemd160, | 721 | hmac-sha2-256,hmac-sha2-512,hmac-ripemd160, |
713 | hmac-sha1-96,hmac-md5-96 | 722 | hmac-sha1-96,hmac-md5-96 |