* options.h, getkey.c (merge_selfsigs_subkey), gpg.c (main), sig-check.c
[gnupg.git] / g10 / mainproc.c
index 5913f93..7c13921 100644 (file)
@@ -327,7 +327,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)
              {
@@ -1296,6 +1311,86 @@ do_proc_packets( CTX c, IOBUF a )
 }
 
 
+/* Helper for pka_uri_from_sig to parse the to-be-verified address out
+   of the notation data. */
+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;
+
+  while ((p = enum_sig_subpkt (sig->hashed, SIGSUBPKT_NOTATION,
+                               &len, &seq, NULL)))
+    {
+      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))
+        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;
+        }
+    }
+
+  return pka;
+}
+
+
+/* Return the URI from a DNS PKA record.  If this record has already
+   be retrieved for the signature we merely return it; if not we go
+   out and try to get that DNS record. */
+static const char *
+pka_uri_from_sig (PKT_signature *sig)
+{
+  if (!sig->flags.pka_tried)
+    {
+      assert (!sig->pka_info);
+      sig->flags.pka_tried = 1;
+      sig->pka_info = get_pka_address (sig);
+      if (sig->pka_info)
+        {
+          char *uri;
+
+          uri = get_pka_info (sig->pka_info->email, sig->pka_info->fpr);
+          if (uri)
+            {
+              sig->pka_info->valid = 1;
+              if (!*uri)
+                xfree (uri);
+              else
+                sig->pka_info->uri = uri;
+            }
+        }
+    }
+  return sig->pka_info? sig->pka_info->uri : NULL;
+}
+
+
 static int
 check_sig_and_print( CTX c, KBNODE node )
 {
@@ -1419,8 +1514,37 @@ check_sig_and_print( CTX c, KBNODE node )
          }
       }
 
-    /* If the preferred keyserver thing above didn't work, this is a
-       second try. */
+
+    /* 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))
+      {
+        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, 0, NULL, 0);
+            if (spec)
+              {
+                glo_ctrl.in_auto_key_retrieve++;
+                res = keyserver_import_keyid (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 );
+              }
+          }
+      }
+
+
+    /* 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))
@@ -1673,8 +1797,11 @@ check_sig_and_print( CTX c, KBNODE node )
            free_public_key( vpk );
        }
 
-       if( !rc )
+       if (!rc)
+          {
+            pka_uri_from_sig (sig); /* Make sure PKA info is available. */
            rc = check_signatures_trust( sig );
+          }
 
        if(sig->flags.expired)
          {