diff options
author | Damien Miller <djm@cvs.openbsd.org> | 2019-11-25 00:52:47 +0000 |
---|---|---|
committer | Damien Miller <djm@cvs.openbsd.org> | 2019-11-25 00:52:47 +0000 |
commit | 4fb21d67a65c6ab35a243d94db5b7217eea38c9e (patch) | |
tree | 34d1101461223d419d80bfb180aa78df94f1d9d0 | |
parent | fd20bc8b0b1c1509670acbedcad3d576840de73d (diff) |
Add a sshd_config PubkeyAuthOptions directive
This directive has a single valid option "no-touch-required" that
causes sshd to skip checking whether user presence was tested before
a security key signature was made (usually by the user touching the
key).
ok markus@
-rw-r--r-- | usr.bin/ssh/auth2-pubkey.c | 22 | ||||
-rw-r--r-- | usr.bin/ssh/monitor.c | 63 | ||||
-rw-r--r-- | usr.bin/ssh/servconf.c | 33 | ||||
-rw-r--r-- | usr.bin/ssh/servconf.h | 6 | ||||
-rw-r--r-- | usr.bin/ssh/sshd_config.5 | 27 |
5 files changed, 119 insertions, 32 deletions
diff --git a/usr.bin/ssh/auth2-pubkey.c b/usr.bin/ssh/auth2-pubkey.c index d5438fe220f..5f325b3fb96 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.95 2019/11/25 00:51:37 djm Exp $ */ +/* $OpenBSD: auth2-pubkey.c,v 1.96 2019/11/25 00:52:46 djm Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. * @@ -65,6 +65,7 @@ #include "ssherr.h" #include "channels.h" /* XXX for session.h */ #include "session.h" /* XXX for child_set_env(); refactor? */ +#include "sk-api.h" /* import */ extern ServerOptions options; @@ -93,7 +94,7 @@ userauth_pubkey(struct ssh *ssh) u_char *pkblob = NULL, *sig = NULL, have_sig; size_t blen, slen; int r, pktype; - int authenticated = 0; + int req_presence = 0, authenticated = 0; struct sshauthopt *authopts = NULL; struct sshkey_sig_details *sig_details = NULL; @@ -214,10 +215,25 @@ userauth_pubkey(struct ssh *ssh) ssh->compat, &sig_details)) == 0) { authenticated = 1; } - if (sig_details != NULL) { + if (authenticated == 1 && sig_details != NULL) { + auth2_record_info(authctxt, "signature count = %u", + sig_details->sk_counter); debug("%s: sk_counter = %u, sk_flags = 0x%02x", __func__, sig_details->sk_counter, sig_details->sk_flags); + req_presence = (options.pubkey_auth_options & + PUBKEYAUTH_TOUCH_REQUIRED); + if (req_presence && (sig_details->sk_flags & + SSH_SK_USER_PRESENCE_REQD) == 0) { + error("public key %s signature for %s%s from " + "%.128s port %d rejected: user presence " + "(key touch) requirement not met ", key_s, + authctxt->valid ? "" : "invalid user ", + authctxt->user, ssh_remote_ipaddr(ssh), + ssh_remote_port(ssh)); + authenticated = 0; + goto done; + } } auth2_record_key(authctxt, authenticated, key); } else { diff --git a/usr.bin/ssh/monitor.c b/usr.bin/ssh/monitor.c index bca521c8597..d35875f3ff0 100644 --- a/usr.bin/ssh/monitor.c +++ b/usr.bin/ssh/monitor.c @@ -1,4 +1,4 @@ -/* $OpenBSD: monitor.c,v 1.202 2019/11/25 00:51:37 djm Exp $ */ +/* $OpenBSD: monitor.c,v 1.203 2019/11/25 00:52:46 djm Exp $ */ /* * Copyright 2002 Niels Provos <provos@citi.umich.edu> * Copyright 2002 Markus Friedl <markus@openbsd.org> @@ -80,6 +80,7 @@ #include "authfd.h" #include "match.h" #include "ssherr.h" +#include "sk-api.h" #ifdef GSSAPI static Gssctxt *gsscontext = NULL; @@ -476,7 +477,7 @@ monitor_read(struct ssh *ssh, struct monitor *pmonitor, struct mon_table *ent, /* allowed key state */ static int -monitor_allowed_key(u_char *blob, u_int bloblen) +monitor_allowed_key(const u_char *blob, u_int bloblen) { /* make sure key is allowed */ if (key_blob == NULL || key_bloblen != bloblen || @@ -1003,7 +1004,7 @@ mm_answer_keyallowed(struct ssh *ssh, int sock, struct sshbuf *m) } static int -monitor_valid_userblob(u_char *data, u_int datalen) +monitor_valid_userblob(const u_char *data, u_int datalen) { struct sshbuf *b; const u_char *p; @@ -1012,10 +1013,8 @@ monitor_valid_userblob(u_char *data, u_int datalen) u_char type; int r, fail = 0; - if ((b = sshbuf_new()) == NULL) - fatal("%s: sshbuf_new", __func__); - if ((r = sshbuf_put(b, data, datalen)) != 0) - fatal("%s: buffer error: %s", __func__, ssh_err(r)); + if ((b = sshbuf_from(data, datalen)) == NULL) + fatal("%s: sshbuf_from", __func__); if (datafellows & SSH_OLD_SESSIONID) { p = sshbuf_ptr(b); @@ -1070,8 +1069,8 @@ monitor_valid_userblob(u_char *data, u_int datalen) } static int -monitor_valid_hostbasedblob(u_char *data, u_int datalen, char *cuser, - char *chost) +monitor_valid_hostbasedblob(const u_char *data, u_int datalen, + const char *cuser, const char *chost) { struct sshbuf *b; const u_char *p; @@ -1080,10 +1079,9 @@ monitor_valid_hostbasedblob(u_char *data, u_int datalen, char *cuser, int r, fail = 0; u_char type; - if ((b = sshbuf_new()) == NULL) + if ((b = sshbuf_from(data, datalen)) == NULL) fatal("%s: sshbuf_new", __func__); - if ((r = sshbuf_put(b, data, datalen)) != 0 || - (r = sshbuf_get_string_direct(b, &p, &len)) != 0) + if ((r = sshbuf_get_string_direct(b, &p, &len)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); if ((session_id2 == NULL) || @@ -1143,15 +1141,15 @@ int mm_answer_keyverify(struct ssh *ssh, int sock, struct sshbuf *m) { struct sshkey *key; - u_char *signature, *data, *blob; - char *sigalg; + const u_char *signature, *data, *blob; + char *sigalg = NULL, *fp = NULL; size_t signaturelen, datalen, bloblen; - int r, ret, valid_data = 0, encoded_ret; + int r, ret, req_presence = 0, valid_data = 0, encoded_ret; struct sshkey_sig_details *sig_details = NULL; - if ((r = sshbuf_get_string(m, &blob, &bloblen)) != 0 || - (r = sshbuf_get_string(m, &signature, &signaturelen)) != 0 || - (r = sshbuf_get_string(m, &data, &datalen)) != 0 || + if ((r = sshbuf_get_string_direct(m, &blob, &bloblen)) != 0 || + (r = sshbuf_get_string_direct(m, &signature, &signaturelen)) != 0 || + (r = sshbuf_get_string_direct(m, &data, &datalen)) != 0 || (r = sshbuf_get_cstring(m, &sigalg, NULL)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); @@ -1186,23 +1184,36 @@ mm_answer_keyverify(struct ssh *ssh, int sock, struct sshbuf *m) if (!valid_data) fatal("%s: bad signature data blob", __func__); + if ((fp = sshkey_fingerprint(key, options.fingerprint_hash, + SSH_FP_DEFAULT)) == NULL) + fatal("%s: sshkey_fingerprint failed", __func__); + ret = sshkey_verify(key, signature, signaturelen, data, datalen, sigalg, ssh->compat, &sig_details); debug3("%s: %s %p signature %s%s%s", __func__, auth_method, key, (ret == 0) ? "verified" : "unverified", (ret != 0) ? ": " : "", (ret != 0) ? ssh_err(ret) : ""); - auth2_record_key(authctxt, ret == 0, key); - free(blob); - free(signature); - free(data); - free(sigalg); + if (ret == 0 && key_blobtype == MM_USERKEY && sig_details != NULL) { + req_presence = (options.pubkey_auth_options & + PUBKEYAUTH_TOUCH_REQUIRED); + if (req_presence && + (sig_details->sk_flags & SSH_SK_USER_PRESENCE_REQD) == 0) { + error("public key %s %s signature for %s%s from %.128s " + "port %d rejected: user presence (key touch) " + "requirement not met ", sshkey_type(key), fp, + authctxt->valid ? "" : "invalid user ", + authctxt->user, ssh_remote_ipaddr(ssh), + ssh_remote_port(ssh)); + ret = SSH_ERR_SIGNATURE_INVALID; + } + } + auth2_record_key(authctxt, ret == 0, key); if (key_blobtype == MM_USERKEY) auth_activate_options(ssh, key_opts); monitor_reset_key_state(); - sshkey_free(key); sshbuf_reset(m); /* encode ret != 0 as positive integer, since we're sending u32 */ @@ -1218,6 +1229,10 @@ mm_answer_keyverify(struct ssh *ssh, int sock, struct sshbuf *m) sshkey_sig_details_free(sig_details); mm_request_send(sock, MONITOR_ANS_KEYVERIFY, m); + free(sigalg); + free(fp); + sshkey_free(key); + return ret == 0; } diff --git a/usr.bin/ssh/servconf.c b/usr.bin/ssh/servconf.c index f9bbae797bc..be059c0f0d2 100644 --- a/usr.bin/ssh/servconf.c +++ b/usr.bin/ssh/servconf.c @@ -1,5 +1,5 @@ -/* $OpenBSD: servconf.c,v 1.353 2019/10/31 21:17:49 djm Exp $ */ +/* $OpenBSD: servconf.c,v 1.354 2019/11/25 00:52:46 djm Exp $ */ /* * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * All rights reserved @@ -104,6 +104,7 @@ initialize_server_options(ServerOptions *options) options->hostbased_key_types = NULL; options->hostkeyalgorithms = NULL; options->pubkey_authentication = -1; + options->pubkey_auth_options = -1; options->pubkey_key_types = NULL; options->kerberos_authentication = -1; options->kerberos_or_local_passwd = -1; @@ -320,6 +321,8 @@ fill_default_server_options(ServerOptions *options) options->hostbased_uses_name_from_packet_only = 0; if (options->pubkey_authentication == -1) options->pubkey_authentication = 1; + if (options->pubkey_auth_options == -1) + options->pubkey_auth_options = 0; if (options->kerberos_authentication == -1) options->kerberos_authentication = 0; if (options->kerberos_or_local_passwd == -1) @@ -475,7 +478,7 @@ typedef enum { sAuthenticationMethods, sHostKeyAgent, sPermitUserRC, sStreamLocalBindMask, sStreamLocalBindUnlink, sAllowStreamLocalForwarding, sFingerprintHash, sDisableForwarding, - sExposeAuthInfo, sRDomain, + sExposeAuthInfo, sRDomain, sPubkeyAuthOptions, sDeprecated, sIgnore, sUnsupported } ServerOpCodes; @@ -509,6 +512,7 @@ static struct { { "rsaauthentication", sDeprecated, SSHCFG_ALL }, { "pubkeyauthentication", sPubkeyAuthentication, SSHCFG_ALL }, { "pubkeyacceptedkeytypes", sPubkeyAcceptedKeyTypes, SSHCFG_ALL }, + { "pubkeyauthoptions", sPubkeyAuthOptions, SSHCFG_ALL }, { "dsaauthentication", sPubkeyAuthentication, SSHCFG_GLOBAL }, /* alias */ #ifdef KRB5 { "kerberosauthentication", sKerberosAuthentication, SSHCFG_ALL }, @@ -1405,6 +1409,24 @@ process_server_config_line(ServerOptions *options, char *line, charptr = &options->pubkey_key_types; goto parse_keytypes; + case sPubkeyAuthOptions: + intptr = &options->pubkey_auth_options; + value = 0; + while ((arg = strdelim(&cp)) && *arg != '\0') { + if (strcasecmp(arg, "none") == 0) + continue; + if (strcasecmp(arg, "touch-required") == 0) + value |= PUBKEYAUTH_TOUCH_REQUIRED; + else { + fatal("%s line %d: unsupported " + "PubkeyAuthOptions option %s", + filename, linenum, arg); + } + } + if (*activep && *intptr == -1) + *intptr = value; + break; + case sKerberosAuthentication: intptr = &options->kerberos_authentication; goto parse_flag; @@ -2227,6 +2249,7 @@ copy_set_server_options(ServerOptions *dst, ServerOptions *src, int preauth) M_CP_INTOPT(password_authentication); M_CP_INTOPT(gss_authentication); M_CP_INTOPT(pubkey_authentication); + M_CP_INTOPT(pubkey_auth_options); M_CP_INTOPT(kerberos_authentication); M_CP_INTOPT(hostbased_authentication); M_CP_INTOPT(hostbased_uses_name_from_packet_only); @@ -2641,4 +2664,10 @@ dump_config(ServerOptions *o) o->permit_user_env_whitelist); } + printf("pubkeyauthoptions"); + if (o->pubkey_auth_options == 0) + printf(" none"); + if (o->pubkey_auth_options & PUBKEYAUTH_TOUCH_REQUIRED) + printf(" touch-required"); + printf("\n"); } diff --git a/usr.bin/ssh/servconf.h b/usr.bin/ssh/servconf.h index 0bcc6a31484..5c653eb89ee 100644 --- a/usr.bin/ssh/servconf.h +++ b/usr.bin/ssh/servconf.h @@ -1,4 +1,4 @@ -/* $OpenBSD: servconf.h,v 1.140 2019/04/18 18:56:16 dtucker Exp $ */ +/* $OpenBSD: servconf.h,v 1.141 2019/11/25 00:52:46 djm Exp $ */ /* * Author: Tatu Ylonen <ylo@cs.hut.fi> @@ -42,6 +42,9 @@ /* Magic name for internal sftp-server */ #define INTERNAL_SFTP_NAME "internal-sftp" +/* PubkeyAuthOptions flags */ +#define PUBKEYAUTH_TOUCH_REQUIRED 1 + struct ssh; struct fwd_perm_list; @@ -114,6 +117,7 @@ typedef struct { char *ca_sign_algorithms; /* Allowed CA signature algorithms */ int pubkey_authentication; /* If true, permit ssh2 pubkey authentication. */ char *pubkey_key_types; /* Key types allowed for public key */ + int pubkey_auth_options; /* -1 or mask of PUBKEYAUTH_* flags */ int kerberos_authentication; /* If true, permit Kerberos * authentication. */ int kerberos_or_local_passwd; /* If true, permit kerberos diff --git a/usr.bin/ssh/sshd_config.5 b/usr.bin/ssh/sshd_config.5 index 8dee24fd742..efce382f6fb 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.292 2019/11/18 04:55:02 djm Exp $ -.Dd $Mdocdate: November 18 2019 $ +.\" $OpenBSD: sshd_config.5,v 1.293 2019/11/25 00:52:46 djm Exp $ +.Dd $Mdocdate: November 25 2019 $ .Dt SSHD_CONFIG 5 .Os .Sh NAME @@ -1446,6 +1446,29 @@ ssh-ed25519,rsa-sha2-512,rsa-sha2-256,ssh-rsa .Pp The list of available key types may also be obtained using .Qq ssh -Q key . +.It Cm PubkeyAuthOptions +Sets one or more public key authentication options. +Two option keywords are currently supported: +.Cm none (the default; indicating no additional options are enabled) +and +.Cm touch-required . +.Pp +The +.Cm touch-required +option causes public key authentication using a security key algorithm +(i.e. +.Cm ecdsa-sk +or +.Cm ed25519-sk ) +to always require the signature to attest that a physically present user +explicitly confirmed the authentication (usually by touching the security key). +By default, +.Xr sshd 8 +requires key touch unless overridden with an authorized_keys option. +The +.Cm touch-required +flag disables this override. +This option has no effect for other, non-security key public key types. .It Cm PubkeyAuthentication Specifies whether public key authentication is allowed. The default is |