[openssh-commits] [openssh] 09/17: upstream: sshd side of hostbound public key auth

git+noreply at mindrot.org git+noreply at mindrot.org
Mon Dec 20 09:28:34 AEDT 2021


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

djm pushed a commit to branch master
in repository openssh.

commit 288fd0218dbfdcb05d9fbd1885904bed9b6d42e6
Author: djm at openbsd.org <djm at openbsd.org>
Date:   Sun Dec 19 22:12:30 2021 +0000

    upstream: sshd side of hostbound public key auth
    
    This is identical to the standard "publickey" method, but it also includes
    the initial server hostkey in the message signed by the client.
    
    feedback / ok markus@
    
    OpenBSD-Commit-ID: 7ea01bb7238a560c1bfb426fda0c10a8aac07862
---
 auth2-pubkey.c | 37 +++++++++++++++++++++++++++++--------
 monitor.c      | 26 +++++++++++++++++++++-----
 2 files changed, 50 insertions(+), 13 deletions(-)

diff --git a/auth2-pubkey.c b/auth2-pubkey.c
index ed3e74c3..9c2298fc 100644
--- a/auth2-pubkey.c
+++ b/auth2-pubkey.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth2-pubkey.c,v 1.111 2021/12/19 22:12:07 djm Exp $ */
+/* $OpenBSD: auth2-pubkey.c,v 1.112 2021/12/19 22:12:30 djm Exp $ */
 /*
  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
  *
@@ -67,6 +67,7 @@
 #include "authfile.h"
 #include "match.h"
 #include "ssherr.h"
+#include "kex.h"
 #include "channels.h" /* XXX for session.h */
 #include "session.h" /* XXX for child_set_env(); refactor? */
 #include "sk-api.h"
@@ -91,19 +92,34 @@ userauth_pubkey(struct ssh *ssh, const char *method)
 	Authctxt *authctxt = ssh->authctxt;
 	struct passwd *pw = authctxt->pw;
 	struct sshbuf *b = NULL;
-	struct sshkey *key = NULL;
+	struct sshkey *key = NULL, *hostkey = NULL;
 	char *pkalg = NULL, *userstyle = NULL, *key_s = NULL, *ca_s = NULL;
 	u_char *pkblob = NULL, *sig = NULL, have_sig;
 	size_t blen, slen;
-	int r, pktype;
+	int hostbound, r, pktype;
 	int req_presence = 0, req_verify = 0, authenticated = 0;
 	struct sshauthopt *authopts = NULL;
 	struct sshkey_sig_details *sig_details = NULL;
 
+	hostbound = strcmp(method, "publickey-hostbound-v00 at openssh.com") == 0;
+
 	if ((r = sshpkt_get_u8(ssh, &have_sig)) != 0 ||
 	    (r = sshpkt_get_cstring(ssh, &pkalg, NULL)) != 0 ||
 	    (r = sshpkt_get_string(ssh, &pkblob, &blen)) != 0)
