gpg: Make card key generation work again.
[gnupg.git] / g10 / mainproc.c
index dcbc4b4..50d1d27 100644 (file)
@@ -1,6 +1,7 @@
 /* mainproc.c - handle packets
  * 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.
  *
@@ -30,7 +31,6 @@
 #include "packet.h"
 #include "iobuf.h"
 #include "options.h"
-#include "cipher.h"
 #include "keydb.h"
 #include "filter.h"
 #include "main.h"
 #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];
@@ -63,15 +68,15 @@ struct mainproc_context
   md_filter_context_t mfx;
   int sigs_only;    /* Process only signatures and reject all other stuff. */
   int encrypt_only; /* Process only encryption messages. */
-    
+
   /* 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 
+  struct
   {
     /* A file descriptor of the the signed data.  Only used if not -1. */
     int data_fd;
@@ -82,16 +87,20 @@ struct mainproc_context
        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;
 };
 
 
@@ -120,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;
 }
@@ -147,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 ));
@@ -198,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
@@ -250,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 )
@@ -385,6 +389,7 @@ proc_pubkey_enc( CTX c, PACKET *pkt )
     else if( is_ELGAMAL(enc->pubkey_algo)
              || 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) {
@@ -446,7 +451,7 @@ 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 )
@@ -541,7 +546,6 @@ proc_encrypted( CTX c, PACKET *pkt )
                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"),
                          openpgp_cipher_algo_name (algo));
@@ -566,6 +570,7 @@ proc_encrypted( CTX c, PACKET *pkt )
     }
     else if( !c->dek )
        result = G10ERR_NO_SECKEY;
+
     if (!result)
       result = decrypt_data (c->ctrl, c, pkt->pkt.encrypted, c->dek );
 
@@ -580,16 +585,6 @@ 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;
@@ -628,7 +623,7 @@ proc_plaintext( CTX c, PACKET *pkt )
     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 );
@@ -670,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);
@@ -699,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
@@ -709,9 +705,9 @@ 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=0;
@@ -724,14 +720,14 @@ proc_plaintext( CTX c, PACKET *pkt )
          {
             write_status_text (STATUS_ERROR, "proc_pkt.plaintext 89_BAD_DATA");
            log_inc_errorcount ();
-           rc = gpg_error (GPG_ERR_UNEXPECTED); 
+           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 ) 
+        if ( gpg_err_code (rc) == GPG_ERR_EACCES && !c->sigs_only )
           {
             /* Can't write output but we hash it anyway to check the
                signature. */
@@ -750,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;
 }
 
@@ -775,25 +771,37 @@ proc_encrypt_cb (IOBUF a, void *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( !zd->algorithm )
-      rc=G10ERR_COMPR_ALGO;
-    else 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( rc )
-       log_error("uncompressing failed: %s\n", g10_errstr(rc));
-    free_packet(pkt);
-    c->last_was_session_key = 0;
+  /*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;
+
+          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;
 }
 
 /****************
@@ -854,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 );
@@ -914,265 +922,203 @@ 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, 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, 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->flags.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, 0 );
+      if ((mainkey && opt.fingerprint) || opt.fingerprint > 1)
+        print_fingerprint (NULL, pk, 0);
+
+      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);
+                    }
+               }
+              else if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
+                {
+                  list_node(c,  node );
+                }
+            }
+        }
     }
-    else if( (mainkey = (node->pkt->pkttype == PKT_SECRET_KEY) )
-            || node->pkt->pkttype == PKT_SECRET_SUBKEY ) {
+  else if ((mainkey = (node->pkt->pkttype == PKT_SECRET_KEY) )
+           || node->pkt->pkttype == PKT_SECRET_SUBKEY)
+    {
 
       log_debug ("FIXME: No way to print secret key packets here\n");
-      /* fixme: We may use a fucntion to trun a secret key packet into
+      /* fixme: We may use a fucntion to turn a secret key packet into
          a public key one and use that here.  */
-       /* PKT_secret_key *sk = node->pkt->pkt.secret_key; */
-
-       /* 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( !any ) */
-       /*     putchar('\n'); */
-       /* if( !mainkey && opt.fingerprint > 1 ) */
-       /*     print_fingerprint( NULL, sk, 0 ); */
     }
