[openssh-commits] [openssh] 05/08: upstream: support for requiring user verified FIDO keys in sshd

git+noreply at mindrot.org git+noreply at mindrot.org
Thu Aug 27 11:28:47 AEST 2020


This is an automated email from the git hooks/post-receive script.

djm pushed a commit to branch master
in repository openssh.

commit 801c9f095e6d8b7b91aefd98f5001c652ea13488
Author: djm at openbsd.org <djm at openbsd.org>
Date:   Thu Aug 27 01:07:09 2020 +0000

    upstream: support for requiring user verified FIDO keys in sshd
    
    This adds a "verify-required" authorized_keys flag and a corresponding
    sshd_config option that tells sshd to require that FIDO keys verify the
    user identity before completing the signing/authentication attempt.
    Whether or not user verification was performed is already baked into the
    signature made on the FIDO token, so this is just plumbing that flag
    through and adding ways to require it.
    
    feedback and ok markus@
    
    OpenBSD-Commit-ID: 3a2313aae153e043d57763d766bb6d55c4e276e6
---
 auth-options.c | 20 +++++++++++++++-----
 auth-options.h |  4 +++-
 auth.c         |  9 +++++----
 auth2-pubkey.c | 18 ++++++++++++++++--
 monitor.c      | 17 +++++++++++++++--
 servconf.c     |  6 +++++-
 servconf.h     |  5 +++--
 sshd.8         | 11 +++++++++--
 sshd_config.5  | 23 +++++++++++++++++------
 9 files changed, 88 insertions(+), 25 deletions(-)

diff --git a/auth-options.c b/auth-options.c
index 696ba6ac..98afdf5f 100644
--- a/auth-options.c
+++ b/auth-options.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth-options.c,v 1.92 2020/03/06 18:15:38 markus Exp $ */
+/* $OpenBSD: auth-options.c,v 1.93 2020/08/27 01:07:09 djm Exp $ */
 /*
  * Copyright (c) 2018 Damien Miller <djm at mindrot.org>
  *
@@ -119,7 +119,10 @@ cert_option_list(struct sshauthopt *opts, struct sshbuf *oblob,
 			}
 		}
 		if (!found && (which & OPTIONS_CRITICAL) != 0) {
-			if (strcmp(name, "force-command") == 0) {
+			if (strcmp(name, "verify-required") == 0) {
+				opts->require_verify = 1;
+				found = 1;
+			} else if (strcmp(name, "force-command") == 0) {
 				if ((r = sshbuf_get_cstring(data, &command,
 				    NULL)) != 0) {
 					error("Unable to parse \"%s\" "
@@ -134,8 +137,7 @@ cert_option_list(struct sshauthopt *opts, struct sshbuf *oblob,
 				}
 				opts->force_command = command;
 				found = 1;
-			}
-			if (strcmp(name, "source-address") == 0) {
+			} else if (strcmp(name, "source-address") == 0) {
 				if ((r = sshbuf_get_cstring(data, &allowed,
 				    NULL)) != 0) {
 					error("Unable to parse \"%s\" "
@@ -351,6 +353,8 @@ sshauthopt_parse(const char *opts, const char **errstrp)
 			ret->permit_x11_forwarding_flag = r == 1;
 		} else if ((r = opt_flag("touch-required", 1, &opts)) != -1) {
 			ret->no_require_user_presence = r != 1; /* NB. flip */
