diff --git a/ChangeLog b/ChangeLog index 0829b3435..5303f3544 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2006-11-30 Werner Koch + + * configure.ac: Save original LIBS when testing for dlopen. + 2006-11-28 Werner Koch Released 2.0.1. diff --git a/NEWS b/NEWS index 786cb8b39..2ce9b93b4 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,14 @@ +Noteworthy changes in version 2.0.2 (unreleased) +------------------------------------------------ + + * Fixed a serious and exploitable bug in processing encrypted + packages. [CVE-2006-6235]. + + * Added --passphrase-repeat to set the number of times GPG will + prompt for a new passphrase to be repeated. This is useful to help + memorize a new passphrase. The default is 1 repetition. + + Noteworthy changes in version 2.0.1 (2006-11-28) ------------------------------------------------ @@ -8,7 +19,7 @@ Noteworthy changes in version 2.0.1 (2006-11-28) * Fixed build problems on some some platforms and crashes on amd64. - * Fixed a buffer overflow in gpg2. [bug#728] + * Fixed a buffer overflow in gpg2. [bug#728,CVE-2006-6169] Noteworthy changes in version 2.0.0 (2006-11-11) diff --git a/README.SVN b/README.SVN index af4f49d7d..c6422829f 100644 --- a/README.SVN +++ b/README.SVN @@ -3,7 +3,9 @@ If you are building from Subversion, run the script ./autogen.sh first, to make sure that you have all the necessary maintainer tools -are installed and to build the actual configuration files. Then run +are installed and to build the actual configuration files. If you +have just updated from SVN, you should add the option "--force" to +autogen.sh so that meta data from SVN is noticed. Then run ./configure --enable-maintainer-mode @@ -40,12 +42,10 @@ knowledge about the actual tools used by autgen.sh. Please don't use autopoint, libtoolize or autoreconf unless you are the current maintainer and want to update the standard configuration -files. All those files should be in the CVS and only updated manually +files. All those files should be in the SVN and only updated manually if the maintainer decides that newer versions are required. The maintainer should also make sure that the required version of automake et al. are properly indicated at the top of configure.ac and take care to copy the files and not merely use symlinks. - - diff --git a/configure.ac b/configure.ac index 81758b1b5..bfe4fe81f 100644 --- a/configure.ac +++ b/configure.ac @@ -26,8 +26,8 @@ min_automake_version="1.9.3" # Remember to change the version number immediately *after* a release. # Set my_issvn to "yes" for non-released code. Remember to run an # "svn up" and "autogen.sh" right before creating a distribution. -m4_define([my_version], [2.0.1]) -m4_define([my_issvn], [no]) +m4_define([my_version], [2.0.2]) +m4_define([my_issvn], [yes]) m4_define([svn_revision], m4_esyscmd([echo -n $( (svn info 2>/dev/null \ @@ -619,10 +619,12 @@ AC_CHECK_FUNCS(usb_create_match) # # Check wether it is necessary to link against libdl. # +gnupg_dlopen_save_libs="$LIBS" LIBS="" AC_SEARCH_LIBS(dlopen, c dl,,,) DL_LIBS=$LIBS AC_SUBST(DL_LIBS) +LIBS="$gnupg_dlopen_save_libs" # # Checks for symcryptrun: diff --git a/doc/ChangeLog b/doc/ChangeLog index bbaa6f4ec..aac2a912a 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -1,3 +1,8 @@ +2006-12-04 Werner Koch + + * gpgv.texi: New. + * tools.texi: Include new file. + 2006-12-02 David Shaw * gpg.texi (GPG Esoteric Options): Document --passphrase-repeat. diff --git a/doc/Makefile.am b/doc/Makefile.am index ab8543b70..c93df6fad 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -28,7 +28,7 @@ EXTRA_DIST = DETAILS HACKING TRANSLATE OpenPGP KEYSERVER samplekeys.asc \ gnupg-card-architecture.pdf \ faq.raw FAQ faq.html gnupg7.texi \ opt-homedir.texi see-also-note.texi specify-user-id.texi \ - texi.css $(examples) + gpgv.texi texi.css $(examples) BUILT_SOURCES = gnupg-card-architecture.eps gnupg-card-architecture.png \ gnupg-card-architecture.pdf FAQ faq.html diff --git a/doc/gpg.texi b/doc/gpg.texi index 524e0cc69..a8e213c95 100644 --- a/doc/gpg.texi +++ b/doc/gpg.texi @@ -1070,6 +1070,9 @@ the filename does not contain a slash, it is assumed to be in the GnuPG home directory (@file{~/.gnupg} if @option{--homedir} or $GNUPGHOME is not used). +@ifset gpgone +@anchor{option --homedir} +@end ifset @include opt-homedir.texi @@ -1130,6 +1133,9 @@ encoded in the character set as specified by @option{--display-charset}. These options affect all following arguments. Both options may be used multiple times. +@ifset gpgone +@anchor{option --options} +@end ifset @item --options @code{file} Read options from @code{file} and do not try to read them from the default options file in the homedir (see @option{--homedir}). This @@ -2497,8 +2503,11 @@ name may be changed on the command line (@pxref{option @c man:.RE Note that on larger installations, it is useful to put predefined files into the directory @file{/etc/skel/.gnupg/} so that newly created users -start up with a working configuration. For existing users the a small +start up with a working configuration. +@ifclear gpgone +For existing users the a small helper script is provided to create these files (@pxref{addgnupghome}). +@end ifclear For internal purposes @command{@gpgname} creates and maintaines a few other files; They all live in in the current home directory (@pxref{option @@ -2678,7 +2687,9 @@ as locked memory is allocated. @mansect see also @ifset isman @command{gpgv}(1), +@ifclear gpgone @command{gpgsm}(1), @command{gpg-agent}(1) +@end ifclear @end ifset @include see-also-note.texi diff --git a/doc/tools.texi b/doc/tools.texi index dec548905..914a1213f 100644 --- a/doc/tools.texi +++ b/doc/tools.texi @@ -92,130 +92,7 @@ Display a brief help page and exit @c @c GPGV @c -@manpage gpgv2.1 -@node gpgv -@section Verify OpenPGP signatures -@ifset manverb -.B gpgv -\- Verify OpenPGP signatures -@end ifset - -@mansect synopsis -@ifset manverb -.B gpgv2 -.RI [ options ] -.I signed_files -@end ifset - -@mansect description -@code{gpgv2} is an OpenPGP signature verification tool. - -This program is actually a stripped down version of @code{gpg} which is -only able to check signatures. It is somewhat smaller than the fully blown -@code{gpg} and uses a different (and simpler) way to check that -the public keys used to make the signature are valid. There are -no configuration files and only a few options are implemented. - -@code{gpgv2} assumes that all keys in the keyring are trustworthy. -By default it uses a keyring named @file{trustedkeys.gpg} which is -assumed to be in the home directory as defined by GnuPG or set by an -option or an environment variable. An option may be used to specify -another keyring or even multiple keyrings. - -@noindent -@mansect options -@code{gpgv2} recognizes these options: - -@table @gnupgtabopt - -@item --verbose -@itemx -v -@opindex verbose -Gives more information during processing. If used -twice, the input data is listed in detail. - -@item --quiet -@itemx -q -@opindex quiet -Try to be as quiet as possible. - -@item --keyring @var{file} -@opindex keyring -Add @var{file} to the list of keyrings. -If @var{file} begins with a tilde and a slash, these -are replaced by the HOME directory. If the filename -does not contain a slash, it is assumed to be in the -home-directory ("~/.gnupg" if --homedir is not used). - -@item --status-fd @var{n} -@opindex status-fd -Write special status strings to the file descriptor @var{n}. See the -file DETAILS in the documentation for a listing of them. - -@item --logger-fd @code{n} -@opindex logger-fd -Write log output to file descriptor @code{n} and not to stderr. - -@item --ignore-time-conflict -@opindex ignore-time-conflict -GnuPG normally checks that the timestamps associated with keys and -signatures have plausible values. However, sometimes a signature seems to -be older than the key due to clock problems. This option turns these -checks into warnings. - -@include opt-homedir.texi - -@end table - -@mansect return value - -The program returns 0 if everything was fine, 1 if at least -one signature was bad, and other error codes for fatal errors. - -@mansect examples -@subsection Examples - -@table @asis - -@item gpgv2 @code{pgpfile} -@itemx gpgv2 @code{sigfile} -Verify the signature of the file. The second form -is used for detached signatures, where @code{sigfile} is the detached -signature (either ASCII armored or binary) and are the signed -data; if this is not given the name of the file holding the signed data is -constructed by cutting off the extension (".asc", ".sig" or ".sign") from -@code{sigfile}. - -@end table - -@mansect environment -@subsection Environment - -@table @asis - -@item HOME -Used to locate the default home directory. - -@item GNUPGHOME -If set directory used instead of "~/.gnupg". - -@end table - -@mansect files -@subsection FILES - -@table @asis - -@item ~/.gnupg/trustedkeys.gpg -The default keyring with the allowed keys - -@end table - -@mansect see also -@command{gpg2}(1) -@include see-also-note.texi - - +@include gpgv.texi @c diff --git a/g10/ChangeLog b/g10/ChangeLog index a94d005f8..ed5b39947 100644 --- a/g10/ChangeLog +++ b/g10/ChangeLog @@ -1,3 +1,58 @@ +2006-12-05 Werner Koch + + * passphrase.c (passphrase_to_dek): Handle a Cancel request + correctly. [Bug#737] + * mainproc.c (proc_symkey_enc): Removed workaround for bogus cancel + processing. + * encode.c (encode_simple): Distinguish error message between + cancel and invalid passphrase. + (setup_symkey): Ditto. + * sign.c (sign_symencrypt_file): Ditto + * keyedit.c (change_passphrase): Allow cancellation. + * keygen.c (do_ask_passphrase): New arg R_CANCELED. + (generate_keypair): Handle a passphrase cancellation. + (generate_raw_key): Ditto. + (generate_subkeypair): Ditto. + +2006-12-04 Werner Koch + + * filter.h (armor_filter_context_t): New element REFCOUNT. + * armor.c (armor_filter): Made static. + (push_armor_filter, release_armor_context, new_armor_context): New. + (armor_filter): Release the context. + * gpg.c (main): Use new armor context functions and + push_armor_filter. + * export.c (do_export): Ditto. + * encode.c (encode_simple, encode_crypt): Ditto. + * decrypt.c (decrypt_message, decrypt_messages): Ditto. + * dearmor.c (dearmor_file, enarmor_file): Ditto. + * verify.c (verify_signatures, verify_one_file): Ditto. + * sign.c (sign_file, clearsign_file, sign_symencrypt_file): Ditto. + * revoke.c (gen_desig_revoke, gen_revoke): Ditto. + * keyserver.c (keyserver_spawn): Ditto. + * keygen.c (output_control_s): Turn AFX fields into pointers. + (read_parameter_file): Allocate and release AFX fields. + (do_generate_keypair): Use push_armor_filter. + * import.c (import): Replace iobuf_push_filter2 hack by the new + armor context stuff. + +2006-12-03 Werner Koch + + * filter.h: New element REFCOUNT. + (handle_progress): Remove prototype. + * progress.c (new_progress_context, release_progress_context): New. + (progress_filter): Use new function to release context. Made static. + (handle_progress): Bumb reference counter. No more check for + enabled progress as this is handled by new_progress_context. + * verify.c (verify_signatures, verify_one_file): Replace stack + based progress context by a heap based one. + * sign.c (sign_file, clearsign_file, sign_symencrypt_file): Ditto. + * plaintext.c (ask_for_detached_datafile, hash_datafiles): Ditto. + * encode.c (encode_simple, encode_crypt): Ditto. + * decrypt.c (decrypt_message, decrypt_messages): Ditto. + + * keyedit.c (menu_clean): Made strings translatable. + 2006-12-03 David Shaw * keyedit.c (menu_clean): Show "already minimized" rather than @@ -11,6 +66,11 @@ re-prompt for a passphrase to ensure the user has typed it correctly. Defaults to 1. +2006-12-02 Werner Koch + + * encr-data.c: Allocate DFX context on the heap and not on the + stack. Changes at several places. Fixes CVE-2006-6235. + 2006-11-27 Werner Koch * openfile.c (ask_outfile_name): Fixed buffer overflow occurring @@ -4166,7 +4226,7 @@ * compress.c (release_context): New. (handle_compressed): Allocate the context and setup a closure to release the context. This is required because there is no - guarabntee that the filter gets popped from the chain at the end + guarantee that the filter gets popped from the chain at the end of the function. Problem noted by Timo and probably also the cause for a couple of other reports. (compress_filter): Use the release function if set. @@ -5983,7 +6043,7 @@ (unarmor_pump): New. * pipemode.c (pipemode_filter): Use the unarmor_pump to handle armored or non-armored detached signatures. We can't use the - regular armor_filter becuase this does only chack for armored + regular armor_filter because this does only check for armored signatures the very first time. In pipemode we may have a mix of armored and binary detached signatures. * mainproc.c (proc_tree): Do not print the "old style" notice when diff --git a/g10/armor.c b/g10/armor.c index e9efa779d..8f22f316c 100644 --- a/g10/armor.c +++ b/g10/armor.c @@ -114,6 +114,54 @@ static char *tail_strings[] = { }; +static int armor_filter ( void *opaque, int control, + iobuf_t chain, byte *buf, size_t *ret_len); + + + + +/* Create a new context for armor filters. */ +armor_filter_context_t * +new_armor_context (void) +{ + armor_filter_context_t *afx; + + afx = xcalloc (1, sizeof *afx); + afx->refcount = 1; + + return afx; +} + +/* Release an armor filter context. Passing NULL is explicitly + allowed and a no-op. */ +void +release_armor_context (armor_filter_context_t *afx) +{ + if (!afx) + return; + assert (afx->refcount); + if ( --afx->refcount ) + return; + xfree (afx); +} + +/* Push the armor filter onto the iobuf stream IOBUF. */ +int +push_armor_filter (armor_filter_context_t *afx, iobuf_t iobuf) +{ + int rc; + + afx->refcount++; + rc = iobuf_push_filter (iobuf, armor_filter, afx); + if (rc) + afx->refcount--; + return rc; +} + + + + + static void initialize(void) { @@ -862,7 +910,7 @@ radix64_read( armor_filter_context_t *afx, IOBUF a, size_t *retn, /**************** * This filter is used to handle the armor stuff */ -int +static int armor_filter( void *opaque, int control, IOBUF a, byte *buf, size_t *ret_len) { @@ -1168,6 +1216,7 @@ armor_filter( void *opaque, int control, "probably a buggy MTA has been used\n") ); xfree( afx->buffer ); afx->buffer = NULL; + release_armor_context (afx); } else if( control == IOBUFCTRL_DESC ) *(char**)buf = "armor_filter"; diff --git a/g10/cipher.c b/g10/cipher.c index 08395575f..802c01905 100644 --- a/g10/cipher.c +++ b/g10/cipher.c @@ -44,7 +44,7 @@ static void write_header( cipher_filter_context_t *cfx, IOBUF a ) { - gcry_error_t err; + gcry_error_t err; PACKET pkt; PKT_encrypted ed; byte temp[18]; diff --git a/g10/dearmor.c b/g10/dearmor.c index ae89e8e58..23c3f7419 100644 --- a/g10/dearmor.c +++ b/g10/dearmor.c @@ -42,12 +42,12 @@ int dearmor_file( const char *fname ) { - armor_filter_context_t afx; + armor_filter_context_t *afx; IOBUF inp = NULL, out = NULL; int rc = 0; int c; - memset( &afx, 0, sizeof afx); + afx = new_armor_context (); /* prepare iobufs */ inp = iobuf_open(fname); @@ -64,23 +64,21 @@ dearmor_file( const char *fname ) goto leave; } - iobuf_push_filter( inp, armor_filter, &afx ); + push_armor_filter ( afx, inp ); if( (rc = open_outfile( fname, 0, &out )) ) goto leave; - - while( (c = iobuf_get(inp)) != -1 ) iobuf_put( out, c ); - leave: if( rc ) iobuf_cancel(out); else iobuf_close(out); iobuf_close(inp); + release_armor_context (afx); return rc; } @@ -91,12 +89,12 @@ dearmor_file( const char *fname ) int enarmor_file( const char *fname ) { - armor_filter_context_t afx; + armor_filter_context_t *afx; IOBUF inp = NULL, out = NULL; int rc = 0; int c; - memset( &afx, 0, sizeof afx); + afx = new_armor_context (); /* prepare iobufs */ inp = iobuf_open(fname); @@ -117,9 +115,9 @@ enarmor_file( const char *fname ) if( (rc = open_outfile( fname, 1, &out )) ) goto leave; - afx.what = 4; - afx.hdrlines = "Comment: Use \"gpg --dearmor\" for unpacking\n"; - iobuf_push_filter( out, armor_filter, &afx ); + afx->what = 4; + afx->hdrlines = "Comment: Use \"gpg --dearmor\" for unpacking\n"; + push_armor_filter ( afx, out ); while( (c = iobuf_get(inp)) != -1 ) iobuf_put( out, c ); @@ -131,6 +129,7 @@ enarmor_file( const char *fname ) else iobuf_close(out); iobuf_close(inp); + release_armor_context (afx); return rc; } diff --git a/g10/decrypt.c b/g10/decrypt.c index 39071427a..4af7c4a0d 100644 --- a/g10/decrypt.c +++ b/g10/decrypt.c @@ -52,10 +52,12 @@ int decrypt_message( const char *filename ) { IOBUF fp; - armor_filter_context_t afx; - progress_filter_context_t pfx; + armor_filter_context_t *afx = NULL; + progress_filter_context_t *pfx; int rc; - int no_out=0; + int no_out = 0; + + pfx = new_progress_context (); /* Open the message file. */ fp = iobuf_open(filename); @@ -69,15 +71,16 @@ decrypt_message( const char *filename ) rc = gpg_error_from_syserror (); log_error (_("can't open `%s': %s\n"), print_fname_stdin(filename), gpg_strerror (rc)); + release_progress_context (pfx); return rc; } - handle_progress (&pfx, fp, filename); + handle_progress (pfx, fp, filename); if( !opt.no_armor ) { if( use_armor_filter( fp ) ) { - memset( &afx, 0, sizeof afx); - iobuf_push_filter( fp, armor_filter, &afx ); + afx = new_armor_context (); + push_armor_filter ( afx, fp ); } } @@ -89,6 +92,8 @@ decrypt_message( const char *filename ) if( no_out ) opt.outfile = NULL; iobuf_close(fp); + release_armor_context (afx); + release_progress_context (pfx); return rc; } @@ -96,8 +101,8 @@ void decrypt_messages(int nfiles, char *files[]) { IOBUF fp; - armor_filter_context_t afx; - progress_filter_context_t pfx; + armor_filter_context_t *afx = NULL; + progress_filter_context_t *pfx; char *p, *output = NULL; int rc=0,use_stdin=0; unsigned int lno=0; @@ -106,9 +111,10 @@ decrypt_messages(int nfiles, char *files[]) { log_error(_("--output doesn't work for this command\n")); return; - } + pfx = new_progress_context (); + if(!nfiles) use_stdin=1; @@ -163,14 +169,14 @@ decrypt_messages(int nfiles, char *files[]) goto next_file; } - handle_progress (&pfx, fp, filename); + handle_progress (pfx, fp, filename); if (!opt.no_armor) { if (use_armor_filter(fp)) { - memset(&afx, 0, sizeof afx); - iobuf_push_filter(fp, armor_filter, &afx); + afx = new_armor_context (); + push_armor_filter ( afx, fp ); } } rc = proc_packets(NULL, fp); @@ -189,4 +195,6 @@ decrypt_messages(int nfiles, char *files[]) } set_next_passphrase(NULL); + release_armor_context (afx); + release_progress_context (pfx); } diff --git a/g10/encode.c b/g10/encode.c index f55f4732c..41bfafe3c 100644 --- a/g10/encode.c +++ b/g10/encode.c @@ -169,14 +169,14 @@ encode_simple( const char *filename, int mode, int use_seskey ) int seskeylen = 0; u32 filesize; cipher_filter_context_t cfx; - armor_filter_context_t afx; + armor_filter_context_t *afx = NULL; compress_filter_context_t zfx; text_filter_context_t tfx; - progress_filter_context_t pfx; + progress_filter_context_t *pfx; int do_compress = !RFC1991 && default_compress_algo(); + pfx = new_progress_context (); memset( &cfx, 0, sizeof cfx); - memset( &afx, 0, sizeof afx); memset( &zfx, 0, sizeof zfx); memset( &tfx, 0, sizeof tfx); init_packet(&pkt); @@ -195,10 +195,11 @@ encode_simple( const char *filename, int mode, int use_seskey ) rc = gpg_error_from_syserror (); log_error(_("can't open `%s': %s\n"), filename? filename: "[stdin]", strerror(errno) ); + release_progress_context (pfx); return rc; } - handle_progress (&pfx, inp, filename); + handle_progress (pfx, inp, filename); if( opt.textmode ) iobuf_push_filter( inp, text_filter, &tfx ); @@ -211,18 +212,21 @@ encode_simple( const char *filename, int mode, int use_seskey ) cfx.dek = NULL; if( mode ) { + int canceled; + s2k = xmalloc_clear( sizeof *s2k ); s2k->mode = RFC1991? 0:opt.s2k_mode; s2k->hash_algo=S2K_DIGEST_ALGO; cfx.dek = passphrase_to_dek( NULL, 0, default_cipher_algo(), s2k, 2, - NULL, NULL); + NULL, &canceled); if( !cfx.dek || !cfx.dek->keylen ) { - rc = gpg_error (GPG_ERR_INV_PASSPHRASE); + rc = gpg_error (canceled? GPG_ERR_CANCELED:GPG_ERR_INV_PASSPHRASE); xfree(cfx.dek); xfree(s2k); iobuf_close(inp); log_error(_("error creating passphrase: %s\n"), gpg_strerror (rc)); + release_progress_context (pfx); return rc; } if (use_seskey && s2k->mode != 1 && s2k->mode != 3) { @@ -259,11 +263,15 @@ encode_simple( const char *filename, int mode, int use_seskey ) iobuf_cancel(inp); xfree(cfx.dek); xfree(s2k); + release_progress_context (pfx); return rc; } - if( opt.armor ) - iobuf_push_filter( out, armor_filter, &afx ); + if ( opt.armor ) + { + afx = new_armor_context (); + push_armor_filter (afx, out); + } if( s2k && !RFC1991 ) { PKT_symkey_enc *enc = xmalloc_clear( sizeof *enc + seskeylen + 1 ); @@ -376,23 +384,27 @@ encode_simple( const char *filename, int mode, int use_seskey ) free_packet(&pkt); xfree(cfx.dek); xfree(s2k); + release_armor_context (afx); + release_progress_context (pfx); return rc; } int setup_symkey(STRING2KEY **symkey_s2k,DEK **symkey_dek) { + int canceled; + *symkey_s2k=xmalloc_clear(sizeof(STRING2KEY)); (*symkey_s2k)->mode = opt.s2k_mode; (*symkey_s2k)->hash_algo = S2K_DIGEST_ALGO; *symkey_dek=passphrase_to_dek(NULL,0,opt.s2k_cipher_algo, - *symkey_s2k,2,NULL,NULL); + *symkey_s2k,2,NULL, &canceled); if(!*symkey_dek || !(*symkey_dek)->keylen) { xfree(*symkey_dek); xfree(*symkey_s2k); - return gpg_error (GPG_ERR_BAD_PASSPHRASE); + return gpg_error (canceled?GPG_ERR_CANCELED:GPG_ERR_BAD_PASSPHRASE); } return 0; @@ -441,25 +453,31 @@ encode_crypt( const char *filename, strlist_t remusr, int use_symkey ) int rc = 0, rc2 = 0; u32 filesize; cipher_filter_context_t cfx; - armor_filter_context_t afx; + armor_filter_context_t *afx = NULL; compress_filter_context_t zfx; text_filter_context_t tfx; - progress_filter_context_t pfx; + progress_filter_context_t *pfx; PK_LIST pk_list,work_list; int do_compress = opt.compress_algo && !RFC1991; + pfx = new_progress_context (); memset( &cfx, 0, sizeof cfx); - memset( &afx, 0, sizeof afx); memset( &zfx, 0, sizeof zfx); memset( &tfx, 0, sizeof tfx); init_packet(&pkt); if(use_symkey && (rc=setup_symkey(&symkey_s2k,&symkey_dek))) - return rc; + { + release_progress_context (pfx); + return rc; + } if( (rc=build_pk_list( remusr, &pk_list, PUBKEY_USAGE_ENC)) ) + { + release_progress_context (pfx); return rc; + } if(PGP2) { for(work_list=pk_list; work_list; work_list=work_list->next) @@ -493,7 +511,7 @@ encode_crypt( const char *filename, strlist_t remusr, int use_symkey ) else if( opt.verbose ) log_info(_("reading from `%s'\n"), filename? filename: "[stdin]"); - handle_progress (&pfx, inp, filename); + handle_progress (pfx, inp, filename); if( opt.textmode ) iobuf_push_filter( inp, text_filter, &tfx ); @@ -501,8 +519,11 @@ encode_crypt( const char *filename, strlist_t remusr, int use_symkey ) if( (rc = open_outfile( filename, opt.armor? 1:0, &out )) ) goto leave; - if( opt.armor ) - iobuf_push_filter( out, armor_filter, &afx ); + if ( opt.armor ) + { + afx = new_armor_context (); + push_armor_filter (afx, out); + } /* create a session key */ cfx.dek = xmalloc_secure_clear (sizeof *cfx.dek); @@ -695,6 +716,8 @@ encode_crypt( const char *filename, strlist_t remusr, int use_symkey ) xfree(symkey_dek); xfree(symkey_s2k); release_pk_list( pk_list ); + release_armor_context (afx); + release_progress_context (pfx); return rc; } diff --git a/g10/encr-data.c b/g10/encr-data.c index c56e01706..696f8af9d 100644 --- a/g10/encr-data.c +++ b/g10/encr-data.c @@ -39,14 +39,35 @@ static int mdc_decode_filter ( void *opaque, int control, IOBUF a, static int decode_filter ( void *opaque, int control, IOBUF a, byte *buf, size_t *ret_len); -typedef struct +typedef struct decode_filter_context_s { gcry_cipher_hd_t cipher_hd; gcry_md_hd_t mdc_hash; char defer[22]; int defer_filled; int eof_seen; -} decode_filter_ctx_t; + int refcount; +} *decode_filter_ctx_t; + + +/* Helper to release the decode context. */ +static void +release_dfx_context (decode_filter_ctx_t dfx) +{ + if (!dfx) + return; + + assert (dfx->refcount); + if ( !--dfx->refcount ) + { + gcry_cipher_close (dfx->cipher_hd); + dfx->cipher_hd = NULL; + gcry_md_close (dfx->mdc_hash); + dfx->mdc_hash = NULL; + xfree (dfx); + } +} + /**************** @@ -62,7 +83,11 @@ decrypt_data( void *procctx, PKT_encrypted *ed, DEK *dek ) unsigned blocksize; unsigned nprefix; - memset( &dfx, 0, sizeof dfx ); + dfx = xtrycalloc (1, sizeof *dfx); + if (!dfx) + return gpg_error_from_syserror (); + dfx->refcount = 1; + if ( opt.verbose && !dek->algo_info_printed ) { const char *s = gcry_cipher_algo_name (dek->algo); @@ -77,20 +102,20 @@ decrypt_data( void *procctx, PKT_encrypted *ed, DEK *dek ) goto leave; blocksize = gcry_cipher_get_algo_blklen (dek->algo); if ( !blocksize || blocksize > 16 ) - log_fatal("unsupported blocksize %u\n", blocksize ); + log_fatal ("unsupported blocksize %u\n", blocksize ); nprefix = blocksize; if ( ed->len && ed->len < (nprefix+2) ) BUG(); if ( ed->mdc_method ) { - if (gcry_md_open (&dfx.mdc_hash, ed->mdc_method, 0 )) + if (gcry_md_open (&dfx->mdc_hash, ed->mdc_method, 0 )) BUG (); if ( DBG_HASHING ) - gcry_md_start_debug (dfx.mdc_hash, "checkmdc"); + gcry_md_start_debug (dfx->mdc_hash, "checkmdc"); } - rc = gcry_cipher_open (&dfx.cipher_hd, dek->algo, + rc = gcry_cipher_open (&dfx->cipher_hd, dek->algo, GCRY_CIPHER_MODE_CFB, (GCRY_CIPHER_SECURE | ((ed->mdc_method || dek->algo >= 100)? @@ -104,7 +129,7 @@ decrypt_data( void *procctx, PKT_encrypted *ed, DEK *dek ) /* log_hexdump( "thekey", dek->key, dek->keylen );*/ - rc = gcry_cipher_setkey (dfx.cipher_hd, dek->key, dek->keylen); + rc = gcry_cipher_setkey (dfx->cipher_hd, dek->key, dek->keylen); if ( gpg_err_code (rc) == GPG_ERR_WEAK_KEY ) { log_info(_("WARNING: message was encrypted with" @@ -123,7 +148,7 @@ decrypt_data( void *procctx, PKT_encrypted *ed, DEK *dek ) goto leave; } - gcry_cipher_setiv (dfx.cipher_hd, NULL, 0); + gcry_cipher_setiv (dfx->cipher_hd, NULL, 0); if ( ed->len ) { @@ -144,8 +169,8 @@ decrypt_data( void *procctx, PKT_encrypted *ed, DEK *dek ) temp[i] = c; } - gcry_cipher_decrypt (dfx.cipher_hd, temp, nprefix+2, NULL, 0); - gcry_cipher_sync (dfx.cipher_hd); + gcry_cipher_decrypt (dfx->cipher_hd, temp, nprefix+2, NULL, 0); + gcry_cipher_sync (dfx->cipher_hd); p = temp; /* log_hexdump( "prefix", temp, nprefix+2 ); */ if (dek->symmetric @@ -155,17 +180,18 @@ decrypt_data( void *procctx, PKT_encrypted *ed, DEK *dek ) goto leave; } - if ( dfx.mdc_hash ) - gcry_md_write (dfx.mdc_hash, temp, nprefix+2); - + if ( dfx->mdc_hash ) + gcry_md_write (dfx->mdc_hash, temp, nprefix+2); + + dfx->refcount++; if ( ed->mdc_method ) - iobuf_push_filter( ed->buf, mdc_decode_filter, &dfx ); + iobuf_push_filter ( ed->buf, mdc_decode_filter, dfx ); else - iobuf_push_filter( ed->buf, decode_filter, &dfx ); + iobuf_push_filter ( ed->buf, decode_filter, dfx ); proc_packets ( procctx, ed->buf ); ed->buf = NULL; - if ( ed->mdc_method && dfx.eof_seen == 2 ) + if ( ed->mdc_method && dfx->eof_seen == 2 ) rc = gpg_error (GPG_ERR_INV_PACKET); else if ( ed->mdc_method ) { @@ -184,26 +210,28 @@ decrypt_data( void *procctx, PKT_encrypted *ed, DEK *dek ) bytes are appended. */ int datalen = gcry_md_get_algo_dlen (ed->mdc_method); - gcry_cipher_decrypt (dfx.cipher_hd, dfx.defer, 22, NULL, 0); - gcry_md_write (dfx.mdc_hash, dfx.defer, 2); - gcry_md_final (dfx.mdc_hash); + assert (dfx->cipher_hd); + assert (dfx->mdc_hash); + gcry_cipher_decrypt (dfx->cipher_hd, dfx->defer, 22, NULL, 0); + gcry_md_write (dfx->mdc_hash, dfx->defer, 2); + gcry_md_final (dfx->mdc_hash); - if (dfx.defer[0] != '\xd3' || dfx.defer[1] != '\x14' ) + if (dfx->defer[0] != '\xd3' || dfx->defer[1] != '\x14' ) { log_error("mdc_packet with invalid encoding\n"); rc = gpg_error (GPG_ERR_INV_PACKET); } else if (datalen != 20 - || memcmp (gcry_md_read (dfx.mdc_hash, 0),dfx.defer+2,datalen)) + || memcmp (gcry_md_read (dfx->mdc_hash, 0), + dfx->defer+2,datalen )) rc = gpg_error (GPG_ERR_BAD_SIGNATURE); - /* log_printhex("MDC message:", dfx.defer, 22); */ - /* log_printhex("MDC calc:", gcry_md_read (dfx.mdc_hash,0), datalen); */ + /* log_printhex("MDC message:", dfx->defer, 22); */ + /* log_printhex("MDC calc:", gcry_md_read (dfx->mdc_hash,0), datalen); */ } leave: - gcry_cipher_close (dfx.cipher_hd); - gcry_md_close (dfx.mdc_hash); + release_dfx_context (dfx); return rc; } @@ -214,7 +242,7 @@ static int mdc_decode_filter (void *opaque, int control, IOBUF a, byte *buf, size_t *ret_len) { - decode_filter_ctx_t *dfx = opaque; + decode_filter_ctx_t dfx = opaque; size_t n, size = *ret_len; int rc = 0; int c; @@ -226,11 +254,11 @@ mdc_decode_filter (void *opaque, int control, IOBUF a, } else if( control == IOBUFCTRL_UNDERFLOW ) { - assert(a); - assert( size > 44 ); + assert (a); + assert ( size > 44 ); /* Get at least 22 bytes and put it somewhere ahead in the buffer. */ - for(n=22; n < 44 ; n++ ) + for (n=22; n < 44 ; n++ ) { if( (c = iobuf_get(a)) == -1 ) break; @@ -279,8 +307,10 @@ mdc_decode_filter (void *opaque, int control, IOBUF a, if ( n ) { - gcry_cipher_decrypt (dfx->cipher_hd, buf, n, NULL, 0); - gcry_md_write (dfx->mdc_hash, buf, n); + if ( dfx->cipher_hd ) + gcry_cipher_decrypt (dfx->cipher_hd, buf, n, NULL, 0); + if ( dfx->mdc_hash ) + gcry_md_write (dfx->mdc_hash, buf, n); } else { @@ -289,6 +319,10 @@ mdc_decode_filter (void *opaque, int control, IOBUF a, } *ret_len = n; } + else if ( control == IOBUFCTRL_FREE ) + { + release_dfx_context (dfx); + } else if ( control == IOBUFCTRL_DESC ) { *(char**)buf = "mdc_decode_filter"; @@ -300,7 +334,7 @@ mdc_decode_filter (void *opaque, int control, IOBUF a, static int decode_filter( void *opaque, int control, IOBUF a, byte *buf, size_t *ret_len) { - decode_filter_ctx_t *fc = opaque; + decode_filter_ctx_t fc = opaque; size_t n, size = *ret_len; int rc = 0; @@ -311,11 +345,18 @@ decode_filter( void *opaque, int control, IOBUF a, byte *buf, size_t *ret_len) if ( n == -1 ) n = 0; if ( n ) - gcry_cipher_decrypt (fc->cipher_hd, buf, n, NULL, 0); + { + if (fc->cipher_hd) + gcry_cipher_decrypt (fc->cipher_hd, buf, n, NULL, 0); + } else rc = -1; /* EOF */ *ret_len = n; } + else if ( control == IOBUFCTRL_FREE ) + { + release_dfx_context (fc); + } else if ( control == IOBUFCTRL_DESC ) { *(char**)buf = "decode_filter"; diff --git a/g10/export.c b/g10/export.c index afc7fd7f9..78def573d 100644 --- a/g10/export.c +++ b/g10/export.c @@ -137,10 +137,9 @@ do_export( strlist_t users, int secret, unsigned int options ) { IOBUF out = NULL; int any, rc; - armor_filter_context_t afx; + armor_filter_context_t *afx = NULL; compress_filter_context_t zfx; - memset( &afx, 0, sizeof afx); memset( &zfx, 0, sizeof zfx); rc = open_outfile( NULL, 0, &out ); @@ -151,8 +150,9 @@ do_export( strlist_t users, int secret, unsigned int options ) { if ( opt.armor ) { - afx.what = secret?5:1; - iobuf_push_filter ( out, armor_filter, &afx ); + afx = new_armor_context (); + afx->what = secret? 5 : 1; + push_armor_filter (afx, out); } if ( opt.compress_keys ) push_compress_filter (out,&zfx,default_compress_algo()); @@ -164,6 +164,7 @@ do_export( strlist_t users, int secret, unsigned int options ) iobuf_cancel (out); else iobuf_close (out); + release_armor_context (afx); return rc; } diff --git a/g10/filter.h b/g10/filter.h index 5c1b9372a..13f6b38d5 100644 --- a/g10/filter.h +++ b/g10/filter.h @@ -32,12 +32,14 @@ typedef struct { } md_filter_context_t; typedef struct { + int refcount; /* Initialized to 1. */ + /* these fields may be initialized */ int what; /* what kind of armor headers to write */ int only_keyblocks; /* skip all headers but ".... key block" */ const char *hdrlines; /* write these headerlines */ - /* these fileds must be initialized to zero */ + /* these fields must be initialized to zero */ int no_openpgp_data; /* output flag: "No valid OpenPGP data found" */ /* the following fields must be initialized to zero */ @@ -121,6 +123,7 @@ typedef struct { unsigned long last; /* last amount reported */ unsigned long offset; /* current amount */ unsigned long total; /* total amount */ + int refcount; } progress_filter_context_t; /* encrypt_filter_context_t defined in main.h */ @@ -130,9 +133,10 @@ int md_filter( void *opaque, int control, iobuf_t a, byte *buf, size_t *ret_len) void free_md_filter_context( md_filter_context_t *mfx ); /*-- armor.c --*/ +armor_filter_context_t *new_armor_context (void); +void release_armor_context (armor_filter_context_t *afx); +int push_armor_filter (armor_filter_context_t *afx, iobuf_t iobuf); int use_armor_filter( iobuf_t a ); -int armor_filter( void *opaque, int control, - iobuf_t chain, byte *buf, size_t *ret_len); UnarmorPump unarmor_pump_new (void); void unarmor_pump_release (UnarmorPump x); int unarmor_pump (UnarmorPump x, int c); @@ -153,8 +157,8 @@ int copy_clearsig_text (iobuf_t out, iobuf_t inp, gcry_md_hd_t md, int escape_dash, int escape_from, int pgp2mode); /*-- progress.c --*/ -int progress_filter (void *opaque, int control, - iobuf_t a, byte *buf, size_t *ret_len); +progress_filter_context_t *new_progress_context (void); +void release_progress_context (progress_filter_context_t *pfx); void handle_progress (progress_filter_context_t *pfx, iobuf_t inp, const char *name); diff --git a/g10/gpg.c b/g10/gpg.c index dde5c6e56..846842054 100644 --- a/g10/gpg.c +++ b/g10/gpg.c @@ -1753,7 +1753,7 @@ main (int argc, char **argv ) int may_coredump; strlist_t sl, remusr= NULL, locusr=NULL; strlist_t nrings=NULL, sec_nrings=NULL; - armor_filter_context_t afx; + armor_filter_context_t *afx = NULL; int detached_sig = 0; FILE *configfp = NULL; char *configname = NULL; @@ -3826,8 +3826,8 @@ main (int argc, char **argv ) if( !opt.no_armor ) { if( use_armor_filter( a ) ) { - memset( &afx, 0, sizeof afx); - iobuf_push_filter( a, armor_filter, &afx ); + afx = new_armor_context (); + push_armor_filter (afx, a); } } if( cmd == aListPackets ) { @@ -3843,6 +3843,7 @@ main (int argc, char **argv ) } /* cleanup */ + release_armor_context (afx); FREE_STRLIST(remusr); FREE_STRLIST(locusr); g10_exit(0); diff --git a/g10/import.c b/g10/import.c index 8481d7beb..b3857fc0a 100644 --- a/g10/import.c +++ b/g10/import.c @@ -251,9 +251,12 @@ import( IOBUF inp, const char* fname,struct stats_s *stats, getkey_disable_caches(); if( !opt.no_armor ) { /* armored reading is not disabled */ - armor_filter_context_t *afx = xmalloc_clear( sizeof *afx ); + armor_filter_context_t *afx; + + afx = new_armor_context (); afx->only_keyblocks = 1; - iobuf_push_filter2( inp, armor_filter, afx, 1 ); + push_armor_filter (afx, inp); + release_armor_context (afx); } while( !(rc = read_block( inp, &pending_pkt, &keyblock) )) { diff --git a/g10/keyedit.c b/g10/keyedit.c index 758ae9436..bb8e63af4 100644 --- a/g10/keyedit.c +++ b/g10/keyedit.c @@ -1187,11 +1187,17 @@ change_passphrase( KBNODE keyblock ) set_next_passphrase( NULL ); for(;;) { + int canceled; + s2k->mode = opt.s2k_mode; s2k->hash_algo = S2K_DIGEST_ALGO; dek = passphrase_to_dek( NULL, 0, opt.s2k_cipher_algo, - s2k, 2, errtext, NULL); - if( !dek ) { + s2k, 2, errtext, &canceled); + if (!dek && canceled) { + rc = GPG_ERR_CANCELED; + break; + } + else if( !dek ) { errtext = N_("passphrase not correctly repeated; try again"); tty_printf ("%s.\n", _(errtext)); } @@ -3235,25 +3241,25 @@ menu_clean(KBNODE keyblock,int self_only) else reason=_("invalid"); - tty_printf("User ID \"%s\" compacted: %s\n",user,reason); + tty_printf (_("User ID \"%s\" compacted: %s\n"), user, reason); modified=1; } else if(sigs) { tty_printf(sigs==1? - "User ID \"%s\": %d signature removed\n": - "User ID \"%s\": %d signatures removed\n", + _("User ID \"%s\": %d signature removed\n") : + _("User ID \"%s\": %d signatures removed\n"), user,sigs); modified=1; } else { - tty_printf(self_only==1? - "User ID \"%s\": already minimized\n": - "User ID \"%s\": already clean\n", - user); + tty_printf (self_only==1? + _("User ID \"%s\": already minimized\n") : + _("User ID \"%s\": already clean\n"), + user); } xfree(user); diff --git a/g10/keygen.c b/g10/keygen.c index 259413754..1335eafff 100644 --- a/g10/keygen.c +++ b/g10/keygen.c @@ -96,13 +96,13 @@ struct output_control_s { char *fname; char *newfname; IOBUF stream; - armor_filter_context_t afx; + armor_filter_context_t *afx; } pub; struct { char *fname; char *newfname; IOBUF stream; - armor_filter_context_t afx; + armor_filter_context_t *afx; } sec; }; @@ -2045,9 +2045,8 @@ ask_user_id( int mode ) } -/* FIXME: We need a way to cancel this prompt. */ static DEK * -do_ask_passphrase( STRING2KEY **ret_s2k ) +do_ask_passphrase ( STRING2KEY **ret_s2k, int *r_canceled ) { DEK *dek = NULL; STRING2KEY *s2k; @@ -2060,8 +2059,13 @@ do_ask_passphrase( STRING2KEY **ret_s2k ) s2k->mode = opt.s2k_mode; s2k->hash_algo = S2K_DIGEST_ALGO; dek = passphrase_to_dek( NULL, 0, opt.s2k_cipher_algo, s2k,2, - errtext, NULL); - if( !dek ) { + errtext, r_canceled); + if (!dek && *r_canceled) { + xfree(dek); dek = NULL; + xfree(s2k); s2k = NULL; + break; + } + else if( !dek ) { errtext = N_("passphrase not correctly repeated; try again"); tty_printf(_("%s.\n"), _(errtext)); } @@ -2541,6 +2545,8 @@ read_parameter_file( const char *fname ) struct output_control_s outctrl; memset( &outctrl, 0, sizeof( outctrl ) ); + outctrl.pub.afx = new_armor_context (); + outctrl.sec.afx = new_armor_context (); if( !fname || !*fname) fname = "-"; @@ -2705,6 +2711,8 @@ read_parameter_file( const char *fname ) release_parameter_list( para ); iobuf_close (fp); + release_armor_context (outctrl.pub.afx); + release_armor_context (outctrl.sec.afx); } @@ -2731,6 +2739,7 @@ generate_keypair (const char *fname, const char *card_serialno, struct para_data_s *para = NULL; struct para_data_s *r; struct output_control_s outctrl; + int canceled; memset( &outctrl, 0, sizeof( outctrl ) ); @@ -2886,7 +2895,8 @@ generate_keypair (const char *fname, const char *card_serialno, r->next = para; para = r; - dek = card_serialno? NULL : do_ask_passphrase( &s2k ); + canceled = 0; + dek = card_serialno? NULL : do_ask_passphrase ( &s2k, &canceled ); if( dek ) { r = xmalloc_clear( sizeof *r ); @@ -2900,8 +2910,11 @@ generate_keypair (const char *fname, const char *card_serialno, r->next = para; para = r; } - - proc_parameter_file( para, "[internal]", &outctrl, !!card_serialno); + + if (canceled) + log_error (_("Key generation canceled.\n")); + else + proc_parameter_file( para, "[internal]", &outctrl, !!card_serialno); release_parameter_list( para ); } @@ -2923,6 +2936,7 @@ generate_raw_key (int algo, unsigned int nbits, u32 created_at, int i; size_t nskey, npkey; gcry_sexp_t s_parms, s_key; + int canceled; npkey = pubkey_get_npkey (algo); nskey = pubkey_get_nskey (algo); @@ -2940,7 +2954,12 @@ generate_raw_key (int algo, unsigned int nbits, u32 created_at, log_info(_("keysize rounded up to %u bits\n"), nbits ); } - dek = do_ask_passphrase (&s2k); + dek = do_ask_passphrase (&s2k, &canceled); + if (canceled) + { + rc = gpg_error (GPG_ERR_CANCELED); + goto leave; + } sk = xmalloc_clear (sizeof *sk); sk->timestamp = created_at; @@ -3050,9 +3069,8 @@ do_generate_keypair( struct para_data_s *para, return; } if( opt.armor ) { - outctrl->pub.afx.what = 1; - iobuf_push_filter( outctrl->pub.stream, armor_filter, - &outctrl->pub.afx ); + outctrl->pub.afx->what = 1; + push_armor_filter (outctrl->pub.afx, outctrl->pub.stream); } } if( outctrl->sec.newfname ) { @@ -3080,9 +3098,8 @@ do_generate_keypair( struct para_data_s *para, return; } if( opt.armor ) { - outctrl->sec.afx.what = 5; - iobuf_push_filter( outctrl->sec.stream, armor_filter, - &outctrl->sec.afx ); + outctrl->sec.afx->what = 5; + push_armor_filter (outctrl->sec.afx, outctrl->sec.stream); } } assert( outctrl->pub.stream ); @@ -3337,6 +3354,7 @@ generate_subkeypair( KBNODE pub_keyblock, KBNODE sec_keyblock ) STRING2KEY *s2k = NULL; u32 cur_time; int ask_pass = 0; + int canceled; /* break out the primary secret key */ node = find_kbnode( sec_keyblock, PKT_SECRET_KEY ); @@ -3404,8 +3422,9 @@ generate_subkeypair( KBNODE pub_keyblock, KBNODE sec_keyblock ) _("Really create? (y/N) "))) goto leave; + canceled = 0; if (ask_pass) - dek = do_ask_passphrase (&s2k); + dek = do_ask_passphrase (&s2k, &canceled); else if (passphrase) { s2k = xmalloc_secure( sizeof *s2k ); s2k->mode = opt.s2k_mode; @@ -3415,8 +3434,12 @@ generate_subkeypair( KBNODE pub_keyblock, KBNODE sec_keyblock ) NULL, NULL ); } - rc = do_create( algo, nbits, pub_keyblock, sec_keyblock, - dek, s2k, &sub_sk, expire, 1 ); + if (canceled) + rc = GPG_ERR_CANCELED; + + if (!rc) + rc = do_create (algo, nbits, pub_keyblock, sec_keyblock, + dek, s2k, &sub_sk, expire, 1 ); if( !rc ) rc = write_keybinding(pub_keyblock, pub_keyblock, pri_sk, sub_sk, use); if( !rc ) diff --git a/g10/keyserver.c b/g10/keyserver.c index 98086c30a..049b971a9 100644 --- a/g10/keyserver.c +++ b/g10/keyserver.c @@ -1196,23 +1196,24 @@ keyserver_spawn(enum ks_action action,strlist_t list,KEYDB_SEARCH_DESC *desc, for(key=list;key!=NULL;key=key->next) { - armor_filter_context_t afx; - IOBUF buffer=iobuf_temp(); + armor_filter_context_t *afx; + IOBUF buffer = iobuf_temp (); KBNODE block; temp=NULL; add_to_strlist(&temp,key->d); - memset(&afx,0,sizeof(afx)); - afx.what=1; + afx = new_armor_context (); + afx->what = 1; /* Tell the armor filter to use Unix-style \n line endings, since we're going to fprintf this to a file that (on Win32) is open in text mode. The win32 stdio will transform the \n to \r\n and we'll end up with the proper line endings on win32. This is a no-op on Unix. */ - afx.eol[0]='\n'; - iobuf_push_filter(buffer,armor_filter,&afx); + afx->eol[0] = '\n'; + push_armor_filter (afx, buffer); + release_armor_context (afx); /* TODO: Remove Comment: lines from keys exported this way? */ diff --git a/g10/mainproc.c b/g10/mainproc.c index c4eb3b0ca..dc7988987 100644 --- a/g10/mainproc.c +++ b/g10/mainproc.c @@ -290,23 +290,8 @@ proc_symkey_enc( CTX c, PACKET *pkt ) } else { - int canceled; - c->dek = passphrase_to_dek (NULL, 0, algo, &enc->s2k, 0, - NULL, &canceled); - if (canceled) - { - /* For unknown reasons passphrase_to_dek does only - return NULL if a new passphrase has been requested - and has not been repeated correctly. Thus even - with a cancel requested (by means of the gpg-agent) - it won't return NULL but an empty passphrase. We - take the most conservative approach for now and - work around it right here. */ - xfree (c->dek); - c->dek = NULL; - } - + NULL, NULL); if(c->dek) { c->dek->symmetric=1; diff --git a/g10/passphrase.c b/g10/passphrase.c index ae22074f6..f4015ef74 100644 --- a/g10/passphrase.c +++ b/g10/passphrase.c @@ -482,7 +482,9 @@ ask_passphrase (const char *description, /* Return a new DEK object Using the string-to-key sepcifier S2K. Use - * KEYID and PUBKEY_ALGO to prompt the user. + KEYID and PUBKEY_ALGO to prompt the user. Returns NULL is the user + selected to cancel the passphrase entry and it CANCELED is not + NULL, sets it to true. MODE 0: Allow cached passphrase 1: Ignore cached passphrase @@ -496,9 +498,11 @@ passphrase_to_dek (u32 *keyid, int pubkey_algo, char *pw = NULL; DEK *dek; STRING2KEY help_s2k; - - if (canceled) - *canceled = 0; + int dummy_canceled; + + if (!canceled) + canceled = &dummy_canceled; + *canceled = 0; if ( !s2k ) { @@ -600,7 +604,7 @@ passphrase_to_dek (u32 *keyid, int pubkey_algo, } else if ( have_static_passphrase () ) { - /* Return the passphrase we have store in FD_PASSWD. */ + /* Return the passphrase we have stored in FD_PASSWD. */ pw = xmalloc_secure ( strlen(fd_passwd)+1 ); strcpy ( pw, fd_passwd ); } @@ -609,6 +613,11 @@ passphrase_to_dek (u32 *keyid, int pubkey_algo, /* Divert to the gpg-agent. */ pw = passphrase_get ( keyid, mode == 2? 1: 0, NULL, tryagain_text, NULL, NULL, canceled ); + if (*canceled) + { + xfree (pw); + return NULL; + } if (!pw) pw = xstrdup (""); if ( *pw && mode == 2 ) @@ -618,6 +627,12 @@ passphrase_to_dek (u32 *keyid, int pubkey_algo, { char *pw2 = passphrase_get ( keyid, 2, NULL, NULL, NULL, NULL, canceled ); + if (*canceled) + { + xfree (pw); + xfree (pw2); + return NULL; + } if (!pw2) pw2 = xstrdup (""); if ( strcmp(pw, pw2) ) diff --git a/g10/plaintext.c b/g10/plaintext.c index 2d516a3a5..cab4d6d46 100644 --- a/g10/plaintext.c +++ b/g10/plaintext.c @@ -449,18 +449,20 @@ int ask_for_detached_datafile (gcry_md_hd_t md, gcry_md_hd_t md2, const char *inname, int textmode ) { - progress_filter_context_t pfx; + progress_filter_context_t *pfx; char *answer = NULL; IOBUF fp; int rc = 0; - fp = open_sigfile( inname, &pfx ); /* open default file */ + pfx = new_progress_context (); + fp = open_sigfile ( inname, pfx ); /* Open default file. */ if( !fp && !opt.batch ) { int any=0; tty_printf(_("Detached signature.\n")); do { char *name; + xfree(answer); tty_enable_completion(NULL); name = cpr_get("detached_signature.filename", @@ -505,6 +507,7 @@ ask_for_detached_datafile (gcry_md_hd_t md, gcry_md_hd_t md2, leave: xfree(answer); + release_progress_context (pfx); return rc; } @@ -518,19 +521,23 @@ int hash_datafiles( gcry_md_hd_t md, gcry_md_hd_t md2, strlist_t files, const char *sigfilename, int textmode ) { - progress_filter_context_t pfx; + progress_filter_context_t *pfx; IOBUF fp; strlist_t sl; + pfx = new_progress_context (); + if( !files ) { /* check whether we can open the signed material */ - fp = open_sigfile( sigfilename, &pfx ); + fp = open_sigfile( sigfilename, pfx ); if( fp ) { do_hash( md, md2, fp, textmode ); iobuf_close(fp); + release_progress_context (pfx); return 0; } log_error (_("no signed data\n")); + release_progress_context (pfx); return gpg_error (GPG_ERR_NO_DATA); } @@ -547,13 +554,15 @@ hash_datafiles( gcry_md_hd_t md, gcry_md_hd_t md2, strlist_t files, int rc = gpg_error_from_syserror (); log_error(_("can't open signed data `%s'\n"), print_fname_stdin(sl->d)); + release_progress_context (pfx); return rc; } - handle_progress (&pfx, fp, sl->d); + handle_progress (pfx, fp, sl->d); do_hash( md, md2, fp, textmode ); iobuf_close(fp); } + release_progress_context (pfx); return 0; } diff --git a/g10/progress.c b/g10/progress.c index 148bf7e2d..8ccc4536f 100644 --- a/g10/progress.c +++ b/g10/progress.c @@ -1,5 +1,5 @@ /* progress.c - emit progress status lines - * Copyright (C) 2003 Free Software Foundation, Inc. + * Copyright (C) 2003, 2006 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -21,6 +21,7 @@ #include #include +#include #include "gpg.h" #include "iobuf.h" @@ -29,10 +30,54 @@ #include "util.h" #include "options.h" +/* Create a new context for use with the progress filter. We need to + allocate such contexts on the heap because there is no guarantee + that at the end of a function the filter has already been popped + off. In general this will happen but with malformed packets it is + possible that a filter has not yet reached the end-of-stream when + the function has done all processing. Checking in each function + that end-of-stream has been reached would be to cumbersome. + + What we also do is to shortcut the progress handler by having this + function return NULL if progress information has not been + requested. +*/ +progress_filter_context_t * +new_progress_context (void) +{ + progress_filter_context_t *pfx; + + if (!opt.enable_progress_filter) + return NULL; + + if (!is_status_enabled ()) + return NULL; + + pfx = xcalloc (1, sizeof *pfx); + pfx->refcount = 1; + + return pfx; +} + +/* Release a progress filter context. Passing NULL is explicitly + allowed and a no-op. */ +void +release_progress_context (progress_filter_context_t *pfx) +{ + if (!pfx) + return; + assert (pfx->refcount); + if ( --pfx->refcount ) + return; + xfree (pfx->what); + xfree (pfx); +} + + /**************** * The filter is used to report progress to the user. */ -int +static int progress_filter (void *opaque, int control, IOBUF a, byte *buf, size_t *ret_len) { @@ -85,11 +130,7 @@ progress_filter (void *opaque, int control, } else if (control == IOBUFCTRL_FREE) { - /* Note, that we must always dealloc resources of a filter - within the filter handler and not anywhere else. (We set it - to NULL and check all uses just in case.) */ - xfree (pfx->what); - pfx->what = NULL; + release_progress_context (pfx); } else if (control == IOBUFCTRL_DESC) *(char**)buf = "progress_filter"; @@ -101,11 +142,11 @@ handle_progress (progress_filter_context_t *pfx, IOBUF inp, const char *name) { off_t filesize = 0; - if (!opt.enable_progress_filter) + if (!pfx) return; - if (!is_status_enabled ()) - return; + assert (opt.enable_progress_filter); + assert (is_status_enabled ()); if ( !iobuf_is_pipe_filename (name) && *name ) filesize = iobuf_get_filelength (inp, NULL); @@ -115,5 +156,6 @@ handle_progress (progress_filter_context_t *pfx, IOBUF inp, const char *name) /* register the progress filter */ pfx->what = xstrdup (name ? name : "stdin"); pfx->total = filesize; + pfx->refcount++; iobuf_push_filter (inp, progress_filter, pfx); } diff --git a/g10/revoke.c b/g10/revoke.c index 29f4b8d2f..4d7b8c366 100644 --- a/g10/revoke.c +++ b/g10/revoke.c @@ -200,7 +200,7 @@ int gen_desig_revoke( const char *uname, strlist_t locusr ) { int rc = 0; - armor_filter_context_t afx; + armor_filter_context_t *afx; PKT_public_key *pk = NULL; PKT_secret_key *sk = NULL; PKT_signature *sig = NULL; @@ -219,7 +219,7 @@ gen_desig_revoke( const char *uname, strlist_t locusr ) return G10ERR_GENERAL; } - memset( &afx, 0, sizeof afx); + afx = new_armor_context (); kdbhd = keydb_new (0); classify_user_id (uname, &desc); @@ -331,10 +331,10 @@ gen_desig_revoke( const char *uname, strlist_t locusr ) if( (rc = open_outfile( NULL, 0, &out )) ) goto leave; - afx.what = 1; - afx.hdrlines = "Comment: A designated revocation certificate" + afx->what = 1; + afx->hdrlines = "Comment: A designated revocation certificate" " should follow\n"; - iobuf_push_filter( out, armor_filter, &afx ); + push_armor_filter (afx, out); /* create it */ rc = make_keysig_packet( &sig, pk, NULL, NULL, sk, 0x20, 0, @@ -427,6 +427,7 @@ gen_desig_revoke( const char *uname, strlist_t locusr ) else iobuf_close(out); release_revocation_reason_info( reason ); + release_armor_context (afx); return rc; } @@ -438,7 +439,7 @@ int gen_revoke( const char *uname ) { int rc = 0; - armor_filter_context_t afx; + armor_filter_context_t *afx; PACKET pkt; PKT_secret_key *sk; /* used as pointer into a kbnode */ PKT_public_key *pk = NULL; @@ -457,7 +458,7 @@ gen_revoke( const char *uname ) return G10ERR_GENERAL; } - memset( &afx, 0, sizeof afx); + afx = new_armor_context (); init_packet( &pkt ); /* search the userid: @@ -556,9 +557,9 @@ gen_revoke( const char *uname ) if( (rc = open_outfile( NULL, 0, &out )) ) goto leave; - afx.what = 1; - afx.hdrlines = "Comment: A revocation certificate should follow\n"; - iobuf_push_filter( out, armor_filter, &afx ); + afx->what = 1; + afx->hdrlines = "Comment: A revocation certificate should follow\n"; + push_armor_filter (afx, out); /* create it */ rc = make_keysig_packet( &sig, pk, NULL, NULL, sk, 0x20, 0, @@ -609,6 +610,7 @@ gen_revoke( const char *uname ) else iobuf_close(out); release_revocation_reason_info( reason ); + release_armor_context (afx); return rc; } diff --git a/g10/sign.c b/g10/sign.c index 32f15c553..8ae9c0b28 100644 --- a/g10/sign.c +++ b/g10/sign.c @@ -739,11 +739,11 @@ sign_file( strlist_t filenames, int detached, strlist_t locusr, int encryptflag, strlist_t remusr, const char *outfile ) { const char *fname; - armor_filter_context_t afx; + armor_filter_context_t *afx; compress_filter_context_t zfx; md_filter_context_t mfx; text_filter_context_t tfx; - progress_filter_context_t pfx; + progress_filter_context_t *pfx; encrypt_filter_context_t efx; IOBUF inp = NULL, out = NULL; PACKET pkt; @@ -754,7 +754,8 @@ sign_file( strlist_t filenames, int detached, strlist_t locusr, int multifile = 0; u32 duration=0; - memset( &afx, 0, sizeof afx); + pfx = new_progress_context (); + afx = new_armor_context (); memset( &zfx, 0, sizeof zfx); memset( &mfx, 0, sizeof mfx); memset( &efx, 0, sizeof efx); @@ -814,7 +815,7 @@ sign_file( strlist_t filenames, int detached, strlist_t locusr, goto leave; } - handle_progress (&pfx, inp, fname); + handle_progress (pfx, inp, fname); } if( outfile ) { @@ -933,10 +934,10 @@ sign_file( strlist_t filenames, int detached, strlist_t locusr, iobuf_push_filter( inp, md_filter, &mfx ); if( detached && !encryptflag && !RFC1991 ) - afx.what = 2; + afx->what = 2; if( opt.armor && !outfile ) - iobuf_push_filter( out, armor_filter, &afx ); + push_armor_filter (afx, out); if( encryptflag ) { efx.pk_list = pk_list; @@ -1008,7 +1009,7 @@ sign_file( strlist_t filenames, int detached, strlist_t locusr, sl->d,strerror(errno)); goto leave; } - handle_progress (&pfx, inp, sl->d); + handle_progress (pfx, inp, sl->d); if( opt.verbose ) fprintf(stderr, " `%s'", sl->d ); if(opt.textmode) @@ -1060,6 +1061,8 @@ sign_file( strlist_t filenames, int detached, strlist_t locusr, release_sk_list( sk_list ); release_pk_list( pk_list ); recipient_digest_algo=0; + release_progress_context (pfx); + release_armor_context (afx); return rc; } @@ -1071,8 +1074,8 @@ sign_file( strlist_t filenames, int detached, strlist_t locusr, int clearsign_file( const char *fname, strlist_t locusr, const char *outfile ) { - armor_filter_context_t afx; - progress_filter_context_t pfx; + armor_filter_context_t *afx; + progress_filter_context_t *pfx; gcry_md_hd_t textmd = NULL; IOBUF inp = NULL, out = NULL; PACKET pkt; @@ -1083,7 +1086,8 @@ clearsign_file( const char *fname, strlist_t locusr, const char *outfile ) int only_md5 = 0; u32 duration=0; - memset( &afx, 0, sizeof afx); + pfx = new_progress_context (); + afx = new_armor_context (); init_packet( &pkt ); if(!opt.force_v3_sigs && !RFC1991) @@ -1121,7 +1125,7 @@ clearsign_file( const char *fname, strlist_t locusr, const char *outfile ) fname? fname: "[stdin]", strerror(errno) ); goto leave; } - handle_progress (&pfx, inp, fname); + handle_progress (pfx, inp, fname); if( outfile ) { if (is_secured_filename (outfile) ) { @@ -1199,8 +1203,8 @@ clearsign_file( const char *fname, strlist_t locusr, const char *outfile ) /* fixme: check for read errors */ /* now write the armor */ - afx.what = 2; - iobuf_push_filter( out, armor_filter, &afx ); + afx->what = 2; + push_armor_filter (afx, out); /* write the signatures */ rc=write_signature_packets (sk_list, out, textmd, 0x01, 0, duration, 'C'); @@ -1215,6 +1219,8 @@ clearsign_file( const char *fname, strlist_t locusr, const char *outfile ) iobuf_close(inp); gcry_md_close ( textmd ); release_sk_list( sk_list ); + release_progress_context (pfx); + release_armor_context (afx); return rc; } @@ -1225,8 +1231,8 @@ clearsign_file( const char *fname, strlist_t locusr, const char *outfile ) int sign_symencrypt_file (const char *fname, strlist_t locusr) { - armor_filter_context_t afx; - progress_filter_context_t pfx; + armor_filter_context_t *afx; + progress_filter_context_t *pfx; compress_filter_context_t zfx; md_filter_context_t mfx; text_filter_context_t tfx; @@ -1239,8 +1245,10 @@ sign_symencrypt_file (const char *fname, strlist_t locusr) SK_LIST sk_rover = NULL; int algo; u32 duration=0; + int canceled; - memset( &afx, 0, sizeof afx); + pfx = new_progress_context (); + afx = new_armor_context (); memset( &zfx, 0, sizeof zfx); memset( &mfx, 0, sizeof mfx); memset( &tfx, 0, sizeof tfx); @@ -1273,7 +1281,7 @@ sign_symencrypt_file (const char *fname, strlist_t locusr) fname? fname: "[stdin]", strerror(errno) ); goto leave; } - handle_progress (&pfx, inp, fname); + handle_progress (pfx, inp, fname); /* prepare key */ s2k = xmalloc_clear( sizeof *s2k ); @@ -1284,10 +1292,10 @@ sign_symencrypt_file (const char *fname, strlist_t locusr) if (!opt.quiet || !opt.batch) log_info (_("%s encryption will be used\n"), gcry_cipher_algo_name (algo) ); - cfx.dek = passphrase_to_dek( NULL, 0, algo, s2k, 2, NULL, NULL); + cfx.dek = passphrase_to_dek( NULL, 0, algo, s2k, 2, NULL, &canceled); if (!cfx.dek || !cfx.dek->keylen) { - rc = gpg_error (GPG_ERR_BAD_PASSPHRASE); + rc = gpg_error (canceled?GPG_ERR_CANCELED:GPG_ERR_BAD_PASSPHRASE); log_error(_("error creating passphrase: %s\n"), gpg_strerror (rc) ); goto leave; } @@ -1321,7 +1329,7 @@ sign_symencrypt_file (const char *fname, strlist_t locusr) /* Push armor output filter */ if (opt.armor) - iobuf_push_filter (out, armor_filter, &afx); + push_armor_filter (afx, out); /* Write the symmetric key packet */ /*(current filters: armor)*/ @@ -1382,6 +1390,8 @@ sign_symencrypt_file (const char *fname, strlist_t locusr) gcry_md_close( mfx.md ); xfree(cfx.dek); xfree(s2k); + release_progress_context (pfx); + release_armor_context (afx); return rc; } diff --git a/g10/verify.c b/g10/verify.c index e34ad7a5d..5145525f5 100644 --- a/g10/verify.c +++ b/g10/verify.c @@ -55,13 +55,14 @@ int verify_signatures( int nfiles, char **files ) { IOBUF fp; - armor_filter_context_t afx; - progress_filter_context_t pfx; + armor_filter_context_t *afx; + progress_filter_context_t *pfx; const char *sigfile; int i, rc; strlist_t sl; - memset( &afx, 0, sizeof afx); + pfx = new_progress_context (); + afx = new_armor_context (); /* decide whether we should handle a detached or a normal signature, * which is needed so that the code later can hash the correct data and * not have a normal signature act as detached signature and ignoring the @@ -101,12 +102,13 @@ verify_signatures( int nfiles, char **files ) rc = gpg_error_from_syserror (); log_error(_("can't open `%s': %s\n"), print_fname_stdin(sigfile), strerror (errno)); + release_progress_context (pfx); return rc; } - handle_progress (&pfx, fp, sigfile); + handle_progress (pfx, fp, sigfile); if( !opt.no_armor && use_armor_filter( fp ) ) - iobuf_push_filter( fp, armor_filter, &afx ); + push_armor_filter (afx, fp); sl = NULL; for(i=nfiles-1 ; i > 0 ; i-- ) @@ -114,13 +116,15 @@ verify_signatures( int nfiles, char **files ) rc = proc_signature_packets( NULL, fp, sl, sigfile ); free_strlist(sl); iobuf_close(fp); - if( (afx.no_openpgp_data && rc == -1) || rc == G10ERR_NO_DATA ) { + if( (afx->no_openpgp_data && rc == -1) || rc == G10ERR_NO_DATA ) { log_error(_("the signature could not be verified.\n" "Please remember that the signature file (.sig or .asc)\n" "should be the first file given on the command line.\n") ); rc = 0; } + release_armor_context (afx); + release_progress_context (pfx); return rc; } @@ -139,10 +143,11 @@ static int verify_one_file( const char *name ) { IOBUF fp; - armor_filter_context_t afx; - progress_filter_context_t pfx; + armor_filter_context_t *afx = NULL; + progress_filter_context_t *pfx; int rc; + pfx = new_progress_context (); print_file_status( STATUS_FILE_START, name, 1 ); fp = iobuf_open(name); if (fp) @@ -158,20 +163,23 @@ verify_one_file( const char *name ) log_error(_("can't open `%s': %s\n"), print_fname_stdin(name), strerror (errno)); print_file_status( STATUS_FILE_ERROR, name, 1 ); + release_progress_context (pfx); return rc; } - handle_progress (&pfx, fp, name); + handle_progress (pfx, fp, name); if( !opt.no_armor ) { if( use_armor_filter( fp ) ) { - memset( &afx, 0, sizeof afx); - iobuf_push_filter( fp, armor_filter, &afx ); + afx = new_armor_context (); + push_armor_filter (afx, fp); } } rc = proc_signature_packets( NULL, fp, NULL, name ); iobuf_close(fp); write_status( STATUS_FILE_DONE ); + release_armor_context (afx); + release_progress_context (pfx); return rc; } diff --git a/jnlib/ChangeLog b/jnlib/ChangeLog index 68340896c..e120319cd 100644 --- a/jnlib/ChangeLog +++ b/jnlib/ChangeLog @@ -1,3 +1,8 @@ +2006-11-29 Werner Koch + + * utf8conv.c (set_native_charset) [HAVE_W32_SYSTEM]: Fixed typo in + macro name. + 2006-11-15 Werner Koch * logging.c (my_funopen_hook_ret_t): New. diff --git a/jnlib/utf8conv.c b/jnlib/utf8conv.c index ec04a52ad..9a2a98b3b 100644 --- a/jnlib/utf8conv.c +++ b/jnlib/utf8conv.c @@ -102,7 +102,7 @@ set_native_charset (const char *newset) if (!newset) { -#ifdef HABE_W32_SYSTEM +#ifdef HAVE_W32_SYSTEM static char codepage[30]; unsigned int cpno; const char *aliases;