diff --git a/common/iobuf.c b/common/iobuf.c index 2d2c8a585..f4766c6a4 100644 --- a/common/iobuf.c +++ b/common/iobuf.c @@ -1,7 +1,7 @@ /* iobuf.c - File Handling for OpenPGP. * Copyright (C) 1998, 1999, 2000, 2001, 2003, 2004, 2006, 2007, 2008, * 2009, 2010, 2011 Free Software Foundation, Inc. - * Copyright (C) 2015 g10 Code GmbH + * Copyright (C) 2015, 2023 g10 Code GmbH * * This file is part of GnuPG. * @@ -93,6 +93,9 @@ typedef struct int no_cache; int eof_seen; int print_only_name; /* Flags indicating that fname is not a real file. */ + char peeked[32]; /* Read ahead buffer. */ + byte npeeked; /* Number of bytes valid in peeked. */ + byte upeeked; /* Number of bytes used from peeked. */ char fname[1]; /* Name of the file. */ } file_filter_ctx_t; @@ -454,7 +457,16 @@ file_filter (void *opaque, int control, iobuf_t chain, byte * buf, if (control == IOBUFCTRL_UNDERFLOW) { log_assert (size); /* We need a buffer. */ - if (a->eof_seen) + if (a->npeeked > a->upeeked) + { + nbytes = a->npeeked - a->upeeked; + if (nbytes > size) + nbytes = size; + memcpy (buf, a->peeked + a->upeeked, nbytes); + a->upeeked += nbytes; + *ret_len = nbytes; + } + else if (a->eof_seen) { rc = -1; *ret_len = 0; @@ -573,6 +585,68 @@ file_filter (void *opaque, int control, iobuf_t chain, byte * buf, a->eof_seen = 0; a->keep_open = 0; a->no_cache = 0; + a->npeeked = 0; + a->upeeked = 0; + } + else if (control == IOBUFCTRL_PEEK) + { + /* Peek on the input. */ +#ifdef HAVE_W32_SYSTEM + unsigned long nread; + + nbytes = 0; + if (!ReadFile (f, a->peeked, sizeof a->peeked, &nread, NULL)) + { + int ec = (int) GetLastError (); + if (ec != ERROR_BROKEN_PIPE) + { + rc = gpg_error_from_errno (ec); + log_error ("%s: read error: ec=%d\n", a->fname, ec); + } + a->npeeked = 0; + } + else if (!nread) + { + a->eof_seen = 1; + a->npeeked = 0; + } + else + { + a->npeeked = nread; + } + +#else /* Unix */ + + int n; + + peek_more: + do + { + n = read (f, a->peeked + a->npeeked, sizeof a->peeked - a->npeeked); + } + while (n == -1 && errno == EINTR); + if (n > 0) + { + a->npeeked += n; + if (a->npeeked < sizeof a->peeked) + goto peek_more; + } + else if (!n) /* eof */ + { + a->eof_seen = 1; + } + else /* error */ + { + rc = gpg_error_from_syserror (); + if (gpg_err_code (rc) != GPG_ERR_EPIPE) + log_error ("%s: read error: %s\n", a->fname, gpg_strerror (rc)); + } +#endif /* Unix */ + + size = a->npeeked < size? a->npeeked : size; + memcpy (buf, a->peeked, size); + *ret_len = size; + rc = 0; /* Return success - the user needs to check ret_len. */ } else if (control == IOBUFCTRL_DESC) { @@ -1487,6 +1561,25 @@ iobuf_ioctl (iobuf_t a, iobuf_ioctl_t cmd, int intval, void *ptrval) return fd_cache_synchronize (ptrval); } } + else if (cmd == IOBUF_IOCTL_PEEK) + { + /* Peek at a justed opened file. Use this only directly after a + * file has been opened for reading. Don't use it after you did + * a seek. This works only if just file filter has been + * pushed. Expects a buffer wit size INTVAL at PTRVAL and returns + * the number of bytes put into the buffer. */ + if (DBG_IOBUF) + log_debug ("iobuf-%d.%d: ioctl '%s' peek\n", + a ? a->no : -1, a ? a->subno : -1, iobuf_desc (a, desc)); + if (a->filter == file_filter && ptrval && intval) + { + file_filter_ctx_t *fcx = a->filter_ov; + size_t len = intval; + + if (!file_filter (fcx, IOBUFCTRL_PEEK, NULL, ptrval, &len)) + return (int)len; + } + } return -1; diff --git a/common/iobuf.h b/common/iobuf.h index 624e154d8..79d361c18 100644 --- a/common/iobuf.h +++ b/common/iobuf.h @@ -106,6 +106,7 @@ enum IOBUFCTRL_FLUSH = 4, IOBUFCTRL_DESC = 5, IOBUFCTRL_CANCEL = 6, + IOBUFCTRL_PEEK = 7, IOBUFCTRL_USER = 16 }; @@ -116,7 +117,8 @@ typedef enum IOBUF_IOCTL_KEEP_OPEN = 1, /* Uses intval. */ IOBUF_IOCTL_INVALIDATE_CACHE = 2, /* Uses ptrval. */ IOBUF_IOCTL_NO_CACHE = 3, /* Uses intval. */ - IOBUF_IOCTL_FSYNC = 4 /* Uses ptrval. */ + IOBUF_IOCTL_FSYNC = 4, /* Uses ptrval. */ + IOBUF_IOCTL_PEEK = 5 /* Uses intval and ptrval. */ } iobuf_ioctl_t; enum iobuf_use diff --git a/common/miscellaneous.c b/common/miscellaneous.c index c3775547b..b73239eaa 100644 --- a/common/miscellaneous.c +++ b/common/miscellaneous.c @@ -466,7 +466,7 @@ decode_c_string (const char *src) /* Check whether (BUF,LEN) is valid header for an OpenPGP compressed * packet. LEN should be at least 6. */ static int -is_openpgp_compressed_packet (unsigned char *buf, size_t len) +is_openpgp_compressed_packet (const unsigned char *buf, size_t len) { int c, ctb, pkttype; int lenbytes; @@ -508,63 +508,46 @@ is_openpgp_compressed_packet (unsigned char *buf, size_t len) /* - * Check if the file is compressed. + * Check if the file is compressed. You need to pass the first bytes + * of the file as (BUF,BUFLEN). Returns true if the buffer seems to + * be compressed. */ int -is_file_compressed (const char *s, int *ret_rc) +is_file_compressed (const byte *buf, unsigned int buflen) { - iobuf_t a; - byte buf[6]; - int i; - int rc = 0; - int overflow; + int i; - struct magic_compress_s { - size_t len; - byte magic[4]; - } magic[] = { - { 3, { 0x42, 0x5a, 0x68, 0x00 } }, /* bzip2 */ - { 3, { 0x1f, 0x8b, 0x08, 0x00 } }, /* gzip */ - { 4, { 0x50, 0x4b, 0x03, 0x04 } }, /* (pk)zip */ - }; + struct magic_compress_s + { + byte len; + byte magic[5]; + } magic[] = + { + { 3, { 0x42, 0x5a, 0x68, 0x00 } }, /* bzip2 */ + { 3, { 0x1f, 0x8b, 0x08, 0x00 } }, /* gzip */ + { 4, { 0x50, 0x4b, 0x03, 0x04 } }, /* (pk)zip */ + { 5, { '%', 'P', 'D', 'F', '-'} } /* PDF */ + }; - if ( iobuf_is_pipe_filename (s) || !ret_rc ) - return 0; /* We can't check stdin or no file was given */ - - a = iobuf_open( s ); - if ( a == NULL ) { - *ret_rc = gpg_error_from_syserror (); - return 0; - } - iobuf_ioctl (a, IOBUF_IOCTL_NO_CACHE, 1, NULL); - - if ( iobuf_get_filelength( a, &overflow ) < 6 && !overflow) { - *ret_rc = 0; - goto leave; + if ( buflen < 6 ) + { + return 0; /* Too short to check - assume uncompressed. */ } - if ( iobuf_read( a, buf, 6 ) == -1 ) { - *ret_rc = a->error; - goto leave; - } - - for ( i = 0; i < DIM( magic ); i++ ) { - if ( !memcmp( buf, magic[i].magic, magic[i].len ) ) { - *ret_rc = 0; - rc = 1; - goto leave; + for ( i = 0; i < DIM (magic); i++ ) + { + if ( !memcmp( buf, magic[i].magic, magic[i].len )) + { + return 1; /* Is compressed. */ } } - if (is_openpgp_compressed_packet (buf, 6)) - { - *ret_rc = 0; - rc = 1; - } + if (buflen >= 6 && is_openpgp_compressed_packet (buf, buflen)) + { + return 1; /* Already compressed. */ + } - leave: - iobuf_close( a ); - return rc; + return 0; /* Not detected as compressed. */ } diff --git a/common/util.h b/common/util.h index cd961d212..e4f8d2470 100644 --- a/common/util.h +++ b/common/util.h @@ -347,7 +347,7 @@ char *try_make_printable_string (const void *p, size_t n, int delim); char *make_printable_string (const void *p, size_t n, int delim); char *decode_c_string (const char *src); -int is_file_compressed (const char *s, int *ret_rc); +int is_file_compressed (const byte *buf, unsigned int buflen); int match_multistr (const char *multistr,const char *match); diff --git a/doc/gpg.texi b/doc/gpg.texi index 9491dc83f..d6320f576 100644 --- a/doc/gpg.texi +++ b/doc/gpg.texi @@ -848,9 +848,10 @@ line. @opindex keyedit:tsign Make a trust signature. This is a signature that combines the notions of certification (like a regular signature), and trust (like the - "trust" command). It is generally only useful in distinct communities - or groups. For more information please read the sections - ``Trust Signature'' and ``Regular Expression'' in RFC-4880. + "trust" command). It is generally useful in distinct communities + or groups to implement the concept of a Trusted Introducer. For + more information please read the sections ``Trust Signature'' and + ``Regular Expression'' in RFC-4880. @end table @c man:.RS @@ -1619,6 +1620,16 @@ for the BZIP2 compression algorithm (defaulting to 6 as well). This is a different option from @option{--compress-level} since BZIP2 uses a significant amount of memory for each additional compression level. @option{-z} sets both. A value of 0 for @var{n} disables compression. +A value of -1 forces compression using the default level. + +Except for the @option{--store} command compression is always used +unless @command{gpg} detects that the input is already compressed. To +inhibit the use of compression use @option{-z0}; to force compression +use @option{-z-1} or option @option{z} with another compression level +than the default as indicated by -1. Note that this overriding of the +default deection works only with @option{z} and not with the long +variant of this option. + @item --bzip2-decompress-lowmem @opindex bzip2-decompress-lowmem diff --git a/g10/encrypt.c b/g10/encrypt.c index 982a128d0..3d8d9160f 100644 --- a/g10/encrypt.c +++ b/g10/encrypt.c @@ -1,7 +1,7 @@ /* encrypt.c - Main encryption driver * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, * 2006, 2009 Free Software Foundation, Inc. - * Copyright (C) 2016, 2022 g10 Code GmbH + * Copyright (C) 2016, 2022, 2023 g10 Code GmbH * * This file is part of GnuPG. * @@ -17,6 +17,7 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, see . + * SPDX-License-Identifier: GPL-3.0-or-later */ #include @@ -326,6 +327,8 @@ encrypt_simple (const char *filename, int mode, int use_seskey) text_filter_context_t tfx; progress_filter_context_t *pfx; int do_compress = !!default_compress_algo(); + char peekbuf[32]; + int peekbuflen; if (!gnupg_rng_is_compliant (opt.compliance)) { @@ -362,6 +365,14 @@ encrypt_simple (const char *filename, int mode, int use_seskey) return rc; } + peekbuflen = iobuf_ioctl (inp, IOBUF_IOCTL_PEEK, sizeof peekbuf, peekbuf); + if (peekbuflen < 0) + { + peekbuflen = 0; + if (DBG_FILTER) + log_debug ("peeking at input failed\n"); + } + handle_progress (pfx, inp, filename); if (opt.textmode) @@ -426,10 +437,11 @@ encrypt_simple (const char *filename, int mode, int use_seskey) if (do_compress && cfx.dek && (cfx.dek->use_mdc || cfx.dek->use_aead) - && is_file_compressed(filename, &rc)) + && !opt.explicit_compress_option + && is_file_compressed (peekbuf, peekbuflen)) { if (opt.verbose) - log_info(_("'%s' already compressed\n"), filename); + log_info(_("'%s' already compressed\n"), filename? filename: "[stdin]"); do_compress = 0; } @@ -768,6 +780,8 @@ encrypt_crypt (ctrl_t ctrl, int filefd, const char *filename, progress_filter_context_t *pfx; PK_LIST pk_list; int do_compress; + char peekbuf[32]; + int peekbuflen; if (filefd != -1 && filename) return gpg_error (GPG_ERR_INV_ARG); /* Both given. */ @@ -840,6 +854,14 @@ encrypt_crypt (ctrl_t ctrl, int filefd, const char *filename, if (opt.verbose) log_info (_("reading from '%s'\n"), iobuf_get_fname_nonnull (inp)); + peekbuflen = iobuf_ioctl (inp, IOBUF_IOCTL_PEEK, sizeof peekbuf, peekbuf); + if (peekbuflen < 0) + { + peekbuflen = 0; + if (DBG_FILTER) + log_debug ("peeking at input failed\n"); + } + handle_progress (pfx, inp, filename); if (opt.textmode) @@ -874,10 +896,11 @@ encrypt_crypt (ctrl_t ctrl, int filefd, const char *filename, if (do_compress && (cfx.dek->use_mdc || cfx.dek->use_aead) - && is_file_compressed(filename, &rc2)) + && !opt.explicit_compress_option + && is_file_compressed (peekbuf, peekbuflen)) { if (opt.verbose) - log_info(_("'%s' already compressed\n"), filename); + log_info(_("'%s' already compressed\n"), filename? filename: "[stdin]"); do_compress = 0; } if (rc2) diff --git a/g10/gpg.c b/g10/gpg.c index e7180b818..d7b75a1d8 100644 --- a/g10/gpg.c +++ b/g10/gpg.c @@ -3126,6 +3126,7 @@ main (int argc, char **argv) case oCompress: /* this is the -z command line option */ opt.compress_level = opt.bz2_compress_level = pargs.r.ret_int; + opt.explicit_compress_option = 1; break; case oCompressLevel: opt.compress_level = pargs.r.ret_int; break; case oBZ2CompressLevel: opt.bz2_compress_level = pargs.r.ret_int; break; diff --git a/g10/options.h b/g10/options.h index ccf7397d0..020b558aa 100644 --- a/g10/options.h +++ b/g10/options.h @@ -92,6 +92,7 @@ struct int force_ocb; int cert_digest_algo; int compress_algo; + int explicit_compress_option; /* A compress option was explicitly given. */ int compress_level; int bz2_compress_level; int bz2_decompress_lowmem; diff --git a/g10/sign.c b/g10/sign.c index 17c6bcdf8..eaf9d9ed5 100644 --- a/g10/sign.c +++ b/g10/sign.c @@ -921,62 +921,68 @@ int sign_file (ctrl_t ctrl, strlist_t filenames, int detached, strlist_t locusr, int encryptflag, strlist_t remusr, const char *outfile ) { - const char *fname; - 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; - encrypt_filter_context_t efx; - IOBUF inp = NULL, out = NULL; - PACKET pkt; - int rc = 0; - PK_LIST pk_list = NULL; - SK_LIST sk_list = NULL; - SK_LIST sk_rover = NULL; - int multifile = 0; - u32 duration=0; + const char *fname; + 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; + encrypt_filter_context_t efx; + iobuf_t inp = NULL; + iobuf_t out = NULL; + PACKET pkt; + int rc = 0; + PK_LIST pk_list = NULL; + SK_LIST sk_list = NULL; + SK_LIST sk_rover = NULL; + int multifile = 0; + u32 duration=0; + char peekbuf[32]; + int peekbuflen = 0; - pfx = new_progress_context (); - afx = new_armor_context (); - memset( &zfx, 0, sizeof zfx); - memset( &mfx, 0, sizeof mfx); - memset( &efx, 0, sizeof efx); - efx.ctrl = ctrl; - init_packet( &pkt ); - if( filenames ) { - fname = filenames->d; - multifile = !!filenames->next; + pfx = new_progress_context (); + afx = new_armor_context (); + memset (&zfx, 0, sizeof zfx); + memset (&mfx, 0, sizeof mfx); + memset (&efx, 0, sizeof efx); + efx.ctrl = ctrl; + init_packet (&pkt); + + if (filenames) + { + fname = filenames->d; + multifile = !!filenames->next; } - else - fname = NULL; + else + fname = NULL; - if( fname && filenames->next && (!detached || encryptflag) ) - log_bug("multiple files can only be detached signed"); + if (fname && filenames->next && (!detached || encryptflag)) + log_bug ("multiple files can only be detached signed"); - if(encryptflag==2 - && (rc=setup_symkey(&efx.symkey_s2k,&efx.symkey_dek))) - goto leave; + if (encryptflag == 2 + && (rc = setup_symkey (&efx.symkey_s2k,&efx.symkey_dek))) + goto leave; - if (opt.ask_sig_expire && !opt.batch) - duration = ask_expire_interval(1,opt.def_sig_expire); - else - duration = parse_expire_string(opt.def_sig_expire); + if (opt.ask_sig_expire && !opt.batch) + duration = ask_expire_interval(1,opt.def_sig_expire); + else + duration = parse_expire_string(opt.def_sig_expire); - /* Note: In the old non-agent version the following call used to - unprotect the secret key. This is now done on demand by the agent. */ - if( (rc = build_sk_list (ctrl, locusr, &sk_list, PUBKEY_USAGE_SIG )) ) - goto leave; + /* Note: In the old non-agent version the following call used to + unprotect the secret key. This is now done on demand by the agent. */ + if ((rc = build_sk_list (ctrl, locusr, &sk_list, PUBKEY_USAGE_SIG ))) + goto leave; - if (encryptflag - && (rc=build_pk_list (ctrl, remusr, &pk_list))) - goto leave; + if (encryptflag + && (rc=build_pk_list (ctrl, remusr, &pk_list))) + goto leave; - /* prepare iobufs */ - if( multifile ) /* have list of filenames */ - inp = NULL; /* we do it later */ - else { + /* Prepare iobufs. */ + if (multifile) /* have list of filenames */ + inp = NULL; /* we do it later */ + else + { inp = iobuf_open(fname); if (inp && is_secured_file (iobuf_get_fd (inp))) { @@ -992,274 +998,298 @@ sign_file (ctrl_t ctrl, strlist_t filenames, int detached, strlist_t locusr, goto leave; } - handle_progress (pfx, inp, fname); - } - - if( outfile ) { - if (is_secured_filename ( outfile )) { - out = NULL; - gpg_err_set_errno (EPERM); + peekbuflen = iobuf_ioctl (inp, IOBUF_IOCTL_PEEK, sizeof peekbuf, peekbuf); + if (peekbuflen < 0) + { + peekbuflen = 0; + if (DBG_FILTER) + log_debug ("peeking at input failed\n"); } - else - out = iobuf_create (outfile, 0); - if( !out ) - { - rc = gpg_error_from_syserror (); - log_error(_("can't create '%s': %s\n"), outfile, strerror(errno) ); - goto leave; - } - else if( opt.verbose ) - log_info(_("writing to '%s'\n"), outfile ); + + handle_progress (pfx, inp, fname); } - else if( (rc = open_outfile (-1, fname, - opt.armor? 1: detached? 2:0, 0, &out))) - goto leave; - /* prepare to calculate the MD over the input */ - if( opt.textmode && !outfile && !multifile ) - { - memset( &tfx, 0, sizeof tfx); - iobuf_push_filter( inp, text_filter, &tfx ); - } + if (outfile) + { + if (is_secured_filename ( outfile )) + { + out = NULL; + gpg_err_set_errno (EPERM); + } + else + out = iobuf_create (outfile, 0); + if (!out) + { + rc = gpg_error_from_syserror (); + log_error(_("can't create '%s': %s\n"), outfile, strerror(errno) ); + goto leave; + } + else if (opt.verbose) + log_info (_("writing to '%s'\n"), outfile); + } + else if ((rc = open_outfile (-1, fname, + opt.armor? 1: detached? 2:0, 0, &out))) + goto leave; - if ( gcry_md_open (&mfx.md, 0, 0) ) - BUG (); - if (DBG_HASHING) - gcry_md_debug (mfx.md, "sign"); + /* Prepare to calculate the MD over the input. */ + if (opt.textmode && !outfile && !multifile) + { + memset( &tfx, 0, sizeof tfx); + iobuf_push_filter( inp, text_filter, &tfx ); + } - /* If we're encrypting and signing, it is reasonable to pick the - hash algorithm to use out of the recipient key prefs. This is - best effort only, as in a DSA2 and smartcard world there are - cases where we cannot please everyone with a single hash (DSA2 - wants >160 and smartcards want =160). In the future this could - be more complex with different hashes for each sk, but the - current design requires a single hash for all SKs. */ - if(pk_list) - { - if(opt.def_digest_algo) - { - if(!opt.expert && - select_algo_from_prefs(pk_list,PREFTYPE_HASH, - opt.def_digest_algo, - NULL)!=opt.def_digest_algo) - log_info(_("WARNING: forcing digest algorithm %s (%d)" - " violates recipient preferences\n"), - gcry_md_algo_name (opt.def_digest_algo), - opt.def_digest_algo ); - } - else - { - int algo; - int conflict = 0; - struct pref_hint hint = { 0 }; + if (gcry_md_open (&mfx.md, 0, 0)) + BUG (); + if (DBG_HASHING) + gcry_md_debug (mfx.md, "sign"); - /* Of course, if the recipient asks for something - unreasonable (like the wrong hash for a DSA key) then - don't do it. Check all sk's - if any are DSA or live - on a smartcard, then the hash has restrictions and we - may not be able to give the recipient what they want. - For DSA, pass a hint for the largest q we have. Note - that this means that a q>160 key will override a q=160 - key and force the use of truncation for the q=160 key. - The alternative would be to ignore the recipient prefs - completely and get a different hash for each DSA key in - hash_for(). The override behavior here is more or less - reasonable as it is under the control of the user which - keys they sign with for a given message and the fact - that the message with multiple signatures won't be - usable on an implementation that doesn't understand - DSA2 anyway. */ + /* If we're encrypting and signing, it is reasonable to pick the + * hash algorithm to use out of the recipient key prefs. This is + * best effort only, as in a DSA2 and smartcard world there are + * cases where we cannot please everyone with a single hash (DSA2 + * wants >160 and smartcards want =160). In the future this could + * be more complex with different hashes for each sk, but the + * current design requires a single hash for all SKs. */ + if (pk_list) + { + if (opt.def_digest_algo) + { + if (!opt.expert && + select_algo_from_prefs(pk_list,PREFTYPE_HASH, + opt.def_digest_algo, + NULL)!=opt.def_digest_algo) + log_info (_("WARNING: forcing digest algorithm %s (%d)" + " violates recipient preferences\n"), + gcry_md_algo_name (opt.def_digest_algo), + opt.def_digest_algo ); + } + else + { + int algo; + int conflict = 0; + struct pref_hint hint = { 0 }; - for (sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next ) - { - if (sk_rover->pk->pubkey_algo == PUBKEY_ALGO_DSA - || sk_rover->pk->pubkey_algo == PUBKEY_ALGO_ECDSA) - { - int temp_hashlen = (gcry_mpi_get_nbits - (sk_rover->pk->pkey[1])); + /* Of course, if the recipient asks for something + * unreasonable (like the wrong hash for a DSA key) then + * don't do it. Check all sk's - if any are DSA or live + * on a smartcard, then the hash has restrictions and we + * may not be able to give the recipient what they want. + * For DSA, pass a hint for the largest q we have. Note + * that this means that a q>160 key will override a q=160 + * key and force the use of truncation for the q=160 key. + * The alternative would be to ignore the recipient prefs + * completely and get a different hash for each DSA key in + * hash_for(). The override behavior here is more or less + * reasonable as it is under the control of the user which + * keys they sign with for a given message and the fact + * that the message with multiple signatures won't be + * usable on an implementation that doesn't understand + * DSA2 anyway. */ + for (sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next ) + { + if (sk_rover->pk->pubkey_algo == PUBKEY_ALGO_DSA + || sk_rover->pk->pubkey_algo == PUBKEY_ALGO_ECDSA) + { + int temp_hashlen = (gcry_mpi_get_nbits + (sk_rover->pk->pkey[1])); - if (sk_rover->pk->pubkey_algo == PUBKEY_ALGO_ECDSA) - { - temp_hashlen = ecdsa_qbits_from_Q (temp_hashlen); - if (!temp_hashlen) - conflict = 1; /* Better don't use the prefs. */ - temp_hashlen = (temp_hashlen+7)/8; - /* Fixup for that funny nistp521 (yes, 521) - * were we need to use a 512 bit hash algo. */ - if (temp_hashlen == 66) - temp_hashlen = 64; - } - else + if (sk_rover->pk->pubkey_algo == PUBKEY_ALGO_ECDSA) + { + temp_hashlen = ecdsa_qbits_from_Q (temp_hashlen); + if (!temp_hashlen) + conflict = 1; /* Better don't use the prefs. */ + temp_hashlen = (temp_hashlen+7)/8; + /* Fixup for that funny nistp521 (yes, 521) + * were we need to use a 512 bit hash algo. */ + if (temp_hashlen == 66) + temp_hashlen = 64; + } + else temp_hashlen = (temp_hashlen+7)/8; - /* Pick a hash that is large enough for our - largest q or matches our Q but if tehreare - several of them we run into a conflict and - don't use the preferences. */ - - if (hint.digest_length < temp_hashlen) - { - if (sk_rover->pk->pubkey_algo == PUBKEY_ALGO_ECDSA) - { - if (hint.exact) - conflict = 1; - hint.exact = 1; - } - hint.digest_length = temp_hashlen; - } - } - } - - if (!conflict - && (algo = select_algo_from_prefs (pk_list,PREFTYPE_HASH, - -1,&hint)) > 0) - { - /* Note that we later check that the algo is not weak. */ - recipient_digest_algo = algo; + /* Pick a hash that is large enough for our + * largest q or matches our Q but if tehreare + * several of them we run into a conflict and + * don't use the preferences. */ + if (hint.digest_length < temp_hashlen) + { + if (sk_rover->pk->pubkey_algo == PUBKEY_ALGO_ECDSA) + { + if (hint.exact) + conflict = 1; + hint.exact = 1; + } + hint.digest_length = temp_hashlen; + } } - } - } + } - for (sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next) - gcry_md_enable (mfx.md, hash_for (sk_rover->pk)); - - if( !multifile ) - iobuf_push_filter( inp, md_filter, &mfx ); - - if( detached && !encryptflag) - afx->what = 2; - - if( opt.armor && !outfile ) - push_armor_filter (afx, out); - - if( encryptflag ) { - efx.pk_list = pk_list; - /* fixme: set efx.cfx.datalen if known */ - iobuf_push_filter( out, encrypt_filter, &efx ); + if (!conflict + && (algo = select_algo_from_prefs (pk_list,PREFTYPE_HASH, + -1,&hint)) > 0) + { + /* Note that we later check that the algo is not weak. */ + recipient_digest_algo = algo; + } + } } - if (opt.compress_algo && !outfile && !detached) - { - int compr_algo=opt.compress_algo; + for (sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next) + gcry_md_enable (mfx.md, hash_for (sk_rover->pk)); - /* If not forced by user */ - if(compr_algo==-1) - { - /* If we're not encrypting, then select_algo_from_prefs - will fail and we'll end up with the default. If we are - encrypting, select_algo_from_prefs cannot fail since - there is an assumed preference for uncompressed data. - Still, if it did fail, we'll also end up with the - default. */ + if (!multifile) + iobuf_push_filter (inp, md_filter, &mfx); - if((compr_algo= - select_algo_from_prefs(pk_list,PREFTYPE_ZIP,-1,NULL))==-1) - compr_algo=default_compress_algo(); - } - else if(!opt.expert && pk_list - && select_algo_from_prefs(pk_list,PREFTYPE_ZIP, - compr_algo,NULL)!=compr_algo) - log_info(_("WARNING: forcing compression algorithm %s (%d)" - " violates recipient preferences\n"), - compress_algo_to_string(compr_algo),compr_algo); + if (detached && !encryptflag) + afx->what = 2; - /* algo 0 means no compression */ - if( compr_algo ) - push_compress_filter(out,&zfx,compr_algo); - } + if (opt.armor && !outfile) + push_armor_filter (afx, out); - /* Write the one-pass signature packets if needed */ - if (!detached) { - rc = write_onepass_sig_packets (sk_list, out, - opt.textmode && !outfile ? 0x01:0x00); - if (rc) - goto leave; + if (encryptflag) + { + efx.pk_list = pk_list; + /* fixme: set efx.cfx.datalen if known */ + iobuf_push_filter( out, encrypt_filter, &efx ); } - write_status_begin_signing (mfx.md); + if (opt.compress_algo && !outfile && !detached) + { + int compr_algo = opt.compress_algo; - /* Setup the inner packet. */ - if( detached ) { - if( multifile ) { - strlist_t sl; + if (!opt.explicit_compress_option + && is_file_compressed (peekbuf, peekbuflen)) + { + if (opt.verbose) + log_info(_("'%s' already compressed\n"), fname? fname: "[stdin]"); + compr_algo = 0; + } + else if (compr_algo==-1) + { + /* If we're not encrypting, then select_algo_from_prefs + * will fail and we'll end up with the default. If we are + * encrypting, select_algo_from_prefs cannot fail since + * there is an assumed preference for uncompressed data. + * Still, if it did fail, we'll also end up with the + * default. */ + if ((compr_algo = select_algo_from_prefs (pk_list, PREFTYPE_ZIP, + -1, NULL)) == -1) + { + compr_algo = default_compress_algo(); + } + } + else if (!opt.expert && pk_list + && select_algo_from_prefs (pk_list, PREFTYPE_ZIP, + compr_algo, NULL) != compr_algo) + { + log_info (_("WARNING: forcing compression algorithm %s (%d)" + " violates recipient preferences\n"), + compress_algo_to_string (compr_algo), compr_algo); + } - if( opt.verbose ) - log_info(_("signing:") ); - /* must walk reverse trough this list */ - for( sl = strlist_last(filenames); sl; - sl = strlist_prev( filenames, sl ) ) { - inp = iobuf_open(sl->d); - if (inp && is_secured_file (iobuf_get_fd (inp))) - { - iobuf_close (inp); - inp = NULL; - gpg_err_set_errno (EPERM); - } - if( !inp ) - { - rc = gpg_error_from_syserror (); - log_error(_("can't open '%s': %s\n"), - sl->d,strerror(errno)); - goto leave; - } - handle_progress (pfx, inp, sl->d); - if( opt.verbose ) - log_printf (" '%s'", sl->d ); - if(opt.textmode) - { - memset( &tfx, 0, sizeof tfx); - iobuf_push_filter( inp, text_filter, &tfx ); - } - iobuf_push_filter( inp, md_filter, &mfx ); - while (iobuf_read (inp, NULL, 1<<30) != -1 ) - ; - iobuf_close(inp); inp = NULL; - } - if( opt.verbose ) - log_printf ("\n"); - } - else { - /* read, so that the filter can calculate the digest */ - while (iobuf_read (inp, NULL, 1<<30) != -1 ) - ; - } - } - else { - rc = write_plaintext_packet (out, inp, fname, - opt.textmode && !outfile ? - (opt.mimemode? 'm':'t'):'b'); + /* Algo 0 means no compression. */ + if (compr_algo) + push_compress_filter (out, &zfx, compr_algo); } - /* catch errors from above */ - if (rc) - goto leave; - - /* write the signatures */ - rc = write_signature_packets (ctrl, sk_list, out, mfx.md, - opt.textmode && !outfile? 0x01 : 0x00, - 0, duration, detached ? 'D':'S', NULL); - if( rc ) + /* Write the one-pass signature packets if needed */ + if (!detached) + { + rc = write_onepass_sig_packets (sk_list, out, + opt.textmode && !outfile ? 0x01:0x00); + if (rc) goto leave; - - - leave: - if( rc ) - iobuf_cancel(out); - else { - iobuf_close(out); - if (encryptflag) - write_status( STATUS_END_ENCRYPTION ); } - iobuf_close(inp); - gcry_md_close ( mfx.md ); - release_sk_list( sk_list ); - release_pk_list( pk_list ); - recipient_digest_algo=0; - release_progress_context (pfx); - release_armor_context (afx); - return rc; -} + write_status_begin_signing (mfx.md); + + /* Setup the inner packet. */ + if (detached) + { + if (multifile) + { + strlist_t sl; + + if (opt.verbose) + log_info(_("signing:") ); + /* Must walk reverse trough this list. */ + for (sl = strlist_last (filenames); sl; + sl = strlist_prev (filenames, sl)) + { + inp = iobuf_open(sl->d); + if (inp && is_secured_file (iobuf_get_fd (inp))) + { + iobuf_close (inp); + inp = NULL; + gpg_err_set_errno (EPERM); + } + if (!inp) + { + rc = gpg_error_from_syserror (); + log_error(_("can't open '%s': %s\n"), + sl->d,strerror(errno)); + goto leave; + } + handle_progress (pfx, inp, sl->d); + if (opt.verbose) + log_printf (" '%s'", sl->d ); + if (opt.textmode) + { + memset( &tfx, 0, sizeof tfx); + iobuf_push_filter( inp, text_filter, &tfx ); + } + iobuf_push_filter( inp, md_filter, &mfx ); + while (iobuf_read (inp, NULL, 1<<30) != -1 ) + ; + iobuf_close(inp); inp = NULL; + } + if (opt.verbose) + log_printf ("\n"); + } + else + { + /* Read, so that the filter can calculate the digest. */ + while (iobuf_read (inp, NULL, 1<<30) != -1 ) + ; + } + } + else + { + rc = write_plaintext_packet (out, inp, fname, + opt.textmode && !outfile ? + (opt.mimemode? 'm':'t'):'b'); + } + + /* Catch errors from above. */ + if (rc) + goto leave; + + /* Write the signatures. */ + rc = write_signature_packets (ctrl, sk_list, out, mfx.md, + opt.textmode && !outfile? 0x01 : 0x00, + 0, duration, detached ? 'D':'S', NULL); + if (rc) + goto leave; + + + leave: + if (rc) + iobuf_cancel (out); + else + { + iobuf_close(out); + if (encryptflag) + write_status( STATUS_END_ENCRYPTION ); + } + iobuf_close(inp); + gcry_md_close ( mfx.md ); + release_sk_list( sk_list ); + release_pk_list( pk_list ); + recipient_digest_algo=0; + release_progress_context (pfx); + release_armor_context (afx); + return rc; +} /****************