346 lines
12 KiB
Diff
346 lines
12 KiB
Diff
|
# HG changeset patch
|
||
|
# Parent 7e46491ef372d47617499c58acf2ea66216858d2
|
||
|
|
||
|
Raise minimal size of DH group parameters to 2048 bits like upstream did in
|
||
|
7.2. 1024b values are believed to be in breaking range for state adversaries
|
||
|
and the default moduli shipped with openssh have been around long enough to
|
||
|
make it more likely for them to be broken.
|
||
|
|
||
|
Also provide an option that allows the client to accept shorter (RFC4419
|
||
|
compliant) parameters.
|
||
|
|
||
|
CVE-2015-4000 (LOGJAM)
|
||
|
bsc#932483
|
||
|
|
||
|
diff --git a/openssh-7.2p2/dh.c b/openssh-7.2p2/dh.c
|
||
|
--- a/openssh-7.2p2/dh.c
|
||
|
+++ b/openssh-7.2p2/dh.c
|
||
|
@@ -37,16 +37,18 @@
|
||
|
#include <limits.h>
|
||
|
|
||
|
#include "dh.h"
|
||
|
#include "pathnames.h"
|
||
|
#include "log.h"
|
||
|
#include "misc.h"
|
||
|
#include "ssherr.h"
|
||
|
|
||
|
+int dh_grp_min = DH_GRP_MIN;
|
||
|
+
|
||
|
static int
|
||
|
parse_prime(int linenum, char *line, struct dhgroup *dhg)
|
||
|
{
|
||
|
char *cp, *arg;
|
||
|
char *strsize, *gen, *prime;
|
||
|
const char *errstr = NULL;
|
||
|
long long n;
|
||
|
|
||
|
diff --git a/openssh-7.2p2/dh.h b/openssh-7.2p2/dh.h
|
||
|
--- a/openssh-7.2p2/dh.h
|
||
|
+++ b/openssh-7.2p2/dh.h
|
||
|
@@ -43,16 +43,17 @@ int dh_gen_key(DH *, int);
|
||
|
int dh_pub_is_valid(DH *, BIGNUM *);
|
||
|
|
||
|
u_int dh_estimate(int);
|
||
|
|
||
|
/*
|
||
|
* Max value from RFC4419.
|
||
|
* Miniumum increased in light of DH precomputation attacks.
|
||
|
*/
|
||
|
+#define DH_GRP_MIN_RFC 1024
|
||
|
#define DH_GRP_MIN 2048
|
||
|
#define DH_GRP_MAX 8192
|
||
|
|
||
|
/*
|
||
|
* Values for "type" field of moduli(5)
|
||
|
* Specifies the internal structure of the prime modulus.
|
||
|
*/
|
||
|
#define MODULI_TYPE_UNKNOWN (0)
|
||
|
diff --git a/openssh-7.2p2/kexgexc.c b/openssh-7.2p2/kexgexc.c
|
||
|
--- a/openssh-7.2p2/kexgexc.c
|
||
|
+++ b/openssh-7.2p2/kexgexc.c
|
||
|
@@ -46,29 +46,32 @@
|
||
|
#include "packet.h"
|
||
|
#include "dh.h"
|
||
|
#include "ssh2.h"
|
||
|
#include "compat.h"
|
||
|
#include "dispatch.h"
|
||
|
#include "ssherr.h"
|
||
|
#include "sshbuf.h"
|
||
|
|
||
|
+/* import from dh.c */
|
||
|
+extern int dh_grp_min;
|
||
|
+
|
||
|
static int input_kex_dh_gex_group(int, u_int32_t, void *);
|
||
|
static int input_kex_dh_gex_reply(int, u_int32_t, void *);
|
||
|
|
||
|
int
|
||
|
kexgex_client(struct ssh *ssh)
|
||
|
{
|
||
|
struct kex *kex = ssh->kex;
|
||
|
int r;
|
||
|
u_int nbits;
|
||
|
|
||
|
nbits = dh_estimate(kex->dh_need * 8);
|
||
|
|
||
|
- kex->min = DH_GRP_MIN;
|
||
|
+ kex->min = dh_grp_min;
|
||
|
kex->max = DH_GRP_MAX;
|
||
|
kex->nbits = nbits;
|
||
|
if (datafellows & SSH_BUG_DHGEX_LARGE)
|
||
|
kex->nbits = MIN(kex->nbits, 4096);
|
||
|
/* New GEX request */
|
||
|
if ((r = sshpkt_start(ssh, SSH2_MSG_KEX_DH_GEX_REQUEST)) != 0 ||
|
||
|
(r = sshpkt_put_u32(ssh, kex->min)) != 0 ||
|
||
|
(r = sshpkt_put_u32(ssh, kex->nbits)) != 0 ||
|
||
|
@@ -104,16 +107,22 @@ input_kex_dh_gex_group(int type, u_int32
|
||
|
goto out;
|
||
|
}
|
||
|
if ((r = sshpkt_get_bignum2(ssh, p)) != 0 ||
|
||
|
(r = sshpkt_get_bignum2(ssh, g)) != 0 ||
|
||
|
(r = sshpkt_get_end(ssh)) != 0)
|
||
|
goto out;
|
||
|
if ((bits = BN_num_bits(p)) < 0 ||
|
||
|
(u_int)bits < kex->min || (u_int)bits > kex->max) {
|
||
|
+ if (bits < kex->min && bits >= DH_GRP_MIN_RFC)
|
||
|
+ logit("DH parameter offered by the server (%d bits) "
|
||
|
+ "is considered insecure. "
|
||
|
+ "You can lower the accepted the minimum "
|
||
|
+ "via the KexDHMin option.",
|
||
|
+ bits);
|
||
|
r = SSH_ERR_DH_GEX_OUT_OF_RANGE;
|
||
|
goto out;
|
||
|
}
|
||
|
if ((kex->dh = dh_new_group(g, p)) == NULL) {
|
||
|
r = SSH_ERR_ALLOC_FAIL;
|
||
|
goto out;
|
||
|
}
|
||
|
p = g = NULL; /* belong to kex->dh now */
|
||
|
diff --git a/openssh-7.2p2/readconf.c b/openssh-7.2p2/readconf.c
|
||
|
--- a/openssh-7.2p2/readconf.c
|
||
|
+++ b/openssh-7.2p2/readconf.c
|
||
|
@@ -56,16 +56,17 @@
|
||
|
#include "misc.h"
|
||
|
#include "readconf.h"
|
||
|
#include "match.h"
|
||
|
#include "kex.h"
|
||
|
#include "mac.h"
|
||
|
#include "uidswap.h"
|
||
|
#include "myproposal.h"
|
||
|
#include "digest.h"
|
||
|
+#include "dh.h"
|
||
|
|
||
|
/* Format of the configuration file:
|
||
|
|
||
|
# Configuration data is parsed as follows:
|
||
|
# 1. command line options
|
||
|
# 2. user-specific file
|
||
|
# 3. system-wide file
|
||
|
# Any configuration value is only changed the first time it is set.
|
||
|
@@ -148,17 +149,18 @@ typedef enum {
|
||
|
oClearAllForwardings, oNoHostAuthenticationForLocalhost,
|
||
|
oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout,
|
||
|
oAddressFamily, oGssAuthentication, oGssDelegateCreds,
|
||
|
oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly,
|
||
|
oSendEnv, oControlPath, oControlMaster, oControlPersist,
|
||
|
oHashKnownHosts,
|
||
|
oTunnel, oTunnelDevice, oLocalCommand, oPermitLocalCommand,
|
||
|
oVisualHostKey,
|
||
|
- oKexAlgorithms, oIPQoS, oRequestTTY, oIgnoreUnknown, oProxyUseFdpass,
|
||
|
+ oKexAlgorithms, oKexDHMin,
|
||
|
+ oIPQoS, oRequestTTY, oIgnoreUnknown, oProxyUseFdpass,
|
||
|
oCanonicalDomains, oCanonicalizeHostname, oCanonicalizeMaxDots,
|
||
|
oCanonicalizeFallbackLocal, oCanonicalizePermittedCNAMEs,
|
||
|
oStreamLocalBindMask, oStreamLocalBindUnlink, oRevokedHostKeys,
|
||
|
oFingerprintHash, oUpdateHostkeys, oHostbasedKeyTypes,
|
||
|
oPubkeyAcceptedKeyTypes,
|
||
|
oIgnoredUnknownOption, oDeprecated, oUnsupported
|
||
|
} OpCodes;
|
||
|
|
||
|
@@ -260,16 +262,17 @@ static struct {
|
||
|
{ "hashknownhosts", oHashKnownHosts },
|
||
|
{ "tunnel", oTunnel },
|
||
|
{ "tunneldevice", oTunnelDevice },
|
||
|
{ "localcommand", oLocalCommand },
|
||
|
{ "permitlocalcommand", oPermitLocalCommand },
|
||
|
{ "visualhostkey", oVisualHostKey },
|
||
|
{ "useroaming", oDeprecated },
|
||
|
{ "kexalgorithms", oKexAlgorithms },
|
||
|
+ { "kexdhmin", oKexDHMin },
|
||
|
{ "ipqos", oIPQoS },
|
||
|
{ "requesttty", oRequestTTY },
|
||
|
{ "proxyusefdpass", oProxyUseFdpass },
|
||
|
{ "canonicaldomains", oCanonicalDomains },
|
||
|
{ "canonicalizefallbacklocal", oCanonicalizeFallbackLocal },
|
||
|
{ "canonicalizehostname", oCanonicalizeHostname },
|
||
|
{ "canonicalizemaxdots", oCanonicalizeMaxDots },
|
||
|
{ "canonicalizepermittedcnames", oCanonicalizePermittedCNAMEs },
|
||
|
@@ -280,16 +283,19 @@ static struct {
|
||
|
{ "updatehostkeys", oUpdateHostkeys },
|
||
|
{ "hostbasedkeytypes", oHostbasedKeyTypes },
|
||
|
{ "pubkeyacceptedkeytypes", oPubkeyAcceptedKeyTypes },
|
||
|
{ "ignoreunknown", oIgnoreUnknown },
|
||
|
|
||
|
{ NULL, oBadOption }
|
||
|
};
|
||
|
|
||
|
+/* import from dh.c */
|
||
|
+extern int dh_grp_min;
|
||
|
+
|
||
|
/*
|
||
|
* Adds a local TCP/IP port forward to options. Never returns if there is an
|
||
|
* error.
|
||
|
*/
|
||
|
|
||
|
void
|
||
|
add_local_forward(Options *options, const struct Forward *newfwd)
|
||
|
{
|
||
|
@@ -1157,16 +1163,20 @@ parse_int:
|
||
|
filename, linenum);
|
||
|
if (!kex_names_valid(*arg == '+' ? arg + 1 : arg))
|
||
|
fatal("%.200s line %d: Bad SSH2 KexAlgorithms '%s'.",
|
||
|
filename, linenum, arg ? arg : "<NONE>");
|
||
|
if (*activep && options->kex_algorithms == NULL)
|
||
|
options->kex_algorithms = xstrdup(arg);
|
||
|
break;
|
||
|
|
||
|
+ case oKexDHMin:
|
||
|
+ intptr = &options->kex_dhmin;
|
||
|
+ goto parse_int;
|
||
|
+
|
||
|
case oHostKeyAlgorithms:
|
||
|
charptr = &options->hostkeyalgorithms;
|
||
|
parse_keytypes:
|
||
|
arg = strdelim(&s);
|
||
|
if (!arg || *arg == '\0')
|
||
|
fatal("%.200s line %d: Missing argument.",
|
||
|
filename, linenum);
|
||
|
if (!sshkey_names_valid2(*arg == '+' ? arg + 1 : arg, 1))
|
||
|
@@ -1664,16 +1674,17 @@ initialize_options(Options * options)
|
||
|
options->address_family = -1;
|
||
|
options->connection_attempts = -1;
|
||
|
options->connection_timeout = -1;
|
||
|
options->number_of_password_prompts = -1;
|
||
|
options->cipher = -1;
|
||
|
options->ciphers = NULL;
|
||
|
options->macs = NULL;
|
||
|
options->kex_algorithms = NULL;
|
||
|
+ options->kex_dhmin = -1;
|
||
|
options->hostkeyalgorithms = NULL;
|
||
|
options->protocol = SSH_PROTO_UNKNOWN;
|
||
|
options->num_identity_files = 0;
|
||
|
options->num_certificate_files = 0;
|
||
|
options->hostname = NULL;
|
||
|
options->host_key_alias = NULL;
|
||
|
options->proxy_command = NULL;
|
||
|
options->user = NULL;
|
||
|
@@ -1805,16 +1816,23 @@ fill_default_options(Options * options)
|
||
|
options->address_family = AF_UNSPEC;
|
||
|
if (options->connection_attempts == -1)
|
||
|
options->connection_attempts = 1;
|
||
|
if (options->number_of_password_prompts == -1)
|
||
|
options->number_of_password_prompts = 3;
|
||
|
/* Selected in ssh_login(). */
|
||
|
if (options->cipher == -1)
|
||
|
options->cipher = SSH_CIPHER_NOT_SET;
|
||
|
+ if (options->kex_dhmin == -1)
|
||
|
+ options->kex_dhmin = DH_GRP_MIN;
|
||
|
+ else {
|
||
|
+ options->kex_dhmin = MAX(options->kex_dhmin, DH_GRP_MIN_RFC);
|
||
|
+ options->kex_dhmin = MIN(options->kex_dhmin, DH_GRP_MAX);
|
||
|
+ }
|
||
|
+ dh_grp_min = options->kex_dhmin;
|
||
|
/* options->hostkeyalgorithms, default set in myproposals.h */
|
||
|
if (options->protocol == SSH_PROTO_UNKNOWN)
|
||
|
options->protocol = SSH_PROTO_2;
|
||
|
if (options->add_keys_to_agent == -1)
|
||
|
options->add_keys_to_agent = 0;
|
||
|
if (options->num_identity_files == 0) {
|
||
|
if (options->protocol & SSH_PROTO_1) {
|
||
|
add_identity_file(options, "~/",
|
||
|
diff --git a/openssh-7.2p2/readconf.h b/openssh-7.2p2/readconf.h
|
||
|
--- a/openssh-7.2p2/readconf.h
|
||
|
+++ b/openssh-7.2p2/readconf.h
|
||
|
@@ -69,16 +69,17 @@ typedef struct {
|
||
|
* aborting connection attempt */
|
||
|
int number_of_password_prompts; /* Max number of password
|
||
|
* prompts. */
|
||
|
int cipher; /* Cipher to use. */
|
||
|
char *ciphers; /* SSH2 ciphers in order of preference. */
|
||
|
char *macs; /* SSH2 macs in order of preference. */
|
||
|
char *hostkeyalgorithms; /* SSH2 server key types in order of preference. */
|
||
|
char *kex_algorithms; /* SSH2 kex methods in order of preference. */
|
||
|
+ int kex_dhmin; /* minimum bit length of the DH group parameter */
|
||
|
int protocol; /* Protocol in order of preference. */
|
||
|
char *hostname; /* Real host to connect. */
|
||
|
char *host_key_alias; /* hostname alias for .ssh/known_hosts */
|
||
|
char *proxy_command; /* Proxy command for connecting the host. */
|
||
|
char *user; /* User to log in as. */
|
||
|
int escape_char; /* Escape character; -2 = none */
|
||
|
|
||
|
u_int num_system_hostfiles; /* Paths for /etc/ssh/ssh_known_hosts */
|
||
|
diff --git a/openssh-7.2p2/ssh_config.0 b/openssh-7.2p2/ssh_config.0
|
||
|
--- a/openssh-7.2p2/ssh_config.0
|
||
|
+++ b/openssh-7.2p2/ssh_config.0
|
||
|
@@ -606,16 +606,29 @@ DESCRIPTION
|
||
|
ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,
|
||
|
diffie-hellman-group-exchange-sha256,
|
||
|
diffie-hellman-group-exchange-sha1,
|
||
|
diffie-hellman-group14-sha1
|
||
|
|
||
|
The list of available key exchange algorithms may also be
|
||
|
obtained using the -Q option of ssh(1) with an argument of M-bM-^@M-^\kexM-bM-^@M-^].
|
||
|
|
||
|
+ KexDHMin
|
||
|
+ Specifies the minimum accepted bit length of the DH group parameter p.
|
||
|
+ As per RFC4419, this is 1024 bits however, this has increasingly
|
||
|
+ been seen as insecure, which prompted the change to 2048 bits.
|
||
|
+ Setting this option allows the client to accept parameters shorter
|
||
|
+ than the current minimum, down to the RFC specified 1024 bits.
|
||
|
+ Using this option may be needed when connecting to servers that
|
||
|
+ only know short DH group parameters.
|
||
|
+
|
||
|
+ Note that using this option can severly impact security and thus
|
||
|
+ should be viewed as a temporary fix of last resort and all efforts
|
||
|
+ should be made to fix the server.
|
||
|
+
|
||
|
LocalCommand
|
||
|
Specifies a command to execute on the local machine after
|
||
|
successfully connecting to the server. The command string
|
||
|
extends to the end of the line, and is executed with the user's
|
||
|
shell. The following escape character substitutions will be
|
||
|
performed: M-bM-^@M-^X%dM-bM-^@M-^Y (local user's home directory), M-bM-^@M-^X%hM-bM-^@M-^Y (remote host
|
||
|
name), M-bM-^@M-^X%lM-bM-^@M-^Y (local host name), M-bM-^@M-^X%nM-bM-^@M-^Y (host name as provided on the
|
||
|
command line), M-bM-^@M-^X%pM-bM-^@M-^Y (remote port), M-bM-^@M-^X%rM-bM-^@M-^Y (remote user name) or
|
||
|
diff --git a/openssh-7.2p2/ssh_config.5 b/openssh-7.2p2/ssh_config.5
|
||
|
--- a/openssh-7.2p2/ssh_config.5
|
||
|
+++ b/openssh-7.2p2/ssh_config.5
|
||
|
@@ -1092,16 +1092,28 @@ diffie-hellman-group14-sha1
|
||
|
.Ed
|
||
|
.Pp
|
||
|
The list of available key exchange algorithms may also be obtained using the
|
||
|
.Fl Q
|
||
|
option of
|
||
|
.Xr ssh 1
|
||
|
with an argument of
|
||
|
.Dq kex .
|
||
|
+.It Cm KexDHMin
|
||
|
+Specifies the minimum accepted bit length of the DH group parameter p.
|
||
|
+As per RFC4419, this is 1024 bits however, this has increasingly
|
||
|
+been seen as insecure, which prompted the change to 2048 bits.
|
||
|
+Setting this option allows the client to accept parameters shorter
|
||
|
+than the current minimum, down to the RFC specified 1024 bits.
|
||
|
+Using this option may be needed when connecting to servers that
|
||
|
+only know short DH group parameters.
|
||
|
+
|
||
|
+Note that using this option can severly impact security and thus
|
||
|
+should be viewed as a temporary fix of last resort and all efforts
|
||
|
+should be made to fix the server.
|
||
|
.It Cm LocalCommand
|
||
|
Specifies a command to execute on the local machine after successfully
|
||
|
connecting to the server.
|
||
|
The command string extends to the end of the line, and is executed with
|
||
|
the user's shell.
|
||
|
The following escape character substitutions will be performed:
|
||
|
.Ql %d
|
||
|
(local user's home directory),
|