vishalmishra434 / rpms / openssh

Forked from rpms/openssh a month ago
Clone
Dmitry Belyavskiy 9fd698
diff --git a/auth2-hostbased.c b/auth2-hostbased.c
Dmitry Belyavskiy aa843e
index 36b9d2f5..6b517db4 100644
Dmitry Belyavskiy 9fd698
--- a/auth2-hostbased.c
Dmitry Belyavskiy 9fd698
+++ b/auth2-hostbased.c
Dmitry Belyavskiy aa843e
@@ -119,6 +119,11 @@ userauth_hostbased(struct ssh *ssh, const char *method)
Dmitry Belyavskiy 9fd698
 		    "(null)" : key->cert->signature_type);
Dmitry Belyavskiy 9fd698
 		goto done;
Dmitry Belyavskiy 9fd698
 	}
Dmitry Belyavskiy aa843e
+	if ((r = sshkey_check_rsa_length(key,
Dmitry Belyavskiy aa843e
+	    options.required_rsa_size)) != 0) {
Dmitry Belyavskiy aa843e
+		logit_r(r, "refusing %s key", sshkey_type(key));
Dmitry Belyavskiy 9fd698
+		goto done;
Dmitry Belyavskiy 9fd698
+	}
Dmitry Belyavskiy 9fd698
 
Dmitry Belyavskiy 9fd698
 	if (!authctxt->valid || authctxt->user == NULL) {
Dmitry Belyavskiy 9fd698
 		debug2_f("disabled because of invalid user");
Dmitry Belyavskiy 9fd698
diff --git a/auth2-pubkey.c b/auth2-pubkey.c
Dmitry Belyavskiy aa843e
index 962fd342..5d59febc 100644
Dmitry Belyavskiy 9fd698
--- a/auth2-pubkey.c
Dmitry Belyavskiy 9fd698
+++ b/auth2-pubkey.c
Dmitry Belyavskiy aa843e
@@ -175,6 +175,11 @@ userauth_pubkey(struct ssh *ssh, const char *method)
Dmitry Belyavskiy 9fd698
 		    "(null)" : key->cert->signature_type);
Dmitry Belyavskiy 9fd698
 		goto done;
Dmitry Belyavskiy 9fd698
 	}
Dmitry Belyavskiy aa843e
+	if ((r = sshkey_check_rsa_length(key,
Dmitry Belyavskiy aa843e
+	    options.required_rsa_size)) != 0) {
Dmitry Belyavskiy aa843e
+		logit_r(r, "refusing %s key", sshkey_type(key));
Dmitry Belyavskiy 9fd698
+		goto done;
Dmitry Belyavskiy 9fd698
+	}
Dmitry Belyavskiy 9fd698
 	key_s = format_key(key);
Dmitry Belyavskiy 9fd698
 	if (sshkey_is_cert(key))
Dmitry Belyavskiy 9fd698
 		ca_s = format_key(key->cert->signature_key);
Dmitry Belyavskiy 9fd698
diff --git a/readconf.c b/readconf.c
Dmitry Belyavskiy aa843e
index 7f26c680..42be690b 100644
Dmitry Belyavskiy 9fd698
--- a/readconf.c
Dmitry Belyavskiy 9fd698
+++ b/readconf.c
Dmitry Belyavskiy aa843e
@@ -174,7 +174,7 @@ typedef enum {
Dmitry Belyavskiy 9fd698
 	oStreamLocalBindMask, oStreamLocalBindUnlink, oRevokedHostKeys,
Dmitry Belyavskiy 9fd698
 	oFingerprintHash, oUpdateHostkeys, oHostbasedAcceptedAlgorithms,
Dmitry Belyavskiy 9fd698
 	oPubkeyAcceptedAlgorithms, oCASignatureAlgorithms, oProxyJump,
Dmitry Belyavskiy 9fd698
-	oSecurityKeyProvider, oKnownHostsCommand,
Dmitry Belyavskiy aa843e
+	oSecurityKeyProvider, oKnownHostsCommand, oRequiredRSASize,
Dmitry Belyavskiy 9fd698
 	oIgnore, oIgnoredUnknownOption, oDeprecated, oUnsupported
Dmitry Belyavskiy 9fd698
 } OpCodes;
Dmitry Belyavskiy 9fd698
 
Dmitry Belyavskiy aa843e
@@ -320,6 +320,8 @@ static struct {
Dmitry Belyavskiy 9fd698
 	{ "proxyjump", oProxyJump },
Dmitry Belyavskiy 9fd698
 	{ "securitykeyprovider", oSecurityKeyProvider },
Dmitry Belyavskiy 9fd698
 	{ "knownhostscommand", oKnownHostsCommand },
Dmitry Belyavskiy aa843e
+	{ "requiredrsasize", oRequiredRSASize },
Dmitry Belyavskiy aa843e
+	{ "rsaminsize", oRequiredRSASize }, /* alias */
Dmitry Belyavskiy 9fd698
 
Dmitry Belyavskiy 9fd698
 	{ NULL, oBadOption }
Dmitry Belyavskiy 9fd698
 };
