upstream commit

Expand ssh_config's StrictModes option with two new
settings:

StrictModes=accept-new will automatically accept hitherto-unseen keys
but will refuse connections for changed or invalid hostkeys.

StrictModes=off is the same as StrictModes=no

Motivation:

StrictModes=no combines two behaviours for host key processing:
automatically learning new hostkeys and continuing to connect to hosts
with invalid/changed hostkeys. The latter behaviour is quite dangerous
since it removes most of the protections the SSH protocol is supposed to
provide.

Quite a few users want to automatically learn hostkeys however, so
this makes that feature available with less danger.

At some point in the future, StrictModes=no will change to be a synonym
for accept-new, with its current behaviour remaining available via
StrictModes=off.

bz#2400, suggested by Michael Samuel; ok markus

Upstream-ID: 0f55502bf75fc93a74fb9853264a8276b9680b64
This commit is contained in:
djm@openbsd.org 2017-09-03 23:33:13 +00:00 committed by Damien Miller
parent ff3c423840
commit 22376d27a3
4 changed files with 52 additions and 22 deletions

View File

@ -1,4 +1,4 @@
/* $OpenBSD: readconf.c,v 1.277 2017/05/30 18:58:37 bluhm Exp $ */ /* $OpenBSD: readconf.c,v 1.278 2017/09/03 23:33:13 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
@ -751,6 +751,16 @@ static const struct multistate multistate_yesnoask[] = {
{ "ask", 2 }, { "ask", 2 },
{ NULL, -1 } { NULL, -1 }
}; };
static const struct multistate multistate_strict_hostkey[] = {
{ "true", SSH_STRICT_HOSTKEY_YES },
{ "false", SSH_STRICT_HOSTKEY_OFF },
{ "yes", SSH_STRICT_HOSTKEY_YES },
{ "no", SSH_STRICT_HOSTKEY_OFF },
{ "ask", SSH_STRICT_HOSTKEY_ASK },
{ "off", SSH_STRICT_HOSTKEY_OFF },
{ "accept-new", SSH_STRICT_HOSTKEY_NEW },
{ NULL, -1 }
};
static const struct multistate multistate_yesnoaskconfirm[] = { static const struct multistate multistate_yesnoaskconfirm[] = {
{ "true", 1 }, { "true", 1 },
{ "false", 0 }, { "false", 0 },
@ -984,7 +994,7 @@ parse_time:
case oStrictHostKeyChecking: case oStrictHostKeyChecking:
intptr = &options->strict_host_key_checking; intptr = &options->strict_host_key_checking;
multistate_ptr = multistate_yesnoask; multistate_ptr = multistate_strict_hostkey;
goto parse_multistate; goto parse_multistate;
case oCompression: case oCompression:
@ -1927,7 +1937,7 @@ fill_default_options(Options * options)
if (options->check_host_ip == -1) if (options->check_host_ip == -1)
options->check_host_ip = 1; options->check_host_ip = 1;
if (options->strict_host_key_checking == -1) if (options->strict_host_key_checking == -1)
options->strict_host_key_checking = 2; /* 2 is default */ options->strict_host_key_checking = SSH_STRICT_HOSTKEY_ASK;
if (options->compression == -1) if (options->compression == -1)
options->compression = 0; options->compression = 0;
if (options->tcp_keep_alive == -1) if (options->tcp_keep_alive == -1)
@ -2329,9 +2339,10 @@ fmt_intarg(OpCodes code, int val)
case oAddressFamily: case oAddressFamily:
return fmt_multistate_int(val, multistate_addressfamily); return fmt_multistate_int(val, multistate_addressfamily);
case oVerifyHostKeyDNS: case oVerifyHostKeyDNS:
case oStrictHostKeyChecking:
case oUpdateHostkeys: case oUpdateHostkeys:
return fmt_multistate_int(val, multistate_yesnoask); return fmt_multistate_int(val, multistate_yesnoask);
case oStrictHostKeyChecking:
return fmt_multistate_int(val, multistate_strict_hostkey);
case oControlMaster: case oControlMaster:
return fmt_multistate_int(val, multistate_controlmaster); return fmt_multistate_int(val, multistate_controlmaster);
case oTunnel: case oTunnel:

View File