-    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;
+  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 )
-              {
-                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 (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( 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)
-             es_write_sanitized (es_stdout,sig->trust_regexp,
-                                  strlen(sig->trust_regexp), ":", NULL);
-           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 );
-           es_write_sanitized (es_stdout, p, n,
-                                opt.with_colons?":":NULL, NULL );
-           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);
 }
 
 
@@ -1214,8 +1160,8 @@ proc_signature_packets (ctrl_t ctrl, 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"));
@@ -1225,8 +1171,8 @@ proc_signature_packets (ctrl_t ctrl, 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;
@@ -1258,19 +1204,19 @@ proc_signature_packets_by_fd (ctrl_t ctrl,
      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"));
       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;
-  
+  if (!rc && c->anchor && c->any.sig_seen)
+    c->anchor->any.sig_seen = 1;
+
   xfree ( c );
   return rc;
 }
@@ -1291,14 +1237,37 @@ proc_encryption_packets (ctrl_t ctrl, 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 ) {
@@ -1319,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;
            }
        }
@@ -1337,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;
@@ -1357,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;
@@ -1382,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 )
            ;
@@ -1492,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)
     {
@@ -1514,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)
@@ -1526,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.
@@ -1540,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). */
@@ -1559,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;
@@ -1607,396 +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 = 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));
+  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_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;
+              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);
 
-                   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;
+                }
+            }
+        }
+    }
 
-                   if(!rc)
-                     break;
-                 }
-             }
-         }
-      }
+  /* 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 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 (c->ctrl, sig->keyid, spec);
+      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 (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;
+  if (gpg_err_code (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 (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 );
-      }
+      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 );
+    }
 
-    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;
+  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;
 
-       keyblock = get_pubkeyblock( sig->keyid );
+          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;
 
-        sprintf (keyid_str, "%08lX%08lX [uncertain] ",
-                 (ulong)sig->keyid[0], (ulong)sig->keyid[1]);
+          assert (pk);
 
-        /* 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;
+          /* 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);
 
-           assert(pk);
+          keyid_str[17] = 0; /* cut off the "[uncertain]" part */
 
-           /* 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);
+          print_good_bad_signature (statno, keyid_str, un, sig, rc);
 
-            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);
-
-           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 */
-
-            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 (opt.trust_model==TM_ALWAYS || !un)
+            keyid_str[17] = 0; /* cut off the "[uncertain]" part */
 
-           if(un)
-             p=utf8_to_native(un->pkt->pkt.user_id->name,
-                               un->pkt->pkt.user_id->len,0);
-           else
-             p=xstrdup("[?]");
+          print_good_bad_signature (statno, keyid_str, un, sig, rc);
 
-           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
-             && !(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(un->pkt->pkt.user_id->attrib_data)
-                 {
-                   dump_attribs (un->pkt->pkt.user_id, pk);
+      /* 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 ,un->pkt->pkt.user_id);
-                 }
+              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 );
+      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);
-
-           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->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 );
+          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;
 }
 
 
@@ -2036,7 +2029,7 @@ 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 );
@@ -2089,7 +2082,7 @@ 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;
         }
@@ -2097,7 +2090,7 @@ proc_tree( CTX c, KBNODE node )
             log_error (_("not a detached signature\n") );
             return;
         }
-       
+
        for( n1 = node; (n1 = find_next_kbnode(n1, PKT_SIGNATURE )); )
            check_sig_and_print( c, n1 );
     }
@@ -2131,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))
@@ -2140,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 ();
@@ -2153,25 +2147,26 @@ 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 ) {
                 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, 
+                                              c->signed_data.data_fd,
                                               (sig->sig_class == 0x01));
                 else
                     rc = hash_datafiles (c->mfx.md, c->mfx.md2,