Dmitry Belyavskiy aa843e
@@ -2176,6 +2177,10 @@ parse_pubkey_algos:
Dmitry Belyavskiy 9fd698
 			*charptr = xstrdup(arg);
Dmitry Belyavskiy 9fd698
 		break;
Dmitry Belyavskiy 9fd698
 
Dmitry Belyavskiy aa843e
+	case oRequiredRSASize:
Dmitry Belyavskiy aa843e
+		intptr = &options->required_rsa_size;
Dmitry Belyavskiy 9fd698
+		goto parse_int;
Dmitry Belyavskiy 9fd698
+
Dmitry Belyavskiy 9fd698
 	case oDeprecated:
Dmitry Belyavskiy 9fd698
 		debug("%s line %d: Deprecated option \"%s\"",
Dmitry Belyavskiy 9fd698
 		    filename, linenum, keyword);
Dmitry Belyavskiy aa843e
@@ -2423,6 +2428,7 @@ initialize_options(Options * options)
Dmitry Belyavskiy 9fd698
 	options->hostbased_accepted_algos = NULL;
Dmitry Belyavskiy 9fd698
 	options->pubkey_accepted_algos = NULL;
Dmitry Belyavskiy 9fd698
 	options->known_hosts_command = NULL;
Dmitry Belyavskiy aa843e
+	options->required_rsa_size = -1;
Dmitry Belyavskiy 9fd698
 }
Dmitry Belyavskiy 9fd698
 
Dmitry Belyavskiy 9fd698
 /*
Dmitry Belyavskiy aa843e
@@ -2619,6 +2625,8 @@ fill_default_options(Options * options)
Dmitry Belyavskiy 9fd698
 	if (options->sk_provider == NULL)
Dmitry Belyavskiy 9fd698
 		options->sk_provider = xstrdup("$SSH_SK_PROVIDER");
Dmitry Belyavskiy 9fd698
 #endif
Dmitry Belyavskiy aa843e
+	if (options->required_rsa_size == -1)
Dmitry Belyavskiy aa843e
+		options->required_rsa_size = SSH_RSA_MINIMUM_MODULUS_SIZE;
Dmitry Belyavskiy 9fd698
 
Dmitry Belyavskiy 9fd698
 	/* Expand KEX name lists */
Dmitry Belyavskiy 9fd698
 	all_cipher = cipher_alg_list(',', 0);
Dmitry Belyavskiy aa843e
@@ -3308,6 +3316,7 @@ dump_client_config(Options *o, const char *host)
Dmitry Belyavskiy 9fd698
 	dump_cfg_int(oNumberOfPasswordPrompts, o->number_of_password_prompts);
Dmitry Belyavskiy 9fd698
 	dump_cfg_int(oServerAliveCountMax, o->server_alive_count_max);
Dmitry Belyavskiy 9fd698
 	dump_cfg_int(oServerAliveInterval, o->server_alive_interval);
Dmitry Belyavskiy aa843e
+	dump_cfg_int(oRequiredRSASize, o->required_rsa_size);
Dmitry Belyavskiy 9fd698
 
Dmitry Belyavskiy 9fd698
 	/* String options */
Dmitry Belyavskiy 9fd698
 	dump_cfg_string(oBindAddress, o->bind_address);
Dmitry Belyavskiy 9fd698
diff --git a/readconf.h b/readconf.h
Dmitry Belyavskiy aa843e
index f647bd42..ffb5ec4f 100644
Dmitry Belyavskiy 9fd698
--- a/readconf.h
Dmitry Belyavskiy 9fd698
+++ b/readconf.h
Dmitry Belyavskiy 9fd698
@@ -176,6 +176,8 @@ typedef struct {
Dmitry Belyavskiy 9fd698
 
Dmitry Belyavskiy 9fd698
 	char   *known_hosts_command;
Dmitry Belyavskiy 9fd698
 
Dmitry Belyavskiy aa843e
+	int	required_rsa_size;	/* minimum size of RSA keys */
Dmitry Belyavskiy 9fd698
+
Dmitry Belyavskiy 9fd698
 	char	*ignored_unknown; /* Pattern list of unknown tokens to ignore */
Dmitry Belyavskiy 9fd698
 }       Options;
Dmitry Belyavskiy 9fd698
 
Dmitry Belyavskiy 9fd698
diff --git a/servconf.c b/servconf.c
Dmitry Belyavskiy aa843e
index 29df0463..423772b1 100644
Dmitry Belyavskiy 9fd698
--- a/servconf.c
Dmitry Belyavskiy 9fd698
+++ b/servconf.c
Dmitry Belyavskiy aa843e
@@ -195,6 +195,7 @@ initialize_server_options(ServerOptions *options)
Dmitry Belyavskiy 9fd698
 	options->fingerprint_hash = -1;
Dmitry Belyavskiy 9fd698
 	options->disable_forwarding = -1;
Dmitry Belyavskiy 9fd698
 	options->expose_userauth_info = -1;
