summaryrefslogtreecommitdiff
path: root/ssh-keygen.c
diff options
context:
space:
mode:
authordjm@openbsd.org <djm@openbsd.org>2020-08-27 01:06:18 +0000
committerDamien Miller <djm@mindrot.org>2020-08-27 11:28:36 +1000
commit9b8ad93824c682ce841f53f3b5762cef4e7cc4dc (patch)
treed4523956d4623b19bf5904d1b92afeb2307f69d3 /ssh-keygen.c
parent1196d7f49d4fbc90f37e550de3056561613b0960 (diff)
upstream: support for user-verified FIDO keys
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
Diffstat (limited to 'ssh-keygen.c')
-rw-r--r--ssh-keygen.c55
1 files changed, 39 insertions, 16 deletions
diff --git a/ssh-keygen.c b/ssh-keygen.c
index cc092368e..89ef9a143 100644
--- a/ssh-keygen.c
+++ b/ssh-keygen.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: ssh-keygen.c,v 1.415 2020/08/03 02:53:51 djm Exp $ */ 1/* $OpenBSD: ssh-keygen.c,v 1.416 2020/08/27 01:06:18 djm Exp $ */
2/* 2/*
3 * Author: Tatu Ylonen <ylo@cs.hut.fi> 3 * Author: Tatu Ylonen <ylo@cs.hut.fi>
4 * Copyright (c) 1994 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4 * Copyright (c) 1994 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -589,7 +589,7 @@ do_convert_private_ssh2(struct sshbuf *b)
589 589
590 /* try the key */ 590 /* try the key */
591 if (sshkey_sign(key, &sig, &slen, data, sizeof(data), 591 if (sshkey_sign(key, &sig, &slen, data, sizeof(data),
592 NULL, NULL, 0) != 0 || 592 NULL, NULL, NULL, 0) != 0 ||
593 sshkey_verify(key, sig, slen, data, sizeof(data), 593 sshkey_verify(key, sig, slen, data, sizeof(data),
594 NULL, 0, NULL) != 0) { 594 NULL, 0, NULL) != 0) {
595 sshkey_free(key); 595 sshkey_free(key);
@@ -1727,7 +1727,8 @@ load_pkcs11_key(char *path)
1727static int 1727static int
1728agent_signer(struct sshkey *key, u_char **sigp, size_t *lenp, 1728agent_signer(struct sshkey *key, u_char **sigp, size_t *lenp,
1729 const u_char *data, size_t datalen, 1729 const u_char *data, size_t datalen,
1730 const char *alg, const char *provider, u_int compat, void *ctx) 1730 const char *alg, const char *provider, const char *pin,
1731 u_int compat, void *ctx)
1731{ 1732{
1732 int *agent_fdp = (int *)ctx; 1733 int *agent_fdp = (int *)ctx;
1733 1734
@@ -1744,7 +1745,7 @@ do_ca_sign(struct passwd *pw, const char *ca_key_path, int prefer_agent,
1744 u_int n; 1745 u_int n;
1745 struct sshkey *ca, *public; 1746 struct sshkey *ca, *public;
1746 char valid[64], *otmp, *tmp, *cp, *out, *comment; 1747 char valid[64], *otmp, *tmp, *cp, *out, *comment;
1747 char *ca_fp = NULL, **plist = NULL; 1748 char *ca_fp = NULL, **plist = NULL, *pin = NULL;
1748 struct ssh_identitylist *agent_ids; 1749 struct ssh_identitylist *agent_ids;
1749 size_t j; 1750 size_t j;
1750 struct notifier_ctx *notifier = NULL; 1751 struct notifier_ctx *notifier = NULL;
@@ -1785,6 +1786,12 @@ do_ca_sign(struct passwd *pw, const char *ca_key_path, int prefer_agent,
1785 } else { 1786 } else {
1786 /* CA key is assumed to be a private key on the filesystem */ 1787 /* CA key is assumed to be a private key on the filesystem */
1787 ca = load_identity(tmp, NULL); 1788 ca = load_identity(tmp, NULL);
1789 if (sshkey_is_sk(ca) &&
1790 (ca->sk_flags & SSH_SK_USER_VERIFICATION_REQD)) {
1791 if ((pin = read_passphrase("Enter PIN for CA key: ",
1792 RP_ALLOW_STDIN)) == NULL)
1793 fatal("%s: couldn't read PIN", __func__);
1794 }
1788 } 1795 }
1789 free(tmp); 1796 free(tmp);
1790 1797
@@ -1844,7 +1851,7 @@ do_ca_sign(struct passwd *pw, const char *ca_key_path, int prefer_agent,
1844 1851
1845 if (agent_fd != -1 && (ca->flags & SSHKEY_FLAG_EXT) != 0) { 1852 if (agent_fd != -1 && (ca->flags & SSHKEY_FLAG_EXT) != 0) {
1846 if ((r = sshkey_certify_custom(public, ca, 1853 if ((r = sshkey_certify_custom(public, ca,
1847 key_type_name, sk_provider, agent_signer, 1854 key_type_name, sk_provider, NULL, agent_signer,
1848 &agent_fd)) != 0) 1855 &agent_fd)) != 0)
1849 fatal("Couldn't certify key %s via agent: %s", 1856 fatal("Couldn't certify key %s via agent: %s",
1850 tmp, ssh_err(r)); 1857 tmp, ssh_err(r));
@@ -1856,7 +1863,7 @@ do_ca_sign(struct passwd *pw, const char *ca_key_path, int prefer_agent,
1856 sshkey_type(ca), ca_fp); 1863 sshkey_type(ca), ca_fp);
1857 } 1864 }
1858 r = sshkey_certify(public, ca, key_type_name, 1865 r = sshkey_certify(public, ca, key_type_name,
1859 sk_provider); 1866 sk_provider, pin);
1860 notify_complete(notifier); 1867 notify_complete(notifier);
1861 if (r != 0) 1868 if (r != 0)
1862 fatal("Couldn't certify key %s: %s", 1869 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,
1890 if (cert_serial_autoinc) 1897 if (cert_serial_autoinc)
1891 cert_serial++; 1898 cert_serial++;
1892 } 1899 }
1900 if (pin != NULL)
1901 freezero(pin, strlen(pin));
1893 free(ca_fp); 1902 free(ca_fp);
1894#ifdef ENABLE_PKCS11 1903#ifdef ENABLE_PKCS11
1895 pkcs11_terminate(); 1904 pkcs11_terminate();
@@ -2526,6 +2535,7 @@ sign_one(struct sshkey *signkey, const char *filename, int fd,
2526 struct sshbuf *sigbuf = NULL, *abuf = NULL; 2535 struct sshbuf *sigbuf = NULL, *abuf = NULL;
2527 int r = SSH_ERR_INTERNAL_ERROR, wfd = -1, oerrno; 2536 int r = SSH_ERR_INTERNAL_ERROR, wfd = -1, oerrno;
2528 char *wfile = NULL, *asig = NULL, *fp = NULL; 2537 char *wfile = NULL, *asig = NULL, *fp = NULL;
2538 char *pin = NULL, *prompt = NULL;
2529 2539
2530 if (!quiet) { 2540 if (!quiet) {
2531 if (fd == STDIN_FILENO) 2541 if (fd == STDIN_FILENO)
@@ -2533,17 +2543,25 @@ sign_one(struct sshkey *signkey, const char *filename, int fd,
2533 else 2543 else
2534 fprintf(stderr, "Signing file %s\n", filename); 2544 fprintf(stderr, "Signing file %s\n", filename);
2535 } 2545 }
2536 if (signer == NULL && sshkey_is_sk(signkey) && 2546 if (signer == NULL && sshkey_is_sk(signkey)) {
2537 (signkey->sk_flags & SSH_SK_USER_PRESENCE_REQD)) { 2547 if ((signkey->sk_flags & SSH_SK_USER_VERIFICATION_REQD)) {
2538 if ((fp = sshkey_fingerprint(signkey, fingerprint_hash, 2548 xasprintf(&prompt, "Enter PIN for %s key: ",
2539 SSH_FP_DEFAULT)) == NULL) 2549 sshkey_type(signkey));
2540 fatal("%s: sshkey_fingerprint failed", __func__); 2550 if ((pin = read_passphrase(prompt,
2541 fprintf(stderr, "Confirm user presence for key %s %s\n", 2551 RP_ALLOW_STDIN)) == NULL)
2542 sshkey_type(signkey), fp); 2552 fatal("%s: couldn't read PIN", __func__);
2543 free(fp); 2553 }
2554 if ((signkey->sk_flags & SSH_SK_USER_PRESENCE_REQD)) {
2555 if ((fp = sshkey_fingerprint(signkey, fingerprint_hash,
2556 SSH_FP_DEFAULT)) == NULL)
2557 fatal("%s: fingerprint failed", __func__);
2558 fprintf(stderr, "Confirm user presence for key %s %s\n",
2559 sshkey_type(signkey), fp);
2560 free(fp);
2561 }
2544 } 2562 }
2545 if ((r = sshsig_sign_fd(signkey, NULL, sk_provider, fd, sig_namespace, 2563 if ((r = sshsig_sign_fd(signkey, NULL, sk_provider, pin,
2546 &sigbuf, signer, signer_ctx)) != 0) { 2564 fd, sig_namespace, &sigbuf, signer, signer_ctx)) != 0) {
2547 error("Signing %s failed: %s", filename, ssh_err(r)); 2565 error("Signing %s failed: %s", filename, ssh_err(r));
2548 goto out; 2566 goto out;
2549 } 2567 }
@@ -2591,7 +2609,10 @@ sign_one(struct sshkey *signkey, const char *filename, int fd,
2591 r = 0; 2609 r = 0;
2592 out: 2610 out:
2593 free(wfile); 2611 free(wfile);
2612 free(prompt);
2594 free(asig); 2613 free(asig);
2614 if (pin != NULL)
2615 freezero(pin, strlen(pin));
2595 sshbuf_free(abuf); 2616 sshbuf_free(abuf);
2596 sshbuf_free(sigbuf); 2617 sshbuf_free(sigbuf);
2597 if (wfd != -1) 2618 if (wfd != -1)
@@ -3554,6 +3575,8 @@ main(int argc, char **argv)
3554 for (i = 0; i < nopts; i++) { 3575 for (i = 0; i < nopts; i++) {
3555 if (strcasecmp(opts[i], "no-touch-required") == 0) { 3576 if (strcasecmp(opts[i], "no-touch-required") == 0) {
3556 sk_flags &= ~SSH_SK_USER_PRESENCE_REQD; 3577 sk_flags &= ~SSH_SK_USER_PRESENCE_REQD;
3578 } else if (strcasecmp(opts[i], "verify-required") == 0) {
3579 sk_flags |= SSH_SK_USER_VERIFICATION_REQD;
3557 } else if (strcasecmp(opts[i], "resident") == 0) { 3580 } else if (strcasecmp(opts[i], "resident") == 0) {
3558 sk_flags |= SSH_SK_RESIDENT_KEY; 3581 sk_flags |= SSH_SK_RESIDENT_KEY;
3559 } else if (strncasecmp(opts[i], "device=", 7) == 0) { 3582 } else if (strncasecmp(opts[i], "device=", 7) == 0) {