From 2b5dca457ca4bc4465cc8b6a3c26ab0023427a0d Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 5 Mar 2002 17:17:08 +0000 Subject: [PATCH] Well and some stuff to access the SC will be helpful. Note, that the code requires the latest OpenSC CVS code. --- scd/card.c | 70 +++++++++++++++++++++++++++++++++++++++----------- scd/command.c | 56 +++++++++++++++++++++++++++++++++++++++- scd/scdaemon.h | 6 +++++ 3 files changed, 116 insertions(+), 16 deletions(-) diff --git a/scd/card.c b/scd/card.c index 543812d51..281c81013 100644 --- a/scd/card.c +++ b/scd/card.c @@ -268,6 +268,8 @@ card_enum_keypairs (CARD card, int idx, { int rc; KsbaError krc; + struct sc_pkcs15_object *objs[32], *tmpobj; + int nobjs; struct sc_pkcs15_prkey_info *pinfo; struct sc_pkcs15_cert_info *certinfo; struct sc_pkcs15_cert *certder; @@ -283,19 +285,22 @@ card_enum_keypairs (CARD card, int idx, if (idx < 0) return GNUPG_Invalid_Index; - rc = sc_pkcs15_enum_private_keys (card->p15card); + rc = sc_pkcs15_get_objects (card->p15card, SC_PKCS15_TYPE_PRKEY_RSA, + objs, DIM (objs)); if (rc < 0) { - log_error ("sc_pkcs15_enum_private_keys failed: %s\n", sc_strerror (rc)); + log_error ("private keys enumeration failed: %s\n", sc_strerror (rc)); return GNUPG_Card_Error; } - if ( idx >= card->p15card->prkey_count) + nobjs = rc; + rc = 0; + if (idx >= nobjs) return -1; - pinfo = card->p15card->prkey_info + idx; + pinfo = objs[idx]->data; /* now we need to read the certificate so that we can calculate the keygrip */ - rc = sc_pkcs15_find_cert_by_id (card->p15card, &pinfo->id, &certinfo); + rc = sc_pkcs15_find_cert_by_id (card->p15card, &pinfo->id, &tmpobj); if (rc) { log_info ("certificate for private key %d not found: %s\n", @@ -312,6 +317,7 @@ card_enum_keypairs (CARD card, int idx, *nkeyid = pinfo->id.len; return GNUPG_Missing_Certificate; } + certinfo = tmpobj->data; rc = sc_pkcs15_read_certificate (card->p15card, certinfo, &certder); if (rc) { @@ -389,6 +395,7 @@ int card_read_cert (CARD card, const char *certidstr, unsigned char **cert, size_t *ncert) { + struct sc_pkcs15_object *tmpobj; struct sc_pkcs15_id certid; struct sc_pkcs15_cert_info *certinfo; struct sc_pkcs15_cert *certder; @@ -401,13 +408,14 @@ card_read_cert (CARD card, const char *certidstr, if (rc) return rc; - rc = sc_pkcs15_find_cert_by_id (card->p15card, &certid, &certinfo); + rc = sc_pkcs15_find_cert_by_id (card->p15card, &certid, &tmpobj); if (rc) { log_info ("certificate '%s' not found: %s\n", certidstr, sc_strerror (rc)); return -1; } + certinfo = tmpobj->data; rc = sc_pkcs15_read_certificate (card->p15card, certinfo, &certder); if (rc) { @@ -430,22 +438,28 @@ card_read_cert (CARD card, const char *certidstr, -/* Create the signature and return the allocated result in OUTDATA. */ +/* Create the signature and return the allocated result in OUTDATA. + If a PIN is required the PINCB will be used to ask for the PIN; it + should return the PIN in an allocated buffer and put it into PIN. */ int card_create_signature (CARD card, const char *keyidstr, int hashalgo, + int (pincb)(void*, const char *, char **), + void *pincb_arg, 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;*/ + struct sc_pkcs15_pin_info *pin; + struct sc_pkcs15_object *keyobj, *pinobj; + char *pinvalue; int rc; unsigned char *outbuf = NULL; size_t outbuflen; if (!card || !card->p15card || !indata || !indatalen - || !outdata || !outdatalen) + || !outdata || !outdatalen || !pincb) return GNUPG_Invalid_Value; if (hashalgo != GCRY_MD_SHA1) @@ -455,7 +469,7 @@ card_create_signature (CARD card, const char *keyidstr, int hashalgo, if (rc) return rc; - rc = sc_pkcs15_find_prkey_by_id (card->p15card, &keyid, &key); + rc = sc_pkcs15_find_prkey_by_id (card->p15card, &keyid, &keyobj); if (rc < 0) { log_error ("private key not found: %s\n", sc_strerror(rc)); @@ -463,13 +477,40 @@ card_create_signature (CARD card, const char *keyidstr, int hashalgo, goto leave; } rc = 0; - key = card->p15card->prkey_info; + key = keyobj->data; + rc = sc_pkcs15_find_pin_by_auth_id (card->p15card, + &keyobj->auth_id, &pinobj); + if (rc) + { + log_error ("failed to find PIN by auth ID: %s\n", sc_strerror (rc)); + rc = GNUPG_Bad_PIN_Method; + goto leave; + } + pin = pinobj->data; - /* FIXME: Handle PIN via callback */ + /* Fixme: pack this into a verification loop */ + /* Fixme: we might want to pass pin->min_length and + pin->stored_length */ + rc = pincb (pincb_arg, pinobj->label, &pinvalue); + if (rc) + { + log_info ("PIN callback returned error: %s\n", gnupg_strerror (rc)); + goto leave; + } - cryptflags |= SC_PKCS15_HASH_SHA1; - cryptflags |= SC_PKCS15_PAD_PKCS1_V1_5; + rc = sc_pkcs15_verify_pin (card->p15card, pin, + pinvalue, strlen (pinvalue)); + xfree (pinvalue); + if (rc) + { + log_info ("PIN verification failed: %s\n", sc_strerror (rc)); + rc = GNUPG_Bad_PIN; + goto leave; + } + +/* cryptflags |= SC_PKCS15_HASH_SHA1; */ +/* cryptflags |= SC_PKCS15_PAD_PKCS1_V1_5; */ outbuflen = 1024; outbuf = xtrymalloc (outbuflen); @@ -494,7 +535,6 @@ card_create_signature (CARD card, const char *keyidstr, int hashalgo, } - leave: xfree (outbuf); return rc; diff --git a/scd/command.c b/scd/command.c index e17248439..a171de3df 100644 --- a/scd/command.c +++ b/scd/command.c @@ -29,6 +29,9 @@ #include "scdaemon.h" #include "../assuan/assuan.h" +/* maximum length aloowed as a PIN; used for INQUIRE NEEDPIN */ +#define MAXLEN_PIN 100 + #define set_error(e,t) assuan_set_error (ctx, ASSUAN_ ## e, (t)) /* Data used to associate an Assuan context with local server data */ @@ -329,6 +332,40 @@ cmd_setdata (ASSUAN_CONTEXT ctx, char *line) +static int +pin_cb (void *opaque, const char *info, char **retstr) +{ + ASSUAN_CONTEXT ctx = opaque; + char *command; + int rc; + char *value; + size_t valuelen; + + *retstr = NULL; + log_debug ("asking for PIN '%s'\n", info); + + rc = asprintf (&command, "NEEDPIN %s", info); + if (rc < 0) + return GNUPG_Out_Of_Core; + + /* FIXME: Write an inquire function which returns the result in + secure memory */ + rc = assuan_inquire (ctx, command, &value, &valuelen, MAXLEN_PIN); + free (command); + if (rc) + return map_assuan_err (rc); + + if (!valuelen || value[valuelen-1]) + { + /* We require that the returned value is an UTF-8 string */ + xfree (value); + return GNUPG_Invalid_Response; + } + *retstr = value; + return 0; +} + + /* PKSIGN */ @@ -337,11 +374,28 @@ cmd_pksign (ASSUAN_CONTEXT ctx, char *line) { CTRL ctrl = assuan_get_pointer (ctx); int rc; + void *outdata; + size_t outdatalen; if ((rc = open_card (ctrl))) return rc; - + rc = card_create_signature (ctrl->card_ctx, + line, GCRY_MD_SHA1, + pin_cb, ctx, + ctrl->in_data.value, ctrl->in_data.valuelen, + &outdata, &outdatalen); + if (rc) + { + log_error ("card_create_signature failed: %s\n", gnupg_strerror (rc)); + } + else + { + rc = assuan_send_data (ctx, outdata, outdatalen); + xfree (outdata); + if (rc) + return rc; /* that is already an assuan error code */ + } return map_to_assuan_status (rc); } diff --git a/scd/scdaemon.h b/scd/scdaemon.h index 4104e8753..8a5506d32 100644 --- a/scd/scdaemon.h +++ b/scd/scdaemon.h @@ -86,6 +86,12 @@ int card_enum_keypairs (CARD card, int idx, unsigned char **keyid, size_t *nkeyid); int card_read_cert (CARD card, const char *certidstr, unsigned char **cert, size_t *ncert); +int card_create_signature (CARD card, + const char *keyidstr, int hashalgo, + int (pincb)(void*, const char *, char **), + void *pincb_arg, + const void *indata, size_t indatalen, + void **outdata, size_t *outdatalen );