X-Git-Url: http://git.gnupg.org/cgi-bin/gitweb.cgi?p=gnupg.git;a=blobdiff_plain;f=g10%2Fmainproc.c;h=50d1d2713ad8ae275affd3c319769593ccaf08cf;hp=dc7988987e9cb734639066ba7aa64158b7dc3f0b;hb=1b8decc4767f0c55867327bdf3113204efcd19a7;hpb=0173cd5a9810622e38b76123528e83024fb59a0c diff --git a/g10/mainproc.c b/g10/mainproc.c index dc7988987..50d1d2713 100644 --- a/g10/mainproc.c +++ b/g10/mainproc.c @@ -1,12 +1,13 @@ /* mainproc.c - handle packets - * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, - * 2005, 2006 Free Software Foundation, Inc. + * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, + * 2008, 2009 Free Software Foundation, Inc. + * Copyright (C) 2013, 2014 Werner Koch * * This file is part of GnuPG. * * GnuPG is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or + * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GnuPG is distributed in the hope that it will be useful, @@ -15,9 +16,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, - * USA. + * along with this program; if not, see . */ #include @@ -28,11 +27,10 @@ #include #include "gpg.h" +#include "util.h" #include "packet.h" #include "iobuf.h" #include "options.h" -#include "util.h" -#include "cipher.h" #include "keydb.h" #include "filter.h" #include "main.h" @@ -44,6 +42,11 @@ #include "pka.h" +/* Put an upper limit on nested packets. The 32 is an arbitrary + value, a much lower should actually be sufficient. */ +#define MAX_NESTING_DEPTH 32 + + struct kidlist_item { struct kidlist_item *next; u32 kid[2]; @@ -58,32 +61,59 @@ struct kidlist_item { typedef struct mainproc_context *CTX; struct mainproc_context { + ctrl_t ctrl; struct mainproc_context *anchor; /* May be useful in the future. */ PKT_public_key *last_pubkey; - PKT_secret_key *last_seckey; PKT_user_id *last_user_id; md_filter_context_t mfx; int sigs_only; /* Process only signatures and reject all other stuff. */ int encrypt_only; /* Process only encryption messages. */ - strlist_t signed_data; + + /* Name of the file with the complete signature or the file with the + detached signature. This is currently only used to deduce the + file name of the data file if that has not been given. */ const char *sigfilename; + + /* A structure to describe the signed data in case of a detached + signature. */ + struct + { + /* A file descriptor of the the signed data. Only used if not -1. */ + int data_fd; + /* A list of filenames with the data files or NULL. This is only + used if DATA_FD is -1. */ + strlist_t data_names; + /* Flag to indicated that either one of the next previous fields + is used. This is only needed for better readability. */ + int used; + } signed_data; + DEK *dek; int last_was_session_key; KBNODE list; /* The current list of packets. */ - int have_data; IOBUF iobuf; /* Used to get the filename etc. */ int trustletter; /* Temporary usage in list_node. */ ulong symkeys; struct kidlist_item *pkenc_list; /* List of encryption packets. */ - int any_sig_seen; /* Set to true if a signature packet has been seen. */ + struct { + unsigned int sig_seen:1; /* Set to true if a signature packet + has been seen. */ + unsigned int data:1; /* Any data packet seen */ + unsigned int uncompress_failed:1; + } any; }; static int do_proc_packets( CTX c, IOBUF a ); - static void list_node( CTX c, KBNODE node ); static void proc_tree( CTX c, KBNODE node ); +static int literals_seen; +void +reset_literals_seen(void) +{ + literals_seen=0; +} static void release_list( CTX c ) @@ -99,7 +129,8 @@ release_list( CTX c ) } c->pkenc_list = NULL; c->list = NULL; - c->have_data = 0; + c->any.data = 0; + c->any.uncompress_failed = 0; c->last_was_session_key = 0; xfree(c->dek); c->dek = NULL; } @@ -126,7 +157,7 @@ add_gpg_control( CTX c, PACKET *pkt ) /* New clear text signature. * Process the last one and reset everything */ release_list(c); - } + } if( c->list ) /* add another packet */ add_kbnode( c->list, new_kbnode( pkt )); @@ -177,7 +208,7 @@ add_signature( CTX c, PACKET *pkt ) { KBNODE node; - c->any_sig_seen = 1; + c->any.sig_seen = 1; if( pkt->pkttype == PKT_SIGNATURE && !c->list ) { /* This is the first signature for the following datafile. * GPG does not write such packets; instead it always uses @@ -212,7 +243,7 @@ symkey_decrypt_seskey( DEK *dek, byte *seskey, size_t slen ) return G10ERR_BAD_KEY; } - if (gcry_cipher_open (&hd, dek->algo, GCRY_CIPHER_MODE_CFB, 1)) + if (openpgp_cipher_open (&hd, dek->algo, GCRY_CIPHER_MODE_CFB, 1)) BUG (); if (gcry_cipher_setkey ( hd, dek->key, dek->keylen )) BUG (); @@ -229,18 +260,12 @@ symkey_decrypt_seskey( DEK *dek, byte *seskey, size_t slen ) if(dek->keylen > DIM(dek->key)) BUG (); - /* This is not completely accurate, since a bad passphrase may have - resulted in a garbage algorithm byte, but it's close enough since - a bogus byte here will fail later. */ - if(dek->algo==CIPHER_ALGO_IDEA) - idea_cipher_warn(0); - memcpy(dek->key, seskey + 1, dek->keylen); /*log_hexdump( "thekey", dek->key, dek->keylen );*/ return 0; -} +} static void proc_symkey_enc( CTX c, PACKET *pkt ) @@ -253,9 +278,9 @@ proc_symkey_enc( CTX c, PACKET *pkt ) else if(!c->dek) { int algo = enc->cipher_algo; - const char *s = gcry_cipher_algo_name (algo); + const char *s = openpgp_cipher_algo_name (algo); - if(s) + if (!openpgp_cipher_test_algo (algo)) { if(!opt.quiet) { @@ -290,7 +315,7 @@ proc_symkey_enc( CTX c, PACKET *pkt ) } else { - c->dek = passphrase_to_dek (NULL, 0, algo, &enc->s2k, 0, + c->dek = passphrase_to_dek (NULL, 0, algo, &enc->s2k, 3, NULL, NULL); if(c->dek) { @@ -340,7 +365,13 @@ proc_pubkey_enc( CTX c, PACKET *pkt ) if( is_status_enabled() ) { char buf[50]; - sprintf(buf, "%08lX%08lX %d 0", + /* FIXME: For ECC support we need to map the OpenPGP algo + number to the Libgcrypt definef one. This is due a + chicken-egg problem: We need to have code in libgcrypt for + a new algorithm so to implement a proposed new algorithm + before the IANA will finally assign an OpenPGP + indentifier. */ + snprintf (buf, sizeof buf, "%08lX%08lX %d 0", (ulong)enc->keyid[0], (ulong)enc->keyid[1], enc->pubkey_algo ); write_status_text( STATUS_ENC_TO, buf ); } @@ -356,13 +387,22 @@ proc_pubkey_enc( CTX c, PACKET *pkt ) } } else if( is_ELGAMAL(enc->pubkey_algo) - || enc->pubkey_algo == PUBKEY_ALGO_DSA - || is_RSA(enc->pubkey_algo) ) { - /* FIXME: strore this all in a list and process it later */ - + || enc->pubkey_algo == PUBKEY_ALGO_DSA + || enc->pubkey_algo == PUBKEY_ALGO_ECDSA + || enc->pubkey_algo == PUBKEY_ALGO_EDDSA + || enc->pubkey_algo == PUBKEY_ALGO_ECDH + || is_RSA(enc->pubkey_algo) + || enc->pubkey_algo == PUBKEY_ALGO_ELGAMAL) { + /* Note that we also allow type 20 Elgamal keys for decryption. + There are still a couple of those keys in active use as a + subkey. */ + + /* FIXME: Store this all in a list and process it later so that + we can prioritize what key to use. This gives a better user + experience if wildcard keyids are used. */ if ( !c->dek && ((!enc->keyid[0] && !enc->keyid[1]) || opt.try_all_secrets - || !seckey_available( enc->keyid )) ) { + || have_secret_key_with_kid (enc->keyid)) ) { if( opt.list_only ) result = -1; else { @@ -411,13 +451,13 @@ print_pkenc_list( struct kidlist_item *list, int failed ) for( ; list; list = list->next ) { PKT_public_key *pk; const char *algstr; - + if ( failed && !list->reason ) continue; if ( !failed && list->reason ) continue; - algstr = gcry_pk_algo_name ( list->pubkey_algo ); + algstr = openpgp_pk_algo_name ( list->pubkey_algo ); pk = xmalloc_clear( sizeof *pk ); if( !algstr ) @@ -442,14 +482,17 @@ print_pkenc_list( struct kidlist_item *list, int failed ) if( list->reason == G10ERR_NO_SECKEY ) { if( is_status_enabled() ) { char buf[20]; - sprintf(buf,"%08lX%08lX", (ulong)list->kid[0], - (ulong)list->kid[1] ); + snprintf (buf, sizeof buf, "%08lX%08lX", + (ulong)list->kid[0], (ulong)list->kid[1]); write_status_text( STATUS_NO_SECKEY, buf ); } } else if (list->reason) + { log_info(_("public key decryption failed: %s\n"), g10_errstr(list->reason)); + write_status_error ("pkdecrypt_failed", list->reason); + } } } @@ -497,16 +540,15 @@ proc_encrypted( CTX c, PACKET *pkt ) algo = opt.def_cipher_algo; if ( algo ) log_info (_("assuming %s encrypted data\n"), - gcry_cipher_algo_name (algo)); - else if ( gcry_cipher_test_algo (CIPHER_ALGO_IDEA) ) + openpgp_cipher_algo_name (algo)); + else if ( openpgp_cipher_test_algo (CIPHER_ALGO_IDEA) ) { algo = opt.def_cipher_algo; if (!algo) algo = opt.s2k_cipher_algo; - idea_cipher_warn(1); log_info (_("IDEA cipher unavailable, " "optimistically attempting to use %s instead\n"), - gcry_cipher_algo_name (algo)); + openpgp_cipher_algo_name (algo)); } else { @@ -521,15 +563,16 @@ 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, NULL ); + c->dek = passphrase_to_dek ( NULL, 0, algo, s2k, 3, NULL, NULL ); if (c->dek) c->dek->algo_info_printed = 1; } } else if( !c->dek ) result = G10ERR_NO_SECKEY; - if( !result ) - result = decrypt_data( c, pkt->pkt.encrypted, c->dek ); + + if (!result) + result = decrypt_data (c->ctrl, c, pkt->pkt.encrypted, c->dek ); if( result == -1 ) ; @@ -542,23 +585,22 @@ proc_encrypted( CTX c, PACKET *pkt ) write_status( STATUS_GOODMDC ); else if(!opt.no_mdc_warn) log_info (_("WARNING: message was not integrity protected\n")); - if(opt.show_session_key) - { - int i; - char *buf = xmalloc ( c->dek->keylen*2 + 20 ); - sprintf ( buf, "%d:", c->dek->algo ); - for(i=0; i < c->dek->keylen; i++ ) - sprintf(buf+strlen(buf), "%02X", c->dek->key[i] ); - log_info( "session key: `%s'\n", buf ); - write_status_text ( STATUS_SESSION_KEY, buf ); - } } else if( result == G10ERR_BAD_SIGN ) { + glo_ctrl.lasterr = result; log_error(_("WARNING: encrypted message has been manipulated!\n")); write_status( STATUS_BADMDC ); write_status( STATUS_DECRYPTION_FAILED ); } else { + if (gpg_err_code (result) == GPG_ERR_BAD_KEY + && *c->dek->s2k_cacheid != '\0') + { + log_debug(_("cleared passphrase cached with ID: %s\n"), + c->dek->s2k_cacheid); + passphrase_clear_cache (NULL, c->dek->s2k_cacheid, 0); + } + glo_ctrl.lasterr = result; write_status( STATUS_DECRYPTION_FAILED ); log_error(_("decryption failed: %s\n"), g10_errstr(result)); /* Hmmm: does this work when we have encrypted using multiple @@ -578,8 +620,10 @@ proc_plaintext( CTX c, PACKET *pkt ) int any, clearsig, only_md5, rc; KBNODE n; + literals_seen++; + if( pt->namelen == 8 && !memcmp( pt->name, "_CONSOLE", 8 ) ) - log_info(_("NOTE: sender requested \"for-your-eyes-only\"\n")); + log_info(_("Note: sender requested \"for-your-eyes-only\"\n")); else if( opt.verbose ) log_info(_("original file name='%.*s'\n"), pt->namelen, pt->name); free_md_filter_context( &c->mfx ); @@ -621,7 +665,7 @@ proc_plaintext( CTX c, PACKET *pkt ) /* check that we have at least the sigclass and one hash */ if ( datalen < 2 ) - log_fatal("invalid control packet CTRLPKT_CLEARSIGN_START\n"); + log_fatal("invalid control packet CTRLPKT_CLEARSIGN_START\n"); /* Note that we don't set the clearsig flag for not-dash-escaped * documents */ clearsig = (*data == 0x01); @@ -650,7 +694,8 @@ proc_plaintext( CTX c, PACKET *pkt ) gcry_md_enable( c->mfx.md, DIGEST_ALGO_SHA1 ); gcry_md_enable( c->mfx.md, DIGEST_ALGO_MD5 ); } - if( opt.pgp2_workarounds && only_md5 && !opt.skip_verify ) { + if (opt.pgp2_workarounds && only_md5 && !opt.skip_verify + && opt.flags.allow_weak_digest_algos) { /* This is a kludge to work around a bug in pgp2. It does only * catch those mails which are armored. To catch the non-armored * pgp mails we could see whether there is the signature packet @@ -660,17 +705,34 @@ proc_plaintext( CTX c, PACKET *pkt ) BUG (); } if ( DBG_HASHING ) { - gcry_md_start_debug ( c->mfx.md, "verify" ); + gcry_md_debug ( c->mfx.md, "verify" ); if ( c->mfx.md2 ) - gcry_md_start_debug ( c->mfx.md2, "verify2" ); + gcry_md_debug ( c->mfx.md2, "verify2" ); } - rc = handle_plaintext( pt, &c->mfx, c->sigs_only, clearsig ); - if ( gpg_err_code (rc) == GPG_ERR_EACCES && !c->sigs_only ) + rc=0; + + if (literals_seen>1) { - /* Can't write output but we hash it anyway to check the - signature. */ - rc = handle_plaintext( pt, &c->mfx, 1, clearsig ); + log_info (_("WARNING: multiple plaintexts seen\n")); + + if (!opt.flags.allow_multiple_messages) + { + write_status_text (STATUS_ERROR, "proc_pkt.plaintext 89_BAD_DATA"); + log_inc_errorcount (); + rc = gpg_error (GPG_ERR_UNEXPECTED); + } + } + + if(!rc) + { + rc = handle_plaintext( pt, &c->mfx, c->sigs_only, clearsig ); + if ( gpg_err_code (rc) == GPG_ERR_EACCES && !c->sigs_only ) + { + /* Can't write output but we hash it anyway to check the + signature. */ + rc = handle_plaintext( pt, &c->mfx, 1, clearsig ); + } } if( rc ) @@ -684,7 +746,7 @@ proc_plaintext( CTX c, PACKET *pkt ) n = new_kbnode (create_gpg_control (CTRLPKT_PLAINTEXT_MARK, NULL, 0)); if (c->list) add_kbnode (c->list, n); - else + else c->list = n; } @@ -692,35 +754,54 @@ proc_plaintext( CTX c, PACKET *pkt ) static int proc_compressed_cb( IOBUF a, void *info ) { - return proc_signature_packets( info, a, ((CTX)info)->signed_data, - ((CTX)info)->sigfilename ); + if ( ((CTX)info)->signed_data.used + && ((CTX)info)->signed_data.data_fd != -1) + return proc_signature_packets_by_fd (((CTX)info)->ctrl, info, a, + ((CTX)info)->signed_data.data_fd); + else + return proc_signature_packets (((CTX)info)->ctrl, info, a, + ((CTX)info)->signed_data.data_names, + ((CTX)info)->sigfilename ); } static int -proc_encrypt_cb( IOBUF a, void *info ) +proc_encrypt_cb (IOBUF a, void *info ) { - return proc_encryption_packets( info, a ); + CTX c = info; + return proc_encryption_packets (c->ctrl, info, a ); } -static void +static int proc_compressed( CTX c, PACKET *pkt ) { - PKT_compressed *zd = pkt->pkt.compressed; - int rc; + PKT_compressed *zd = pkt->pkt.compressed; + int rc; + + /*printf("zip: compressed data packet\n");*/ + if (c->sigs_only) + rc = handle_compressed (c->ctrl, c, zd, proc_compressed_cb, c); + else if( c->encrypt_only ) + rc = handle_compressed (c->ctrl, c, zd, proc_encrypt_cb, c); + else + rc = handle_compressed (c->ctrl, c, zd, NULL, NULL); + + if (gpg_err_code (rc) == GPG_ERR_BAD_DATA) + { + if (!c->any.uncompress_failed) + { + CTX cc; - /*printf("zip: compressed data packet\n");*/ - if( !zd->algorithm ) - rc=G10ERR_COMPR_ALGO; - else if( c->sigs_only ) - rc = handle_compressed( c, zd, proc_compressed_cb, c ); - else if( c->encrypt_only ) - rc = handle_compressed( c, zd, proc_encrypt_cb, c ); - else - rc = handle_compressed( c, zd, NULL, NULL ); - if( rc ) - log_error("uncompressing failed: %s\n", g10_errstr(rc)); - free_packet(pkt); - c->last_was_session_key = 0; + for (cc=c; cc; cc = cc->anchor) + cc->any.uncompress_failed = 1; + log_error ("uncompressing failed: %s\n", gpg_strerror (rc)); + } + } + else if (rc) + log_error ("uncompressing failed: %s\n", gpg_strerror (rc)); + + free_packet(pkt); + c->last_was_session_key = 0; + return rc; } /**************** @@ -781,7 +862,7 @@ do_check_sig( CTX c, KBNODE node, int *is_selfsig, || sig->sig_class == 0x1f || sig->sig_class == 0x20 || sig->sig_class == 0x28 - || sig->sig_class == 0x30 ) { + || sig->sig_class == 0x30 ) { if( c->list->pkt->pkttype == PKT_PUBLIC_KEY || c->list->pkt->pkttype == PKT_PUBLIC_SUBKEY ) { return check_key_signature( c->list, node, is_selfsig ); @@ -825,12 +906,12 @@ print_userid( PACKET *pkt ) pkt->pkt.user_id->numattribs, pkt->pkt.user_id->attrib_len); else - print_string( stdout, pkt->pkt.user_id->name, - pkt->pkt.user_id->len, ':'); + es_write_sanitized (es_stdout, pkt->pkt.user_id->name, + pkt->pkt.user_id->len, ":", NULL); } else - print_utf8_string( stdout, pkt->pkt.user_id->name, - pkt->pkt.user_id->len ); + print_utf8_buffer (es_stdout, pkt->pkt.user_id->name, + pkt->pkt.user_id->len ); } @@ -841,272 +922,214 @@ print_userid( PACKET *pkt ) static void list_node( CTX c, KBNODE node ) { - int any=0; - int mainkey; + int mainkey; + char pkstrbuf[PUBKEY_STRING_SIZE]; - if( !node ) - ; - else if( (mainkey = (node->pkt->pkttype == PKT_PUBLIC_KEY) ) - || node->pkt->pkttype == PKT_PUBLIC_SUBKEY ) { - PKT_public_key *pk = node->pkt->pkt.public_key; + if (!node) + ; + else if ((mainkey = (node->pkt->pkttype == PKT_PUBLIC_KEY)) + || node->pkt->pkttype == PKT_PUBLIC_SUBKEY ) + { + PKT_public_key *pk = node->pkt->pkt.public_key; - if( opt.with_colons ) - { - u32 keyid[2]; - keyid_from_pk( pk, keyid ); - if( mainkey ) - c->trustletter = opt.fast_list_mode? - 0 : get_validity_info( pk, NULL ); - printf("%s:", mainkey? "pub":"sub" ); - if( c->trustletter ) - putchar( c->trustletter ); - printf(":%u:%d:%08lX%08lX:%s:%s::", - nbits_from_pk( pk ), - pk->pubkey_algo, - (ulong)keyid[0],(ulong)keyid[1], - colon_datestr_from_pk( pk ), - colon_strtime (pk->expiredate) ); - if( mainkey && !opt.fast_list_mode ) - putchar( get_ownertrust_info (pk) ); - putchar(':'); - if( node->next && node->next->pkt->pkttype == PKT_RING_TRUST) { - putchar('\n'); any=1; - if( opt.fingerprint ) - print_fingerprint( pk, NULL, 0 ); - printf("rtv:1:%u:\n", - node->next->pkt->pkt.ring_trust->trustval ); - } - } - else - printf("%s %4u%c/%s %s%s", - mainkey? "pub":"sub", nbits_from_pk( pk ), - pubkey_letter( pk->pubkey_algo ), keystr_from_pk( pk ), - datestr_from_pk( pk ), mainkey?" ":""); - - if( mainkey ) { - /* and now list all userids with their signatures */ - for( node = node->next; node; node = node->next ) { - if( node->pkt->pkttype == PKT_SIGNATURE ) { - if( !any ) { - if( node->pkt->pkt.signature->sig_class == 0x20 ) - puts("[revoked]"); - else - putchar('\n'); - any = 1; - } - list_node(c, node ); - } - else if( node->pkt->pkttype == PKT_USER_ID ) { - if( any ) { - if( opt.with_colons ) - printf("%s:::::::::", - node->pkt->pkt.user_id->attrib_data?"uat":"uid"); - else - printf( "uid%*s", 28, "" ); - } - print_userid( node->pkt ); - if( opt.with_colons ) - putchar(':'); - putchar('\n'); - if( opt.fingerprint && !any ) - print_fingerprint( pk, NULL, 0 ); - if( opt.with_colons - && node->next - && node->next->pkt->pkttype == PKT_RING_TRUST ) { - printf("rtv:2:%u:\n", - node->next->pkt->pkt.ring_trust? - node->next->pkt->pkt.ring_trust->trustval : 0); - } - any=1; - } - else if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY ) { - if( !any ) { - putchar('\n'); - any = 1; - } - list_node(c, node ); - } - } - } - else - { - /* of subkey */ - if( pk->is_revoked ) - { - printf(" ["); - printf(_("revoked: %s"),revokestr_from_pk(pk)); - printf("]"); - } - else if( pk->expiredate ) - { - printf(" ["); - printf(_("expires: %s"),expirestr_from_pk(pk)); - printf("]"); - } - } + if (opt.with_colons) + { + u32 keyid[2]; + + keyid_from_pk( pk, keyid ); + if (mainkey) + c->trustletter = (opt.fast_list_mode? + 0 : get_validity_info( pk, NULL)); + es_printf ("%s:", mainkey? "pub":"sub" ); + if (c->trustletter) + es_putc (c->trustletter, es_stdout); + es_printf (":%u:%d:%08lX%08lX:%s:%s::", + nbits_from_pk( pk ), + pk->pubkey_algo, + (ulong)keyid[0],(ulong)keyid[1], + colon_datestr_from_pk( pk ), + colon_strtime (pk->expiredate) ); + if (mainkey && !opt.fast_list_mode) + es_putc (get_ownertrust_info (pk), es_stdout); + es_putc (':', es_stdout); + } + else + es_printf ("%s %s/%s %s", + mainkey? "pub":"sub", + pubkey_string (pk, pkstrbuf, sizeof pkstrbuf), + keystr_from_pk (pk), + datestr_from_pk (pk)); + + if (pk->flags.revoked) + { + es_printf (" ["); + es_printf (_("revoked: %s"), revokestr_from_pk (pk)); + es_printf ("]\n"); + } + else if( pk->expiredate && !opt.with_colons) + { + es_printf (" ["); + es_printf (_("expires: %s"), expirestr_from_pk (pk)); + es_printf ("]\n"); + } + else + es_putc ('\n', es_stdout); - if( !any ) - putchar('\n'); - if( !mainkey && opt.fingerprint > 1 ) - print_fingerprint( pk, NULL, 0 ); - } - else if( (mainkey = (node->pkt->pkttype == PKT_SECRET_KEY) ) - || node->pkt->pkttype == PKT_SECRET_SUBKEY ) { - PKT_secret_key *sk = node->pkt->pkt.secret_key; + if ((mainkey && opt.fingerprint) || opt.fingerprint > 1) + print_fingerprint (NULL, pk, 0); - if( opt.with_colons ) - { - u32 keyid[2]; - keyid_from_sk( sk, keyid ); - printf("%s::%u:%d:%08lX%08lX:%s:%s:::", - mainkey? "sec":"ssb", - nbits_from_sk( sk ), - sk->pubkey_algo, - (ulong)keyid[0],(ulong)keyid[1], - colon_datestr_from_sk( sk ), - colon_strtime (sk->expiredate) - /* fixme: add LID */ ); - } - else - printf("%s %4u%c/%s %s ", mainkey? "sec":"ssb", - nbits_from_sk( sk ), pubkey_letter( sk->pubkey_algo ), - keystr_from_sk( sk ), datestr_from_sk( sk )); - if( mainkey ) { - /* and now list all userids with their signatures */ - for( node = node->next; node; node = node->next ) { - if( node->pkt->pkttype == PKT_SIGNATURE ) { - if( !any ) { - if( node->pkt->pkt.signature->sig_class == 0x20 ) - puts("[revoked]"); - else - putchar('\n'); - any = 1; - } - list_node(c, node ); - } - else if( node->pkt->pkttype == PKT_USER_ID ) { - if( any ) { - if( opt.with_colons ) - printf("%s:::::::::", - node->pkt->pkt.user_id->attrib_data?"uat":"uid"); - else - printf( "uid%*s", 28, "" ); - } - print_userid( node->pkt ); - if( opt.with_colons ) - putchar(':'); - putchar('\n'); - if( opt.fingerprint && !any ) - print_fingerprint( NULL, sk, 0 ); - any=1; - } - else if( node->pkt->pkttype == PKT_SECRET_SUBKEY ) { - if( !any ) { - putchar('\n'); - any = 1; - } - list_node(c, node ); + if (opt.with_colons) + { + if (node->next && node->next->pkt->pkttype == PKT_RING_TRUST) + es_printf ("rtv:1:%u:\n", + node->next->pkt->pkt.ring_trust->trustval); + } + + if (mainkey) + { + /* Now list all userids with their signatures. */ + for (node = node->next; node; node = node->next) + { + if (node->pkt->pkttype == PKT_SIGNATURE) + { + list_node (c, node ); + } + else if (node->pkt->pkttype == PKT_USER_ID) + { + if (opt.with_colons) + es_printf ("%s:::::::::", + node->pkt->pkt.user_id->attrib_data?"uat":"uid"); + else + es_printf ("uid%*s", 28, "" ); + print_userid (node->pkt); + if (opt.with_colons) + es_putc (':', es_stdout); + es_putc ('\n', es_stdout); + if (opt.with_colons + && node->next + && node->next->pkt->pkttype == PKT_RING_TRUST) + { + es_printf ("rtv:2:%u:\n", + node->next->pkt->pkt.ring_trust? + node->next->pkt->pkt.ring_trust->trustval : 0); + } } - } - } - if( !any ) - putchar('\n'); - if( !mainkey && opt.fingerprint > 1 ) - print_fingerprint( NULL, sk, 0 ); + else if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY) + { + list_node(c, node ); + } + } + } } - else if( node->pkt->pkttype == PKT_SIGNATURE ) { - PKT_signature *sig = node->pkt->pkt.signature; - int is_selfsig = 0; - int rc2=0; - size_t n; - char *p; - int sigrc = ' '; + else if ((mainkey = (node->pkt->pkttype == PKT_SECRET_KEY) ) + || node->pkt->pkttype == PKT_SECRET_SUBKEY) + { - if( !opt.verbose ) - return; + log_debug ("FIXME: No way to print secret key packets here\n"); + /* fixme: We may use a fucntion to turn a secret key packet into + a public key one and use that here. */ + } + else if (node->pkt->pkttype == PKT_SIGNATURE) + { + PKT_signature *sig = node->pkt->pkt.signature; + int is_selfsig = 0; + int rc2 = 0; + size_t n; + char *p; + int sigrc = ' '; + + if (!opt.verbose) + return; - if( sig->sig_class == 0x20 || sig->sig_class == 0x30 ) - fputs("rev", stdout); - else - fputs("sig", stdout); - if( opt.check_sigs ) { - fflush(stdout); - rc2=do_check_sig( c, node, &is_selfsig, NULL, NULL ); - switch (gpg_err_code (rc2)) { - case 0: sigrc = '!'; break; - case GPG_ERR_BAD_SIGNATURE: sigrc = '-'; break; - case GPG_ERR_NO_PUBKEY: - case GPG_ERR_UNUSABLE_PUBKEY: sigrc = '?'; break; - default: sigrc = '%'; break; + if (sig->sig_class == 0x20 || sig->sig_class == 0x30) + es_fputs ("rev", es_stdout); + else + es_fputs ("sig", es_stdout); + if (opt.check_sigs) + { + fflush (stdout); + rc2 = do_check_sig (c, node, &is_selfsig, NULL, NULL); + switch (gpg_err_code (rc2)) + { + case 0: sigrc = '!'; break; + case GPG_ERR_BAD_SIGNATURE: sigrc = '-'; break; + case GPG_ERR_NO_PUBKEY: + case GPG_ERR_UNUSABLE_PUBKEY: sigrc = '?'; break; + default: sigrc = '%'; break; } } - else { /* check whether this is a self signature */ - u32 keyid[2]; + else /* Check whether this is a self signature. */ + { + u32 keyid[2]; - if( c->list->pkt->pkttype == PKT_PUBLIC_KEY - || c->list->pkt->pkttype == PKT_SECRET_KEY ) { - if( c->list->pkt->pkttype == PKT_PUBLIC_KEY ) - keyid_from_pk( c->list->pkt->pkt.public_key, keyid ); - else - keyid_from_sk( c->list->pkt->pkt.secret_key, keyid ); + if (c->list->pkt->pkttype == PKT_PUBLIC_KEY + || c->list->pkt->pkttype == PKT_SECRET_KEY ) + { + keyid_from_pk (c->list->pkt->pkt.public_key, keyid); - if( keyid[0] == sig->keyid[0] && keyid[1] == sig->keyid[1] ) - is_selfsig = 1; - } + if (keyid[0] == sig->keyid[0] && keyid[1] == sig->keyid[1]) + is_selfsig = 1; + } } - if( opt.with_colons ) { - putchar(':'); - if( sigrc != ' ' ) - putchar(sigrc); - printf("::%d:%08lX%08lX:%s:%s:", sig->pubkey_algo, - (ulong)sig->keyid[0], (ulong)sig->keyid[1], - colon_datestr_from_sig(sig), - colon_expirestr_from_sig(sig)); - - if(sig->trust_depth || sig->trust_value) - printf("%d %d",sig->trust_depth,sig->trust_value); - printf(":"); - - if(sig->trust_regexp) - print_string(stdout,sig->trust_regexp, - strlen(sig->trust_regexp),':'); - printf(":"); + + if (opt.with_colons) + { + es_putc (':', es_stdout); + if (sigrc != ' ') + es_putc (sigrc, es_stdout); + es_printf ("::%d:%08lX%08lX:%s:%s:", sig->pubkey_algo, + (ulong)sig->keyid[0], (ulong)sig->keyid[1], + colon_datestr_from_sig (sig), + colon_expirestr_from_sig (sig)); + + if (sig->trust_depth || sig->trust_value) + es_printf ("%d %d",sig->trust_depth,sig->trust_value); + es_putc (':', es_stdout); + + if (sig->trust_regexp) + es_write_sanitized (es_stdout, sig->trust_regexp, + strlen (sig->trust_regexp), ":", NULL); + es_putc (':', es_stdout); } - else - printf("%c %s %s ", - sigrc, keystr(sig->keyid), datestr_from_sig(sig)); - if( sigrc == '%' ) - printf("[%s] ", g10_errstr(rc2) ); - else if( sigrc == '?' ) - ; - else if( is_selfsig ) { - if( opt.with_colons ) - putchar(':'); - fputs( sig->sig_class == 0x18? "[keybind]":"[selfsig]", stdout); - if( opt.with_colons ) - putchar(':'); + else + es_printf ("%c %s %s ", + sigrc, keystr (sig->keyid), datestr_from_sig(sig)); + if (sigrc == '%') + es_printf ("[%s] ", g10_errstr(rc2) ); + else if (sigrc == '?') + ; + else if (is_selfsig) + { + if (opt.with_colons) + es_putc (':', es_stdout); + es_fputs (sig->sig_class == 0x18? "[keybind]":"[selfsig]", es_stdout); + if (opt.with_colons) + es_putc (':', es_stdout); } - else if( !opt.fast_list_mode ) { - p = get_user_id( sig->keyid, &n ); - print_string( stdout, p, n, opt.with_colons ); - xfree(p); + else if (!opt.fast_list_mode) + { + p = get_user_id (sig->keyid, &n); + es_write_sanitized (es_stdout, p, n, + opt.with_colons?":":NULL, NULL ); + xfree (p); } - if( opt.with_colons ) - printf(":%02x%c:", sig->sig_class, sig->flags.exportable?'x':'l'); - putchar('\n'); + if (opt.with_colons) + es_printf (":%02x%c:", sig->sig_class, sig->flags.exportable?'x':'l'); + es_putc ('\n', es_stdout); } - else - log_error("invalid node with packet of type %d\n", node->pkt->pkttype); + else + log_error ("invalid node with packet of type %d\n", node->pkt->pkttype); } int -proc_packets( void *anchor, IOBUF a ) +proc_packets (ctrl_t ctrl, void *anchor, IOBUF a ) { int rc; CTX c = xmalloc_clear( sizeof *c ); + c->ctrl = ctrl; c->anchor = anchor; rc = do_proc_packets( c, a ); xfree( c ); @@ -1116,15 +1139,20 @@ proc_packets( void *anchor, IOBUF a ) int -proc_signature_packets( void *anchor, IOBUF a, +proc_signature_packets (ctrl_t ctrl, void *anchor, IOBUF a, strlist_t signedfiles, const char *sigfilename ) { CTX c = xmalloc_clear( sizeof *c ); int rc; + c->ctrl = ctrl; c->anchor = anchor; c->sigs_only = 1; - c->signed_data = signedfiles; + + c->signed_data.data_fd = -1; + c->signed_data.data_names = signedfiles; + c->signed_data.used = !!signedfiles; + c->sigfilename = sigfilename; rc = do_proc_packets( c, a ); @@ -1132,8 +1160,8 @@ proc_signature_packets( void *anchor, IOBUF a, messages, send a NODATA status back and return an error code. Using log_error is required because verify_files does not check error codes for each file but we want to terminate the process - with an error. */ - if (!rc && !c->any_sig_seen) + with an error. */ + if (!rc && !c->any.sig_seen) { write_status_text (STATUS_NODATA, "4"); log_error (_("no signature found\n")); @@ -1143,19 +1171,64 @@ proc_signature_packets( void *anchor, IOBUF a, /* Propagate the signature seen flag upward. Do this only on success so that we won't issue the nodata status several times. */ - if (!rc && c->anchor && c->any_sig_seen) - c->anchor->any_sig_seen = 1; + if (!rc && c->anchor && c->any.sig_seen) + c->anchor->any.sig_seen = 1; xfree( c ); return rc; } + +int +proc_signature_packets_by_fd (ctrl_t ctrl, + void *anchor, IOBUF a, int signed_data_fd ) +{ + int rc; + CTX c; + + c = xtrycalloc (1, sizeof *c); + if (!c) + return gpg_error_from_syserror (); + + c->ctrl = ctrl; + c->anchor = anchor; + c->sigs_only = 1; + + c->signed_data.data_fd = signed_data_fd; + c->signed_data.data_names = NULL; + c->signed_data.used = (signed_data_fd != -1); + + rc = do_proc_packets ( c, a ); + + /* If we have not encountered any signature we print an error + messages, send a NODATA status back and return an error code. + Using log_error is required because verify_files does not check + error codes for each file but we want to terminate the process + with an error. */ + if (!rc && !c->any.sig_seen) + { + write_status_text (STATUS_NODATA, "4"); + log_error (_("no signature found\n")); + rc = gpg_error (GPG_ERR_NO_DATA); + } + + /* Propagate the signature seen flag upward. Do this only on success + so that we won't issue the nodata status several times. */ + if (!rc && c->anchor && c->any.sig_seen) + c->anchor->any.sig_seen = 1; + + xfree ( c ); + return rc; +} + + int -proc_encryption_packets( void *anchor, IOBUF a ) +proc_encryption_packets (ctrl_t ctrl, void *anchor, IOBUF a ) { CTX c = xmalloc_clear( sizeof *c ); int rc; + c->ctrl = ctrl; c->anchor = anchor; c->encrypt_only = 1; rc = do_proc_packets( c, a ); @@ -1164,14 +1237,37 @@ proc_encryption_packets( void *anchor, IOBUF a ) } -int +static int +check_nesting (CTX c) +{ + int level; + + for (level=0; c; c = c->anchor) + level++; + + if (level > MAX_NESTING_DEPTH) + { + log_error ("input data with too deeply nested packets\n"); + write_status_text (STATUS_UNEXPECTED, "1"); + return GPG_ERR_BAD_DATA; + } + return 0; +} + + +static int do_proc_packets( CTX c, IOBUF a ) { - PACKET *pkt = xmalloc( sizeof *pkt ); - int rc=0; - int any_data=0; + PACKET *pkt; + int rc = 0; + int any_data = 0; int newpkt; + rc = check_nesting (c); + if (rc) + return rc; + + pkt = xmalloc( sizeof *pkt ); c->iobuf = a; init_packet(pkt); while( (rc=parse_packet(a, pkt)) != -1 ) { @@ -1192,7 +1288,7 @@ do_proc_packets( CTX c, IOBUF a ) case PKT_SYMKEY_ENC: proc_symkey_enc( c, pkt ); break; case PKT_ENCRYPTED: case PKT_ENCRYPTED_MDC: proc_encrypted( c, pkt ); break; - case PKT_COMPRESSED: proc_compressed( c, pkt ); break; + case PKT_COMPRESSED: rc = proc_compressed( c, pkt ); break; default: newpkt = 0; break; } } @@ -1210,7 +1306,7 @@ do_proc_packets( CTX c, IOBUF a ) goto leave; case PKT_SIGNATURE: newpkt = add_signature( c, pkt ); break; case PKT_PLAINTEXT: proc_plaintext( c, pkt ); break; - case PKT_COMPRESSED: proc_compressed( c, pkt ); break; + case PKT_COMPRESSED: rc = proc_compressed( c, pkt ); break; case PKT_ONEPASS_SIG: newpkt = add_onepass_sig( c, pkt ); break; case PKT_GPG_CONTROL: newpkt = add_gpg_control(c, pkt); break; default: newpkt = 0; break; @@ -1230,7 +1326,7 @@ do_proc_packets( CTX c, IOBUF a ) case PKT_ENCRYPTED: case PKT_ENCRYPTED_MDC: proc_encrypted( c, pkt ); break; case PKT_PLAINTEXT: proc_plaintext( c, pkt ); break; - case PKT_COMPRESSED: proc_compressed( c, pkt ); break; + case PKT_COMPRESSED: rc = proc_compressed( c, pkt ); break; case PKT_ONEPASS_SIG: newpkt = add_onepass_sig( c, pkt ); break; case PKT_GPG_CONTROL: newpkt = add_gpg_control(c, pkt); break; default: newpkt = 0; break; @@ -1255,23 +1351,27 @@ do_proc_packets( CTX c, IOBUF a ) case PKT_ENCRYPTED: case PKT_ENCRYPTED_MDC: proc_encrypted( c, pkt ); break; case PKT_PLAINTEXT: proc_plaintext( c, pkt ); break; - case PKT_COMPRESSED: proc_compressed( c, pkt ); break; + case PKT_COMPRESSED: rc = proc_compressed( c, pkt ); break; case PKT_ONEPASS_SIG: newpkt = add_onepass_sig( c, pkt ); break; case PKT_GPG_CONTROL: newpkt = add_gpg_control(c, pkt); break; case PKT_RING_TRUST: newpkt = add_ring_trust( c, pkt ); break; default: newpkt = 0; break; } } + + if (rc) + goto leave; + /* This is a very ugly construct and frankly, I don't remember why * I used it. Adding the MDC check here is a hack. * The right solution is to initiate another context for encrypted * packet and not to reuse the current one ... It works right * when there is a compression packet inbetween which adds just * an extra layer. - * Hmmm: Rewrite this whole module here?? + * Hmmm: Rewrite this whole module here?? */ if( pkt->pkttype != PKT_SIGNATURE && pkt->pkttype != PKT_MDC ) - c->have_data = pkt->pkttype == PKT_PLAINTEXT; + c->any.data = (pkt->pkttype == PKT_PLAINTEXT); if( newpkt == -1 ) ; @@ -1365,12 +1465,45 @@ pka_uri_from_sig (PKT_signature *sig) } +static void +print_good_bad_signature (int statno, const char *keyid_str, kbnode_t un, + PKT_signature *sig, int rc) +{ + char *p; + + write_status_text_and_buffer (statno, keyid_str, + un? un->pkt->pkt.user_id->name:"[?]", + un? un->pkt->pkt.user_id->len:3, + -1); + + if (un) + p = utf8_to_native (un->pkt->pkt.user_id->name, + un->pkt->pkt.user_id->len, 0); + else + p = xstrdup ("[?]"); + + if (rc) + log_info (_("BAD signature from \"%s\""), p); + else if (sig->flags.expired) + log_info (_("Expired signature from \"%s\""), p); + else + log_info (_("Good signature from \"%s\""), p); + + xfree (p); +} + + static int -check_sig_and_print( CTX c, KBNODE node ) +check_sig_and_print (CTX c, KBNODE node) { PKT_signature *sig = node->pkt->pkt.signature; const char *astr; - int rc, is_expkey=0, is_revkey=0; + int rc; + int is_expkey = 0; + int is_revkey = 0; + char pkstrbuf[PUBKEY_STRING_SIZE]; + + *pkstrbuf = 0; if (opt.skip_verify) { @@ -1387,7 +1520,7 @@ check_sig_and_print( CTX c, KBNODE node ) O{1,n} P S{1,n} -- standard OpenPGP signature. C P S{1,n} -- cleartext signature. - + O = One-Pass Signature packet. S = Signature packet. P = OpenPGP Message packet (Encrypted | Compressed | Literal) @@ -1399,7 +1532,7 @@ check_sig_and_print( CTX c, KBNODE node ) C = Marker packet for cleartext signatures. We reject all other messages. - + Actually we are calling this too often, i.e. for verification of each message but better have some duplicate work than to silently introduce a bug here. @@ -1413,7 +1546,7 @@ check_sig_and_print( CTX c, KBNODE node ) n = c->list; assert (n); - if ( n->pkt->pkttype == PKT_SIGNATURE ) + if ( n->pkt->pkttype == PKT_SIGNATURE ) { /* This is either "S{1,n}" case (detached signature) or "S{1,n} P" (old style PGP2 signature). */ @@ -1432,7 +1565,7 @@ check_sig_and_print( CTX c, KBNODE node ) else goto ambiguous; } - else if (n->pkt->pkttype == PKT_ONEPASS_SIG) + else if (n->pkt->pkttype == PKT_ONEPASS_SIG) { /* This is the "O{1,n} P S{1,n}" case (standard signature). */ for (n_onepass=1, n = n->next; @@ -1447,8 +1580,17 @@ check_sig_and_print( CTX c, KBNODE node ) n_sig++; if (!n_sig) goto ambiguous; - if (n && !opt.allow_multisig_verification) - goto ambiguous; + + /* If we wanted to disallow multiple sig verification, we'd do + something like this: + + if (n && !opt.allow_multisig_verification) + goto ambiguous; + + However, now that we have --allow-multiple-messages, this + can stay allowable as we can't get here unless multiple + messages (i.e. multiple literals) are allowed. */ + if (n_onepass != n_sig) { log_info ("number of one-pass packets does not match " @@ -1471,394 +1613,383 @@ check_sig_and_print( CTX c, KBNODE node ) if (n || !n_sig) goto ambiguous; } - else + else { ambiguous: log_error(_("can't handle this ambiguous signature data\n")); return 0; } - } - /* (Indendation below not yet changed to GNU style.) */ + astr = openpgp_pk_algo_name ( sig->pubkey_algo ); + if (keystrlen () > 8) + { + log_info (_("Signature made %s\n"), asctimestamp(sig->timestamp)); + log_info (_(" using %s key %s\n"), + astr? astr: "?",keystr(sig->keyid)); + } + else + log_info (_("Signature made %s using %s key ID %s\n"), + asctimestamp(sig->timestamp), astr? astr: "?", + keystr(sig->keyid)); - astr = gcry_pk_algo_name ( sig->pubkey_algo ); - if(keystrlen()>8) - { - log_info(_("Signature made %s\n"),asctimestamp(sig->timestamp)); - log_info(_(" using %s key %s\n"), - astr? astr: "?",keystr(sig->keyid)); - } - else - log_info(_("Signature made %s using %s key ID %s\n"), - asctimestamp(sig->timestamp), astr? astr: "?", - keystr(sig->keyid)); + rc = do_check_sig (c, node, NULL, &is_expkey, &is_revkey ); - rc = do_check_sig(c, node, NULL, &is_expkey, &is_revkey ); + /* If the key isn't found, check for a preferred keyserver */ - /* If the key isn't found, check for a preferred keyserver */ + if (gpg_err_code (rc) == G10ERR_NO_PUBKEY && sig->flags.pref_ks) + { + const byte *p; + int seq = 0; + size_t n; - if(rc==G10ERR_NO_PUBKEY && sig->flags.pref_ks) - { - const byte *p; - int seq=0; - size_t n; + while ((p=enum_sig_subpkt (sig->hashed,SIGSUBPKT_PREF_KS,&n,&seq,NULL))) + { + /* According to my favorite copy editor, in English grammar, + you say "at" if the key is located on a web page, but + "from" if it is located on a keyserver. I'm not going to + even try to make two strings here :) */ + log_info(_("Key available at: ") ); + print_utf8_buffer (log_get_stream(), p, n); + log_printf ("\n"); + + if (opt.keyserver_options.options&KEYSERVER_AUTO_KEY_RETRIEVE + && opt.keyserver_options.options&KEYSERVER_HONOR_KEYSERVER_URL) + { + struct keyserver_spec *spec; - while((p=enum_sig_subpkt(sig->hashed,SIGSUBPKT_PREF_KS,&n,&seq,NULL))) - { - /* According to my favorite copy editor, in English - grammar, you say "at" if the key is located on a web - page, but "from" if it is located on a keyserver. I'm - not going to even try to make two strings here :) */ - log_info(_("Key available at: ") ); - print_utf8_string( log_get_stream(), p, n ); - log_printf ("\n"); - - if(opt.keyserver_options.options&KEYSERVER_AUTO_KEY_RETRIEVE - && opt.keyserver_options.options&KEYSERVER_HONOR_KEYSERVER_URL) - { - struct keyserver_spec *spec; + spec = parse_preferred_keyserver (sig); + if (spec) + { + int res; - spec=parse_preferred_keyserver(sig); - if(spec) - { - int res; + glo_ctrl.in_auto_key_retrieve++; + res = keyserver_import_keyid (c->ctrl, sig->keyid,spec); + glo_ctrl.in_auto_key_retrieve--; + if (!res) + rc = do_check_sig(c, node, NULL, &is_expkey, &is_revkey ); + free_keyserver_spec (spec); + + if (!rc) + break; + } + } + } + } - glo_ctrl.in_auto_key_retrieve++; - res=keyserver_import_keyid(sig->keyid,spec); - glo_ctrl.in_auto_key_retrieve--; - if(!res) - rc=do_check_sig(c, node, NULL, &is_expkey, &is_revkey ); - free_keyserver_spec(spec); + /* If the preferred keyserver thing above didn't work, our second + try is to use the URI from a DNS PKA record. */ + if (gpg_err_code (rc) == G10ERR_NO_PUBKEY + && (opt.keyserver_options.options & KEYSERVER_AUTO_KEY_RETRIEVE) + && (opt.keyserver_options.options & KEYSERVER_HONOR_PKA_RECORD)) + { + const char *uri = pka_uri_from_sig (sig); - if(!rc) - break; - } - } - } - } + if (uri) + { + /* FIXME: We might want to locate the key using the + fingerprint instead of the keyid. */ + int res; + struct keyserver_spec *spec; - /* If the preferred keyserver thing above didn't work, our second - try is to use the URI from a DNS PKA record. */ - if ( rc == G10ERR_NO_PUBKEY - && opt.keyserver_options.options&KEYSERVER_AUTO_KEY_RETRIEVE - && opt.keyserver_options.options&KEYSERVER_HONOR_PKA_RECORD) - { - const char *uri = pka_uri_from_sig (sig); - - if (uri) - { - /* FIXME: We might want to locate the key using the - fingerprint instead of the keyid. */ - int res; - struct keyserver_spec *spec; - - spec = parse_keyserver_uri (uri, 1, NULL, 0); - if (spec) - { - glo_ctrl.in_auto_key_retrieve++; - res = keyserver_import_keyid (sig->keyid, spec); + spec = parse_keyserver_uri (uri, 1, NULL, 0); + if (spec) + { + glo_ctrl.in_auto_key_retrieve++; + res = keyserver_import_keyid (c->ctrl, sig->keyid, spec); glo_ctrl.in_auto_key_retrieve--; free_keyserver_spec (spec); if (!res) - rc = do_check_sig(c, node, NULL, &is_expkey, &is_revkey ); - } - } - } + rc = do_check_sig (c, node, NULL, &is_expkey, &is_revkey ); + } + } + } - /* If the preferred keyserver thing above didn't work and we got + /* If the preferred keyserver thing above didn't work and we got no information from the DNS PKA, this is a third try. */ - if( rc == G10ERR_NO_PUBKEY && opt.keyserver - && opt.keyserver_options.options&KEYSERVER_AUTO_KEY_RETRIEVE) - { - int res; - - glo_ctrl.in_auto_key_retrieve++; - res=keyserver_import_keyid ( sig->keyid, opt.keyserver ); - glo_ctrl.in_auto_key_retrieve--; - if(!res) - rc = do_check_sig(c, node, NULL, &is_expkey, &is_revkey ); - } + if (gpg_err_code (rc) == G10ERR_NO_PUBKEY + && opt.keyserver + && (opt.keyserver_options.options&KEYSERVER_AUTO_KEY_RETRIEVE)) + { + int res; - if( !rc || gpg_err_code (rc) == GPG_ERR_BAD_SIGNATURE ) { - KBNODE un, keyblock; - int count=0, statno; - char keyid_str[50]; - PKT_public_key *pk=NULL; - - if(rc) - statno=STATUS_BADSIG; - else if(sig->flags.expired) - statno=STATUS_EXPSIG; - else if(is_expkey) - statno=STATUS_EXPKEYSIG; - else if(is_revkey) - statno=STATUS_REVKEYSIG; - else - statno=STATUS_GOODSIG; + glo_ctrl.in_auto_key_retrieve++; + res=keyserver_import_keyid (c->ctrl, sig->keyid, opt.keyserver ); + glo_ctrl.in_auto_key_retrieve--; + if (!res) + rc = do_check_sig (c, node, NULL, &is_expkey, &is_revkey ); + } - keyblock = get_pubkeyblock( sig->keyid ); + if (!rc || gpg_err_code (rc) == GPG_ERR_BAD_SIGNATURE) + { + kbnode_t un, keyblock; + int count = 0; + int statno; + char keyid_str[50]; + PKT_public_key *pk = NULL; + + if (rc) + statno = STATUS_BADSIG; + else if (sig->flags.expired) + statno = STATUS_EXPSIG; + else if (is_expkey) + statno = STATUS_EXPKEYSIG; + else if(is_revkey) + statno = STATUS_REVKEYSIG; + else + statno = STATUS_GOODSIG; + + keyblock = get_pubkeyblock (sig->keyid); + + snprintf (keyid_str, sizeof keyid_str, "%08lX%08lX [uncertain] ", + (ulong)sig->keyid[0], (ulong)sig->keyid[1]); + + /* Find and print the primary user ID. */ + for (un=keyblock; un; un = un->next) + { + int valid; - sprintf (keyid_str, "%08lX%08lX [uncertain] ", - (ulong)sig->keyid[0], (ulong)sig->keyid[1]); + if (un->pkt->pkttype==PKT_PUBLIC_KEY) + { + pk=un->pkt->pkt.public_key; + continue; + } + if (un->pkt->pkttype != PKT_USER_ID) + continue; + if (!un->pkt->pkt.user_id->created) + continue; + if (un->pkt->pkt.user_id->is_revoked) + continue; + if (un->pkt->pkt.user_id->is_expired) + continue; + if (!un->pkt->pkt.user_id->is_primary) + continue; + /* We want the textual primary user ID here */ + if (un->pkt->pkt.user_id->attrib_data) + continue; - /* find and print the primary user ID */ - for( un=keyblock; un; un = un->next ) { - char *p; - int valid; - if(un->pkt->pkttype==PKT_PUBLIC_KEY) - { - pk=un->pkt->pkt.public_key; - continue; - } - if( un->pkt->pkttype != PKT_USER_ID ) - continue; - if ( !un->pkt->pkt.user_id->created ) - continue; - if ( un->pkt->pkt.user_id->is_revoked ) - continue; - if ( un->pkt->pkt.user_id->is_expired ) - continue; - if ( !un->pkt->pkt.user_id->is_primary ) - continue; - /* We want the textual primary user ID here */ - if ( un->pkt->pkt.user_id->attrib_data ) - continue; + assert (pk); - assert(pk); + /* Get it before we print anything to avoid interrupting the + output with the "please do a --check-trustdb" line. */ + valid = get_validity (pk, un->pkt->pkt.user_id); - /* Get it before we print anything to avoid interrupting - the output with the "please do a --check-trustdb" - line. */ - valid=get_validity(pk,un->pkt->pkt.user_id); + keyid_str[17] = 0; /* cut off the "[uncertain]" part */ - keyid_str[17] = 0; /* cut off the "[uncertain]" part */ - write_status_text_and_buffer (statno, keyid_str, - un->pkt->pkt.user_id->name, - un->pkt->pkt.user_id->len, - -1 ); - - p=utf8_to_native(un->pkt->pkt.user_id->name, - un->pkt->pkt.user_id->len,0); - - if(rc) - log_info(_("BAD signature from \"%s\""),p); - else if(sig->flags.expired) - log_info(_("Expired signature from \"%s\""),p); - else - log_info(_("Good signature from \"%s\""),p); + print_good_bad_signature (statno, keyid_str, un, sig, rc); - xfree(p); + if ((opt.verify_options & VERIFY_SHOW_UID_VALIDITY)) + log_printf (" [%s]\n",trust_value_to_string(valid)); + else + log_printf ("\n"); - if(opt.verify_options&VERIFY_SHOW_UID_VALIDITY) - log_printf (" [%s]\n",trust_value_to_string(valid)); - else - log_printf ("\n"); - count++; + pubkey_string (pk, pkstrbuf, sizeof pkstrbuf); + count++; } - if( !count ) { /* just in case that we have no valid textual - userid */ - char *p; - /* Try for an invalid textual userid */ - for( un=keyblock; un; un = un->next ) { - if( un->pkt->pkttype == PKT_USER_ID && - !un->pkt->pkt.user_id->attrib_data ) - break; + if (!count) /* Just in case that we have no valid textual userid */ + { + /* Try for an invalid textual userid */ + for (un=keyblock; un; un = un->next) + { + if (un->pkt->pkttype == PKT_USER_ID + && !un->pkt->pkt.user_id->attrib_data) + break; } - /* Try for any userid at all */ - if(!un) { - for( un=keyblock; un; un = un->next ) { - if( un->pkt->pkttype == PKT_USER_ID ) - break; + /* Try for any userid at all */ + if (!un) + { + for (un=keyblock; un; un = un->next) + { + if (un->pkt->pkttype == PKT_USER_ID) + break; } } - if (opt.trust_model==TM_ALWAYS || !un) - keyid_str[17] = 0; /* cut off the "[uncertain]" part */ + if (opt.trust_model==TM_ALWAYS || !un) + keyid_str[17] = 0; /* cut off the "[uncertain]" part */ - write_status_text_and_buffer (statno, keyid_str, - un? un->pkt->pkt.user_id->name:"[?]", - un? un->pkt->pkt.user_id->len:3, - -1 ); + print_good_bad_signature (statno, keyid_str, un, sig, rc); - if(un) - p=utf8_to_native(un->pkt->pkt.user_id->name, - un->pkt->pkt.user_id->len,0); - else - p=xstrdup("[?]"); - - if(rc) - log_info(_("BAD signature from \"%s\""),p); - else if(sig->flags.expired) - log_info(_("Expired signature from \"%s\""),p); - else - log_info(_("Good signature from \"%s\""),p); - if (opt.trust_model!=TM_ALWAYS && un) - log_printf (" %s",_("[uncertain]") ); - log_printf ("\n"); + if (opt.trust_model != TM_ALWAYS && un) + log_printf (" %s",_("[uncertain]") ); + log_printf ("\n"); } - /* If we have a good signature and already printed - * the primary user ID, print all the other user IDs */ - if ( count && !rc ) { - char *p; - for( un=keyblock; un; un = un->next ) { - if( un->pkt->pkttype != PKT_USER_ID ) - continue; - if((un->pkt->pkt.user_id->is_revoked - || un->pkt->pkt.user_id->is_expired) - && !(opt.verify_options&VERIFY_SHOW_UNUSABLE_UIDS)) - continue; - /* Only skip textual primaries */ - if ( un->pkt->pkt.user_id->is_primary && - !un->pkt->pkt.user_id->attrib_data ) - continue; - - if(un->pkt->pkt.user_id->attrib_data) - { - dump_attribs(un->pkt->pkt.user_id,pk,NULL); + /* If we have a good signature and already printed + * the primary user ID, print all the other user IDs */ + if (count + && !rc + && !(opt.verify_options & VERIFY_SHOW_PRIMARY_UID_ONLY)) + { + char *p; + for( un=keyblock; un; un = un->next) + { + if (un->pkt->pkttype != PKT_USER_ID) + continue; + if ((un->pkt->pkt.user_id->is_revoked + || un->pkt->pkt.user_id->is_expired) + && !(opt.verify_options & VERIFY_SHOW_UNUSABLE_UIDS)) + continue; + /* Only skip textual primaries */ + if (un->pkt->pkt.user_id->is_primary + && !un->pkt->pkt.user_id->attrib_data ) + continue; - if(opt.verify_options&VERIFY_SHOW_PHOTOS) - show_photos(un->pkt->pkt.user_id->attribs, - un->pkt->pkt.user_id->numattribs,pk,NULL); - } + if (un->pkt->pkt.user_id->attrib_data) + { + dump_attribs (un->pkt->pkt.user_id, pk); - p=utf8_to_native(un->pkt->pkt.user_id->name, - un->pkt->pkt.user_id->len,0); - log_info(_(" aka \"%s\""),p); - xfree(p); + if (opt.verify_options&VERIFY_SHOW_PHOTOS) + show_photos (un->pkt->pkt.user_id->attribs, + un->pkt->pkt.user_id->numattribs, + pk ,un->pkt->pkt.user_id); + } - if(opt.verify_options&VERIFY_SHOW_UID_VALIDITY) - { - const char *valid; - if(un->pkt->pkt.user_id->is_revoked) - valid=_("revoked"); - else if(un->pkt->pkt.user_id->is_expired) - valid=_("expired"); - else - valid=trust_value_to_string(get_validity(pk, - un->pkt-> - pkt.user_id)); - log_printf (" [%s]\n",valid); - } - else - log_printf ("\n"); + p = utf8_to_native (un->pkt->pkt.user_id->name, + un->pkt->pkt.user_id->len, 0); + log_info (_(" aka \"%s\""), p); + xfree (p); + + if ((opt.verify_options & VERIFY_SHOW_UID_VALIDITY)) + { + const char *valid; + + if (un->pkt->pkt.user_id->is_revoked) + valid = _("revoked"); + else if (un->pkt->pkt.user_id->is_expired) + valid = _("expired"); + else + valid = (trust_value_to_string + (get_validity (pk, un->pkt->pkt.user_id))); + log_printf (" [%s]\n",valid); + } + else + log_printf ("\n"); } } - release_kbnode( keyblock ); - - if( !rc ) - { - if(opt.verify_options&VERIFY_SHOW_POLICY_URLS) - show_policy_url(sig,0,1); - else - show_policy_url(sig,0,2); + release_kbnode( keyblock ); - if(opt.verify_options&VERIFY_SHOW_KEYSERVER_URLS) - show_keyserver_url(sig,0,1); - else - show_keyserver_url(sig,0,2); + if (!rc) + { + if ((opt.verify_options & VERIFY_SHOW_POLICY_URLS)) + show_policy_url (sig, 0, 1); + else + show_policy_url (sig, 0, 2); + + if ((opt.verify_options & VERIFY_SHOW_KEYSERVER_URLS)) + show_keyserver_url (sig, 0, 1); + else + show_keyserver_url (sig, 0, 2); + + if ((opt.verify_options & VERIFY_SHOW_NOTATIONS)) + show_notation + (sig, 0, 1, + (((opt.verify_options&VERIFY_SHOW_STD_NOTATIONS)?1:0) + + ((opt.verify_options&VERIFY_SHOW_USER_NOTATIONS)?2:0))); + else + show_notation (sig, 0, 2, 0); + } - if(opt.verify_options&VERIFY_SHOW_NOTATIONS) - show_notation(sig,0,1, - ((opt.verify_options&VERIFY_SHOW_STD_NOTATIONS)?1:0)+ - ((opt.verify_options&VERIFY_SHOW_USER_NOTATIONS)?2:0)); - else - show_notation(sig,0,2,0); - } + if (!rc && is_status_enabled ()) + { + /* Print a status response with the fingerprint. */ + PKT_public_key *vpk = xmalloc_clear (sizeof *vpk); - if( !rc && is_status_enabled() ) { - /* print a status response with the fingerprint */ - PKT_public_key *vpk = xmalloc_clear( sizeof *vpk ); - - if( !get_pubkey( vpk, sig->keyid ) ) { - byte array[MAX_FINGERPRINT_LEN], *p; - char buf[MAX_FINGERPRINT_LEN*4+90], *bufp; - size_t i, n; - - bufp = buf; - fingerprint_from_pk( vpk, array, &n ); - p = array; - for(i=0; i < n ; i++, p++, bufp += 2) - sprintf(bufp, "%02X", *p ); - /* TODO: Replace the reserved '0' in the field below - with bits for status flags (policy url, notation, - etc.). Remember to make the buffer larger to - match! */ - sprintf(bufp, " %s %lu %lu %d 0 %d %d %02X ", - strtimestamp( sig->timestamp ), - (ulong)sig->timestamp,(ulong)sig->expiredate, - sig->version,sig->pubkey_algo,sig->digest_algo, - sig->sig_class); - bufp = bufp + strlen (bufp); - if (!vpk->is_primary) { - u32 akid[2]; - - akid[0] = vpk->main_keyid[0]; - akid[1] = vpk->main_keyid[1]; - free_public_key (vpk); - vpk = xmalloc_clear( sizeof *vpk ); - if (get_pubkey (vpk, akid)) { - /* impossible error, we simply return a zeroed out fpr */ - n = MAX_FINGERPRINT_LEN < 20? MAX_FINGERPRINT_LEN : 20; - memset (array, 0, n); - } - else - fingerprint_from_pk( vpk, array, &n ); + if (!get_pubkey (vpk, sig->keyid)) + { + byte array[MAX_FINGERPRINT_LEN], *p; + char buf[MAX_FINGERPRINT_LEN*4+90], *bufp; + size_t i, n; + + bufp = buf; + fingerprint_from_pk (vpk, array, &n); + p = array; + for(i=0; i < n ; i++, p++, bufp += 2) + sprintf (bufp, "%02X", *p ); + /* TODO: Replace the reserved '0' in the field below + with bits for status flags (policy url, notation, + etc.). Remember to make the buffer larger to match! */ + sprintf (bufp, " %s %lu %lu %d 0 %d %d %02X ", + strtimestamp( sig->timestamp ), + (ulong)sig->timestamp,(ulong)sig->expiredate, + sig->version,sig->pubkey_algo,sig->digest_algo, + sig->sig_class); + bufp = bufp + strlen (bufp); + if (!vpk->flags.primary) + { + u32 akid[2]; + + akid[0] = vpk->main_keyid[0]; + akid[1] = vpk->main_keyid[1]; + free_public_key (vpk); + vpk = xmalloc_clear (sizeof *vpk); + if (get_pubkey (vpk, akid)) + { + /* Impossible error, we simply return a zeroed out fpr */ + n = MAX_FINGERPRINT_LEN < 20? MAX_FINGERPRINT_LEN : 20; + memset (array, 0, n); + } + else + fingerprint_from_pk( vpk, array, &n ); } - p = array; - for(i=0; i < n ; i++, p++, bufp += 2) - sprintf(bufp, "%02X", *p ); - write_status_text( STATUS_VALIDSIG, buf ); + p = array; + for (i=0; i < n ; i++, p++, bufp += 2) + sprintf(bufp, "%02X", *p ); + write_status_text (STATUS_VALIDSIG, buf); } - free_public_key( vpk ); + free_public_key (vpk); } - if (!rc) - { - if(opt.verify_options&VERIFY_PKA_LOOKUPS) - pka_uri_from_sig (sig); /* Make sure PKA info is available. */ - rc = check_signatures_trust( sig ); - } + if (!rc) + { + if ((opt.verify_options & VERIFY_PKA_LOOKUPS)) + pka_uri_from_sig (sig); /* Make sure PKA info is available. */ + rc = check_signatures_trust (sig); + } - if(sig->flags.expired) - { - log_info(_("Signature expired %s\n"), - asctimestamp(sig->expiredate)); - rc=G10ERR_GENERAL; /* need a better error here? */ - } - else if(sig->expiredate) - log_info(_("Signature expires %s\n"),asctimestamp(sig->expiredate)); - - if(opt.verbose) - log_info(_("%s signature, digest algorithm %s\n"), - sig->sig_class==0x00?_("binary"): - sig->sig_class==0x01?_("textmode"):_("unknown"), - gcry_md_algo_name (sig->digest_algo)); - - if( rc ) - g10_errors_seen = 1; - if( opt.batch && rc ) - g10_exit(1); + if (sig->flags.expired) + { + log_info (_("Signature expired %s\n"), asctimestamp(sig->expiredate)); + rc = G10ERR_GENERAL; /* need a better error here? */ + } + else if (sig->expiredate) + log_info (_("Signature expires %s\n"), asctimestamp(sig->expiredate)); + + if (opt.verbose) + log_info (_("%s signature, digest algorithm %s%s%s\n"), + sig->sig_class==0x00?_("binary"): + sig->sig_class==0x01?_("textmode"):_("unknown"), + gcry_md_algo_name (sig->digest_algo), + *pkstrbuf?_(", key algorithm "):"", + pkstrbuf); + + if (rc) + g10_errors_seen = 1; + if (opt.batch && rc) + g10_exit (1); } - else { - char buf[50]; - sprintf(buf, "%08lX%08lX %d %d %02x %lu %d", - (ulong)sig->keyid[0], (ulong)sig->keyid[1], - sig->pubkey_algo, sig->digest_algo, - sig->sig_class, (ulong)sig->timestamp, rc ); - write_status_text( STATUS_ERRSIG, buf ); - if( rc == G10ERR_NO_PUBKEY ) { - buf[16] = 0; - write_status_text( STATUS_NO_PUBKEY, buf ); + else + { + char buf[50]; + + snprintf (buf, sizeof buf, "%08lX%08lX %d %d %02x %lu %d", + (ulong)sig->keyid[0], (ulong)sig->keyid[1], + sig->pubkey_algo, sig->digest_algo, + sig->sig_class, (ulong)sig->timestamp, rc); + write_status_text (STATUS_ERRSIG, buf); + if (gpg_err_code (rc) == G10ERR_NO_PUBKEY) + { + buf[16] = 0; + write_status_text (STATUS_NO_PUBKEY, buf); } - if( rc != G10ERR_NOT_PROCESSED ) - log_error(_("Can't check signature: %s\n"), g10_errstr(rc) ); + if (gpg_err_code (rc) != G10ERR_NOT_PROCESSED) + log_error (_("Can't check signature: %s\n"), g10_errstr(rc)); } - return rc; + + return rc; } @@ -1898,7 +2029,9 @@ proc_tree( CTX c, KBNODE node ) } else if( node->pkt->pkttype == PKT_ONEPASS_SIG ) { /* check all signatures */ - if( !c->have_data ) { + if( !c->any.data ) { + int use_textmode = 0; + free_md_filter_context( &c->mfx ); /* prepare to create all requested message digests */ if (gcry_md_open (&c->mfx.md, 0, 0)) @@ -1911,23 +2044,33 @@ proc_tree( CTX c, KBNODE node ) gcry_md_enable (c->mfx.md, n1->pkt->pkt.signature->digest_algo); } - /* ask for file and hash it */ + + if (n1 && n1->pkt->pkt.onepass_sig->sig_class == 0x01) + use_textmode = 1; + + /* Ask for file and hash it. */ if( c->sigs_only ) { - rc = hash_datafiles( c->mfx.md, NULL, - c->signed_data, c->sigfilename, - n1? (n1->pkt->pkt.onepass_sig->sig_class == 0x01):0 ); + if (c->signed_data.used && c->signed_data.data_fd != -1) + rc = hash_datafile_by_fd (c->mfx.md, NULL, + c->signed_data.data_fd, + use_textmode); + else + rc = hash_datafiles (c->mfx.md, NULL, + c->signed_data.data_names, + c->sigfilename, + use_textmode ); } else { - rc = ask_for_detached_datafile( c->mfx.md, c->mfx.md2, + rc = ask_for_detached_datafile (c->mfx.md, c->mfx.md2, iobuf_get_real_fname(c->iobuf), - n1? (n1->pkt->pkt.onepass_sig->sig_class == 0x01):0 ); + use_textmode ); } if( rc ) { log_error("can't hash datafile: %s\n", g10_errstr(rc)); return; } } - else if ( c->signed_data ) { + else if ( c->signed_data.used ) { log_error (_("not a detached signature\n") ); return; } @@ -1939,15 +2082,15 @@ proc_tree( CTX c, KBNODE node ) && node->pkt->pkt.gpg_control->control == CTRLPKT_CLEARSIGN_START ) { /* clear text signed message */ - if( !c->have_data ) { + if( !c->any.data ) { log_error("cleartext signature without data\n" ); return; } - else if ( c->signed_data ) { + else if ( c->signed_data.used ) { log_error (_("not a detached signature\n") ); return; } - + for( n1 = node; (n1 = find_next_kbnode(n1, PKT_SIGNATURE )); ) check_sig_and_print( c, n1 ); } @@ -1981,7 +2124,7 @@ proc_tree( CTX c, KBNODE node ) if( sig->sig_class != 0x00 && sig->sig_class != 0x01 ) log_info(_("standalone signature of class 0x%02x\n"), sig->sig_class); - else if( !c->have_data ) { + else if( !c->any.data ) { /* detached signature */ free_md_filter_context( &c->mfx ); if (gcry_md_open (&c->mfx.md, sig->digest_algo, 0)) @@ -1990,7 +2133,8 @@ proc_tree( CTX c, KBNODE node ) if( !opt.pgp2_workarounds ) ; else if( sig->digest_algo == DIGEST_ALGO_MD5 - && is_RSA( sig->pubkey_algo ) ) { + && is_RSA( sig->pubkey_algo) + && opt.flags.allow_weak_digest_algos) { /* enable a workaround for a pgp2 bug */ if (gcry_md_open (&c->mfx.md2, DIGEST_ALGO_MD5, 0)) BUG (); @@ -2003,25 +2147,32 @@ proc_tree( CTX c, KBNODE node ) if (gcry_md_open (&c->mfx.md2, sig->digest_algo, 0 )) BUG (); } -#if 0 /* workaround disabled */ - /* Here we have another hack to work around a pgp 2 bug - * It works by not using the textmode for detached signatures; - * this will let the first signature check (on md) fail - * but the second one (on md2) which adds an extra CR should - * then produce the "correct" hash. This is very, very ugly - * hack but it may help in some cases (and break others) - */ - /* c->mfx.md2? 0 :(sig->sig_class == 0x01) */ -#endif + + /* Here we used to have another hack to work around a pgp + * 2 bug: It worked by not using the textmode for detached + * signatures; this would let the first signature check + * (on md) fail but the second one (on md2), which adds an + * extra CR would then have produced the "correct" hash. + * This is very, very ugly hack but it may haved help in + * some cases (and break others). + * c->mfx.md2? 0 :(sig->sig_class == 0x01) + */ + if ( DBG_HASHING ) { - gcry_md_start_debug( c->mfx.md, "verify" ); + gcry_md_debug( c->mfx.md, "verify" ); if ( c->mfx.md2 ) - gcry_md_start_debug( c->mfx.md2, "verify2" ); + gcry_md_debug( c->mfx.md2, "verify2" ); } if( c->sigs_only ) { - rc = hash_datafiles( c->mfx.md, c->mfx.md2, - c->signed_data, c->sigfilename, - (sig->sig_class == 0x01) ); + if (c->signed_data.used && c->signed_data.data_fd != -1) + rc = hash_datafile_by_fd (c->mfx.md, c->mfx.md2, + c->signed_data.data_fd, + (sig->sig_class == 0x01)); + else + rc = hash_datafiles (c->mfx.md, c->mfx.md2, + c->signed_data.data_names, + c->sigfilename, + (sig->sig_class == 0x01)); } else { rc = ask_for_detached_datafile( c->mfx.md, c->mfx.md2, @@ -2033,7 +2184,7 @@ proc_tree( CTX c, KBNODE node ) return; } } - else if ( c->signed_data ) { + else if ( c->signed_data.used ) { log_error (_("not a detached signature\n") ); return; }