Preparing for an RC23
[gnupg.git] / g10 / mainproc.c
index 438543d..dbe64c9 100644 (file)
@@ -1,6 +1,6 @@
 /* mainproc.c - handle packets
  * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004,
- *               2005 Free Software Foundation, Inc.
+ *               2005, 2006 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -55,28 +55,31 @@ struct kidlist_item {
  * Structure to hold the context
  */
 typedef struct mainproc_context *CTX;
-struct mainproc_context {
-    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 encrytion messages */
-    STRLIST signed_data;
-    const char *sigfilename;
-    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; /* temp usage in list_node */
-    ulong symkeys;
-    struct kidlist_item *pkenc_list;   /* list of encryption packets */
-    struct {
-        int op;
-        int stop_now;
-    } pipemode;
+struct mainproc_context
+{
+  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 signed_data;
+  const char *sigfilename;
+  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. */
+  struct 
+  {
+    int op;
+    int stop_now;
+  } pipemode;
+  int any_sig_seen;  /* Set to true if a signature packet has been seen. */
 };
 
 
@@ -111,27 +114,14 @@ release_list( CTX c )
 static int
 add_onepass_sig( CTX c, PACKET *pkt )
 {
-    KBNODE node;
+  KBNODE node;
 
-    if( c->list ) { /* add another packet */
-        /* We can only append another onepass packet if the list
-         * does contain only onepass packets */
-        for( node=c->list; node && node->pkt->pkttype == PKT_ONEPASS_SIG;
-             node = node->next )
-            ;
-       if( node ) {
-            /* this is not the case, so we flush the current thing and 
-             * allow this packet to start a new verification thing */
-          release_list( c );
-          c->list = new_kbnode( pkt );
-       }
-       else
-          add_kbnode( c->list, new_kbnode( pkt ));
-    }
-    else /* insert the first one */
-       c->list = node = new_kbnode( pkt );
+  if ( c->list ) /* add another packet */
+    add_kbnode( c->list, new_kbnode( pkt ));
+  else /* insert the first one */
+    c->list = node = new_kbnode( pkt );
 
-    return 1;
+  return 1;
 }
 
 
@@ -217,6 +207,7 @@ add_signature( CTX c, PACKET *pkt )
 {
     KBNODE node;
 
+    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
@@ -327,7 +318,22 @@ proc_symkey_enc( CTX c, PACKET *pkt )
          }
        else
          {
-           c->dek=passphrase_to_dek(NULL, 0, algo, &enc->s2k, 0, NULL, NULL);
+            int canceled;
+
+           c->dek = passphrase_to_dek (NULL, 0, algo, &enc->s2k, 0,
+                                        NULL, &canceled);
+            if (canceled)
+              {
+                /* For unknown reasons passphrase_to_dek does only
+                   return NULL if a new passphrase has been requested
+                   and has not been repeated correctly.  Thus even
+                   with a cancel requested (by means of the gpg-agent)
+                   it won't return NULL but an empty passphrase.  We
+                   take the most conservative approach for now and
+                   work around it right here. */
+                xfree (c->dek);
+                c->dek = NULL;
+              }
 
            if(c->dek)
              {
@@ -385,7 +391,7 @@ proc_pubkey_enc( CTX c, PACKET *pkt )
     if( !opt.list_only && opt.override_session_key ) {
        /* It does not make much sense to store the session key in
         * secure memory because it has already been passed on the
-        * command line and the GCHQ knows about it */
+        * command line and the GCHQ knows about it */
        c->dek = xmalloc_clear( sizeof *c->dek );
        result = get_override_session_key ( c->dek, opt.override_session_key );
        if ( result ) {
@@ -395,6 +401,8 @@ 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 */
+
        if ( !c->dek && ((!enc->keyid[0] && !enc->keyid[1])
                           || opt.try_all_secrets
                          || !seckey_available( enc->keyid )) ) {
@@ -504,6 +512,9 @@ proc_encrypted( CTX c, PACKET *pkt )
         print_pkenc_list ( c->pkenc_list, 0 );
       }
 
+    /* FIXME: Figure out the session key by looking at all pkenc packets. */
+
+
     write_status( STATUS_BEGIN_DECRYPTION );
 
     /*log_debug("dat: %sencrypted data\n", c->dek?"":"conventional ");*/
@@ -656,7 +667,8 @@ proc_plaintext( CTX c, PACKET *pkt )
             for( data++, datalen--; datalen; datalen--, data++ )
              md_enable( c->mfx.md, *data );
             any = 1;
-            break;  /* no pass signature packets are expected */
+            break;  /* Stop here as one-pass signature packets are not
+                       expected.  */
          }
        else if(n->pkt->pkttype==PKT_SIGNATURE)
          {
@@ -736,7 +748,9 @@ proc_compressed( CTX c, PACKET *pkt )
     int rc;
 
     /*printf("zip: compressed data packet\n");*/
-    if( c->sigs_only )
+    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 );
@@ -800,8 +814,8 @@ do_check_sig( CTX c, KBNODE node, int *is_selfsig,
            return check_key_signature( c->list, node, is_selfsig );
        }
        else if( sig->sig_class == 0x20 ) {
-           log_info(_("standalone revocation - "
-                      "use \"gpg --import\" to apply\n"));
+           log_error (_("standalone revocation - "
+                         "use \"gpg --import\" to apply\n"));
            return G10ERR_NOT_PROCESSED;
        }
        else {
@@ -1137,6 +1151,25 @@ proc_signature_packets( void *anchor, IOBUF a,
     c->signed_data = signedfiles;
     c->sigfilename = sigfilename;
     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 = G10ERR_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;
 }
@@ -1301,47 +1334,32 @@ do_proc_packets( CTX c, IOBUF a )
 static pka_info_t *
 get_pka_address (PKT_signature *sig)
 {
-  const unsigned char *p;
-  size_t len, n1, n2;
-  int seq = 0;
   pka_info_t *pka = NULL;
+  struct notation *nd,*notation;
+
+  notation=sig_to_notation(sig);
 
-  while ((p = enum_sig_subpkt (sig->hashed, SIGSUBPKT_NOTATION,
-                               &len, &seq, NULL)))
+  for(nd=notation;nd;nd=nd->next)
     {
-      if (len < 8)
-        continue; /* Notation packet is too short. */
-      n1 = (p[4]<<8)|p[5];
-      n2 = (p[6]<<8)|p[7];
-      if (8 + n1 + n2 != len)
-        continue; /* Length fields of notation packet are inconsistent. */
-      p += 8;
-      if (n1 != 21 || memcmp (p, "pka-address@gnupg.org", 21))
+      if(strcmp(nd->name,"pka-address@gnupg.org")!=0)
         continue; /* Not the notation we want. */
-      p += n1;
-      if (n2 < 3)
-        continue; /* Impossible email address. */
-
-      if (pka)
-        break; /* For now we only use the first valid PKA notation. In
-                  future we might want to keep additional PKA
-                  notations in a linked list. */
-
-      pka = xmalloc (sizeof *pka + n2);
-      pka->valid = 0;
-      pka->checked = 0;
-      pka->uri = NULL;
-      memcpy (pka->email, p, n2);
-      pka->email[n2] = 0;
-
-      if (!is_valid_mailbox (pka->email))
-        {
-          /* We don't accept invalid mail addresses. */
-          xfree (pka);
-          pka = NULL;
-        }
+
+      /* For now we only use the first valid PKA notation. In future
+        we might want to keep additional PKA notations in a linked
+        list. */
+      if (is_valid_mailbox (pka->email))
+       {
+         pka = xmalloc (sizeof *pka + strlen(nd->value));
+         pka->valid = 0;
+         pka->checked = 0;
+         pka->uri = NULL;
+         strcpy (pka->email, nd->value);
+         break;
+       }
     }
 
+  free_notation(notation);
+
   return pka;
 }
 
@@ -1379,69 +1397,119 @@ pka_uri_from_sig (PKT_signature *sig)
 static int
 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;
+  PKT_signature *sig = node->pkt->pkt.signature;
+  const char *astr;
+  int rc, is_expkey=0, is_revkey=0;
 
-    if( opt.skip_verify ) {
-       log_info(_("signature verification suppressed\n"));
-       return 0;
+  if (opt.skip_verify)
+    {
+      log_info(_("signature verification suppressed\n"));
+      return 0;
     }
 
-    /* It is not in all cases possible to check multiple signatures:
-     * PGP 2 (which is also allowed by OpenPGP), does use the packet
-     * sequence: sig+data,  OpenPGP does use onepas+data=sig and GnuPG
-     * sometimes uses (because I did'nt read the specs right) data+sig.
-     * Because it is possible to create multiple signatures with
-     * different packet sequence (e.g. data+sig and sig+data) it might
-     * not be possible to get it right:  let's say we have:
-     * data+sig, sig+data,sig+data and we have not yet encountered the last
-     * data, we could also see this a one data with 2 signatures and then 
-     * data+sig.
-     * To protect against this we check that all signatures follow
-     * without any intermediate packets.  Note, that we won't get this
-     * error when we use onepass packets or cleartext signatures because
-     * we reset the list every time
-     *
-     * FIXME: Now that we have these marker packets, we should create a 
-     * real grammar and check against this.
-     */
-    {
-        KBNODE n;
-        int n_sig=0;
+  /* Check that the message composition is valid.
 
-        for (n=c->list; n; n=n->next ) {
-            if ( n->pkt->pkttype == PKT_SIGNATURE ) 
-                n_sig++;
-        }
-        if (n_sig > 1) { /* more than one signature - check sequence */
-            int tmp, onepass;
-
-            for (tmp=onepass=0,n=c->list; n; n=n->next ) {
-                if (n->pkt->pkttype == PKT_ONEPASS_SIG) 
-                    onepass++;
-                else if (n->pkt->pkttype == PKT_GPG_CONTROL
-                         && n->pkt->pkt.gpg_control->control
-                            == CTRLPKT_CLEARSIGN_START ) {
-                    onepass++; /* handle the same way as a onepass */
-                }
-                else if ( (tmp && n->pkt->pkttype != PKT_SIGNATURE) ) {
-                    log_error(_("can't handle these multiple signatures\n"));
-                    return 0;
-                }
-                else if ( n->pkt->pkttype == PKT_SIGNATURE ) 
-                    tmp = 1;
-                else if (!tmp && !onepass 
-                         && n->pkt->pkttype == PKT_GPG_CONTROL
-                         && n->pkt->pkt.gpg_control->control
-                            == CTRLPKT_PLAINTEXT_MARK ) {
-                    /* plaintext before signatures but no one-pass packets*/
-                    log_error(_("can't handle these multiple signatures\n"));
-                    return 0;
-                }
-            }
-        }
-    }
+     Per RFC-2440bis (-15) allowed:
+
+     S{1,n}           -- detached signature.
+     S{1,n} P         -- old style PGP2 signature
+     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)
+                 (Note that the current rfc2440bis draft also allows
+                  for a signed message but that does not work as it
+                  introduces ambiguities.)
+              We keep track of these packages using the marker packet
+              CTRLPKT_PLAINTEXT_MARK.
+          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.
+  */
+  {
+    KBNODE n;
+    int n_onepass, n_sig;
+
+/*     log_debug ("checking signature packet composition\n"); */
+/*     dump_kbnode (c->list); */
+
+    n = c->list;
+    assert (n);
+    if ( n->pkt->pkttype == PKT_SIGNATURE ) 
+      {
+        /* This is either "S{1,n}" case (detached signature) or
+           "S{1,n} P" (old style PGP2 signature). */
+        for (n = n->next; n; n = n->next)
+          if (n->pkt->pkttype != PKT_SIGNATURE)
+            break;
+        if (!n)
+          ; /* Okay, this is a detached signature.  */
+        else if (n->pkt->pkttype == PKT_GPG_CONTROL
+                 && (n->pkt->pkt.gpg_control->control
+                     == CTRLPKT_PLAINTEXT_MARK) )
+          {
+            if (n->next)
+              goto ambiguous;  /* We only allow one P packet. */
+          }
+        else
+          goto ambiguous;
+      }
+    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;
+             n && n->pkt->pkttype == PKT_ONEPASS_SIG; n = n->next)
+          n_onepass++;
+        if (!n || !(n->pkt->pkttype == PKT_GPG_CONTROL
+                    && (n->pkt->pkt.gpg_control->control
+                        == CTRLPKT_PLAINTEXT_MARK)))
+          goto ambiguous;
+        for (n_sig=0, n = n->next;
+             n && n->pkt->pkttype == PKT_SIGNATURE; n = n->next)
+          n_sig++;
+        if (!n_sig)
+          goto ambiguous;
+        if (n && !opt.allow_multisig_verification)
+          goto ambiguous;
+        if (n_onepass != n_sig)
+          {
+            log_info ("number of one-pass packets does not match "
+                      "number of signature packets\n");
+            goto ambiguous;
+          }
+      }
+    else if (n->pkt->pkttype == PKT_GPG_CONTROL
+             && n->pkt->pkt.gpg_control->control == CTRLPKT_CLEARSIGN_START )
+      {
+        /* This is the "C P S{1,n}" case (clear text signature). */
+        n = n->next;
+        if (!n || !(n->pkt->pkttype == PKT_GPG_CONTROL
+                    && (n->pkt->pkt.gpg_control->control
+                        == CTRLPKT_PLAINTEXT_MARK)))
+          goto ambiguous;
+        for (n_sig=0, n = n->next;
+             n && n->pkt->pkttype == PKT_SIGNATURE; n = n->next)
+          n_sig++;
+        if (n || !n_sig)
+          goto ambiguous;
+      }
+    else 
+      {
+      ambiguous:
+        log_error(_("can't handle this ambiguous signature data\n"));
+        return 0;
+      }
+
+  }
+
+  /* (Indendation below not yet changed to GNU style.) */
 
     astr = pubkey_algo_to_string( sig->pubkey_algo );
     if(keystrlen()>8)
@@ -1499,11 +1567,11 @@ check_sig_and_print( CTX c, KBNODE node )
          }
       }
 
