From 6b5587891221213706b131e262f95072b5ff6a63 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Thu, 10 Apr 2003 09:56:47 +0000 Subject: [PATCH] =?UTF-8?q?*=20passphrase.c=20(read=5Fpassphrase=5Ffrom=5F?= =?UTF-8?q?fd):=20Do=20a=20dummy=20read=20if=20the=20agent=20is=20to=20be?= =?UTF-8?q?=20used.=20=20Noted=20by=20Ingo=20Kl=EF=BF=BDcker.=20(agent=5Fg?= =?UTF-8?q?et=5Fpassphrase):=20Inhibit=20caching=20when=20we=20have=20no?= =?UTF-8?q?=20fingerprint.=20=20This=20is=20required=20for=20key=20generat?= =?UTF-8?q?ion=20as=20well=20as=20for=20symmetric=20only=20encryption.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * passphrase .c (agent_get_passphrase): New arg CANCELED. (passphrase_to_dek): Ditto. Passed to above. Changed all callers to pass NULL. * seckey-cert.c (do_check): New arg CANCELED. (check_secret_key): Terminate loop when canceled. * keyedit.c (change_passphrase): Pass ERRTEXT untranslated to passphrase_to_dek and translate where appropriate. * seckey-cert.c (check_secret_key): Ditto. * keygen.c (ask_passphrase): Ditto. * passphrase.c (agent_get_passphrase): Translate the TRYAGAIN_TEXT. Switch the codeset to utf-8. --- g10/ChangeLog | 27 +++++++++ g10/decrypt.c | 20 +++---- g10/encode.c | 3 +- g10/gpgv.c | 6 +- g10/keydb.h | 2 +- g10/keyedit.c | 6 +- g10/keygen.c | 13 ++-- g10/mainproc.c | 4 +- g10/passphrase.c | 147 ++++++++++++++++++++++++++++++++++------------ g10/seckey-cert.c | 18 ++++-- g10/sign.c | 2 +- 11 files changed, 178 insertions(+), 70 deletions(-) diff --git a/g10/ChangeLog b/g10/ChangeLog index 95c066908..eb358b1a5 100644 --- a/g10/ChangeLog +++ b/g10/ChangeLog @@ -1,3 +1,30 @@ +2003-04-10 Werner Koch + + * passphrase.c (read_passphrase_from_fd): Do a dummy read if the + agent is to be used. Noted by Ingo Klöcker. + (agent_get_passphrase): Inhibit caching when we have no + fingerprint. This is required for key generation as well as for + symmetric only encryption. + + * passphrase .c (agent_get_passphrase): New arg CANCELED. + (passphrase_to_dek): Ditto. Passed to above. Changed all + callers to pass NULL. + * seckey-cert.c (do_check): New arg CANCELED. + (check_secret_key): Terminate loop when canceled. + + * keyedit.c (change_passphrase): Pass ERRTEXT untranslated to + passphrase_to_dek and translate where appropriate. + * seckey-cert.c (check_secret_key): Ditto. + * keygen.c (ask_passphrase): Ditto. + * passphrase.c (agent_get_passphrase): Translate the TRYAGAIN_TEXT. + Switch the codeset to utf-8. + +2003-04-09 Werner Koch + + * decrypt.c (decrypt_messages): Fixed error handling; the function + used to re-loop with same file after an error. Reported by Joseph + Walton. + 2003-04-08 David Shaw * main.h, g10.c (main), import.c (parse_import_options, diff --git a/g10/decrypt.c b/g10/decrypt.c index 297ee3418..bea16b728 100644 --- a/g10/decrypt.c +++ b/g10/decrypt.c @@ -1,5 +1,5 @@ /* decrypt.c - verify signed data - * Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc. + * Copyright (C) 1998,1999,2000,2001,2002,2003 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -99,12 +99,12 @@ decrypt_messages(int nfiles, char **files) print_file_status(STATUS_FILE_START, *files, 3); output = make_outfile_name(*files); if (!output) - continue; + goto next_file; fp = iobuf_open(*files); if (!fp) { log_error(_("can't open `%s'\n"), print_fname_stdin(*files)); - continue; + goto next_file; } if (!opt.no_armor) { @@ -122,17 +122,13 @@ decrypt_messages(int nfiles, char **files) p = get_last_passphrase(); set_next_passphrase(p); m_free (p); - files++; - m_free(output); + + next_file: + /* Note that we emit file_done even after an error. */ write_status( STATUS_FILE_DONE ); + m_free(output); + files++; } set_next_passphrase(NULL); } - - - - - - - diff --git a/g10/encode.c b/g10/encode.c index e705a6fad..d1b0cdb11 100644 --- a/g10/encode.c +++ b/g10/encode.c @@ -194,7 +194,8 @@ encode_simple( const char *filename, int mode, int compat ) s2k->mode = opt.rfc1991? 0:opt.s2k_mode; s2k->hash_algo = opt.s2k_digest_algo; cfx.dek = passphrase_to_dek( NULL, 0, - default_cipher_algo(), s2k, 2, NULL ); + default_cipher_algo(), s2k, 2, + NULL, NULL); if( !cfx.dek || !cfx.dek->keylen ) { rc = G10ERR_PASSPHRASE; m_free(cfx.dek); diff --git a/g10/gpgv.c b/g10/gpgv.c index eba6f8dd0..caa669171 100644 --- a/g10/gpgv.c +++ b/g10/gpgv.c @@ -314,9 +314,11 @@ check_secret_key( PKT_secret_key *sk, int n ) DEK * passphrase_to_dek( u32 *keyid, int pubkey_algo, int cipher_algo, STRING2KEY *s2k, int mode, - const char *tmp) + const char *tmp, int *canceled) { - return NULL; + if (canceled) + *canceled = 0; + return NULL; } /* Stubs to avoid linking to photoid.c */ diff --git a/g10/keydb.h b/g10/keydb.h index b506af65d..8395c118f 100644 --- a/g10/keydb.h +++ b/g10/keydb.h @@ -187,7 +187,7 @@ void read_passphrase_from_fd( int fd ); void passphrase_clear_cache ( u32 *keyid, int algo ); DEK *passphrase_to_dek( u32 *keyid, int pubkey_algo, int cipher_algo, STRING2KEY *s2k, int mode, - const char *tryagain_text); + const char *tryagain_text, int *canceled); void set_next_passphrase( const char *s ); char *get_last_passphrase(void); diff --git a/g10/keyedit.c b/g10/keyedit.c index 9186bd931..2b954e285 100644 --- a/g10/keyedit.c +++ b/g10/keyedit.c @@ -915,10 +915,10 @@ change_passphrase( KBNODE keyblock ) s2k->mode = opt.s2k_mode; s2k->hash_algo = opt.s2k_digest_algo; dek = passphrase_to_dek( NULL, 0, opt.s2k_cipher_algo, - s2k, 2, errtext); + s2k, 2, errtext, NULL); if( !dek ) { - errtext = _("passphrase not correctly repeated; try again"); - tty_printf ("%s.\n", errtext); + errtext = N_("passphrase not correctly repeated; try again"); + tty_printf ("%s.\n", _(errtext)); } else if( !dek->keylen ) { rc = 0; diff --git a/g10/keygen.c b/g10/keygen.c index 3e5bc4fcd..ef4b422dd 100644 --- a/g10/keygen.c +++ b/g10/keygen.c @@ -1479,10 +1479,11 @@ ask_passphrase( STRING2KEY **ret_s2k ) for(;;) { s2k->mode = opt.s2k_mode; s2k->hash_algo = opt.s2k_digest_algo; - dek = passphrase_to_dek( NULL, 0, opt.s2k_cipher_algo, s2k,2,errtext); + dek = passphrase_to_dek( NULL, 0, opt.s2k_cipher_algo, s2k,2, + errtext, NULL); if( !dek ) { - errtext = _("passphrase not correctly repeated; try again"); - tty_printf(_("%s.\n"), errtext); + errtext = N_("passphrase not correctly repeated; try again"); + tty_printf(_("%s.\n"), _(errtext)); } else if( !dek->keylen ) { m_free(dek); dek = NULL; @@ -1809,7 +1810,8 @@ proc_parameter_file( struct para_data_s *para, const char *fname, s2k->mode = opt.s2k_mode; s2k->hash_algo = opt.s2k_digest_algo; set_next_passphrase( r->u.value ); - dek = passphrase_to_dek( NULL, 0, opt.s2k_cipher_algo, s2k, 2, NULL ); + dek = passphrase_to_dek( NULL, 0, opt.s2k_cipher_algo, s2k, 2, + NULL, NULL); set_next_passphrase( NULL ); assert( dek ); memset( r->u.value, 0, strlen(r->u.value) ); @@ -2476,7 +2478,8 @@ generate_subkeypair( KBNODE pub_keyblock, KBNODE sec_keyblock ) s2k->mode = opt.s2k_mode; s2k->hash_algo = opt.s2k_digest_algo; set_next_passphrase( passphrase ); - dek = passphrase_to_dek( NULL, 0, opt.s2k_cipher_algo, s2k, 2, NULL ); + dek = passphrase_to_dek( NULL, 0, opt.s2k_cipher_algo, s2k, 2, + NULL, NULL ); } rc = do_create( algo, nbits, pub_keyblock, sec_keyblock, diff --git a/g10/mainproc.c b/g10/mainproc.c index 97af59591..1911d0076 100644 --- a/g10/mainproc.c +++ b/g10/mainproc.c @@ -292,7 +292,7 @@ proc_symkey_enc( CTX c, PACKET *pkt ) c->last_was_session_key = 2; if ( opt.list_only ) goto leave; - c->dek = passphrase_to_dek( NULL, 0, algo, &enc->s2k, 0, NULL ); + c->dek = passphrase_to_dek( NULL, 0, algo, &enc->s2k, 0, NULL, NULL ); if (c->dek) c->dek->algo_info_printed = 1; if ( c->dek && enc->seskeylen ) @@ -486,7 +486,7 @@ proc_encrypted( CTX c, PACKET *pkt ) log_info (_("assuming %s encrypted data\n"), "IDEA"); } - c->dek = passphrase_to_dek ( NULL, 0, algo, s2k, 0, NULL ); + c->dek = passphrase_to_dek ( NULL, 0, algo, s2k, 0, NULL, NULL ); if (c->dek) c->dek->algo_info_printed = 1; } diff --git a/g10/passphrase.c b/g10/passphrase.c index 5345fb9b7..769276221 100644 --- a/g10/passphrase.c +++ b/g10/passphrase.c @@ -1,5 +1,5 @@ /* passphrase.c - Get a passphrase - * Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc. + * Copyright (C) 1998,1999,2000,2001,2002,2003 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -36,6 +36,9 @@ #ifdef HAVE_LOCALE_H #include #endif +#ifdef HAVE_LANGINFO_CODESET +#include +#endif #include "util.h" #include "memory.h" @@ -144,33 +147,44 @@ get_last_passphrase() void read_passphrase_from_fd( int fd ) { - int i, len; - char *pw; + int i, len; + char *pw; + + if ( opt.use_agent ) + { /* Not used but we have to do a dummy read, so that it won't end + up at the begin of the message if the quite usual trick to + prepend the passphtrase to the message is used. */ + char buf[1]; - if ( opt.use_agent ) - return; /* not used here */ - - if( !opt.batch ) - tty_printf("Reading passphrase from file descriptor %d ...", fd ); - for( pw = NULL, i = len = 100; ; i++ ) { - if( i >= len-1 ) { - char *pw2 = pw; - len += 100; - pw = m_alloc_secure( len ); - if( pw2 ) - memcpy(pw, pw2, i ); - else - i=0; - } - if( read( fd, pw+i, 1) != 1 || pw[i] == '\n' ) - break; + while (!(read (fd, buf, 1) != 1 || *buf == '\n' )) + ; + *buf = 0; + return; } - pw[i] = 0; - if( !opt.batch ) - tty_printf("\b\b\b \n" ); - m_free( fd_passwd ); - fd_passwd = pw; + if (!opt.batch ) + tty_printf("Reading passphrase from file descriptor %d ...", fd ); + for (pw = NULL, i = len = 100; ; i++ ) + { + if (i >= len-1 ) + { + char *pw2 = pw; + len += 100; + pw = m_alloc_secure( len ); + if( pw2 ) + memcpy(pw, pw2, i ); + else + i=0; + } + if (read( fd, pw+i, 1) != 1 || pw[i] == '\n' ) + break; + } + pw[i] = 0; + if (!opt.batch) + tty_printf("\b\b\b \n" ); + + m_free( fd_passwd ); + fd_passwd = pw; } static int @@ -590,15 +604,20 @@ agent_close ( int fd ) * Mode 0: Allow cached passphrase * 1: No cached passphrase FIXME: Not really implemented * 2: Ditto, but change the text to "repeat entry" + * + * 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. */ static char * -agent_get_passphrase ( u32 *keyid, int mode, const char *tryagain_text ) +agent_get_passphrase ( u32 *keyid, int mode, const char *tryagain_text, + int *canceled) { #if defined(__riscos__) return NULL; #else size_t n; - char *atext; + char *atext = NULL; char buf[50]; int fd = -1; int nread; @@ -606,7 +625,12 @@ agent_get_passphrase ( u32 *keyid, int mode, const char *tryagain_text ) char *pw = NULL; PKT_public_key *pk = m_alloc_clear( sizeof *pk ); byte fpr[MAX_FINGERPRINT_LEN]; + int have_fpr = 0; int prot; + char *orig_codeset = NULL; + + if (canceled) + *canceled = 0; #if MAX_FINGERPRINT_LEN < 20 #error agent needs a 20 byte fingerprint @@ -619,6 +643,24 @@ agent_get_passphrase ( u32 *keyid, int mode, const char *tryagain_text ) pk = NULL; /* oops: no key for some reason */ } +#ifdef ENABLE_NLS + /* The Assuan agent protol requires us to trasnmit utf-8 strings */ + orig_codeset = bind_textdomain_codeset (PACKAGE, NULL); +#ifdef HAVE_LANGINFO_CODESET + if (!orig_codeset) + orig_codeset = nl_langinfo (CODESET); +#endif + if (orig_codeset) + { /* We only switch when we are able to restore the codeset later. */ + orig_codeset = m_strdup (orig_codeset); + if (!bind_textdomain_codeset (PACKAGE, "utf-8")) + orig_codeset = NULL; + } +#endif + + if ( (fd = agent_open (&prot)) == -1 ) + goto failure; + if ( !mode && pk && keyid ) { char *uid; @@ -658,6 +700,7 @@ agent_get_passphrase ( u32 *keyid, int mode, const char *tryagain_text ) { size_t dummy; fingerprint_from_pk( pk, fpr, &dummy ); + have_fpr = 1; } } @@ -666,9 +709,6 @@ agent_get_passphrase ( u32 *keyid, int mode, const char *tryagain_text ) else atext = m_strdup ( _("Enter passphrase\n") ); - if ( (fd = agent_open (&prot)) == -1 ) - goto failure; - if (!prot) { /* old style protocol */ n = 4 + 20 + strlen (atext); @@ -724,10 +764,19 @@ agent_get_passphrase ( u32 *keyid, int mode, const char *tryagain_text ) pw[pwlen] = 0; /* make a C String */ agent_close (fd); free_public_key( pk ); +#ifdef ENABLE_NLS + if (orig_codeset) + bind_textdomain_codeset (PACKAGE, orig_codeset); +#endif + m_free (orig_codeset); return pw; } else if ( reply == GPGA_PROT_CANCELED ) - log_info ( _("cancelled by user\n") ); + { + log_info ( _("cancelled by user\n") ); + if (canceled) + *canceled = 1; + } else log_error ( _("problem with the agent: agent returns 0x%lx\n"), (ulong)reply ); @@ -740,6 +789,8 @@ agent_get_passphrase ( u32 *keyid, int mode, const char *tryagain_text ) if (!tryagain_text) tryagain_text = "X"; + else + tryagain_text = _(tryagain_text); /* We allocate 2 time the needed space for atext so that there is nenough space for escaping */ @@ -747,7 +798,7 @@ agent_get_passphrase ( u32 *keyid, int mode, const char *tryagain_text ) + 3*strlen (tryagain_text) + 3*strlen (atext) + 2); strcpy (line, "GET_PASSPHRASE "); p = line+15; - if (!mode) + if (!mode && have_fpr) { for (i=0; i < 20; i++, p +=2 ) sprintf (p, "%02X", fpr[i]); @@ -805,11 +856,20 @@ agent_get_passphrase ( u32 *keyid, int mode, const char *tryagain_text ) pw[pwlen] = 0; /* make a C String */ agent_close (fd); free_public_key( pk ); +#ifdef ENABLE_NLS + if (orig_codeset) + bind_textdomain_codeset (PACKAGE, orig_codeset); +#endif + m_free (orig_codeset); return pw; } else if (nread > 7 && !memcmp (pw, "ERR 111", 7) && (pw[7] == ' ' || pw[7] == '\n') ) - log_info (_("cancelled by user\n") ); + { + log_info (_("cancelled by user\n") ); + if (canceled) + *canceled = 1; + } else { log_error (_("problem with the agent - disabling agent use\n")); @@ -819,6 +879,10 @@ agent_get_passphrase ( u32 *keyid, int mode, const char *tryagain_text ) failure: +#ifdef ENABLE_NLS + if (orig_codeset) + bind_textdomain_codeset (PACKAGE, orig_codeset); +#endif m_free (atext); if ( fd != -1 ) agent_close (fd); @@ -945,17 +1009,25 @@ passphrase_clear_cache ( u32 *keyid, int algo ) * (only for mode 2) * a dek->keylen of 0 means: no passphrase entered. * (only for mode 2) - * pubkey_algo is only informational. + * + * pubkey_algo is only informational. Note that TRYAGAIN_TEXT must + * not be translated as this is done within this function (required to + * switch to utf-8 when the agent is in use). If CANCELED is not + * NULL, it is set to 1 if the user choosed to cancel the operation, + * otherwise it will be set to 0. */ DEK * passphrase_to_dek( u32 *keyid, int pubkey_algo, int cipher_algo, STRING2KEY *s2k, int mode, - const char *tryagain_text) + const char *tryagain_text, int *canceled) { char *pw = NULL; DEK *dek; STRING2KEY help_s2k; + if (canceled) + *canceled = 0; + if( !s2k ) { /* This is used for the old rfc1991 mode * Note: This must match the code in encode.c with opt.rfc1991 set */ @@ -1030,7 +1102,8 @@ passphrase_to_dek( u32 *keyid, int pubkey_algo, next_pw = NULL; } else if ( opt.use_agent ) { - pw = agent_get_passphrase ( keyid, mode == 2? 1: 0, tryagain_text ); + pw = agent_get_passphrase ( keyid, mode == 2? 1: 0, + tryagain_text, canceled ); if (!pw) { if (!opt.use_agent) @@ -1038,7 +1111,7 @@ passphrase_to_dek( u32 *keyid, int pubkey_algo, pw = m_strdup (""); } if( *pw && mode == 2 ) { - char *pw2 = agent_get_passphrase ( keyid, 2, NULL ); + char *pw2 = agent_get_passphrase ( keyid, 2, NULL, canceled ); if (!pw2) { if (!opt.use_agent) diff --git a/g10/seckey-cert.c b/g10/seckey-cert.c index 4984c888b..32c54498d 100644 --- a/g10/seckey-cert.c +++ b/g10/seckey-cert.c @@ -36,7 +36,8 @@ static int -do_check( PKT_secret_key *sk, const char *tryagain_text, int mode ) +do_check( PKT_secret_key *sk, const char *tryagain_text, int mode, + int *canceled ) { byte *buffer; u16 csum=0; @@ -69,7 +70,11 @@ do_check( PKT_secret_key *sk, const char *tryagain_text, int mode ) keyid[3] = sk->main_keyid[1]; } dek = passphrase_to_dek( keyid, sk->pubkey_algo, sk->protect.algo, - &sk->protect.s2k, mode, tryagain_text ); + &sk->protect.s2k, mode, + tryagain_text, canceled ); + if (!dek && canceled && *canceled) + return G10ERR_GENERAL; + cipher_hd = cipher_open( sk->protect.algo, CIPHER_MODE_AUTO_CFB, 1); cipher_setkey( cipher_hd, dek->key, dek->keylen ); @@ -229,12 +234,13 @@ check_secret_key( PKT_secret_key *sk, int n ) n = (opt.batch && !opt.use_agent)? 1 : 3; /* use the default value */ for(i=0; i < n && rc == G10ERR_BAD_PASS; i++ ) { + int canceled = 0; const char *tryagain = NULL; if (i) { - tryagain = _("Invalid passphrase; please try again"); - log_info (_("%s ...\n"), tryagain); + tryagain = N_("Invalid passphrase; please try again"); + log_info (_("%s ...\n"), _(tryagain)); } - rc = do_check( sk, tryagain, mode ); + rc = do_check( sk, tryagain, mode, &canceled ); if( rc == G10ERR_BAD_PASS && is_status_enabled() ) { u32 kid[2]; char buf[50]; @@ -243,7 +249,7 @@ check_secret_key( PKT_secret_key *sk, int n ) sprintf(buf, "%08lX%08lX", (ulong)kid[0], (ulong)kid[1]); write_status_text( STATUS_BAD_PASSPHRASE, buf ); } - if( have_static_passphrase() ) + if( have_static_passphrase() || canceled) break; } diff --git a/g10/sign.c b/g10/sign.c index cbc93af2d..9dad9b300 100644 --- a/g10/sign.c +++ b/g10/sign.c @@ -1059,7 +1059,7 @@ sign_symencrypt_file (const char *fname, STRLIST locusr) if (!opt.quiet || !opt.batch) log_info (_("%s encryption will be used\n"), cipher_algo_to_string(algo) ); - cfx.dek = passphrase_to_dek( NULL, 0, algo, s2k, 2, NULL ); + cfx.dek = passphrase_to_dek( NULL, 0, algo, s2k, 2, NULL, NULL); if (!cfx.dek || !cfx.dek->keylen) { rc = G10ERR_PASSPHRASE;