summaryrefslogtreecommitdiffstats
path: root/meta/recipes-connectivity/openssh/openssh/CVE-2023-38408-05.patch
blob: 0ddbdc68d45dc82cd4f53c51a84e9a6ca99a3652 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
From a6cee3905edf070c0de135d3f2ee5b74da1dbd28 Mon Sep 17 00:00:00 2001
From: "djm@openbsd.org" <djm@openbsd.org>
Date: Tue, 26 May 2020 01:26:58 +0000
Subject: [PATCH 05/12] upstream: Restrict ssh-agent from signing web
 challenges for FIDO

keys.

When signing messages in ssh-agent using a FIDO key that has an
application string that does not start with "ssh:", ensure that the
message being signed is one of the forms expected for the SSH protocol
(currently pubkey authentication and sshsig signatures).

This prevents ssh-agent forwarding on a host that has FIDO keys
attached granting the ability for the remote side to sign challenges
for web authentication using those keys too.

Note that the converse case of web browsers signing SSH challenges is
already precluded because no web RP can have the "ssh:" prefix in the
application string that we require.

ok markus@

OpenBSD-Commit-ID: 9ab6012574ed0352d2f097d307f4a988222d1b19

Upstream-Status: Backport [https://github.com/openssh/openssh-portable/commit/0c111eb84efba7c2a38b2cc3278901a0123161b9]
CVE: CVE-2023-38408
Signed-off-by: Shubham Kulkarni <skulkarni@mvista.com>
---
 ssh-agent.c | 110 +++++++++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 100 insertions(+), 10 deletions(-)

diff --git a/ssh-agent.c b/ssh-agent.c
index ceb348c..1794f35 100644
--- a/ssh-agent.c
+++ b/ssh-agent.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh-agent.c,v 1.255 2020/02/06 22:30:54 naddy Exp $ */
+/* $OpenBSD: ssh-agent.c,v 1.258 2020/05/26 01:26:58 djm Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -77,6 +77,7 @@

 #include "xmalloc.h"
 #include "ssh.h"
+#include "ssh2.h"
 #include "sshbuf.h"
 #include "sshkey.h"
 #include "authfd.h"
@@ -167,6 +168,9 @@ static long lifetime = 0;

 static int fingerprint_hash = SSH_FP_HASH_DEFAULT;

+/* Refuse signing of non-SSH messages for web-origin FIDO keys */
+static int restrict_websafe = 1;
+
 static void
 close_socket(SocketEntry *e)
 {
@@ -282,6 +286,80 @@ agent_decode_alg(struct sshkey *key, u_int flags)
	return NULL;
 }

+/*
+ * This function inspects a message to be signed by a FIDO key that has a
+ * web-like application string (i.e. one that does not begin with "ssh:".
+ * It checks that the message is one of those expected for SSH operations
+ * (pubkey userauth, sshsig, CA key signing) to exclude signing challenges
+ * for the web.
+ */
+static int
+check_websafe_message_contents(struct sshkey *key,
+    const u_char *msg, size_t len)
+{
+	int matched = 0;
+	struct sshbuf *b;
+	u_char m, n;
+	char *cp1 = NULL, *cp2 = NULL;
+	int r;
+	struct sshkey *mkey = NULL;
+
+	if ((b = sshbuf_from(msg, len)) == NULL)
+		fatal("%s: sshbuf_new", __func__);
+
+	/* SSH userauth request */
+	if ((r = sshbuf_get_string_direct(b, NULL, NULL)) == 0 && /* sess_id */
+	    (r = sshbuf_get_u8(b, &m)) == 0 && /* SSH2_MSG_USERAUTH_REQUEST */
+	    (r = sshbuf_get_cstring(b, NULL, NULL)) == 0 && /* server user */
+	    (r = sshbuf_get_cstring(b, &cp1, NULL)) == 0 && /* service */
+	    (r = sshbuf_get_cstring(b, &cp2, NULL)) == 0 && /* method */
+	    (r = sshbuf_get_u8(b, &n)) == 0 && /* sig-follows */
+	    (r = sshbuf_get_cstring(b, NULL, NULL)) == 0 && /* alg */
+	    (r = sshkey_froms(b, &mkey)) == 0 && /* key */
+	    sshbuf_len(b) == 0) {
+		debug("%s: parsed userauth", __func__);
+		if (m == SSH2_MSG_USERAUTH_REQUEST && n == 1 &&
+		    strcmp(cp1, "ssh-connection") == 0 &&
+		    strcmp(cp2, "publickey") == 0 &&
+		    sshkey_equal(key, mkey)) {
+			debug("%s: well formed userauth", __func__);
+			matched = 1;
+		}
+	}
+	free(cp1);
+	free(cp2);
+	sshkey_free(mkey);
+	sshbuf_free(b);
+	if (matched)
+		return 1;
+
+	if ((b = sshbuf_from(msg, len)) == NULL)
+		fatal("%s: sshbuf_new", __func__);
+	cp1 = cp2 = NULL;
+	mkey = NULL;
+
+	/* SSHSIG */
+	if ((r = sshbuf_cmp(b, 0, "SSHSIG", 6)) == 0 &&
+	    (r = sshbuf_consume(b, 6)) == 0 &&
+	    (r = sshbuf_get_cstring(b, NULL, NULL)) == 0 && /* namespace */
+	    (r = sshbuf_get_string_direct(b, NULL, NULL)) == 0 && /* reserved */
+	    (r = sshbuf_get_cstring(b, NULL, NULL)) == 0 && /* hashalg */
+	    (r = sshbuf_get_string_direct(b, NULL, NULL)) == 0 && /* H(msg) */
+	    sshbuf_len(b) == 0) {
+		debug("%s: parsed sshsig", __func__);
+		matched = 1;
+	}
+
+	sshbuf_free(b);
+	if (matched)
+		return 1;
+
+	/* XXX CA signature operation */
+
+	error("web-origin key attempting to sign non-SSH message");
+	return 0;
+}
+
 /* ssh2 only */
 static void
 process_sign_request2(SocketEntry *e)
@@ -314,14 +392,20 @@ process_sign_request2(SocketEntry *e)
		verbose("%s: user refused key", __func__);
		goto send;
	}