-
     /* 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_PKA_RETRIEVE))
+        && opt.keyserver_options.options&KEYSERVER_AUTO_KEY_RETRIEVE
+         && opt.keyserver_options.options&KEYSERVER_HONOR_PKA_RECORD)
       {
         const char *uri = pka_uri_from_sig (sig);
         
@@ -1514,7 +1582,7 @@ check_sig_and_print( CTX c, KBNODE node )
             int res;
             struct keyserver_spec *spec;
             
-            spec = parse_keyserver_uri (uri, 0, NULL, 0);
+            spec = parse_keyserver_uri (uri, 1, NULL, 0);
             if (spec)
               {
                 glo_ctrl.in_auto_key_retrieve++;
@@ -1527,12 +1595,11 @@ check_sig_and_print( CTX c, KBNODE node )
           }
       }
 
-
     /* 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))
+       && opt.keyserver_options.options&KEYSERVER_AUTO_KEY_RETRIEVE)
       {
        int res;
 
@@ -1784,7 +1851,8 @@ check_sig_and_print( CTX c, KBNODE node )
 
        if (!rc)
           {
-            pka_uri_from_sig (sig); /* Make sure PKA info is available. */
+           if(opt.verify_options&VERIFY_PKA_LOOKUPS)
+             pka_uri_from_sig (sig); /* Make sure PKA info is available. */
            rc = check_signatures_trust( sig );
           }
 
@@ -1867,7 +1935,8 @@ proc_tree( CTX c, KBNODE node )
            /* prepare to create all requested message digests */
            c->mfx.md = md_open(0, 0);
 
-           /* fixme: why looking for the signature packet and not 1passpacket*/
+           /* fixme: why looking for the signature packet and not the
+               one-pass packet? */
            for( n1 = node; (n1 = find_next_kbnode(n1, PKT_SIGNATURE )); ) {
                md_enable( c->mfx.md, n1->pkt->pkt.signature->digest_algo);
            }