]> git.ipfire.org Git - thirdparty/openssh-portable.git/commitdiff
upstream: support for user-verified FIDO keys
authordjm@openbsd.org <djm@openbsd.org>
Thu, 27 Aug 2020 01:06:18 +0000 (01:06 +0000)
committerDamien Miller <djm@mindrot.org>
Thu, 27 Aug 2020 01:28:36 +0000 (11:28 +1000)
FIDO2 supports a notion of "user verification" where the user is
required to demonstrate their identity to the token before particular
operations (e.g. signing). Typically this is done by authenticating
themselves using a PIN that has been set on the token.

This adds support for generating and using user verified keys where
the verification happens via PIN (other options might be added in the
future, but none are in common use now). Practically, this adds
another key generation option "verify-required" that yields a key that
requires a PIN before each authentication.

feedback markus@ and Pedro Martelletto; ok markus@

OpenBSD-Commit-ID: 57fd461e4366f87c47502c5614ec08573e6d6a15

16 files changed:
krl.c
monitor.c
monitor_wrap.c
monitor_wrap.h
sk-usbhid.c
ssh-agent.c
ssh-keygen.1
ssh-keygen.c
ssh-keysign.c
ssh_api.c
sshconnect2.c
sshd.c
sshkey.c
sshkey.h
sshsig.c
sshsig.h

diff --git a/krl.c b/krl.c
index c431f70475c58343a4b9af53bca2784f5c097ceb..3a69b636a359f3012fb72015755c440ae3220ceb 100644 (file)
--- a/krl.c
+++ b/krl.c
@@ -14,7 +14,7 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $OpenBSD: krl.c,v 1.50 2020/04/03 05:48:57 djm Exp $ */
+/* $OpenBSD: krl.c,v 1.51 2020/08/27 01:06:18 djm Exp $ */
 
 #include "includes.h"
 
@@ -812,9 +812,10 @@ ssh_krl_to_blob(struct ssh_krl *krl, struct sshbuf *buf,
                if ((r = sshbuf_put_u8(buf, KRL_SECTION_SIGNATURE)) != 0 ||
                    (r = sshkey_puts(sign_keys[i], buf)) != 0)
                        goto out;
-
+               /* XXX support sk-* keys */
                if ((r = sshkey_sign(sign_keys[i], &sblob, &slen,
-                   sshbuf_ptr(buf), sshbuf_len(buf), NULL, NULL, 0)) != 0)
+                   sshbuf_ptr(buf), sshbuf_len(buf), NULL, NULL,
+                   NULL, 0)) != 0)
                        goto out;
                KRL_DBG(("%s: signature sig len %zu", __func__, slen));
                if ((r = sshbuf_put_string(buf, sblob, slen)) != 0)
