summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordjm@openbsd.org <djm@openbsd.org>2021-12-19 22:12:30 +0000
committerDamien Miller <djm@mindrot.org>2021-12-20 09:28:07 +1100
commit288fd0218dbfdcb05d9fbd1885904bed9b6d42e6 (patch)
tree7e31fb89f6384e5312308562c1b7609eb3011832
parentdbb339f015c33d63484261d140c84ad875a9e548 (diff)
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
-rw-r--r--auth2-pubkey.c37
-rw-r--r--monitor.c26
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@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@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@citi.umich.edu>
* Copyright 2002 Markus Friedl <markus@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@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);
}