From dc9cac76df6e44b19c92737fba575da89ba76ff4 Mon Sep 17 00:00:00 2001 From: djm Date: Tue, 13 Jan 2015 07:39:19 +0000 Subject: [PATCH] add sshd_config HostbasedAcceptedKeyTypes and PubkeyAcceptedKeyTypes options to allow sshd to control what public key types will be accepted. Currently defaults to all. Feedback & ok markus@ --- usr.bin/ssh/auth2-hostbased.c | 11 ++++++++- usr.bin/ssh/auth2-pubkey.c | 9 ++++++- usr.bin/ssh/key.h | 3 +-- usr.bin/ssh/monitor.c | 14 ++++++++++- usr.bin/ssh/readconf.c | 4 ++-- usr.bin/ssh/servconf.c | 44 +++++++++++++++++++++++++++++------ usr.bin/ssh/servconf.h | 6 ++++- usr.bin/ssh/sshd_config.5 | 28 ++++++++++++++++++++-- usr.bin/ssh/sshkey.c | 32 +++++++++++++++++++++---- usr.bin/ssh/sshkey.h | 4 ++-- 10 files changed, 131 insertions(+), 24 deletions(-) diff --git a/usr.bin/ssh/auth2-hostbased.c b/usr.bin/ssh/auth2-hostbased.c index e75a5cf0cd4..104725bc2f3 100644 --- a/usr.bin/ssh/auth2-hostbased.c +++ b/usr.bin/ssh/auth2-hostbased.c @@ -1,4 +1,4 @@ -/* $OpenBSD: auth2-hostbased.c,v 1.21 2015/01/08 10:14:08 djm Exp $ */ +/* $OpenBSD: auth2-hostbased.c,v 1.22 2015/01/13 07:39:19 djm Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. * @@ -47,6 +47,7 @@ #endif #include "monitor_wrap.h" #include "pathnames.h" +#include "match.h" /* import */ extern ServerOptions options; @@ -107,6 +108,14 @@ userauth_hostbased(Authctxt *authctxt) "signature format"); goto done; } + if (match_pattern_list(sshkey_ssh_name(key), + options.hostbased_key_types, + strlen(options.hostbased_key_types), 0) != 1) { + logit("%s: key type %s not in HostbasedAcceptedKeyTypes", + __func__, sshkey_type(key)); + goto done; + } + service = datafellows & SSH_BUG_HBSERVICE ? "ssh-userauth" : authctxt->service; buffer_init(&b); diff --git a/usr.bin/ssh/auth2-pubkey.c b/usr.bin/ssh/auth2-pubkey.c index f880717d7b4..87c8132c8dc 100644 --- a/usr.bin/ssh/auth2-pubkey.c +++ b/usr.bin/ssh/auth2-pubkey.c @@ -1,4 +1,4 @@ -/* $OpenBSD: auth2-pubkey.c,v 1.44 2014/12/22 07:51:30 djm Exp $ */ +/* $OpenBSD: auth2-pubkey.c,v 1.45 2015/01/13 07:39:19 djm Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. * @@ -124,6 +124,13 @@ userauth_pubkey(Authctxt *authctxt) logit("refusing previously-used %s key", key_type(key)); goto done; } + if (match_pattern_list(sshkey_ssh_name(key), options.pubkey_key_types, + strlen(options.pubkey_key_types), 0) != 1) { + logit("%s: key type %s not in PubkeyAcceptedKeyTypes", + __func__, sshkey_ssh_name(key)); + goto done; + } + if (have_sig) { sig = packet_get_string(&slen); packet_check_eom(); diff --git a/usr.bin/ssh/key.h b/usr.bin/ssh/key.h index 9d7e84e78e4..188d417041a 100644 --- a/usr.bin/ssh/key.h +++ b/usr.bin/ssh/key.h @@ -1,4 +1,4 @@ -/* $OpenBSD: key.h,v 1.45 2015/01/08 10:14:08 djm Exp $ */ +/* $OpenBSD: key.h,v 1.46 2015/01/13 07:39:19 djm Exp $ */ /* * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. @@ -50,7 +50,6 @@ typedef struct sshkey Key; #define key_size sshkey_size #define key_ecdsa_bits_to_nid sshkey_ecdsa_bits_to_nid #define key_ecdsa_key_to_nid sshkey_ecdsa_key_to_nid -#define key_names_valid2 sshkey_names_valid2 #define key_is_cert sshkey_is_cert #define key_type_plain sshkey_type_plain #define key_cert_is_legacy sshkey_cert_is_legacy diff --git a/usr.bin/ssh/monitor.c b/usr.bin/ssh/monitor.c index 637009c878f..85b98dc952a 100644 --- a/usr.bin/ssh/monitor.c +++ b/usr.bin/ssh/monitor.c @@ -1,4 +1,4 @@ -/* $OpenBSD: monitor.c,v 1.136 2014/12/22 07:51:30 djm Exp $ */ +/* $OpenBSD: monitor.c,v 1.137 2015/01/13 07:39:19 djm Exp $ */ /* * Copyright 2002 Niels Provos * Copyright 2002 Markus Friedl @@ -79,6 +79,7 @@ #include "ssh2.h" #include "roaming.h" #include "authfd.h" +#include "match.h" #ifdef GSSAPI static Gssctxt *gsscontext = NULL; @@ -881,10 +882,18 @@ mm_answer_keyallowed(int sock, Buffer *m) debug3("%s: key_from_blob: %p", __func__, key); if (key != NULL && authctxt->valid) { + /* These should not make it past the privsep child */ + if (key_type_plain(key->type) == KEY_RSA && + (datafellows & SSH_BUG_RSASIGMD5) != 0) + fatal("%s: passed a SSH_BUG_RSASIGMD5 key", __func__); + switch (type) { case MM_USERKEY: allowed = options.pubkey_authentication && !auth2_userkey_already_used(authctxt, key) && + match_pattern_list(sshkey_ssh_name(key), + options.pubkey_key_types, + strlen(options.pubkey_key_types), 0) == 1 && user_key_allowed(authctxt->pw, key); pubkey_auth_info(authctxt, key, NULL); auth_method = "publickey"; @@ -893,6 +902,9 @@ mm_answer_keyallowed(int sock, Buffer *m) break; case MM_HOSTKEY: allowed = options.hostbased_authentication && + match_pattern_list(sshkey_ssh_name(key), + options.hostbased_key_types, + strlen(options.hostbased_key_types), 0) == 1 && hostbased_key_allowed(authctxt->pw, cuser, chost, key); pubkey_auth_info(authctxt, key, diff --git a/usr.bin/ssh/readconf.c b/usr.bin/ssh/readconf.c index 51034c1782e..83944dca23f 100644 --- a/usr.bin/ssh/readconf.c +++ b/usr.bin/ssh/readconf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: readconf.c,v 1.225 2015/01/08 13:44:36 djm Exp $ */ +/* $OpenBSD: readconf.c,v 1.226 2015/01/13 07:39:19 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -1104,7 +1104,7 @@ parse_int: arg = strdelim(&s); if (!arg || *arg == '\0') fatal("%.200s line %d: Missing argument.", filename, linenum); - if (!key_names_valid2(arg)) + if (!sshkey_names_valid2(arg, 1)) fatal("%.200s line %d: Bad protocol 2 host key algorithms '%s'.", filename, linenum, arg ? arg : ""); if (*activep && options->hostkeyalgorithms == NULL) diff --git a/usr.bin/ssh/servconf.c b/usr.bin/ssh/servconf.c index 5732d787ccc..f36cc9c352e 100644 --- a/usr.bin/ssh/servconf.c +++ b/usr.bin/ssh/servconf.c @@ -1,5 +1,5 @@ -/* $OpenBSD: servconf.c,v 1.257 2014/12/22 07:55:51 djm Exp $ */ +/* $OpenBSD: servconf.c,v 1.258 2015/01/13 07:39:19 djm Exp $ */ /* * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland * All rights reserved @@ -94,8 +94,10 @@ initialize_server_options(ServerOptions *options) options->rhosts_rsa_authentication = -1; options->hostbased_authentication = -1; options->hostbased_uses_name_from_packet_only = -1; + options->hostbased_key_types = NULL; options->rsa_authentication = -1; options->pubkey_authentication = -1; + options->pubkey_key_types = NULL; options->kerberos_authentication = -1; options->kerberos_or_local_passwd = -1; options->kerberos_ticket_cleanup = -1; @@ -231,10 +233,14 @@ fill_default_server_options(ServerOptions *options) options->hostbased_authentication = 0; if (options->hostbased_uses_name_from_packet_only == -1) options->hostbased_uses_name_from_packet_only = 0; + if (options->hostbased_key_types == NULL) + options->hostbased_key_types = xstrdup("*"); if (options->rsa_authentication == -1) options->rsa_authentication = 1; if (options->pubkey_authentication == -1) options->pubkey_authentication = 1; + if (options->pubkey_key_types == NULL) + options->pubkey_key_types = xstrdup("*"); if (options->kerberos_authentication == -1) options->kerberos_authentication = 0; if (options->kerberos_or_local_passwd == -1) @@ -335,8 +341,8 @@ fill_default_server_options(ServerOptions *options) /* Keyword tokens. */ typedef enum { sBadOption, /* == unknown option */ - sPort, sHostKeyFile, sServerKeyBits, sLoginGraceTime, sKeyRegenerationTime, - sPermitRootLogin, sLogFacility, sLogLevel, + sPort, sHostKeyFile, sServerKeyBits, sLoginGraceTime, + sKeyRegenerationTime, sPermitRootLogin, sLogFacility, sLogLevel, sRhostsRSAAuthentication, sRSAAuthentication, sKerberosAuthentication, sKerberosOrLocalPasswd, sKerberosTicketCleanup, sKerberosGetAFSToken, @@ -349,11 +355,11 @@ typedef enum { sPermitUserEnvironment, sUseLogin, sAllowTcpForwarding, sCompression, sRekeyLimit, sAllowUsers, sDenyUsers, sAllowGroups, sDenyGroups, sIgnoreUserKnownHosts, sCiphers, sMacs, sProtocol, sPidFile, - sGatewayPorts, sPubkeyAuthentication, sXAuthLocation, sSubsystem, - sMaxStartups, sMaxAuthTries, sMaxSessions, + sGatewayPorts, sPubkeyAuthentication, sPubkeyAcceptedKeyTypes, + sXAuthLocation, sSubsystem, sMaxStartups, sMaxAuthTries, sMaxSessions, sBanner, sUseDNS, sHostbasedAuthentication, - sHostbasedUsesNameFromPacketOnly, sClientAliveInterval, - sClientAliveCountMax, sAuthorizedKeysFile, + sHostbasedUsesNameFromPacketOnly, sHostbasedAcceptedKeyTypes, + sClientAliveInterval, sClientAliveCountMax, sAuthorizedKeysFile, sGssAuthentication, sGssCleanupCreds, sAcceptEnv, sPermitTunnel, sMatch, sPermitOpen, sForceCommand, sChrootDirectory, sUsePrivilegeSeparation, sAllowAgentForwarding, @@ -392,8 +398,10 @@ static struct { { "rhostsrsaauthentication", sRhostsRSAAuthentication, SSHCFG_ALL }, { "hostbasedauthentication", sHostbasedAuthentication, SSHCFG_ALL }, { "hostbasedusesnamefrompacketonly", sHostbasedUsesNameFromPacketOnly, SSHCFG_ALL }, + { "hostbasedacceptedkeytypes", sHostbasedAcceptedKeyTypes, SSHCFG_ALL }, { "rsaauthentication", sRSAAuthentication, SSHCFG_ALL }, { "pubkeyauthentication", sPubkeyAuthentication, SSHCFG_ALL }, + { "pubkeyacceptedkeytypes", sPubkeyAcceptedKeyTypes, SSHCFG_ALL }, { "dsaauthentication", sPubkeyAuthentication, SSHCFG_GLOBAL }, /* alias */ #ifdef KRB5 { "kerberosauthentication", sKerberosAuthentication, SSHCFG_ALL }, @@ -1063,6 +1071,20 @@ process_server_config_line(ServerOptions *options, char *line, intptr = &options->hostbased_uses_name_from_packet_only; goto parse_flag; + case sHostbasedAcceptedKeyTypes: + charptr = &options->hostbased_key_types; + parse_keytypes: + arg = strdelim(&cp); + if (!arg || *arg == '\0') + fatal("%s line %d: Missing argument.", + filename, linenum); + if (!sshkey_names_valid2(arg, 1)) + fatal("%s line %d: Bad key types '%s'.", + filename, linenum, arg ? arg : ""); + if (*activep && *charptr == NULL) + *charptr = xstrdup(arg); + break; + case sRSAAuthentication: intptr = &options->rsa_authentication; goto parse_flag; @@ -1071,6 +1093,10 @@ process_server_config_line(ServerOptions *options, char *line, intptr = &options->pubkey_authentication; goto parse_flag; + case sPubkeyAcceptedKeyTypes: + charptr = &options->pubkey_key_types; + goto parse_keytypes; + case sKerberosAuthentication: intptr = &options->kerberos_authentication; goto parse_flag; @@ -2089,6 +2115,10 @@ dump_config(ServerOptions *o) dump_cfg_string(sHostKeyAgent, o->host_key_agent); dump_cfg_string(sKexAlgorithms, o->kex_algorithms ? o->kex_algorithms : KEX_SERVER_KEX); + dump_cfg_string(sHostbasedAcceptedKeyTypes, o->hostbased_key_types ? + o->hostbased_key_types : KEX_DEFAULT_PK_ALG); + dump_cfg_string(sPubkeyAcceptedKeyTypes, o->pubkey_key_types ? + o->pubkey_key_types : KEX_DEFAULT_PK_ALG); /* string arguments requiring a lookup */ dump_cfg_string(sLogLevel, log_level_name(o->log_level)); diff --git a/usr.bin/ssh/servconf.h b/usr.bin/ssh/servconf.h index 88a4bd4bbad..447a2cec867 100644 --- a/usr.bin/ssh/servconf.h +++ b/usr.bin/ssh/servconf.h @@ -1,4 +1,4 @@ -/* $OpenBSD: servconf.h,v 1.115 2014/12/21 22:27:56 djm Exp $ */ +/* $OpenBSD: servconf.h,v 1.116 2015/01/13 07:39:19 djm Exp $ */ /* * Author: Tatu Ylonen @@ -99,8 +99,10 @@ typedef struct { * authentication. */ int hostbased_authentication; /* If true, permit ssh2 hostbased auth */ int hostbased_uses_name_from_packet_only; /* experimental */ + char *hostbased_key_types; /* Key types allowed for hostbased */ int rsa_authentication; /* If true, permit RSA authentication. */ int pubkey_authentication; /* If true, permit ssh2 pubkey authentication. */ + char *pubkey_key_types; /* Key types allowed for public key */ int kerberos_authentication; /* If true, permit Kerberos * authentication. */ int kerberos_or_local_passwd; /* If true, permit kerberos @@ -213,6 +215,8 @@ struct connection_info { M_CP_STROPT(authorized_principals_file); \ M_CP_STROPT(authorized_keys_command); \ M_CP_STROPT(authorized_keys_command_user); \ + M_CP_STROPT(hostbased_key_types); \ + M_CP_STROPT(pubkey_key_types); \ M_CP_STRARRAYOPT(authorized_keys_files, num_authkeys_files); \ M_CP_STRARRAYOPT(allow_users, num_allow_users); \ M_CP_STRARRAYOPT(deny_users, num_deny_users); \ diff --git a/usr.bin/ssh/sshd_config.5 b/usr.bin/ssh/sshd_config.5 index 7f79255789c..33c93bc9306 100644 --- a/usr.bin/ssh/sshd_config.5 +++ b/usr.bin/ssh/sshd_config.5 @@ -33,8 +33,8 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.\" $OpenBSD: sshd_config.5,v 1.188 2014/12/22 09:05:17 djm Exp $ -.Dd $Mdocdate: December 22 2014 $ +.\" $OpenBSD: sshd_config.5,v 1.189 2015/01/13 07:39:19 djm Exp $ +.Dd $Mdocdate: January 13 2015 $ .Dt SSHD_CONFIG 5 .Os .Sh NAME @@ -562,6 +562,17 @@ on logout. The default is .Dq yes . Note that this option applies to protocol version 2 only. +.It Cm HostbasedAcceptedKeyTypes +Specifies the key types that will be accepted for hostbased authentication +as a comma-separated pattern list. +The default +.Dq * +will allow all key types. +The +.Fl Q +option of +.Xr ssh 1 +may be used to list supported key types. .It Cm HostbasedAuthentication Specifies whether rhosts or /etc/hosts.equiv authentication together with successful public key client host authentication is allowed @@ -963,6 +974,7 @@ Available keywords are .Cm ForceCommand , .Cm GatewayPorts , .Cm GSSAPIAuthentication , +.Cm HostbasedAcceptedKeyTypes , .Cm HostbasedAuthentication , .Cm HostbasedUsesNameFromPacketOnly , .Cm KbdInteractiveAuthentication , @@ -976,6 +988,7 @@ Available keywords are .Cm PermitTTY , .Cm PermitTunnel , .Cm PermitUserRC , +.Cm PubkeyAcceptedKeyTypes , .Cm PubkeyAuthentication , .Cm RekeyLimit , .Cm RhostsRSAAuthentication , @@ -1183,6 +1196,17 @@ Specifying .Dq 2,1 is identical to .Dq 1,2 . +.It Cm PubkeyAcceptedKeyTypes +Specifies the key types that will be accepted for public key authentication +as a comma-separated pattern list. +The default +.Dq * +will allow all key types. +The +.Fl Q +option of +.Xr ssh 1 +may be used to list supported key types. .It Cm PubkeyAuthentication Specifies whether public key authentication is allowed. The default is diff --git a/usr.bin/ssh/sshkey.c b/usr.bin/ssh/sshkey.c index 1fd3136340f..5116fad5028 100644 --- a/usr.bin/ssh/sshkey.c +++ b/usr.bin/ssh/sshkey.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sshkey.c,v 1.10 2015/01/12 20:13:27 markus Exp $ */ +/* $OpenBSD: sshkey.c,v 1.11 2015/01/13 07:39:19 djm Exp $ */ /* * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. * Copyright (c) 2008 Alexander von Gernler. All rights reserved. @@ -50,6 +50,7 @@ #include "digest.h" #define SSHKEY_INTERNAL #include "sshkey.h" +#include "match.h" /* openssh private key file format */ #define MARK_BEGIN "-----BEGIN OPENSSH PRIVATE KEY-----\n" @@ -207,9 +208,11 @@ key_alg_list(int certs_only, int plain_only) } int -sshkey_names_valid2(const char *names) +sshkey_names_valid2(const char *names, int allow_wildcard) { char *s, *cp, *p; + const struct keytype *kt; + int type; if (names == NULL || strcmp(names, "") == 0) return 0; @@ -217,9 +220,28 @@ sshkey_names_valid2(const char *names) return 0; for ((p = strsep(&cp, ",")); p && *p != '\0'; (p = strsep(&cp, ","))) { - switch (sshkey_type_from_name(p)) { - case KEY_RSA1: - case KEY_UNSPEC: + type = sshkey_type_from_name(p); + if (type == KEY_RSA1) { + free(s); + return 0; + } + if (type == KEY_UNSPEC) { + if (allow_wildcard) { + /* + * Try matching key types against the string. + * If any has a positive or negative match then + * the component is accepted. + */ + for (kt = keytypes; kt->type != -1; kt++) { + if (kt->type == KEY_RSA1) + continue; + if (match_pattern_list(kt->name, + p, strlen(p), 0) != 0) + break; + } + if (kt->type != -1) + continue; + } free(s); return 0; } diff --git a/usr.bin/ssh/sshkey.h b/usr.bin/ssh/sshkey.h index 2db64d76787..f4d7b954a7f 100644 --- a/usr.bin/ssh/sshkey.h +++ b/usr.bin/ssh/sshkey.h @@ -1,4 +1,4 @@ -/* $OpenBSD: sshkey.h,v 1.3 2015/01/08 10:14:08 djm Exp $ */ +/* $OpenBSD: sshkey.h,v 1.4 2015/01/13 07:39:19 djm Exp $ */ /* * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. @@ -150,7 +150,7 @@ int sshkey_ec_validate_public(const EC_GROUP *, const EC_POINT *); int sshkey_ec_validate_private(const EC_KEY *); const char *sshkey_ssh_name(const struct sshkey *); const char *sshkey_ssh_name_plain(const struct sshkey *); -int sshkey_names_valid2(const char *); +int sshkey_names_valid2(const char *, int); char *key_alg_list(int, int); int sshkey_from_blob(const u_char *, size_t, struct sshkey **); -- 2.20.1