summaryrefslogtreecommitdiff
path: root/ssh-keygen.c
diff options
context:
space:
mode:
Diffstat (limited to 'ssh-keygen.c')
-rw-r--r--ssh-keygen.c336
1 files changed, 195 insertions, 141 deletions
diff --git a/ssh-keygen.c b/ssh-keygen.c
index 2c5c75db7..a12b79a56 100644
--- a/ssh-keygen.c
+++ b/ssh-keygen.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: ssh-keygen.c,v 1.409.2.1 2020/05/18 19:02:13 benno Exp $ */ 1/* $OpenBSD: ssh-keygen.c,v 1.420 2020/09/09 03:08:01 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
@@ -133,13 +133,13 @@ static char *certflags_command = NULL;
133static char *certflags_src_addr = NULL; 133static char *certflags_src_addr = NULL;
134 134
135/* Arbitrary extensions specified by user */ 135/* Arbitrary extensions specified by user */
136struct cert_userext { 136struct cert_ext {
137 char *key; 137 char *key;
138 char *val; 138 char *val;
139 int crit; 139 int crit;
140}; 140};
141static struct cert_userext *cert_userext; 141static struct cert_ext *cert_ext;
142static size_t ncert_userext; 142static size_t ncert_ext;
143 143
144/* Conversion to/from various formats */ 144/* Conversion to/from various formats */
145enum { 145enum {
@@ -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);
@@ -815,10 +815,14 @@ do_print_public(struct passwd *pw)
815 prv = load_identity(identity_file, &comment); 815 prv = load_identity(identity_file, &comment);
816 if ((r = sshkey_write(prv, stdout)) != 0) 816 if ((r = sshkey_write(prv, stdout)) != 0)
817 error("sshkey_write failed: %s", ssh_err(r)); 817 error("sshkey_write failed: %s", ssh_err(r));
818 sshkey_free(prv);
819 if (comment != NULL && *comment != '\0') 818 if (comment != NULL && *comment != '\0')
820 fprintf(stdout, " %s", comment); 819 fprintf(stdout, " %s", comment);
821 fprintf(stdout, "\n"); 820 fprintf(stdout, "\n");
821 if (sshkey_is_sk(prv)) {
822 debug("sk_application: \"%s\", sk_flags 0x%02x",
823 prv->sk_application, prv->sk_flags);
824 }
825 sshkey_free(prv);
822 free(comment); 826 free(comment);
823 exit(0); 827 exit(0);
824} 828}
@@ -1292,6 +1296,7 @@ do_known_hosts(struct passwd *pw, const char *name, int find_host,
1292 int r, fd, oerrno, inplace = 0; 1296 int r, fd, oerrno, inplace = 0;
1293 struct known_hosts_ctx ctx; 1297 struct known_hosts_ctx ctx;
1294 u_int foreach_options; 1298 u_int foreach_options;
1299 struct stat sb;
1295 1300
1296 if (!have_identity) { 1301 if (!have_identity) {
1297 cp = tilde_expand_filename(_PATH_SSH_USER_HOSTFILE, pw->pw_uid); 1302 cp = tilde_expand_filename(_PATH_SSH_USER_HOSTFILE, pw->pw_uid);
@@ -1301,6 +1306,8 @@ do_known_hosts(struct passwd *pw, const char *name, int find_host,
1301 free(cp); 1306 free(cp);
1302 have_identity = 1; 1307 have_identity = 1;
1303 } 1308 }
1309 if (stat(identity_file, &sb) != 0)
1310 fatal("Cannot stat %s: %s", identity_file, strerror(errno));
1304 1311
1305 memset(&ctx, 0, sizeof(ctx)); 1312 memset(&ctx, 0, sizeof(ctx));
1306 ctx.out = stdout; 1313 ctx.out = stdout;
@@ -1327,6 +1334,7 @@ do_known_hosts(struct passwd *pw, const char *name, int find_host,
1327 unlink(tmp); 1334 unlink(tmp);
1328 fatal("fdopen: %s", strerror(oerrno)); 1335 fatal("fdopen: %s", strerror(oerrno));
1329 } 1336 }
1337 fchmod(fd, sb.st_mode & 0644);
1330 inplace = 1; 1338 inplace = 1;
1331 } 1339 }
1332 /* XXX support identity_file == "-" for stdin */ 1340 /* XXX support identity_file == "-" for stdin */
@@ -1597,31 +1605,32 @@ do_change_comment(struct passwd *pw, const char *identity_comment)
1597} 1605}
1598 1606
1599static void 1607static void
1600add_flag_option(struct sshbuf *c, const char *name) 1608cert_ext_add(const char *key, const char *value, int iscrit)
1601{ 1609{
1602 int r; 1610 cert_ext = xreallocarray(cert_ext, ncert_ext + 1, sizeof(*cert_ext));
1603 1611 cert_ext[ncert_ext].key = xstrdup(key);
1604 debug3("%s: %s", __func__, name); 1612 cert_ext[ncert_ext].val = value == NULL ? NULL : xstrdup(value);
1605 if ((r = sshbuf_put_cstring(c, name)) != 0 || 1613 cert_ext[ncert_ext].crit = iscrit;
1606 (r = sshbuf_put_string(c, NULL, 0)) != 0) 1614 ncert_ext++;
1607 fatal("%s: buffer error: %s", __func__, ssh_err(r));
1608} 1615}
1609 1616
1610static void 1617/* qsort(3) comparison function for certificate extensions */
1611add_string_option(struct sshbuf *c, const char *name, const char *value) 1618static int
1619cert_ext_cmp(const void *_a, const void *_b)
1612{ 1620{
1613 struct sshbuf *b; 1621 const struct cert_ext *a = (const struct cert_ext *)_a;
1622 const struct cert_ext *b = (const struct cert_ext *)_b;
1614 int r; 1623 int r;
1615 1624
1616 debug3("%s: %s=%s", __func__, name, value); 1625 if (a->crit != b->crit)
1617 if ((b = sshbuf_new()) == NULL) 1626 return (a->crit < b->crit) ? -1 : 1;
1618 fatal("%s: sshbuf_new failed", __func__); 1627 if ((r = strcmp(a->key, b->key)) != 0)
1619 if ((r = sshbuf_put_cstring(b, value)) != 0 || 1628 return r;
1620 (r = sshbuf_put_cstring(c, name)) != 0 || 1629 if ((a->val == NULL) != (b->val == NULL))
1621 (r = sshbuf_put_stringb(c, b)) != 0) 1630 return (a->val == NULL) ? -1 : 1;
1622 fatal("%s: buffer error: %s", __func__, ssh_err(r)); 1631 if (a->val != NULL && (r = strcmp(a->val, b->val)) != 0)
1623 1632 return r;
1624 sshbuf_free(b); 1633 return 0;
1625} 1634}
1626 1635
1627#define OPTIONS_CRITICAL 1 1636#define OPTIONS_CRITICAL 1
@@ -1629,44 +1638,62 @@ add_string_option(struct sshbuf *c, const char *name, const char *value)
1629static void 1638static void
1630prepare_options_buf(struct sshbuf *c, int which) 1639prepare_options_buf(struct sshbuf *c, int which)
1631{ 1640{
1641 struct sshbuf *b;
1632 size_t i; 1642 size_t i;
1643 int r;
1644 const struct cert_ext *ext;
1633 1645
1646 if ((b = sshbuf_new()) == NULL)
1647 fatal("%s: sshbuf_new failed", __func__);
1634 sshbuf_reset(c); 1648 sshbuf_reset(c);
1635 if ((which & OPTIONS_CRITICAL) != 0 && 1649 for (i = 0; i < ncert_ext; i++) {
1636 certflags_command != NULL) 1650 ext = &cert_ext[i];
1637 add_string_option(c, "force-command", certflags_command); 1651 if ((ext->crit && (which & OPTIONS_EXTENSIONS)) ||
1638 if ((which & OPTIONS_EXTENSIONS) != 0 && 1652 (!ext->crit && (which & OPTIONS_CRITICAL)))
1639 (certflags_flags & CERTOPT_X_FWD) != 0)
1640 add_flag_option(c, "permit-X11-forwarding");
1641 if ((which & OPTIONS_EXTENSIONS) != 0 &&
1642 (certflags_flags & CERTOPT_AGENT_FWD) != 0)
1643 add_flag_option(c, "permit-agent-forwarding");
1644 if ((which & OPTIONS_EXTENSIONS) != 0 &&
1645 (certflags_flags & CERTOPT_PORT_FWD) != 0)
1646 add_flag_option(c, "permit-port-forwarding");
1647 if ((which & OPTIONS_EXTENSIONS) != 0 &&
1648 (certflags_flags & CERTOPT_PTY) != 0)
1649 add_flag_option(c, "permit-pty");
1650 if ((which & OPTIONS_EXTENSIONS) != 0 &&
1651 (certflags_flags & CERTOPT_USER_RC) != 0)
1652 add_flag_option(c, "permit-user-rc");
1653 if ((which & OPTIONS_EXTENSIONS) != 0 &&
1654 (certflags_flags & CERTOPT_NO_REQUIRE_USER_PRESENCE) != 0)
1655 add_flag_option(c, "no-touch-required");
1656 if ((which & OPTIONS_CRITICAL) != 0 &&
1657 certflags_src_addr != NULL)
1658 add_string_option(c, "source-address", certflags_src_addr);
1659 for (i = 0; i < ncert_userext; i++) {
1660 if ((cert_userext[i].crit && (which & OPTIONS_EXTENSIONS)) ||
1661 (!cert_userext[i].crit && (which & OPTIONS_CRITICAL)))
1662 continue; 1653 continue;
1663 if (cert_userext[i].val == NULL) 1654 if (ext->val == NULL) {
1664 add_flag_option(c, cert_userext[i].key); 1655 /* flag option */
1665 else { 1656 debug3("%s: %s", __func__, ext->key);
1666 add_string_option(c, cert_userext[i].key, 1657 if ((r = sshbuf_put_cstring(c, ext->key)) != 0 ||
1667 cert_userext[i].val); 1658 (r = sshbuf_put_string(c, NULL, 0)) != 0)
1659 fatal("%s: buffer: %s", __func__, ssh_err(r));
1660 } else {
1661 /* key/value option */
1662 debug3("%s: %s=%s", __func__, ext->key, ext->val);
1663 sshbuf_reset(b);
1664 if ((r = sshbuf_put_cstring(c, ext->key)) != 0 ||
1665 (r = sshbuf_put_cstring(b, ext->val)) != 0 ||
1666 (r = sshbuf_put_stringb(c, b)) != 0)
1667 fatal("%s: buffer: %s", __func__, ssh_err(r));
1668 } 1668 }
1669 } 1669 }
1670 sshbuf_free(b);
1671}
1672
1673static void
1674finalise_cert_exts(void)
1675{
1676 /* critical options */
1677 if (certflags_command != NULL)
1678 cert_ext_add("force-command", certflags_command, 1);
1679 if (certflags_src_addr != NULL)
1680 cert_ext_add("source-address", certflags_src_addr, 1);
1681 /* extensions */
1682 if ((certflags_flags & CERTOPT_X_FWD) != 0)
1683 cert_ext_add("permit-X11-forwarding", NULL, 0);
1684 if ((certflags_flags & CERTOPT_AGENT_FWD) != 0)
1685 cert_ext_add("permit-agent-forwarding", NULL, 0);
1686 if ((certflags_flags & CERTOPT_PORT_FWD) != 0)
1687 cert_ext_add("permit-port-forwarding", NULL, 0);
1688 if ((certflags_flags & CERTOPT_PTY) != 0)
1689 cert_ext_add("permit-pty", NULL, 0);
1690 if ((certflags_flags & CERTOPT_USER_RC) != 0)
1691 cert_ext_add("permit-user-rc", NULL, 0);
1692 if ((certflags_flags & CERTOPT_NO_REQUIRE_USER_PRESENCE) != 0)
1693 cert_ext_add("no-touch-required", NULL, 0);
1694 /* order lexically by key */
1695 if (ncert_ext > 0)
1696 qsort(cert_ext, ncert_ext, sizeof(*cert_ext), cert_ext_cmp);
1670} 1697}
1671 1698
1672static struct sshkey * 1699static struct sshkey *
@@ -1704,7 +1731,8 @@ load_pkcs11_key(char *path)
1704static int 1731static int
1705agent_signer(struct sshkey *key, u_char **sigp, size_t *lenp, 1732agent_signer(struct sshkey *key, u_char **sigp, size_t *lenp,
1706 const u_char *data, size_t datalen, 1733 const u_char *data, size_t datalen,
1707 const char *alg, const char *provider, u_int compat, void *ctx) 1734 const char *alg, const char *provider, const char *pin,
1735 u_int compat, void *ctx)
1708{ 1736{
1709 int *agent_fdp = (int *)ctx; 1737 int *agent_fdp = (int *)ctx;
1710 1738
@@ -1721,7 +1749,7 @@ do_ca_sign(struct passwd *pw, const char *ca_key_path, int prefer_agent,
1721 u_int n; 1749 u_int n;
1722 struct sshkey *ca, *public; 1750 struct sshkey *ca, *public;
1723 char valid[64], *otmp, *tmp, *cp, *out, *comment; 1751 char valid[64], *otmp, *tmp, *cp, *out, *comment;
1724 char *ca_fp = NULL, **plist = NULL; 1752 char *ca_fp = NULL, **plist = NULL, *pin = NULL;
1725 struct ssh_identitylist *agent_ids; 1753 struct ssh_identitylist *agent_ids;
1726 size_t j; 1754 size_t j;
1727 struct notifier_ctx *notifier = NULL; 1755 struct notifier_ctx *notifier = NULL;
@@ -1762,6 +1790,12 @@ do_ca_sign(struct passwd *pw, const char *ca_key_path, int prefer_agent,
1762 } else { 1790 } else {
1763 /* CA key is assumed to be a private key on the filesystem */ 1791 /* CA key is assumed to be a private key on the filesystem */
1764 ca = load_identity(tmp, NULL); 1792 ca = load_identity(tmp, NULL);
1793 if (sshkey_is_sk(ca) &&
1794 (ca->sk_flags & SSH_SK_USER_VERIFICATION_REQD)) {
1795 if ((pin = read_passphrase("Enter PIN for CA key: ",
1796 RP_ALLOW_STDIN)) == NULL)
1797 fatal("%s: couldn't read PIN", __func__);
1798 }
1765 } 1799 }
1766 free(tmp); 1800 free(tmp);
1767 1801
@@ -1776,6 +1810,7 @@ do_ca_sign(struct passwd *pw, const char *ca_key_path, int prefer_agent,
1776 } 1810 }
1777 ca_fp = sshkey_fingerprint(ca, fingerprint_hash, SSH_FP_DEFAULT); 1811 ca_fp = sshkey_fingerprint(ca, fingerprint_hash, SSH_FP_DEFAULT);
1778 1812
1813 finalise_cert_exts();
1779 for (i = 0; i < argc; i++) { 1814 for (i = 0; i < argc; i++) {
1780 /* Split list of principals */ 1815 /* Split list of principals */
1781 n = 0; 1816 n = 0;
@@ -1820,7 +1855,7 @@ do_ca_sign(struct passwd *pw, const char *ca_key_path, int prefer_agent,
1820 1855
1821 if (agent_fd != -1 && (ca->flags & SSHKEY_FLAG_EXT) != 0) { 1856 if (agent_fd != -1 && (ca->flags & SSHKEY_FLAG_EXT) != 0) {
1822 if ((r = sshkey_certify_custom(public, ca, 1857 if ((r = sshkey_certify_custom(public, ca,
1823 key_type_name, sk_provider, agent_signer, 1858 key_type_name, sk_provider, NULL, agent_signer,
1824 &agent_fd)) != 0) 1859 &agent_fd)) != 0)
1825 fatal("Couldn't certify key %s via agent: %s", 1860 fatal("Couldn't certify key %s via agent: %s",
1826 tmp, ssh_err(r)); 1861 tmp, ssh_err(r));
@@ -1832,7 +1867,7 @@ do_ca_sign(struct passwd *pw, const char *ca_key_path, int prefer_agent,
1832 sshkey_type(ca), ca_fp); 1867 sshkey_type(ca), ca_fp);
1833 } 1868 }
1834 r = sshkey_certify(public, ca, key_type_name, 1869 r = sshkey_certify(public, ca, key_type_name,
1835 sk_provider); 1870 sk_provider, pin);
1836 notify_complete(notifier); 1871 notify_complete(notifier);
1837 if (r != 0) 1872 if (r != 0)
1838 fatal("Couldn't certify key %s: %s", 1873 fatal("Couldn't certify key %s: %s",
@@ -1866,6 +1901,8 @@ do_ca_sign(struct passwd *pw, const char *ca_key_path, int prefer_agent,
1866 if (cert_serial_autoinc) 1901 if (cert_serial_autoinc)
1867 cert_serial++; 1902 cert_serial++;
1868 } 1903 }
1904 if (pin != NULL)
1905 freezero(pin, strlen(pin));
1869 free(ca_fp); 1906 free(ca_fp);
1870#ifdef ENABLE_PKCS11 1907#ifdef ENABLE_PKCS11
1871 pkcs11_terminate(); 1908 pkcs11_terminate();
@@ -1990,13 +2027,8 @@ add_cert_option(char *opt)
1990 val = xstrdup(strchr(opt, ':') + 1); 2027 val = xstrdup(strchr(opt, ':') + 1);
1991 if ((cp = strchr(val, '=')) != NULL) 2028 if ((cp = strchr(val, '=')) != NULL)
1992 *cp++ = '\0'; 2029 *cp++ = '\0';
1993 cert_userext = xreallocarray(cert_userext, ncert_userext + 1, 2030 cert_ext_add(val, cp, iscrit);
1994 sizeof(*cert_userext)); 2031 free(val);
1995 cert_userext[ncert_userext].key = val;
1996 cert_userext[ncert_userext].val = cp == NULL ?
1997 NULL : xstrdup(cp);
1998 cert_userext[ncert_userext].crit = iscrit;
1999 ncert_userext++;
2000 } else 2032 } else
2001 fatal("Unsupported certificate option \"%s\"", opt); 2033 fatal("Unsupported certificate option \"%s\"", opt);
2002} 2034}
@@ -2004,7 +2036,7 @@ add_cert_option(char *opt)
2004static void 2036static void
2005show_options(struct sshbuf *optbuf, int in_critical) 2037show_options(struct sshbuf *optbuf, int in_critical)
2006{ 2038{
2007 char *name, *arg; 2039 char *name, *arg, *hex;
2008 struct sshbuf *options, *option = NULL; 2040 struct sshbuf *options, *option = NULL;
2009 int r; 2041 int r;
2010 2042
@@ -2033,11 +2065,14 @@ show_options(struct sshbuf *optbuf, int in_critical)
2033 __func__, ssh_err(r)); 2065 __func__, ssh_err(r));
2034 printf(" %s\n", arg); 2066 printf(" %s\n", arg);
2035 free(arg); 2067 free(arg);
2036 } else { 2068 } else if (sshbuf_len(option) > 0) {
2037 printf(" UNKNOWN OPTION (len %zu)\n", 2069 hex = sshbuf_dtob16(option);
2038 sshbuf_len(option)); 2070 printf(" UNKNOWN OPTION: %s (len %zu)\n",
2071 hex, sshbuf_len(option));
2039 sshbuf_reset(option); 2072 sshbuf_reset(option);
2040 } 2073 free(hex);
2074 } else
2075 printf(" UNKNOWN FLAG OPTION\n");
2041 free(name); 2076 free(name);
2042 if (sshbuf_len(option) != 0) 2077 if (sshbuf_len(option) != 0)
2043 fatal("Option corrupt: extra data at end"); 2078 fatal("Option corrupt: extra data at end");
@@ -2504,6 +2539,7 @@ sign_one(struct sshkey *signkey, const char *filename, int fd,
2504 struct sshbuf *sigbuf = NULL, *abuf = NULL; 2539 struct sshbuf *sigbuf = NULL, *abuf = NULL;
2505 int r = SSH_ERR_INTERNAL_ERROR, wfd = -1, oerrno; 2540 int r = SSH_ERR_INTERNAL_ERROR, wfd = -1, oerrno;
2506 char *wfile = NULL, *asig = NULL, *fp = NULL; 2541 char *wfile = NULL, *asig = NULL, *fp = NULL;
2542 char *pin = NULL, *prompt = NULL;
2507 2543
2508 if (!quiet) { 2544 if (!quiet) {
2509 if (fd == STDIN_FILENO) 2545 if (fd == STDIN_FILENO)
@@ -2511,17 +2547,25 @@ sign_one(struct sshkey *signkey, const char *filename, int fd,
2511 else 2547 else
2512 fprintf(stderr, "Signing file %s\n", filename); 2548 fprintf(stderr, "Signing file %s\n", filename);
2513 } 2549 }
2514 if (signer == NULL && sshkey_is_sk(signkey) && 2550 if (signer == NULL && sshkey_is_sk(signkey)) {
2515 (signkey->sk_flags & SSH_SK_USER_PRESENCE_REQD)) { 2551 if ((signkey->sk_flags & SSH_SK_USER_VERIFICATION_REQD)) {
2516 if ((fp = sshkey_fingerprint(signkey, fingerprint_hash, 2552 xasprintf(&prompt, "Enter PIN for %s key: ",
2517 SSH_FP_DEFAULT)) == NULL) 2553 sshkey_type(signkey));
2518 fatal("%s: sshkey_fingerprint failed", __func__); 2554 if ((pin = read_passphrase(prompt,
2519 fprintf(stderr, "Confirm user presence for key %s %s\n", 2555 RP_ALLOW_STDIN)) == NULL)
2520 sshkey_type(signkey), fp); 2556 fatal("%s: couldn't read PIN", __func__);
2521 free(fp); 2557 }
2558 if ((signkey->sk_flags & SSH_SK_USER_PRESENCE_REQD)) {
2559 if ((fp = sshkey_fingerprint(signkey, fingerprint_hash,
2560 SSH_FP_DEFAULT)) == NULL)
2561 fatal("%s: fingerprint failed", __func__);
2562 fprintf(stderr, "Confirm user presence for key %s %s\n",
2563 sshkey_type(signkey), fp);
2564 free(fp);
2565 }
2522 } 2566 }
2523 if ((r = sshsig_sign_fd(signkey, NULL, sk_provider, fd, sig_namespace, 2567 if ((r = sshsig_sign_fd(signkey, NULL, sk_provider, pin,
2524 &sigbuf, signer, signer_ctx)) != 0) { 2568 fd, sig_namespace, &sigbuf, signer, signer_ctx)) != 0) {
2525 error("Signing %s failed: %s", filename, ssh_err(r)); 2569 error("Signing %s failed: %s", filename, ssh_err(r));
2526 goto out; 2570 goto out;
2527 } 2571 }
@@ -2569,7 +2613,10 @@ sign_one(struct sshkey *signkey, const char *filename, int fd,
2569 r = 0; 2613 r = 0;
2570 out: 2614 out:
2571 free(wfile); 2615 free(wfile);
2616 free(prompt);
2572 free(asig); 2617 free(asig);
2618 if (pin != NULL)
2619 freezero(pin, strlen(pin));
2573 sshbuf_free(abuf); 2620 sshbuf_free(abuf);
2574 sshbuf_free(sigbuf); 2621 sshbuf_free(sigbuf);
2575 if (wfd != -1) 2622 if (wfd != -1)
@@ -2934,27 +2981,24 @@ do_download_sk(const char *skprovider, const char *device)
2934{ 2981{
2935 struct sshkey **keys; 2982 struct sshkey **keys;
2936 size_t nkeys, i; 2983 size_t nkeys, i;
2937 int r, ok = -1; 2984 int r, ret = -1;
2938 char *fp, *pin = NULL, *pass = NULL, *path, *pubpath; 2985 char *fp, *pin = NULL, *pass = NULL, *path, *pubpath;
2939 const char *ext; 2986 const char *ext;
2940 2987
2941 if (skprovider == NULL) 2988 if (skprovider == NULL)
2942 fatal("Cannot download keys without provider"); 2989 fatal("Cannot download keys without provider");
2943 2990
2944 for (i = 0; i < 2; i++) { 2991 pin = read_passphrase("Enter PIN for authenticator: ", RP_ALLOW_STDIN);
2945 if (i == 1) { 2992 if (!quiet) {
2946 pin = read_passphrase("Enter PIN for authenticator: ", 2993 printf("You may need to touch your authenticator "
2947 RP_ALLOW_STDIN); 2994 "to authorize key download.\n");
2948 } 2995 }
2949 if ((r = sshsk_load_resident(skprovider, device, pin, 2996 if ((r = sshsk_load_resident(skprovider, device, pin,
2950 &keys, &nkeys)) != 0) { 2997 &keys, &nkeys)) != 0) {
2951 if (i == 0 && r == SSH_ERR_KEY_WRONG_PASSPHRASE) 2998 if (pin != NULL)
2952 continue; 2999 freezero(pin, strlen(pin));
2953 if (pin != NULL) 3000 error("Unable to load resident keys: %s", ssh_err(r));
2954 freezero(pin, strlen(pin)); 3001 return -1;
2955 error("Unable to load resident keys: %s", ssh_err(r));
2956 return -1;
2957 }
2958 } 3002 }
2959 if (nkeys == 0) 3003 if (nkeys == 0)
2960 logit("No keys to download"); 3004 logit("No keys to download");
@@ -3018,28 +3062,50 @@ do_download_sk(const char *skprovider, const char *device)
3018 } 3062 }
3019 3063
3020 if (i >= nkeys) 3064 if (i >= nkeys)
3021 ok = 0; /* success */ 3065 ret = 0; /* success */
3022 if (pass != NULL) 3066 if (pass != NULL)
3023 freezero(pass, strlen(pass)); 3067 freezero(pass, strlen(pass));
3024 for (i = 0; i < nkeys; i++) 3068 for (i = 0; i < nkeys; i++)
3025 sshkey_free(keys[i]); 3069 sshkey_free(keys[i]);
3026 free(keys); 3070 free(keys);
3027 return ok ? 0 : -1; 3071 return ret;
3072}
3073
3074static void
3075save_attestation(struct sshbuf *attest, const char *path)
3076{
3077 mode_t omask;
3078 int r;
3079
3080 if (path == NULL)
3081 return; /* nothing to do */
3082 if (attest == NULL || sshbuf_len(attest) == 0)
3083 fatal("Enrollment did not return attestation data");
3084 omask = umask(077);
3085 r = sshbuf_write_file(path, attest);
3086 umask(omask);
3087 if (r != 0)
3088 fatal("Unable to write attestation data \"%s\": %s", path,
3089 ssh_err(r));
3090 if (!quiet)
3091 printf("Your FIDO attestation certificate has been saved in "
3092 "%s\n", path);
3028} 3093}
3029 3094
3030static void 3095static void
3031usage(void) 3096usage(void)
3032{ 3097{
3033 fprintf(stderr, 3098 fprintf(stderr,
3034 "usage: ssh-keygen [-q] [-b bits] [-C comment] [-f output_keyfile] [-m format]\n" 3099 "usage: ssh-keygen [-q] [-a rounds] [-b bits] [-C comment] [-f output_keyfile]\n"
3100 " [-m format] [-N new_passphrase] [-O option]\n"
3035 " [-t dsa | ecdsa | ecdsa-sk | ed25519 | ed25519-sk | rsa]\n" 3101 " [-t dsa | ecdsa | ecdsa-sk | ed25519 | ed25519-sk | rsa]\n"
3036 " [-N new_passphrase] [-O option] [-w provider]\n" 3102 " [-w provider]\n"
3037 " ssh-keygen -p [-f keyfile] [-m format] [-N new_passphrase]\n" 3103 " ssh-keygen -p [-a rounds] [-f keyfile] [-m format] [-N new_passphrase]\n"
3038 " [-P old_passphrase]\n" 3104 " [-P old_passphrase]\n"
3039 " ssh-keygen -i [-f input_keyfile] [-m key_format]\n" 3105 " ssh-keygen -i [-f input_keyfile] [-m key_format]\n"
3040 " ssh-keygen -e [-f input_keyfile] [-m key_format]\n" 3106 " ssh-keygen -e [-f input_keyfile] [-m key_format]\n"
3041 " ssh-keygen -y [-f input_keyfile]\n" 3107 " ssh-keygen -y [-f input_keyfile]\n"
3042 " ssh-keygen -c [-C comment] [-f keyfile] [-P passphrase]\n" 3108 " ssh-keygen -c [-a rounds] [-C comment] [-f keyfile] [-P passphrase]\n"
3043 " ssh-keygen -l [-v] [-E fingerprint_hash] [-f input_keyfile]\n" 3109 " ssh-keygen -l [-v] [-E fingerprint_hash] [-f input_keyfile]\n"
3044 " ssh-keygen -B [-f input_keyfile]\n"); 3110 " ssh-keygen -B [-f input_keyfile]\n");
3045#ifdef ENABLE_PKCS11 3111#ifdef ENABLE_PKCS11
@@ -3049,7 +3115,7 @@ usage(void)
3049 fprintf(stderr, 3115 fprintf(stderr,
3050 " ssh-keygen -F hostname [-lv] [-f known_hosts_file]\n" 3116 " ssh-keygen -F hostname [-lv] [-f known_hosts_file]\n"
3051 " ssh-keygen -H [-f known_hosts_file]\n" 3117 " ssh-keygen -H [-f known_hosts_file]\n"
3052 " ssh-keygen -K [-w provider]\n" 3118 " ssh-keygen -K [-a rounds] [-w provider]\n"
3053 " ssh-keygen -R hostname [-f known_hosts_file]\n" 3119 " ssh-keygen -R hostname [-f known_hosts_file]\n"
3054 " ssh-keygen -r hostname [-g] [-f input_keyfile]\n" 3120 " ssh-keygen -r hostname [-g] [-f input_keyfile]\n"
3055#ifdef WITH_OPENSSL 3121#ifdef WITH_OPENSSL
@@ -3060,7 +3126,7 @@ usage(void)
3060 " [-n principals] [-O option] [-V validity_interval]\n" 3126 " [-n principals] [-O option] [-V validity_interval]\n"
3061 " [-z serial_number] file ...\n" 3127 " [-z serial_number] file ...\n"
3062 " ssh-keygen -L [-f input_keyfile]\n" 3128 " ssh-keygen -L [-f input_keyfile]\n"
3063 " ssh-keygen -A [-f prefix_path]\n" 3129 " ssh-keygen -A [-a rounds] [-f prefix_path]\n"
3064 " ssh-keygen -k -f krl_file [-u] [-s ca_public] [-z version_number]\n" 3130 " ssh-keygen -k -f krl_file [-u] [-s ca_public] [-z version_number]\n"
3065 " file ...\n" 3131 " file ...\n"
3066 " ssh-keygen -Q [-l] -f krl_file [file ...]\n" 3132 " ssh-keygen -Q [-l] -f krl_file [file ...]\n"
@@ -3078,11 +3144,10 @@ usage(void)
3078int 3144int
3079main(int argc, char **argv) 3145main(int argc, char **argv)
3080{ 3146{
3081 char dotsshdir[PATH_MAX], comment[1024], *passphrase; 3147 char comment[1024], *passphrase;
3082 char *rr_hostname = NULL, *ep, *fp, *ra; 3148 char *rr_hostname = NULL, *ep, *fp, *ra;
3083 struct sshkey *private, *public; 3149 struct sshkey *private, *public;
3084 struct passwd *pw; 3150 struct passwd *pw;
3085 struct stat st;
3086 int r, opt, type; 3151 int r, opt, type;
3087 int change_passphrase = 0, change_comment = 0, show_cert = 0; 3152 int change_passphrase = 0, change_comment = 0, show_cert = 0;
3088 int find_host = 0, delete_host = 0, hash_hosts = 0; 3153 int find_host = 0, delete_host = 0, hash_hosts = 0;
@@ -3093,7 +3158,7 @@ main(int argc, char **argv)
3093 unsigned long long cert_serial = 0; 3158 unsigned long long cert_serial = 0;
3094 char *identity_comment = NULL, *ca_key_path = NULL, **opts = NULL; 3159 char *identity_comment = NULL, *ca_key_path = NULL, **opts = NULL;
3095 char *sk_application = NULL, *sk_device = NULL, *sk_user = NULL; 3160 char *sk_application = NULL, *sk_device = NULL, *sk_user = NULL;
3096 char *sk_attestaion_path = NULL; 3161 char *sk_attestation_path = NULL;
3097 struct sshbuf *challenge = NULL, *attest = NULL; 3162 struct sshbuf *challenge = NULL, *attest = NULL;
3098 size_t i, nopts = 0; 3163 size_t i, nopts = 0;
3099 u_int32_t bits = 0; 3164 u_int32_t bits = 0;
@@ -3532,6 +3597,8 @@ main(int argc, char **argv)
3532 for (i = 0; i < nopts; i++) { 3597 for (i = 0; i < nopts; i++) {
3533 if (strcasecmp(opts[i], "no-touch-required") == 0) { 3598 if (strcasecmp(opts[i], "no-touch-required") == 0) {
3534 sk_flags &= ~SSH_SK_USER_PRESENCE_REQD; 3599 sk_flags &= ~SSH_SK_USER_PRESENCE_REQD;
3600 } else if (strcasecmp(opts[i], "verify-required") == 0) {
3601 sk_flags |= SSH_SK_USER_VERIFICATION_REQD;
3535 } else if (strcasecmp(opts[i], "resident") == 0) { 3602 } else if (strcasecmp(opts[i], "resident") == 0) {
3536 sk_flags |= SSH_SK_RESIDENT_KEY; 3603 sk_flags |= SSH_SK_RESIDENT_KEY;
3537 } else if (strncasecmp(opts[i], "device=", 7) == 0) { 3604 } else if (strncasecmp(opts[i], "device=", 7) == 0) {
@@ -3547,7 +3614,7 @@ main(int argc, char **argv)
3547 } 3614 }
3548 } else if (strncasecmp(opts[i], 3615 } else if (strncasecmp(opts[i],
3549 "write-attestation=", 18) == 0) { 3616 "write-attestation=", 18) == 0) {
3550 sk_attestaion_path = opts[i] + 18; 3617 sk_attestation_path = opts[i] + 18;
3551 } else if (strncasecmp(opts[i], 3618 } else if (strncasecmp(opts[i],
3552 "application=", 12) == 0) { 3619 "application=", 12) == 0) {
3553 sk_application = xstrdup(opts[i] + 12); 3620 sk_application = xstrdup(opts[i] + 12);
@@ -3564,9 +3631,15 @@ main(int argc, char **argv)
3564 printf("You may need to touch your authenticator " 3631 printf("You may need to touch your authenticator "
3565 "to authorize key generation.\n"); 3632 "to authorize key generation.\n");
3566 } 3633 }
3567 passphrase = NULL;
3568 if ((attest = sshbuf_new()) == NULL) 3634 if ((attest = sshbuf_new()) == NULL)
3569 fatal("sshbuf_new failed"); 3635 fatal("sshbuf_new failed");
3636 if ((sk_flags &
3637 (SSH_SK_USER_VERIFICATION_REQD|SSH_SK_RESIDENT_KEY))) {
3638 passphrase = read_passphrase("Enter PIN for "
3639 "authenticator: ", RP_ALLOW_STDIN);
3640 } else {
3641 passphrase = NULL;
3642 }
3570 for (i = 0 ; ; i++) { 3643 for (i = 0 ; ; i++) {
3571 fflush(stdout); 3644 fflush(stdout);
3572 r = sshsk_enroll(type, sk_provider, sk_device, 3645 r = sshsk_enroll(type, sk_provider, sk_device,
@@ -3577,9 +3650,8 @@ main(int argc, char **argv)
3577 break; 3650 break;
3578 if (r != SSH_ERR_KEY_WRONG_PASSPHRASE) 3651 if (r != SSH_ERR_KEY_WRONG_PASSPHRASE)
3579 fatal("Key enrollment failed: %s", ssh_err(r)); 3652 fatal("Key enrollment failed: %s", ssh_err(r));
3580 else if (i > 0) 3653 else if (passphrase != NULL) {
3581 error("PIN incorrect"); 3654 error("PIN incorrect");
3582 if (passphrase != NULL) {
3583 freezero(passphrase, strlen(passphrase)); 3655 freezero(passphrase, strlen(passphrase));
3584 passphrase = NULL; 3656 passphrase = NULL;
3585 } 3657 }
@@ -3587,6 +3659,11 @@ main(int argc, char **argv)
3587 fatal("Too many incorrect PINs"); 3659 fatal("Too many incorrect PINs");
3588 passphrase = read_passphrase("Enter PIN for " 3660 passphrase = read_passphrase("Enter PIN for "
3589 "authenticator: ", RP_ALLOW_STDIN); 3661 "authenticator: ", RP_ALLOW_STDIN);
3662 if (!quiet) {
3663 printf("You may need to touch your "
3664 "authenticator (again) to authorize "
3665 "key generation.\n");
3666 }
3590 } 3667 }
3591 if (passphrase != NULL) { 3668 if (passphrase != NULL) {
3592 freezero(passphrase, strlen(passphrase)); 3669 freezero(passphrase, strlen(passphrase));
@@ -3605,20 +3682,8 @@ main(int argc, char **argv)
3605 ask_filename(pw, "Enter file in which to save the key"); 3682 ask_filename(pw, "Enter file in which to save the key");
3606 3683
3607 /* Create ~/.ssh directory if it doesn't already exist. */ 3684 /* Create ~/.ssh directory if it doesn't already exist. */
3608 snprintf(dotsshdir, sizeof dotsshdir, "%s/%s", 3685 hostfile_create_user_ssh_dir(identity_file, !quiet);
3609 pw->pw_dir, _PATH_SSH_USER_DIR); 3686
3610 if (strstr(identity_file, dotsshdir) != NULL) {
3611 if (stat(dotsshdir, &st) == -1) {
3612 if (errno != ENOENT) {
3613 error("Could not stat %s: %s", dotsshdir,
3614 strerror(errno));
3615 } else if (mkdir(dotsshdir, 0700) == -1) {
3616 error("Could not create directory '%s': %s",
3617 dotsshdir, strerror(errno));
3618 } else if (!quiet)
3619 printf("Created directory '%s'.\n", dotsshdir);
3620 }
3621 }
3622 /* If the file already exists, ask the user to confirm. */ 3687 /* If the file already exists, ask the user to confirm. */
3623 if (!confirm_overwrite(identity_file)) 3688 if (!confirm_overwrite(identity_file))
3624 exit(1); 3689 exit(1);
@@ -3671,20 +3736,9 @@ main(int argc, char **argv)
3671 free(fp); 3736 free(fp);
3672 } 3737 }
3673 3738
3674 if (sk_attestaion_path != NULL) { 3739 if (sk_attestation_path != NULL)
3675 if (attest == NULL || sshbuf_len(attest) == 0) { 3740 save_attestation(attest, sk_attestation_path);
3676 fatal("Enrollment did not return attestation " 3741
3677 "certificate");
3678 }
3679 if ((r = sshbuf_write_file(sk_attestaion_path, attest)) != 0) {
3680 fatal("Unable to write attestation certificate "
3681 "\"%s\": %s", sk_attestaion_path, ssh_err(r));
3682 }
3683 if (!quiet) {
3684 printf("Your FIDO attestation certificate has been "
3685 "saved in %s\n", sk_attestaion_path);
3686 }
3687 }
3688 sshbuf_free(attest); 3742 sshbuf_free(attest);
3689 sshkey_free(public); 3743 sshkey_free(public);
3690 3744