summaryrefslogtreecommitdiffstats
path: root/scd/command.c
diff options
context:
space:
mode:
Diffstat (limited to 'scd/command.c')
-rw-r--r--scd/command.c156
1 files changed, 131 insertions, 25 deletions
diff --git a/scd/command.c b/scd/command.c
index 10b900628..b4eaa8a47 100644
--- a/scd/command.c
+++ b/scd/command.c
@@ -75,14 +75,20 @@ option_handler (ASSUAN_CONTEXT ctx, const char *key, const char *value)
/* LEARN [--force]
Learn all useful information of the currently inserted card. When
- used without the force options, the command might to an INQUIRE
+ used without the force options, the command might do an INQUIRE
like this:
INQUIRE KNOWNCARDP <hexstring_with_serialNumber> <timestamp>
The client should just send an "END" if the processing should go on
or a "CANCEL" to force the function to terminate with a Cancel
- error message.
+ error message. The response of this command is a list of status
+ lines formatted as this:
+
+ S KEYPAIRINFO <hexstring_with_keygrip> <hexstring_with_id>
+
+ If there is no certificate yet stored on the card a single "X" is
+ returned as the keygrip.
*/
static int
@@ -90,6 +96,7 @@ cmd_learn (ASSUAN_CONTEXT ctx, char *line)
{
CTRL ctrl = assuan_get_pointer (ctx);
int rc = 0;
+ int idx;
/* if this is the first command issued for a new card, open the card and
and create a context */
@@ -104,40 +111,138 @@ cmd_learn (ASSUAN_CONTEXT ctx, char *line)
the card using a serial number and inquiring the client with
that. The client may choose to cancel the operation if he already
knows about this card */
- if (!has_option (line, "--force"))
+ {
+ char *serial_and_stamp;
+ char *serial;
+ time_t stamp;
+
+ rc = card_get_serial_and_stamp (ctrl->card_ctx, &serial, &stamp);
+ if (rc)
+ return map_to_assuan_status (rc);
+ rc = asprintf (&serial_and_stamp, "%s %lu", serial, (unsigned long)stamp);
+ xfree (serial);
+ if (rc < 0)
+ return ASSUAN_Out_Of_Core;
+ rc = 0;
+ assuan_write_status (ctx, "SERIALNO", serial_and_stamp);
+
+ if (!has_option (line, "--force"))
+ {
+ char *command;
+
+ rc = asprintf (&command, "KNOWNCARDP %s", serial_and_stamp);
+ if (rc < 0)
+ {
+ free (serial_and_stamp);
+ return ASSUAN_Out_Of_Core;
+ }
+ rc = 0;
+ rc = assuan_inquire (ctx, command, NULL, NULL, 0);
+ free (command); /* (must use standard free here) */
+ if (rc)
+ {
+ if (rc != ASSUAN_Canceled)
+ log_error ("inquire KNOWNCARDP failed: %s\n",
+ assuan_strerror (rc));
+ free (serial_and_stamp);
+ return rc;
+ }
+ /* not canceled, so we have to proceeed */
+ }
+ free (serial_and_stamp);
+ }
+
+ for (idx=0; !rc; idx++)
{
- char *serial;
- time_t stamp;
- char *command;
-
- rc = card_get_serial_and_stamp (ctrl->card_ctx, &serial, &stamp);
- if (rc)
- return map_to_assuan_status (rc);
-
- rc = asprintf (&command, "KNOWNCARDP %s %lu",
- serial, (unsigned long)stamp);
- xfree (serial);
- if (rc < 0)
- return ASSUAN_Out_Of_Core;
- rc = 0;
- rc = assuan_inquire (ctx, command, NULL, NULL, 0);
- free (command); /* (must use standard free here) */
- if (rc)
+ unsigned char keygrip[20];
+ unsigned char *keyid;
+ size_t nkeyid;
+ int no_cert = 0;
+
+ rc = card_enum_keypairs (ctrl->card_ctx, idx,
+ keygrip, &keyid, &nkeyid);
+ if (rc == GNUPG_Missing_Certificate && keyid)
+ {
+ /* this does happen with an incomplete personalized
+ card; i.e. during the time we have stored the key on the
+ card but not stored the certificate; probably becuase it
+ has not yet been received back from the CA. Note that we
+ must release KEYID in this case. */
+ rc = 0;
+ no_cert = 1;
+ }
+ if (!rc)
{
- if (rc != ASSUAN_Canceled)
- log_error ("inquire KNOWNCARDP failed: %s\n",
- assuan_strerror (rc));
- return rc;
+ char *buf, *p;
+
+ buf = p = xtrymalloc (40+1+9+2*nkeyid+1);
+ if (!buf)
+ rc = GNUPG_Out_Of_Core;
+ else
+ {
+ int i;
+
+ if (no_cert)
+ *p++ = 'X';
+ else
+ {
+ for (i=0; i < 20; i++, p += 2)
+ sprintf (p, "%02X", keygrip[i]);
+ }
+ *p++ = ' ';
+ /* fixme: we need to get the pkcs-15 DF from the card function */
+ p = stpcpy (p, "3F005015.");
+ for (i=0; i < nkeyid; i++, p += 2)
+ sprintf (p, "%02X", keyid[i]);
+ *p = 0;
+ assuan_write_status (ctx, "KEYPAIRINFO", buf);
+ xfree (buf);
+ }
}
- /* not canceled, so we have to proceeed */
+ xfree (keyid);
}
+ if (rc == -1)
+ rc = 0;
+
return map_to_assuan_status (rc);
}
+
+/* READCERT <hexified_certid>
+ */
+static int
+cmd_readcert (ASSUAN_CONTEXT ctx, char *line)
+{
+ CTRL ctrl = assuan_get_pointer (ctx);
+ int rc;
+ unsigned char *cert;
+ size_t ncert;
+ if (!ctrl->card_ctx)
+ {
+ rc = card_open (&ctrl->card_ctx);
+ if (rc)
+ return map_to_assuan_status (rc);
+ }
+
+ rc = card_read_cert (ctrl->card_ctx, line, &cert, &ncert);
+ if (rc)
+ {
+ log_error ("card_read_cert failed: %s\n", gnupg_strerror (rc));
+ }
+ if (!rc)
+ {
+ rc = assuan_send_data (ctx, cert, ncert);
+ xfree (cert);
+ if (rc)
+ return rc;
+ }
+
+ return map_to_assuan_status (rc);
+}
/* Tell the assuan library about our commands */
@@ -150,6 +255,7 @@ register_commands (ASSUAN_CONTEXT ctx)
int (*handler)(ASSUAN_CONTEXT, char *line);
} table[] = {
{ "LEARN", 0, cmd_learn },
+ { "READCERT", 0, cmd_readcert },
{ "", ASSUAN_CMD_INPUT, NULL },
{ "", ASSUAN_CMD_OUTPUT, NULL },
{ NULL }