From f8efc7c4ef65a9ec76353247aae837134ad13756 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Mon, 4 Mar 2002 10:34:09 +0000 Subject: [PATCH] Added more code fragments. --- scd/card.c | 110 ++++++++++++++++++++++++++++++++++------ scd/command.c | 135 ++++++++++++++++++++++++++++++++++++++++++++----- scd/scdaemon.h | 4 ++ 3 files changed, 220 insertions(+), 29 deletions(-) diff --git a/scd/card.c b/scd/card.c index dbfbe5333..543812d51 100644 --- a/scd/card.c +++ b/scd/card.c @@ -359,6 +359,28 @@ card_enum_keypairs (CARD card, int idx, +static int +idstr_to_id (const char *idstr, struct sc_pkcs15_id *id) +{ + const char *s; + int n; + + /* For now we only support the standard DF */ + if (strncmp (idstr, "3F005015.", 9) ) + return GNUPG_Invalid_Id; + for (s=idstr+9, n=0; hexdigitp (s); s++, n++) + ; + if (*s || (n&1)) + return GNUPG_Invalid_Id; /* invalid or odd number of digits */ + n /= 2; + if (!n || n > SC_PKCS15_MAX_ID_SIZE) + return GNUPG_Invalid_Id; /* empty or too large */ + for (s=idstr+9, n=0; *s; s += 2, n++) + id->value[n] = xtoi_2 (s); + id->len = n; + return 0; +} + /* Read the certificate identified by CERTIDSTR which is the hexadecimal encoded ID of the certificate, prefixed with the string "3F005015.". The certificate is return in DER encoded form in CERT @@ -370,25 +392,14 @@ card_read_cert (CARD card, const char *certidstr, struct sc_pkcs15_id certid; struct sc_pkcs15_cert_info *certinfo; struct sc_pkcs15_cert *certder; - const char *s; - int rc, n; + int rc; if (!card || !certidstr || !card->p15card || !cert || !ncert) return GNUPG_Invalid_Value; - /* For now we only support the standard DF */ - if (strncmp (certidstr, "3F005015.", 9) ) - return GNUPG_Invalid_Id; - for (s=certidstr+9, n=0; hexdigitp (s); s++, n++) - ; - if (*s || (n&1)) - return GNUPG_Invalid_Id; /* invalid or odd number of digits */ - n /= 2; - if (!n || n > SC_PKCS15_MAX_ID_SIZE) - return GNUPG_Invalid_Id; /* empty or too large */ - for (s=certidstr+9, n=0; *s; s += 2, n++) - certid.value[n] = xtoi_2 (s); - certid.len = n; + rc = idstr_to_id (certidstr, &certid); + if (rc) + return rc; rc = sc_pkcs15_find_cert_by_id (card->p15card, &certid, &certinfo); if (rc) @@ -418,6 +429,75 @@ card_read_cert (CARD card, const char *certidstr, } + +/* Create the signature and return the allocated result in OUTDATA. */ +int +card_create_signature (CARD card, const char *keyidstr, int hashalgo, + const void *indata, size_t indatalen, + void **outdata, size_t *outdatalen ) +{ + unsigned int cryptflags = 0; + struct sc_pkcs15_id keyid; + struct sc_pkcs15_prkey_info *key; + /* struct sc_pkcs15_pin_info *pin;*/ + int rc; + unsigned char *outbuf = NULL; + size_t outbuflen; + + if (!card || !card->p15card || !indata || !indatalen + || !outdata || !outdatalen) + return GNUPG_Invalid_Value; + + if (hashalgo != GCRY_MD_SHA1) + return GNUPG_Unsupported_Algorithm; + + rc = idstr_to_id (keyidstr, &keyid); + if (rc) + return rc; + + rc = sc_pkcs15_find_prkey_by_id (card->p15card, &keyid, &key); + if (rc < 0) + { + log_error ("private key not found: %s\n", sc_strerror(rc)); + rc = GNUPG_No_Secret_Key; + goto leave; + } + rc = 0; + key = card->p15card->prkey_info; + + + /* FIXME: Handle PIN via callback */ + + cryptflags |= SC_PKCS15_HASH_SHA1; + cryptflags |= SC_PKCS15_PAD_PKCS1_V1_5; + + outbuflen = 1024; + outbuf = xtrymalloc (outbuflen); + if (!outbuf) + return GNUPG_Out_Of_Core; + + rc = sc_pkcs15_compute_signature (card->p15card, key, + cryptflags, + indata, indatalen, + outbuf, outbuflen ); + if (rc < 0) + { + log_error ("failed to create signature: %s\n", sc_strerror (rc)); + rc = GNUPG_Card_Error; + } + else + { + *outdatalen = rc; + *outdata = outbuf; + outbuf = NULL; + rc = 0; + } +leave: + xfree (outbuf); + return rc; +} + + diff --git a/scd/command.c b/scd/command.c index b4eaa8a47..e17248439 100644 --- a/scd/command.c +++ b/scd/command.c @@ -61,6 +61,8 @@ reset_notify (ASSUAN_CONTEXT ctx) { card_close (ctrl->card_ctx); ctrl->card_ctx = NULL; + xfree (ctrl->in_data.value); + ctrl->in_data.value = NULL; } } @@ -72,6 +74,63 @@ option_handler (ASSUAN_CONTEXT ctx, const char *key, const char *value) } +/* If the card has not yet been opened, do it. Note that this + function returns an Assuan error, so don't map the error a second + time */ +static AssuanError +open_card (CTRL ctrl) +{ + if (!ctrl->card_ctx) + { + int rc = card_open (&ctrl->card_ctx); + if (rc) + return map_to_assuan_status (rc); + } + return 0; +} + + +/* SERIALNO + + Return the serial number of the card using a status reponse. This + functon should be used to check for the presence of a card. + + This function is special in that it can be used to reset the card. + Most other functions will return an error when a card change has + been detected and the use of this function is therefore required. + + Background: We want to keep the client clear of handling card + changes between operations; i.e. the client can assume that all + operations are doneon the same card unless he call this function. + */ +static int +cmd_serialno (ASSUAN_CONTEXT ctx, char *line) +{ + CTRL ctrl = assuan_get_pointer (ctx); + int rc = 0; + char *serial_and_stamp; + char *serial; + time_t stamp; + + if ((rc = open_card (ctrl))) + return rc; + + 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); + free (serial_and_stamp); + return 0; +} + + + + /* LEARN [--force] Learn all useful information of the currently inserted card. When @@ -98,14 +157,8 @@ cmd_learn (ASSUAN_CONTEXT ctx, char *line) int rc = 0; int idx; - /* if this is the first command issued for a new card, open the card and - and create a context */ - if (!ctrl->card_ctx) - { - rc = card_open (&ctrl->card_ctx); - if (rc) - return map_to_assuan_status (rc); - } + if ((rc = open_card (ctrl))) + return rc; /* Unless the force option is used we try a shortcut by identifying the card using a serial number and inquiring the client with @@ -221,12 +274,8 @@ cmd_readcert (ASSUAN_CONTEXT ctx, char *line) unsigned char *cert; size_t ncert; - if (!ctrl->card_ctx) - { - rc = card_open (&ctrl->card_ctx); - if (rc) - return map_to_assuan_status (rc); - } + if ((rc = open_card (ctrl))) + return rc; rc = card_read_cert (ctrl->card_ctx, line, &cert, &ncert); if (rc) @@ -244,6 +293,61 @@ cmd_readcert (ASSUAN_CONTEXT ctx, char *line) return map_to_assuan_status (rc); } + + + +/* SETDATA + + The client should use this command to tell us the data he want to + sign. */ +static int +cmd_setdata (ASSUAN_CONTEXT ctx, char *line) +{ + CTRL ctrl = assuan_get_pointer (ctx); + int n; + char *p; + unsigned char *buf; + + /* parse the hexstring */ + for (p=line,n=0; hexdigitp (p); p++, n++) + ; + if (*p) + return set_error (Parameter_Error, "invalid hexstring"); + if ((n&1)) + return set_error (Parameter_Error, "odd number of digits"); + n /= 2; + buf = xtrymalloc (n); + if (!buf) + return ASSUAN_Out_Of_Core; + + ctrl->in_data.value = buf; + ctrl->in_data.valuelen = n; + for (p=line, n=0; n < ctrl->in_data.valuelen; p += 2, n++) + buf[n] = xtoi_2 (p); + return 0; +} + + + +/* PKSIGN + + */ +static int +cmd_pksign (ASSUAN_CONTEXT ctx, char *line) +{ + CTRL ctrl = assuan_get_pointer (ctx); + int rc; + + if ((rc = open_card (ctrl))) + return rc; + + + + return map_to_assuan_status (rc); +} + + + /* Tell the assuan library about our commands */ static int @@ -254,8 +358,11 @@ register_commands (ASSUAN_CONTEXT ctx) int cmd_id; int (*handler)(ASSUAN_CONTEXT, char *line); } table[] = { + { "SERIALNO", 0, cmd_serialno }, { "LEARN", 0, cmd_learn }, { "READCERT", 0, cmd_readcert }, + { "SETDATA", 0, cmd_setdata }, + { "PKSIGN", 0, cmd_pksign }, { "", ASSUAN_CMD_INPUT, NULL }, { "", ASSUAN_CMD_OUTPUT, NULL }, { NULL } diff --git a/scd/scdaemon.h b/scd/scdaemon.h index e77012416..4104e8753 100644 --- a/scd/scdaemon.h +++ b/scd/scdaemon.h @@ -61,6 +61,10 @@ struct card_ctx_s; struct server_control_s { struct server_local_s *server_local; struct card_ctx_s *card_ctx; + struct { + unsigned char *value; + int valuelen; + } in_data; /* helper to store the value we are going to sign */ }; typedef struct server_control_s *CTRL;