jonathancammack / rpms / openssh

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