diff options
Diffstat (limited to '')
-rw-r--r-- | scd/app-openpgp.c | 189 |
1 files changed, 172 insertions, 17 deletions
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: |