@ -1,4 +1,4 @@
/* $OpenBSD: readconf.h,v 1.122 2017/05/30 18:58:37 bluhm Exp $ */ /* $OpenBSD: readconf.h,v 1.123 2017/09/03 23:33:13 djm Exp $ */
/* /*
* Author: Tatu Ylonen <ylo@cs.hut.fi> * Author: Tatu Ylonen <ylo@cs.hut.fi>
@ -190,6 +190,11 @@ typedef struct {
#define SSH_UPDATE_HOSTKEYS_YES 1 #define SSH_UPDATE_HOSTKEYS_YES 1
#define SSH_UPDATE_HOSTKEYS_ASK 2 #define SSH_UPDATE_HOSTKEYS_ASK 2
#define SSH_STRICT_HOSTKEY_OFF 0
#define SSH_STRICT_HOSTKEY_NEW 1
#define SSH_STRICT_HOSTKEY_YES 2
#define SSH_STRICT_HOSTKEY_ASK 3
void initialize_options(Options *); void initialize_options(Options *);
void fill_default_options(Options *); void fill_default_options(Options *);
void fill_default_options_for_canonicalization(Options *); void fill_default_options_for_canonicalization(Options *);

View File

@ -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.253 2017/07/23 23:37:02 djm Exp $ .\" $OpenBSD: ssh_config.5,v 1.254 2017/09/03 23:33:13 djm Exp $
.Dd $Mdocdate: July 23 2017 $ .Dd $Mdocdate: September 3 2017 $
.Dt SSH_CONFIG 5 .Dt SSH_CONFIG 5
.Os .Os
.Sh NAME .Sh NAME
@ -1459,9 +1459,17 @@ frequently made.
This option forces the user to manually This option forces the user to manually
add all new hosts. add all new hosts.
If this flag is set to If this flag is set to
.Cm no , .Dq accept-new
ssh will automatically add new host keys to the then ssh will automatically add new new host keys to the user
user known hosts files. known hosts files, but will not permit connections to hosts with
changed host keys.
If this flag is set to
.Dq no
or
.Dq off ,
ssh will automatically add new host keys to the user known hosts files,
and allow connections to hosts with changed hostkeys to proceed subject
to some restrictions.
If this flag is set to If this flag is set to
.Cm ask .Cm ask
(the default), (the default),

View File

@ -1,4 +1,4 @@
/* $OpenBSD: sshconnect.c,v 1.284 2017/09/01 05:53:56 djm Exp $ */ /* $OpenBSD: sshconnect.c,v 1.285 2017/09/03 23:33:13 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
@ -891,7 +891,8 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port,
if (readonly || want_cert) if (readonly || want_cert)
goto fail; goto fail;
/* The host is new. */ /* The host is new. */
if (options.strict_host_key_checking == 1) { if (options.strict_host_key_checking ==
SSH_STRICT_HOSTKEY_YES) {
/* /*
* User has requested strict host key checking. We * User has requested strict host key checking. We
* will not add the host key automatically. The only * will not add the host key automatically. The only
@ -900,7 +901,8 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port,
error("No %s host key is known for %.200s and you " error("No %s host key is known for %.200s and you "
"have requested strict checking.", type, host); "have requested strict checking.", type, host);
goto fail; goto fail;
} else if (options.strict_host_key_checking == 2) { } else if (options.strict_host_key_checking ==
SSH_STRICT_HOSTKEY_ASK) {
char msg1[1024], msg2[1024]; char msg1[1024], msg2[1024];
if (show_other_keys(host_hostkeys, host_key)) if (show_other_keys(host_hostkeys, host_key))
@ -944,8 +946,8 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port,
hostkey_trusted = 1; /* user explicitly confirmed */ hostkey_trusted = 1; /* user explicitly confirmed */
} }
/* /*
* If not in strict mode, add the key automatically to the * If in "new" or "off" strict mode, add the key automatically
* local known_hosts file. * to the local known_hosts file.
*/ */
if (options.check_host_ip && ip_status == HOST_NEW) { if (options.check_host_ip && ip_status == HOST_NEW) {
snprintf(hostline, sizeof(hostline), "%s,%s", host, ip); snprintf(hostline, sizeof(hostline), "%s,%s", host, ip);
@ -987,7 +989,8 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port,
* If strict host key checking is in use, the user will have * If strict host key checking is in use, the user will have
* to edit the key manually and we can only abort. * to edit the key manually and we can only abort.
*/ */
if (options.strict_host_key_checking) { if (options.strict_host_key_checking !=
SSH_STRICT_HOSTKEY_OFF) {
error("%s host key for %.200s was revoked and you have " error("%s host key for %.200s was revoked and you have "
"requested strict checking.", type, host); "requested strict checking.", type, host);
goto fail; goto fail;
@ -1040,7 +1043,8 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port,
* If strict host key checking is in use, the user will have * If strict host key checking is in use, the user will have
* to edit the key manually and we can only abort. * to edit the key manually and we can only abort.
*/ */
if (options.strict_host_key_checking) { if (options.strict_host_key_checking !=
SSH_STRICT_HOSTKEY_OFF) {
error("%s host key for %.200s has changed and you have " error("%s host key for %.200s has changed and you have "
"requested strict checking.", type, host); "requested strict checking.", type, host);
goto fail; goto fail;
@ -1127,15 +1131,17 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port,
"\nMatching host key in %s:%lu", "\nMatching host key in %s:%lu",
host_found->file, host_found->line); host_found->file, host_found->line);
} }
if (options.strict_host_key_checking == 1) { if (options.strict_host_key_checking ==
logit("%s", msg); SSH_STRICT_HOSTKEY_ASK) {
error("Exiting, you have requested strict checking.");
goto fail;
} else if (options.strict_host_key_checking == 2) {
strlcat(msg, "\nAre you sure you want " strlcat(msg, "\nAre you sure you want "
"to continue connecting (yes/no)? ", sizeof(msg)); "to continue connecting (yes/no)? ", sizeof(msg));
if (!confirm(msg)) if (!confirm(msg))
goto fail; goto fail;
} else if (options.strict_host_key_checking !=
SSH_STRICT_HOSTKEY_OFF) {
logit("%s", msg);
error("Exiting, you have requested strict checking.");
goto fail;
} else { } else {
logit("%s", msg); logit("%s", msg);
} }