From af43a7ac2d77c57112b48f34c7a72be2adb761bc Mon Sep 17 00:00:00 2001 From: Damien Miller Date: Wed, 12 Dec 2012 10:46:31 +1100 Subject: - 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@ --- PROTOCOL | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) (limited to 'PROTOCOL') diff --git a/PROTOCOL b/PROTOCOL index c28196011..834716cc9 100644 --- a/PROTOCOL +++ b/PROTOCOL @@ -51,6 +51,33 @@ and ecdsa-sha2-nistp521 curves over GF(p) are supported. Elliptic curve points encoded using point compression are NOT accepted or generated. +1.5 transport: Protocol 2 Encrypt-then-MAC MAC algorithms + +OpenSSH supports MAC algorithms, whose names contain "-etm", that +perform the calculations in a different order to that defined in RFC +4253. These variants use the so-called "encrypt then MAC" ordering, +calculating the MAC over the packet ciphertext rather than the +plaintext. This ordering closes a security flaw in the SSH transport +protocol, where decryption of unauthenticated ciphertext provided a +"decryption oracle" that could, in conjunction with cipher flaws, reveal +session plaintext. + +Specifically, the "-etm" MAC algorithms modify the transport protocol +to calculate the MAC over the packet ciphertext and to send the packet +length unencrypted. This is necessary for the transport to obtain the +length of the packet and location of the MAC tag so that it may be +verified without decrypting unauthenticated data. + +As such, the MAC covers: + + mac = MAC(key, sequence_number || encrypted_packet) + +where "encrypted_packet" contains: + + byte padding_length + byte[n1] payload; n1 = packet_length - padding_length - 1 + byte[n2] random padding; n2 = padding_length + 2. Connection protocol changes 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. This extension is advertised in the SSH_FXP_VERSION hello with version "1". -$OpenBSD: PROTOCOL,v 1.17 2010/12/04 00:18:01 djm Exp $ +$OpenBSD: PROTOCOL,v 1.18 2012/12/11 22:31:18 markus Exp $ -- cgit v1.2.3 From 3739c8f0413bc7a90a1fc3a6c723436bd285bf86 Mon Sep 17 00:00:00 2001 From: Damien Miller Date: Wed, 9 Jan 2013 15:57:16 +1100 Subject: - djm@cvs.openbsd.org 2013/01/03 12:49:01 [PROTOCOL] fix description of MAC calculation for EtM modes; ok markus@ --- ChangeLog | 3 +++ PROTOCOL | 7 ++++--- 2 files changed, 7 insertions(+), 3 deletions(-) (limited to 'PROTOCOL') diff --git a/ChangeLog b/ChangeLog index 66cc48ba2..67d4884d6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -16,6 +16,9 @@ add a couple of ServerOptions members that should be copied to the privsep child (for consistency, in this case they happen only to be accessed in the monitor); ok dtucker@ + - djm@cvs.openbsd.org 2013/01/03 12:49:01 + [PROTOCOL] + fix description of MAC calculation for EtM modes; ok markus@ 20121217 - (dtucker) [Makefile.in] Add some scaffolding so that the new regress diff --git a/PROTOCOL b/PROTOCOL index 834716cc9..eb5d0889c 100644 --- a/PROTOCOL +++ b/PROTOCOL @@ -70,9 +70,10 @@ verified without decrypting unauthenticated data. As such, the MAC covers: - mac = MAC(key, sequence_number || encrypted_packet) + mac = MAC(key, sequence_number || packet_length || encrypted_packet) -where "encrypted_packet" contains: +where "packet_length" is encoded as a uint32 and "encrypted_packet" +contains: byte padding_length byte[n1] payload; n1 = packet_length - padding_length - 1 @@ -318,4 +319,4 @@ link(oldpath, newpath) and will respond with a SSH_FXP_STATUS message. This extension is advertised in the SSH_FXP_VERSION hello with version "1". -$OpenBSD: PROTOCOL,v 1.18 2012/12/11 22:31:18 markus Exp $ +$OpenBSD: PROTOCOL,v 1.19 2013/01/03 12:49:01 djm Exp $ -- cgit v1.2.3 From 1d75abfe23cadf8cdba0bd2cfd54f3bc1ca80dc5 Mon Sep 17 00:00:00 2001 From: Damien Miller Date: Wed, 9 Jan 2013 16:12:19 +1100 Subject: - markus@cvs.openbsd.org 2013/01/08 18:49:04 [PROTOCOL authfile.c cipher.c cipher.h kex.c kex.h monitor_wrap.c] [myproposal.h packet.c ssh_config.5 sshd_config.5] support AES-GCM as defined in RFC 5647 (but with simpler KEX handling) ok and feedback djm@ --- ChangeLog | 5 +++ PROTOCOL | 14 +++++++- authfile.c | 6 ++-- cipher.c | 105 ++++++++++++++++++++++++++++++++++++++++++++------------- cipher.h | 8 +++-- kex.c | 16 ++++++--- kex.h | 3 +- monitor_wrap.c | 39 ++++++++++----------- myproposal.h | 3 +- packet.c | 45 ++++++++++++++----------- ssh_config.5 | 7 ++-- sshd_config.5 | 7 ++-- 12 files changed, 179 insertions(+), 79 deletions(-) (limited to 'PROTOCOL') diff --git a/ChangeLog b/ChangeLog index 0f62953c7..b5812cc7d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -32,6 +32,11 @@ sftp-server.8: add argument name to -d sftp-server.c: add -d to usage() ok djm + - markus@cvs.openbsd.org 2013/01/08 18:49:04 + [PROTOCOL authfile.c cipher.c cipher.h kex.c kex.h monitor_wrap.c] + [myproposal.h packet.c ssh_config.5 sshd_config.5] + support AES-GCM as defined in RFC 5647 (but with simpler KEX handling) + ok and feedback djm@ 20121217 - (dtucker) [Makefile.in] Add some scaffolding so that the new regress diff --git a/PROTOCOL b/PROTOCOL index eb5d0889c..48b3a4400 100644 --- a/PROTOCOL +++ b/PROTOCOL @@ -79,6 +79,18 @@ contains: byte[n1] payload; n1 = packet_length - padding_length - 1 byte[n2] random padding; n2 = padding_length +1.6 transport: AES-GCM + +OpenSSH supports the AES-GCM algorithm as specified in RFC 5647. +Because of problems with the specification of the key exchange +the behaviour of OpenSSH differs from the RFC as follows: + +AES-GCM is only negotiated as the cipher algorithms +"aes128-gcm@openssh.com" or "aes256-gcm@openssh.com" and never as +an MAC algorithm. Additionally, if AES-GCM is selected as the cipher +the exchanged MAC algorithms are ignored and there doesn't have to be +a matching MAC. + 2. Connection protocol changes 2.1. connection: Channel write close extension "eow@openssh.com" @@ -319,4 +331,4 @@ link(oldpath, newpath) and will respond with a SSH_FXP_STATUS message. This extension is advertised in the SSH_FXP_VERSION hello with version "1". -$OpenBSD: PROTOCOL,v 1.19 2013/01/03 12:49:01 djm Exp $ +$OpenBSD: PROTOCOL,v 1.20 2013/01/08 18:49:04 markus Exp $ diff --git a/authfile.c b/authfile.c index d9ee4ca65..3544d170b 100644 --- a/authfile.c +++ b/authfile.c @@ -1,4 +1,4 @@ -/* $OpenBSD: authfile.c,v 1.94 2012/12/11 22:31:18 markus Exp $ */ +/* $OpenBSD: authfile.c,v 1.95 2013/01/08 18:49:04 markus Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -150,7 +150,7 @@ key_private_rsa1_to_blob(Key *key, Buffer *blob, const char *passphrase, cipher_set_key_string(&ciphercontext, cipher, passphrase, CIPHER_ENCRYPT); cipher_crypt(&ciphercontext, cp, - buffer_ptr(&buffer), buffer_len(&buffer), 0); + buffer_ptr(&buffer), buffer_len(&buffer), 0, 0); cipher_cleanup(&ciphercontext); memset(&ciphercontext, 0, sizeof(ciphercontext)); @@ -474,7 +474,7 @@ key_parse_private_rsa1(Buffer *blob, const char *passphrase, char **commentp) cipher_set_key_string(&ciphercontext, cipher, passphrase, CIPHER_DECRYPT); cipher_crypt(&ciphercontext, cp, - buffer_ptr(©), buffer_len(©), 0); + buffer_ptr(©), buffer_len(©), 0, 0); cipher_cleanup(&ciphercontext); memset(&ciphercontext, 0, sizeof(ciphercontext)); buffer_free(©); diff --git a/cipher.c b/cipher.c index aae69c347..cad8a2f36 100644 --- a/cipher.c +++ b/cipher.c @@ -1,4 +1,4 @@ -/* $OpenBSD: cipher.c,v 1.84 2012/12/12 16:46:10 naddy Exp $ */ +/* $OpenBSD: cipher.c,v 1.85 2013/01/08 18:49:04 markus Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -71,29 +71,38 @@ struct Cipher { u_int cbc_mode; const EVP_CIPHER *(*evptype)(void); } ciphers[] = { - { "none", SSH_CIPHER_NONE, 8, 0, 0, 0, EVP_enc_null }, - { "des", SSH_CIPHER_DES, 8, 8, 0, 1, EVP_des_cbc }, - { "3des", SSH_CIPHER_3DES, 8, 16, 0, 1, evp_ssh1_3des }, - { "blowfish", SSH_CIPHER_BLOWFISH, 8, 32, 0, 1, evp_ssh1_bf }, - - { "3des-cbc", SSH_CIPHER_SSH2, 8, 24, 0, 1, EVP_des_ede3_cbc }, - { "blowfish-cbc", SSH_CIPHER_SSH2, 8, 16, 0, 1, EVP_bf_cbc }, - { "cast128-cbc", SSH_CIPHER_SSH2, 8, 16, 0, 1, EVP_cast5_cbc }, - { "arcfour", SSH_CIPHER_SSH2, 8, 16, 0, 0, EVP_rc4 }, - { "arcfour128", SSH_CIPHER_SSH2, 8, 16, 1536, 0, EVP_rc4 }, - { "arcfour256", SSH_CIPHER_SSH2, 8, 32, 1536, 0, EVP_rc4 }, - { "aes128-cbc", SSH_CIPHER_SSH2, 16, 16, 0, 1, EVP_aes_128_cbc }, - { "aes192-cbc", SSH_CIPHER_SSH2, 16, 24, 0, 1, EVP_aes_192_cbc }, - { "aes256-cbc", SSH_CIPHER_SSH2, 16, 32, 0, 1, EVP_aes_256_cbc }, + { NULL, SSH_CIPHER_INVALID, 0, 0, 0, 0, NULL } + + { "none", SSH_CIPHER_NONE, 8, 0, 0, 0, 0, 0, EVP_enc_null }, + { "des", SSH_CIPHER_DES, 8, 8, 0, 0, 0, 1, EVP_des_cbc }, + { "3des", SSH_CIPHER_3DES, 8, 16, 0, 0, 0, 1, evp_ssh1_3des }, + { "blowfish", SSH_CIPHER_BLOWFISH, 8, 32, 0, 0, 0, 1, evp_ssh1_bf }, + + { "3des-cbc", SSH_CIPHER_SSH2, 8, 24, 0, 0, 0, 1, EVP_des_ede3_cbc }, + { "blowfish-cbc", + SSH_CIPHER_SSH2, 8, 16, 0, 0, 0, 1, EVP_bf_cbc }, + { "cast128-cbc", + SSH_CIPHER_SSH2, 8, 16, 0, 0, 0, 1, EVP_cast5_cbc }, + { "arcfour", SSH_CIPHER_SSH2, 8, 16, 0, 0, 0, 0, EVP_rc4 }, + { "arcfour128", SSH_CIPHER_SSH2, 8, 16, 0, 0, 1536, 0, EVP_rc4 }, + { "arcfour256", SSH_CIPHER_SSH2, 8, 32, 0, 0, 1536, 0, EVP_rc4 }, + { "aes128-cbc", SSH_CIPHER_SSH2, 16, 16, 0, 0, 0, 1, EVP_aes_128_cbc }, + { "aes192-cbc", SSH_CIPHER_SSH2, 16, 24, 0, 0, 0, 1, EVP_aes_192_cbc }, + { "aes256-cbc", SSH_CIPHER_SSH2, 16, 32, 0, 0, 0, 1, EVP_aes_256_cbc }, { "rijndael-cbc@lysator.liu.se", - SSH_CIPHER_SSH2, 16, 32, 0, 1, EVP_aes_256_cbc }, - { "aes128-ctr", SSH_CIPHER_SSH2, 16, 16, 0, 0, EVP_aes_128_ctr }, - { "aes192-ctr", SSH_CIPHER_SSH2, 16, 24, 0, 0, EVP_aes_192_ctr }, - { "aes256-ctr", SSH_CIPHER_SSH2, 16, 32, 0, 0, EVP_aes_256_ctr }, + SSH_CIPHER_SSH2, 16, 32, 0, 0, 0, 1, EVP_aes_256_cbc }, + { "aes128-ctr", SSH_CIPHER_SSH2, 16, 16, 0, 0, 0, 0, EVP_aes_128_ctr }, + { "aes192-ctr", SSH_CIPHER_SSH2, 16, 24, 0, 0, 0, 0, EVP_aes_192_ctr }, + { "aes256-ctr", SSH_CIPHER_SSH2, 16, 32, 0, 0, 0, 0, EVP_aes_256_ctr }, + { "aes128-gcm@openssh.com", + SSH_CIPHER_SSH2, 16, 16, 12, 16, 0, 0, EVP_aes_128_gcm }, + { "aes256-gcm@openssh.com", + SSH_CIPHER_SSH2, 16, 32, 12, 16, 0, 0, EVP_aes_256_gcm }, #ifdef USE_CIPHER_ACSS - { "acss@openssh.org", SSH_CIPHER_SSH2, 16, 5, 0, 0, EVP_acss }, + { "acss@openssh.org", + SSH_CIPHER_SSH2, 16, 5, 0, 0, 0, 0, EVP_acss }, #endif - { NULL, SSH_CIPHER_INVALID, 0, 0, 0, 0, NULL } + { NULL, SSH_CIPHER_INVALID, 0, 0, 0, 0, 0, 0, NULL } }; /*--*/ @@ -110,6 +119,18 @@ cipher_keylen(const Cipher *c) return (c->key_len); } +u_int +cipher_authlen(const Cipher *c) +{ + return (c->auth_len); +} + +u_int +cipher_ivlen(const Cipher *c) +{ + return (c->iv_len ? c->iv_len : c->block_size); +} + u_int cipher_get_number(const Cipher *c) { @@ -229,11 +250,12 @@ cipher_init(CipherContext *cc, Cipher *cipher, keylen = 8; } cc->plaintext = (cipher->number == SSH_CIPHER_NONE); + cc->encrypt = do_encrypt; if (keylen < cipher->key_len) fatal("cipher_init: key length %d is insufficient for %s.", keylen, cipher->name); - if (iv != NULL && ivlen < cipher->block_size) + if (iv != NULL && ivlen < cipher_ivlen(cipher)) fatal("cipher_init: iv length %d is insufficient for %s.", ivlen, cipher->name); cc->cipher = cipher; @@ -254,6 +276,11 @@ cipher_init(CipherContext *cc, Cipher *cipher, (do_encrypt == CIPHER_ENCRYPT)) == 0) fatal("cipher_init: EVP_CipherInit failed for %s", cipher->name); + if (cipher_authlen(cipher) && + !EVP_CIPHER_CTX_ctrl(&cc->evp, EVP_CTRL_GCM_SET_IV_FIXED, + -1, (u_char *)iv)) + fatal("cipher_init: EVP_CTRL_GCM_SET_IV_FIXED failed for %s", + cipher->name); klen = EVP_CIPHER_CTX_key_length(&cc->evp); if (klen > 0 && keylen != (u_int)klen) { debug2("cipher_init: set keylen (%d -> %d)", klen, keylen); @@ -284,19 +311,49 @@ cipher_init(CipherContext *cc, Cipher *cipher, * Theses bytes are treated as additional authenticated data for * authenticated encryption modes. * En/Decrypt 'len' bytes at offset 'aadlen' from 'src' to 'dest'. + * Use 'authlen' bytes at offset 'len'+'aadlen' as the authentication tag. + * This tag is written on encryption and verified on decryption. * Both 'aadlen' and 'authlen' can be set to 0. */ void cipher_crypt(CipherContext *cc, u_char *dest, const u_char *src, - u_int len, u_int aadlen) + u_int len, u_int aadlen, u_int authlen) { - if (aadlen) + if (authlen) { + u_char lastiv[1]; + + if (authlen != cipher_authlen(cc->cipher)) + fatal("%s: authlen mismatch %d", __func__, authlen); + /* increment IV */ + if (!EVP_CIPHER_CTX_ctrl(&cc->evp, EVP_CTRL_GCM_IV_GEN, + 1, lastiv)) + fatal("%s: EVP_CTRL_GCM_IV_GEN", __func__); + /* set tag on decyption */ + if (!cc->encrypt && + !EVP_CIPHER_CTX_ctrl(&cc->evp, EVP_CTRL_GCM_SET_TAG, + authlen, (u_char *)src + aadlen + len)) + fatal("%s: EVP_CTRL_GCM_SET_TAG", __func__); + } + if (aadlen) { + if (authlen && + EVP_Cipher(&cc->evp, NULL, (u_char *)src, aadlen) < 0) + fatal("%s: EVP_Cipher(aad) failed", __func__); memcpy(dest, src, aadlen); + } if (len % cc->cipher->block_size) fatal("%s: bad plaintext length %d", __func__, len); if (EVP_Cipher(&cc->evp, dest + aadlen, (u_char *)src + aadlen, len) < 0) fatal("%s: EVP_Cipher failed", __func__); + if (authlen) { + /* compute tag (on encrypt) or verify tag (on decrypt) */ + if (EVP_Cipher(&cc->evp, NULL, NULL, 0) < 0) + fatal("%s: EVP_Cipher(finish) failed", __func__); + if (cc->encrypt && + !EVP_CIPHER_CTX_ctrl(&cc->evp, EVP_CTRL_GCM_GET_TAG, + authlen, dest + aadlen + len)) + fatal("%s: EVP_CTRL_GCM_GET_TAG", __func__); + } } void diff --git a/cipher.h b/cipher.h index 78972fea5..8cb57c3e5 100644 --- a/cipher.h +++ b/cipher.h @@ -1,4 +1,4 @@ -/* $OpenBSD: cipher.h,v 1.38 2012/12/11 22:31:18 markus Exp $ */ +/* $OpenBSD: cipher.h,v 1.39 2013/01/08 18:49:04 markus Exp $ */ /* * Author: Tatu Ylonen @@ -64,6 +64,7 @@ typedef struct CipherContext CipherContext; struct Cipher; struct CipherContext { int plaintext; + int encrypt; EVP_CIPHER_CTX evp; Cipher *cipher; }; @@ -76,11 +77,14 @@ char *cipher_name(int); int ciphers_valid(const char *); void cipher_init(CipherContext *, Cipher *, const u_char *, u_int, const u_char *, u_int, int); -void cipher_crypt(CipherContext *, u_char *, const u_char *, u_int, u_int); +void cipher_crypt(CipherContext *, u_char *, const u_char *, + u_int, u_int, u_int); void cipher_cleanup(CipherContext *); void cipher_set_key_string(CipherContext *, Cipher *, const char *, int); u_int cipher_blocksize(const Cipher *); u_int cipher_keylen(const Cipher *); +u_int cipher_authlen(const Cipher *); +u_int cipher_ivlen(const Cipher *); u_int cipher_is_cbc(const Cipher *); u_int cipher_get_number(const Cipher *); diff --git a/kex.c b/kex.c index f77b3c925..57a79dd9e 100644 --- a/kex.c +++ b/kex.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kex.c,v 1.87 2012/08/17 01:22:56 djm Exp $ */ +/* $OpenBSD: kex.c,v 1.88 2013/01/08 18:49:04 markus Exp $ */ /* * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. * @@ -304,6 +304,7 @@ choose_enc(Enc *enc, char *client, char *server) enc->name = name; enc->enabled = 0; enc->iv = NULL; + enc->iv_len = cipher_ivlen(enc->cipher); enc->key = NULL; enc->key_len = cipher_keylen(enc->cipher); enc->block_size = cipher_blocksize(enc->cipher); @@ -415,7 +416,7 @@ kex_choose_conf(Kex *kex) char **my, **peer; char **cprop, **sprop; int nenc, nmac, ncomp; - u_int mode, ctos, need; + u_int mode, ctos, need, authlen; int first_kex_follows, type; my = kex_buf2prop(&kex->my, NULL); @@ -448,13 +449,16 @@ kex_choose_conf(Kex *kex) nenc = ctos ? PROPOSAL_ENC_ALGS_CTOS : PROPOSAL_ENC_ALGS_STOC; nmac = ctos ? PROPOSAL_MAC_ALGS_CTOS : PROPOSAL_MAC_ALGS_STOC; ncomp = ctos ? PROPOSAL_COMP_ALGS_CTOS : PROPOSAL_COMP_ALGS_STOC; - choose_enc (&newkeys->enc, cprop[nenc], sprop[nenc]); - choose_mac (&newkeys->mac, cprop[nmac], sprop[nmac]); + choose_enc(&newkeys->enc, cprop[nenc], sprop[nenc]); + /* ignore mac for authenticated encryption */ + authlen = cipher_authlen(newkeys->enc.cipher); + if (authlen == 0) + choose_mac(&newkeys->mac, cprop[nmac], sprop[nmac]); choose_comp(&newkeys->comp, cprop[ncomp], sprop[ncomp]); debug("kex: %s %s %s %s", ctos ? "client->server" : "server->client", newkeys->enc.name, - newkeys->mac.name, + authlen == 0 ? newkeys->mac.name : "", newkeys->comp.name); } choose_kex(kex, cprop[PROPOSAL_KEX_ALGS], sprop[PROPOSAL_KEX_ALGS]); @@ -467,6 +471,8 @@ kex_choose_conf(Kex *kex) need = newkeys->enc.key_len; if (need < newkeys->enc.block_size) need = newkeys->enc.block_size; + if (need < newkeys->enc.iv_len) + need = newkeys->enc.iv_len; if (need < newkeys->mac.key_len) need = newkeys->mac.key_len; } diff --git a/kex.h b/kex.h index 03b984cc8..46731fa45 100644 --- a/kex.h +++ b/kex.h @@ -1,4 +1,4 @@ -/* $OpenBSD: kex.h,v 1.53 2012/12/11 22:31:18 markus Exp $ */ +/* $OpenBSD: kex.h,v 1.54 2013/01/08 18:49:04 markus Exp $ */ /* * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. @@ -89,6 +89,7 @@ struct Enc { Cipher *cipher; int enabled; u_int key_len; + u_int iv_len; u_int block_size; u_char *key; u_char *iv; diff --git a/monitor_wrap.c b/monitor_wrap.c index c22d0a2a6..ea654a73f 100644 --- a/monitor_wrap.c +++ b/monitor_wrap.c @@ -1,4 +1,4 @@ -/* $OpenBSD: monitor_wrap.c,v 1.74 2012/10/01 13:59:51 naddy Exp $ */ +/* $OpenBSD: monitor_wrap.c,v 1.75 2013/01/08 18:49:04 markus Exp $ */ /* * Copyright 2002 Niels Provos * Copyright 2002 Markus Friedl @@ -491,25 +491,24 @@ mm_newkeys_from_blob(u_char *blob, int blen) enc->enabled = buffer_get_int(&b); enc->block_size = buffer_get_int(&b); enc->key = buffer_get_string(&b, &enc->key_len); - enc->iv = buffer_get_string(&b, &len); - if (len != enc->block_size) - fatal("%s: bad ivlen: expected %u != %u", __func__, - enc->block_size, len); + enc->iv = buffer_get_string(&b, &enc->iv_len); if (enc->name == NULL || cipher_by_name(enc->name) != enc->cipher) fatal("%s: bad cipher name %s or pointer %p", __func__, enc->name, enc->cipher); /* Mac structure */ - mac->name = buffer_get_string(&b, NULL); - if (mac->name == NULL || mac_setup(mac, mac->name) == -1) - fatal("%s: can not setup mac %s", __func__, mac->name); - mac->enabled = buffer_get_int(&b); - mac->key = buffer_get_string(&b, &len); - if (len > mac->key_len) - fatal("%s: bad mac key length: %u > %d", __func__, len, - mac->key_len); - mac->key_len = len; + if (cipher_authlen(enc->cipher) == 0) { + mac->name = buffer_get_string(&b, NULL); + if (mac->name == NULL || mac_setup(mac, mac->name) == -1) + fatal("%s: can not setup mac %s", __func__, mac->name); + mac->enabled = buffer_get_int(&b); + mac->key = buffer_get_string(&b, &len); + if (len > mac->key_len) + fatal("%s: bad mac key length: %u > %d", __func__, len, + mac->key_len); + mac->key_len = len; + } /* Comp structure */ comp->type = buffer_get_int(&b); @@ -551,13 +550,15 @@ mm_newkeys_to_blob(int mode, u_char **blobp, u_int *lenp) buffer_put_int(&b, enc->enabled); buffer_put_int(&b, enc->block_size); buffer_put_string(&b, enc->key, enc->key_len); - packet_get_keyiv(mode, enc->iv, enc->block_size); - buffer_put_string(&b, enc->iv, enc->block_size); + packet_get_keyiv(mode, enc->iv, enc->iv_len); + buffer_put_string(&b, enc->iv, enc->iv_len); /* Mac structure */ - buffer_put_cstring(&b, mac->name); - buffer_put_int(&b, mac->enabled); - buffer_put_string(&b, mac->key, mac->key_len); + if (cipher_authlen(enc->cipher) == 0) { + buffer_put_cstring(&b, mac->name); + buffer_put_int(&b, mac->enabled); + buffer_put_string(&b, mac->key, mac->key_len); + } /* Comp structure */ buffer_put_int(&b, comp->type); diff --git a/myproposal.h b/myproposal.h index d98f4b051..99d093461 100644 --- a/myproposal.h +++ b/myproposal.h @@ -1,4 +1,4 @@ -/* $OpenBSD: myproposal.h,v 1.31 2012/12/11 22:31:18 markus Exp $ */ +/* $OpenBSD: myproposal.h,v 1.32 2013/01/08 18:49:04 markus Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. @@ -73,6 +73,7 @@ #define KEX_DEFAULT_ENCRYPT \ "aes128-ctr,aes192-ctr,aes256-ctr," \ "arcfour256,arcfour128," \ + "aes128-gcm@openssh.com,aes256-gcm@openssh.com," \ "aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc," \ "aes192-cbc,aes256-cbc,arcfour,rijndael-cbc@lysator.liu.se" #ifdef HAVE_EVP_SHA256 diff --git a/packet.c b/packet.c index fe379aa49..ae7b04cd8 100644 --- a/packet.c +++ b/packet.c @@ -1,4 +1,4 @@ -/* $OpenBSD: packet.c,v 1.179 2012/12/12 16:45:52 markus Exp $ */ +/* $OpenBSD: packet.c,v 1.180 2013/01/08 18:49:04 markus Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -709,7 +709,7 @@ packet_send1(void) buffer_len(&active_state->outgoing_packet)); cipher_crypt(&active_state->send_context, cp, buffer_ptr(&active_state->outgoing_packet), - buffer_len(&active_state->outgoing_packet), 0); + buffer_len(&active_state->outgoing_packet), 0, 0); #ifdef PACKET_DEBUG fprintf(stderr, "encrypted: "); @@ -757,7 +757,7 @@ set_newkeys(int mode) mac = &active_state->newkeys[mode]->mac; comp = &active_state->newkeys[mode]->comp; mac_clear(mac); - memset(enc->iv, 0, enc->block_size); + memset(enc->iv, 0, enc->iv_len); memset(enc->key, 0, enc->key_len); memset(mac->key, 0, mac->key_len); xfree(enc->name); @@ -774,11 +774,11 @@ set_newkeys(int mode) enc = &active_state->newkeys[mode]->enc; mac = &active_state->newkeys[mode]->mac; comp = &active_state->newkeys[mode]->comp; - if (mac_init(mac) == 0) + if (cipher_authlen(enc->cipher) == 0 && mac_init(mac) == 0) mac->enabled = 1; DBG(debug("cipher_init_context: %d", mode)); cipher_init(cc, enc->cipher, enc->key, enc->key_len, - enc->iv, enc->block_size, crypt_type); + enc->iv, enc->iv_len, crypt_type); /* Deleting the keys does not gain extra security */ /* memset(enc->iv, 0, enc->block_size); memset(enc->key, 0, enc->key_len); @@ -846,7 +846,7 @@ packet_send2_wrapped(void) { u_char type, *cp, *macbuf = NULL; u_char padlen, pad = 0; - u_int i, len, aadlen = 0; + u_int i, len, authlen = 0, aadlen = 0; u_int32_t rnd = 0; Enc *enc = NULL; Mac *mac = NULL; @@ -857,9 +857,12 @@ packet_send2_wrapped(void) enc = &active_state->newkeys[MODE_OUT]->enc; mac = &active_state->newkeys[MODE_OUT]->mac; comp = &active_state->newkeys[MODE_OUT]->comp; + /* disable mac for authenticated encryption */ + if ((authlen = cipher_authlen(enc->cipher)) != 0) + mac = NULL; } block_size = enc ? enc->block_size : 8; - aadlen = mac && mac->enabled && mac->etm ? 4 : 0; + aadlen = (mac && mac->enabled && mac->etm) || authlen ? 4 : 0; cp = buffer_ptr(&active_state->outgoing_packet); type = cp[5]; @@ -936,10 +939,10 @@ packet_send2_wrapped(void) DBG(debug("done calc MAC out #%d", active_state->p_send.seqnr)); } /* encrypt packet and append to output buffer. */ - cp = buffer_append_space(&active_state->output, len); + cp = buffer_append_space(&active_state->output, len + authlen); cipher_crypt(&active_state->send_context, cp, buffer_ptr(&active_state->outgoing_packet), - len - aadlen, aadlen); + len - aadlen, aadlen, authlen); /* append unencrypted MAC */ if (mac && mac->enabled) { if (mac->etm) { @@ -1199,7 +1202,7 @@ packet_read_poll1(void) buffer_clear(&active_state->incoming_packet); cp = buffer_append_space(&active_state->incoming_packet, padded_len); cipher_crypt(&active_state->receive_context, cp, - buffer_ptr(&active_state->input), padded_len, 0); + buffer_ptr(&active_state->input), padded_len, 0, 0); buffer_consume(&active_state->input, padded_len); @@ -1248,7 +1251,7 @@ packet_read_poll2(u_int32_t *seqnr_p) { u_int padlen, need; u_char *macbuf = NULL, *cp, type; - u_int maclen, aadlen = 0, block_size; + u_int maclen, authlen = 0, aadlen = 0, block_size; Enc *enc = NULL; Mac *mac = NULL; Comp *comp = NULL; @@ -1260,10 +1263,13 @@ packet_read_poll2(u_int32_t *seqnr_p) enc = &active_state->newkeys[MODE_IN]->enc; mac = &active_state->newkeys[MODE_IN]->mac; comp = &active_state->newkeys[MODE_IN]->comp; + /* disable mac for authenticated encryption */ + if ((authlen = cipher_authlen(enc->cipher)) != 0) + mac = NULL; } maclen = mac && mac->enabled ? mac->mac_len : 0; block_size = enc ? enc->block_size : 8; - aadlen = mac && mac->enabled && mac->etm ? 4 : 0; + aadlen = (mac && mac->enabled && mac->etm) || authlen ? 4 : 0; if (aadlen && active_state->packlen == 0) { if (buffer_len(&active_state->input) < 4) @@ -1290,7 +1296,7 @@ packet_read_poll2(u_int32_t *seqnr_p) cp = buffer_append_space(&active_state->incoming_packet, block_size); cipher_crypt(&active_state->receive_context, cp, - buffer_ptr(&active_state->input), block_size, 0); + buffer_ptr(&active_state->input), block_size, 0, 0); cp = buffer_ptr(&active_state->incoming_packet); active_state->packlen = get_u32(cp); if (active_state->packlen < 1 + 4 || @@ -1316,8 +1322,8 @@ packet_read_poll2(u_int32_t *seqnr_p) */ need = 4 + active_state->packlen - block_size; } - DBG(debug("partial packet: block %d, need %d, maclen %d, aadlen %d", - block_size, need, maclen, aadlen)); + DBG(debug("partial packet: block %d, need %d, maclen %d, authlen %d," + " aadlen %d", block_size, need, maclen, authlen, aadlen)); if (need % block_size != 0) { logit("padding error: need %d block %d mod %d", need, block_size, need % block_size); @@ -1329,10 +1335,11 @@ packet_read_poll2(u_int32_t *seqnr_p) * check if the entire packet has been received and * decrypt into incoming_packet: * 'aadlen' bytes are unencrypted, but authenticated. - * 'need' bytes are encrypted, followed by + * 'need' bytes are encrypted, followed by either + * 'authlen' bytes of authentication tag or * 'maclen' bytes of message authentication code. */ - if (buffer_len(&active_state->input) < aadlen + need + maclen) + if (buffer_len(&active_state->input) < aadlen + need + authlen + maclen) return SSH_MSG_NONE; #ifdef PACKET_DEBUG fprintf(stderr, "read_poll enc/full: "); @@ -1344,8 +1351,8 @@ packet_read_poll2(u_int32_t *seqnr_p) buffer_ptr(&active_state->input), aadlen + need); cp = buffer_append_space(&active_state->incoming_packet, aadlen + need); cipher_crypt(&active_state->receive_context, cp, - buffer_ptr(&active_state->input), need, aadlen); - buffer_consume(&active_state->input, aadlen + need); + buffer_ptr(&active_state->input), need, aadlen, authlen); + buffer_consume(&active_state->input, aadlen + need + authlen); /* * compute MAC over seqnr and packet, * increment sequence number for incoming packet diff --git a/ssh_config.5 b/ssh_config.5 index ee466d800..269529c00 100644 --- a/ssh_config.5 +++ b/ssh_config.5 @@ -33,8 +33,8 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.\" $OpenBSD: ssh_config.5,v 1.160 2012/12/11 22:31:18 markus Exp $ -.Dd $Mdocdate: December 11 2012 $ +.\" $OpenBSD: ssh_config.5,v 1.161 2013/01/08 18:49:04 markus Exp $ +.Dd $Mdocdate: January 8 2013 $ .Dt SSH_CONFIG 5 .Os .Sh NAME @@ -204,6 +204,8 @@ The supported ciphers are .Dq aes128-ctr , .Dq aes192-ctr , .Dq aes256-ctr , +.Dq aes128-gcm@openssh.com , +.Dq aes256-gcm@openssh.com , .Dq arcfour128 , .Dq arcfour256 , .Dq arcfour , @@ -213,6 +215,7 @@ and The default is: .Bd -literal -offset 3n aes128-ctr,aes192-ctr,aes256-ctr,arcfour256,arcfour128, +aes128-gcm@openssh.com,aes256-gcm@openssh.com, aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc,aes192-cbc, aes256-cbc,arcfour .Ed diff --git a/sshd_config.5 b/sshd_config.5 index 0f4aa639d..e7bb0b55f 100644 --- a/sshd_config.5 +++ b/sshd_config.5 @@ -33,8 +33,8 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.\" $OpenBSD: sshd_config.5,v 1.152 2012/12/11 22:31:18 markus Exp $ -.Dd $Mdocdate: December 11 2012 $ +.\" $OpenBSD: sshd_config.5,v 1.153 2013/01/08 18:49:04 markus Exp $ +.Dd $Mdocdate: January 8 2013 $ .Dt SSHD_CONFIG 5 .Os .Sh NAME @@ -336,6 +336,8 @@ The supported ciphers are .Dq aes128-ctr , .Dq aes192-ctr , .Dq aes256-ctr , +.Dq aes128-gcm@openssh.com , +.Dq aes256-gcm@openssh.com , .Dq arcfour128 , .Dq arcfour256 , .Dq arcfour , @@ -345,6 +347,7 @@ and The default is: .Bd -literal -offset 3n aes128-ctr,aes192-ctr,aes256-ctr,arcfour256,arcfour128, +aes128-gcm@openssh.com,aes256-gcm@openssh.com, aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc,aes192-cbc, aes256-cbc,arcfour .Ed -- cgit v1.2.3