Bugzilla – Attachment 3227 Details for
Bug 2472
Add support to load additional certificates
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
add SSH2_AGENTC_ADD_CERTIFICATES to add certificates for matching with private keys
bz2742.diff (text/plain), 27.02 KB, created by
Damien Miller
on 2019-01-22 21:05:34 AEDT
(
hide
)
Description:
add SSH2_AGENTC_ADD_CERTIFICATES to add certificates for matching with private keys
Filename:
MIME Type:
Creator:
Damien Miller
Created:
2019-01-22 21:05:34 AEDT
Size:
27.02 KB
patch
obsolete
>diff --git a/auth2.c b/auth2.c >index 1f705fa..e03bddf 100644 >--- a/auth2.c >+++ b/auth2.c >@@ -676,7 +676,7 @@ auth2_record_key(Authctxt *authctxt, int authenticated, > struct sshkey **tmp, *dup; > int r; > >- if ((r = sshkey_from_private(key, &dup)) != 0) >+ if ((r = sshkey_copy_public(key, &dup)) != 0) > fatal("%s: copy key: %s", __func__, ssh_err(r)); > sshkey_free(authctxt->auth_method_key); > authctxt->auth_method_key = dup; >@@ -685,7 +685,7 @@ auth2_record_key(Authctxt *authctxt, int authenticated, > return; > > /* If authenticated, make sure we don't accept this key again */ >- if ((r = sshkey_from_private(key, &dup)) != 0) >+ if ((r = sshkey_copy_public(key, &dup)) != 0) > fatal("%s: copy key: %s", __func__, ssh_err(r)); > if (authctxt->nprev_keys >= INT_MAX || > (tmp = recallocarray(authctxt->prev_keys, authctxt->nprev_keys, >diff --git a/authfd.c b/authfd.c >index 11d1a14..c328cbb 100644 >--- a/authfd.c >+++ b/authfd.c >@@ -470,6 +470,31 @@ ssh_add_identity_constrained(int sock, const struct sshkey *key, > return r; > } > >+/* >+ * Adds a cert to the authentication server that may be later joined with a >+ * private key. >+ * This call is intended only for use by ssh-add(1) and like applications. >+ */ >+int >+ssh_add_certificate(int sock, const struct sshkey *cert) >+{ >+ struct sshbuf *msg; >+ int r; >+ u_char type = 0; >+ >+ if ((msg = sshbuf_new()) == NULL) >+ return SSH_ERR_ALLOC_FAIL; >+ if ((r = sshbuf_put_u8(msg, SSH2_AGENTC_ADD_CERTIFICATES)) != 0 || >+ (r = sshkey_puts(cert, msg)) != 0 || >+ (r = ssh_request_reply(sock, msg, msg)) != 0 || >+ (r = sshbuf_get_u8(msg, &type)) != 0) >+ goto out; >+ r = decode_reply(type); >+ out: >+ sshbuf_free(msg); >+ return r; >+} >+ > /* > * Removes an identity from the authentication server. > * This call is intended only for use by ssh-add(1) and like applications. >diff --git a/authfd.h b/authfd.h >index a032fd5..3aabce0 100644 >--- a/authfd.h >+++ b/authfd.h >@@ -31,6 +31,7 @@ int ssh_fetch_identitylist(int sock, struct ssh_identitylist **idlp); > void ssh_free_identitylist(struct ssh_identitylist *idl); > int ssh_add_identity_constrained(int sock, const struct sshkey *key, > const char *comment, u_int life, u_int confirm, u_int maxsign); >+int ssh_add_certificate(int sock, const 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); >@@ -73,6 +74,9 @@ int ssh_agent_sign(int sock, const struct sshkey *key, > #define SSH2_AGENTC_ADD_ID_CONSTRAINED 25 > #define SSH_AGENTC_ADD_SMARTCARD_KEY_CONSTRAINED 26 > >+/* certificates */ >+#define SSH2_AGENTC_ADD_CERTIFICATES 27 >+ > #define SSH_AGENT_CONSTRAIN_LIFETIME 1 > #define SSH_AGENT_CONSTRAIN_CONFIRM 2 > #define SSH_AGENT_CONSTRAIN_MAXSIGN 3 >diff --git a/krl.c b/krl.c >index 4d03247..ef1105b 100644 >--- a/krl.c >+++ b/krl.c >@@ -230,7 +230,7 @@ revoked_certs_for_ca_key(struct ssh_krl *krl, const struct sshkey *ca_key, > return SSH_ERR_ALLOC_FAIL; > if (ca_key == NULL) > rc->ca_key = NULL; >- else if ((r = sshkey_from_private(ca_key, &rc->ca_key)) != 0) { >+ else if ((r = sshkey_copy_public(ca_key, &rc->ca_key)) != 0) { > free(rc); > return r; > } >@@ -369,7 +369,7 @@ plain_key_blob(const struct sshkey *key, u_char **blob, size_t *blen) > struct sshkey *kcopy; > int r; > >- if ((r = sshkey_from_private(key, &kcopy)) != 0) >+ if ((r = sshkey_copy_public(key, &kcopy)) != 0) > return r; > if (sshkey_is_cert(kcopy)) { > if ((r = sshkey_drop_cert(kcopy)) != 0) { >diff --git a/ssh-add.c b/ssh-add.c >index d9c8ef3..1f3fcbd 100644 >--- a/ssh-add.c >+++ b/ssh-add.c >@@ -60,6 +60,7 @@ > #include "misc.h" > #include "ssherr.h" > #include "digest.h" >+#include "authfile.h" > > /* argv0 */ > extern char *__progname; >@@ -381,6 +382,42 @@ add_file(int agent_fd, const char *filename, int key_only, int qflag) > return ret; > } > >+static int >+add_cert(int agent_fd, const char *filename, int qflag) >+{ >+ struct sshkey *cert = NULL; >+ char *comment = NULL; >+ int r, ret = -1; >+ >+ if ((r = sshkey_load_public(filename, &cert, &comment)) != 0) { >+ if (r == SSH_ERR_INVALID_FORMAT) >+ return 0; /* ignore; probably a private key */ >+ fprintf(stderr, "Error loading key \"%s\": %s\n", >+ filename, ssh_err(r)); >+ return -1; >+ } >+ if (!sshkey_is_cert(cert)) { >+ debug("%s: key %s is not a cert", __func__, sshkey_type(cert)); >+ ret = 0; /* not an error */ >+ goto out; >+ } >+ ret = 1; >+ if ((r = ssh_add_certificate(agent_fd, cert)) == 0) { >+ if (!qflag) { >+ fprintf(stderr, "Certificate added pending " >+ "private key load: %s (%s)\n", filename, comment); >+ } >+ } else { >+ fprintf(stderr, "Could not add certificate \"%s\": %s\n", >+ filename, ssh_err(r)); >+ } >+ out: >+ sshkey_free(cert); >+ free(comment); >+ >+ return ret; >+} >+ > static int > update_card(int agent_fd, int add, const char *id, int qflag) > { >@@ -519,14 +556,41 @@ lock_agent(int agent_fd, int lock) > } > > static int >-do_file(int agent_fd, int deleting, int key_only, char *file, int qflag) >+do_files(int agent_fd, int deleting, int key_only, int qflag, >+ char **files, size_t nfiles) > { >+ size_t i; >+ int r; >+ > if (deleting) { >- if (delete_file(agent_fd, file, key_only, qflag) == -1) >- return -1; >+ for (i = 0; i < nfiles; i++) { >+ if (delete_file(agent_fd, files[i], >+ key_only, qflag) == -1) >+ return -1; >+ } > } else { >- if (add_file(agent_fd, file, key_only, qflag) == -1) >- return -1; >+ /* >+ * Load plain certificates first, so they are there ready for >+ * private keys to find them. >+ */ >+ for (i = 0; !key_only && i < nfiles; i++) { >+ if (strcmp(files[i], "-") == 0) >+ continue; >+ if ((r = add_cert(agent_fd, files[i], qflag)) == -1) >+ return -1; >+ else if (r == 1) { >+ /* consume file */ >+ free(files[i]); >+ files[i] = NULL; >+ } >+ } >+ for (i = 0; i < nfiles; i++) { >+ if (files[i] == NULL) >+ continue; >+ if (add_file(agent_fd, files[i], >+ key_only, qflag) == -1) >+ return -1; >+ } > } > return 0; > } >@@ -560,9 +624,9 @@ main(int argc, char **argv) > { > extern char *optarg; > extern int optind; >- int agent_fd; >- char *pkcs11provider = NULL; >- int r, i, ch, deleting = 0, ret = 0, key_only = 0; >+ char *pkcs11provider = NULL, **files = NULL; >+ size_t j, nfiles = 0; >+ int i, agent_fd, r, ch, deleting = 0, ret = 0, key_only = 0; > int xflag = 0, lflag = 0, Dflag = 0, qflag = 0, Tflag = 0; > SyslogFacility log_facility = SYSLOG_FACILITY_AUTH; > LogLevel log_level = SYSLOG_LEVEL_INFO; >@@ -703,11 +767,10 @@ main(int argc, char **argv) > ret = 1; > goto done; > } >- if (argc == 0) { >- char buf[PATH_MAX]; >+ if (argc <= 0) { >+ char *cp; > struct passwd *pw; > struct stat st; >- int count = 0; > > if ((pw = getpwuid(getuid())) == NULL) { > fprintf(stderr, "No user found with uid %u\n", >@@ -716,28 +779,30 @@ main(int argc, char **argv) > goto done; > } > >- for (i = 0; default_files[i]; i++) { >- snprintf(buf, sizeof(buf), "%s/%s", pw->pw_dir, >- default_files[i]); >- if (stat(buf, &st) < 0) >+ for (j = 0; default_files[j]; j++) { >+ xasprintf(&cp, "%s/%s", pw->pw_dir, default_files[j]); >+ if (stat(cp, &st) < 0) { >+ free(cp); > continue; >- if (do_file(agent_fd, deleting, key_only, buf, >- qflag) == -1) >- ret = 1; >- else >- count++; >+ } >+ files = xrecallocarray(files, nfiles, nfiles + 1, >+ sizeof(*files)); >+ files[nfiles++] = cp; > } >- if (count == 0) >- ret = 1; > } else { >- for (i = 0; i < argc; i++) { >- if (do_file(agent_fd, deleting, key_only, >- argv[i], qflag) == -1) >- ret = 1; >- } >+ /* Copy argv as we need to modify the list later */ >+ nfiles = (size_t)argc; >+ files = xcalloc(nfiles, sizeof(*files)); >+ for (j = 0; j < nfiles; j++) >+ files[j] = xstrdup(argv[j]); > } >+ if (nfiles == 0 || >+ do_files(agent_fd, deleting, key_only, qflag, files, nfiles) == -1) >+ ret = 1; >+ for (j = 0; j < nfiles; j++) >+ free(files[j]); >+ free(files); > clear_pass(); >- > done: > ssh_close_authentication_socket(agent_fd); > return ret; >diff --git a/ssh-agent.c b/ssh-agent.c >index 59ee90c..14e2d38 100644 >--- a/ssh-agent.c >+++ b/ssh-agent.c >@@ -116,6 +116,9 @@ struct idtable { > /* private key table */ > struct idtable *idtab; > >+/* certificates waiting for private keys */ >+struct idtable *pending_certs; >+ > int max_fd = 0; > > /* pid of shell == parent of agent */ >@@ -159,11 +162,11 @@ close_socket(SocketEntry *e) > } > > static void >-idtab_init(void) >+idtable_init(struct idtable **tab) > { >- idtab = xcalloc(1, sizeof(*idtab)); >- TAILQ_INIT(&idtab->idlist); >- idtab->nentries = 0; >+ *tab = xcalloc(1, sizeof(**tab)); >+ TAILQ_INIT(&(*tab)->idlist); >+ (*tab)->nentries = 0; > } > > static void >@@ -175,17 +178,41 @@ free_identity(Identity *id) > free(id); > } > >+static Identity * >+idtable_lookup(struct idtable *tab, struct sshkey *key, int public) >+{ >+ Identity *id; >+ >+ TAILQ_FOREACH(id, &tab->idlist, next) { >+ if (public) { >+ if (sshkey_equal_public(key, id->key)) >+ return (id); >+ } else { >+ if (sshkey_equal(key, id->key)) >+ return (id); >+ } >+ } >+ return (NULL); >+} >+ > /* return matching private key for given public key */ > static Identity * > lookup_identity(struct sshkey *key) > { >- Identity *id; >+ return idtable_lookup(idtab, key, 0); >+} > >- TAILQ_FOREACH(id, &idtab->idlist, next) { >- if (sshkey_equal(key, id->key)) >- return (id); >- } >- return (NULL); >+static Identity * >+lookup_identity_plain(struct sshkey *key) >+{ >+ return idtable_lookup(idtab, key, 1); >+} >+ >+/* return matching certificate key for given key */ >+static Identity * >+lookup_cert(struct sshkey *key) >+{ >+ return idtable_lookup(pending_certs, key, 1); > } > > /* Check confirmation of keysign request */ >@@ -309,6 +336,19 @@ process_sign_request2(SocketEntry *e) > free(signature); > } > >+/* Remove an entry from an idtable; NB. frees 'id' in the process */ >+static void >+idtable_remove(struct idtable *tab, Identity *id) >+{ >+ if (tab->nentries < 1) { >+ fatal("%s: internal error: nentries %d", >+ __func__, tab->nentries); >+ } >+ TAILQ_REMOVE(&tab->idlist, id, next); >+ free_identity(id); >+ tab->nentries--; >+} >+ > /* shared */ > static void > process_remove_identity(SocketEntry *e) >@@ -326,32 +366,40 @@ process_remove_identity(SocketEntry *e) > goto done; > } > /* We have this key, free it. */ >- if (idtab->nentries < 1) >- fatal("%s: internal error: nentries %d", >- __func__, idtab->nentries); >- TAILQ_REMOVE(&idtab->idlist, id, next); >- free_identity(id); >- idtab->nentries--; >- sshkey_free(key); >+ idtable_remove(idtab, id); >+ > success = 1; > done: >+ /* Clobber any pending certificates that happen to match too */ >+ if ((id = lookup_cert(key)) != NULL) >+ idtable_remove(pending_certs, id); >+ >+ sshkey_free(key); > send_status(e, success); > } > > static void >-process_remove_all_identities(SocketEntry *e) >+idtable_clear(struct idtable *tab) > { > Identity *id; > > /* Loop over all identities and clear the keys. */ >- for (id = TAILQ_FIRST(&idtab->idlist); id; >- id = TAILQ_FIRST(&idtab->idlist)) { >- TAILQ_REMOVE(&idtab->idlist, id, next); >+ for (id = TAILQ_FIRST(&tab->idlist); id != NULL; >+ id = TAILQ_FIRST(&tab->idlist)) { >+ TAILQ_REMOVE(&tab->idlist, id, next); > free_identity(id); > } >+} >+ >+static void >+process_remove_all_identities(SocketEntry *e) >+{ >+ idtable_clear(idtab); >+ idtable_clear(pending_certs); > > /* Mark that there are no identities. */ > idtab->nentries = 0; >+ pending_certs->nentries = 0; > > /* Send success. */ > send_status(e, 1); >@@ -383,6 +431,99 @@ reaper(void) > return (deadline - now); > } > >+static int >+promote_cert(Identity *private_id, Identity *cert) >+{ >+ Identity *id; >+ struct sshkey *grafted = NULL; >+ int r = SSH_ERR_INTERNAL_ERROR; >+ >+ if ((r = sshkey_copy_private(private_id->key, &grafted)) != 0) { >+ error("%s: sshkey_copy_private: %s", __func__, ssh_err(r)); >+ goto out; >+ } >+ if ((r = sshkey_to_certified(grafted)) != 0) { >+ error("%s: sshkey_to_certified: %s", __func__, ssh_err(r)); >+ goto out; >+ } >+ if ((r = sshkey_cert_copy(cert->key, grafted)) != 0) { >+ error("%s: sshkey_cert_copy: %s", __func__, ssh_err(r)); >+ goto out; >+ } >+ >+ /* Check whether the grafted cert is already recorded */ >+ if ((id = lookup_identity(grafted)) == NULL) { >+ debug("%s: added new %s private cert, now have %d private keys", >+ __func__, sshkey_type(grafted), idtab->nentries); >+ id = xcalloc(1, sizeof(*id)); >+ TAILQ_INSERT_TAIL(&idtab->idlist, id, next); >+ idtab->nentries++; >+ id->key = grafted; >+ grafted = NULL; /* transfer */ >+ } else { >+ debug("%s: existing %s private cert", >+ __func__, sshkey_type(grafted)); >+ /* Update the identity, as constraints may have changed */ >+ free(id->comment); >+ free(id->provider); >+ } >+ id->comment = private_id->comment != NULL ? >+ xstrdup(private_id->comment) : NULL; >+ id->provider = private_id->provider != NULL? >+ xstrdup(private_id->provider) : NULL; >+ id->death = private_id->death; >+ id->confirm = private_id->confirm; >+ >+ /* success */ >+ r = 0; >+ out: >+ sshkey_free(grafted); >+ return r; >+} >+ >+/* Check whether an incoming private key against the pending cert list */ >+static int >+check_pending_by_key(Identity *private_id) >+{ >+ Identity *cert; >+ int r; >+ >+ debug3("%s: entering for %s, npending = %d", __func__, >+ sshkey_type(private_id->key), pending_certs->nentries); >+ /* A private key could conceivable match multiple certificates */ >+ while ((cert = lookup_cert(private_id->key)) != NULL) { >+ debug3("%s: found matching cert %s", >+ __func__, sshkey_type(cert->key)); >+ if ((r = promote_cert(private_id, cert)) != 0) >+ return r; >+ /* Remove the cert from the pending list */ >+ idtable_remove(pending_certs, cert); >+ debug("%s: remove pending cert, now have %d pending", >+ __func__, pending_certs->nentries); >+ } >+ return 0; >+} >+ >+/* Check whether an incoming cert against the pending cert list */ >+static int >+check_pending_by_cert(Identity *cert, int *matched) >+{ >+ Identity *private_id; >+ int r; >+ >+ *matched = 0; >+ debug3("%s: entering for %s", __func__, sshkey_type(cert->key)); >+ /* A certificate should match at most one private key */ >+ if ((private_id = lookup_identity_plain(cert->key)) != NULL) { >+ debug3("%s: found matching key %s", >+ __func__, sshkey_type(private_id->key)); >+ if ((r = promote_cert(private_id, cert)) != 0) >+ return r; >+ *matched = 1; >+ } >+ return 0; >+} >+ > static void > process_add_identity(SocketEntry *e) > { >@@ -402,6 +543,9 @@ process_add_identity(SocketEntry *e) > goto err; > } > >+ debug3("%s: have %s key constraint len %zu", __func__, >+ sshkey_type(k), sshbuf_len(e->request)); >+ > while (sshbuf_len(e->request)) { > if ((r = sshbuf_get_u8(e->request, &ctype)) != 0) { > error("%s: buffer error: %s", __func__, ssh_err(r)); >@@ -441,7 +585,6 @@ process_add_identity(SocketEntry *e) > } > } > >- success = 1; > if (lifetime && !death) > death = monotime() + lifetime; > if ((id = lookup_identity(k)) == NULL) { >@@ -449,19 +592,84 @@ process_add_identity(SocketEntry *e) > TAILQ_INSERT_TAIL(&idtab->idlist, id, next); > /* Increment the number of identities. */ > idtab->nentries++; >+ debug("%s: new key, now have %d", __func__, idtab->nentries); > } else { > /* key state might have been updated */ > sshkey_free(id->key); > free(id->comment); >+ debug("%s: existing key", __func__); > } > id->key = k; > id->comment = comment; > id->death = death; > id->confirm = confirm; >+ >+ /* Can this key matriculate a pending_cert? */ >+ if (!sshkey_is_cert(id->key) && check_pending_by_key(id) != 0) >+ goto send; >+ >+ success = 1; > send: > send_status(e, success); > } > >+static void >+process_add_certificates(SocketEntry *e) >+{ >+ Identity *id; >+ int matched, success = 0; >+ struct sshkey *k = NULL; >+ int r = SSH_ERR_INTERNAL_ERROR; >+ >+ debug3("%s: entering len = %zu", __func__, sshbuf_len(e->request)); >+ >+ while (sshbuf_len(e->request)) { >+ sshkey_free(k); >+ k = NULL; >+ if ((r = sshkey_froms(e->request, &k)) != 0) { >+ error("%s: buffer error: %s", __func__, ssh_err(r)); >+ goto send; >+ } >+ debug2("%s: key type %s", __func__, sshkey_type(k)); >+ if (!sshkey_is_cert(k)) { >+ error("%s: key is not a certificate", __func__); >+ goto send; >+ } >+ if ((id = lookup_identity(k)) != NULL) { >+ debug("%s: cert already has key", __func__); >+ } else if ((id = lookup_cert(k)) != NULL) { >+ debug("%s: cert already enqueued", __func__); >+ if ((r = check_pending_by_cert(id, &matched)) != 0) >+ goto send; >+ if (matched) { >+ debug("%s: cert matches, remove from pending", >+ __func__); >+ idtable_remove(pending_certs, id); >+ } >+ } else { >+ id = xcalloc(1, sizeof(Identity)); >+ id->key = k; >+ k = NULL; /* transfer */ >+ if ((r = check_pending_by_cert(id, &matched)) != 0) >+ goto send; >+ if (matched) >+ free_identity(id); >+ else { >+ TAILQ_INSERT_TAIL(&pending_certs->idlist, >+ id, next); >+ pending_certs->nentries++; >+ debug("%s: add cert, nentries %d", >+ __func__, pending_certs->nentries); >+ } >+ } >+ } >+ success = 1; >+send: >+ sshkey_free(k); >+ send_status(e, success); >+} >+ >+ > /* XXX todo: encrypt sensitive data with passphrase */ > static void > process_lock_agent(SocketEntry *e, int lock) >@@ -539,7 +747,7 @@ process_add_smartcard_key(SocketEntry *e) > u_int seconds; > time_t death = 0; > u_char type; >- struct sshkey **keys = NULL, *k; >+ struct sshkey **keys = NULL; > Identity *id; > > if ((r = sshbuf_get_cstring(e->request, &provider, NULL)) != 0 || >@@ -586,25 +794,29 @@ process_add_smartcard_key(SocketEntry *e) > > count = pkcs11_add_provider(canonical_provider, pin, &keys); > for (i = 0; i < count; i++) { >- k = keys[i]; >- if (lookup_identity(k) == NULL) { >+ if ((id = lookup_identity(keys[i])) == NULL) { > id = xcalloc(1, sizeof(Identity)); >- id->key = k; > id->provider = xstrdup(canonical_provider); > id->comment = xstrdup(canonical_provider); /* XXX */ > id->death = death; > id->confirm = confirm; >+ id->key = keys[i]; >+ keys[i] = NULL; /* transfer */ > TAILQ_INSERT_TAIL(&idtab->idlist, id, next); > idtab->nentries++; >- success = 1; >- } else { >- sshkey_free(k); > } >- keys[i] = NULL; >+ /* Can this key matriculate a pending_cert? */ >+ if (!sshkey_is_cert(id->key) && check_pending_by_key(id) != 0) { >+ success = 0; >+ goto send; >+ } >+ success = 1; > } > send: > free(pin); > free(provider); >+ for (i = 0; i < count; i++) >+ sshkey_free(keys[i]); > free(keys); > send_status(e, success); > } >@@ -743,6 +955,9 @@ process_message(u_int socknum) > process_remove_smartcard_key(e); > break; > #endif /* ENABLE_PKCS11 */ >+ case SSH2_AGENTC_ADD_CERTIFICATES: >+ process_add_certificates(e); >+ break; > default: > /* Unknown message. Respond with failure. */ > error("Unknown message %d", type); >@@ -1287,7 +1502,8 @@ skip: > new_socket(AUTH_SOCKET, sock); > if (ac > 0) > parent_alive_interval = 10; >- idtab_init(); >+ idtable_init(&idtab); >+ idtable_init(&pending_certs); > signal(SIGPIPE, SIG_IGN); > signal(SIGINT, (d_flag | D_flag) ? cleanup_handler : SIG_IGN); > signal(SIGHUP, cleanup_handler); >diff --git a/ssh-keygen.c b/ssh-keygen.c >index 550f466..e13c3d4 100644 >--- a/ssh-keygen.c >+++ b/ssh-keygen.c >@@ -1052,8 +1052,8 @@ do_gen_all_hostkeys(struct passwd *pw) > error("sshkey_generate failed: %s", ssh_err(r)); > goto failnext; > } >- if ((r = sshkey_from_private(private, &public)) != 0) >- fatal("sshkey_from_private failed: %s", ssh_err(r)); >+ if ((r = sshkey_copy_public(private, &public)) != 0) >+ fatal("sshkey_copy_public failed: %s", ssh_err(r)); > snprintf(comment, sizeof comment, "%s@%s", pw->pw_name, > hostname); > if ((r = sshkey_save_private(private, prv_tmp, "", >@@ -1519,8 +1519,8 @@ do_change_comment(struct passwd *pw) > } > explicit_bzero(passphrase, strlen(passphrase)); > free(passphrase); >- if ((r = sshkey_from_private(private, &public)) != 0) >- fatal("sshkey_from_private failed: %s", ssh_err(r)); >+ if ((r = sshkey_copy_public(private, &public)) != 0) >+ fatal("sshkey_copy_public failed: %s", ssh_err(r)); > sshkey_free(private); > > strlcat(identity_file, ".pub", sizeof(identity_file)); >@@ -1750,9 +1750,9 @@ do_ca_sign(struct passwd *pw, int argc, char **argv) > prepare_options_buf(public->cert->critical, OPTIONS_CRITICAL); > prepare_options_buf(public->cert->extensions, > OPTIONS_EXTENSIONS); >- if ((r = sshkey_from_private(ca, >+ if ((r = sshkey_copy_public(ca, > &public->cert->signature_key)) != 0) >- fatal("sshkey_from_private (ca key): %s", ssh_err(r)); >+ fatal("sshkey_copy_public (ca key): %s", ssh_err(r)); > > if (agent_fd != -1 && (ca->flags & SSHKEY_FLAG_EXT) != 0) { > if ((r = sshkey_certify_custom(public, ca, >@@ -2806,8 +2806,8 @@ main(int argc, char **argv) > key_type_name); > if ((r = sshkey_generate(type, bits, &private)) != 0) > fatal("sshkey_generate failed"); >- if ((r = sshkey_from_private(private, &public)) != 0) >- fatal("sshkey_from_private failed: %s\n", ssh_err(r)); >+ if ((r = sshkey_copy_public(private, &public)) != 0) >+ fatal("sshkey_copy_public failed: %s\n", ssh_err(r)); > > if (!have_identity) > ask_filename(pw, "Enter file in which to save the key"); >diff --git a/ssh_api.c b/ssh_api.c >index 9dd008c..01d8e9f 100644 >--- a/ssh_api.c >+++ b/ssh_api.c >@@ -174,7 +174,7 @@ ssh_add_hostkey(struct ssh *ssh, struct sshkey *key) > int r; > > if (ssh->kex->server) { >- if ((r = sshkey_from_private(key, &pubkey)) != 0) >+ if ((r = sshkey_copy_public(key, &pubkey)) != 0) > return r; > if ((k = malloc(sizeof(*k))) == NULL || > (k_prv = malloc(sizeof(*k_prv))) == NULL) { >diff --git a/sshconnect.c b/sshconnect.c >index e6d2a1f..0f0b544 100644 >--- a/sshconnect.c >+++ b/sshconnect.c >@@ -1075,8 +1075,8 @@ fail: > * search normally. > */ > debug("No matching CA found. Retry with plain key"); >- if ((r = sshkey_from_private(host_key, &raw_key)) != 0) >- fatal("%s: sshkey_from_private: %s", >+ if ((r = sshkey_copy_public(host_key, &raw_key)) != 0) >+ fatal("%s: sshkey_copy_public: %s", > __func__, ssh_err(r)); > if ((r = sshkey_drop_cert(raw_key)) != 0) > fatal("Couldn't drop certificate: %s", ssh_err(r)); >@@ -1167,7 +1167,7 @@ verify_host_key(char *host, struct sockaddr *hostaddr, struct sshkey *host_key) > * XXX certs are not yet supported for DNS, so downgrade > * them and try the plain key. > */ >- if ((r = sshkey_from_private(host_key, &plain)) != 0) >+ if ((r = sshkey_copy_public(host_key, &plain)) != 0) > goto out; > if (sshkey_is_cert(plain)) > sshkey_drop_cert(plain); >@@ -1200,7 +1200,7 @@ out: > free(cafp); > if (r == 0 && host_key != NULL) { > sshkey_free(previous_host_key); >- r = sshkey_from_private(host_key, &previous_host_key); >+ r = sshkey_copy_public(host_key, &previous_host_key); > } > > return r; >diff --git a/sshd.c b/sshd.c >index 21c8889..5724f5e 100644 >--- a/sshd.c >+++ b/sshd.c >@@ -363,7 +363,7 @@ demote_sensitive_data(void) > > for (i = 0; i < options.num_host_key_files; i++) { > if (sensitive_data.host_keys[i]) { >- if ((r = sshkey_from_private( >+ if ((r = sshkey_copy_public( > sensitive_data.host_keys[i], &tmp)) != 0) > fatal("could not demote host %s key: %s", > sshkey_type(sensitive_data.host_keys[i]), >@@ -1546,7 +1546,7 @@ main(int ac, char **av) > do_log2(ll, "Unable to load host key \"%s\": %s", > options.host_key_files[i], ssh_err(r)); > if (pubkey == NULL && key != NULL) >- if ((r = sshkey_from_private(key, &pubkey)) != 0) >+ if ((r = sshkey_copy_public(key, &pubkey)) != 0) > fatal("Could not demote key: \"%s\": %s", > options.host_key_files[i], ssh_err(r)); > sensitive_data.host_keys[i] = key; >diff --git a/sshkey.c b/sshkey.c >index 8a7538c..c6c1f72 100644 >--- a/sshkey.c >+++ b/sshkey.c >@@ -1646,7 +1646,7 @@ sshkey_cert_copy(const struct sshkey *from_key, struct sshkey *to_key) > to->valid_before = from->valid_before; > if (from->signature_key == NULL) > to->signature_key = NULL; >- else if ((r = sshkey_from_private(from->signature_key, >+ else if ((r = sshkey_copy_public(from->signature_key, > &to->signature_key)) != 0) > goto out; > if (from->signature_type != NULL && >@@ -1686,7 +1686,7 @@ sshkey_cert_copy(const struct sshkey *from_key, struct sshkey *to_key) > } > > int >-sshkey_from_private(const struct sshkey *k, struct sshkey **pkp) >+sshkey_copy_public(const struct sshkey *k, struct sshkey **pkp) > { > struct sshkey *n = NULL; > int r = SSH_ERR_INTERNAL_ERROR; >@@ -1825,6 +1825,116 @@ sshkey_from_private(const struct sshkey *k, struct sshkey **pkp) > return r; > } > >+int >+sshkey_copy_private(const struct sshkey *k, struct sshkey **pvp) >+{ >+ struct sshkey *n = NULL; >+ int r = SSH_ERR_INTERNAL_ERROR; >+ >+ *pvp = NULL; >+ switch (k->type) { >+#ifdef WITH_OPENSSL >+ case KEY_DSA: >+ case KEY_DSA_CERT: >+ if ((n = sshkey_new(k->type)) == NULL) { >+ r = SSH_ERR_ALLOC_FAIL; >+ goto out; >+ } >+ n->dsa = k->dsa; >+ DSA_up_ref(n->dsa); >+ break; >+ case KEY_ECDSA: >+ case KEY_ECDSA_CERT: >+ if ((n = sshkey_new(k->type)) == NULL) { >+ r = SSH_ERR_ALLOC_FAIL; >+ goto out; >+ } >+ n->ecdsa_nid = k->ecdsa_nid; >+ n->ecdsa = k->ecdsa; >+ EC_KEY_up_ref(k->ecdsa); >+ break; >+ case KEY_RSA: >+ case KEY_RSA_CERT: >+ if ((n = sshkey_new(k->type)) == NULL) { >+ r = SSH_ERR_ALLOC_FAIL; >+ goto out; >+ } >+ n->rsa = k->rsa; >+ RSA_up_ref(k->rsa); >+ break; >+#endif /* WITH_OPENSSL */ >+ case KEY_ED25519: >+ case KEY_ED25519_CERT: >+ if ((n = sshkey_new(k->type)) == NULL) { >+ r = SSH_ERR_ALLOC_FAIL; >+ goto out; >+ } >+ if (k->ed25519_pk != NULL) { >+ if ((n->ed25519_pk = malloc(ED25519_PK_SZ)) == NULL) { >+ r = SSH_ERR_ALLOC_FAIL; >+ goto out; >+ } >+ memcpy(n->ed25519_pk, k->ed25519_pk, ED25519_PK_SZ); >+ } >+ if (k->ed25519_sk != NULL) { >+ if ((n->ed25519_sk = malloc(ED25519_SK_SZ)) == NULL) { >+ r = SSH_ERR_ALLOC_FAIL; >+ goto out; >+ } >+ memcpy(n->ed25519_sk, k->ed25519_sk, ED25519_SK_SZ); >+ } >+ break; >+#ifdef WITH_XMSS >+ case KEY_XMSS: >+ case KEY_XMSS_CERT: >+ if ((n = sshkey_new(k->type)) == NULL) { >+ r = SSH_ERR_ALLOC_FAIL; >+ goto out; >+ } >+ if ((r = sshkey_xmss_init(n, k->xmss_name)) != 0) >+ goto out; >+ if (k->xmss_pk != NULL) { >+ size_t pklen = sshkey_xmss_pklen(k); >+ if (pklen == 0 || sshkey_xmss_pklen(n) != pklen) { >+ r = SSH_ERR_INTERNAL_ERROR; >+ goto out; >+ } >+ if ((n->xmss_pk = malloc(pklen)) == NULL) { >+ r = SSH_ERR_ALLOC_FAIL; >+ goto out; >+ } >+ memcpy(n->xmss_pk, k->xmss_pk, pklen); >+ } >+ if (k->xmss_sk != NULL) { >+ size_t sklen = sshkey_xmss_sklen(k); >+ if (sklen == 0 || sshkey_xmss_sklen(n) != pklen) { >+ r = SSH_ERR_INTERNAL_ERROR; >+ goto out; >+ } >+ if ((n->xmss_sk = malloc(sklen)) == NULL) { >+ r = SSH_ERR_ALLOC_FAIL; >+ goto out; >+ } >+ memcpy(n->xmss_sk, k->xmss_sk, sklen); >+ } >+ break; >+#endif /* WITH_XMSS */ >+ default: >+ r = SSH_ERR_KEY_TYPE_UNKNOWN; >+ goto out; >+ } >+ if (sshkey_is_cert(k) && (r = sshkey_cert_copy(k, n)) != 0) >+ goto out; >+ /* success */ >+ *pvp = n; >+ n = NULL; >+ r = 0; >+ out: >+ sshkey_free(n); >+ return r; >+} >+ >+ > static int > cert_parse(struct sshbuf *b, struct sshkey *key, struct sshbuf *certbuf) > { >diff --git a/sshkey.h b/sshkey.h >index b514ad7..8b3e678 100644 >--- a/sshkey.h >+++ b/sshkey.h >@@ -139,7 +139,8 @@ int sshkey_read(struct sshkey *, char **); > u_int sshkey_size(const struct sshkey *); > > int sshkey_generate(int type, u_int bits, struct sshkey **keyp); >-int sshkey_from_private(const struct sshkey *, struct sshkey **); >+int sshkey_copy_public(const struct sshkey *, struct sshkey **); >+int sshkey_copy_private(const struct sshkey *, struct sshkey **); > int sshkey_type_from_name(const char *); > int sshkey_is_cert(const struct sshkey *); > int sshkey_type_is_cert(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 2472
:
2715
|
2716
|
2717
|
2933
|
2934
| 3227