-		fatal_fr(r, "parse packet");
+		fatal_fr(r, "parse %s packet", method);
+
+	/* hostbound auth includes the hostkey offered at initial KEX */
+	if (hostbound) {
+		if ((r = sshpkt_getb_froms(ssh, &b)) != 0 ||
+		    (r = sshkey_fromb(b, &hostkey)) != 0)
+			fatal_fr(r, "parse %s hostkey", method);
+		if (ssh->kex->initial_hostkey == NULL)
+			fatal_f("internal error: initial hostkey not recorded");
+		if (!sshkey_equal(hostkey, ssh->kex->initial_hostkey))
+			fatal_f("%s packet contained wrong host key", method);
+		sshbuf_free(b);
+		b = NULL;
+	}
 
 	if (log_level_get() >= SYSLOG_LEVEL_DEBUG2) {
 		char *keystring;
@@ -166,7 +182,8 @@ userauth_pubkey(struct ssh *ssh, const char *method)
 		ca_s = format_key(key->cert->signature_key);
 
 	if (have_sig) {
-		debug3_f("have %s signature for %s%s%s", pkalg, key_s,
+		debug3_f("%s have %s signature for %s%s%s",
+		    method, pkalg, key_s,
 		    ca_s == NULL ? "" : " CA ", ca_s == NULL ? "" : ca_s);
 		if ((r = sshpkt_get_string(ssh, &sig, &slen)) != 0 ||
 		    (r = sshpkt_get_end(ssh)) != 0)
@@ -196,7 +213,10 @@ userauth_pubkey(struct ssh *ssh, const char *method)
 		    (r = sshbuf_put_u8(b, have_sig)) != 0 ||
 		    (r = sshbuf_put_cstring(b, pkalg)) != 0 ||
 		    (r = sshbuf_put_string(b, pkblob, blen)) != 0)
-			fatal_fr(r, "reconstruct packet");
+			fatal_fr(r, "reconstruct %s packet", method);
+		if (hostbound &&
+		    (r = sshkey_puts(ssh->kex->initial_hostkey, b)) != 0)
+			fatal_fr(r, "reconstruct %s packet", method);
 #ifdef DEBUG_PK
 		sshbuf_dump(b, stderr);
 #endif
@@ -246,7 +266,7 @@ userauth_pubkey(struct ssh *ssh, const char *method)
 		}
 		auth2_record_key(authctxt, authenticated, key);
 	} else {
-		debug_f("test pkalg %s pkblob %s%s%s", pkalg, key_s,
+		debug_f("%s test pkalg %s pkblob %s%s%s", method, pkalg, key_s,
 		    ca_s == NULL ? "" : " CA ", ca_s == NULL ? "" : ca_s);
 
 		if ((r = sshpkt_get_end(ssh)) != 0)
@@ -285,6 +305,7 @@ done:
 	sshbuf_free(b);
 	sshauthopt_free(authopts);
 	sshkey_free(key);
+	sshkey_free(hostkey);
 	free(userstyle);
 	free(pkalg);
 	free(pkblob);
@@ -1067,7 +1088,7 @@ user_key_allowed(struct ssh *ssh, struct passwd *pw, struct sshkey *key,
 
 Authmethod method_pubkey = {
 	"publickey",
-	NULL,
+	"publickey-hostbound-v00 at openssh.com",
 	userauth_pubkey,
 	&options.pubkey_authentication
 };
diff --git a/monitor.c b/monitor.c
index 74c803e1..a6429852 100644
--- a/monitor.c
+++ b/monitor.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: monitor.c,v 1.228 2021/08/11 05:20:17 djm Exp $ */
+/* $OpenBSD: monitor.c,v 1.229 2021/12/19 22:12:30 djm Exp $ */
 /*
  * Copyright 2002 Niels Provos <provos at citi.umich.edu>
  * Copyright 2002 Markus Friedl <markus at openbsd.org>
@@ -1246,11 +1246,12 @@ static int
 monitor_valid_userblob(struct ssh *ssh, const u_char *data, u_int datalen)
 {
 	struct sshbuf *b;
+	struct sshkey *hostkey = NULL;
 	const u_char *p;
 	char *userstyle, *cp;
 	size_t len;
 	u_char type;
-	int r, fail = 0;
+	int hostbound = 0, r, fail = 0;
 
 	if ((b = sshbuf_from(data, datalen)) == NULL)
 		fatal_f("sshbuf_from");
@@ -1291,19 +1292,34 @@ monitor_valid_userblob(struct ssh *ssh, const u_char *data, u_int datalen)
 	if ((r = sshbuf_skip_string(b)) != 0 ||	/* service */
 	    (r = sshbuf_get_cstring(b, &cp, NULL)) != 0)
 		fatal_fr(r, "parse method");
-	if (strcmp("publickey", cp) != 0)
-		fail++;
+	if (strcmp("publickey", cp) != 0) {
+		if (strcmp("publickey-hostbound-v00 at openssh.com", cp) == 0)
+			hostbound = 1;
+		else
+			fail++;
+	}
 	free(cp);
 	if ((r = sshbuf_get_u8(b, &type)) != 0)
 		fatal_fr(r, "parse pktype");
 	if (type == 0)
 		fail++;
 	if ((r = sshbuf_skip_string(b)) != 0 ||	/* pkalg */
-	    (r = sshbuf_skip_string(b)) != 0)	/* pkblob */
+	    (r = sshbuf_skip_string(b)) != 0 ||	/* pkblob */
+	    (hostbound && (r = sshkey_froms(b, &hostkey)) != 0))
 		fatal_fr(r, "parse pk");
 	if (sshbuf_len(b) != 0)
 		fail++;
 	sshbuf_free(b);
+	if (hostkey != NULL) {
+		/*
+		 * Ensure this is actually one of our hostkeys; unfortunately
+		 * can't check ssh->kex->initial_hostkey directly at this point
+		 * as packet state has not yet been exported to monitor.
+		 */
+		if (get_hostkey_index(hostkey, 1, ssh) == -1)
+			fatal_f("hostbound hostkey does not match");
+		sshkey_free(hostkey);
+	}
 	return (fail == 0);
 }
 

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


More information about the openssh-commits mailing list