+		} else if ((r = opt_flag("verify-required", 1, &opts)) != -1) {
+			ret->require_verify = r == 1;
 		} else if ((r = opt_flag("pty", 1, &opts)) != -1) {
 			ret->permit_pty_flag = r == 1;
 		} else if ((r = opt_flag("user-rc", 1, &opts)) != -1) {
@@ -572,6 +576,7 @@ sshauthopt_merge(const struct sshauthopt *primary,
 	}
 
 #define OPTFLAG_AND(x) ret->x = (primary->x == 1) && (additional->x == 1)
+#define OPTFLAG_OR(x) ret->x = (primary->x == 1) || (additional->x == 1)
 	/* Permissive flags are logical-AND (i.e. must be set in both) */
 	OPTFLAG_AND(permit_port_forwarding_flag);
 	OPTFLAG_AND(permit_agent_forwarding_flag);
@@ -579,6 +584,8 @@ sshauthopt_merge(const struct sshauthopt *primary,
 	OPTFLAG_AND(permit_pty_flag);
 	OPTFLAG_AND(permit_user_rc);
 	OPTFLAG_AND(no_require_user_presence);
+	/* Restrictive flags are logical-OR (i.e. must be set in either) */
+	OPTFLAG_OR(require_verify);
 #undef OPTFLAG_AND
 
 	/* Earliest expiry time should win */
@@ -649,6 +656,7 @@ sshauthopt_copy(const struct sshauthopt *orig)
 	OPTSCALAR(force_tun_device);
 	OPTSCALAR(valid_before);
 	OPTSCALAR(no_require_user_presence);
+	OPTSCALAR(require_verify);
 #undef OPTSCALAR
 #define OPTSTRING(x) \
 	do { \
@@ -781,7 +789,8 @@ sshauthopt_serialise(const struct sshauthopt *opts, struct sshbuf *m,
 	    (r = sshbuf_put_u8(m, opts->permit_user_rc)) != 0 ||
 	    (r = sshbuf_put_u8(m, opts->restricted)) != 0 ||
 	    (r = sshbuf_put_u8(m, opts->cert_authority)) != 0 ||
-	    (r = sshbuf_put_u8(m, opts->no_require_user_presence)) != 0)
+	    (r = sshbuf_put_u8(m, opts->no_require_user_presence)) != 0 ||
+	    (r = sshbuf_put_u8(m, opts->require_verify)) != 0)
 		return r;
 
 	/* Simple integer options */
@@ -844,6 +853,7 @@ sshauthopt_deserialise(struct sshbuf *m, struct sshauthopt **optsp)
 	OPT_FLAG(restricted);
 	OPT_FLAG(cert_authority);
 	OPT_FLAG(no_require_user_presence);
+	OPT_FLAG(require_verify);
 #undef OPT_FLAG
 
 	/* Simple integer options */
diff --git a/auth-options.h b/auth-options.h
index d96ffede..118a3208 100644
--- a/auth-options.h
+++ b/auth-options.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth-options.h,v 1.29 2019/11/25 00:54:23 djm Exp $ */
+/* $OpenBSD: auth-options.h,v 1.30 2020/08/27 01:07:09 djm Exp $ */
 
 /*
  * Copyright (c) 2018 Damien Miller <djm at mindrot.org>
@@ -71,6 +71,8 @@ struct sshauthopt {
 
 	/* Key requires user presence asserted */
 	int no_require_user_presence;
+	/* Key requires user verification (e.g. PIN) */
+	int require_verify;
 };
 
 struct sshauthopt *sshauthopt_new(void);
diff --git a/auth.c b/auth.c
index 086b8ebb..9a5498b6 100644
--- a/auth.c
+++ b/auth.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth.c,v 1.146 2020/01/31 22:42:45 djm Exp $ */
+/* $OpenBSD: auth.c,v 1.147 2020/08/27 01:07:09 djm Exp $ */
 /*
  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
  *
@@ -1006,21 +1006,22 @@ auth_log_authopts(const char *loc, const struct sshauthopt *opts, int do_remote)
 
 	snprintf(buf, sizeof(buf), "%d", opts->force_tun_device);
 	/* Try to keep this alphabetically sorted */
-	snprintf(msg, sizeof(msg), "key options:%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
+	snprintf(msg, sizeof(msg), "key options:%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
 	    opts->permit_agent_forwarding_flag ? " agent-forwarding" : "",
 	    opts->force_command == NULL ? "" : " command",
 	    do_env ?  " environment" : "",
 	    opts->valid_before == 0 ? "" : "expires",
+	    opts->no_require_user_presence ? " no-touch-required" : "",
 	    do_permitopen ?  " permitopen" : "",
 	    do_permitlisten ?  " permitlisten" : "",
 	    opts->permit_port_forwarding_flag ? " port-forwarding" : "",
 	    opts->cert_principals == NULL ? "" : " principals",
 	    opts->permit_pty_flag ? " pty" : "",
+	    opts->require_verify ? " uv" : "",
 	    opts->force_tun_device == -1 ? "" : " tun=",
 	    opts->force_tun_device == -1 ? "" : buf,
 	    opts->permit_user_rc ? " user-rc" : "",
-	    opts->permit_x11_forwarding_flag ? " x11-forwarding" : "",
-	    opts->no_require_user_presence ? " no-touch-required" : "");
+	    opts->permit_x11_forwarding_flag ? " x11-forwarding" : "");
 
 	debug("%s: %s", loc, msg);
 	if (do_remote)
diff --git a/auth2-pubkey.c b/auth2-pubkey.c
index 815ea0f2..c3ecd9af 100644
--- a/auth2-pubkey.c
+++ b/auth2-pubkey.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth2-pubkey.c,v 1.99 2020/02/06 22:30:54 naddy Exp $ */
+/* $OpenBSD: auth2-pubkey.c,v 1.100 2020/08/27 01:07:09 djm Exp $ */
 /*
  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
  *
@@ -97,7 +97,7 @@ userauth_pubkey(struct ssh *ssh)
 	u_char *pkblob = NULL, *sig = NULL, have_sig;
 	size_t blen, slen;
 	int r, pktype;
-	int req_presence = 0, authenticated = 0;
+	int req_presence = 0, req_verify = 0, authenticated = 0;
 	struct sshauthopt *authopts = NULL;
 	struct sshkey_sig_details *sig_details = NULL;
 
@@ -239,6 +239,20 @@ userauth_pubkey(struct ssh *ssh)
 				authenticated = 0;
 				goto done;
 			}
+			req_verify = (options.pubkey_auth_options &
+			    PUBKEYAUTH_VERIFY_REQUIRED) ||
+			    authopts->require_verify;
+			if (req_verify && (sig_details->sk_flags &
+			    SSH_SK_USER_VERIFICATION_REQD) == 0) {
+				error("public key %s signature for %s%s from "
+				    "%.128s port %d rejected: user "
+				    "verification 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/monitor.c b/monitor.c
index 7c3e6aaf..4cf79dfc 100644
--- a/monitor.c
+++ b/monitor.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: monitor.c,v 1.213 2020/08/27 01:06:18 djm Exp $ */
+/* $OpenBSD: monitor.c,v 1.214 2020/08/27 01:07:09 djm Exp $ */
 /*
  * Copyright 2002 Niels Provos <provos at citi.umich.edu>
  * Copyright 2002 Markus Friedl <markus at openbsd.org>
@@ -1387,7 +1387,8 @@ mm_answer_keyverify(struct ssh *ssh, int sock, struct sshbuf *m)
 	const u_char *signature, *data, *blob;
 	char *sigalg = NULL, *fp = NULL;
 	size_t signaturelen, datalen, bloblen;
-	int r, ret, req_presence = 0, valid_data = 0, encoded_ret;
+	int r, ret, req_presence = 0, req_verify = 0, valid_data = 0;
+	int encoded_ret;
 	struct sshkey_sig_details *sig_details = NULL;
 
 	if ((r = sshbuf_get_string_direct(m, &blob, &bloblen)) != 0 ||
@@ -1452,6 +1453,18 @@ mm_answer_keyverify(struct ssh *ssh, int sock, struct sshbuf *m)
 			    ssh_remote_port(ssh));
 			ret = SSH_ERR_SIGNATURE_INVALID;
 		}
+		req_verify = (options.pubkey_auth_options &
+		    PUBKEYAUTH_VERIFY_REQUIRED) || key_opts->require_verify;
+		if (req_verify &&
+		    (sig_details->sk_flags & SSH_SK_USER_VERIFICATION_REQD) == 0) {
+			error("public key %s %s signature for %s%s from %.128s "
+			    "port %d rejected: user verification 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);
 
diff --git a/servconf.c b/servconf.c
index 67581ccf..1bc7ee31 100644
--- a/servconf.c
+++ b/servconf.c
@@ -1,5 +1,5 @@
 
-/* $OpenBSD: servconf.c,v 1.367 2020/07/05 23:59:45 djm Exp $ */
+/* $OpenBSD: servconf.c,v 1.368 2020/08/27 01:07:09 djm Exp $ */
 /*
  * Copyright (c) 1995 Tatu Ylonen <ylo at cs.hut.fi>, Espoo, Finland
  *                    All rights reserved
@@ -1527,6 +1527,8 @@ process_server_config_line_depth(ServerOptions *options, char *line,
 				continue;
 			if (strcasecmp(arg, "touch-required") == 0)
 				value |= PUBKEYAUTH_TOUCH_REQUIRED;
+			else if (strcasecmp(arg, "verify-required") == 0)
+				value |= PUBKEYAUTH_VERIFY_REQUIRED;
 			else {
 				fatal("%s line %d: unsupported "
 				    "PubkeyAuthOptions option %s",
@@ -2937,5 +2939,7 @@ dump_config(ServerOptions *o)
 		printf(" none");
 	if (o->pubkey_auth_options & PUBKEYAUTH_TOUCH_REQUIRED)
 		printf(" touch-required");
+	if (o->pubkey_auth_options & PUBKEYAUTH_VERIFY_REQUIRED)
+		printf(" verify-required");
 	printf("\n");
 }
diff --git a/servconf.h b/servconf.h
index 8422f3f5..1df8f3db 100644
--- a/servconf.h
+++ b/servconf.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: servconf.h,v 1.145 2020/07/05 23:59:45 djm Exp $ */
+/* $OpenBSD: servconf.h,v 1.146 2020/08/27 01:07:10 djm Exp $ */
 
 /*
  * Author: Tatu Ylonen <ylo at cs.hut.fi>
@@ -50,7 +50,8 @@
 #define INTERNAL_SFTP_NAME	"internal-sftp"
 
 /* PubkeyAuthOptions flags */
-#define PUBKEYAUTH_TOUCH_REQUIRED	1
+#define PUBKEYAUTH_TOUCH_REQUIRED	(1)
+#define PUBKEYAUTH_VERIFY_REQUIRED	(1<<1)
 
 struct ssh;
 struct fwd_perm_list;
diff --git a/sshd.8 b/sshd.8
index c5f8987d..b2fad56d 100644
--- a/sshd.8
+++ b/sshd.8
@@ -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.8,v 1.312 2020/01/25 06:03:10 djm Exp $
-.Dd $Mdocdate: January 25 2020 $
+.\" $OpenBSD: sshd.8,v 1.313 2020/08/27 01:07:10 djm Exp $
+.Dd $Mdocdate: August 27 2020 $
 .Dt SSHD 8
 .Os
 .Sh NAME
@@ -631,6 +631,13 @@ This option only makes sense for the FIDO authenticator algorithms
 .Cm ecdsa-sk
 and
 .Cm ed25519-sk .
+.It Cm verify-required
+Require that signatures made using this key attest that they verified
+the user, e.g. via a PIN.
+This option only makes sense for the FIDO authenticator algorithms
+.Cm ecdsa-sk
+and
+.Cm ed25519-sk .
 .It Cm restrict
 Enable all restrictions, i.e. disable port, agent and X11 forwarding,
 as well as disabling PTY allocation
diff --git a/sshd_config.5 b/sshd_config.5
index 17d8c130..a1898baa 100644
--- a/sshd_config.5
+++ b/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.312 2020/05/29 05:37:03 djm Exp $
-.Dd $Mdocdate: May 29 2020 $
+.\" $OpenBSD: sshd_config.5,v 1.313 2020/08/27 01:07:10 djm Exp $
+.Dd $Mdocdate: August 27 2020 $
 .Dt SSHD_CONFIG 5
 .Os
 .Sh NAME
@@ -1476,11 +1476,12 @@ The list of available key types may also be obtained using
 .Qq ssh -Q PubkeyAcceptedKeyTypes .
 .It Cm PubkeyAuthOptions
 Sets one or more public key authentication options.
-Two option keywords are currently supported:
+The supported keywords are:
 .Cm none
-(the default; indicating no additional options are enabled)
+(the default; indicating no additional options are enabled),
+.Cm touch-required
 and
-.Cm touch-required .
+.Cm verify-required .
 .Pp
 The
 .Cm touch-required
@@ -1497,7 +1498,17 @@ requires user presence unless overridden with an authorized_keys option.
 The
 .Cm touch-required
 flag disables this override.
-This option has no effect for other, non-authenticator public key types.
+.Pp
+The
+.Cm verify-required
+option requires a FIDO key signature attest that verified the user, e.g.
+via a PIN.
+.Pp
+Neither the
+.Cm touch-required
+or
+.Cm verify-required
+options have any effect for other, non-FIDO public key types.
 .It Cm PubkeyAuthentication
 Specifies whether public key authentication is allowed.
 The default is

-- 
To stop receiving notification emails like this one, please contact
djm at mindrot.org.


More information about the openssh-commits mailing list