Dmitry Belyavskiy aa843e
+	options->required_rsa_size = -1;
Dmitry Belyavskiy 9fd698
 }
Dmitry Belyavskiy 9fd698
 
Dmitry Belyavskiy 9fd698
 /* Returns 1 if a string option is unset or set to "none" or 0 otherwise. */
Dmitry Belyavskiy aa843e
@@ -441,6 +442,8 @@ fill_default_server_options(ServerOptions *options)
Dmitry Belyavskiy 9fd698
 		options->expose_userauth_info = 0;
Dmitry Belyavskiy 9fd698
 	if (options->sk_provider == NULL)
Dmitry Belyavskiy 9fd698
 		options->sk_provider = xstrdup("internal");
Dmitry Belyavskiy aa843e
+	if (options->required_rsa_size == -1)
Dmitry Belyavskiy aa843e
+		options->required_rsa_size = SSH_RSA_MINIMUM_MODULUS_SIZE;
Dmitry Belyavskiy 9fd698
 
Dmitry Belyavskiy 9fd698
 	assemble_algorithms(options);
Dmitry Belyavskiy 9fd698
 
Dmitry Belyavskiy aa843e
@@ -517,6 +520,7 @@ typedef enum {
Dmitry Belyavskiy 9fd698
 	sStreamLocalBindMask, sStreamLocalBindUnlink,
Dmitry Belyavskiy 9fd698
 	sAllowStreamLocalForwarding, sFingerprintHash, sDisableForwarding,
Dmitry Belyavskiy 9fd698
 	sExposeAuthInfo, sRDomain, sPubkeyAuthOptions, sSecurityKeyProvider,
Dmitry Belyavskiy aa843e
+	sRequiredRSASize,
Dmitry Belyavskiy 9fd698
 	sDeprecated, sIgnore, sUnsupported
Dmitry Belyavskiy 9fd698
 } ServerOpCodes;
Dmitry Belyavskiy 9fd698
 
Dmitry Belyavskiy aa843e
@@ -676,6 +680,8 @@ static struct {
Dmitry Belyavskiy 9fd698
 	{ "rdomain", sRDomain, SSHCFG_ALL },
Dmitry Belyavskiy 9fd698
 	{ "casignaturealgorithms", sCASignatureAlgorithms, SSHCFG_ALL },
Dmitry Belyavskiy 9fd698
 	{ "securitykeyprovider", sSecurityKeyProvider, SSHCFG_GLOBAL },
Dmitry Belyavskiy aa843e
+	{ "requiredrsasize", sRequiredRSASize, SSHCFG_ALL },
Dmitry Belyavskiy aa843e
+	{ "rsaminsize", sRequiredRSASize, SSHCFG_ALL }, /* alias */
Dmitry Belyavskiy 9fd698
 	{ NULL, sBadOption, 0 }
Dmitry Belyavskiy 9fd698
 };
Dmitry Belyavskiy 9fd698
 
Dmitry Belyavskiy aa843e
@@ -2438,6 +2443,10 @@ process_server_config_line_depth(ServerOptions *options, char *line,
Dmitry Belyavskiy 9fd698
 			*charptr = xstrdup(arg);
Dmitry Belyavskiy 9fd698
 		break;
Dmitry Belyavskiy 9fd698
 
Dmitry Belyavskiy aa843e
+	case sRequiredRSASize:
Dmitry Belyavskiy aa843e
+		intptr = &options->required_rsa_size;
Dmitry Belyavskiy 9fd698
+		goto parse_int;
Dmitry Belyavskiy 9fd698
+
Dmitry Belyavskiy 9fd698
 	case sDeprecated:
Dmitry Belyavskiy 9fd698
 	case sIgnore:
Dmitry Belyavskiy 9fd698
 	case sUnsupported:
Dmitry Belyavskiy aa843e
@@ -2610,6 +2619,7 @@ copy_set_server_options(ServerOptions *dst, ServerOptions *src, int preauth)
Dmitry Belyavskiy 9fd698
 	M_CP_INTOPT(rekey_limit);
Dmitry Belyavskiy 9fd698
 	M_CP_INTOPT(rekey_interval);
Dmitry Belyavskiy 9fd698
 	M_CP_INTOPT(log_level);
Dmitry Belyavskiy aa843e
+	M_CP_INTOPT(required_rsa_size);
Dmitry Belyavskiy 9fd698
 
Dmitry Belyavskiy 9fd698
 	/*
Dmitry Belyavskiy 9fd698
 	 * The bind_mask is a mode_t that may be unsigned, so we can't use
Dmitry Belyavskiy aa843e
@@ -2874,6 +2884,7 @@ dump_config(ServerOptions *o)
Dmitry Belyavskiy 9fd698
 	dump_cfg_int(sMaxSessions, o->max_sessions);
Dmitry Belyavskiy 9fd698
 	dump_cfg_int(sClientAliveInterval, o->client_alive_interval);
Dmitry Belyavskiy 9fd698
 	dump_cfg_int(sClientAliveCountMax, o->client_alive_count_max);
Dmitry Belyavskiy aa843e
+	dump_cfg_int(sRequiredRSASize, o->required_rsa_size);
Dmitry Belyavskiy 9fd698
 	dump_cfg_oct(sStreamLocalBindMask, o->fwd_opts.streamlocal_bind_mask);
Dmitry Belyavskiy 9fd698
 
Dmitry Belyavskiy 9fd698
 	/* formatted integer arguments */
Dmitry Belyavskiy 9fd698
diff --git a/servconf.h b/servconf.h
Dmitry Belyavskiy aa843e
index 8a04463e..9346155c 100644
Dmitry Belyavskiy 9fd698
--- a/servconf.h
Dmitry Belyavskiy 9fd698
+++ b/servconf.h
Dmitry Belyavskiy aa843e
@@ -229,6 +229,7 @@ typedef struct {
Dmitry Belyavskiy 9fd698
 	int	expose_userauth_info;
Dmitry Belyavskiy 9fd698
 	u_int64_t timing_secret;
Dmitry Belyavskiy 9fd698
 	char   *sk_provider;
Dmitry Belyavskiy aa843e
+	int	required_rsa_size;	/* minimum size of RSA keys */
Dmitry Belyavskiy 9fd698
 }       ServerOptions;
Dmitry Belyavskiy 9fd698
 
Dmitry Belyavskiy 9fd698
 /* Information about the incoming connection as used by Match */
Dmitry Belyavskiy 9fd698
diff --git a/ssh.c b/ssh.c
Dmitry Belyavskiy aa843e
index 559bf2af..25be53d5 100644
Dmitry Belyavskiy 9fd698
--- a/ssh.c
Dmitry Belyavskiy 9fd698
+++ b/ssh.c
Dmitry Belyavskiy aa843e
@@ -516,14 +516,22 @@ resolve_canonicalize(char **hostp, int port)
Dmitry Belyavskiy 9fd698
 }
