]> git.ipfire.org Git - thirdparty/openssh-portable.git/commitdiff
upstream: use ssh-sk-helper for all security key signing operations
authordjm@openbsd.org <djm@openbsd.org>
Fri, 13 Dec 2019 19:09:10 +0000 (19:09 +0000)
committerDamien Miller <djm@mindrot.org>
Fri, 13 Dec 2019 20:17:44 +0000 (07:17 +1100)
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

ssh-agent.c
ssh-sk.c
ssh-sk.h
sshkey.c
sshkey.h

index 1d4b779f6aa3ba9e3b683ae3ebe99df02201fcf8..09d12dc3f86541f8a72fb9abc948a7b86f4e9b79 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh-agent.c,v 1.250 2019/11/19 16:02:32 jmc Exp $ */
+/* $OpenBSD: ssh-agent.c,v 1.251 2019/12/13 19:09:10 djm Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -90,7 +90,7 @@
 #include "ssherr.h"
 #include "pathnames.h"
 #include "ssh-pkcs11.h"
-#include "ssh-sk.h"
+#include "sk-api.h"
 
 #ifndef DEFAULT_PROVIDER_WHITELIST
 # define DEFAULT_PROVIDER_WHITELIST "/usr/lib*/*,/usr/local/lib*/*"
@@ -282,130 +282,6 @@ agent_decode_alg(struct sshkey *key, u_int flags)
        return NULL;
 }
 
-static int
-provider_sign(const char *provider, struct sshkey *key,
-    u_char **sigp, size_t *lenp,
-    const u_char *data, size_t datalen,
-    const char *alg, u_int compat)
-{
-       int status, pair[2], r = SSH_ERR_INTERNAL_ERROR;
-       pid_t pid;
-       char *helper, *verbosity = NULL, *fp = NULL;
-       struct sshbuf *kbuf, *req, *resp;
-       u_char version;
-       struct notifier_ctx *notifier = NULL;
-
-       debug3("%s: start for provider %s", __func__, provider);
-
-       *sigp = NULL;
-       *lenp = 0;
-
-       helper = getenv("SSH_SK_HELPER");
-       if (helper == NULL || strlen(helper) == 0)
-               helper = _PATH_SSH_SK_HELPER;
-       if (log_level_get() >= SYSLOG_LEVEL_DEBUG1)
-               verbosity = "-vvv";
-
-       /* Start helper */
-       if (socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1) {
-               error("socketpair: %s", strerror(errno));
-               return SSH_ERR_SYSTEM_ERROR;
-       }
-       if ((pid = fork()) == -1) {
-               error("fork: %s", strerror(errno));
-               close(pair[0]);
-               close(pair[1]);
-               return SSH_ERR_SYSTEM_ERROR;
-       }
-       if (pid == 0) {
-               if ((dup2(pair[1], STDIN_FILENO) == -1) ||
-                   (dup2(pair[1], STDOUT_FILENO) == -1))
-                       fatal("%s: dup2: %s", __func__, ssh_err(r));
-               close(pair[0]);
-               close(pair[1]);
-               closefrom(STDERR_FILENO + 1);
-               debug("%s: starting %s %s", __func__, helper,
-                   verbosity == NULL ? "" : verbosity);
-               execlp(helper, helper, verbosity, (char *)NULL);
-               fatal("%s: execlp: %s", __func__, strerror(errno));
-       }
-       close(pair[1]);
-
-       if ((kbuf = sshbuf_new()) == NULL ||
-           (req = sshbuf_new()) == NULL ||
-           (resp = sshbuf_new()) == NULL)
-               fatal("%s: sshbuf_new failed", __func__);
-
-       if ((r = sshkey_private_serialize(key, kbuf)) != 0 ||
-           (r = sshbuf_put_stringb(req, kbuf)) != 0 ||
-           (r = sshbuf_put_cstring(req, provider)) != 0 ||
-           (r = sshbuf_put_string(req, data, datalen)) != 0 ||
-           (r = sshbuf_put_u32(req, compat)) != 0)
-               fatal("%s: compose: %s", __func__, ssh_err(r));
-
-       if ((fp = sshkey_fingerprint(key, SSH_FP_HASH_DEFAULT,
-           SSH_FP_DEFAULT)) == NULL)
-               fatal("%s: sshkey_fingerprint failed", __func__);
-       notifier = notify_start(0,
-           "Confirm user presence for key %s %s", sshkey_type(key), fp);
-
-       if ((r = ssh_msg_send(pair[0], SSH_SK_HELPER_VERSION, req)) != 0) {
-               error("%s: send: %s", __func__, ssh_err(r));
-               goto out;
-       }
-       if ((r = ssh_msg_recv(pair[0], resp)) != 0) {
-               error("%s: receive: %s", __func__, ssh_err(r));
-               goto out;
-       }
-       if ((r = sshbuf_get_u8(resp, &version)) != 0) {
-               error("%s: parse version: %s", __func__, ssh_err(r));
-               goto out;
-       }
-       if (version != SSH_SK_HELPER_VERSION) {
-               error("%s: unsupported version: got %u, expected %u",
-                   __func__, version, SSH_SK_HELPER_VERSION);
-               r = SSH_ERR_INVALID_FORMAT;
-               goto out;
-       }
-       if ((r = sshbuf_get_string(resp, sigp, lenp)) != 0) {
-               error("%s: parse signature: %s", __func__, ssh_err(r));
-               r = SSH_ERR_INVALID_FORMAT;
-               goto out;
-       }
-       if (sshbuf_len(resp) != 0) {
-               error("%s: trailing data in response", __func__);
-               r = SSH_ERR_INVALID_FORMAT;
-               goto out;
-       }
-       /* success */
-       r = 0;
- out:
-       while (waitpid(pid, &status, 0) == -1) {
-               if (errno != EINTR)
-                       fatal("%s: waitpid: %s", __func__, ssh_err(r));
-       }
-       notify_complete(notifier);
-       if (!WIFEXITED(status)) {
-               error("%s: helper %s exited abnormally", __func__, helper);
-               if (r == 0)
-                       r = SSH_ERR_SYSTEM_ERROR;
-       } else if (WEXITSTATUS(status) != 0) {
-               error("%s: helper %s exited with non-zero exit status",
-                   __func__, helper);
-               if (r == 0)
-                       r = SSH_ERR_SYSTEM_ERROR;
-       }
-       if (r != 0) {
-               freezero(*sigp, *lenp);
-               *sigp = NULL;
-               *lenp = 0;
-       }
-       sshbuf_free(kbuf);
-       sshbuf_free(req);
-       sshbuf_free(resp);
-       return r;
-}
-
 /* ssh2 only */
 static void
 process_sign_request2(SocketEntry *e)
