# HG changeset patch
# Parent  2e38e2dd55da92c77e5d99ea40eaa0121e71f45a

Raise minimal size of DH group parameters to 1536bits. 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.

CVE-2015-4000 (LOGJAM)
bsc#932483

diff --git a/openssh-5.1p1/dh.c b/openssh-5.1p1/dh.c
--- a/openssh-5.1p1/dh.c
+++ b/openssh-5.1p1/dh.c
@@ -35,16 +35,18 @@
 #include <stdlib.h>
 #include <string.h>
 
 #include "dh.h"
 #include "pathnames.h"
 #include "log.h"
 #include "misc.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-5.1p1/dh.h b/openssh-5.1p1/dh.h
--- a/openssh-5.1p1/dh.h
+++ b/openssh-5.1p1/dh.h
@@ -38,17 +38,18 @@ DH	*dh_new_group(BIGNUM *, BIGNUM *);
 DH	*dh_new_group1(void);
 DH	*dh_new_group14(void);
 
 void	 dh_gen_key(DH *, int);
 int	 dh_pub_is_valid(DH *, BIGNUM *);
 
 int	 dh_estimate(int);
 
-#define DH_GRP_MIN	1024
+#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)
 #define MODULI_TYPE_UNSTRUCTURED	(1)
diff --git a/openssh-5.1p1/kexgexc.c b/openssh-5.1p1/kexgexc.c
--- a/openssh-5.1p1/kexgexc.c
+++ b/openssh-5.1p1/kexgexc.c
@@ -39,41 +39,45 @@
 #include "cipher.h"
 #include "kex.h"
 #include "log.h"
 #include "packet.h"
 #include "dh.h"
 #include "ssh2.h"
 #include "compat.h"
 