Dmitry Belyavskiy 9fd698
 
Dmitry Belyavskiy 9fd698
 /*
Dmitry Belyavskiy 9fd698
- * Check the result of hostkey loading, ignoring some errors and
Dmitry Belyavskiy 9fd698
- * fatal()ing for others.
Dmitry Belyavskiy 9fd698
+ * Check the result of hostkey loading, ignoring some errors and either
Dmitry Belyavskiy 9fd698
+ * discarding the key or fatal()ing for others.
Dmitry Belyavskiy 9fd698
  */
Dmitry Belyavskiy 9fd698
 static void
Dmitry Belyavskiy 9fd698
-check_load(int r, const char *path, const char *message)
Dmitry Belyavskiy 9fd698
+check_load(int r, struct sshkey **k, const char *path, const char *message)
Dmitry Belyavskiy 9fd698
 {
Dmitry Belyavskiy 9fd698
 	switch (r) {
Dmitry Belyavskiy 9fd698
 	case 0:
Dmitry Belyavskiy 9fd698
+		/* Check RSA keys size and discard if undersized */
Dmitry Belyavskiy 9fd698
+		if (k != NULL && *k != NULL &&
Dmitry Belyavskiy 9fd698
+		    (r = sshkey_check_rsa_length(*k,
Dmitry Belyavskiy aa843e
+		    options.required_rsa_size)) != 0) {
Dmitry Belyavskiy 9fd698
+			error_r(r, "load %s \"%s\"", message, path);
Dmitry Belyavskiy 9fd698
+			free(*k);
Dmitry Belyavskiy 9fd698
+			*k = NULL;
Dmitry Belyavskiy 9fd698
+		}
Dmitry Belyavskiy 9fd698
 		break;
Dmitry Belyavskiy 9fd698
 	case SSH_ERR_INTERNAL_ERROR:
Dmitry Belyavskiy 9fd698
 	case SSH_ERR_ALLOC_FAIL:
Dmitry Belyavskiy aa843e
@@ -1578,7 +1586,7 @@ main(int ac, char **av)
Dmitry Belyavskiy 9fd698
 	if ((o) >= sensitive_data.nkeys) \
Dmitry Belyavskiy 9fd698
 		fatal_f("pubkey out of array bounds"); \
Dmitry Belyavskiy 9fd698
 	check_load(sshkey_load_public(p, &(sensitive_data.keys[o]), NULL), \
Dmitry Belyavskiy 9fd698
-	    p, "pubkey"); \
Dmitry Belyavskiy 9fd698
+	    &(sensitive_data.keys[o]), p, "pubkey"); \
Dmitry Belyavskiy aa843e
 	if (sensitive_data.keys[o] != NULL) \
Dmitry Belyavskiy aa843e
 		debug2("hostbased key %d: %s key from \"%s\"", o, \
Dmitry Belyavskiy aa843e
 		    sshkey_ssh_name(sensitive_data.keys[o]), p); \
Dmitry Belyavskiy aa843e
@@ -1586,7 +1594,8 @@ main(int ac, char **av)
Dmitry Belyavskiy 9fd698
 #define L_CERT(p,o) do { \
Dmitry Belyavskiy 9fd698
 	if ((o) >= sensitive_data.nkeys) \
Dmitry Belyavskiy 9fd698
 		fatal_f("cert out of array bounds"); \
Dmitry Belyavskiy 9fd698
-	check_load(sshkey_load_cert(p, &(sensitive_data.keys[o])), p, "cert"); \
Dmitry Belyavskiy 9fd698
+	check_load(sshkey_load_cert(p, &(sensitive_data.keys[o])), \
Dmitry Belyavskiy 9fd698
+	    &(sensitive_data.keys[o]), p, "cert"); \
Dmitry Belyavskiy aa843e
 	if (sensitive_data.keys[o] != NULL) \
Dmitry Belyavskiy aa843e
 		debug2("hostbased key %d: %s cert from \"%s\"", o, \
Dmitry Belyavskiy aa843e
 		    sshkey_ssh_name(sensitive_data.keys[o]), p); \
Dmitry Belyavskiy aa843e
@@ -2265,7 +2274,7 @@ load_public_identity_files(const struct ssh_conn_info *cinfo)
Dmitry Belyavskiy 9fd698
 		filename = default_client_percent_dollar_expand(cp, cinfo);
Dmitry Belyavskiy 9fd698
 		free(cp);
Dmitry Belyavskiy 9fd698
 		check_load(sshkey_load_public(filename, &public, NULL),
Dmitry Belyavskiy 9fd698
-		    filename, "pubkey");
Dmitry Belyavskiy 9fd698
+		    &public, filename, "pubkey");
Dmitry Belyavskiy 9fd698
 		debug("identity file %s type %d", filename,
Dmitry Belyavskiy 9fd698
 		    public ? public->type : -1);