index 0107a7ebabcabe0541411fb80e8ab45deacecbc9..7c3e6aafe8bc0c84a6dc67cd65d7088f94d32daa 100644 (file)
--- a/monitor.c
+++ b/monitor.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: monitor.c,v 1.212 2020/07/07 02:47:21 deraadt Exp $ */
+/* $OpenBSD: monitor.c,v 1.213 2020/08/27 01:06:18 djm Exp $ */
 /*
  * Copyright 2002 Niels Provos <provos@citi.umich.edu>
  * Copyright 2002 Markus Friedl <markus@openbsd.org>
@@ -679,7 +679,7 @@ mm_answer_sign(struct ssh *ssh, int sock, struct sshbuf *m)
 
        if ((key = get_hostkey_by_index(keyid)) != NULL) {
                if ((r = sshkey_sign(key, &signature, &siglen, p, datlen, alg,
-                   options.sk_provider, compat)) != 0)
+                   options.sk_provider, NULL, compat)) != 0)
                        fatal("%s: sshkey_sign failed: %s",
                            __func__, ssh_err(r));
        } else if ((key = get_hostkey_public_by_index(keyid, ssh)) != NULL &&
index 001a8fa1c99a26d547464586877e84cc637f8703..5e38d83eb05257c68412f656fae0a7b7ad097591 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: monitor_wrap.c,v 1.117 2019/12/15 18:57:30 djm Exp $ */
+/* $OpenBSD: monitor_wrap.c,v 1.118 2020/08/27 01:06:18 djm Exp $ */
 /*
  * Copyright 2002 Niels Provos <provos@citi.umich.edu>
  * Copyright 2002 Markus Friedl <markus@openbsd.org>
@@ -216,7 +216,7 @@ mm_choose_dh(int min, int nbits, int max)
 int
 mm_sshkey_sign(struct ssh *ssh, struct sshkey *key, u_char **sigp, size_t *lenp,
     const u_char *data, size_t datalen, const char *hostkey_alg,
-    const char *sk_provider, u_int compat)
+    const char *sk_provider, const char *sk_pin, u_int compat)
 {
        struct kex *kex = *pmonitor->m_pkex;
        struct sshbuf *m;
index 23ab096aa6decbace4252f9c16cdd35c03f015cc..0db38c20657f0f782d6b02942df7a72b9791f6b6 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: monitor_wrap.h,v 1.44 2019/11/25 00:51:37 djm Exp $ */
+/* $OpenBSD: monitor_wrap.h,v 1.45 2020/08/27 01:06:18 djm Exp $ */
 
 /*
  * Copyright 2002 Niels Provos <provos@citi.umich.edu>
@@ -46,7 +46,8 @@ int mm_is_monitor(void);
 DH *mm_choose_dh(int, int, int);
 #endif
 int mm_sshkey_sign(struct ssh *, struct sshkey *, u_char **, size_t *,
-    const u_char *, size_t, const char *, const char *, u_int compat);
+    const u_char *, size_t, const char *, const char *,
+    const char *, u_int compat);
 void mm_inform_authserv(char *, char *);
 struct passwd *mm_getpwnamallow(struct ssh *, const char *);
 char *mm_auth2_read_banner(void);
index 2a573caa218d7f34404d22b0faceaf8bd7d80f7a..1dd8348837b94b174d735c48b199ee978e03b09c 100644 (file)
@@ -163,7 +163,8 @@ pick_first_device(void)
 /* Check if the specified key handle exists on a given device. */
 static int
 try_device(fido_dev_t *dev, const uint8_t *message, size_t message_len,
-    const char *application, const uint8_t *key_handle, size_t key_handle_len)
+    const char *application, const uint8_t *key_handle, size_t key_handle_len,
+    uint8_t flags, const char *pin)
 {
        fido_assert_t *assert = NULL;
        int r = FIDO_ERR_INTERNAL;
@@ -191,7 +192,7 @@ try_device(fido_dev_t *dev, const uint8_t *message, size_t message_len,
                skdebug(__func__, "fido_assert_up: %s", fido_strerr(r));
                goto out;
        }
-       r = fido_dev_get_assert(dev, assert, NULL);
+       r = fido_dev_get_assert(dev, assert, pin);
        skdebug(__func__, "fido_dev_get_assert: %s", fido_strerr(r));
        if (r == FIDO_ERR_USER_PRESENCE_REQUIRED) {
                /* U2F tokens may return this */
@@ -206,7 +207,8 @@ try_device(fido_dev_t *dev, const uint8_t *message, size_t message_len,
 /* Iterate over configured devices looking for a specific key handle */
 static fido_dev_t *
 find_device(const char *path, const uint8_t *message, size_t message_len,
-    const char *application, const uint8_t *key_handle, size_t key_handle_len)
+    const char *application, const uint8_t *key_handle, size_t key_handle_len,
+    uint8_t flags, const char *pin)
 {
        fido_dev_info_t *devlist = NULL;
        fido_dev_t *dev = NULL;
@@ -260,7 +262,7 @@ find_device(const char *path, const uint8_t *message, size_t message_len,
                        continue;
                }
                if (try_device(dev, message, message_len, application,
-                   key_handle, key_handle_len) == 0) {
+                   key_handle, key_handle_len, flags, pin) == 0) {
                        skdebug(__func__, "found key");
                        break;
                }
@@ -570,19 +572,23 @@ sk_enroll(uint32_t alg, const uint8_t *challenge, size_t challenge_len,
                skdebug(__func__, "fido_dev_open: %s", fido_strerr(r));
                goto out;
        }
-       if ((flags & SSH_SK_RESIDENT_KEY) != 0) {
+       if ((flags & (SSH_SK_RESIDENT_KEY|SSH_SK_USER_VERIFICATION_REQD)) != 0) {
                if (check_sk_extensions(dev, "credProtect", &credprot) < 0) {
                        skdebug(__func__, "check_sk_extensions failed");
                        goto out;
                }
                if (credprot == 0) {
                        skdebug(__func__, "refusing to create unprotected "
-                           "resident key");
+                           "resident/verify-required key");
                        ret = SSH_SK_ERR_UNSUPPORTED;
                        goto out;
                }
-               if ((r = fido_cred_set_prot(cred,
-                   FIDO_CRED_PROT_UV_OPTIONAL_WITH_ID)) != FIDO_OK) {
+               if ((flags & SSH_SK_USER_VERIFICATION_REQD))
+                       credprot = FIDO_CRED_PROT_UV_REQUIRED;
+               else
+                       credprot = FIDO_CRED_PROT_UV_OPTIONAL_WITH_ID;
+
+               if ((r = fido_cred_set_prot(cred, credprot)) != FIDO_OK) {
                        skdebug(__func__, "fido_cred_set_prot: %s",
                            fido_strerr(r));
                        ret = fidoerr_to_skerr(r);
@@ -826,7 +832,7 @@ sk_sign(uint32_t alg, const uint8_t *data, size_t datalen,
                goto out;
        }
        if ((dev = find_device(device, message, sizeof(message),
-           application, key_handle, key_handle_len)) == NULL) {
+           application, key_handle, key_handle_len, flags, pin)) == NULL) {
                skdebug(__func__, "couldn't find device for key handle");
                goto out;
        }
@@ -855,8 +861,15 @@ sk_sign(uint32_t alg, const uint8_t *data, size_t datalen,
                skdebug(__func__, "fido_assert_set_up: %s", fido_strerr(r));
                goto out;
        }
-       if ((r = fido_dev_get_assert(dev, assert, NULL)) != FIDO_OK) {
+       if (pin == NULL && (flags & SSH_SK_USER_VERIFICATION_REQD) &&
+           (r = fido_assert_set_uv(assert, FIDO_OPT_TRUE)) != FIDO_OK) {
+               skdebug(__func__, "fido_assert_set_uv: %s", fido_strerr(r));
+               ret = FIDO_ERR_PIN_REQUIRED;
+               goto out;
+       }
+       if ((r = fido_dev_get_assert(dev, assert, pin)) != FIDO_OK) {
                skdebug(__func__, "fido_dev_get_assert: %s", fido_strerr(r));
+               ret = fidoerr_to_skerr(r);
                goto out;
        }
        if ((response = calloc(1, sizeof(*response))) == NULL) {
@@ -978,8 +991,9 @@ read_rks(const char *devpath, const char *pin,
                                continue;
                        }
                        skdebug(__func__, "Device %s RP \"%s\" slot %zu: "
-                           "type %d", devpath, fido_credman_rp_id(rp, i), j,
-                           fido_cred_type(cred));
+                           "type %d flags 0x%02x prot 0x%02x", devpath,
+                           fido_credman_rp_id(rp, i), j, fido_cred_type(cred),
+                           fido_cred_flags(cred), fido_cred_prot(cred));
 
                        /* build response entry */
                        if ((srk = calloc(1, sizeof(*srk))) == NULL ||
index 5f7ac8b910e8e5b110b3396586afbcef4981fd66..d24a63089668d8e32d66bfe30dbee76386dc4142 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh-agent.c,v 1.262 2020/07/05 23:59:45 djm Exp $ */
+/* $OpenBSD: ssh-agent.c,v 1.263 2020/08/27 01:06:18 djm Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -407,9 +407,10 @@ process_sign_request2(SocketEntry *e)
                            sshkey_type(id->key), fp);
                }
        }
+       /* XXX support PIN required FIDO keys */
        if ((r = sshkey_sign(id->key, &signature, &slen,
            data, dlen, agent_decode_alg(key, flags),
-           id->sk_provider, compat)) != 0) {
+           id->sk_provider, NULL, compat)) != 0) {
                error("%s: sshkey_sign: %s", __func__, ssh_err(r));
                goto send;
        }
index 9198a511fb70ea5769f8b6f50f363e65ba9b0339..7e0558fe194edff28ae67a74f901c1518d622c12 100644 (file)
@@ -1,4 +1,4 @@
-.\"    $OpenBSD: ssh-keygen.1,v 1.205 2020/07/15 07:50:46 solene Exp $
+.\"    $OpenBSD: ssh-keygen.1,v 1.206 2020/08/27 01:06:18 djm Exp $
 .\"
 .\" Author: Tatu Ylonen <ylo@cs.hut.fi>
 .\" Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -35,7 +35,7 @@
 .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 .\"
-.Dd $Mdocdate: July 15 2020 $
+.Dd $Mdocdate: August 27 2020 $
 .Dt SSH-KEYGEN 1
 .Os
 .Sh NAME
@@ -511,6 +511,12 @@ A username to be associated with a resident key,
 overriding the empty default username.
 Specifying a username may be useful when generating multiple resident keys
 for the same application name.
+.It Cm verify-required
+Indicate that this private key should require user verification for
+each signature.
+Not all FIDO tokens support support this option.
+Currently PIN authentication is the only supported verification method,
+but other methods may be supported in the future.
 .It Cm write-attestation Ns = Ns Ar path
 May be used at key generation time to record the attestation certificate
 returned from FIDO tokens during key generation.
@@ -961,7 +967,7 @@ by
 Allows X11 forwarding.
 .Pp
 .It Ic no-touch-required
-Do not require signatures made using this key require demonstration
+Do not require signatures made using this key include demonstration
 of user presence (e.g. by having the user touch the authenticator).
 This option only makes sense for the FIDO authenticator algorithms
 .Cm ecdsa-sk
@@ -974,6 +980,16 @@ The
 .Ar address_list
 is a comma-separated list of one or more address/netmask pairs in CIDR
 format.
+.Pp
+.It Ic verify-required
+Require signatures made using this key indicate that the user was first
+verified.
+This option only makes sense for the FIDO authenticator algorithms
+.Cm ecdsa-sk
+and
+.Cm ed25519-sk .
+Currently PIN authentication is the only supported verification method,
+but other methods may be supported in the future.
 .El
 .Pp
 At present, no standard options are valid for host keys.
index cc092368e0f550ceaadd446490fdfe875fd734e0..89ef9a14365fd3a8f874843c98f7c5f7d6ca3e54 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh-keygen.c,v 1.415 2020/08/03 02:53:51 djm Exp $ */
+/* $OpenBSD: ssh-keygen.c,v 1.416 2020/08/27 01:06:18 djm Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1994 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -589,7 +589,7 @@ do_convert_private_ssh2(struct sshbuf *b)
 
        /* try the key */
        if (sshkey_sign(key, &sig, &slen, data, sizeof(data),
-           NULL, NULL, 0) != 0 ||
+           NULL, NULL, NULL, 0) != 0 ||
            sshkey_verify(key, sig, slen, data, sizeof(data),
            NULL, 0, NULL) != 0) {
                sshkey_free(key);
@@ -1727,7 +1727,8 @@ load_pkcs11_key(char *path)
 static int
 agent_signer(struct sshkey *key, u_char **sigp, size_t *lenp,
     const u_char *data, size_t datalen,
-    const char *alg, const char *provider, u_int compat, void *ctx)
+    const char *alg, const char *provider, const char *pin,
+    u_int compat, void *ctx)
 {
        int *agent_fdp = (int *)ctx;
 
@@ -1744,7 +1745,7 @@ do_ca_sign(struct passwd *pw, const char *ca_key_path, int prefer_agent,
        u_int n;
        struct sshkey *ca, *public;
        char valid[64], *otmp, *tmp, *cp, *out, *comment;
-       char *ca_fp = NULL, **plist = NULL;
+       char *ca_fp = NULL, **plist = NULL, *pin = NULL;
        struct ssh_identitylist *agent_ids;
        size_t j;
        struct notifier_ctx *notifier = NULL;
@@ -1785,6 +1786,12 @@ do_ca_sign(struct passwd *pw, const char *ca_key_path, int prefer_agent,
        } else {
                /* CA key is assumed to be a private key on the filesystem */
                ca = load_identity(tmp, NULL);
+               if (sshkey_is_sk(ca) &&
+                   (ca->sk_flags & SSH_SK_USER_VERIFICATION_REQD)) {
+                       if ((pin = read_passphrase("Enter PIN for CA key: ",
+                           RP_ALLOW_STDIN)) == NULL)
+                               fatal("%s: couldn't read PIN", __func__);
+               }
        }
        free(tmp);
 
@@ -1844,7 +1851,7 @@ do_ca_sign(struct passwd *pw, const char *ca_key_path, int prefer_agent,
 
                if (agent_fd != -1 && (ca->flags & SSHKEY_FLAG_EXT) != 0) {
                        if ((r = sshkey_certify_custom(public, ca,
-                           key_type_name, sk_provider, agent_signer,
+                           key_type_name, sk_provider, NULL, agent_signer,
                            &agent_fd)) != 0)
                                fatal("Couldn't certify key %s via agent: %s",
                                    tmp, ssh_err(r));
@@ -1856,7 +1863,7 @@ do_ca_sign(struct passwd *pw, const char *ca_key_path, int prefer_agent,
                                    sshkey_type(ca), ca_fp);
                        }
                        r = sshkey_certify(public, ca, key_type_name,
-                           sk_provider);
+                           sk_provider, pin);
                        notify_complete(notifier);
                        if (r != 0)
                                fatal("Couldn't certify key %s: %s",
@@ -1890,6 +1897,8 @@ do_ca_sign(struct passwd *pw, const char *ca_key_path, int prefer_agent,
                if (cert_serial_autoinc)
                        cert_serial++;
        }
+       if (pin != NULL)
+               freezero(pin, strlen(pin));
        free(ca_fp);
 #ifdef ENABLE_PKCS11
        pkcs11_terminate();
@@ -2526,6 +2535,7 @@ sign_one(struct sshkey *signkey, const char *filename, int fd,
        struct sshbuf *sigbuf = NULL, *abuf = NULL;
        int r = SSH_ERR_INTERNAL_ERROR, wfd = -1, oerrno;
        char *wfile = NULL, *asig = NULL, *fp = NULL;
+       char *pin = NULL, *prompt = NULL;
 
        if (!quiet) {
                if (fd == STDIN_FILENO)
@@ -2533,17 +2543,25 @@ sign_one(struct sshkey *signkey, const char *filename, int fd,
                else
                        fprintf(stderr, "Signing file %s\n", filename);
        }
-       if (signer == NULL && sshkey_is_sk(signkey) &&
-           (signkey->sk_flags & SSH_SK_USER_PRESENCE_REQD)) {
-               if ((fp = sshkey_fingerprint(signkey, fingerprint_hash,
-                   SSH_FP_DEFAULT)) == NULL)
-                       fatal("%s: sshkey_fingerprint failed", __func__);
-               fprintf(stderr, "Confirm user presence for key %s %s\n",
-                   sshkey_type(signkey), fp);
-               free(fp);
+       if (signer == NULL && sshkey_is_sk(signkey)) {
+               if ((signkey->sk_flags & SSH_SK_USER_VERIFICATION_REQD)) {
+                       xasprintf(&prompt, "Enter PIN for %s key: ",
+                           sshkey_type(signkey));
+                       if ((pin = read_passphrase(prompt,
+                           RP_ALLOW_STDIN)) == NULL)
+                               fatal("%s: couldn't read PIN", __func__);
+               }
+               if ((signkey->sk_flags & SSH_SK_USER_PRESENCE_REQD)) {
+                       if ((fp = sshkey_fingerprint(signkey, fingerprint_hash,
+                           SSH_FP_DEFAULT)) == NULL)
+                               fatal("%s: fingerprint failed", __func__);
+                       fprintf(stderr, "Confirm user presence for key %s %s\n",
+                           sshkey_type(signkey), fp);
+                       free(fp);
+               }
        }
-       if ((r = sshsig_sign_fd(signkey, NULL, sk_provider, fd, sig_namespace,
-           &sigbuf, signer, signer_ctx)) != 0) {
+       if ((r = sshsig_sign_fd(signkey, NULL, sk_provider, pin,
+           fd, sig_namespace, &sigbuf, signer, signer_ctx)) != 0) {
                error("Signing %s failed: %s", filename, ssh_err(r));
                goto out;
        }
@@ -2591,7 +2609,10 @@ sign_one(struct sshkey *signkey, const char *filename, int fd,
        r = 0;
  out:
        free(wfile);
+       free(prompt);
        free(asig);
+       if (pin != NULL)
+               freezero(pin, strlen(pin));
        sshbuf_free(abuf);
        sshbuf_free(sigbuf);
        if (wfd != -1)
@@ -3554,6 +3575,8 @@ main(int argc, char **argv)
                for (i = 0; i < nopts; i++) {
                        if (strcasecmp(opts[i], "no-touch-required") == 0) {
                                sk_flags &= ~SSH_SK_USER_PRESENCE_REQD;
+                       } else if (strcasecmp(opts[i], "verify-required") == 0) {
+                               sk_flags |= SSH_SK_USER_VERIFICATION_REQD;
                        } else if (strcasecmp(opts[i], "resident") == 0) {
                                sk_flags |= SSH_SK_RESIDENT_KEY;
                        } else if (strncasecmp(opts[i], "device=", 7) == 0) {
index 3e3ea3e1481d2d7a2c0ef6701cf47b7d8f952614..7991e0f016948fd3124366dba9ba6acafd239427 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh-keysign.c,v 1.63 2019/11/18 16:10:05 naddy Exp $ */
+/* $OpenBSD: ssh-keysign.c,v 1.64 2020/08/27 01:06:18 djm Exp $ */
 /*
  * Copyright (c) 2002 Markus Friedl.  All rights reserved.
  *
@@ -278,7 +278,7 @@ main(int argc, char **argv)
        }
 
        if ((r = sshkey_sign(keys[i], &signature, &slen, data, dlen,
-           NULL, NULL, 0)) != 0)
+           NULL, NULL, NULL, 0)) != 0)
                fatal("sshkey_sign failed: %s", ssh_err(r));
        free(data);
 
index a0358d4bed19f79065cd3fa883fd24afe662211e..129404b207b8ac8a6eac29e013212e4a04d65020 100644 (file)
--- a/ssh_api.c
+++ b/ssh_api.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh_api.c,v 1.20 2020/07/01 16:28:31 markus Exp $ */
+/* $OpenBSD: ssh_api.c,v 1.21 2020/08/27 01:06:18 djm Exp $ */
 /*
  * Copyright (c) 2012 Markus Friedl.  All rights reserved.
  *
@@ -54,7 +54,7 @@ int   _ssh_host_key_sign(struct ssh *, struct sshkey *, struct sshkey *,
  */
 int    use_privsep = 0;
 int    mm_sshkey_sign(struct sshkey *, u_char **, u_int *,
-    const u_char *, u_int, const char *, const char *, u_int);
+    const u_char *, u_int, const char *, const char *, const char *, u_int);
 
 #ifdef WITH_OPENSSL
 DH     *mm_choose_dh(int, int, int);
@@ -66,8 +66,8 @@ u_int session_id2_len = 0;
 
 int
 mm_sshkey_sign(struct sshkey *key, u_char **sigp, u_int *lenp,
-    const u_char *data, u_int datalen, const char *alg, const char *sk_provider,
-    u_int compat)
+    const u_char *data, u_int datalen, const char *alg,
+    const char *sk_provider, const char *sk_pin, u_int compat)
 {
        return (-1);
 }
@@ -567,5 +567,5 @@ _ssh_host_key_sign(struct ssh *ssh, struct sshkey *privkey,
     const u_char *data, size_t dlen, const char *alg)
 {
        return sshkey_sign(privkey, signature, slen, data, dlen,
-           alg, NULL, ssh->compat);
+           alg, NULL, NULL, ssh->compat);
 }
index 74946da0d385bd740ee0731ec4cefe2d08ed94b7..347e348c607ed88c85c57ad0c9daa4821f174a97 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: sshconnect2.c,v 1.324 2020/06/27 13:39:09 bket Exp $ */
+/* $OpenBSD: sshconnect2.c,v 1.325 2020/08/27 01:06:18 djm Exp $ */
 /*
  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
  * Copyright (c) 2008 Damien Miller.  All rights reserved.
@@ -1175,7 +1175,7 @@ identity_sign(struct identity *id, u_char **sigp, size_t *lenp,
        struct sshkey *sign_key = NULL, *prv = NULL;
        int r = SSH_ERR_INTERNAL_ERROR;
        struct notifier_ctx *notifier = NULL;
-       char *fp = NULL;
+       char *fp = NULL, *pin = NULL, *prompt = NULL;
 
        *sigp = NULL;
        *lenp = 0;
@@ -1204,20 +1204,28 @@ identity_sign(struct identity *id, u_char **sigp, size_t *lenp,
                        goto out;
                }
                sign_key = prv;
-               if (sshkey_is_sk(sign_key) &&
-                   (sign_key->sk_flags & SSH_SK_USER_PRESENCE_REQD)) {
-                       /* XXX match batch mode should just skip these keys? */
-                       if ((fp = sshkey_fingerprint(sign_key,
-                           options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL)
-                               fatal("%s: sshkey_fingerprint", __func__);
-                       notifier = notify_start(options.batch_mode,
-                           "Confirm user presence for key %s %s",
-                           sshkey_type(sign_key), fp);
-                       free(fp);
+               if (sshkey_is_sk(sign_key)) {
+                       if ((sign_key->sk_flags &
+                           SSH_SK_USER_VERIFICATION_REQD)) {
+                               xasprintf(&prompt, "Enter PIN for %s key %s: ",
+                                   sshkey_type(sign_key), id->filename);
+                               pin = read_passphrase(prompt, 0);
+                       }
+                       if ((sign_key->sk_flags & SSH_SK_USER_PRESENCE_REQD)) {
+                               /* XXX should batch mode just skip these? */
+                               if ((fp = sshkey_fingerprint(sign_key,
+                                   options.fingerprint_hash,
+                                   SSH_FP_DEFAULT)) == NULL)
+                                       fatal("%s: fingerprint", __func__);
+                               notifier = notify_start(options.batch_mode,
+                                   "Confirm user presence for key %s %s",
+                                   sshkey_type(sign_key), fp);
+                               free(fp);
+                       }
                }
        }
        if ((r = sshkey_sign(sign_key, sigp, lenp, data, datalen,
-           alg, options.sk_provider, compat)) != 0) {
+           alg, options.sk_provider, pin, compat)) != 0) {
                debug("%s: sshkey_sign: %s", __func__, ssh_err(r));
                goto out;
        }
@@ -1232,6 +1240,9 @@ identity_sign(struct identity *id, u_char **sigp, size_t *lenp,
        /* success */
        r = 0;
  out:
+       free(prompt);
+       if (pin != NULL)
+               freezero(pin, strlen(pin));
        notify_complete(notifier);
        sshkey_free(prv);
        return r;
diff --git a/sshd.c b/sshd.c
index d9a159f6a77643b83fd4f2a3730adfc8e62ab817..8aa7f3df61b8e472c59398e7881fe56c404c15b2 100644 (file)
--- a/sshd.c
+++ b/sshd.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: sshd.c,v 1.560 2020/07/03 10:12:26 markus Exp $ */
+/* $OpenBSD: sshd.c,v 1.561 2020/08/27 01:06:19 djm Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -2338,19 +2338,19 @@ sshd_hostkey_sign(struct ssh *ssh, struct sshkey *privkey,
        if (use_privsep) {
                if (privkey) {
                        if (mm_sshkey_sign(ssh, privkey, signature, slenp,
-                           data, dlen, alg, options.sk_provider,
+                           data, dlen, alg, options.sk_provider, NULL,
                            ssh->compat) < 0)
                                fatal("%s: privkey sign failed", __func__);
                } else {
                        if (mm_sshkey_sign(ssh, pubkey, signature, slenp,
-                           data, dlen, alg, options.sk_provider,
+                           data, dlen, alg, options.sk_provider, NULL,
                            ssh->compat) < 0)
                                fatal("%s: pubkey sign failed", __func__);
                }
        } else {
                if (privkey) {
                        if (sshkey_sign(privkey, signature, slenp, data, dlen,
-                           alg, options.sk_provider, ssh->compat) < 0)
+                           alg, options.sk_provider, NULL, ssh->compat) < 0)
                                fatal("%s: privkey sign failed", __func__);
                } else {
                        if ((r = ssh_agent_sign(auth_sock, pubkey,
index 10b9e4676f46c6ffa4f5089e3b2d3e15f84c1780..ac451f1a84c2e6dc1e00020bbde808570ad5d927 100644 (file)
--- a/sshkey.c
+++ b/sshkey.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: sshkey.c,v 1.110 2020/06/24 15:07:33 markus Exp $ */
+/* $OpenBSD: sshkey.c,v 1.111 2020/08/27 01:06:19 djm Exp $ */
 /*
  * Copyright (c) 2000, 2001 Markus Friedl.  All rights reserved.
  * Copyright (c) 2008 Alexander von Gernler.  All rights reserved.
@@ -2727,7 +2727,7 @@ int
 sshkey_sign(struct sshkey *key,
     u_char **sigp, size_t *lenp,
     const u_char *data, size_t datalen,
-    const char *alg, const char *sk_provider, u_int compat)
+    const char *alg, const char *sk_provider, const char *sk_pin, u_int compat)
 {
        int was_shielded = sshkey_is_shielded(key);
        int r2, r = SSH_ERR_INTERNAL_ERROR;
@@ -2766,7 +2766,7 @@ sshkey_sign(struct sshkey *key,
        case KEY_ECDSA_SK_CERT:
        case KEY_ECDSA_SK:
                r = sshsk_sign(sk_provider, key, sigp, lenp, data,
-                   datalen, compat, /* XXX PIN */ NULL);
+                   datalen, compat, sk_pin);
                break;
 #ifdef WITH_XMSS
        case KEY_XMSS:
@@ -2888,7 +2888,8 @@ sshkey_drop_cert(struct sshkey *k)
 /* Sign a certified key, (re-)generating the signed certblob. */
 int
 sshkey_certify_custom(struct sshkey *k, struct sshkey *ca, const char *alg,
-    const char *sk_provider, sshkey_certify_signer *signer, void *signer_ctx)
+    const char *sk_provider, const char *sk_pin,
+    sshkey_certify_signer *signer, void *signer_ctx)
 {
        struct sshbuf *principals = NULL;
        u_char *ca_blob = NULL, *sig_blob = NULL, nonce[32];
@@ -3026,7 +3027,7 @@ sshkey_certify_custom(struct sshkey *k, struct sshkey *ca, const char *alg,
 
        /* Sign the whole mess */
        if ((ret = signer(ca, &sig_blob, &sig_len, sshbuf_ptr(cert),
-           sshbuf_len(cert), alg, sk_provider, 0, signer_ctx)) != 0)
+           sshbuf_len(cert), alg, sk_provider, sk_pin, 0, signer_ctx)) != 0)
                goto out;
        /* Check and update signature_type against what was actually used */
        if ((ret = sshkey_get_sigtype(sig_blob, sig_len, &sigtype)) != 0)
@@ -3056,19 +3057,20 @@ sshkey_certify_custom(struct sshkey *k, struct sshkey *ca, const char *alg,
 static int
 default_key_sign(struct sshkey *key, u_char **sigp, size_t *lenp,
     const u_char *data, size_t datalen,
-    const char *alg, const char *sk_provider, u_int compat, void *ctx)
+    const char *alg, const char *sk_provider, const char *sk_pin,
+    u_int compat, void *ctx)
 {
        if (ctx != NULL)
                return SSH_ERR_INVALID_ARGUMENT;
        return sshkey_sign(key, sigp, lenp, data, datalen, alg,
-           sk_provider, compat);
+           sk_provider, sk_pin, compat);
 }
 
 int
 sshkey_certify(struct sshkey *k, struct sshkey *ca, const char *alg,
-    const char *sk_provider)
+    const char *sk_provider, const char *sk_pin)
 {
-       return sshkey_certify_custom(k, ca, alg, sk_provider,
+       return sshkey_certify_custom(k, ca, alg, sk_provider, sk_pin,
            default_key_sign, NULL);
 }
 
index 9c1d4f6372f6144458994436010a6d4f6da752eb..2d8b6249708c6c057546bf09bce01a67968126df 100644 (file)
--- a/sshkey.h
+++ b/sshkey.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: sshkey.h,v 1.45 2020/04/08 00:08:46 djm Exp $ */
+/* $OpenBSD: sshkey.h,v 1.46 2020/08/27 01:06:19 djm Exp $ */
 
 /*
  * Copyright (c) 2000, 2001 Markus Friedl.  All rights reserved.
@@ -200,12 +200,13 @@ size_t     sshkey_format_cert_validity(const struct sshkey_cert *,
 int     sshkey_check_cert_sigtype(const struct sshkey *, const char *);
 
 int     sshkey_certify(struct sshkey *, struct sshkey *,
-    const char *, const char *);
+    const char *, const char *, const char *);
 /* Variant allowing use of a custom signature function (e.g. for ssh-agent) */
 typedef int sshkey_certify_signer(struct sshkey *, u_char **, size_t *,
-    const u_char *, size_t, const char *, const char *, u_int, void *);
+    const u_char *, size_t, const char *, const char *, const char *,
+    u_int, void *);
 int     sshkey_certify_custom(struct sshkey *, struct sshkey *, const char *,
-    const char *, sshkey_certify_signer *, void *);
+    const char *, const char *, sshkey_certify_signer *, void *);
 
 int             sshkey_ecdsa_nid_from_name(const char *);
 int             sshkey_curve_name_to_nid(const char *);
@@ -234,7 +235,7 @@ int  sshkey_plain_to_blob(const struct sshkey *, u_char **, size_t *);
 int     sshkey_putb_plain(const struct sshkey *, struct sshbuf *);
 
 int     sshkey_sign(struct sshkey *, u_char **, size_t *,
-    const u_char *, size_t, const char *, const char *, u_int);
+    const u_char *, size_t, const char *, const char *, const char *, u_int);
 int     sshkey_verify(const struct sshkey *, const u_char *, size_t,
     const u_char *, size_t, const char *, u_int, struct sshkey_sig_details **);
 int     sshkey_check_sigtype(const u_char *, size_t, const char *);
index 15f9cead697f31363085e770b2b0132bb4f3e2cf..658b8c8528734cbe48dbce090ad09a0eff00a0c6 100644 (file)
--- a/sshsig.c
+++ b/sshsig.c
@@ -151,7 +151,7 @@ done:
 
 static int
 sshsig_wrap_sign(struct sshkey *key, const char *hashalg,
-    const char *sk_provider, const struct sshbuf *h_message,
+    const char *sk_provider, const char *sk_pin, const struct sshbuf *h_message,
     const char *sig_namespace, struct sshbuf **out,
     sshsig_signer *signer, void *signer_ctx)
 {
@@ -185,14 +185,14 @@ sshsig_wrap_sign(struct sshkey *key, const char *hashalg,
        if (signer != NULL) {
                if ((r = signer(key, &sig, &slen,
                    sshbuf_ptr(tosign), sshbuf_len(tosign),
-                   sign_alg, sk_provider, 0, signer_ctx)) != 0) {
+                   sign_alg, sk_provider, sk_pin, 0, signer_ctx)) != 0) {
                        error("Couldn't sign message: %s", ssh_err(r));
                        goto done;
                }
        } else {
                if ((r = sshkey_sign(key, &sig, &slen,
                    sshbuf_ptr(tosign), sshbuf_len(tosign),
-                   sign_alg, sk_provider, 0)) != 0) {
+                   sign_alg, sk_provider, sk_pin, 0)) != 0) {
                        error("Couldn't sign message: %s", ssh_err(r));
                        goto done;
                }
