summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ssh-agent.c110
1 files changed, 100 insertions, 10 deletions
diff --git a/ssh-agent.c b/ssh-agent.c
index e081413b8..effffffed 100644
--- a/ssh-agent.c
+++ b/ssh-agent.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: ssh-agent.c,v 1.257 2020/03/06 18:28:27 markus Exp $ */ 1/* $OpenBSD: ssh-agent.c,v 1.258 2020/05/26 01:26:58 djm Exp $ */
2/* 2/*
3 * Author: Tatu Ylonen <ylo@cs.hut.fi> 3 * Author: Tatu Ylonen <ylo@cs.hut.fi>
4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -77,6 +77,7 @@
77 77
78#include "xmalloc.h" 78#include "xmalloc.h"
79#include "ssh.h" 79#include "ssh.h"
80#include "ssh2.h"
80#include "sshbuf.h" 81#include "sshbuf.h"
81#include "sshkey.h" 82#include "sshkey.h"
82#include "authfd.h" 83#include "authfd.h"
@@ -167,6 +168,9 @@ static long lifetime = 0;
167 168
168static int fingerprint_hash = SSH_FP_HASH_DEFAULT; 169static int fingerprint_hash = SSH_FP_HASH_DEFAULT;
169 170
171/* Refuse signing of non-SSH messages for web-origin FIDO keys */
172static int restrict_websafe = 1;
173
170static void 174static void
171close_socket(SocketEntry *e) 175close_socket(SocketEntry *e)
172{ 176{
@@ -282,6 +286,80 @@ agent_decode_alg(struct sshkey *key, u_int flags)
282 return NULL; 286 return NULL;
283} 287}
284 288
289/*
290 * This function inspects a message to be signed by a FIDO key that has a
291 * web-like application string (i.e. one that does not begin with "ssh:".
292 * It checks that the message is one of those expected for SSH operations
293 * (pubkey userauth, sshsig, CA key signing) to exclude signing challenges
294 * for the web.
295 */
296static int
297check_websafe_message_contents(struct sshkey *key,
298 const u_char *msg, size_t len)
299{
300 int matched = 0;
301 struct sshbuf *b;
302 u_char m, n;
303 char *cp1 = NULL, *cp2 = NULL;
304 int r;
305 struct sshkey *mkey = NULL;
306
307 if ((b = sshbuf_from(msg, len)) == NULL)
308 fatal("%s: sshbuf_new", __func__);
309
310 /* SSH userauth request */
311 if ((r = sshbuf_get_string_direct(b, NULL, NULL)) == 0 && /* sess_id */
312 (r = sshbuf_get_u8(b, &m)) == 0 && /* SSH2_MSG_USERAUTH_REQUEST */
313 (r = sshbuf_get_cstring(b, NULL, NULL)) == 0 && /* server user */
314 (r = sshbuf_get_cstring(b, &cp1, NULL)) == 0 && /* service */
315 (r = sshbuf_get_cstring(b, &cp2, NULL)) == 0 && /* method */
316 (r = sshbuf_get_u8(b, &n)) == 0 && /* sig-follows */
317 (r = sshbuf_get_cstring(b, NULL, NULL)) == 0 && /* alg */
318 (r = sshkey_froms(b, &mkey)) == 0 && /* key */
319 sshbuf_len(b) == 0) {
320 debug("%s: parsed userauth", __func__);
321 if (m == SSH2_MSG_USERAUTH_REQUEST && n == 1 &&
322 strcmp(cp1, "ssh-connection") == 0 &&
323 strcmp(cp2, "publickey") == 0 &&
324 sshkey_equal(key, mkey)) {
325 debug("%s: well formed userauth", __func__);
326 matched = 1;
327 }
328 }
329 free(cp1);
330 free(cp2);
331 sshkey_free(mkey);
332 sshbuf_free(b);
333 if (matched)
334 return 1;
335
336 if ((b = sshbuf_from(msg, len)) == NULL)
337 fatal("%s: sshbuf_new", __func__);
338 cp1 = cp2 = NULL;
339 mkey = NULL;
340
341 /* SSHSIG */
342 if ((r = sshbuf_cmp(b, 0, "SSHSIG", 6)) == 0 &&
343 (r = sshbuf_consume(b, 6)) == 0 &&
344 (r = sshbuf_get_cstring(b, NULL, NULL)) == 0 && /* namespace */
345 (r = sshbuf_get_string_direct(b, NULL, NULL)) == 0 && /* reserved */
346 (r = sshbuf_get_cstring(b, NULL, NULL)) == 0 && /* hashalg */
347 (r = sshbuf_get_string_direct(b, NULL, NULL)) == 0 && /* H(msg) */
348 sshbuf_len(b) == 0) {
349 debug("%s: parsed sshsig", __func__);
350 matched = 1;
351 }
352
353 sshbuf_free(b);
354 if (matched)
355 return 1;
356
357 /* XXX CA signature operation */
358
359 error("web-origin key attempting to sign non-SSH message");
360 return 0;
361}
362
285/* ssh2 only */ 363/* ssh2 only */
286static void 364static void
287process_sign_request2(SocketEntry *e) 365process_sign_request2(SocketEntry *e)
@@ -314,14 +392,20 @@ process_sign_request2(SocketEntry *e)
314 verbose("%s: user refused key", __func__); 392 verbose("%s: user refused key", __func__);
315 goto send; 393 goto send;
316 } 394 }
317 if (sshkey_is_sk(id->key) && 395 if (sshkey_is_sk(id->key)) {
318 (id->key->sk_flags & SSH_SK_USER_PRESENCE_REQD)) { 396 if (strncmp(id->key->sk_application, "ssh:", 4) != 0 &&
319 if ((fp = sshkey_fingerprint(key, SSH_FP_HASH_DEFAULT, 397 !check_websafe_message_contents(key, data, dlen)) {
320 SSH_FP_DEFAULT)) == NULL) 398 /* error already logged */
321 fatal("%s: fingerprint failed", __func__); 399 goto send;
322 notifier = notify_start(0, 400 }
323 "Confirm user presence for key %s %s", 401 if ((id->key->sk_flags & SSH_SK_USER_PRESENCE_REQD)) {
324 sshkey_type(id->key), fp); 402 if ((fp = sshkey_fingerprint(key, SSH_FP_HASH_DEFAULT,
403 SSH_FP_DEFAULT)) == NULL)
404 fatal("%s: fingerprint failed", __func__);
405 notifier = notify_start(0,
406 "Confirm user presence for key %s %s",
407 sshkey_type(id->key), fp);
408 }
325 } 409 }
326 if ((r = sshkey_sign(id->key, &signature, &slen, 410 if ((r = sshkey_sign(id->key, &signature, &slen,
327 data, dlen, agent_decode_alg(key, flags), 411 data, dlen, agent_decode_alg(key, flags),
@@ -1212,7 +1296,7 @@ main(int ac, char **av)
1212 __progname = ssh_get_progname(av[0]); 1296 __progname = ssh_get_progname(av[0]);
1213 seed_rng(); 1297 seed_rng();
1214 1298
1215 while ((ch = getopt(ac, av, "cDdksE:a:P:t:")) != -1) { 1299 while ((ch = getopt(ac, av, "cDdksE:a:O:P:t:")) != -1) {
1216 switch (ch) { 1300 switch (ch) {
1217 case 'E': 1301 case 'E':
1218 fingerprint_hash = ssh_digest_alg_by_name(optarg); 1302 fingerprint_hash = ssh_digest_alg_by_name(optarg);
@@ -1227,6 +1311,12 @@ main(int ac, char **av)
1227 case 'k': 1311 case 'k':
1228 k_flag++; 1312 k_flag++;
1229 break; 1313 break;
1314 case 'O':
1315 if (strcmp(optarg, "no-restrict-websafe") == 0)
1316 restrict_websafe = 0;
1317 else
1318 fatal("Unknown -O option");
1319 break;
1230 case 'P': 1320 case 'P':
1231 if (provider_whitelist != NULL) 1321 if (provider_whitelist != NULL)
1232 fatal("-P option already specified"); 1322 fatal("-P option already specified");