Dmitry Belyavskiy 9fd698
 		free(options.identity_files[i]);
Dmitry Belyavskiy aa843e
@@ -2284,7 +2293,7 @@ load_public_identity_files(const struct ssh_conn_info *cinfo)
Dmitry Belyavskiy 9fd698
 			continue;
Dmitry Belyavskiy 9fd698
 		xasprintf(&cp, "%s-cert", filename);
Dmitry Belyavskiy 9fd698
 		check_load(sshkey_load_public(cp, &public, NULL),
Dmitry Belyavskiy 9fd698
-		    filename, "pubkey");
Dmitry Belyavskiy 9fd698
+		    &public, filename, "pubkey");
Dmitry Belyavskiy 9fd698
 		debug("identity file %s type %d", cp,
Dmitry Belyavskiy 9fd698
 		    public ? public->type : -1);
Dmitry Belyavskiy 9fd698
 		if (public == NULL) {
Dmitry Belyavskiy aa843e
@@ -2315,7 +2324,7 @@ load_public_identity_files(const struct ssh_conn_info *cinfo)
Dmitry Belyavskiy 9fd698
 		free(cp);
Dmitry Belyavskiy 9fd698
 
Dmitry Belyavskiy 9fd698
 		check_load(sshkey_load_public(filename, &public, NULL),
Dmitry Belyavskiy 9fd698
-		    filename, "certificate");
Dmitry Belyavskiy 9fd698
+		    &public, filename, "certificate");
Dmitry Belyavskiy 9fd698
 		debug("certificate file %s type %d", filename,
Dmitry Belyavskiy 9fd698
 		    public ? public->type : -1);
Dmitry Belyavskiy 9fd698
 		free(options.certificate_files[i]);
Dmitry Belyavskiy 9fd698
diff --git a/sshconnect2.c b/sshconnect2.c
Dmitry Belyavskiy aa843e
index f9bd19ea..58fe98db 100644
Dmitry Belyavskiy 9fd698
--- a/sshconnect2.c
Dmitry Belyavskiy 9fd698
+++ b/sshconnect2.c
Dmitry Belyavskiy aa843e
@@ -96,6 +96,11 @@ static const struct ssh_conn_info *xxx_conn_info;
Dmitry Belyavskiy 9fd698
 static int
Dmitry Belyavskiy 9fd698
 verify_host_key_callback(struct sshkey *hostkey, struct ssh *ssh)
Dmitry Belyavskiy 9fd698
 {
Dmitry Belyavskiy 9fd698
+	int r;
Dmitry Belyavskiy 9fd698
+
Dmitry Belyavskiy aa843e
+	if ((r = sshkey_check_rsa_length(hostkey,
Dmitry Belyavskiy aa843e
+	    options.required_rsa_size)) != 0)
Dmitry Belyavskiy 9fd698
+		fatal_r(r, "Bad server host key");
Dmitry Belyavskiy 9fd698
 	if (verify_host_key(xxx_host, xxx_hostaddr, hostkey,
Dmitry Belyavskiy 9fd698
 	    xxx_conn_info) == -1)
Dmitry Belyavskiy 9fd698
 		fatal("Host key verification failed.");
Dmitry Belyavskiy aa843e
@@ -1606,6 +1611,13 @@ load_identity_file(Identity *id)
Dmitry Belyavskiy 483723
 			private = NULL;
Dmitry Belyavskiy 483723
 			quit = 1;
Dmitry Belyavskiy 483723
 		}
