summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarkus Friedl <markus@cvs.openbsd.org>2013-01-08 18:49:05 +0000
committerMarkus Friedl <markus@cvs.openbsd.org>2013-01-08 18:49:05 +0000
commitadf9515dca30a3e56b227376e4caf8279c4385cd (patch)
tree2ef3374d339cc3c8ba5369bf449b62680f0fc5d8
parent9c87c513b2e6c27969fbb097086b37bbff57e99a (diff)
support AES-GCM as defined in RFC 5647 (but with simpler KEX handling)
ok and feedback djm@
-rw-r--r--usr.bin/ssh/PROTOCOL14
-rw-r--r--usr.bin/ssh/authfile.c6
-rw-r--r--usr.bin/ssh/cipher.c122
-rw-r--r--usr.bin/ssh/cipher.h8
-rw-r--r--usr.bin/ssh/kex.c16
-rw-r--r--usr.bin/ssh/kex.h3
-rw-r--r--usr.bin/ssh/monitor_wrap.c39
-rw-r--r--usr.bin/ssh/myproposal.h3
-rw-r--r--usr.bin/ssh/packet.c45
-rw-r--r--usr.bin/ssh/ssh_config.57
-rw-r--r--usr.bin/ssh/sshd_config.57
11 files changed, 188 insertions, 82 deletions
diff --git a/usr.bin/ssh/PROTOCOL b/usr.bin/ssh/PROTOCOL
index eb5d0889c89..48b3a440075 100644
--- a/usr.bin/ssh/PROTOCOL
+++ b/usr.bin/ssh/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/usr.bin/ssh/authfile.c b/usr.bin/ssh/authfile.c
index f4cdf340d59..65dccabe916 100644
--- a/usr.bin/ssh/authfile.c
+++ b/usr.bin/ssh/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 <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -145,7 +145,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));
@@ -463,7 +463,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(&copy), buffer_len(&copy), 0);
+ buffer_ptr(&copy), buffer_len(&copy), 0, 0);
cipher_cleanup(&ciphercontext);
memset(&ciphercontext, 0, sizeof(ciphercontext));
buffer_free(&copy);
diff --git a/usr.bin/ssh/cipher.c b/usr.bin/ssh/cipher.c
index 5ccd265f9ce..e916bc84746 100644
--- a/usr.bin/ssh/cipher.c
+++ b/usr.bin/ssh/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 <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -55,32 +55,41 @@ struct Cipher {
int number; /* for ssh1 only */
u_int block_size;
u_int key_len;
+ u_int iv_len; /* defaults to block_size */
+ u_int auth_len;
u_int discard_len;
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 },
+ { "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 },
- { "acss@openssh.org", SSH_CIPHER_SSH2, 16, 5, 0, 0, EVP_acss },
-
- { NULL, SSH_CIPHER_INVALID, 0, 0, 0, 0, NULL }
+ 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 },
+ { "acss@openssh.org",
+ SSH_CIPHER_SSH2, 16, 5, 0, 0, 0, 0, EVP_acss },
+ { "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 },
+
+ { NULL, SSH_CIPHER_INVALID, 0, 0, 0, 0, 0, 0, NULL }
};
/*--*/
@@ -98,6 +107,18 @@ cipher_keylen(const Cipher *c)
}
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)
{
return (c->number);
@@ -212,11 +233,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;
@@ -228,6 +250,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);
@@ -257,19 +284,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
@@ -336,7 +393,12 @@ cipher_get_keyiv(CipherContext *cc, u_char *iv, u_int len)
if ((u_int)evplen != len)
fatal("%s: wrong iv length %d != %d", __func__,
evplen, len);
- memcpy(iv, cc->evp.iv, len);
+ if (cipher_authlen(c)) {
+ if (!EVP_CIPHER_CTX_ctrl(&cc->evp, EVP_CTRL_GCM_IV_GEN,
+ len, iv))
+ fatal("%s: EVP_CTRL_GCM_IV_GEN", __func__);
+ } else
+ memcpy(iv, cc->evp.iv, len);
break;
case SSH_CIPHER_3DES:
ssh1_3des_iv(&cc->evp, 0, iv, 24);
@@ -359,7 +421,13 @@ cipher_set_keyiv(CipherContext *cc, u_char *iv)
evplen = EVP_CIPHER_CTX_iv_length(&cc->evp);
if (evplen == 0)
return;
- memcpy(cc->evp.iv, iv, evplen);
+ if (cipher_authlen(c)) {
+ if (!EVP_CIPHER_CTX_ctrl(&cc->evp,
+ EVP_CTRL_GCM_SET_IV_FIXED, -1, iv))
+ fatal("%s: EVP_CTRL_GCM_SET_IV_FIXED failed",
+ __func__);
+ } else
+ memcpy(cc->evp.iv, iv, evplen);
break;
case SSH_CIPHER_3DES:
ssh1_3des_iv(&cc->evp, 1, iv, 24);
diff --git a/usr.bin/ssh/cipher.h b/usr.bin/ssh/cipher.h
index 78972fea5bf..8cb57c3e594 100644
--- a/usr.bin/ssh/cipher.h
+++ b/usr.bin/ssh/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 <ylo@cs.hut.fi>
@@ -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/usr.bin/ssh/kex.c b/usr.bin/ssh/kex.c
index 87ccd6bf78e..023ebf099dd 100644
--- a/usr.bin/ssh/kex.c
+++ b/usr.bin/ssh/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.
*
@@ -293,6 +293,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);
@@ -402,7 +403,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);
@@ -435,13 +436,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 : "<implicit>",
newkeys->comp.name);
}
choose_kex(kex, cprop[PROPOSAL_KEX_ALGS], sprop[PROPOSAL_KEX_ALGS]);
@@ -454,6 +458,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/usr.bin/ssh/kex.h b/usr.bin/ssh/kex.h
index 2db7eac4956..0cb2269d8c2 100644
--- a/usr.bin/ssh/kex.h
+++ b/usr.bin/ssh/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.
@@ -86,6 +86,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/usr.bin/ssh/monitor_wrap.c b/usr.bin/ssh/monitor_wrap.c
index c1def97470b..031284844b2 100644
--- a/usr.bin/ssh/monitor_wrap.c
+++ b/usr.bin/ssh/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 <provos@citi.umich.edu>
* Copyright 2002 Markus Friedl <markus@openbsd.org>
@@ -480,25 +480,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);
@@ -540,13 +539,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/usr.bin/ssh/myproposal.h b/usr.bin/ssh/myproposal.h
index 269bdbc839c..22a4f3998e7 100644
--- a/usr.bin/ssh/myproposal.h
+++ b/usr.bin/ssh/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.
@@ -50,6 +50,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"
#define KEX_DEFAULT_MAC \
diff --git a/usr.bin/ssh/packet.c b/usr.bin/ssh/packet.c
index b3aa9195c88..40d7cd9dbf3 100644
--- a/usr.bin/ssh/packet.c
+++ b/usr.bin/ssh/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 <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -698,7 +698,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: ");
@@ -746,7 +746,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);
@@ -763,11 +763,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);
@@ -835,7 +835,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;
@@ -846,9 +846,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];
@@ -925,10 +928,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) {
@@ -1187,7 +1190,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);
@@ -1236,7 +1239,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;
@@ -1248,10 +1251,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)
@@ -1278,7 +1284,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 ||
@@ -1304,8 +1310,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);
@@ -1317,10 +1323,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: ");
@@ -1332,8 +1339,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/usr.bin/ssh/ssh_config.5 b/usr.bin/ssh/ssh_config.5
index ee466d800af..269529c0082 100644
--- a/usr.bin/ssh/ssh_config.5
+++ b/usr.bin/ssh/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/usr.bin/ssh/sshd_config.5 b/usr.bin/ssh/sshd_config.5
index 7022f60b41a..f07c9c343c6 100644
--- a/usr.bin/ssh/sshd_config.5
+++ b/usr.bin/ssh/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
@@ -337,6 +337,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 ,
@@ -346,6 +348,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