[openssh-commits] [openssh] 03/07: upstream: Add a sshd_config PubkeyAuthOptions directive

git+noreply at mindrot.org git+noreply at mindrot.org
Mon Nov 25 12:26:02 AEDT 2019


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

djm pushed a commit to branch master
in repository openssh.

commit 0fddf2967ac51d518e300408a0d7e6adf4cd2634
Author: djm at openbsd.org <djm at openbsd.org>
Date:   Mon Nov 25 00:52:46 2019 +0000

    upstream: 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@
    
    OpenBSD-Commit-ID: 46e434a49802d4ed82bc0aa38cb985c198c407de
---
 auth2-pubkey.c | 22 +++++++++++++++++---
 monitor.c      | 63 ++++++++++++++++++++++++++++++++++++----------------------
 servconf.c     | 33 ++++++++++++++++++++++++++++--
 servconf.h     |  6 +++++-
 sshd_config.5  | 27 +++++++++++++++++++++++--
 5 files changed, 119 insertions(+), 32 deletions(-)

diff --git a/auth2-pubkey.c b/auth2-pubkey.c
index 2b698670..0ef982a4 100644
--- a/auth2-pubkey.c
+++ b/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.
  *
@@ -68,6 +68,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;
@@ -96,7 +97,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;
 
@@ -217,10 +218,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/monitor.c b/monitor.c
index 40ff43ee..9b171c44 100644
--- a/monitor.c
+++ b/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 at citi.umich.edu>
  * Copyright 2002 Markus Friedl <markus at openbsd.org>
@@ -95,6 +95,7 @@
 #include "authfd.h"
 #include "match.h"
 #include "ssherr.h"
+#include "sk-api.h"
 
 #ifdef GSSAPI
 static Gssctxt *gsscontext = NULL;
@@ -542,7 +543,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 ||
@@ -1247,7 +1248,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;
@@ -1256,10 +1257,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);
@@ -1314,8 +1313,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;
@@ -1324,10 +1323,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) ||
@@ -1387,15 +1385,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));
 
@@ -1430,23 +1428,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) : "");
+
+	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);
 
-	free(blob);
-	free(signature);
-	free(data);
-	free(sigalg);
-
 	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 */
@@ -1462,6 +1473,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/servconf.c b/servconf.c
index e2f44d38..1f3beab4 100644
--- a/servconf.c
+++ b/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 at cs.hut.fi>, Espoo, Finland
  *                    All rights reserved
@@ -118,6 +118,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;
@@ -341,6 +342,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)
@@ -509,7 +512,7 @@ typedef enum {
 	sAuthenticationMethods, sHostKeyAgent, sPermitUserRC,
 	sStreamLocalBindMask, sStreamLocalBindUnlink,
 	sAllowStreamLocalForwarding, sFingerprintHash, sDisableForwarding,
-	sExposeAuthInfo, sRDomain,
+	sExposeAuthInfo, sRDomain, sPubkeyAuthOptions,
 	sDeprecated, sIgnore, sUnsupported
 } ServerOpCodes;
 
@@ -551,6 +554,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 },
@@ -1468,6 +1472,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;
@@ -2290,6 +2312,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);
@@ -2711,4 +2734,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/servconf.h b/servconf.h
index 5483da05..9f202260 100644
--- a/servconf.h
+++ b/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 at 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/sshd_config.5 b/sshd_config.5
index 5052ca20..60077e39 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.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
@@ -1444,6 +1444,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

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


More information about the openssh-commits mailing list