Bugzilla – Attachment 2983 Details for
Bug 2377
Add ssh-agent support to ssh-keygen
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
allow CA signature operation to use keys hosted in ssh-agent
keygen-ca-agent1.diff (text/plain), 9.86 KB, created by
Damien Miller
on 2017-05-25 12:29:32 AEST
(
hide
)
Description:
allow CA signature operation to use keys hosted in ssh-agent
Filename:
MIME Type:
Creator:
Damien Miller
Created:
2017-05-25 12:29:32 AEST
Size:
9.86 KB
patch
obsolete
>commit d060cc7b961a51deda464427a54b686970ece58d >Author: Damien Miller <djm@mindrot.org> >Date: Thu May 25 12:05:01 2017 +1000 > > ability to use ssh-agent for CA operation > >diff --git a/authfd.c b/authfd.c >index 8486e28b..7a2a3e41 100644 >--- a/authfd.c >+++ b/authfd.c >@@ -326,7 +326,7 @@ ssh_free_identitylist(struct ssh_identitylist *idl) > > /* encode signature algoritm in flag bits, so we can keep the msg format */ > static u_int >-agent_encode_alg(struct sshkey *key, const char *alg) >+agent_encode_alg(const struct sshkey *key, const char *alg) > { > if (alg != NULL && key->type == KEY_RSA) { > if (strcmp(alg, "rsa-sha2-256") == 0) >@@ -339,7 +339,7 @@ agent_encode_alg(struct sshkey *key, const char *alg) > > /* ask agent to sign data, returns err.h code on error, 0 on success */ > int >-ssh_agent_sign(int sock, struct sshkey *key, >+ssh_agent_sign(int sock, const struct sshkey *key, > u_char **sigp, size_t *lenp, > const u_char *data, size_t datalen, const char *alg, u_int compat) > { >diff --git a/authfd.h b/authfd.h >index 0e98331d..805642ee 100644 >--- a/authfd.h >+++ b/authfd.h >@@ -38,7 +38,7 @@ int ssh_remove_all_identities(int sock, int version); > > int ssh_decrypt_challenge(int sock, struct sshkey* key, BIGNUM *challenge, > u_char session_id[16], u_char response[16]); >-int ssh_agent_sign(int sock, struct sshkey *key, >+int ssh_agent_sign(int sock, const struct sshkey *key, > u_char **sigp, size_t *lenp, > const u_char *data, size_t datalen, const char *alg, u_int compat); > >diff --git a/ssh-keygen.1 b/ssh-keygen.1 >index 786d37d5..492df3f4 100644 >--- a/ssh-keygen.1 >+++ b/ssh-keygen.1 >@@ -114,6 +114,8 @@ > .Fl s Ar ca_key > .Fl I Ar certificate_identity > .Op Fl h >+.Op Fl U >+.Op Fl D Ar pkcs11_provider > .Op Fl n Ar principals > .Op Fl O Ar option > .Op Fl V Ar validity_interval >@@ -558,6 +560,14 @@ The possible values are > .Dq ed25519 , > or > .Dq rsa . >+.It Fl U >+When used in combination with >+.Fl s , >+this option indicates that a CA key resides in a >+.Xr ssh-agent 1 . >+See the >+.Sx CERTIFICATES >+section for more information. > .It Fl u > Update a KRL. > When specified with >@@ -705,6 +715,14 @@ to > .Pp > .Dl $ ssh-keygen -s ca_key.pub -D libpkcs11.so -I key_id user_key.pub > .Pp >+Similarly, it is possible for the CA key to be hosted in a >+.Xr ssh-agent 1 . >+This is indicated by the >+.Fl U >+flag and, again, the CA key must be identified by its public half. >+.Pp >+.Dl $ ssh-keygen -Us ca_key.pub -I key_id user_key.pub >+.Pp > In all cases, > .Ar key_id > is a "key identifier" that is logged by the server when the certificate >diff --git a/ssh-keygen.c b/ssh-keygen.c >index 7886582d..233a0975 100644 >--- a/ssh-keygen.c >+++ b/ssh-keygen.c >@@ -59,6 +59,7 @@ > #include "krl.h" > #include "digest.h" > #include "utf8.h" >+#include "authfd.h" > > #ifdef WITH_OPENSSL > # define DEFAULT_KEY_TYPE_NAME "rsa" >@@ -121,6 +122,9 @@ char *identity_comment = NULL; > /* Path to CA key when certifying keys. */ > char *ca_key_path = NULL; > >+/* Prefer to use agent keys for CA signing */ >+int prefer_agent = 0; >+ > /* Certificate serial number */ > unsigned long long cert_serial = 0; > >@@ -1597,24 +1601,66 @@ load_pkcs11_key(char *path) > #endif /* ENABLE_PKCS11 */ > } > >+/* Signer for sshkey_certify that uses the agent */ >+static int >+agent_signer(const struct sshkey *key, u_char **sigp, size_t *lenp, >+ const u_char *data, size_t datalen, >+ const char *alg, u_int compat, void *ctx) >+{ >+ int *agent_fdp = (int *)ctx; >+ >+ return ssh_agent_sign(*agent_fdp, key, sigp, lenp, >+ data, datalen, alg, compat); >+} >+ > static void > do_ca_sign(struct passwd *pw, int argc, char **argv) > { >- int r, i, fd; >+ int r, i, fd, found, agent_fd = -1; > u_int n; > struct sshkey *ca, *public; > char valid[64], *otmp, *tmp, *cp, *out, *comment, **plist = NULL; > FILE *f; >+ struct ssh_identitylist *agent_ids; >+ size_t j; > > #ifdef ENABLE_PKCS11 > pkcs11_init(1); > #endif > tmp = tilde_expand_filename(ca_key_path, pw->pw_uid); > if (pkcs11provider != NULL) { >+ /* If a PKCS#11 token was specified then try to use it */ > if ((ca = load_pkcs11_key(tmp)) == NULL) > fatal("No PKCS#11 key matching %s found", ca_key_path); >- } else >+ } else if (prefer_agent) { >+ /* >+ * Agent signature requested. Try to use agent after making >+ * sure the public key specified is actually present in the >+ * agent. >+ */ >+ if ((r = sshkey_load_public(tmp, &ca, NULL)) != 0) >+ fatal("Cannot load CA public key %s: %s", >+ tmp, ssh_err(r)); >+ if ((r = ssh_get_authentication_socket(&agent_fd)) != 0) >+ fatal("Cannot use public key for CA signature: %s", >+ ssh_err(r)); >+ if ((r = ssh_fetch_identitylist(agent_fd, &agent_ids)) != 0) >+ fatal("Retrieve agent key list: %s", ssh_err(r)); >+ found = 0; >+ for (j = 0; j < agent_ids->nkeys; j++) { >+ if (sshkey_equal(ca, agent_ids->keys[j])) { >+ found = 1; >+ break; >+ } >+ } >+ if (!found) >+ fatal("CA key %s not found in agent", tmp); >+ ssh_free_identitylist(agent_ids); >+ ca->flags |= SSHKEY_FLAG_EXT; >+ } else { >+ /* CA key is assumed to be a private key on the filesystem */ > ca = load_identity(tmp); >+ } > free(tmp); > > if (key_type_name != NULL && >@@ -1664,8 +1710,16 @@ do_ca_sign(struct passwd *pw, int argc, char **argv) > &public->cert->signature_key)) != 0) > fatal("key_from_private (ca key): %s", ssh_err(r)); > >- if ((r = sshkey_certify(public, ca, key_type_name)) != 0) >- fatal("Couldn't certify key %s: %s", tmp, ssh_err(r)); >+ if (agent_fd != -1 && (ca->flags & SSHKEY_FLAG_EXT) != 0) { >+ if ((r = sshkey_certify_custom(public, ca, >+ key_type_name, agent_signer, &agent_fd)) != 0) >+ fatal("Couldn't certify key %s via agent: %s", >+ tmp, ssh_err(r)); >+ } else { >+ if ((sshkey_certify(public, ca, key_type_name)) != 0) >+ fatal("Couldn't certify key %s: %s", >+ tmp, ssh_err(r)); >+ } > > if ((cp = strrchr(tmp, '.')) != NULL && strcmp(cp, ".pub") == 0) > *cp = '\0'; >@@ -2261,8 +2315,9 @@ usage(void) > " ssh-keygen -T output_file -f input_file [-v] [-a rounds] [-J num_lines]\n" > " [-j start_line] [-K checkpt] [-W generator]\n" > #endif >- " ssh-keygen -s ca_key -I certificate_identity [-h] [-n principals]\n" >- " [-O option] [-V validity_interval] [-z serial_number] file ...\n" >+ " ssh-keygen -s ca_key -I certificate_identity [-h] [-U]\n" >+ " [-D pkcs11_provider] [-n principals] [-O option]\n" >+ " [-V validity_interval] [-z serial_number] file ...\n" > " ssh-keygen -L [-f input_keyfile]\n" > " ssh-keygen -A\n" > " ssh-keygen -k -f krl_file [-u] [-s ca_public] [-z version_number]\n" >@@ -2320,8 +2375,8 @@ main(int argc, char **argv) > if (gethostname(hostname, sizeof(hostname)) < 0) > fatal("gethostname: %s", strerror(errno)); > >- /* Remaining characters: UYdw */ >- while ((opt = getopt(argc, argv, "ABHLQXceghiklopquvxy" >+ /* Remaining characters: Ydw */ >+ while ((opt = getopt(argc, argv, "ABHLQUXceghiklopquvxy" > "C:D:E:F:G:I:J:K:M:N:O:P:R:S:T:V:W:Z:" > "a:b:f:g:j:m:n:r:s:t:z:")) != -1) { > switch (opt) { >@@ -2448,6 +2503,9 @@ main(int argc, char **argv) > case 'D': > pkcs11provider = optarg; > break; >+ case 'U': >+ prefer_agent = 1; >+ break; > case 'u': > update_krl = 1; > break; >diff --git a/sshkey.c b/sshkey.c >index f9518bd7..b5ff8559 100644 >--- a/sshkey.c >+++ b/sshkey.c >@@ -2252,7 +2252,8 @@ sshkey_drop_cert(struct sshkey *k) > > /* Sign a certified key, (re-)generating the signed certblob. */ > int >-sshkey_certify(struct sshkey *k, struct sshkey *ca, const char *alg) >+sshkey_certify_custom(struct sshkey *k, struct sshkey *ca, const char *alg, >+ sshkey_certify_signer *signer, void *signer_ctx) > { > struct sshbuf *principals = NULL; > u_char *ca_blob = NULL, *sig_blob = NULL, nonce[32]; >@@ -2341,8 +2342,8 @@ sshkey_certify(struct sshkey *k, struct sshkey *ca, const char *alg) > goto out; > > /* Sign the whole mess */ >- if ((ret = sshkey_sign(ca, &sig_blob, &sig_len, sshbuf_ptr(cert), >- sshbuf_len(cert), alg, 0)) != 0) >+ if ((ret = signer(ca, &sig_blob, &sig_len, sshbuf_ptr(cert), >+ sshbuf_len(cert), alg, 0, signer_ctx)) != 0) > goto out; > > /* Append signature and we are done */ >@@ -2358,6 +2359,22 @@ sshkey_certify(struct sshkey *k, struct sshkey *ca, const char *alg) > return ret; > } > >+static int >+default_key_sign(const struct sshkey *key, u_char **sigp, size_t *lenp, >+ const u_char *data, size_t datalen, >+ const char *alg, u_int compat, void *ctx) >+{ >+ if (ctx != NULL) >+ return SSH_ERR_INVALID_ARGUMENT; >+ return sshkey_sign(key, sigp, lenp, data, datalen, alg, compat); >+} >+ >+int >+sshkey_certify(struct sshkey *k, struct sshkey *ca, const char *alg) >+{ >+ return sshkey_certify_custom(k, ca, alg, default_key_sign, NULL); >+} >+ > int > sshkey_cert_check_authority(const struct sshkey *k, > int want_host, int require_principal, >diff --git a/sshkey.h b/sshkey.h >index b0b5b274..f0440291 100644 >--- a/sshkey.h >+++ b/sshkey.h >@@ -136,13 +136,19 @@ int sshkey_type_is_cert(int); > int sshkey_type_plain(int); > int sshkey_to_certified(struct sshkey *); > int sshkey_drop_cert(struct sshkey *); >-int sshkey_certify(struct sshkey *, struct sshkey *, const char *); > int sshkey_cert_copy(const struct sshkey *, struct sshkey *); > int sshkey_cert_check_authority(const struct sshkey *, int, int, > const char *, const char **); > size_t sshkey_format_cert_validity(const struct sshkey_cert *, > char *, size_t) __attribute__((__bounded__(__string__, 2, 3))); > >+int sshkey_certify(struct sshkey *, struct sshkey *, const char *); >+/* Variant allowing use of a custom signature function (e.g. for ssh-agent) */ >+typedef int sshkey_certify_signer(const struct sshkey *, u_char **, size_t *, >+ const u_char *, size_t, const char *, u_int, void *); >+int sshkey_certify_custom(struct sshkey *, struct sshkey *, const char *, >+ sshkey_certify_signer *, void *); >+ > int sshkey_ecdsa_nid_from_name(const char *); > int sshkey_curve_name_to_nid(const char *); > const char * sshkey_curve_nid_to_name(int);
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 2377
:
2690
|
2692
|
2887
| 2983