diff options
author | Markus Friedl <markus@cvs.openbsd.org> | 2013-01-08 18:49:05 +0000 |
---|---|---|
committer | Markus Friedl <markus@cvs.openbsd.org> | 2013-01-08 18:49:05 +0000 |
commit | adf9515dca30a3e56b227376e4caf8279c4385cd (patch) | |
tree | 2ef3374d339cc3c8ba5369bf449b62680f0fc5d8 | |
parent | 9c87c513b2e6c27969fbb097086b37bbff57e99a (diff) |
support AES-GCM as defined in RFC 5647 (but with simpler KEX handling)
ok and feedback djm@
-rw-r--r-- | usr.bin/ssh/PROTOCOL | 14 | ||||
-rw-r--r-- | usr.bin/ssh/authfile.c | 6 | ||||
-rw-r--r-- | usr.bin/ssh/cipher.c | 122 | ||||
-rw-r--r-- | usr.bin/ssh/cipher.h | 8 | ||||
-rw-r--r-- | usr.bin/ssh/kex.c | 16 | ||||
-rw-r--r-- | usr.bin/ssh/kex.h | 3 | ||||
-rw-r--r-- | usr.bin/ssh/monitor_wrap.c | 39 | ||||
-rw-r--r-- | usr.bin/ssh/myproposal.h | 3 | ||||
-rw-r--r-- | usr.bin/ssh/packet.c | 45 | ||||
-rw-r--r-- | usr.bin/ssh/ssh_config.5 | 7 | ||||
-rw-r--r-- | usr.bin/ssh/sshd_config.5 | 7 |
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(©), buffer_len(©), 0); + buffer_ptr(©), buffer_len(©), 0, 0); cipher_cleanup(&ciphercontext); memset(&ciphercontext, 0, sizeof(ciphercontext)); buffer_free(©); 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 |