summaryrefslogtreecommitdiff
path: root/ssh-keygen.c
diff options
context:
space:
mode:
authordjm@openbsd.org <djm@openbsd.org>2017-06-28 01:09:22 +0000
committerDamien Miller <djm@mindrot.org>2017-06-28 11:13:19 +1000
commita98339edbc1fc21342a390f345179a9c3031bef7 (patch)
tree574e103d0a458f96213e808118eb75d39bc3387f /ssh-keygen.c
parentc9cdef35524bd59007e17d5bd2502dade69e2dfb (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.c76
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. */
122char *ca_key_path = NULL; 123char *ca_key_path = NULL;
123 124
125/* Prefer to use agent keys for CA signing */
126int prefer_agent = 0;
127
124/* Certificate serial number */ 128/* Certificate serial number */
125unsigned long long cert_serial = 0; 129unsigned 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 */
1605static int
1606agent_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
1600static void 1616static void
1601do_ca_sign(struct passwd *pw, int argc, char **argv) 1617do_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;