mirror of
https://github.com/PowerShell/openssh-portable.git
synced 2025-07-28 16:24:39 +02:00
upstream: add a RequiredRSASize for checking RSA key length in
ssh(1). User authentication keys that fall beneath this limit will be ignored. If a host presents a host key beneath this limit then the connection will be terminated (unfortunately there are no fallbacks in the protocol for host authentication). feedback deraadt, Dmitry Belyavskiy; ok markus@ OpenBSD-Commit-ID: 430e339b2a79fa9ecc63f2837b06fdd88a7da13a
This commit is contained in:
parent
07d8771bac
commit
54b333d12e
13
readconf.c
13
readconf.c
@ -1,4 +1,4 @@
|
|||||||
/* $OpenBSD: readconf.c,v 1.368 2022/06/03 04:30:47 djm Exp $ */
|
/* $OpenBSD: readconf.c,v 1.369 2022/09/17 10:33:18 djm Exp $ */
|
||||||
/*
|
/*
|
||||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||||
@ -174,7 +174,7 @@ typedef enum {
|
|||||||
oStreamLocalBindMask, oStreamLocalBindUnlink, oRevokedHostKeys,
|
oStreamLocalBindMask, oStreamLocalBindUnlink, oRevokedHostKeys,
|
||||||
oFingerprintHash, oUpdateHostkeys, oHostbasedAcceptedAlgorithms,
|
oFingerprintHash, oUpdateHostkeys, oHostbasedAcceptedAlgorithms,
|
||||||
oPubkeyAcceptedAlgorithms, oCASignatureAlgorithms, oProxyJump,
|
oPubkeyAcceptedAlgorithms, oCASignatureAlgorithms, oProxyJump,
|
||||||
oSecurityKeyProvider, oKnownHostsCommand,
|
oSecurityKeyProvider, oKnownHostsCommand, oRequiredRSASize,
|
||||||
oIgnore, oIgnoredUnknownOption, oDeprecated, oUnsupported
|
oIgnore, oIgnoredUnknownOption, oDeprecated, oUnsupported
|
||||||
} OpCodes;
|
} OpCodes;
|
||||||
|
|
||||||
@ -320,6 +320,7 @@ static struct {
|
|||||||
{ "proxyjump", oProxyJump },
|
{ "proxyjump", oProxyJump },
|
||||||
{ "securitykeyprovider", oSecurityKeyProvider },
|
{ "securitykeyprovider", oSecurityKeyProvider },
|
||||||
{ "knownhostscommand", oKnownHostsCommand },
|
{ "knownhostscommand", oKnownHostsCommand },
|
||||||
|
{ "requiredrsasize", oRequiredRSASize },
|
||||||
|
|
||||||
{ NULL, oBadOption }
|
{ NULL, oBadOption }
|
||||||
};
|
};
|
||||||
@ -2176,6 +2177,10 @@ parse_pubkey_algos:
|
|||||||
*charptr = xstrdup(arg);
|
*charptr = xstrdup(arg);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case oRequiredRSASize:
|
||||||
|
intptr = &options->required_rsa_size;
|
||||||
|
goto parse_int;
|
||||||
|
|
||||||
case oDeprecated:
|
case oDeprecated:
|
||||||
debug("%s line %d: Deprecated option \"%s\"",
|
debug("%s line %d: Deprecated option \"%s\"",
|
||||||
filename, linenum, keyword);
|
filename, linenum, keyword);
|
||||||
@ -2423,6 +2428,7 @@ initialize_options(Options * options)
|
|||||||
options->hostbased_accepted_algos = NULL;
|
options->hostbased_accepted_algos = NULL;
|
||||||
options->pubkey_accepted_algos = NULL;
|
options->pubkey_accepted_algos = NULL;
|
||||||
options->known_hosts_command = NULL;
|
options->known_hosts_command = NULL;
|
||||||
|
options->required_rsa_size = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -2619,6 +2625,8 @@ fill_default_options(Options * options)
|
|||||||
if (options->sk_provider == NULL)
|
if (options->sk_provider == NULL)
|
||||||
options->sk_provider = xstrdup("$SSH_SK_PROVIDER");
|
options->sk_provider = xstrdup("$SSH_SK_PROVIDER");
|
||||||
#endif
|
#endif
|
||||||
|
if (options->required_rsa_size == -1)
|
||||||
|
options->required_rsa_size = SSH_RSA_MINIMUM_MODULUS_SIZE;
|
||||||
|
|
||||||
/* Expand KEX name lists */
|
/* Expand KEX name lists */
|
||||||
all_cipher = cipher_alg_list(',', 0);
|
all_cipher = cipher_alg_list(',', 0);
|
||||||
@ -3308,6 +3316,7 @@ dump_client_config(Options *o, const char *host)
|
|||||||
dump_cfg_int(oNumberOfPasswordPrompts, o->number_of_password_prompts);
|
dump_cfg_int(oNumberOfPasswordPrompts, o->number_of_password_prompts);
|
||||||
dump_cfg_int(oServerAliveCountMax, o->server_alive_count_max);
|
dump_cfg_int(oServerAliveCountMax, o->server_alive_count_max);
|
||||||
dump_cfg_int(oServerAliveInterval, o->server_alive_interval);
|
dump_cfg_int(oServerAliveInterval, o->server_alive_interval);
|
||||||
|
dump_cfg_int(oRequiredRSASize, o->required_rsa_size);
|
||||||
|
|
||||||
/* String options */
|
/* String options */
|
||||||
dump_cfg_string(oBindAddress, o->bind_address);
|
dump_cfg_string(oBindAddress, o->bind_address);
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* $OpenBSD: readconf.h,v 1.147 2022/06/03 04:30:47 djm Exp $ */
|
/* $OpenBSD: readconf.h,v 1.148 2022/09/17 10:33:18 djm Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||||
@ -176,6 +176,8 @@ typedef struct {
|
|||||||
|
|
||||||
char *known_hosts_command;
|
char *known_hosts_command;
|
||||||
|
|
||||||
|
int required_rsa_size; /* minimum size of RSA keys */
|
||||||
|
|
||||||
char *ignored_unknown; /* Pattern list of unknown tokens to ignore */
|
char *ignored_unknown; /* Pattern list of unknown tokens to ignore */
|
||||||
} Options;
|
} Options;
|
||||||
|
|
||||||
|
5
ssh.1
5
ssh.1
@ -33,8 +33,8 @@
|
|||||||
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
.\"
|
.\"
|
||||||
.\" $OpenBSD: ssh.1,v 1.431 2022/05/28 05:57:56 jmc Exp $
|
.\" $OpenBSD: ssh.1,v 1.432 2022/09/17 10:33:18 djm Exp $
|
||||||
.Dd $Mdocdate: May 28 2022 $
|
.Dd $Mdocdate: September 17 2022 $
|
||||||
.Dt SSH 1
|
.Dt SSH 1
|
||||||
.Os
|
.Os
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
@ -571,6 +571,7 @@ For full details of the options listed below, and their possible values, see
|
|||||||
.It RemoteCommand
|
.It RemoteCommand
|
||||||
.It RemoteForward
|
.It RemoteForward
|
||||||
.It RequestTTY
|
.It RequestTTY
|
||||||
|
.It RequiredRSASize
|
||||||
.It SendEnv
|
.It SendEnv
|
||||||
.It ServerAliveInterval
|
.It ServerAliveInterval
|
||||||
.It ServerAliveCountMax
|
.It ServerAliveCountMax
|
||||||
|
27
ssh.c
27
ssh.c
@ -1,4 +1,4 @@
|
|||||||
/* $OpenBSD: ssh.c,v 1.575 2022/07/01 00:36:30 djm Exp $ */
|
/* $OpenBSD: ssh.c,v 1.576 2022/09/17 10:33:18 djm Exp $ */
|
||||||
/*
|
/*
|
||||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||||
@ -516,14 +516,22 @@ resolve_canonicalize(char **hostp, int port)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check the result of hostkey loading, ignoring some errors and
|
* Check the result of hostkey loading, ignoring some errors and either
|
||||||
* fatal()ing for others.
|
* discarding the key or fatal()ing for others.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
check_load(int r, const char *path, const char *message)
|
check_load(int r, struct sshkey **k, const char *path, const char *message)
|
||||||
{
|
{
|
||||||
switch (r) {
|
switch (r) {
|
||||||
case 0:
|
case 0:
|
||||||
|
/* Check RSA keys size and discard if undersized */
|
||||||
|
if (k != NULL && *k != NULL &&
|
||||||
|
(r = sshkey_check_rsa_length(*k,
|
||||||
|
options.required_rsa_size)) != 0) {
|
||||||
|
error_r(r, "load %s \"%s\"", message, path);
|
||||||
|
free(*k);
|
||||||
|
*k = NULL;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case SSH_ERR_INTERNAL_ERROR:
|
case SSH_ERR_INTERNAL_ERROR:
|
||||||
case SSH_ERR_ALLOC_FAIL:
|
case SSH_ERR_ALLOC_FAIL:
|
||||||
@ -1578,7 +1586,7 @@ main(int ac, char **av)
|
|||||||
if ((o) >= sensitive_data.nkeys) \
|
if ((o) >= sensitive_data.nkeys) \
|
||||||
fatal_f("pubkey out of array bounds"); \
|
fatal_f("pubkey out of array bounds"); \
|
||||||
check_load(sshkey_load_public(p, &(sensitive_data.keys[o]), NULL), \
|
check_load(sshkey_load_public(p, &(sensitive_data.keys[o]), NULL), \
|
||||||
p, "pubkey"); \
|
&(sensitive_data.keys[o]), p, "pubkey"); \
|
||||||
if (sensitive_data.keys[o] != NULL) \
|
if (sensitive_data.keys[o] != NULL) \
|
||||||
debug2("hostbased key %d: %s key from \"%s\"", o, \
|
debug2("hostbased key %d: %s key from \"%s\"", o, \
|
||||||
sshkey_ssh_name(sensitive_data.keys[o]), p); \
|
sshkey_ssh_name(sensitive_data.keys[o]), p); \
|
||||||
@ -1586,7 +1594,8 @@ main(int ac, char **av)
|
|||||||
#define L_CERT(p,o) do { \
|
#define L_CERT(p,o) do { \
|
||||||
if ((o) >= sensitive_data.nkeys) \
|
if ((o) >= sensitive_data.nkeys) \
|
||||||
fatal_f("cert out of array bounds"); \
|
fatal_f("cert out of array bounds"); \
|
||||||
check_load(sshkey_load_cert(p, &(sensitive_data.keys[o])), p, "cert"); \
|
check_load(sshkey_load_cert(p, &(sensitive_data.keys[o])), \
|
||||||
|
&(sensitive_data.keys[o]), p, "cert"); \
|
||||||
if (sensitive_data.keys[o] != NULL) \
|
if (sensitive_data.keys[o] != NULL) \
|
||||||
debug2("hostbased key %d: %s cert from \"%s\"", o, \
|
debug2("hostbased key %d: %s cert from \"%s\"", o, \
|
||||||
sshkey_ssh_name(sensitive_data.keys[o]), p); \
|
sshkey_ssh_name(sensitive_data.keys[o]), p); \
|
||||||
@ -2265,7 +2274,7 @@ load_public_identity_files(const struct ssh_conn_info *cinfo)
|
|||||||
filename = default_client_percent_dollar_expand(cp, cinfo);
|
filename = default_client_percent_dollar_expand(cp, cinfo);
|
||||||
free(cp);
|
free(cp);
|
||||||
check_load(sshkey_load_public(filename, &public, NULL),
|
check_load(sshkey_load_public(filename, &public, NULL),
|
||||||
filename, "pubkey");
|
&public, filename, "pubkey");
|
||||||
debug("identity file %s type %d", filename,
|
debug("identity file %s type %d", filename,
|
||||||
public ? public->type : -1);
|
public ? public->type : -1);
|
||||||
free(options.identity_files[i]);
|
free(options.identity_files[i]);
|
||||||
@ -2284,7 +2293,7 @@ load_public_identity_files(const struct ssh_conn_info *cinfo)
|
|||||||
continue;
|
continue;
|
||||||
xasprintf(&cp, "%s-cert", filename);
|
xasprintf(&cp, "%s-cert", filename);
|
||||||
check_load(sshkey_load_public(cp, &public, NULL),
|
check_load(sshkey_load_public(cp, &public, NULL),
|
||||||
filename, "pubkey");
|
&public, filename, "pubkey");
|
||||||
debug("identity file %s type %d", cp,
|
debug("identity file %s type %d", cp,
|
||||||
public ? public->type : -1);
|
public ? public->type : -1);
|
||||||
if (public == NULL) {
|
if (public == NULL) {
|
||||||
@ -2315,7 +2324,7 @@ load_public_identity_files(const struct ssh_conn_info *cinfo)
|
|||||||
free(cp);
|
free(cp);
|
||||||
|
|
||||||
check_load(sshkey_load_public(filename, &public, NULL),
|
check_load(sshkey_load_public(filename, &public, NULL),
|
||||||
filename, "certificate");
|
&public, filename, "certificate");
|
||||||
debug("certificate file %s type %d", filename,
|
debug("certificate file %s type %d", filename,
|
||||||
public ? public->type : -1);
|
public ? public->type : -1);
|
||||||
free(options.certificate_files[i]);
|
free(options.certificate_files[i]);
|
||||||
|
15
ssh_config.5
15
ssh_config.5
@ -33,8 +33,8 @@
|
|||||||
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
.\"
|
.\"
|
||||||
.\" $OpenBSD: ssh_config.5,v 1.373 2022/06/24 04:27:14 djm Exp $
|
.\" $OpenBSD: ssh_config.5,v 1.374 2022/09/17 10:33:18 djm Exp $
|
||||||
.Dd $Mdocdate: June 24 2022 $
|
.Dd $Mdocdate: September 17 2022 $
|
||||||
.Dt SSH_CONFIG 5
|
.Dt SSH_CONFIG 5
|
||||||
.Os
|
.Os
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
@ -1634,6 +1634,17 @@ and
|
|||||||
.Fl T
|
.Fl T
|
||||||
flags for
|
flags for
|
||||||
.Xr ssh 1 .
|
.Xr ssh 1 .
|
||||||
|
.It Cm RequiredRSASize
|
||||||
|
Specifies the minimum RSA key size (in bits) that
|
||||||
|
.Xr ssh 1
|
||||||
|
will accept.
|
||||||
|
User authentication keys smaller than this limit will be ignored.
|
||||||
|
Servers that present host keys smaller than this limit will cause the
|
||||||
|
connection to be terminated.
|
||||||
|
The default is
|
||||||
|
.Cm 1024
|
||||||
|
bits.
|
||||||
|
Note that this limit may only be raised from the default.
|
||||||
.It Cm RevokedHostKeys
|
.It Cm RevokedHostKeys
|
||||||
Specifies revoked host public keys.
|
Specifies revoked host public keys.
|
||||||
Keys listed in this file will be refused for host authentication.
|
Keys listed in this file will be refused for host authentication.
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* $OpenBSD: sshconnect2.c,v 1.360 2022/08/19 06:07:47 djm Exp $ */
|
/* $OpenBSD: sshconnect2.c,v 1.361 2022/09/17 10:33:18 djm Exp $ */
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2000 Markus Friedl. All rights reserved.
|
* Copyright (c) 2000 Markus Friedl. All rights reserved.
|
||||||
* Copyright (c) 2008 Damien Miller. All rights reserved.
|
* Copyright (c) 2008 Damien Miller. All rights reserved.
|
||||||
@ -96,6 +96,11 @@ static const struct ssh_conn_info *xxx_conn_info;
|
|||||||
static int
|
static int
|
||||||
verify_host_key_callback(struct sshkey *hostkey, struct ssh *ssh)
|
verify_host_key_callback(struct sshkey *hostkey, struct ssh *ssh)
|
||||||
{
|
{
|
||||||
|
int r;
|
||||||
|
|
||||||
|
if ((r = sshkey_check_rsa_length(hostkey,
|
||||||
|
options.required_rsa_size)) != 0)
|
||||||
|
fatal_r(r, "Bad server host key");
|
||||||
if (verify_host_key(xxx_host, xxx_hostaddr, hostkey,
|
if (verify_host_key(xxx_host, xxx_hostaddr, hostkey,
|
||||||
xxx_conn_info) == -1)
|
xxx_conn_info) == -1)
|
||||||
fatal("Host key verification failed.");
|
fatal("Host key verification failed.");
|
||||||
@ -1606,6 +1611,13 @@ load_identity_file(Identity *id)
|
|||||||
private = NULL;
|
private = NULL;
|
||||||
quit = 1;
|
quit = 1;
|
||||||
}
|
}
|
||||||
|
if (!quit && (r = sshkey_check_rsa_length(private,
|
||||||
|
options.required_rsa_size)) != 0) {
|
||||||
|
debug_fr(r, "Skipping key %s", id->filename);
|
||||||
|
sshkey_free(private);
|
||||||
|
private = NULL;
|
||||||
|
quit = 1;
|
||||||
|
}
|
||||||
if (!quit && private != NULL && id->agent_fd == -1 &&
|
if (!quit && private != NULL && id->agent_fd == -1 &&
|
||||||
!(id->key && id->isprivate))
|
!(id->key && id->isprivate))
|
||||||
maybe_add_key_to_agent(id->filename, private, comment,
|
maybe_add_key_to_agent(id->filename, private, comment,
|
||||||
@ -1752,6 +1764,12 @@ pubkey_prepare(struct ssh *ssh, Authctxt *authctxt)
|
|||||||
/* list of keys supported by the agent */
|
/* list of keys supported by the agent */
|
||||||
if ((r = get_agent_identities(ssh, &agent_fd, &idlist)) == 0) {
|
if ((r = get_agent_identities(ssh, &agent_fd, &idlist)) == 0) {
|
||||||
for (j = 0; j < idlist->nkeys; j++) {
|
for (j = 0; j < idlist->nkeys; j++) {
|
||||||
|
if ((r = sshkey_check_rsa_length(idlist->keys[j],
|
||||||
|
options.required_rsa_size)) != 0) {
|
||||||
|
debug_fr(r, "ignoring %s agent key",
|
||||||
|
sshkey_ssh_name(idlist->keys[j]));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
found = 0;
|
found = 0;
|
||||||
TAILQ_FOREACH(id, &files, next) {
|
TAILQ_FOREACH(id, &files, next) {
|
||||||
/*
|
/*
|
||||||
|
Loading…
x
Reference in New Issue
Block a user