From 6639bbf699b7625c3b674f39b30138ef835f00ee Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 3 May 2005 22:27:07 +0000 Subject: [PATCH] * passphrase.c (agent_get_passphrase): Add new arg CACHEID. Changed all callers. (ask_passphrase): Add new arg CACHEID and use it in agent mode. Changed all callers. (passphrase_clear_cache): New arg CACHEID. Changed all callers. * cardglue.c (format_cacheid): New. (pin_cb): Compute a cache ID. (agent_scd_pksign, agent_scd_pkdecrypt): Use it. (agent_clear_pin_cache): New. * card-util.c (change_pin): Clear the PIN cache. (check_pin_for_key_operation): Ditto. --- g10/ChangeLog | 19 ++++++++++ g10/card-util.c | 4 ++ g10/cardglue.c | 97 +++++++++++++++++++++++++++++++++++++++++++---- g10/cardglue.h | 4 ++ g10/keydb.h | 5 ++- g10/passphrase.c | 71 +++++++++++++++++++++++----------- g10/seckey-cert.c | 4 +- g10/sign.c | 4 ++ 8 files changed, 174 insertions(+), 34 deletions(-) diff --git a/g10/ChangeLog b/g10/ChangeLog index 30f8939bf..b7ce53c65 100644 --- a/g10/ChangeLog +++ b/g10/ChangeLog @@ -1,3 +1,17 @@ +2005-05-03 Werner Koch + + * passphrase.c (agent_get_passphrase): Add new arg CACHEID. + Changed all callers. + (ask_passphrase): Add new arg CACHEID and use it in agent mode. + Changed all callers. + (passphrase_clear_cache): New arg CACHEID. Changed all callers. + * cardglue.c (format_cacheid): New. + (pin_cb): Compute a cache ID. + (agent_scd_pksign, agent_scd_pkdecrypt): Use it. + (agent_clear_pin_cache): New. + * card-util.c (change_pin): Clear the PIN cache. + (check_pin_for_key_operation): Ditto. + 2005-04-24 David Shaw * trustdb.h, trustdb.c (mark_usable_uid_certs): Add flags for the @@ -24,6 +38,11 @@ here. We'll fail quite happily later, and usually with a better error message to boot. +2005-04-20 Werner Koch + + * sign.c (sign_file, sign_symencrypt_file): Allow for hash + debugging. + 2005-04-16 David Shaw * keyserver.c (keyserver_spawn): Free some memory. diff --git a/g10/card-util.c b/g10/card-util.c index ecb80f08a..8874935e3 100644 --- a/g10/card-util.c +++ b/g10/card-util.c @@ -67,6 +67,8 @@ change_pin (int chvno, int allow_admin) log_info (_("OpenPGP card no. %s detected\n"), info.serialno? info.serialno : "[none]"); + agent_clear_pin_cache (info.serialno); + agent_release_card_info (&info); if (opt.batch) @@ -950,6 +952,8 @@ check_pin_for_key_operation (struct agent_card_info_s *info, int *forced_chv1) { int rc = 0; + agent_clear_pin_cache (info->serialno); + *forced_chv1 = !info->chv1_cached; if (*forced_chv1) { /* Switch of the forced mode so that during key generation we diff --git a/g10/cardglue.c b/g10/cardglue.c index 530e8a43f..9e7aef81f 100644 --- a/g10/cardglue.c +++ b/g10/cardglue.c @@ -43,12 +43,19 @@ #include "apdu.h" #include "app-common.h" -struct ctrl_ctx_s { +struct ctrl_ctx_s +{ int (*status_cb)(void *opaque, const char *line); void *status_cb_arg; }; +struct pincb_parm_s +{ + const char *sn; +}; + + static char *default_reader_port; static APP current_app; @@ -334,6 +341,39 @@ card_close (void) } +/* Format a cache ID from the serialnumber in SN and return it as an + allocated string. In case of an error NULL is returned. */ +static char * +format_cacheid (const char *sn) +{ + const char *s; + size_t snlen; + char *cacheid = NULL; + + /* The serialnumber we use for a card is "CARDSN:serialno". Where + serialno is the BCD string (i.e. hex string) with the full + number. The serial number expect here constsis of hexdigits + followed by other characters, we cut off these other + characters. */ + if (sn) + { + for (s=sn,snlen=0; hexdigitp (s); s++, snlen++) + ; + if (snlen == 32) + { + /* Yes, this looks indeed like an OpenPGP card S/N. */ + cacheid = xtrymalloc (7+snlen+1); + if (cacheid) + { + memcpy (cacheid, "CARDSN:", 7); + memcpy (cacheid+7, sn, snlen); + cacheid[7+snlen] = 0; + } + } + } + return cacheid; +} + /* Check that the serial number of the current card (as described by APP) matches SERIALNO. If there is no match and we are not in batch mode, present a prompt to insert the desired card. The @@ -651,12 +691,14 @@ agent_scd_getattr (const char *name, struct agent_card_info_s *info) static int pin_cb (void *opaque, const char *info, char **retstr) { + struct pincb_parm_s *parm = opaque; char *value; int canceled; int isadmin = 0; int newpin = 0; const char *again_text = NULL; const char *ends, *s; + char *cacheid = NULL; *retstr = NULL; /* log_debug ("asking for PIN '%s'\n", info); */ @@ -674,9 +716,23 @@ pin_cb (void *opaque, const char *info, char **retstr) } info = ends+1; } - else + else if (info && *info == '|') log_debug ("pin_cb called without proper PIN info hack\n"); + /* If we are not requesting a new PIN and we are not requesting an + AdminPIN, compute a string to be used as the cacheID for + gpg-agent. */ + if (!newpin && !isadmin && parm) + { + cacheid = format_cacheid (parm->sn); + } + else if (newpin && parm) + { + /* Make really sure that it is not cached anymore. */ + agent_clear_pin_cache (parm->sn); + } + + again: if (is_status_enabled()) write_status_text (STATUS_NEED_PASSPHRASE_PIN, @@ -691,7 +747,10 @@ pin_cb (void *opaque, const char *info, char **retstr) newpin? _("Enter New PIN: ") : isadmin? _("Enter Admin PIN: ") : _("Enter PIN: "), + cacheid, &canceled); + xfree (cacheid); + cacheid = NULL; again_text = NULL; if (!value && canceled) return -1; @@ -702,7 +761,7 @@ pin_cb (void *opaque, const char *info, char **retstr) { char *value2; - value2 = ask_passphrase (info, NULL, + value2 = ask_passphrase (info, NULL, NULL, "passphrase.pin.repeat", _("Repeat this PIN: "), &canceled); @@ -837,11 +896,14 @@ agent_scd_pksign (const char *serialno, int hashalgo, const unsigned char *indata, size_t indatalen, unsigned char **r_buf, size_t *r_buflen) { + struct pincb_parm_s parm; APP app; int rc; *r_buf = NULL; *r_buflen = 0; + memset (&parm, 0, sizeof parm); + parm.sn = serialno; retry: app = current_app? current_app : open_card (); if (!app) @@ -854,11 +916,14 @@ agent_scd_pksign (const char *serialno, int hashalgo, if (!rc) rc = app->fnc.sign (app, serialno, hashalgo, - pin_cb, NULL, + pin_cb, &parm, indata, indatalen, r_buf, r_buflen); if (rc) - write_status (STATUS_SC_OP_FAILURE); + { + write_status (STATUS_SC_OP_FAILURE); + agent_clear_pin_cache (serialno); + } return rc; } @@ -869,11 +934,14 @@ agent_scd_pkdecrypt (const char *serialno, const unsigned char *indata, size_t indatalen, unsigned char **r_buf, size_t *r_buflen) { + struct pincb_parm_s parm; APP app; int rc; *r_buf = NULL; *r_buflen = 0; + memset (&parm, 0, sizeof parm); + parm.sn = serialno; retry: app = current_app? current_app : open_card (); if (!app) @@ -886,11 +954,14 @@ agent_scd_pkdecrypt (const char *serialno, if (!rc) rc = app->fnc.decipher (app, serialno, - pin_cb, NULL, + pin_cb, &parm, indata, indatalen, r_buf, r_buflen); if (rc) - write_status (STATUS_SC_OP_FAILURE); + { + write_status (STATUS_SC_OP_FAILURE); + agent_clear_pin_cache (serialno); + } return rc; } @@ -960,3 +1031,15 @@ agent_openpgp_storekey (int keyno, write_status (STATUS_SC_OP_FAILURE); return rc; } + + +void +agent_clear_pin_cache (const char *sn) +{ + char *cacheid = format_cacheid (sn); + if (cacheid) + { + passphrase_clear_cache (NULL, cacheid, 0); + xfree (cacheid); + } +} diff --git a/g10/cardglue.h b/g10/cardglue.h index 7ab04f027..068a1aacf 100644 --- a/g10/cardglue.h +++ b/g10/cardglue.h @@ -194,6 +194,10 @@ int agent_openpgp_storekey (int keyno, const unsigned char *m, size_t mlen, const unsigned char *e, size_t elen); +/* Clear a cached PIN. */ +void agent_clear_pin_cache (const char *sn); + + #endif /*ENABLE_CARD_SUPPORT*/ #endif /*GNUPG_G10_CARDGLUE_H*/ diff --git a/g10/keydb.h b/g10/keydb.h index 7ec0384a1..eca817ea0 100644 --- a/g10/keydb.h +++ b/g10/keydb.h @@ -186,11 +186,12 @@ int build_sk_list( STRLIST locusr, SK_LIST *ret_sk_list, /*-- passphrase.h --*/ int have_static_passphrase(void); void read_passphrase_from_fd( int fd ); -void passphrase_clear_cache ( u32 *keyid, int algo ); +void passphrase_clear_cache ( u32 *keyid, const char *cacheid, int algo ); char *ask_passphrase (const char *description, const char *tryagain_text, const char *promptid, - const char *prompt, int *canceled); + const char *prompt, + const char *cacheid, int *canceled); DEK *passphrase_to_dek( u32 *keyid, int pubkey_algo, int cipher_algo, STRING2KEY *s2k, int mode, const char *tryagain_text, int *canceled); diff --git a/g10/passphrase.c b/g10/passphrase.c index c309904b1..a68d564fe 100644 --- a/g10/passphrase.c +++ b/g10/passphrase.c @@ -425,10 +425,13 @@ agent_okay_cb (void *opaque, const char *line) * * Note that TRYAGAIN_TEXT must not be translated. If canceled is not * NULL, the function does set it to 1 if the user canceled the - * operation. + * operation. If CACHEID is not NULL, it will be used as the cacheID + * for the gpg-agent; if is NULL and a key fingerprint can be + * computed, this will be used as the cacheid. */ static char * -agent_get_passphrase ( u32 *keyid, int mode, const char *tryagain_text, +agent_get_passphrase ( u32 *keyid, int mode, const char *cacheid, + const char *tryagain_text, const char *custom_description, const char *custom_prompt, int *canceled) { @@ -545,11 +548,16 @@ agent_get_passphrase ( u32 *keyid, int mode, const char *tryagain_text, line = xmalloc (15 + 46 + 3*strlen (atext) + 3*strlen (custom_prompt? custom_prompt:"") + + (cacheid? (3*strlen (cacheid)): 0) + 3*strlen (tryagain_text) + 1); strcpy (line, "GET_PASSPHRASE "); p = line+15; - if (!mode && have_fpr) + if (!mode && cacheid) + { + p = percent_plus_escape (p, cacheid); + } + else if (!mode && have_fpr) { for (i=0; i < 20; i++, p +=2 ) sprintf (p, "%02X", fpr[i]); @@ -629,10 +637,11 @@ agent_get_passphrase ( u32 *keyid, int mode, const char *tryagain_text, /* - * Clear the cached passphrase + * Clear the cached passphrase. If CACHEID is not NULL, it will be + * used instead of a cache ID derived from KEYID. */ void -passphrase_clear_cache ( u32 *keyid, int algo ) +passphrase_clear_cache ( u32 *keyid, const char *cacheid, int algo ) { #ifdef ENABLE_AGENT_SUPPORT assuan_context_t ctx = NULL; @@ -646,17 +655,22 @@ passphrase_clear_cache ( u32 *keyid, int algo ) if (!opt.use_agent) return; - pk = xcalloc (1, sizeof *pk); - memset (fpr, 0, MAX_FINGERPRINT_LEN ); - if( !keyid || get_pubkey( pk, keyid ) ) + if (!cacheid) { - goto failure; /* oops: no key for some reason */ - } + pk = xcalloc (1, sizeof *pk); + memset (fpr, 0, MAX_FINGERPRINT_LEN ); + if( !keyid || get_pubkey( pk, keyid ) ) + { + goto failure; /* oops: no key for some reason */ + } - { - size_t dummy; - fingerprint_from_pk( pk, fpr, &dummy ); - } + { + size_t dummy; + fingerprint_from_pk( pk, fpr, &dummy ); + } + } + else + pk = NULL; if ( !(ctx = agent_open ()) ) goto failure; @@ -665,11 +679,21 @@ passphrase_clear_cache ( u32 *keyid, int algo ) char *line, *p; int i, rc; - line = xmalloc (17 + 40 + 2); - strcpy (line, "CLEAR_PASSPHRASE "); - p = line+17; - for (i=0; i < 20; i++, p +=2 ) - sprintf (p, "%02X", fpr[i]); + if (cacheid) + { + line = xmalloc (17 + 3*strlen (cacheid) + 2); + strcpy (line, "CLEAR_PASSPHRASE "); + p = line+17; + p = percent_plus_escape (p, cacheid); + } + else + { + line = xmalloc (17 + 40 + 2); + strcpy (line, "CLEAR_PASSPHRASE "); + p = line+17; + for (i=0; i < 20; i++, p +=2 ) + sprintf (p, "%02X", fpr[i]); + } *p = 0; rc = assuan_transact (ctx, line, NULL, NULL, NULL, NULL, NULL, NULL); @@ -696,7 +720,8 @@ char * ask_passphrase (const char *description, const char *tryagain_text, const char *promptid, - const char *prompt, int *canceled) + const char *prompt, + const char *cacheid, int *canceled) { char *pw = NULL; @@ -709,7 +734,7 @@ ask_passphrase (const char *description, agent_died: if ( opt.use_agent ) { - pw = agent_get_passphrase (NULL, 0, + pw = agent_get_passphrase (NULL, 0, cacheid, tryagain_text, description, prompt, canceled ); if (!pw) @@ -853,7 +878,7 @@ passphrase_to_dek( u32 *keyid, int pubkey_algo, } else if ( opt.use_agent ) { /* Divert to the gpg-agent. */ - pw = agent_get_passphrase ( keyid, mode == 2? 1: 0, + pw = agent_get_passphrase ( keyid, mode == 2? 1: 0, NULL, tryagain_text, NULL, NULL, canceled ); if (!pw) { @@ -862,7 +887,7 @@ passphrase_to_dek( u32 *keyid, int pubkey_algo, pw = m_strdup (""); } if( *pw && mode == 2 ) { - char *pw2 = agent_get_passphrase ( keyid, 2, NULL, NULL, + char *pw2 = agent_get_passphrase ( keyid, 2, NULL, NULL, NULL, NULL, canceled ); if (!pw2) { diff --git a/g10/seckey-cert.c b/g10/seckey-cert.c index 9153b9508..fc318d0ae 100644 --- a/g10/seckey-cert.c +++ b/g10/seckey-cert.c @@ -203,7 +203,7 @@ do_check( PKT_secret_key *sk, const char *tryagain_text, int mode, /* now let's see whether we have used the right passphrase */ if( csum != sk->csum ) { copy_secret_key( sk, save_sk ); - passphrase_clear_cache ( keyid, sk->pubkey_algo ); + passphrase_clear_cache ( keyid, NULL, sk->pubkey_algo ); free_secret_key( save_sk ); return G10ERR_BAD_PASS; } @@ -211,7 +211,7 @@ do_check( PKT_secret_key *sk, const char *tryagain_text, int mode, res = pubkey_check_secret_key( sk->pubkey_algo, sk->skey ); if( res ) { copy_secret_key( sk, save_sk ); - passphrase_clear_cache ( keyid, sk->pubkey_algo ); + passphrase_clear_cache ( keyid, NULL, sk->pubkey_algo ); free_secret_key( save_sk ); return G10ERR_BAD_PASS; } diff --git a/g10/sign.c b/g10/sign.c index 814f3816d..c65b8275e 100644 --- a/g10/sign.c +++ b/g10/sign.c @@ -808,6 +808,8 @@ sign_file( STRLIST filenames, int detached, STRLIST locusr, } mfx.md = md_open(0, 0); + if (DBG_HASHING) + md_start_debug (mfx.md, "sign"); /* If we're encrypting and signing, it is reasonable to pick the hash algorithm to use out of the recepient key prefs. */ @@ -1217,6 +1219,8 @@ sign_symencrypt_file (const char *fname, STRLIST locusr) if (opt.textmode) iobuf_push_filter (inp, text_filter, &tfx); mfx.md = md_open(0, 0); + if ( DBG_HASHING ) + md_start_debug (mfx.md, "symc-sign"); for (sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next) { PKT_secret_key *sk = sk_rover->sk;