+/* import from dh.c */
+extern int dh_grp_min;
+
 void
 kexgex_client(Kex *kex)
 {
 	BIGNUM *dh_server_pub = NULL, *shared_secret = NULL;
 	BIGNUM *p = NULL, *g = NULL;
 	Key *server_host_key;
 	u_char *kbuf, *hash, *signature = NULL, *server_host_key_blob = NULL;
 	u_int klen, slen, sbloblen, hashlen;
 	int kout;
 	int min, max, nbits;
+	int p_bitlen;
 	DH *dh;
 
 	nbits = dh_estimate(kex->we_need * 8);
 
 	if (datafellows & SSH_OLD_DHGEX) {
 		/* Old GEX request */
 		packet_start(SSH2_MSG_KEX_DH_GEX_REQUEST_OLD);
 		packet_put_int(nbits);
-		min = DH_GRP_MIN;
+		min = dh_grp_min;
 		max = DH_GRP_MAX;
 
 		debug("SSH2_MSG_KEX_DH_GEX_REQUEST_OLD(%u) sent", nbits);
 	} else {
 		/* New GEX request */
-		min = DH_GRP_MIN;
+		min = dh_grp_min;
 		max = DH_GRP_MAX;
 		packet_start(SSH2_MSG_KEX_DH_GEX_REQUEST);
 		packet_put_int(min);
 		packet_put_int(nbits);
 		packet_put_int(max);
 
 		debug("SSH2_MSG_KEX_DH_GEX_REQUEST(%u<%u<%u) sent",
 		    min, nbits, max);
@@ -85,24 +89,32 @@ kexgex_client(Kex *kex)
 	packet_send();
 
 	debug("expecting SSH2_MSG_KEX_DH_GEX_GROUP");
 	packet_read_expect(SSH2_MSG_KEX_DH_GEX_GROUP);
 
 	if ((p = BN_new()) == NULL)
 		fatal("BN_new");
 	packet_get_bignum2(p);
+	p_bitlen = BN_num_bits(p);
 	if ((g = BN_new()) == NULL)
 		fatal("BN_new");
 	packet_get_bignum2(g);
 	packet_check_eom();
 
-	if (BN_num_bits(p) < min || BN_num_bits(p) > max)
+	if (p_bitlen < min || p_bitlen > max) {
+		if (p_bitlen < min && p_bitlen >= DH_GRP_MIN_RFC)
+			logit("DH parameter offered by the server (%d bits) "
+			    "is considered insecure. "
+			    "You can lower the accepted minimum "
+			    "via the KexDHMin option.",
+			    p_bitlen);
 		fatal("DH_GEX group out of range: %d !< %d !< %d",
-		    min, BN_num_bits(p), max);
+		    min, p_bitlen, max);
+	}
 
 	dh = dh_new_group(g, p);
 	dh_gen_key(dh, kex->we_need * 8);
 
 #ifdef DEBUG_KEXDH
 	DHparams_print_fp(stderr, dh);
 	fprintf(stderr, "pub= ");
 	BN_print_fp(stderr, dh->pub_key);
diff --git a/openssh-5.1p1/kexgexs.c b/openssh-5.1p1/kexgexs.c
--- a/openssh-5.1p1/kexgexs.c
+++ b/openssh-5.1p1/kexgexs.c
@@ -45,16 +45,19 @@
 #include "dh.h"
 #include "ssh2.h"
 #include "compat.h"
 #ifdef GSSAPI
 #include "ssh-gss.h"
 #endif
 #include "monitor_wrap.h"
 
+/* import from dh.c */
+extern int dh_grp_min;
+
 void
 kexgex_server(Kex *kex)
 {
 	BIGNUM *shared_secret = NULL, *dh_client_pub = NULL;
 	Key *server_host_key;
 	DH *dh;
 	u_char *kbuf, *hash, *signature = NULL, *server_host_key_blob = NULL;
 	u_int sbloblen, klen, slen, hashlen;
@@ -69,36 +72,43 @@ kexgex_server(Kex *kex)
 
 	type = packet_read();
 	switch (type) {
 	case SSH2_MSG_KEX_DH_GEX_REQUEST:
 		debug("SSH2_MSG_KEX_DH_GEX_REQUEST received");
 		omin = min = packet_get_int();
 		onbits = nbits = packet_get_int();
 		omax = max = packet_get_int();
-		min = MAX(DH_GRP_MIN, min);
+		min = MAX(dh_grp_min, min);
 		max = MIN(DH_GRP_MAX, max);
-		nbits = MAX(DH_GRP_MIN, nbits);
+		nbits = MAX(dh_grp_min, nbits);
 		nbits = MIN(DH_GRP_MAX, nbits);
 		break;
 	case SSH2_MSG_KEX_DH_GEX_REQUEST_OLD:
 		debug("SSH2_MSG_KEX_DH_GEX_REQUEST_OLD received");
 		onbits = nbits = packet_get_int();
 		/* unused for old GEX */
-		omin = min = DH_GRP_MIN;
+		omin = min = dh_grp_min;
 		omax = max = DH_GRP_MAX;
 		break;
 	default:
 		fatal("protocol error during kex, no DH_GEX_REQUEST: %d", type);
 	}
 	packet_check_eom();
 
-	if (omax < omin || onbits < omin || omax < onbits)
+	if (omax < omin || onbits < omin || omax < onbits) {
+		if (onbits < omin && onbits >= DH_GRP_MIN_RFC)
+			logit("DH parameter requested by the client (%d bits) "
+			    "is considered insecure. "
+			    "You can lower the accepted minimum "
+			    "via the KexDHMin option.",
+			    onbits);
 		fatal("DH_GEX_REQUEST, bad parameters: %d !< %d !< %d",
 		    omin, onbits, omax);
+	}
 
 	/* Contact privileged parent */
 	dh = PRIVSEP(choose_dh(min, nbits, max));
 	if (dh == NULL)
 		packet_disconnect("Protocol error: no matching DH grp found");
 
 	debug("SSH2_MSG_KEX_DH_GEX_GROUP sent");
 	packet_start(SSH2_MSG_KEX_DH_GEX_GROUP);
diff --git a/openssh-5.1p1/readconf.c b/openssh-5.1p1/readconf.c
--- a/openssh-5.1p1/readconf.c
+++ b/openssh-5.1p1/readconf.c
@@ -37,16 +37,17 @@
 #include "log.h"
 #include "key.h"
 #include "readconf.h"
 #include "match.h"
 #include "misc.h"
 #include "buffer.h"
 #include "kex.h"
 #include "mac.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.
@@ -126,16 +127,17 @@ typedef enum {
 	oHostKeyAlgorithms, oBindAddress, oSmartcardDevice,
 	oClearAllForwardings, oNoHostAuthenticationForLocalhost,
 	oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout,
 	oAddressFamily, oGssAuthentication, oGssDelegateCreds, oGssEnableMITM,
 	oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly,
 	oSendEnv, oControlPath, oControlMaster, oHashKnownHosts,
 	oTunnel, oTunnelDevice, oLocalCommand, oPermitLocalCommand,
 	oVisualHostKey,
+	oKexDHMin,
 	oDeprecated, oUnsupported
 } OpCodes;
 
 /* Textual representations of the tokens. */
 
 static struct {
 	const char *name;
 	OpCodes opcode;
@@ -225,19 +227,23 @@ static struct {
 	{ "controlpath", oControlPath },
 	{ "controlmaster", oControlMaster },
 	{ "hashknownhosts", oHashKnownHosts },
 	{ "tunnel", oTunnel },
 	{ "tunneldevice", oTunnelDevice },
 	{ "localcommand", oLocalCommand },
 	{ "permitlocalcommand", oPermitLocalCommand },
 	{ "visualhostkey", oVisualHostKey },
+	{ "kexdhmin", oKexDHMin },
 	{ 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 Forward *newfwd)
 {
@@ -670,16 +676,20 @@ parse_int:
 			fatal("%.200s line %d: Missing argument.", filename, linenum);
 		if (!mac_valid(arg))
 			fatal("%.200s line %d: Bad SSH2 Mac spec '%s'.",
 			    filename, linenum, arg ? arg : "<NONE>");
 		if (*activep && options->macs == NULL)
 			options->macs = xstrdup(arg);
 		break;
 
+	case oKexDHMin:
+		intptr = &options->kex_dhmin;
+		goto parse_int;
+
 	case oHostKeyAlgorithms:
 		arg = strdelim(&s);
 		if (!arg || *arg == '\0')
 			fatal("%.200s line %d: Missing argument.", filename, linenum);
 		if (!key_names_valid2(arg))
 			fatal("%.200s line %d: Bad protocol 2 host key algorithms '%s'.",
 			    filename, linenum, arg ? arg : "<NONE>");
 		if (*activep && options->hostkeyalgorithms == NULL)
@@ -1038,16 +1048,17 @@ initialize_options(Options * options)
 	options->port = -1;
 	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_dhmin = -1;
 	options->hostkeyalgorithms = NULL;
 	options->protocol = SSH_PROTO_UNKNOWN;
 	options->num_identity_files = 0;
 	options->hostname = NULL;
 	options->host_key_alias = NULL;
 	options->proxy_command = NULL;
 	options->user = NULL;
 	options->escape_char = -1;
@@ -1145,16 +1156,23 @@ fill_default_options(Options * options)
 		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;
 	/* options->ciphers, default set in myproposals.h */
 	/* options->macs, default set in myproposals.h */
+	if (options->kex_dhmin == -1)
+		options->kex_dhmin = DH_GRP_MIN_RFC;
+	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_1|SSH_PROTO_2;
 	if (options->num_identity_files == 0) {
 		if (options->protocol & SSH_PROTO_1) {
 			len = 2 + strlen(_PATH_SSH_CLIENT_IDENTITY) + 1;
 			options->identity_files[options->num_identity_files] =
 			    xmalloc(len);
diff --git a/openssh-5.1p1/readconf.h b/openssh-5.1p1/readconf.h
--- a/openssh-5.1p1/readconf.h
+++ b/openssh-5.1p1/readconf.h
@@ -66,16 +66,17 @@ typedef struct {
 	int     connection_timeout;	/* Max time (seconds) before
 					 * 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. */
+	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 */
 
 	char   *system_hostfile;/* Path for /etc/ssh/ssh_known_hosts. */
diff --git a/openssh-5.1p1/servconf.c b/openssh-5.1p1/servconf.c
--- a/openssh-5.1p1/servconf.c
+++ b/openssh-5.1p1/servconf.c
@@ -36,16 +36,20 @@
 #include "misc.h"
 #include "cipher.h"
 #include "key.h"
 #include "kex.h"
 #include "mac.h"
 #include "match.h"
 #include "channels.h"
 #include "groupaccess.h"
+#include "dh.h"
+
+/* import from dh.c */
+extern int dh_grp_min;
 
 static void add_listen_addr(ServerOptions *, char *, u_short);
 static void add_one_listen_addr(ServerOptions *, char *, u_short);
 
 /* Use of privilege separation or not */
 extern int use_privsep;
 extern Buffer cfg;
 
@@ -104,16 +108,17 @@ initialize_server_options(ServerOptions 
 	options->allow_tcp_forwarding = -1;
 	options->allow_agent_forwarding = -1;
 	options->num_allow_users = 0;
 	options->num_deny_users = 0;
 	options->num_allow_groups = 0;
 	options->num_deny_groups = 0;
 	options->ciphers = NULL;
 	options->macs = NULL;
+	options->kex_dhmin = -1;
 	options->protocol = SSH_PROTO_UNKNOWN;
 	options->gateway_ports = -1;
 	options->num_subsystems = 0;
 	options->max_startups_begin = -1;
 	options->max_startups_rate = -1;
 	options->max_startups = -1;
 	options->max_authtries = -1;
 	options->max_sessions = -1;
@@ -132,16 +137,23 @@ initialize_server_options(ServerOptions 
 
 void
 fill_default_server_options(ServerOptions *options)
 {
 	/* Portable-specific options */
 	if (options->use_pam == -1)
 		options->use_pam = 0;
 
+	if (options->kex_dhmin == -1)
+		options->kex_dhmin = DH_GRP_MIN_RFC;
+	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;
 	/* Standard Options */
 	if (options->protocol == SSH_PROTO_UNKNOWN)
 		options->protocol = SSH_PROTO_1|SSH_PROTO_2;
 	if (options->num_host_key_files == 0) {
 		/* fill default hostkeys for protocols */
 		if (options->protocol & SSH_PROTO_1)
 			options->host_key_files[options->num_host_key_files++] =
 			    _PATH_HOST_KEY_FILE;
@@ -300,16 +312,17 @@ typedef enum {
 	sGatewayPorts, sPubkeyAuthentication, sXAuthLocation, sSubsystem,
 	sMaxStartups, sMaxAuthTries, sMaxSessions,
 	sBanner, sUseDNS, sHostbasedAuthentication,
 	sHostbasedUsesNameFromPacketOnly, sClientAliveInterval,
 	sClientAliveCountMax, sAuthorizedKeysFile, sAuthorizedKeysFile2,
 	sGssAuthentication, sGssCleanupCreds, sAcceptEnv, sPermitTunnel, sGssEnableMITM,
 	sMatch, sPermitOpen, sForceCommand, sChrootDirectory,
 	sUsePrivilegeSeparation, sAllowAgentForwarding,
+	sKexDHMin,
 	sDeprecated, sUnsupported
 } ServerOpCodes;
 
 #define SSHCFG_GLOBAL	0x01	/* allowed in main section of sshd_config */
 #define SSHCFG_MATCH	0x02	/* allowed inside a Match section */
 #define SSHCFG_ALL	(SSHCFG_GLOBAL|SSHCFG_MATCH)
 
 /* Textual representation of the tokens. */
@@ -415,16 +428,17 @@ static struct {
 	{ "authorizedkeysfile2", sAuthorizedKeysFile2, SSHCFG_GLOBAL },
 	{ "useprivilegeseparation", sUsePrivilegeSeparation, SSHCFG_GLOBAL },
 	{ "acceptenv", sAcceptEnv, SSHCFG_GLOBAL },
 	{ "permittunnel", sPermitTunnel, SSHCFG_GLOBAL },
  	{ "match", sMatch, SSHCFG_ALL },
 	{ "permitopen", sPermitOpen, SSHCFG_ALL },
 	{ "forcecommand", sForceCommand, SSHCFG_ALL },
 	{ "chrootdirectory", sChrootDirectory, SSHCFG_ALL },
+	{ "kexdhmin", sKexDHMin },
 	{ NULL, sBadOption, 0 }
 };
 
 static struct {
 	int val;
 	char *text;
 } tunmode_desc[] = {
 	{ SSH_TUNMODE_NO, "no" },
@@ -1085,16 +1099,20 @@ process_server_config_line(ServerOptions
 			fatal("%s line %d: Missing argument.", filename, linenum);
 		if (!mac_valid(arg))
 			fatal("%s line %d: Bad SSH2 mac spec '%s'.",
 			    filename, linenum, arg ? arg : "<NONE>");
 		if (options->macs == NULL)
 			options->macs = xstrdup(arg);
 		break;
 
+	case sKexDHMin:
+		intptr = &options->kex_dhmin;
+		goto parse_int;
+
 	case sProtocol:
 		intptr = &options->protocol;
 		arg = strdelim(&cp);
 		if (!arg || *arg == '\0')
 			fatal("%s line %d: Missing argument.", filename, linenum);
 		value = proto_spec(arg);
 		if (value == SSH_PROTO_UNKNOWN)
 			fatal("%s line %d: Bad protocol spec '%s'.",
@@ -1555,16 +1573,17 @@ dump_config(ServerOptions *o)
 	/* integer arguments */
 	dump_cfg_int(sServerKeyBits, o->server_key_bits);
 	dump_cfg_int(sLoginGraceTime, o->login_grace_time);
 	dump_cfg_int(sKeyRegenerationTime, o->key_regeneration_time);
 	dump_cfg_int(sX11DisplayOffset, o->x11_display_offset);
 	dump_cfg_int(sMaxAuthTries, o->max_authtries);
 	dump_cfg_int(sClientAliveInterval, o->client_alive_interval);
 	dump_cfg_int(sClientAliveCountMax, o->client_alive_count_max);
+	dump_cfg_int(sKexDHMin, o->kex_dhmin);
 
 	/* formatted integer arguments */
 	dump_cfg_fmtint(sPermitRootLogin, o->permit_root_login);
 	dump_cfg_fmtint(sIgnoreRhosts, o->ignore_rhosts);
 	dump_cfg_fmtint(sIgnoreUserKnownHosts, o->ignore_user_known_hosts);
 	dump_cfg_fmtint(sRhostsRSAAuthentication, o->rhosts_rsa_authentication);
 	dump_cfg_fmtint(sHostbasedAuthentication, o->hostbased_authentication);
 	dump_cfg_fmtint(sHostbasedUsesNameFromPacketOnly,
diff --git a/openssh-5.1p1/servconf.h b/openssh-5.1p1/servconf.h
--- a/openssh-5.1p1/servconf.h
+++ b/openssh-5.1p1/servconf.h
@@ -64,16 +64,17 @@ typedef struct {
 	int     x11_display_offset;	/* What DISPLAY number to start
 					 * searching at */
 	int     x11_use_localhost;	/* If true, use localhost for fake X11 server. */
 	char   *xauth_location;	/* Location of xauth program */
 	int     strict_modes;	/* If true, require string home dir modes. */
 	int     tcp_keep_alive;	/* If true, set SO_KEEPALIVE. */
 	char   *ciphers;	/* Supported SSH2 ciphers. */
 	char   *macs;		/* Supported SSH2 macs. */
+	int     kex_dhmin;	/* minimum bit length of the DH group parameter */
 	int	protocol;	/* Supported protocol versions. */
 	int     gateway_ports;	/* If true, allow remote connects to forwarded ports. */
 	SyslogFacility log_facility;	/* Facility for system logging. */
 	LogLevel log_level;	/* Level for system logging. */
 	int     rhosts_rsa_authentication;	/* If true, permit rhosts RSA
 						 * authentication. */
 	int     hostbased_authentication;	/* If true, permit ssh2 hostbased auth */
 	int     hostbased_uses_name_from_packet_only; /* experimental */
diff --git a/openssh-5.1p1/ssh_config b/openssh-5.1p1/ssh_config
--- a/openssh-5.1p1/ssh_config
+++ b/openssh-5.1p1/ssh_config
@@ -12,16 +12,21 @@
 # Any configuration value is only changed the first time it is set.
 # Thus, host-specific definitions should be at the beginning of the
 # configuration file, and defaults at the end.
 
 # Site-wide defaults for some commonly used options.  For a comprehensive
 # list of available options, their meanings and defaults, please see the
 # ssh_config(5) man page.
 
+# Minimum accepted size of the DH parameter p. By default this is set to 1024
+# to maintain compatibility with RFC4419, but should be set higher.
+# Upstream default is identical to setting this to 2048.
+#KexDHMin 1024
+
 Host *
 #   ForwardAgent no
 #   ForwardX11 no
 
 # If you do not trust your remote host (or its administrator), you
 # should not forward X11 connections to your local X11-display for
 # security reasons: Someone stealing the authentification data on the
 # remote side (the "spoofed" X-server by the remote sshd) can read your
diff --git a/openssh-5.1p1/ssh_config.0 b/openssh-5.1p1/ssh_config.0
--- a/openssh-5.1p1/ssh_config.0
+++ b/openssh-5.1p1/ssh_config.0
@@ -334,16 +334,33 @@ DESCRIPTION
      KbdInteractiveDevices
              Specifies the list of methods to use in keyboard-interactive au-
              thentication.  Multiple method names must be comma-separated.
              The default is to use the server specified list.  The methods
              available vary depending on what the server supports.  For an
              OpenSSH server, it may be zero or more of: ``bsdauth'', ``pam'',
              and ``skey''.
 
+     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 while by default this option is set to 1024 to maintain
+             maximum backward compatibility, using it 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 (broken)
+             counterparty.
+
      LocalCommand
              Specifies a command to execute on the local machine after suc-
              cessfully 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:
              `%d' (local user's home directory), `%h' (remote host name), `%l'
              (local host name), `%n' (host name as provided on the command
              line), `%p' (remote port), `%r' (remote user name) or `%u' (local
diff --git a/openssh-5.1p1/ssh_config.5 b/openssh-5.1p1/ssh_config.5
--- a/openssh-5.1p1/ssh_config.5
+++ b/openssh-5.1p1/ssh_config.5
@@ -591,16 +591,32 @@ Multiple method names must be comma-sepa
 The default is to use the server specified list.
 The methods available vary depending on what the server supports.
 For an OpenSSH server,
 it may be zero or more of:
 .Dq bsdauth ,
 .Dq pam ,
 and
 .Dq skey .
+.It Cm KexDHMin
+Specifies the minimum accepted bit length of the DH group
+parameter p.
+.Pp
+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.
+.Pp
+Note, that while by default this option is set to 1024 to maintain
+maximum backward compatibility, using it 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 (broken)
+counterparty.
 .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),
diff --git a/openssh-5.1p1/sshd_config b/openssh-5.1p1/sshd_config
--- a/openssh-5.1p1/sshd_config
+++ b/openssh-5.1p1/sshd_config
@@ -21,16 +21,21 @@
 Protocol 2
 
 # HostKey for protocol version 1
 #HostKey /etc/ssh/ssh_host_key
 # HostKeys for protocol version 2
 #HostKey /etc/ssh/ssh_host_rsa_key
 #HostKey /etc/ssh/ssh_host_dsa_key
 
+# Minimum accepted size of the DH parameter p. By default this is set to 1024
+# to maintain compatibility with RFC4419, but should be set higher.
+# Upstream default is identical to setting this to 2048.
+#KexDHMin 1024
+
 # Lifetime and size of ephemeral version 1 server key
 #KeyRegenerationInterval 1h
 #ServerKeyBits 1024
 
 # Logging
 # obsoletes QuietMode and FascistLogging
 #SyslogFacility AUTH
 #LogLevel INFO
diff --git a/openssh-5.1p1/sshd_config.0 b/openssh-5.1p1/sshd_config.0
--- a/openssh-5.1p1/sshd_config.0
+++ b/openssh-5.1p1/sshd_config.0
@@ -269,16 +269,33 @@ DESCRIPTION
              If password authentication through Kerberos fails then the pass-
              word will be validated via any additional local mechanism such as
              /etc/passwd.  The default is ``yes''.
 
      KerberosTicketCleanup
              Specifies whether to automatically destroy the user's ticket
              cache file on logout.  The default is ``yes''.
 
+     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 server to accept parameters shorter
+             than the current minimum, down to the RFC specified 1024 bits.
+             Using this option may be needed when some of the connecting
+             clients only know short DH group parameters.
+
+             Note, that while by default this option is set to 1024 to maintain
+             maximum backward compatibility, using it 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 (broken)
+             counterparty.
+
      KeyRegenerationInterval
              In protocol version 1, the ephemeral server key is automatically
              regenerated after this many seconds (if it has been used).  The
              purpose of regeneration is to prevent decrypting captured ses-
              sions by later breaking into the machine and stealing the keys.
              The key is never stored anywhere.  If the value is 0, the key is
              never regenerated.  The default is 3600 (seconds).
 
diff --git a/openssh-5.1p1/sshd_config.5 b/openssh-5.1p1/sshd_config.5
--- a/openssh-5.1p1/sshd_config.5
+++ b/openssh-5.1p1/sshd_config.5
@@ -470,16 +470,32 @@ such as
 .Pa /etc/passwd .
 The default is
 .Dq yes .
 .It Cm KerberosTicketCleanup
 Specifies whether to automatically destroy the user's ticket cache
 file on logout.
 The default is
 .Dq yes .
+.It Cm KexDHMin
+Specifies the minimum accepted bit length of the DH group
+parameter p.
+.Pp
+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 server to accept parameters shorter
+than the current minimum, down to the RFC specified 1024 bits.
+Using this option may be needed when some of the connecting
+clients only know short DH group parameters.
+.Pp
+Note, that while by default this option is set to 1024 to maintain
+maximum backward compatibility, using it 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 (broken)
+counterparty.
 .It Cm KeyRegenerationInterval
 In protocol version 1, the ephemeral server key is automatically regenerated
 after this many seconds (if it has been used).
 The purpose of regeneration is to prevent
 decrypting captured sessions by later breaking into the machine and
 stealing the keys.
 The key is never stored anywhere.
 If the value is 0, the key is never regenerated.
