From 3f4f64b6ac0d7160fd9e1301f95820894b219c3f Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Fri, 17 Feb 2017 19:39:28 +0900 Subject: [PATCH] agent: Send back all public keys for available cards. * agent/call-scd.c (card_cardlist_cb, agent_card_cardlist): New. * agent/command-ssh.c (card_key_list): New. (ssh_handler_request_identities): Call card_key_list and loop for the list to send public keys for all available cards. Signed-off-by: NIIBE Yutaka --- agent/agent.h | 1 + agent/call-scd.c | 66 ++++++++++++++++++++++++++++++++++++++ agent/command-ssh.c | 78 +++++++++++++++++++++++++++++++++++++++------ 3 files changed, 136 insertions(+), 9 deletions(-) diff --git a/agent/agent.h b/agent/agent.h index 217838472..2a722fd24 100644 --- a/agent/agent.h +++ b/agent/agent.h @@ -556,6 +556,7 @@ int agent_card_writekey (ctrl_t ctrl, int force, const char *serialno, int (*getpin_cb)(void *, const char *, char*, size_t), void *getpin_cb_arg); gpg_error_t agent_card_getattr (ctrl_t ctrl, const char *name, char **result); +gpg_error_t agent_card_cardlist (ctrl_t ctrl, strlist_t *result); int agent_card_scd (ctrl_t ctrl, const char *cmdline, int (*getpin_cb)(void *, const char *, char*, size_t), void *getpin_cb_arg, void *assuan_context); diff --git a/agent/call-scd.c b/agent/call-scd.c index 15a2ba529..71e0f581c 100644 --- a/agent/call-scd.c +++ b/agent/call-scd.c @@ -39,6 +39,7 @@ #include "agent.h" #include +#include "strlist.h" #ifdef _POSIX_OPEN_MAX #define MAX_OPEN_FDS _POSIX_OPEN_MAX @@ -1189,9 +1190,74 @@ agent_card_getattr (ctrl_t ctrl, const char *name, char **result) return unlock_scd (ctrl, err); } + +struct card_cardlist_parm_s { + int error; + strlist_t list; +}; +/* Callback function for agent_card_cardlist. */ +static gpg_error_t +card_cardlist_cb (void *opaque, const char *line) +{ + struct card_cardlist_parm_s *parm = opaque; + const char *keyword = line; + int keywordlen; + for (keywordlen=0; *line && !spacep (line); line++, keywordlen++) + ; + while (spacep (line)) + line++; + if (keywordlen == 8 && !memcmp (keyword, "SERIALNO", keywordlen)) + { + const char *s; + int n; + + for (n=0,s=line; hexdigitp (s); s++, n++) + ; + + if (!n || (n&1) || *s) + parm->error = gpg_error (GPG_ERR_ASS_PARAMETER); + else + add_to_strlist (&parm->list, line); + } + + return 0; +} + +/* Call the scdaemon to retrieve list of available cards. On success + the allocated strlist is stored at RESULT. On error an error code is + returned and NULL stored at RESULT. */ +gpg_error_t +agent_card_cardlist (ctrl_t ctrl, strlist_t *result) +{ + int err; + struct card_cardlist_parm_s parm; + char line[ASSUAN_LINELENGTH]; + + *result = NULL; + + memset (&parm, 0, sizeof parm); + strcpy (line, "GETINFO card_list"); + + err = start_scd (ctrl); + if (err) + return err; + + err = assuan_transact (ctrl->scd_local->ctx, line, + NULL, NULL, NULL, NULL, + card_cardlist_cb, &parm); + if (!err && parm.error) + err = parm.error; + + if (!err) + *result = parm.list; + else + free_strlist (parm.list); + + return unlock_scd (ctrl, err); +} static gpg_error_t pass_status_thru (void *opaque, const char *line) diff --git a/agent/command-ssh.c b/agent/command-ssh.c index 1d4453c84..2c74618d6 100644 --- a/agent/command-ssh.c +++ b/agent/command-ssh.c @@ -2382,6 +2382,29 @@ ssh_key_grip (gcry_sexp_t key, unsigned char *buffer) } +static gpg_error_t +card_key_list (ctrl_t ctrl, char **r_serialno, strlist_t *result) +{ + gpg_error_t err; + + err = agent_card_serialno (ctrl, r_serialno, NULL); + if (err) + { + if (opt.verbose) + log_info (_("error getting serial number of card: %s\n"), + gpg_strerror (err)); + return err; + } + + err = agent_card_cardlist (ctrl, result); + if (err) + { + xfree (*r_serialno); + *r_serialno = NULL; + } + return err; +} + /* Check whether a smartcard is available and whether it has a usable key. Store a copy of that key at R_PK and return 0. If no key is available store NULL at R_PK and return an error code. If CARDSN @@ -2561,17 +2584,54 @@ ssh_handler_request_identities (ctrl_t ctrl, reader - this should be allowed even without being listed in sshcontrol. */ - if (!opt.disable_scdaemon - && !card_key_available (ctrl, &key_public, &cardsn)) + if (!opt.disable_scdaemon) { - err = ssh_send_key_public (key_blobs, key_public, cardsn); - gcry_sexp_release (key_public); - key_public = NULL; - xfree (cardsn); - if (err) - goto out; + char *serialno; + strlist_t card_list, sl; - key_counter++; + err = card_key_list (ctrl, &serialno, &card_list); + if (err) + { + if (opt.verbose) + log_info (_("error getting list of cards: %s\n"), + gpg_strerror (err)); + goto out; + } + + for (sl = card_list; sl; sl = sl->next) + { + char *serialno0; + err = agent_card_serialno (ctrl, &serialno0, sl->d); + if (err) + { + if (opt.verbose) + log_info (_("error getting serial number of card: %s\n"), + gpg_strerror (err)); + xfree (serialno); + free_strlist (card_list); + goto out; + } + + xfree (serialno0); + if (card_key_available (ctrl, &key_public, &cardsn)) + continue; + + err = ssh_send_key_public (key_blobs, key_public, cardsn); + gcry_sexp_release (key_public); + key_public = NULL; + xfree (cardsn); + if (err) + { + xfree (serialno); + free_strlist (card_list); + goto out; + } + + key_counter++; + } + + xfree (serialno); + free_strlist (card_list); } /* Then look at all the registered and non-disabled keys. */