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 9fd698
index 2ab222ed6..4e9437912 100644
Dmitry Belyavskiy 9fd698
--- a/auth2-hostbased.c
Dmitry Belyavskiy 9fd698
+++ b/auth2-hostbased.c
Dmitry Belyavskiy 9fd698
@@ -118,6 +118,10 @@ 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 9fd698
+	if ((r = sshkey_check_rsa_length(key, options.rsa_min_size)) != 0) {
Dmitry Belyavskiy 9fd698
+		logit("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 9fd698
index daa756a01..68e7dea1f 100644
Dmitry Belyavskiy 9fd698
--- a/auth2-pubkey.c
Dmitry Belyavskiy 9fd698
+++ b/auth2-pubkey.c
Dmitry Belyavskiy 9fd698
@@ -172,6 +172,10 @@ 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 9fd698
+	if ((r = sshkey_check_rsa_length(key, options.rsa_min_size)) != 0) {
Dmitry Belyavskiy 9fd698
+		logit("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 9fd698
index 5b5afa8e3..5e17abd41 100644
Dmitry Belyavskiy 9fd698
--- a/readconf.c
Dmitry Belyavskiy 9fd698
+++ b/readconf.c
Dmitry Belyavskiy 9fd698
@@ -160,7 +160,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 9fd698
+	oSecurityKeyProvider, oKnownHostsCommand, oRSAMinSize,
Dmitry Belyavskiy 9fd698
 	oIgnore, oIgnoredUnknownOption, oDeprecated, oUnsupported
Dmitry Belyavskiy 9fd698
 } OpCodes;
Dmitry Belyavskiy 9fd698
 
Dmitry Belyavskiy 9fd698
@@ -306,6 +306,7 @@ static struct {
Dmitry Belyavskiy 9fd698
 	{ "proxyjump", oProxyJump },
Dmitry Belyavskiy 9fd698
 	{ "securitykeyprovider", oSecurityKeyProvider },
Dmitry Belyavskiy 9fd698
 	{ "knownhostscommand", oKnownHostsCommand },
Dmitry Belyavskiy 9fd698
+	{ "rsaminsize", oRSAMinSize },
Dmitry Belyavskiy 9fd698
 
Dmitry Belyavskiy 9fd698
 	{ NULL, oBadOption }
Dmitry Belyavskiy 9fd698
 };
Dmitry Belyavskiy 9fd698
@@ -2162,6 +2163,10 @@ process_config_line_depth(Options *options, struct passwd *pw, const char *host,
Dmitry Belyavskiy 9fd698
 			*charptr = xstrdup(arg);
Dmitry Belyavskiy 9fd698
 		break;
Dmitry Belyavskiy 9fd698
 
Dmitry Belyavskiy 9fd698
+	case oRSAMinSize:
Dmitry Belyavskiy 9fd698
+		intptr = &options->rsa_min_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 9fd698
@@ -2409,6 +2414,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 9fd698
+	options->rsa_min_size = -1;
Dmitry Belyavskiy 9fd698
 }
Dmitry Belyavskiy 9fd698
 
Dmitry Belyavskiy 9fd698
 /*
Dmitry Belyavskiy 9fd698
@@ -2598,6 +2604,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 9fd698
+	if (options->rsa_min_size == -1)
Dmitry Belyavskiy 9fd698
+		options->rsa_min_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 9fd698
@@ -3287,6 +3295,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 9fd698
+	dump_cfg_int(oRSAMinSize, o->rsa_min_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 9fd698
index f647bd42a..29db353ab 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 9fd698
+	int	rsa_min_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 9fd698
index f7317a5cb..362ff5b67 100644
Dmitry Belyavskiy 9fd698
--- a/servconf.c
Dmitry Belyavskiy 9fd698
+++ b/servconf.c
Dmitry Belyavskiy 9fd698
@@ -177,6 +177,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 9fd698
+	options->rsa_min_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 9fd698
@@ -416,6 +417,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 9fd698
+	if (options->rsa_min_size == -1)
Dmitry Belyavskiy 9fd698
+		options->rsa_min_size = SSH_RSA_MINIMUM_MODULUS_SIZE;
Dmitry Belyavskiy 9fd698
 
Dmitry Belyavskiy 9fd698
 	assemble_algorithms(options);
Dmitry Belyavskiy 9fd698
 
Dmitry Belyavskiy 9fd698
@@ -489,6 +492,7 @@ typedef enum {
Dmitry Belyavskiy 9fd698
 	sStreamLocalBindMask, sStreamLocalBindUnlink,
Dmitry Belyavskiy 9fd698
 	sAllowStreamLocalForwarding, sFingerprintHash, sDisableForwarding,
Dmitry Belyavskiy 9fd698
 	sExposeAuthInfo, sRDomain, sPubkeyAuthOptions, sSecurityKeyProvider,
Dmitry Belyavskiy 9fd698
+	sRSAMinSize,
Dmitry Belyavskiy 9fd698
 	sDeprecated, sIgnore, sUnsupported
Dmitry Belyavskiy 9fd698
 } ServerOpCodes;
Dmitry Belyavskiy 9fd698
 
Dmitry Belyavskiy 9fd698
@@ -632,6 +636,7 @@ 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 9fd698
+	{ "rsaminsize", sRSAMinSize, SSHCFG_ALL },
Dmitry Belyavskiy 9fd698
 	{ NULL, sBadOption, 0 }
Dmitry Belyavskiy 9fd698
 };
Dmitry Belyavskiy 9fd698
 
Dmitry Belyavskiy 9fd698
@@ -2377,6 +2382,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 9fd698
+	case sRSAMinSize:
Dmitry Belyavskiy 9fd698
+		intptr = &options->rsa_min_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 9fd698
@@ -2549,6 +2558,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 9fd698
+	M_CP_INTOPT(rsa_min_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 9fd698
@@ -2810,6 +2820,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 9fd698
+	dump_cfg_int(sRSAMinSize, o->rsa_min_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 9fd698
index 115db1e79..2e3486906 100644
Dmitry Belyavskiy 9fd698
--- a/servconf.h
Dmitry Belyavskiy 9fd698
+++ b/servconf.h
Dmitry Belyavskiy 9fd698
@@ -227,6 +227,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 9fd698
+	int	rsa_min_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 9fd698
index a926cc007..cd13fb879 100644
Dmitry Belyavskiy 9fd698
--- a/ssh.c
Dmitry Belyavskiy 9fd698
+++ b/ssh.c
Dmitry Belyavskiy 9fd698
@@ -500,14 +500,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 9fd698
+		    options.rsa_min_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 9fd698
@@ -1557,12 +1565,13 @@ 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 9fd698
 } while (0)
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 9fd698
 } while (0)
Dmitry Belyavskiy 9fd698
 
Dmitry Belyavskiy 9fd698
 		if (options.hostbased_authentication == 1) {
Dmitry Belyavskiy 9fd698
@@ -2244,7 +2253,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 9fd698
@@ -2263,7 +2272,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 9fd698
@@ -2294,7 +2303,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 9fd698
index 67f8e0309..d050c1656 100644
Dmitry Belyavskiy 9fd698
--- a/sshconnect2.c
Dmitry Belyavskiy 9fd698
+++ b/sshconnect2.c
Dmitry Belyavskiy 9fd698
@@ -91,6 +91,10 @@ 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 9fd698
+	if ((r = sshkey_check_rsa_length(hostkey, options.rsa_min_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 9fd698
@@ -1747,6 +1751,12 @@ pubkey_prepare(struct ssh *ssh, Authctxt *authctxt)
Dmitry Belyavskiy 9fd698
		close(agent_fd);
Dmitry Belyavskiy 9fd698
	} else {
Dmitry Belyavskiy 9fd698
 		for (j = 0; j < idlist->nkeys; j++) {
Dmitry Belyavskiy 9fd698
+			if ((r = sshkey_check_rsa_length(idlist->keys[j],
Dmitry Belyavskiy 9fd698
+			    options.rsa_min_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 9fd698
index d26eb86ae..5f36905a1 100644
Dmitry Belyavskiy 9fd698
--- a/sshd.c
Dmitry Belyavskiy 9fd698
+++ b/sshd.c
Dmitry Belyavskiy 9fd698
@@ -1746,6 +1746,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 9fd698
+		    options.rsa_min_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 9fd698
index 47864e6d8..8bad6bd99 100644
Dmitry Belyavskiy 9fd698
--- a/sshkey.c
Dmitry Belyavskiy 9fd698
+++ b/sshkey.c
Dmitry Belyavskiy 9fd698
@@ -2319,18 +2319,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 9fd698
@@ -2391,7 +2397,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 9fd698
@@ -3580,7 +3586,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 9fd698
@@ -4566,7 +4572,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 9fd698
index 125cadb64..52e879456 100644
Dmitry Belyavskiy 9fd698
--- a/sshkey.h
Dmitry Belyavskiy 9fd698
+++ b/sshkey.h
Dmitry Belyavskiy 9fd698
@@ -267,6 +267,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 9fd698
index b4956aec..b1a40ebd 100644
Dmitry Belyavskiy 9fd698
--- a/ssh.1
Dmitry Belyavskiy 9fd698
+++ b/ssh.1
Dmitry Belyavskiy 9fd698
@@ -554,6 +554,7 @@ For full details of the options listed below, and their possible values, see
Dmitry Belyavskiy 9fd698
 .It LogLevel
Dmitry Belyavskiy 9fd698
 .It MACs
Dmitry Belyavskiy 9fd698
 .It Match
Dmitry Belyavskiy 9fd698
+.It RSAMinSize
Dmitry Belyavskiy 9fd698
 .It NoHostAuthenticationForLocalhost
Dmitry Belyavskiy 9fd698
 .It NumberOfPasswordPrompts
Dmitry Belyavskiy 9fd698
 .It PasswordAuthentication
Dmitry Belyavskiy 9fd698
diff --git a/ssh_config.5 b/ssh_config.5
Dmitry Belyavskiy 9fd698
index 24a46460..68771e4b 100644
Dmitry Belyavskiy 9fd698
--- a/ssh_config.5
Dmitry Belyavskiy 9fd698
+++ b/ssh_config.5
Dmitry Belyavskiy 9fd698
@@ -1322,6 +1322,10 @@ The argument to this keyword must be
Dmitry Belyavskiy 9fd698
 or
Dmitry Belyavskiy 9fd698
 .Cm no
Dmitry Belyavskiy 9fd698
 (the default).
Dmitry Belyavskiy 9fd698
+.It Cm RSAMinSize
Dmitry Belyavskiy 9fd698
+Provides a minimal bits requirement for RSA keys when used for signature and
Dmitry Belyavskiy 9fd698
+verification but not for the key generation. The default value is 1024 and
Dmitry Belyavskiy 9fd698
+can't be reduced.
Dmitry Belyavskiy 9fd698
 .It Cm NumberOfPasswordPrompts
Dmitry Belyavskiy 9fd698
 Specifies the number of password prompts before giving up.
Dmitry Belyavskiy 9fd698
 The argument to this keyword must be an integer.
Dmitry Belyavskiy 9fd698
diff --git a/sshd_config.5 b/sshd_config.5
Dmitry Belyavskiy 9fd698
index 867a747d..e08811ca 100644
Dmitry Belyavskiy 9fd698
--- a/sshd_config.5
Dmitry Belyavskiy 9fd698
+++ b/sshd_config.5
Dmitry Belyavskiy 9fd698
@@ -1266,6 +1266,10 @@ will refuse connection attempts with a probability of rate/100 (30%)
Dmitry Belyavskiy 9fd698
 if there are currently start (10) unauthenticated connections.
Dmitry Belyavskiy 9fd698
 The probability increases linearly and all connection attempts
Dmitry Belyavskiy 9fd698
 are refused if the number of unauthenticated connections reaches full (60).
Dmitry Belyavskiy 9fd698
+.It Cm RSAMinSize
Dmitry Belyavskiy 9fd698
+Provides a minimal bits requirement for RSA keys when used for signature and
Dmitry Belyavskiy 9fd698
+verification but not for the key generation. The default value is 1024 and
Dmitry Belyavskiy 9fd698
+can't be reduced.
Dmitry Belyavskiy 9fd698
 .It Cm ModuliFile
Dmitry Belyavskiy 9fd698
 Specifies the
Dmitry Belyavskiy 9fd698
 .Xr moduli 5
Dmitry Belyavskiy 9fd698
diff --git a/sshkey.h b/sshkey.h
Dmitry Belyavskiy 9fd698
index 094815e0..2bb8cb90 100644
Dmitry Belyavskiy 9fd698
--- a/sshkey.h
Dmitry Belyavskiy 9fd698
+++ b/sshkey.h
Dmitry Belyavskiy 9fd698
@@ -286,6 +286,8 @@ int	 sshkey_private_serialize_maxsign(struct sshkey *key,
Dmitry Belyavskiy 9fd698
 
Dmitry Belyavskiy 9fd698
 void	 sshkey_sig_details_free(struct sshkey_sig_details *);
Dmitry Belyavskiy 9fd698
 
Dmitry Belyavskiy 9fd698
+int ssh_set_rsa_min_bits(int minbits);
Dmitry Belyavskiy 9fd698
+
Dmitry Belyavskiy 9fd698
 #ifdef SSHKEY_INTERNAL
Dmitry Belyavskiy 9fd698
 int ssh_rsa_sign(const struct sshkey *key,
Dmitry Belyavskiy 9fd698
     u_char **sigp, size_t *lenp, const u_char *data, size_t datalen,