-	if (sshkey_is_sk(id->key) &&
-	    (id->key->sk_flags & SSH_SK_USER_PRESENCE_REQD)) {
-		if ((fp = sshkey_fingerprint(key, SSH_FP_HASH_DEFAULT,
-		    SSH_FP_DEFAULT)) == NULL)
-			fatal("%s: fingerprint failed", __func__);
-		notifier = notify_start(0,
-		    "Confirm user presence for key %s %s",
-		    sshkey_type(id->key), fp);
+	if (sshkey_is_sk(id->key)) {
+		if (strncmp(id->key->sk_application, "ssh:", 4) != 0 &&
+		    !check_websafe_message_contents(key, data, dlen)) {
+			/* error already logged */
+			goto send;
+		}
+		if ((id->key->sk_flags & SSH_SK_USER_PRESENCE_REQD)) {
+			if ((fp = sshkey_fingerprint(key, SSH_FP_HASH_DEFAULT,
+			    SSH_FP_DEFAULT)) == NULL)
+				fatal("%s: fingerprint failed", __func__);
+			notifier = notify_start(0,
+			    "Confirm user presence for key %s %s",
+			    sshkey_type(id->key), fp);
+		}
	}
	if ((r = sshkey_sign(id->key, &signature, &slen,
	    data, dlen, agent_decode_alg(key, flags),
@@ -1214,7 +1298,7 @@ main(int ac, char **av)
	__progname = ssh_get_progname(av[0]);
	seed_rng();

-	while ((ch = getopt(ac, av, "cDdksE:a:P:t:")) != -1) {
+	while ((ch = getopt(ac, av, "cDdksE:a:O:P:t:")) != -1) {
		switch (ch) {
		case 'E':
			fingerprint_hash = ssh_digest_alg_by_name(optarg);
@@ -1229,6 +1313,12 @@ main(int ac, char **av)
		case 'k':
			k_flag++;
			break;
+		case 'O':
+			if (strcmp(optarg, "no-restrict-websafe") == 0)
+				restrict_websafe  = 0;
+			else
+				fatal("Unknown -O option");
+			break;
		case 'P':
			if (provider_whitelist != NULL)
				fatal("-P option already specified");
--
2.41.0