diff options
Diffstat (limited to 'meta/recipes-connectivity/openssh/openssh/CVE-2023-38408-08.patch')
-rw-r--r-- | meta/recipes-connectivity/openssh/openssh/CVE-2023-38408-08.patch | 315 |
1 files changed, 315 insertions, 0 deletions
diff --git a/meta/recipes-connectivity/openssh/openssh/CVE-2023-38408-08.patch b/meta/recipes-connectivity/openssh/openssh/CVE-2023-38408-08.patch new file mode 100644 index 0000000000..141c8113bf --- /dev/null +++ b/meta/recipes-connectivity/openssh/openssh/CVE-2023-38408-08.patch | |||
@@ -0,0 +1,315 @@ | |||
1 | From c30158ea225cf8ad67c3dcc88fa9e4afbf8959a7 Mon Sep 17 00:00:00 2001 | ||
2 | From: "djm@openbsd.org" <djm@openbsd.org> | ||
3 | Date: Tue, 26 Jan 2021 00:53:31 +0000 | ||
4 | Subject: [PATCH 08/12] upstream: more ssh-agent refactoring | ||
5 | |||
6 | Allow confirm_key() to accept an additional reason suffix | ||
7 | |||
8 | Factor publickey userauth parsing out into its own function and allow | ||
9 | it to optionally return things it parsed out of the message to its | ||
10 | caller. | ||
11 | |||
12 | feedback/ok markus@ | ||
13 | |||
14 | OpenBSD-Commit-ID: 29006515617d1aa2d8b85cd2bf667e849146477e | ||
15 | |||
16 | Upstream-Status: Backport [https://github.com/openssh/openssh-portable/commit/e0e8bee8024fa9e31974244d14f03d799e5c0775] | ||
17 | CVE: CVE-2023-38408 | ||
18 | Signed-off-by: Shubham Kulkarni <skulkarni@mvista.com> | ||
19 | --- | ||
20 | ssh-agent.c | 197 ++++++++++++++++++++++++++++++++++------------------ | ||
21 | 1 file changed, 130 insertions(+), 67 deletions(-) | ||
22 | |||
23 | diff --git a/ssh-agent.c b/ssh-agent.c | ||
24 | index 2635bc5..7ad323c 100644 | ||
25 | --- a/ssh-agent.c | ||
26 | +++ b/ssh-agent.c | ||
27 | @@ -1,4 +1,4 @@ | ||
28 | -/* $OpenBSD: ssh-agent.c,v 1.269 2021/01/26 00:47:47 djm Exp $ */ | ||
29 | +/* $OpenBSD: ssh-agent.c,v 1.270 2021/01/26 00:53:31 djm Exp $ */ | ||
30 | /* | ||
31 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | ||
32 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | ||
33 | @@ -216,15 +216,16 @@ lookup_identity(struct sshkey *key) | ||
34 | |||
35 | /* Check confirmation of keysign request */ | ||
36 | static int | ||
37 | -confirm_key(Identity *id) | ||
38 | +confirm_key(Identity *id, const char *extra) | ||
39 | { | ||
40 | char *p; | ||
41 | int ret = -1; | ||
42 | |||
43 | p = sshkey_fingerprint(id->key, fingerprint_hash, SSH_FP_DEFAULT); | ||
44 | if (p != NULL && | ||
45 | - ask_permission("Allow use of key %s?\nKey fingerprint %s.", | ||
46 | - id->comment, p)) | ||
47 | + ask_permission("Allow use of key %s?\nKey fingerprint %s.%s%s", | ||
48 | + id->comment, p, | ||
49 | + extra == NULL ? "" : "\n", extra == NULL ? "" : extra)) | ||
50 | ret = 0; | ||
51 | free(p); | ||
52 | |||
53 | @@ -290,74 +291,133 @@ agent_decode_alg(struct sshkey *key, u_int flags) | ||
54 | } | ||
55 | |||
56 | /* | ||
57 | - * This function inspects a message to be signed by a FIDO key that has a | ||
58 | - * web-like application string (i.e. one that does not begin with "ssh:". | ||
59 | - * It checks that the message is one of those expected for SSH operations | ||
60 | - * (pubkey userauth, sshsig, CA key signing) to exclude signing challenges | ||
61 | - * for the web. | ||
62 | + * Attempt to parse the contents of a buffer as a SSH publickey userauth | ||
63 | + * request, checking its contents for consistency and matching the embedded | ||
64 | + * key against the one that is being used for signing. | ||
65 | + * Note: does not modify msg buffer. | ||
66 | + * Optionally extract the username and session ID from the request. | ||
67 | */ | ||
68 | static int | ||
69 | -check_websafe_message_contents(struct sshkey *key, | ||
70 | - const u_char *msg, size_t len) | ||
71 | +parse_userauth_request(struct sshbuf *msg, const struct sshkey *expected_key, | ||
72 | + char **userp, struct sshbuf **sess_idp) | ||
73 | { | ||
74 | - int matched = 0; | ||
75 | - struct sshbuf *b; | ||
76 | - u_char m, n; | ||
77 | - char *cp1 = NULL, *cp2 = NULL; | ||
78 | + struct sshbuf *b = NULL, *sess_id = NULL; | ||
79 | + char *user = NULL, *service = NULL, *method = NULL, *pkalg = NULL; | ||
80 | int r; | ||
81 | + u_char t, sig_follows; | ||
82 | struct sshkey *mkey = NULL; | ||
83 | |||
84 | - if ((b = sshbuf_from(msg, len)) == NULL) | ||
85 | - fatal("%s: sshbuf_new", __func__); | ||
86 | + if (userp != NULL) | ||
87 | + *userp = NULL; | ||
88 | + if (sess_idp != NULL) | ||
89 | + *sess_idp = NULL; | ||
90 | + if ((b = sshbuf_fromb(msg)) == NULL) | ||
91 | + fatal("%s: sshbuf_fromb", __func__); | ||
92 | |||
93 | /* SSH userauth request */ | ||
94 | - if ((r = sshbuf_get_string_direct(b, NULL, NULL)) == 0 && /* sess_id */ | ||
95 | - (r = sshbuf_get_u8(b, &m)) == 0 && /* SSH2_MSG_USERAUTH_REQUEST */ | ||
96 | - (r = sshbuf_get_cstring(b, NULL, NULL)) == 0 && /* server user */ | ||
97 | - (r = sshbuf_get_cstring(b, &cp1, NULL)) == 0 && /* service */ | ||
98 | - (r = sshbuf_get_cstring(b, &cp2, NULL)) == 0 && /* method */ | ||
99 | - (r = sshbuf_get_u8(b, &n)) == 0 && /* sig-follows */ | ||
100 | - (r = sshbuf_get_cstring(b, NULL, NULL)) == 0 && /* alg */ | ||
101 | - (r = sshkey_froms(b, &mkey)) == 0 && /* key */ | ||
102 | - sshbuf_len(b) == 0) { | ||
103 | - debug("%s: parsed userauth", __func__); | ||
104 | - if (m == SSH2_MSG_USERAUTH_REQUEST && n == 1 && | ||
105 | - strcmp(cp1, "ssh-connection") == 0 && | ||
106 | - strcmp(cp2, "publickey") == 0 && | ||
107 | - sshkey_equal(key, mkey)) { | ||
108 | - debug("%s: well formed userauth", __func__); | ||
109 | - matched = 1; | ||
110 | - } | ||
111 | + if ((r = sshbuf_froms(b, &sess_id)) != 0) | ||
112 | + goto out; | ||
113 | + if (sshbuf_len(sess_id) == 0) { | ||
114 | + r = SSH_ERR_INVALID_FORMAT; | ||
115 | + goto out; | ||
116 | } | ||
117 | - free(cp1); | ||
118 | - free(cp2); | ||
119 | - sshkey_free(mkey); | ||
120 | + if ((r = sshbuf_get_u8(b, &t)) != 0 || /* SSH2_MSG_USERAUTH_REQUEST */ | ||
121 | + (r = sshbuf_get_cstring(b, &user, NULL)) != 0 || /* server user */ | ||
122 | + (r = sshbuf_get_cstring(b, &service, NULL)) != 0 || /* service */ | ||
123 | + (r = sshbuf_get_cstring(b, &method, NULL)) != 0 || /* method */ | ||
124 | + (r = sshbuf_get_u8(b, &sig_follows)) != 0 || /* sig-follows */ | ||
125 | + (r = sshbuf_get_cstring(b, &pkalg, NULL)) != 0 || /* alg */ | ||
126 | + (r = sshkey_froms(b, &mkey)) != 0) /* key */ | ||
127 | + goto out; | ||
128 | + if (t != SSH2_MSG_USERAUTH_REQUEST || | ||
129 | + sig_follows != 1 || | ||
130 | + strcmp(service, "ssh-connection") != 0 || | ||
131 | + !sshkey_equal(expected_key, mkey) || | ||
132 | + sshkey_type_from_name(pkalg) != expected_key->type) { | ||
133 | + r = SSH_ERR_INVALID_FORMAT; | ||
134 | + goto out; | ||
135 | + } | ||
136 | + if (strcmp(method, "publickey") != 0) { | ||
137 | + r = SSH_ERR_INVALID_FORMAT; | ||
138 | + goto out; | ||
139 | + } | ||
140 | + if (sshbuf_len(b) != 0) { | ||
141 | + r = SSH_ERR_INVALID_FORMAT; | ||
142 | + goto out; | ||
143 | + } | ||
144 | + /* success */ | ||
145 | + r = 0; | ||
146 | + debug("%s: well formed userauth", __func__); | ||
147 | + if (userp != NULL) { | ||
148 | + *userp = user; | ||
149 | + user = NULL; | ||
150 | + } | ||
151 | + if (sess_idp != NULL) { | ||
152 | + *sess_idp = sess_id; | ||
153 | + sess_id = NULL; | ||
154 | + } | ||
155 | + out: | ||
156 | sshbuf_free(b); | ||
157 | - if (matched) | ||
158 | - return 1; | ||
159 | + sshbuf_free(sess_id); | ||
160 | + free(user); | ||
161 | + free(service); | ||
162 | + free(method); | ||
163 | + free(pkalg); | ||
164 | + sshkey_free(mkey); | ||
165 | + return r; | ||
166 | +} | ||
167 | |||
168 | - if ((b = sshbuf_from(msg, len)) == NULL) | ||
169 | - fatal("%s: sshbuf_new", __func__); | ||
170 | - cp1 = cp2 = NULL; | ||
171 | - mkey = NULL; | ||
172 | - | ||
173 | - /* SSHSIG */ | ||
174 | - if ((r = sshbuf_cmp(b, 0, "SSHSIG", 6)) == 0 && | ||
175 | - (r = sshbuf_consume(b, 6)) == 0 && | ||
176 | - (r = sshbuf_get_cstring(b, NULL, NULL)) == 0 && /* namespace */ | ||
177 | - (r = sshbuf_get_string_direct(b, NULL, NULL)) == 0 && /* reserved */ | ||
178 | - (r = sshbuf_get_cstring(b, NULL, NULL)) == 0 && /* hashalg */ | ||
179 | - (r = sshbuf_get_string_direct(b, NULL, NULL)) == 0 && /* H(msg) */ | ||
180 | - sshbuf_len(b) == 0) { | ||
181 | - debug("%s: parsed sshsig", __func__); | ||
182 | - matched = 1; | ||
183 | - } | ||
184 | +/* | ||
185 | + * Attempt to parse the contents of a buffer as a SSHSIG signature request. | ||
186 | + * Note: does not modify buffer. | ||
187 | + */ | ||
188 | +static int | ||
189 | +parse_sshsig_request(struct sshbuf *msg) | ||
190 | +{ | ||
191 | + int r; | ||
192 | + struct sshbuf *b; | ||
193 | |||
194 | + if ((b = sshbuf_fromb(msg)) == NULL) | ||
195 | + fatal("%s: sshbuf_fromb", __func__); | ||
196 | + | ||
197 | + if ((r = sshbuf_cmp(b, 0, "SSHSIG", 6)) != 0 || | ||
198 | + (r = sshbuf_consume(b, 6)) != 0 || | ||
199 | + (r = sshbuf_get_cstring(b, NULL, NULL)) != 0 || /* namespace */ | ||
200 | + (r = sshbuf_get_string_direct(b, NULL, NULL)) != 0 || /* reserved */ | ||
201 | + (r = sshbuf_get_cstring(b, NULL, NULL)) != 0 || /* hashalg */ | ||
202 | + (r = sshbuf_get_string_direct(b, NULL, NULL)) != 0) /* H(msg) */ | ||
203 | + goto out; | ||
204 | + if (sshbuf_len(b) != 0) { | ||
205 | + r = SSH_ERR_INVALID_FORMAT; | ||
206 | + goto out; | ||
207 | + } | ||
208 | + /* success */ | ||
209 | + r = 0; | ||
210 | + out: | ||
211 | sshbuf_free(b); | ||
212 | - if (matched) | ||
213 | + return r; | ||
214 | +} | ||
215 | + | ||
216 | +/* | ||
217 | + * This function inspects a message to be signed by a FIDO key that has a | ||
218 | + * web-like application string (i.e. one that does not begin with "ssh:". | ||
219 | + * It checks that the message is one of those expected for SSH operations | ||
220 | + * (pubkey userauth, sshsig, CA key signing) to exclude signing challenges | ||
221 | + * for the web. | ||
222 | + */ | ||
223 | +static int | ||
224 | +check_websafe_message_contents(struct sshkey *key, struct sshbuf *data) | ||
225 | +{ | ||
226 | + if (parse_userauth_request(data, key, NULL, NULL) == 0) { | ||
227 | + debug("%s: signed data matches public key userauth request", __func__); | ||
228 | return 1; | ||
229 | + } | ||
230 | + if (parse_sshsig_request(data) == 0) { | ||
231 | + debug("%s: signed data matches SSHSIG signature request", __func__); | ||
232 | + return 1; | ||
233 | + } | ||
234 | |||
235 | - /* XXX CA signature operation */ | ||
236 | + /* XXX check CA signature operation */ | ||
237 | |||
238 | error("web-origin key attempting to sign non-SSH message"); | ||
239 | return 0; | ||
240 | @@ -367,21 +427,22 @@ check_websafe_message_contents(struct sshkey *key, | ||
241 | static void | ||
242 | process_sign_request2(SocketEntry *e) | ||
243 | { | ||
244 | - const u_char *data; | ||
245 | u_char *signature = NULL; | ||
246 | - size_t dlen, slen = 0; | ||
247 | + size_t i, slen = 0; | ||
248 | u_int compat = 0, flags; | ||
249 | int r, ok = -1; | ||
250 | char *fp = NULL; | ||
251 | - struct sshbuf *msg; | ||
252 | + struct sshbuf *msg = NULL, *data = NULL; | ||
253 | struct sshkey *key = NULL; | ||
254 | struct identity *id; | ||
255 | struct notifier_ctx *notifier = NULL; | ||
256 | |||
257 | - if ((msg = sshbuf_new()) == NULL) | ||
258 | + debug("%s: entering", __func__); | ||
259 | + | ||
260 | + if ((msg = sshbuf_new()) == NULL | (data = sshbuf_new()) == NULL) | ||
261 | fatal("%s: sshbuf_new failed", __func__); | ||
262 | if ((r = sshkey_froms(e->request, &key)) != 0 || | ||
263 | - (r = sshbuf_get_string_direct(e->request, &data, &dlen)) != 0 || | ||
264 | + (r = sshbuf_get_stringb(e->request, data)) != 0 || | ||
265 | (r = sshbuf_get_u32(e->request, &flags)) != 0) { | ||
266 | error("%s: couldn't parse request: %s", __func__, ssh_err(r)); | ||
267 | goto send; | ||
268 | @@ -391,13 +452,13 @@ process_sign_request2(SocketEntry *e) | ||
269 | verbose("%s: %s key not found", __func__, sshkey_type(key)); | ||
270 | goto send; | ||
271 | } | ||
272 | - if (id->confirm && confirm_key(id) != 0) { | ||
273 | + if (id->confirm && confirm_key(id, NULL) != 0) { | ||
274 | verbose("%s: user refused key", __func__); | ||
275 | goto send; | ||
276 | } | ||
277 | if (sshkey_is_sk(id->key)) { | ||
278 | if (strncmp(id->key->sk_application, "ssh:", 4) != 0 && | ||
279 | - !check_websafe_message_contents(key, data, dlen)) { | ||
280 | + !check_websafe_message_contents(key, data)) { | ||
281 | /* error already logged */ | ||
282 | goto send; | ||
283 | } | ||
284 | @@ -411,7 +472,7 @@ process_sign_request2(SocketEntry *e) | ||
285 | } | ||
286 | } | ||
287 | if ((r = sshkey_sign(id->key, &signature, &slen, | ||
288 | - data, dlen, agent_decode_alg(key, flags), | ||
289 | + sshbuf_ptr(data), sshbuf_len(data), agent_decode_alg(key, flags), | ||
290 | id->sk_provider, compat)) != 0) { | ||
291 | error("%s: sshkey_sign: %s", __func__, ssh_err(r)); | ||
292 | goto send; | ||
293 | @@ -420,8 +481,7 @@ process_sign_request2(SocketEntry *e) | ||
294 | ok = 0; | ||
295 | send: | ||
296 | notify_complete(notifier); | ||
297 | - sshkey_free(key); | ||
298 | - free(fp); | ||
299 | + | ||
300 | if (ok == 0) { | ||
301 | if ((r = sshbuf_put_u8(msg, SSH2_AGENT_SIGN_RESPONSE)) != 0 || | ||
302 | (r = sshbuf_put_string(msg, signature, slen)) != 0) | ||
303 | @@ -432,7 +492,10 @@ process_sign_request2(SocketEntry *e) | ||
304 | if ((r = sshbuf_put_stringb(e->output, msg)) != 0) | ||
305 | fatal("%s: buffer error: %s", __func__, ssh_err(r)); | ||
306 | |||
307 | + sshbuf_free(data); | ||
308 | sshbuf_free(msg); | ||
309 | + sshkey_free(key); | ||
310 | + free(fp); | ||
311 | free(signature); | ||
312 | } | ||
313 | |||
314 | -- | ||
315 | 2.41.0 | ||