From 8b9f0bda3dc81a8e7ffa29dfc6589f364ee53aad Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Thu, 3 Jul 2003 18:10:13 +0000 Subject: [PATCH] * app-openpgp.c (do_setattr): Add setting of the URL. (app_select_openpgp): Dump card data only in very verbose mode. (do_decipher): New. --- scd/ChangeLog | 12 +++ scd/app-common.h | 8 +- scd/app-openpgp.c | 191 +++++++++++++++++++++++++++++++++++++++---- scd/app.c | 4 +- scd/card-common.h | 4 +- scd/card-p15.c | 4 +- scd/card.c | 4 +- scd/command.c | 4 +- scd/iso7816.c | 6 +- scd/sc-investigate.c | 3 + scd/scdaemon.h | 4 +- 11 files changed, 207 insertions(+), 37 deletions(-) diff --git a/scd/ChangeLog b/scd/ChangeLog index 0d78525aa..c7327f0b2 100644 --- a/scd/ChangeLog +++ b/scd/ChangeLog @@ -1,3 +1,15 @@ +2003-07-03 Werner Koch + + * app-openpgp.c (do_setattr): Add setting of the URL. + (app_select_openpgp): Dump card data only in very verbose mode. + (do_decipher): New. + +2003-07-02 Werner Koch + + * app-openpgp.c (get_sig_counter): New. + (do_sign): Print the signature counter and enable the PIN callback. + (do_genkey): Implement the PIN callback. + 2003-07-01 Werner Koch * app-openpgp.c (store_fpr): Fixed fingerprint calculation. diff --git a/scd/app-common.h b/scd/app-common.h index 16ee7d708..00d09828c 100644 --- a/scd/app-common.h +++ b/scd/app-common.h @@ -43,12 +43,12 @@ struct app_ctx_s { int (pincb)(void*, const char *, char **), void *pincb_arg, const void *indata, size_t indatalen, - void **outdata, size_t *outdatalen ); + unsigned char **outdata, size_t *outdatalen ); int (*decipher) (APP app, const char *keyidstr, int (pincb)(void*, const char *, char **), void *pincb_arg, const void *indata, size_t indatalen, - void **outdata, size_t *outdatalen); + unsigned char **outdata, size_t *outdatalen); int (*genkey) (APP app, CTRL ctrl, const char *keynostr, unsigned int flags, int (*pincb)(void*, const char *, char **), @@ -70,12 +70,12 @@ int app_sign (APP app, 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 char **outdata, size_t *outdatalen ); int app_decipher (APP app, const char *keyidstr, int (pincb)(void*, const char *, char **), void *pincb_arg, const void *indata, size_t indatalen, - void **outdata, size_t *outdatalen ); + unsigned char **outdata, size_t *outdatalen ); int app_genkey (APP app, CTRL ctrl, const char *keynostr, unsigned int flags, int (*pincb)(void*, const char *, char **), void *pincb_arg); diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c index 1e1e7fcd3..b546ed569 100644 --- a/scd/app-openpgp.c +++ b/scd/app-openpgp.c @@ -176,15 +176,19 @@ get_one_do (int slot, int tag, unsigned char **result, size_t *nbytes) &buffer, &buflen); if (!rc) { - value = find_tlv (buffer, buflen, tag, &valuelen, 0); - if (!value) - ; /* not found */ - else if (valuelen > buflen - (value - buffer)) + const unsigned char *s; + + s = find_tlv (buffer, buflen, tag, &valuelen, 0); + if (!s) + value = NULL; /* not found */ + else if (valuelen > buflen - (s - buffer)) { log_error ("warning: constructed DO too short\n"); value = NULL; xfree (buffer); buffer = NULL; } + else + value = buffer + (s - buffer); } } @@ -436,7 +440,7 @@ do_learn_status (APP app, CTRL ctrl) send_status_info (ctrl, "DISP-NAME", value, valuelen, NULL, 0); xfree (relptr); } - relptr = get_one_do (app->slot, 0x5FF0, &value, &valuelen); + relptr = get_one_do (app->slot, 0x5F50, &value, &valuelen); if (relptr) { send_status_info (ctrl, "PUBKEY-URL", value, valuelen, NULL, 0); @@ -479,8 +483,8 @@ do_setattr (APP app, const char *name, { char *pinvalue; -/* rc = pincb (pincb_arg, "Please enter the card's admin PIN (CHV3)", */ -/* &pinvalue); */ + rc = pincb (pincb_arg, "Admin PIN (CHV3)", + &pinvalue); pinvalue = xstrdup ("12345678"); rc = 0; if (rc) @@ -515,6 +519,15 @@ do_setattr (APP app, const char *name, rc = gpg_error (GPG_ERR_GENERAL); } } + else if (!strcmp (name, "PUBKEY-URL")) + { + rc = iso7816_put_data (app->slot, 0x5F50, value, valuelen); + if (rc) + { + log_error ("failed to set `Pubkey-URL'\n"); + rc = gpg_error (GPG_ERR_GENERAL); + } + } else rc = gpg_error (GPG_ERR_INV_NAME); @@ -539,6 +552,7 @@ do_genkey (APP app, CTRL ctrl, const char *keynostr, unsigned int flags, time_t created_at; int keyno = atoi (keynostr); int force = (flags & 1); + time_t start_at; if (keyno < 1 || keyno > 3) return gpg_error (GPG_ERR_INV_ID); @@ -571,7 +585,17 @@ do_genkey (APP app, CTRL ctrl, const char *keynostr, unsigned int flags, else log_info ("generating new key\n"); - rc = iso7816_verify (app->slot, 0x83, "12345678", 8); + { + char *pinvalue; + rc = pincb (pincb_arg, "Admin PIN", &pinvalue); + if (rc) + { + log_error ("error getting PIN: %s\n", gpg_strerror (rc)); + return rc; + } + rc = iso7816_verify (app->slot, 0x83, pinvalue, strlen (pinvalue)); + xfree (pinvalue); + } if (rc) { log_error ("verify CHV3 failed: rc=%04X\n", rc); @@ -580,6 +604,8 @@ do_genkey (APP app, CTRL ctrl, const char *keynostr, unsigned int flags, xfree (buffer); buffer = NULL; #if 1 + log_info ("please wait while key is being generated ...\n"); + start_at = time (NULL); rc = iso7816_generate_keypair #else #warning key generation temporary replaced by reading an existing key. @@ -596,6 +622,8 @@ do_genkey (APP app, CTRL ctrl, const char *keynostr, unsigned int flags, log_error ("generating key failed\n"); goto leave; } + log_info ("key generation completed (%d seconds)\n", + (int)(time (NULL) - start_at)); keydata = find_tlv (buffer, buflen, 0x7F49, &keydatalen, 0); if (!keydata) { @@ -609,7 +637,7 @@ do_genkey (APP app, CTRL ctrl, const char *keynostr, unsigned int flags, log_error ("response does not contain the RSA modulus\n"); goto leave; } - log_printhex ("RSA n:", m, mlen); +/* log_printhex ("RSA n:", m, mlen); */ send_key_data (ctrl, "n", m, mlen); e = find_tlv (keydata, keydatalen, 0x0082, &elen, 0); @@ -618,7 +646,7 @@ do_genkey (APP app, CTRL ctrl, const char *keynostr, unsigned int flags, log_error ("response does not contain the RSA public exponent\n"); goto leave; } - log_printhex ("RSA e:", e, elen); +/* log_printhex ("RSA e:", e, elen); */ send_key_data (ctrl, "e", e, elen); created_at = gnupg_get_time (); @@ -639,6 +667,28 @@ do_genkey (APP app, CTRL ctrl, const char *keynostr, unsigned int flags, } +static unsigned long +get_sig_counter (APP app) +{ + void *relptr; + unsigned char *value; + size_t valuelen; + unsigned long ul; + + relptr = get_one_do (app->slot, 0x0093, &value, &valuelen); + if (!relptr) + return 0; + if (valuelen == 3 ) + ul = (value[0] << 16) | (value[1] << 8) | value[2]; + else + { + log_error ("invalid structure of OpenPGP card (DO 0x93)\n"); + ul = 0; + } + xfree (relptr); + return ul; +} + static int compare_fingerprint (APP app, int keyno, unsigned char *sha1fpr) { @@ -688,7 +738,7 @@ do_sign (APP app, 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 char **outdata, size_t *outdatalen ) { static unsigned char sha1_prefix[15] = /* Object ID is 1.3.14.3.2.26 */ { 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, @@ -702,6 +752,7 @@ do_sign (APP app, const char *keyidstr, int hashalgo, const char *s; int n; const char *fpr = NULL; + unsigned long sigcount; if (!keyidstr || !*keyidstr) return gpg_error (GPG_ERR_INV_VALUE); @@ -731,7 +782,7 @@ do_sign (APP app, const char *keyidstr, int hashalgo, if (memcmp (app->serialno, tmp_sn, 16)) return gpg_error (GPG_ERR_WRONG_CARD); - /* If a fingerprint has been speicified check it against the one on + /* If a fingerprint has been specified check it against the one on the card. This is allows for a meaningful error message in case the key on the card has been replaced but the shadow information known to gpg was not updated. If there is no fingerprint, gpg @@ -763,14 +814,24 @@ do_sign (APP app, const char *keyidstr, int hashalgo, return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM); memcpy (data+15, indata, indatalen); + sigcount = get_sig_counter (app); + log_info ("signatures created so far: %lu\n", sigcount); - if (!app->did_chv1) + /* FIXME: Check whether we are really required to enter the PIN for + each signature. There is a DO for this. */ + if (!app->did_chv1 || 1) { char *pinvalue; -/* rc = pincb (pincb_arg, "signature PIN", &pinvalue); */ - pinvalue = xstrdup ("123456"); - rc = 0; + { + char *prompt; + if (asprintf (&prompt, "Signature PIN [sigs done: %lu]", sigcount) < 0) + return gpg_error_from_errno (errno); + rc = pincb (pincb_arg, prompt, &pinvalue); + free (prompt); + } +/* pinvalue = xstrdup ("123456"); */ +/* rc = 0; */ if (rc) { log_info ("PIN callback returned error: %s\n", gpg_strerror (rc)); @@ -789,11 +850,103 @@ do_sign (APP app, const char *keyidstr, int hashalgo, } rc = iso7816_compute_ds (app->slot, data, 35, outdata, outdatalen); - return rc; } +static int +do_decipher (APP app, const char *keyidstr, + int (pincb)(void*, const char *, char **), + void *pincb_arg, + const void *indata, size_t indatalen, + unsigned char **outdata, size_t *outdatalen ) +{ + int rc; + unsigned char tmp_sn[20]; /* actually 16 but we use it also for the fpr. */ + const char *s; + int n; + const char *fpr = NULL; + + if (!keyidstr || !*keyidstr || !indatalen) + return gpg_error (GPG_ERR_INV_VALUE); + + /* Check whether an OpenPGP card of any version has been requested. */ + if (strlen (keyidstr) < 32 || strncmp (keyidstr, "D27600012401", 12)) + return gpg_error (GPG_ERR_INV_ID); + + for (s=keyidstr, n=0; hexdigitp (s); s++, n++) + ; + if (n != 32) + return gpg_error (GPG_ERR_INV_ID); + else if (!*s) + ; /* no fingerprint given: we allow this for now. */ + else if (*s == '/') + fpr = s + 1; + else + return gpg_error (GPG_ERR_INV_ID); + + for (s=keyidstr, n=0; n < 16; s += 2, n++) + tmp_sn[n] = xtoi_2 (s); + + if (app->serialnolen != 16) + return gpg_error (GPG_ERR_INV_CARD); + if (memcmp (app->serialno, tmp_sn, 16)) + return gpg_error (GPG_ERR_WRONG_CARD); + + /* If a fingerprint has been specified check it against the one on + the card. This is allows for a meaningful error message in case + the key on the card has been replaced but the shadow information + known to gpg was not updated. If there is no fingerprint, the + decryption will won't produce the right plaintext anyway. */ + if (fpr) + { + for (s=fpr, n=0; hexdigitp (s); s++, n++) + ; + if (n != 40) + return gpg_error (GPG_ERR_INV_ID); + else if (!*s) + ; /* okay */ + else + return gpg_error (GPG_ERR_INV_ID); + + for (s=fpr, n=0; n < 20; s += 2, n++) + tmp_sn[n] = xtoi_2 (s); + rc = compare_fingerprint (app, 2, tmp_sn); + if (rc) + return rc; + } + + if (!app->did_chv2) + { + char *pinvalue; + + rc = pincb (pincb_arg, "Decryption PIN", &pinvalue); +/* pinvalue = xstrdup ("123456"); */ +/* rc = 0; */ + if (rc) + { + log_info ("PIN callback returned error: %s\n", gpg_strerror (rc)); + return rc; + } + + rc = iso7816_verify (app->slot, 0x82, pinvalue, strlen (pinvalue)); + xfree (pinvalue); + if (rc) + { + log_error ("verify CHV2 failed\n"); + rc = gpg_error (GPG_ERR_GENERAL); + return rc; + } + app->did_chv2 = 1; + } + + rc = iso7816_decipher (app->slot, indata, indatalen, outdata, outdatalen); + return rc; +} + + + + /* Select the OpenPGP application on the card in SLOT. This function must be used before any other OpenPGP application functions. */ int @@ -827,12 +980,14 @@ app_select_openpgp (APP app, unsigned char **sn, size_t *snlen) else xfree (buffer); - dump_all_do (slot); + if (opt.verbose > 1) + dump_all_do (slot); app->fnc.learn_status = do_learn_status; app->fnc.setattr = do_setattr; app->fnc.genkey = do_genkey; app->fnc.sign = do_sign; + app->fnc.decipher = do_decipher; } leave: diff --git a/scd/app.c b/scd/app.c index 3688b1c8d..7d143ad13 100644 --- a/scd/app.c +++ b/scd/app.c @@ -138,7 +138,7 @@ app_sign (APP app, 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 char **outdata, size_t *outdatalen ) { int rc; @@ -166,7 +166,7 @@ app_decipher (APP app, const char *keyidstr, int (pincb)(void*, const char *, char **), void *pincb_arg, const void *indata, size_t indatalen, - void **outdata, size_t *outdatalen ) + unsigned char **outdata, size_t *outdatalen ) { int rc; diff --git a/scd/card-common.h b/scd/card-common.h index 7ce2726c3..31f0dfe8f 100644 --- a/scd/card-common.h +++ b/scd/card-common.h @@ -48,12 +48,12 @@ struct card_ctx_s { int (pincb)(void*, const char *, char **), void *pincb_arg, const void *indata, size_t indatalen, - void **outdata, size_t *outdatalen ); + unsigned char **outdata, size_t *outdatalen ); int (*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); + unsigned char **outdata, size_t *outdatalen); } fnc; }; diff --git a/scd/card-p15.c b/scd/card-p15.c index 47830a0ec..3cf4ba519 100644 --- a/scd/card-p15.c +++ b/scd/card-p15.c @@ -382,7 +382,7 @@ p15_sign (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 char **outdata, size_t *outdatalen ) { unsigned int cryptflags; struct sc_pkcs15_object *keyobj; @@ -432,7 +432,7 @@ p15_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 ) + unsigned char **outdata, size_t *outdatalen ) { struct sc_pkcs15_object *keyobj; int rc; diff --git a/scd/card.c b/scd/card.c index e46bb9d21..00c190fa1 100644 --- a/scd/card.c +++ b/scd/card.c @@ -512,7 +512,7 @@ card_sign (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 char **outdata, size_t *outdatalen ) { int rc; @@ -540,7 +540,7 @@ 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 ) + unsigned char **outdata, size_t *outdatalen ) { int rc; diff --git a/scd/command.c b/scd/command.c index 45ce7b33d..ac6ddb412 100644 --- a/scd/command.c +++ b/scd/command.c @@ -565,7 +565,7 @@ cmd_pksign (ASSUAN_CONTEXT ctx, char *line) { CTRL ctrl = assuan_get_pointer (ctx); int rc; - void *outdata; + unsigned char *outdata; size_t outdatalen; char *keyidstr; @@ -615,7 +615,7 @@ cmd_pkdecrypt (ASSUAN_CONTEXT ctx, char *line) { CTRL ctrl = assuan_get_pointer (ctx); int rc; - void *outdata; + unsigned char *outdata; size_t outdatalen; char *keyidstr; diff --git a/scd/iso7816.c b/scd/iso7816.c index 3152698c5..de3ada7c6 100644 --- a/scd/iso7816.c +++ b/scd/iso7816.c @@ -140,7 +140,7 @@ iso7816_compute_ds (int slot, const unsigned char *data, size_t datalen, if (sw != SW_SUCCESS) { /* Make sure that pending buffers are released. */ - xfree (result); + xfree (*result); *result = NULL; *resultlen = 0; return -1; /* FIXME: Map error codes. */ @@ -178,7 +178,7 @@ iso7816_decipher (int slot, const unsigned char *data, size_t datalen, if (sw != SW_SUCCESS) { /* Make sure that pending buffers are released. */ - xfree (result); + xfree (*result); *result = NULL; *resultlen = 0; return -1; /* FIXME: Map error codes. */ @@ -205,7 +205,7 @@ iso7816_internal_authenticate (int slot, if (sw != SW_SUCCESS) { /* Make sure that pending buffers are released. */ - xfree (result); + xfree (*result); *result = NULL; *resultlen = 0; return -1; /* FIXME: Map error codes. */ diff --git a/scd/sc-investigate.c b/scd/sc-investigate.c index 1100bdf43..e7fd6dddc 100644 --- a/scd/sc-investigate.c +++ b/scd/sc-investigate.c @@ -140,6 +140,9 @@ main (int argc, char **argv ) if (log_get_errorcount(0)) exit(2); + if (opt.verbose < 2) + opt.verbose = 2; /* hack to let select_openpgp print some info. */ + if (argc) usage (1); diff --git a/scd/scdaemon.h b/scd/scdaemon.h index 394a13a1a..b21e19f8c 100644 --- a/scd/scdaemon.h +++ b/scd/scdaemon.h @@ -116,12 +116,12 @@ int card_sign (CARD card, int (pincb)(void*, const char *, char **), void *pincb_arg, const void *indata, size_t indatalen, - void **outdata, size_t *outdatalen ); + unsigned char **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); + unsigned char **outdata, size_t *outdatalen); #endif /*SCDAEMON_H*/