| Hi, |
| |
| So I screwed up when writing the support for the curve25519 KEX method |
| that doesn't depend on OpenSSL's BIGNUM type - a bug in my code left |
| leading zero bytes where they should have been skipped. The impact of |
| this is that OpenSSH 6.5 and 6.6 will fail during key exchange with a |
| peer that implements curve25519-sha256 at libssh.org properly about 0.2% |
| of the time (one in every 512ish connections). |
| |
| We've fixed this for OpenSSH 6.7 by avoiding the curve25519-sha256 |
| key exchange for previous versions, but I'd recommend distributors |
| of OpenSSH apply this patch so the affected code doesn't become |
| too entrenched in LTS releases. |
| |
| The patch fixes the bug and makes OpenSSH identify itself as 6.6.1 so as |
| to distinguish itself from the incorrect versions so the compatibility |
| code to disable the affected KEX isn't activated. |
| |
| I've committed this on the 6.6 branch too. |
| |
| Apologies for the hassle. |
| |
| -d |
| |
| Index: version.h |
| =================================================================== |
| RCS file: /var/cvs/openssh/version.h,v |
| retrieving revision 1.82 |
| diff -u -p -r1.82 version.h |
| --- version.h 27 Feb 2014 23:01:54 -0000 1.82 |
| +++ version.h 20 Apr 2014 03:35:15 -0000 |
| @@ -1,6 +1,6 @@ |
| /* $OpenBSD: version.h,v 1.70 2014/02/27 22:57:40 djm Exp $ */ |
| |
| -#define SSH_VERSION "OpenSSH_6.6" |
| +#define SSH_VERSION "OpenSSH_6.6.1" |
| |
| #define SSH_PORTABLE "p1" |
| #define SSH_RELEASE SSH_VERSION SSH_PORTABLE |
| Index: compat.c |
| =================================================================== |
| RCS file: /var/cvs/openssh/compat.c,v |
| retrieving revision 1.82 |
| retrieving revision 1.85 |
| diff -u -p -r1.82 -r1.85 |
| --- compat.c 31 Dec 2013 01:25:41 -0000 1.82 |
| +++ compat.c 20 Apr 2014 03:33:59 -0000 1.85 |
| @@ -95,6 +95,9 @@ compat_datafellows(const char *version) |
| { "Sun_SSH_1.0*", SSH_BUG_NOREKEY|SSH_BUG_EXTEOF}, |
| { "OpenSSH_4*", 0 }, |
| { "OpenSSH_5*", SSH_NEW_OPENSSH|SSH_BUG_DYNAMIC_RPORT}, |
| + { "OpenSSH_6.6.1*", SSH_NEW_OPENSSH}, |
| + { "OpenSSH_6.5*," |
| + "OpenSSH_6.6*", SSH_NEW_OPENSSH|SSH_BUG_CURVE25519PAD}, |
| { "OpenSSH*", SSH_NEW_OPENSSH }, |
| { "*MindTerm*", 0 }, |
| { "2.1.0*", SSH_BUG_SIGBLOB|SSH_BUG_HMAC| |
| @@ -251,7 +254,6 @@ compat_cipher_proposal(char *cipher_prop |
| return cipher_prop; |
| } |
| |
| - |
| char * |
| compat_pkalg_proposal(char *pkalg_prop) |
| { |
| @@ -263,5 +265,18 @@ compat_pkalg_proposal(char *pkalg_prop) |
| if (*pkalg_prop == '\0') |
| fatal("No supported PK algorithms found"); |
| return pkalg_prop; |
| +} |
| + |
| +char * |
| +compat_kex_proposal(char *kex_prop) |
| +{ |
| + if (!(datafellows & SSH_BUG_CURVE25519PAD)) |
| + return kex_prop; |
| + debug2("%s: original KEX proposal: %s", __func__, kex_prop); |
| + kex_prop = filter_proposal(kex_prop, "curve25519-sha256@libssh.org"); |
| + debug2("%s: compat KEX proposal: %s", __func__, kex_prop); |
| + if (*kex_prop == '\0') |
| + fatal("No supported key exchange algorithms found"); |
| + return kex_prop; |
| } |
| |
| Index: compat.h |
| =================================================================== |
| RCS file: /var/cvs/openssh/compat.h,v |
| retrieving revision 1.42 |
| retrieving revision 1.43 |
| diff -u -p -r1.42 -r1.43 |
| --- compat.h 31 Dec 2013 01:25:41 -0000 1.42 |
| +++ compat.h 20 Apr 2014 03:25:31 -0000 1.43 |
| @@ -59,6 +59,7 @@ |
| #define SSH_BUG_RFWD_ADDR 0x02000000 |
| #define SSH_NEW_OPENSSH 0x04000000 |
| #define SSH_BUG_DYNAMIC_RPORT 0x08000000 |
| +#define SSH_BUG_CURVE25519PAD 0x10000000 |
| |
| void enable_compat13(void); |
| void enable_compat20(void); |
| @@ -66,6 +67,7 @@ void compat_datafellows(const char * |
| int proto_spec(const char *); |
| char *compat_cipher_proposal(char *); |
| char *compat_pkalg_proposal(char *); |
| +char *compat_kex_proposal(char *); |
| |
| extern int compat13; |
| extern int compat20; |
| Index: sshd.c |
| =================================================================== |
| RCS file: /var/cvs/openssh/sshd.c,v |
| retrieving revision 1.448 |
| retrieving revision 1.453 |
| diff -u -p -r1.448 -r1.453 |
| --- sshd.c 26 Feb 2014 23:20:08 -0000 1.448 |
| +++ sshd.c 20 Apr 2014 03:28:41 -0000 1.453 |
| @@ -2462,6 +2438,9 @@ do_ssh2_kex(void) |
| if (options.kex_algorithms != NULL) |
| myproposal[PROPOSAL_KEX_ALGS] = options.kex_algorithms; |
| |
| + myproposal[PROPOSAL_KEX_ALGS] = compat_kex_proposal( |
| + myproposal[PROPOSAL_KEX_ALGS]); |
| + |
| if (options.rekey_limit || options.rekey_interval) |
| packet_set_rekey_limits((u_int32_t)options.rekey_limit, |
| (time_t)options.rekey_interval); |
| Index: sshconnect2.c |
| =================================================================== |
| RCS file: /var/cvs/openssh/sshconnect2.c,v |
| retrieving revision 1.197 |
| retrieving revision 1.199 |
| diff -u -p -r1.197 -r1.199 |
| --- sshconnect2.c 4 Feb 2014 00:20:16 -0000 1.197 |
| +++ sshconnect2.c 20 Apr 2014 03:25:31 -0000 1.199 |
| @@ -195,6 +196,8 @@ ssh_kex2(char *host, struct sockaddr *ho |
| } |
| if (options.kex_algorithms != NULL) |
| myproposal[PROPOSAL_KEX_ALGS] = options.kex_algorithms; |
| + myproposal[PROPOSAL_KEX_ALGS] = compat_kex_proposal( |
| + myproposal[PROPOSAL_KEX_ALGS]); |
| |
| if (options.rekey_limit || options.rekey_interval) |
| packet_set_rekey_limits((u_int32_t)options.rekey_limit, |
| Index: bufaux.c |
| =================================================================== |
| RCS file: /var/cvs/openssh/bufaux.c,v |
| retrieving revision 1.62 |
| retrieving revision 1.63 |
| diff -u -p -r1.62 -r1.63 |
| --- bufaux.c 4 Feb 2014 00:20:15 -0000 1.62 |
| +++ bufaux.c 20 Apr 2014 03:24:50 -0000 1.63 |
| @@ -1,4 +1,4 @@ |
| -/* $OpenBSD: bufaux.c,v 1.56 2014/02/02 03:44:31 djm Exp $ */ |
| +/* $OpenBSD: bufaux.c,v 1.57 2014/04/16 23:22:45 djm Exp $ */ |
| /* |
| * Author: Tatu Ylonen <ylo@cs.hut.fi> |
| * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
| @@ -372,6 +372,9 @@ buffer_put_bignum2_from_string(Buffer *b |
| |
| if (l > 8 * 1024) |
| fatal("%s: length %u too long", __func__, l); |
| + /* Skip leading zero bytes */ |
| + for (; l > 0 && *s == 0; l--, s++) |
| + ; |
| p = buf = xmalloc(l + 1); |
| /* |
| * If most significant bit is set then prepend a zero byte to |