summaryrefslogtreecommitdiff
path: root/ssh-agent.c
diff options
context:
space:
mode:
authordjm@openbsd.org <djm@openbsd.org>2019-12-13 19:09:10 +0000
committerDamien Miller <djm@mindrot.org>2019-12-14 07:17:44 +1100
commitb52ec0ba3983859514aa7b57d6100fa9759fe696 (patch)
tree262c9a2ebc4e6972594f45ea75fc15e8ae3bfefb /ssh-agent.c
parentc33d46868c3d88e04a92610cdb429094aeeb5847 (diff)
upstream: use ssh-sk-helper for all security key signing operations
This extracts and refactors the client interface for ssh-sk-helper from ssh-agent and generalises it for use by the other programs. This means that most OpenSSH tools no longer need to link against libfido2 or directly interact with /dev/uhid* requested by, feedback and ok markus@ OpenBSD-Commit-ID: 1abcd3aea9a7460eccfbf8ca154cdfa62f1dc93f
Diffstat (limited to 'ssh-agent.c')
-rw-r--r--ssh-agent.c160
1 files changed, 20 insertions, 140 deletions
diff --git a/ssh-agent.c b/ssh-agent.c
index 1d4b779f6..09d12dc3f 100644
--- a/ssh-agent.c
+++ b/ssh-agent.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: ssh-agent.c,v 1.250 2019/11/19 16:02:32 jmc Exp $ */ 1/* $OpenBSD: ssh-agent.c,v 1.251 2019/12/13 19:09:10 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
@@ -90,7 +90,7 @@
90#include "ssherr.h" 90#include "ssherr.h"
91#include "pathnames.h" 91#include "pathnames.h"
92#include "ssh-pkcs11.h" 92#include "ssh-pkcs11.h"
93#include "ssh-sk.h" 93#include "sk-api.h"
94 94
95#ifndef DEFAULT_PROVIDER_WHITELIST 95#ifndef DEFAULT_PROVIDER_WHITELIST
96# define DEFAULT_PROVIDER_WHITELIST "/usr/lib*/*,/usr/local/lib*/*" 96# define DEFAULT_PROVIDER_WHITELIST "/usr/lib*/*,/usr/local/lib*/*"
@@ -282,130 +282,6 @@ agent_decode_alg(struct sshkey *key, u_int flags)
282 return NULL; 282 return NULL;
283} 283}
284 284
285static int
286provider_sign(const char *provider, struct sshkey *key,
287 u_char **sigp, size_t *lenp,
288 const u_char *data, size_t datalen,
289 const char *alg, u_int compat)
290{
291 int status, pair[2], r = SSH_ERR_INTERNAL_ERROR;
292 pid_t pid;
293 char *helper, *verbosity = NULL, *fp = NULL;
294 struct sshbuf *kbuf, *req, *resp;
295 u_char version;
296 struct notifier_ctx *notifier = NULL;
297
298 debug3("%s: start for provider %s", __func__, provider);
299
300 *sigp = NULL;
301 *lenp = 0;
302
303 helper = getenv("SSH_SK_HELPER");
304 if (helper == NULL || strlen(helper) == 0)
305 helper = _PATH_SSH_SK_HELPER;
306 if (log_level_get() >= SYSLOG_LEVEL_DEBUG1)
307 verbosity = "-vvv";
308
309 /* Start helper */
310 if (socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1) {
311 error("socketpair: %s", strerror(errno));
312 return SSH_ERR_SYSTEM_ERROR;
313 }
314 if ((pid = fork()) == -1) {
315 error("fork: %s", strerror(errno));
316 close(pair[0]);
317 close(pair[1]);
318 return SSH_ERR_SYSTEM_ERROR;
319 }
320 if (pid == 0) {
321 if ((dup2(pair[1], STDIN_FILENO) == -1) ||
322 (dup2(pair[1], STDOUT_FILENO) == -1))
323 fatal("%s: dup2: %s", __func__, ssh_err(r));
324 close(pair[0]);
325 close(pair[1]);
326 closefrom(STDERR_FILENO + 1);
327 debug("%s: starting %s %s", __func__, helper,
328 verbosity == NULL ? "" : verbosity);
329 execlp(helper, helper, verbosity, (char *)NULL);
330 fatal("%s: execlp: %s", __func__, strerror(errno));
331 }
332 close(pair[1]);
333
334 if ((kbuf = sshbuf_new()) == NULL ||
335 (req = sshbuf_new()) == NULL ||
336 (resp = sshbuf_new()) == NULL)
337 fatal("%s: sshbuf_new failed", __func__);
338
339 if ((r = sshkey_private_serialize(key, kbuf)) != 0 ||
340 (r = sshbuf_put_stringb(req, kbuf)) != 0 ||
341 (r = sshbuf_put_cstring(req, provider)) != 0 ||
342 (r = sshbuf_put_string(req, data, datalen)) != 0 ||
343 (r = sshbuf_put_u32(req, compat)) != 0)
344 fatal("%s: compose: %s", __func__, ssh_err(r));
345
346 if ((fp = sshkey_fingerprint(key, SSH_FP_HASH_DEFAULT,
347 SSH_FP_DEFAULT)) == NULL)
348 fatal("%s: sshkey_fingerprint failed", __func__);
349 notifier = notify_start(0,
350 "Confirm user presence for key %s %s", sshkey_type(key), fp);
351
352 if ((r = ssh_msg_send(pair[0], SSH_SK_HELPER_VERSION, req)) != 0) {
353 error("%s: send: %s", __func__, ssh_err(r));
354 goto out;
355 }
356 if ((r = ssh_msg_recv(pair[0], resp)) != 0) {
357 error("%s: receive: %s", __func__, ssh_err(r));
358 goto out;
359 }
360 if ((r = sshbuf_get_u8(resp, &version)) != 0) {
361 error("%s: parse version: %s", __func__, ssh_err(r));
362 goto out;
363 }
364 if (version != SSH_SK_HELPER_VERSION) {
365 error("%s: unsupported version: got %u, expected %u",
366 __func__, version, SSH_SK_HELPER_VERSION);
367 r = SSH_ERR_INVALID_FORMAT;
368 goto out;
369 }
370 if ((r = sshbuf_get_string(resp, sigp, lenp)) != 0) {
371 error("%s: parse signature: %s", __func__, ssh_err(r));
372 r = SSH_ERR_INVALID_FORMAT;
373 goto out;
374 }
375 if (sshbuf_len(resp) != 0) {
376 error("%s: trailing data in response", __func__);
377 r = SSH_ERR_INVALID_FORMAT;
378 goto out;
379 }
380 /* success */
381 r = 0;
382 out:
383 while (waitpid(pid, &status, 0) == -1) {
384 if (errno != EINTR)
385 fatal("%s: waitpid: %s", __func__, ssh_err(r));
386 }
387 notify_complete(notifier);
388 if (!WIFEXITED(status)) {
389 error("%s: helper %s exited abnormally", __func__, helper);
390 if (r == 0)
391 r = SSH_ERR_SYSTEM_ERROR;
392 } else if (WEXITSTATUS(status) != 0) {
393 error("%s: helper %s exited with non-zero exit status",
394 __func__, helper);
395 if (r == 0)
396 r = SSH_ERR_SYSTEM_ERROR;
397 }
398 if (r != 0) {
399 freezero(*sigp, *lenp);
400 *sigp = NULL;
401 *lenp = 0;
402 }
403 sshbuf_free(kbuf);
404 sshbuf_free(req);
405 sshbuf_free(resp);
406 return r;
407}
408
409/* ssh2 only */ 285/* ssh2 only */
410static void 286static void
411process_sign_request2(SocketEntry *e) 287process_sign_request2(SocketEntry *e)
@@ -415,9 +291,11 @@ process_sign_request2(SocketEntry *e)
415 size_t dlen, slen = 0; 291 size_t dlen, slen = 0;
416 u_int compat = 0, flags; 292 u_int compat = 0, flags;
417 int r, ok = -1; 293 int r, ok = -1;
294 char *fp = NULL;
418 struct sshbuf *msg; 295 struct sshbuf *msg;
419 struct sshkey *key = NULL; 296 struct sshkey *key = NULL;
420 struct identity *id; 297 struct identity *id;
298 struct notifier_ctx *notifier = NULL;
421 299
422 if ((msg = sshbuf_new()) == NULL) 300 if ((msg = sshbuf_new()) == NULL)
423 fatal("%s: sshbuf_new failed", __func__); 301 fatal("%s: sshbuf_new failed", __func__);
@@ -436,25 +314,27 @@ process_sign_request2(SocketEntry *e)
436 verbose("%s: user refused key", __func__); 314 verbose("%s: user refused key", __func__);
437 goto send; 315 goto send;
438 } 316 }
439 if (id->sk_provider != NULL) { 317 if (sshkey_is_sk(id->key) &&
440 if ((r = provider_sign(id->sk_provider, id->key, &signature, 318 (id->key->sk_flags & SSH_SK_USER_PRESENCE_REQD)) {
441 &slen, data, dlen, agent_decode_alg(key, flags), 319 if ((fp = sshkey_fingerprint(key, SSH_FP_HASH_DEFAULT,
442 compat)) != 0) { 320 SSH_FP_DEFAULT)) == NULL)
443 error("%s: sign: %s", __func__, ssh_err(r)); 321 fatal("%s: fingerprint failed", __func__);
444 goto send; 322 notifier = notify_start(0,
445 } 323 "Confirm user presence for key %s %s",
446 } else { 324 sshkey_type(id->key), fp);
447 if ((r = sshkey_sign(id->key, &signature, &slen, 325 }
448 data, dlen, agent_decode_alg(key, flags), 326 if ((r = sshkey_sign(id->key, &signature, &slen,
449 NULL, compat)) != 0) { 327 data, dlen, agent_decode_alg(key, flags),
450 error("%s: sshkey_sign: %s", __func__, ssh_err(r)); 328 id->sk_provider, compat)) != 0) {
451 goto send; 329 error("%s: sshkey_sign: %s", __func__, ssh_err(r));
452 } 330 goto send;
453 } 331 }
454 /* Success */ 332 /* Success */
455 ok = 0; 333 ok = 0;
456 send: 334 send:
335 notify_complete(notifier);
457 sshkey_free(key); 336 sshkey_free(key);
337 free(fp);
458 if (ok == 0) { 338 if (ok == 0) {
459 if ((r = sshbuf_put_u8(msg, SSH2_AGENT_SIGN_RESPONSE)) != 0 || 339 if ((r = sshbuf_put_u8(msg, SSH2_AGENT_SIGN_RESPONSE)) != 0 ||
460 (r = sshbuf_put_string(msg, signature, slen)) != 0) 340 (r = sshbuf_put_string(msg, signature, slen)) != 0)