Dmitry Belyavskiy aa843e
+		if (!quit && (r = sshkey_check_rsa_length(private,
Dmitry Belyavskiy aa843e
+		    options.required_rsa_size)) != 0) {
Dmitry Belyavskiy 483723
+			debug_fr(r, "Skipping key %s", id->filename);
Dmitry Belyavskiy 483723
+			sshkey_free(private);
Dmitry Belyavskiy 483723
+			private = NULL;
Dmitry Belyavskiy 483723
+			quit = 1;
Dmitry Belyavskiy 483723
+		}
Dmitry Belyavskiy 483723
 		if (!quit && private != NULL && id->agent_fd == -1 &&
Dmitry Belyavskiy 483723
 		    !(id->key && id->isprivate))
Dmitry Belyavskiy 483723
 			maybe_add_key_to_agent(id->filename, private, comment,
Dmitry Belyavskiy aa843e
@@ -1752,6 +1764,12 @@ pubkey_prepare(struct ssh *ssh, Authctxt *authctxt)
Dmitry Belyavskiy aa843e
 	/* list of keys supported by the agent */
Dmitry Belyavskiy aa843e
 	if ((r = get_agent_identities(ssh, &agent_fd, &idlist)) == 0) {
Dmitry Belyavskiy aa843e
 		for (j = 0; j < idlist->nkeys; j++) {
Dmitry Belyavskiy 9fd698
+			if ((r = sshkey_check_rsa_length(idlist->keys[j],
Dmitry Belyavskiy aa843e
+			    options.required_rsa_size)) != 0) {
Dmitry Belyavskiy 9fd698
+				debug_fr(r, "ignoring %s agent key",
Dmitry Belyavskiy 9fd698
+				    sshkey_ssh_name(idlist->keys[j]));
Dmitry Belyavskiy 9fd698
+				continue;
Dmitry Belyavskiy 9fd698
+			}
Dmitry Belyavskiy 9fd698
 			found = 0;
Dmitry Belyavskiy 9fd698
 			TAILQ_FOREACH(id, &files, next) {
Dmitry Belyavskiy 9fd698
 				/*
Dmitry Belyavskiy 9fd698
diff --git a/sshd.c b/sshd.c
Dmitry Belyavskiy aa843e
index 17eee9d8..395ef493 100644
Dmitry Belyavskiy 9fd698
--- a/sshd.c
Dmitry Belyavskiy 9fd698
+++ b/sshd.c
Dmitry Belyavskiy aa843e
@@ -1870,6 +1870,13 @@ main(int ac, char **av)
Dmitry Belyavskiy 9fd698
 				fatal_r(r, "Could not demote key: \"%s\"",
Dmitry Belyavskiy 9fd698
 				    options.host_key_files[i]);
Dmitry Belyavskiy 9fd698
 		}
Dmitry Belyavskiy 9fd698
+		if (pubkey != NULL && (r = sshkey_check_rsa_length(pubkey,
Dmitry Belyavskiy aa843e
+		    options.required_rsa_size)) != 0) {
Dmitry Belyavskiy 9fd698
+			error_fr(r, "Host key %s", options.host_key_files[i]);
Dmitry Belyavskiy 9fd698
+			sshkey_free(pubkey);
Dmitry Belyavskiy 9fd698
+			sshkey_free(key);
Dmitry Belyavskiy 9fd698
+			continue;
Dmitry Belyavskiy 9fd698
+		}
Dmitry Belyavskiy 9fd698
 		sensitive_data.host_keys[i] = key;
Dmitry Belyavskiy 9fd698
 		sensitive_data.host_pubkeys[i] = pubkey;
Dmitry Belyavskiy 9fd698
 
Dmitry Belyavskiy 9fd698
diff --git a/sshkey.c b/sshkey.c
Dmitry Belyavskiy aa843e
index ed2b5dff..77093235 100644
Dmitry Belyavskiy 9fd698
--- a/sshkey.c
Dmitry Belyavskiy 9fd698
+++ b/sshkey.c
Dmitry Belyavskiy aa843e
@@ -2365,18 +2365,24 @@ cert_parse(struct sshbuf *b, struct sshkey *key, struct sshbuf *certbuf)
Dmitry Belyavskiy 9fd698
 	return ret;
Dmitry Belyavskiy 9fd698
 }
Dmitry Belyavskiy 9fd698
 
Dmitry Belyavskiy 9fd698
-#ifdef WITH_OPENSSL
Dmitry Belyavskiy 9fd698
-static int
Dmitry Belyavskiy 9fd698
-check_rsa_length(const RSA *rsa)
Dmitry Belyavskiy 9fd698
+int
Dmitry Belyavskiy 9fd698
+sshkey_check_rsa_length(const struct sshkey *k, int min_size)
Dmitry Belyavskiy 9fd698
 {
Dmitry Belyavskiy 9fd698
+#ifdef WITH_OPENSSL
Dmitry Belyavskiy 9fd698
 	const BIGNUM *rsa_n;
Dmitry Belyavskiy 9fd698
+	int nbits;
Dmitry Belyavskiy 9fd698
 
Dmitry Belyavskiy 9fd698
-	RSA_get0_key(rsa, &rsa_n, NULL, NULL);
Dmitry Belyavskiy 9fd698
-	if (BN_num_bits(rsa_n) < SSH_RSA_MINIMUM_MODULUS_SIZE)
Dmitry Belyavskiy 9fd698
+	if (k == NULL || k->rsa == NULL ||
Dmitry Belyavskiy 9fd698
+	    (k->type != KEY_RSA && k->type != KEY_RSA_CERT))
Dmitry Belyavskiy 9fd698
+		return 0;
Dmitry Belyavskiy 9fd698
+	RSA_get0_key(k->rsa, &rsa_n, NULL, NULL);
Dmitry Belyavskiy 9fd698
+	nbits = BN_num_bits(rsa_n);
Dmitry Belyavskiy 9fd698
+	if (nbits < SSH_RSA_MINIMUM_MODULUS_SIZE ||
Dmitry Belyavskiy 9fd698
+	    (min_size > 0 && nbits < min_size))
Dmitry Belyavskiy 9fd698
 		return SSH_ERR_KEY_LENGTH;
Dmitry Belyavskiy 9fd698
+#endif /* WITH_OPENSSL */
Dmitry Belyavskiy 9fd698
 	return 0;
Dmitry Belyavskiy 9fd698
 }
Dmitry Belyavskiy 9fd698
-#endif
Dmitry Belyavskiy 9fd698
 
Dmitry Belyavskiy 9fd698
 static int
Dmitry Belyavskiy 9fd698
 sshkey_from_blob_internal(struct sshbuf *b, struct sshkey **keyp,
Dmitry Belyavskiy aa843e
@@ -2439,7 +2445,7 @@ sshkey_from_blob_internal(struct sshbuf *b, struct sshkey **keyp,
Dmitry Belyavskiy 9fd698
 			goto out;
Dmitry Belyavskiy 9fd698
 		}
Dmitry Belyavskiy 9fd698
 		rsa_n = rsa_e = NULL; /* transferred */
Dmitry Belyavskiy 9fd698
-		if ((ret = check_rsa_length(key->rsa)) != 0)
Dmitry Belyavskiy 9fd698
+		if ((ret = sshkey_check_rsa_length(key, 0)) != 0)
Dmitry Belyavskiy 9fd698
 			goto out;
Dmitry Belyavskiy 9fd698
 #ifdef DEBUG_PK
Dmitry Belyavskiy 9fd698
 		RSA_print_fp(stderr, key->rsa, 8);
Dmitry Belyavskiy aa843e
@@ -3642,7 +3648,7 @@ sshkey_private_deserialize(struct sshbuf *buf, struct sshkey **kp)
Dmitry Belyavskiy 9fd698
 			goto out;
Dmitry Belyavskiy 9fd698
 		}
Dmitry Belyavskiy 9fd698
 		rsa_p = rsa_q = NULL; /* transferred */
Dmitry Belyavskiy 9fd698
-		if ((r = check_rsa_length(k->rsa)) != 0)
Dmitry Belyavskiy 9fd698
+		if ((r = sshkey_check_rsa_length(k, 0)) != 0)
Dmitry Belyavskiy 9fd698
 			goto out;
Dmitry Belyavskiy 9fd698
 		if ((r = ssh_rsa_complete_crt_parameters(k, rsa_iqmp)) != 0)
Dmitry Belyavskiy 9fd698
 			goto out;
Dmitry Belyavskiy aa843e
@@ -4644,7 +4650,7 @@ sshkey_parse_private_pem_fileblob(struct sshbuf *blob, int type,
Dmitry Belyavskiy 9fd698
 			r = SSH_ERR_LIBCRYPTO_ERROR;
Dmitry Belyavskiy 9fd698
 			goto out;
Dmitry Belyavskiy 9fd698
 		}
Dmitry Belyavskiy 9fd698
-		if ((r = check_rsa_length(prv->rsa)) != 0)
Dmitry Belyavskiy 9fd698
+		if ((r = sshkey_check_rsa_length(prv, 0)) != 0)
Dmitry Belyavskiy 9fd698
 			goto out;
Dmitry Belyavskiy 9fd698
 	} else if (EVP_PKEY_base_id(pk) == EVP_PKEY_DSA &&
Dmitry Belyavskiy 9fd698
 	    (type == KEY_UNSPEC || type == KEY_DSA)) {
Dmitry Belyavskiy 9fd698
diff --git a/sshkey.h b/sshkey.h
Dmitry Belyavskiy aa843e
index 094815e0..be254e6b 100644
Dmitry Belyavskiy 9fd698
--- a/sshkey.h
Dmitry Belyavskiy 9fd698
+++ b/sshkey.h
Dmitry Belyavskiy aa843e
@@ -273,6 +273,7 @@ int	sshkey_parse_private_fileblob_type(struct sshbuf *blob, int type,
Dmitry Belyavskiy 9fd698
 int	sshkey_parse_pubkey_from_private_fileblob_type(struct sshbuf *blob,
Dmitry Belyavskiy 9fd698
     int type, struct sshkey **pubkeyp);
Dmitry Belyavskiy 9fd698
 
Dmitry Belyavskiy 9fd698
+int sshkey_check_rsa_length(const struct sshkey *, int);
Dmitry Belyavskiy 9fd698
 /* XXX should be internal, but used by ssh-keygen */
Dmitry Belyavskiy 9fd698
 int ssh_rsa_complete_crt_parameters(struct sshkey *, const BIGNUM *);
Dmitry Belyavskiy 9fd698
 
Dmitry Belyavskiy 9fd698
diff --git a/ssh.1 b/ssh.1
Dmitry Belyavskiy aa843e
index b4956aec..e255b9b9 100644
Dmitry Belyavskiy 9fd698
--- a/ssh.1
Dmitry Belyavskiy 9fd698
+++ b/ssh.1
Dmitry Belyavskiy aa843e
@@ -571,6 +571,7 @@ For full details of the options listed below, and their possible values, see
Dmitry Belyavskiy aa843e
 .It RemoteCommand
Dmitry Belyavskiy aa843e
 .It RemoteForward
Dmitry Belyavskiy aa843e
 .It RequestTTY
Dmitry Belyavskiy aa843e
+.It RequiredRSASize
Dmitry Belyavskiy aa843e
 .It SendEnv
Dmitry Belyavskiy aa843e
 .It ServerAliveInterval
Dmitry Belyavskiy aa843e
 .It ServerAliveCountMax
Dmitry Belyavskiy 9fd698
diff --git a/ssh_config.5 b/ssh_config.5
Dmitry Belyavskiy aa843e
index 24a46460..d1ede18e 100644
Dmitry Belyavskiy 9fd698
--- a/ssh_config.5
Dmitry Belyavskiy 9fd698
+++ b/ssh_config.5
Dmitry Belyavskiy aa843e
@@ -1634,6 +1634,17 @@ and
Dmitry Belyavskiy aa843e
 .Fl T
Dmitry Belyavskiy aa843e
 flags for
Dmitry Belyavskiy aa843e
 .Xr ssh 1 .
Dmitry Belyavskiy aa843e
+.It Cm RequiredRSASize
Dmitry Belyavskiy aa843e
+Specifies the minimum RSA key size (in bits) that
Dmitry Belyavskiy aa843e
+.Xr ssh 1
Dmitry Belyavskiy aa843e
+will accept.
Dmitry Belyavskiy aa843e
+User authentication keys smaller than this limit will be ignored.
Dmitry Belyavskiy aa843e
+Servers that present host keys smaller than this limit will cause the
Dmitry Belyavskiy aa843e
+connection to be terminated.
Dmitry Belyavskiy aa843e
+The default is
Dmitry Belyavskiy aa843e
+.Cm 1024
Dmitry Belyavskiy aa843e
+bits.
Dmitry Belyavskiy aa843e
+Note that this limit may only be raised from the default.
Dmitry Belyavskiy aa843e
 .It Cm RevokedHostKeys
Dmitry Belyavskiy aa843e
 Specifies revoked host public keys.
Dmitry Belyavskiy aa843e
 Keys listed in this file will be refused for host authentication.
Dmitry Belyavskiy 9fd698
diff --git a/sshd_config.5 b/sshd_config.5
Dmitry Belyavskiy aa843e
index 867a747d..f5a06637 100644
Dmitry Belyavskiy 9fd698
--- a/sshd_config.5
Dmitry Belyavskiy 9fd698
+++ b/sshd_config.5
Dmitry Belyavskiy aa843e
@@ -1596,6 +1596,16 @@ is
Dmitry Belyavskiy aa843e
 .Cm default none ,
Dmitry Belyavskiy aa843e
 which means that rekeying is performed after the cipher's default amount
Dmitry Belyavskiy aa843e
 of data has been sent or received and no time based rekeying is done.
Dmitry Belyavskiy aa843e
+.It Cm RequiredRSASize
Dmitry Belyavskiy aa843e
+Specifies the minimum RSA key size (in bits) that
Dmitry Belyavskiy aa843e
+.Xr sshd 8
Dmitry Belyavskiy aa843e
+will accept.
Dmitry Belyavskiy aa843e
+User and host-based authentication keys smaller than this limit will be
Dmitry Belyavskiy aa843e
+refused.
Dmitry Belyavskiy aa843e
+The default is
Dmitry Belyavskiy aa843e
+.Cm 1024
Dmitry Belyavskiy aa843e
+bits.
Dmitry Belyavskiy aa843e
+Note that this limit may only be raised from the default.
Dmitry Belyavskiy aa843e
 .It Cm RevokedKeys
Dmitry Belyavskiy aa843e
 Specifies revoked public keys file, or
Dmitry Belyavskiy aa843e
 .Cm none