diff options
author | djm@openbsd.org <djm@openbsd.org> | 2017-06-28 01:09:22 +0000 |
---|---|---|
committer | Damien Miller <djm@mindrot.org> | 2017-06-28 11:13:19 +1000 |
commit | a98339edbc1fc21342a390f345179a9c3031bef7 (patch) | |
tree | 574e103d0a458f96213e808118eb75d39bc3387f /ssh-keygen.c | |
parent | c9cdef35524bd59007e17d5bd2502dade69e2dfb (diff) |
upstream commit
Allow ssh-keygen to use a key held in ssh-agent as a CA when
signing certificates. bz#2377 ok markus
Upstream-ID: fb42e920b592edcbb5b50465739a867c09329c8f
Diffstat (limited to 'ssh-keygen.c')
-rw-r--r-- | ssh-keygen.c | 76 |
1 files changed, 67 insertions, 9 deletions
diff --git a/ssh-keygen.c b/ssh-keygen.c index cc3a7df18..b6b690051 100644 --- a/ssh-keygen.c +++ b/ssh-keygen.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: ssh-keygen.c,v 1.304 2017/05/30 14:16:41 markus Exp $ */ | 1 | /* $OpenBSD: ssh-keygen.c,v 1.305 2017/06/28 01:09:22 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 |
@@ -59,6 +59,7 @@ | |||
59 | #include "krl.h" | 59 | #include "krl.h" |
60 | #include "digest.h" | 60 | #include "digest.h" |
61 | #include "utf8.h" | 61 | #include "utf8.h" |
62 | #include "authfd.h" | ||
62 | 63 | ||
63 | #ifdef WITH_OPENSSL | 64 | #ifdef WITH_OPENSSL |
64 | # define DEFAULT_KEY_TYPE_NAME "rsa" | 65 | # define DEFAULT_KEY_TYPE_NAME "rsa" |
@@ -121,6 +122,9 @@ char *identity_comment = NULL; | |||
121 | /* Path to CA key when certifying keys. */ | 122 | /* Path to CA key when certifying keys. */ |
122 | char *ca_key_path = NULL; | 123 | char *ca_key_path = NULL; |
123 | 124 | ||
125 | /* Prefer to use agent keys for CA signing */ | ||
126 | int prefer_agent = 0; | ||
127 | |||
124 | /* Certificate serial number */ | 128 | /* Certificate serial number */ |
125 | unsigned long long cert_serial = 0; | 129 | unsigned long long cert_serial = 0; |
126 | 130 | ||
@@ -1597,24 +1601,66 @@ load_pkcs11_key(char *path) | |||
1597 | #endif /* ENABLE_PKCS11 */ | 1601 | #endif /* ENABLE_PKCS11 */ |
1598 | } | 1602 | } |
1599 | 1603 | ||
1604 | /* Signer for sshkey_certify_custom that uses the agent */ | ||
1605 | static int | ||
1606 | agent_signer(const struct sshkey *key, u_char **sigp, size_t *lenp, | ||
1607 | const u_char *data, size_t datalen, | ||
1608 | const char *alg, u_int compat, void *ctx) | ||
1609 | { | ||
1610 | int *agent_fdp = (int *)ctx; | ||
1611 | |||
1612 | return ssh_agent_sign(*agent_fdp, key, sigp, lenp, | ||
1613 | data, datalen, alg, compat); | ||
1614 | } | ||
1615 | |||
1600 | static void | 1616 | static void |
1601 | do_ca_sign(struct passwd *pw, int argc, char **argv) | 1617 | do_ca_sign(struct passwd *pw, int argc, char **argv) |
1602 | { | 1618 | { |
1603 | int r, i, fd; | 1619 | int r, i, fd, found, agent_fd = -1; |
1604 | u_int n; | 1620 | u_int n; |
1605 | struct sshkey *ca, *public; | 1621 | struct sshkey *ca, *public; |
1606 | char valid[64], *otmp, *tmp, *cp, *out, *comment, **plist = NULL; | 1622 | char valid[64], *otmp, *tmp, *cp, *out, *comment, **plist = NULL; |
1607 | FILE *f; | 1623 | FILE *f; |
1624 | struct ssh_identitylist *agent_ids; | ||
1625 | size_t j; | ||
1608 | 1626 | ||
1609 | #ifdef ENABLE_PKCS11 | 1627 | #ifdef ENABLE_PKCS11 |
1610 | pkcs11_init(1); | 1628 | pkcs11_init(1); |
1611 | #endif | 1629 | #endif |
1612 | tmp = tilde_expand_filename(ca_key_path, pw->pw_uid); | 1630 | tmp = tilde_expand_filename(ca_key_path, pw->pw_uid); |
1613 | if (pkcs11provider != NULL) { | 1631 | if (pkcs11provider != NULL) { |
1632 | /* If a PKCS#11 token was specified then try to use it */ | ||
1614 | if ((ca = load_pkcs11_key(tmp)) == NULL) | 1633 | if ((ca = load_pkcs11_key(tmp)) == NULL) |
1615 | fatal("No PKCS#11 key matching %s found", ca_key_path); | 1634 | fatal("No PKCS#11 key matching %s found", ca_key_path); |
1616 | } else | 1635 | } else if (prefer_agent) { |
1636 | /* | ||
1637 | * Agent signature requested. Try to use agent after making | ||
1638 | * sure the public key specified is actually present in the | ||
1639 | * agent. | ||
1640 | */ | ||
1641 | if ((r = sshkey_load_public(tmp, &ca, NULL)) != 0) | ||
1642 | fatal("Cannot load CA public key %s: %s", | ||
1643 | tmp, ssh_err(r)); | ||
1644 | if ((r = ssh_get_authentication_socket(&agent_fd)) != 0) | ||
1645 | fatal("Cannot use public key for CA signature: %s", | ||
1646 | ssh_err(r)); | ||
1647 | if ((r = ssh_fetch_identitylist(agent_fd, &agent_ids)) != 0) | ||
1648 | fatal("Retrieve agent key list: %s", ssh_err(r)); | ||
1649 | found = 0; | ||
1650 | for (j = 0; j < agent_ids->nkeys; j++) { | ||
1651 | if (sshkey_equal(ca, agent_ids->keys[j])) { | ||
1652 | found = 1; | ||
1653 | break; | ||
1654 | } | ||
1655 | } | ||
1656 | if (!found) | ||
1657 | fatal("CA key %s not found in agent", tmp); | ||
1658 | ssh_free_identitylist(agent_ids); | ||
1659 | ca->flags |= SSHKEY_FLAG_EXT; | ||
1660 | } else { | ||
1661 | /* CA key is assumed to be a private key on the filesystem */ | ||
1617 | ca = load_identity(tmp); | 1662 | ca = load_identity(tmp); |
1663 | } | ||
1618 | free(tmp); | 1664 | free(tmp); |
1619 | 1665 | ||
1620 | if (key_type_name != NULL && | 1666 | if (key_type_name != NULL && |
@@ -1664,8 +1710,16 @@ do_ca_sign(struct passwd *pw, int argc, char **argv) | |||
1664 | &public->cert->signature_key)) != 0) | 1710 | &public->cert->signature_key)) != 0) |
1665 | fatal("sshkey_from_private (ca key): %s", ssh_err(r)); | 1711 | fatal("sshkey_from_private (ca key): %s", ssh_err(r)); |
1666 | 1712 | ||
1667 | if ((r = sshkey_certify(public, ca, key_type_name)) != 0) | 1713 | if (agent_fd != -1 && (ca->flags & SSHKEY_FLAG_EXT) != 0) { |
1668 | fatal("Couldn't certify key %s: %s", tmp, ssh_err(r)); | 1714 | if ((r = sshkey_certify_custom(public, ca, |
1715 | key_type_name, agent_signer, &agent_fd)) != 0) | ||
1716 | fatal("Couldn't certify key %s via agent: %s", | ||
1717 | tmp, ssh_err(r)); | ||
1718 | } else { | ||
1719 | if ((sshkey_certify(public, ca, key_type_name)) != 0) | ||
1720 | fatal("Couldn't certify key %s: %s", | ||
1721 | tmp, ssh_err(r)); | ||
1722 | } | ||
1669 | 1723 | ||
1670 | if ((cp = strrchr(tmp, '.')) != NULL && strcmp(cp, ".pub") == 0) | 1724 | if ((cp = strrchr(tmp, '.')) != NULL && strcmp(cp, ".pub") == 0) |
1671 | *cp = '\0'; | 1725 | *cp = '\0'; |
@@ -2261,8 +2315,9 @@ usage(void) | |||
2261 | " ssh-keygen -T output_file -f input_file [-v] [-a rounds] [-J num_lines]\n" | 2315 | " ssh-keygen -T output_file -f input_file [-v] [-a rounds] [-J num_lines]\n" |
2262 | " [-j start_line] [-K checkpt] [-W generator]\n" | 2316 | " [-j start_line] [-K checkpt] [-W generator]\n" |
2263 | #endif | 2317 | #endif |
2264 | " ssh-keygen -s ca_key -I certificate_identity [-h] [-n principals]\n" | 2318 | " ssh-keygen -s ca_key -I certificate_identity [-h] [-U]\n" |
2265 | " [-O option] [-V validity_interval] [-z serial_number] file ...\n" | 2319 | " [-D pkcs11_provider] [-n principals] [-O option]\n" |
2320 | " [-V validity_interval] [-z serial_number] file ...\n" | ||
2266 | " ssh-keygen -L [-f input_keyfile]\n" | 2321 | " ssh-keygen -L [-f input_keyfile]\n" |
2267 | " ssh-keygen -A\n" | 2322 | " ssh-keygen -A\n" |
2268 | " ssh-keygen -k -f krl_file [-u] [-s ca_public] [-z version_number]\n" | 2323 | " ssh-keygen -k -f krl_file [-u] [-s ca_public] [-z version_number]\n" |
@@ -2320,8 +2375,8 @@ main(int argc, char **argv) | |||
2320 | if (gethostname(hostname, sizeof(hostname)) < 0) | 2375 | if (gethostname(hostname, sizeof(hostname)) < 0) |
2321 | fatal("gethostname: %s", strerror(errno)); | 2376 | fatal("gethostname: %s", strerror(errno)); |
2322 | 2377 | ||
2323 | /* Remaining characters: UYdw */ | 2378 | /* Remaining characters: Ydw */ |
2324 | while ((opt = getopt(argc, argv, "ABHLQXceghiklopquvxy" | 2379 | while ((opt = getopt(argc, argv, "ABHLQUXceghiklopquvxy" |
2325 | "C:D:E:F:G:I:J:K:M:N:O:P:R:S:T:V:W:Z:" | 2380 | "C:D:E:F:G:I:J:K:M:N:O:P:R:S:T:V:W:Z:" |
2326 | "a:b:f:g:j:m:n:r:s:t:z:")) != -1) { | 2381 | "a:b:f:g:j:m:n:r:s:t:z:")) != -1) { |
2327 | switch (opt) { | 2382 | switch (opt) { |
@@ -2448,6 +2503,9 @@ main(int argc, char **argv) | |||
2448 | case 'D': | 2503 | case 'D': |
2449 | pkcs11provider = optarg; | 2504 | pkcs11provider = optarg; |
2450 | break; | 2505 | break; |
2506 | case 'U': | ||
2507 | prefer_agent = 1; | ||
2508 | break; | ||
2451 | case 'u': | 2509 | case 'u': |
2452 | update_krl = 1; | 2510 | update_krl = 1; |
2453 | break; | 2511 | break; |