Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
SUSE:SLE-12-SP5:Update
openssh-askpass-gnome.32839
openssh-ssh-keygen-ssh-agent-intergration.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File openssh-ssh-keygen-ssh-agent-intergration.patch of Package openssh-askpass-gnome.32839
From 7cbf93fc11db07cd4fb205fbb6386b9e4db74762 Mon Sep 17 00:00:00 2001 From: Michal Suchanek <msuchanek@suse.de> Date: Fri, 11 Nov 2022 08:14:19 +0100 Subject: [PATCH] ssh-keygen ssh-agent intergration Patch-mainline: V_8_1_P1 Git-commit: 06af3583f46e2c327fdd44d8a95b8b4e8dfd8db5 OpenBSD-Commit-ID: d43c5826353e1fdc1af71eb42961b30782c7bd13 upstream: authfd: add function to check if key is in agent This commit adds a helper function which allows the caller to check if a given public key is present in ssh-agent. work by Sebastian Kinne; ok markus@ Differences in 7.2 - ssh_fetch_identitylist supports both v1 and v2 identities, only v2 is checked Patch-mainline: V_7_6_P1 Git-commit: a98339edbc1fc21342a390f345179a9c3031bef7 Upstream-ID: fb42e920b592edcbb5b50465739a867c09329c8f Allow ssh-keygen to use a key held in ssh-agent as a CA when signing certificates. bz#2377 ok markus Differences in 7.2 - ssh_fetch_identitylist supports both v1 and v2 identities, only v2 is tested - slightly different logic in do_ca_sign, missing key_type_name - missing alg paramater for sshkey_certify --- authfd.c | 30 +++++++++++++++++++-- authfd.h | 3 ++- ssh-keygen.1 | 18 +++++++++++++ ssh-keygen.c | 74 ++++++++++++++++++++++++++++++++++++++++++++++------ sshkey.c | 23 +++++++++++++--- sshkey.h | 8 +++++- 6 files changed, 141 insertions(+), 15 deletions(-) diff --git a/authfd.c b/authfd.c index a634bcb8..89ef2b28 100644 --- a/authfd.c +++ b/authfd.c @@ -378,6 +378,32 @@ ssh_free_identitylist(struct ssh_identitylist *idl) free(idl); } +/* + * Check if the ssh agent has a given key. + * Returns 0 if found, or a negative SSH_ERR_* error code on failure. + */ +int +ssh_agent_has_key(int sock, struct sshkey *key) +{ + int r, ret = SSH_ERR_KEY_NOT_FOUND; + size_t i; + struct ssh_identitylist *idlist = NULL; + + if ((r = ssh_fetch_identitylist(sock, 2, &idlist)) < 0) { + return r; + } + + for (i = 0; i < idlist->nkeys; i++) { + if (sshkey_equal_public(idlist->keys[i], key)) { + ret = 0; + break; + } + } + + ssh_free_identitylist(idlist); + return ret; +} + /* * Sends a challenge (typically from a server via ssh(1)) to the agent, * and waits for a response from the agent. @@ -428,7 +454,7 @@ ssh_decrypt_challenge(int sock, struct sshkey* key, BIGNUM *challenge, /* 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) @@ -441,7 +467,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 4b417e3f..5863e636 100644 --- a/authfd.h +++ b/authfd.h @@ -32,6 +32,7 @@ int ssh_fetch_identitylist(int sock, int version, void ssh_free_identitylist(struct ssh_identitylist *idl); int ssh_add_identity_constrained(int sock, struct sshkey *key, const char *comment, u_int life, u_int confirm); +int ssh_agent_has_key(int sock, struct sshkey *key); int ssh_remove_identity(int sock, struct sshkey *key); int ssh_update_card(int sock, int add, const char *reader_id, const char *pin, u_int life, u_int confirm); @@ -39,7 +40,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 46941fd1..5b0a049b 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 @@ -539,6 +541,14 @@ for protocol version 1 and or .Dq rsa for protocol version 2. +.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 @@ -686,6 +696,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 3df6c340..c2739e2b 100644 --- a/ssh-keygen.c +++ b/ssh-keygen.c @@ -59,6 +59,7 @@ #include "fips.h" +#include "authfd.h" #ifdef WITH_OPENSSL # define DEFAULT_KEY_TYPE_NAME "rsa" #else @@ -120,6 +121,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; @@ -1608,24 +1612,66 @@ load_pkcs11_key(char *path) #endif /* ENABLE_PKCS11 */ } +/* Signer for sshkey_certify_custom 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, 2, &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); for (i = 0; i < argc; i++) { @@ -1669,8 +1715,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 (sshkey_certify(public, ca) != 0) - fatal("Couldn't not certify key %s", tmp); + if (agent_fd != -1 && (ca->flags & SSHKEY_FLAG_EXT) != 0) { + if ((r = sshkey_certify_custom(public, ca, + agent_signer, &agent_fd)) != 0) + fatal("Couldn't certify key %s via agent: %s", + tmp, ssh_err(r)); + } else { + if ((sshkey_certify(public, ca)) != 0) + fatal("Couldn't certify key %s: %s", + tmp, ssh_err(r)); + } if ((cp = strrchr(tmp, '.')) != NULL && strcmp(cp, ".pub") == 0) *cp = '\0'; @@ -2253,8 +2307,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" @@ -2310,8 +2365,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) { @@ -2438,6 +2493,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 22d45d53..f4a81dfb 100644 --- a/sshkey.c +++ b/sshkey.c @@ -2396,7 +2396,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) +sshkey_certify_custom(struct sshkey *k, struct sshkey *ca, + sshkey_certify_signer *signer, void *signer_ctx) { struct sshbuf *principals = NULL; u_char *ca_blob = NULL, *sig_blob = NULL, nonce[32]; @@ -2485,8 +2486,8 @@ sshkey_certify(struct sshkey *k, struct sshkey *ca) goto out; /* Sign the whole mess */ - if ((ret = sshkey_sign(ca, &sig_blob, &sig_len, sshbuf_ptr(cert), - sshbuf_len(cert), NULL, 0)) != 0) + if ((ret = signer(ca, &sig_blob, &sig_len, sshbuf_ptr(cert), + sshbuf_len(cert), NULL, 0, signer_ctx)) != 0) goto out; /* Append signature and we are done */ @@ -2502,6 +2503,22 @@ sshkey_certify(struct sshkey *k, struct sshkey *ca) 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) +{ + return sshkey_certify_custom(k, ca, 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 f318863d..0bb14f35 100644 --- a/sshkey.h +++ b/sshkey.h @@ -139,13 +139,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 *); 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 *); +/* 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 *, + 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); -- 2.38.0
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor