diff options
Diffstat (limited to 'scd')
-rw-r--r-- | scd/card.c | 100 | ||||
-rw-r--r-- | scd/command.c | 35 | ||||
-rw-r--r-- | scd/scdaemon.h | 6 |
3 files changed, 140 insertions, 1 deletions
diff --git a/scd/card.c b/scd/card.c index 281c81013..e7640ffcb 100644 --- a/scd/card.c +++ b/scd/card.c @@ -541,3 +541,103 @@ leave: } +/* 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_decipher (CARD card, const char *keyidstr, + int (pincb)(void*, const char *, char **), + void *pincb_arg, + const void *indata, size_t indatalen, + void **outdata, size_t *outdatalen ) +{ + struct sc_pkcs15_id keyid; + struct sc_pkcs15_prkey_info *key; + 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 || !pincb) + return GNUPG_Invalid_Value; + + rc = idstr_to_id (keyidstr, &keyid); + if (rc) + return rc; + + 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)); + rc = GNUPG_No_Secret_Key; + goto leave; + } + rc = 0; + 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: 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; + } + + 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; + } + + outbuflen = indatalen < 256? 256 : indatalen; + outbuf = xtrymalloc (outbuflen); + if (!outbuf) + return GNUPG_Out_Of_Core; + + /* OpenSC does not yet support decryption for cryptflex cards */ +/* rc = sc_pkcs15_decipher (card->p15card, key, */ +/* indata, indatalen, */ +/* outbuf, outbuflen); */ + rc = sc_pkcs15_compute_signature (card->p15card, key, + 0, + indata, indatalen, + outbuf, outbuflen ); + if (rc < 0) + { + log_error ("failed to decipger the data: %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 a171de3df..30191dd95 100644 --- a/scd/command.c +++ b/scd/command.c @@ -400,6 +400,40 @@ cmd_pksign (ASSUAN_CONTEXT ctx, char *line) return map_to_assuan_status (rc); } +/* PKDECRYPT <hexified_id> + + */ +static int +cmd_pkdecrypt (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_decipher (ctrl->card_ctx, + line, + 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); +} + @@ -417,6 +451,7 @@ register_commands (ASSUAN_CONTEXT ctx) { "READCERT", 0, cmd_readcert }, { "SETDATA", 0, cmd_setdata }, { "PKSIGN", 0, cmd_pksign }, + { "PKDECRYPT", 0,cmd_pkdecrypt }, { "", ASSUAN_CMD_INPUT, NULL }, { "", ASSUAN_CMD_OUTPUT, NULL }, { NULL } diff --git a/scd/scdaemon.h b/scd/scdaemon.h index 8a5506d32..bd604b41c 100644 --- a/scd/scdaemon.h +++ b/scd/scdaemon.h @@ -92,7 +92,11 @@ int card_create_signature (CARD card, void *pincb_arg, const void *indata, size_t indatalen, void **outdata, size_t *outdatalen ); - +int card_decipher (CARD card, const char *keyidstr, + int (pincb)(void*, const char *, char **), + void *pincb_arg, + const void *indata, size_t indatalen, + void **outdata, size_t *outdatalen); #endif /*SCDAEMON_H*/ |