From 8c8ce8711d9c938fcb982b0341e6b052742cb887 Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Thu, 16 Mar 2017 14:32:51 +0900 Subject: [PATCH] agent,g10: Remove redundant SERIALNO request. * agent/learncard.c (agent_handle_learn): Don't call agent_card_serialno. Get the serialno in status response. * g10/call-agent.c (agent_scd_learn): Don't request "SCD SERIALNO". (agent_scd_serialno): New. (card_cardlist_cb, agent_scd_cardlist): New. Signed-off-by: NIIBE Yutaka --- agent/learncard.c | 21 +++++----- g10/call-agent.c | 104 ++++++++++++++++++++++++++++++++++++++++------ g10/call-agent.h | 6 +++ 3 files changed, 109 insertions(+), 22 deletions(-) diff --git a/agent/learncard.c b/agent/learncard.c index cce9c3a36..e0c882ac5 100644 --- a/agent/learncard.c +++ b/agent/learncard.c @@ -302,11 +302,10 @@ int agent_handle_learn (ctrl_t ctrl, int send, void *assuan_context, int force) { int rc; - struct kpinfo_cb_parm_s parm; struct certinfo_cb_parm_s cparm; struct sinfo_cb_parm_s sparm; - char *serialno = NULL; + const char *serialno = NULL; KEYPAIR_INFO item; SINFO sitem; unsigned char grip[20]; @@ -329,11 +328,6 @@ agent_handle_learn (ctrl_t ctrl, int send, void *assuan_context, int force) parm.ctrl = ctrl; cparm.ctrl = ctrl; - /* Check whether a card is present and get the serial number */ - rc = agent_card_serialno (ctrl, &serialno, NULL); - if (rc) - goto leave; - /* Now gather all the available info. */ rc = agent_card_learn (ctrl, kpinfo_cb, &parm, certinfo_cb, &cparm, sinfo_cb, &sparm); @@ -345,17 +339,25 @@ agent_handle_learn (ctrl_t ctrl, int send, void *assuan_context, int force) goto leave; } - log_info ("card has S/N: %s\n", serialno); - /* Pass on all the collected status information. */ if (assuan_context) { for (sitem = sparm.info; sitem; sitem = sitem->next) { + if (!strcmp (sitem->keyword, "SERIALNO")) + serialno = sitem->data; assuan_write_status (assuan_context, sitem->keyword, sitem->data); } } + if (!serialno) + { + rc = GPG_ERR_NOT_FOUND; + goto leave; + } + + log_info ("card has S/N: %s\n", serialno); + /* Write out the certificates in a standard order. */ for (i=0; certtype_list[i] != -1; i++) { @@ -438,7 +440,6 @@ agent_handle_learn (ctrl_t ctrl, int send, void *assuan_context, int force) leave: - xfree (serialno); release_keypair_info (parm.info); release_certinfo (cparm.info); release_sinfo (sparm.info); diff --git a/g10/call-agent.c b/g10/call-agent.c index 160679749..af06bf511 100644 --- a/g10/call-agent.c +++ b/g10/call-agent.c @@ -656,18 +656,6 @@ agent_scd_learn (struct agent_card_info_s *info, int force) if (rc) return rc; - /* Send the serialno command to initialize the connection. We don't - care about the data returned. If the card has already been - initialized, this is a very fast command. The main reason we - need to do this here is to handle a card removed case so that an - "l" command in --edit-card can be used to show ta newly inserted - card. We request the openpgp card because that is what we - expect. */ - rc = assuan_transact (agent_ctx, "SCD SERIALNO openpgp", - NULL, NULL, NULL, NULL, NULL, NULL); - if (rc) - return rc; - parm.ctx = agent_ctx; rc = assuan_transact (agent_ctx, force ? "LEARN --sendinfo --force" : "LEARN --sendinfo", @@ -1024,9 +1012,37 @@ agent_scd_genkey (int keyno, int force, u32 *createtime) status_sc_op_failure (rc); return rc; } + +/* Return the serial number of the card or an appropriate error. The + serial number is returned as a hexstring. */ +int +agent_scd_serialno (char **r_serialno, const char *demand) +{ + int err; + char *serialno = NULL; + char line[ASSUAN_LINELENGTH]; + err = start_agent (NULL, 1); + if (err) + return err; + if (!demand) + strcpy (line, "SCD SERIALNO"); + else + snprintf (line, DIM(line), "SCD SERIALNO --demand=%s", demand); + err = assuan_transact (agent_ctx, line, + NULL, NULL, NULL, NULL, + get_serialno_cb, &serialno); + if (err) + { + xfree (serialno); + return err; + } + + *r_serialno = serialno; + return 0; +} /* Send a READCERT command to the SCdaemon. */ int @@ -1066,8 +1082,72 @@ agent_scd_readcert (const char *certidstr, return 0; } + +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; +} + +/* Return cardlist. */ +int +agent_scd_cardlist (strlist_t *result) +{ + int err; + char line[ASSUAN_LINELENGTH]; + struct card_cardlist_parm_s parm; + + memset (&parm, 0, sizeof parm); + *result = NULL; + err = start_agent (NULL, 1); + if (err) + return err; + + strcpy (line, "SCD GETINFO card_list"); + + err = assuan_transact (agent_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 0; +} /* Change the PIN of an OpenPGP card or reset the retry counter. CHVNO 1: Change the PIN diff --git a/g10/call-agent.h b/g10/call-agent.h index e4fea5730..a04fc734c 100644 --- a/g10/call-agent.h +++ b/g10/call-agent.h @@ -76,6 +76,12 @@ void agent_release_card_info (struct agent_card_info_s *info); /* Return card info. */ int agent_scd_learn (struct agent_card_info_s *info, int force); +/* Return list of cards. */ +int agent_scd_cardlist (strlist_t *result); + +/* Return the serial number, possibly select by DEMAND. */ +int agent_scd_serialno (char **r_serialno, const char *demand); + /* Send an APDU to the card. */ gpg_error_t agent_scd_apdu (const char *hexapdu, unsigned int *r_sw);