@@ -415,9 +291,11 @@ process_sign_request2(SocketEntry *e)
        size_t dlen, slen = 0;
        u_int compat = 0, flags;
        int r, ok = -1;
+       char *fp = NULL;
        struct sshbuf *msg;
        struct sshkey *key = NULL;
        struct identity *id;
+       struct notifier_ctx *notifier = NULL;
 
        if ((msg = sshbuf_new()) == NULL)
                fatal("%s: sshbuf_new failed", __func__);
@@ -436,25 +314,27 @@ process_sign_request2(SocketEntry *e)
                verbose("%s: user refused key", __func__);
                goto send;
        }
-       if (id->sk_provider != NULL) {
-               if ((r = provider_sign(id->sk_provider, id->key, &signature,
-                   &slen, data, dlen, agent_decode_alg(key, flags),
-                   compat)) != 0) {
-                       error("%s: sign: %s", __func__, ssh_err(r));
-                       goto send;
-               }
-       } else {
-               if ((r = sshkey_sign(id->key, &signature, &slen,
-                   data, dlen, agent_decode_alg(key, flags),
-                   NULL, compat)) != 0) {
-                       error("%s: sshkey_sign: %s", __func__, ssh_err(r));
-                       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 ((r = sshkey_sign(id->key, &signature, &slen,
+           data, dlen, agent_decode_alg(key, flags),
+           id->sk_provider, compat)) != 0) {
+               error("%s: sshkey_sign: %s", __func__, ssh_err(r));
+               goto send;
        }
        /* Success */
        ok = 0;
  send:
+       notify_complete(notifier);
        sshkey_free(key);
+       free(fp);
        if (ok == 0) {
                if ((r = sshbuf_put_u8(msg, SSH2_AGENT_SIGN_RESPONSE)) != 0 ||
                    (r = sshbuf_put_string(msg, signature, slen)) != 0)
index 7c63536e28799f1e4884c3b8c4229e992ee97831..9e5637353827228c6794679678a75dae89cf4a10 100644 (file)
--- a/ssh-sk.c
+++ b/ssh-sk.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh-sk.c,v 1.17 2019/11/27 22:32:11 djm Exp $ */
+/* $OpenBSD: ssh-sk.c,v 1.18 2019/12/13 19:09:10 djm Exp $ */
 /*
  * Copyright (c) 2019 Google LLC
  *
@@ -464,7 +464,7 @@ sshsk_ed25519_sig(struct sk_sign_response *resp, struct sshbuf *sig)
 }
 
 int
-sshsk_sign(const char *provider_path, const struct sshkey *key,
+sshsk_sign(const char *provider_path, struct sshkey *key,
     u_char **sigp, size_t *lenp, const u_char *data, size_t datalen,
     u_int compat)
 {
index bb593160a0be71fbe973b7bb371e2cfdbae5e919..4d667884ec20314f1d24aa5180de640227af6cf4 100644 (file)
--- a/ssh-sk.h
+++ b/ssh-sk.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh-sk.h,v 1.5 2019/11/12 19:31:45 markus Exp $ */
+/* $OpenBSD: ssh-sk.h,v 1.6 2019/12/13 19:09:10 djm Exp $ */
 /*
  * Copyright (c) 2019 Google LLC
  *
@@ -21,9 +21,6 @@
 struct sshbuf;
 struct sshkey;
 
-/* Version of protocol between ssh-agent and ssh-sk-helper */
-#define SSH_SK_HELPER_VERSION  1
-
 /*
  * Enroll (generate) a new security-key hosted private key of given type
  * via the specified provider middleware.
@@ -44,7 +41,7 @@ int sshsk_enroll(int type, const char *provider_path, const char *application,
  *
  * Returns 0 on success or a ssherr.h error code on failure.
  */
-int sshsk_sign(const char *provider_path, const struct sshkey *key,
+int sshsk_sign(const char *provider_path, struct sshkey *key,
     u_char **sigp, size_t *lenp, const u_char *data, size_t datalen,
     u_int compat);
 
index 920c0dc3c17c726c90728dddae298bd45f0962f6..674303c37e152a367021dbb3292d978950f9fe04 100644 (file)
--- a/sshkey.c
+++ b/sshkey.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: sshkey.c,v 1.96 2019/11/25 00:51:37 djm Exp $ */
+/* $OpenBSD: sshkey.c,v 1.97 2019/12/13 19:09:10 djm Exp $ */
 /*
  * Copyright (c) 2000, 2001 Markus Friedl.  All rights reserved.
  * Copyright (c) 2008 Alexander von Gernler.  All rights reserved.
@@ -2750,13 +2750,6 @@ sshkey_sign(struct sshkey *key,
        case KEY_ECDSA:
                r = ssh_ecdsa_sign(key, sigp, lenp, data, datalen, compat);
                break;
-#  ifdef ENABLE_SK
-       case KEY_ECDSA_SK_CERT:
-       case KEY_ECDSA_SK:
-               r = sshsk_sign(sk_provider, key, sigp, lenp, data, datalen,
-                   compat);
-               break;
-#  endif /* ENABLE_SK */
 # endif /* OPENSSL_HAS_ECC */
        case KEY_RSA_CERT:
        case KEY_RSA:
@@ -2770,8 +2763,10 @@ sshkey_sign(struct sshkey *key,
 #ifdef ENABLE_SK
        case KEY_ED25519_SK:
        case KEY_ED25519_SK_CERT:
-               r = sshsk_sign(sk_provider, key, sigp, lenp, data, datalen,
-                   compat);
+       case KEY_ECDSA_SK_CERT:
+       case KEY_ECDSA_SK:
+               r = sshsk_sign(sk_provider, key, sigp, lenp, data,
+                   datalen, compat);
                break;
 #endif /* ENABLE_SK */
 #ifdef WITH_XMSS
index 56c0a9cdf4ac6ca703b2c420045a09ce47e9d148..d96dcb8b0c024d3810cef4bade01090a2d0c0358 100644 (file)
--- a/sshkey.h
+++ b/sshkey.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: sshkey.h,v 1.40 2019/11/25 00:51:37 djm Exp $ */
+/* $OpenBSD: sshkey.h,v 1.41 2019/12/13 19:09:10 djm Exp $ */
 
 /*
  * Copyright (c) 2000, 2001 Markus Friedl.  All rights reserved.
@@ -51,6 +51,9 @@
 #define SSH_RSA_MINIMUM_MODULUS_SIZE   1024
 #define SSH_KEY_MAX_SIGN_DATA_SIZE     (1 << 20)
 
+/* Version of protocol expected from ssh-sk-helper */
+#define SSH_SK_HELPER_VERSION  1
+
 struct sshbuf;
 
 /* Key types */