@@ -430,7 +430,8 @@ hash_buffer(const struct sshbuf *m, const char *hashalg, struct sshbuf **bp)
 }
 
 int
-sshsig_signb(struct sshkey *key, const char *hashalg, const char *sk_provider,
+sshsig_signb(struct sshkey *key, const char *hashalg,
+    const char *sk_provider, const char *sk_pin,
     const struct sshbuf *message, const char *sig_namespace,
     struct sshbuf **out, sshsig_signer *signer, void *signer_ctx)
 {
@@ -445,7 +446,7 @@ sshsig_signb(struct sshkey *key, const char *hashalg, const char *sk_provider,
                error("%s: hash_buffer failed: %s", __func__, ssh_err(r));
                goto out;
        }
-       if ((r = sshsig_wrap_sign(key, hashalg, sk_provider, b,
+       if ((r = sshsig_wrap_sign(key, hashalg, sk_provider, sk_pin, b,
            sig_namespace, out, signer, signer_ctx)) != 0)
                goto out;
        /* success */
@@ -558,7 +559,8 @@ hash_file(int fd, const char *hashalg, struct sshbuf **bp)
 }
 
 int
-sshsig_sign_fd(struct sshkey *key, const char *hashalg, const char *sk_provider,
+sshsig_sign_fd(struct sshkey *key, const char *hashalg,
+    const char *sk_provider, const char *sk_pin,
     int fd, const char *sig_namespace, struct sshbuf **out,
     sshsig_signer *signer, void *signer_ctx)
 {
@@ -573,7 +575,7 @@ sshsig_sign_fd(struct sshkey *key, const char *hashalg, const char *sk_provider,
                error("%s: hash_file failed: %s", __func__, ssh_err(r));
                return r;
        }
-       if ((r = sshsig_wrap_sign(key, hashalg, sk_provider, b,
+       if ((r = sshsig_wrap_sign(key, hashalg, sk_provider, sk_pin, b,
            sig_namespace, out, signer, signer_ctx)) != 0)
                goto out;
        /* success */
index 63cc1ad1a2036b924aea66738b42256111d2c2c7..44157bc2ace473dd55a90df824d1b53e2a48d270 100644 (file)
--- a/sshsig.h
+++ b/sshsig.h
@@ -23,7 +23,8 @@ struct sshsigopt;
 struct sshkey_sig_details;
 
 typedef int sshsig_signer(struct sshkey *, u_char **, size_t *,
-    const u_char *, size_t, const char *, const char *, u_int, void *);
+    const u_char *, size_t, const char *, const char *, const char *,
+    u_int, void *);
 
 /* Buffer-oriented API */
 
@@ -33,7 +34,7 @@ typedef int sshsig_signer(struct sshkey *, u_char **, size_t *,
  * out is populated with the detached signature, or NULL on failure.
  */
 int sshsig_signb(struct sshkey *key, const char *hashalg,
-    const char *sk_provider, const struct sshbuf *message,
+    const char *sk_provider, const char *sk_pin, const struct sshbuf *message,
     const char *sig_namespace, struct sshbuf **out,
     sshsig_signer *signer, void *signer_ctx);
 
@@ -54,7 +55,8 @@ int sshsig_verifyb(struct sshbuf *signature,
  * out is populated with the detached signature, or NULL on failure.
  */
 int sshsig_sign_fd(struct sshkey *key, const char *hashalg,
-    const char *sk_provider, int fd, const char *sig_namespace,
+    const char *sk_provider, const char *sk_pin,
+    int fd, const char *sig_namespace,
     struct sshbuf **out, sshsig_signer *signer, void *signer_ctx);
 
 /*