* gpgsm.c: New option --auto-issuer-key-retrieve.
authorWerner Koch <wk@gnupg.org>
Sat, 29 Jun 2002 14:01:53 +0000 (14:01 +0000)
committerWerner Koch <wk@gnupg.org>
Sat, 29 Jun 2002 14:01:53 +0000 (14:01 +0000)
* certpath.c (find_up): Try to retrieve an issuer key from an
external source and from the ephemeral key DB.
(find_up_store_certs_cb): New.

* keydb.c (keydb_set_ephemeral): Does now return the old
state.  Call the backend only when required.

* call-dirmngr.c (start_dirmngr): Use GNUPG_DEFAULT_DIRMNGR.
(lookup_status_cb): Issue status only when CTRL is not NULL.
(gpgsm_dirmngr_lookup): Document that CTRL is optional.

* call-agent.c (start_agent): Use GNUPG_DEFAULT_AGENT.

sm/ChangeLog
sm/call-agent.c
sm/call-dirmngr.c
sm/certchain.c
sm/certpath.c
sm/gpgsm.c
sm/gpgsm.h
sm/keydb.c

index 160fe47..6a0200b 100644 (file)
@@ -1,3 +1,19 @@
+2002-06-29  Werner Koch  <wk@gnupg.org>
+
+       * gpgsm.c: New option --auto-issuer-key-retrieve.
+       * certpath.c (find_up): Try to retrieve an issuer key from an
+       external source and from the ephemeral key DB.
+       (find_up_store_certs_cb): New.
+
+       * keydb.c (keydb_set_ephemeral): Does now return the old
+       state.  Call the backend only when required.
+
+       * call-dirmngr.c (start_dirmngr): Use GNUPG_DEFAULT_DIRMNGR.
+       (lookup_status_cb): Issue status only when CTRL is not NULL.
+       (gpgsm_dirmngr_lookup): Document that CTRL is optional.
+
+       * call-agent.c (start_agent): Use GNUPG_DEFAULT_AGENT.
+
 2002-06-28  Werner Koch  <wk@gnupg.org>
 
        * server.c (cmd_recipient): Add more reason codes.
index b3c7857..9462deb 100644 (file)
@@ -164,7 +164,7 @@ start_agent (void)
         }
 
       if (!opt.agent_program || !*opt.agent_program)
-        opt.agent_program = "../agent/gpg-agent";
+        opt.agent_program = GNUPG_DEFAULT_AGENT;
       if ( !(pgmname = strrchr (opt.agent_program, '/')))
         pgmname = opt.agent_program;
       else
index 017191d..30b3476 100644 (file)
@@ -156,7 +156,7 @@ start_dirmngr (void)
         }
 
       if (!opt.dirmngr_program || !*opt.dirmngr_program)
-        opt.dirmngr_program = "/usr/sbin/dirmngr";
+        opt.dirmngr_program = GNUPG_DEFAULT_DIRMNGR;
       if ( !(pgmname = strrchr (opt.dirmngr_program, '/')))
         pgmname = opt.dirmngr_program;
       else
@@ -432,9 +432,12 @@ lookup_status_cb (void *opaque, const char *line)
 
   if (!strncmp (line, "TRUNCATED", 9) && (line[9]==' ' || !line[9]))
     {
-      for (line +=9; *line == ' '; line++)
-        ;
-      gpgsm_status (parm->ctrl, STATUS_TRUNCATED, line);
+      if (parm->ctrl)
+        {
+          for (line +=9; *line == ' '; line++)
+            ;
+          gpgsm_status (parm->ctrl, STATUS_TRUNCATED, line);
+        }
     }
   return 0;
 }
@@ -442,7 +445,8 @@ lookup_status_cb (void *opaque, const char *line)
 
 /* Run the Directroy Managers lookup command using the apptern
    compiled from the strings given in NAMES.  The caller must provide
-   the callback CB which will be passed cert by cert. */
+   the callback CB which will be passed cert by cert.  Note that CTRL
+   is optional. */
 int 
 gpgsm_dirmngr_lookup (CTRL ctrl, STRLIST names,
                       void (*cb)(void*, KsbaCert), void *cb_value)
index a32c2d7..0457a0a 100644 (file)
@@ -196,6 +196,15 @@ check_cert_policy (KsbaCert cert)
 }
 
 
+static void
+find_up_store_certs_cb (void *cb_value, KsbaCert cert)
+{
+  if (keydb_store_cert (cert, 1))
+    log_error ("error storing issuer certificate as ephemeral\n");
+  ++*(int*)cb_value;
+}
+
+
 static int
 find_up (KEYDB_HANDLE kh, KsbaCert cert, const char *issuer)
 {
@@ -211,13 +220,82 @@ find_up (KEYDB_HANDLE kh, KsbaCert cert, const char *issuer)
           rc = keydb_search_issuer_sn (kh, s, authidno);
           if (rc)
               keydb_search_reset (kh);
+          if (rc == -1)
+            { /* And try the ephemeral DB. */
+              int old = keydb_set_ephemeral (kh, 1);
+              if (!old)
+                {
+                  rc = keydb_search_issuer_sn (kh, s, authidno);
+                  if (rc)
+                    keydb_search_reset (kh);
+                }
+              keydb_set_ephemeral (kh, old);
+            }
         }
       ksba_name_release (authid);
       xfree (authidno);
+      /* Fixme: don't know how to do dirmngr lookup with serial+issuer. */
     }
   
-  if (rc)
-    rc = keydb_search_subject (kh, issuer);
+  if (rc) /* not found via authorithyKeyIdentifier, try regular issuer name */
+      rc = keydb_search_subject (kh, issuer);
+  if (rc == -1)
+    {
+      /* Not found, lets see whether we have one in the ephemeral key DB. */
+      int old = keydb_set_ephemeral (kh, 1);
+      if (!old)
+        {
+          keydb_search_reset (kh);
+          rc = keydb_search_subject (kh, issuer);
+        }
+      keydb_set_ephemeral (kh, old);
+    }
+
+  if (rc == -1 && opt.auto_issuer_key_retrieve)
+    {
+      STRLIST names = NULL;
+      int count = 0;
+      char *pattern;
+      const char *s;
+      
+      if (opt.verbose)
+        log_info (_("looking up issuer at external location\n"));
+      /* dirmngr is confused about unknown attributes so has a quick
+         and ugly hack we locate the CN and use this and the
+         following.  Fixme: we should have far ebtter parsing in the
+         dirmngr. */
+      s = strstr (issuer, "CN=");
+      if (!s || s == issuer || s[-1] != ',')
+        s = issuer;
+
+      pattern = xtrymalloc (strlen (s)+2);
+      if (!pattern)
+        return GNUPG_Out_Of_Core;
+      strcpy (stpcpy (pattern, "/"), s);
+      add_to_strlist (&names, pattern);
+      xfree (pattern);
+      rc = gpgsm_dirmngr_lookup (NULL, names, find_up_store_certs_cb, &count);
+      free_strlist (names);
+      if (opt.verbose)
+        log_info (_("number of issuers matching: %d\n"), count);
+      if (rc) 
+        {
+          log_error ("external key lookup failed: %s\n", gnupg_strerror (rc));
+          rc = -1;
+        }
+      else if (!count)
+        rc = -1;
+      else
+        {
+          int old;
+          /* The issuers are currently stored in the ephemeral key
+             DB, so we temporary switch to ephemeral mode. */
+          old = keydb_set_ephemeral (kh, 1);
+          keydb_search_reset (kh);
+          rc = keydb_search_subject (kh, issuer);
+          keydb_set_ephemeral (kh, old);
+        }
+    }
   return rc;
 }
 
index a32c2d7..0457a0a 100644 (file)
@@ -196,6 +196,15 @@ check_cert_policy (KsbaCert cert)
 }
 
 
+static void
+find_up_store_certs_cb (void *cb_value, KsbaCert cert)
+{
+  if (keydb_store_cert (cert, 1))
+    log_error ("error storing issuer certificate as ephemeral\n");
+  ++*(int*)cb_value;
+}
+
+
 static int
 find_up (KEYDB_HANDLE kh, KsbaCert cert, const char *issuer)
 {
@@ -211,13 +220,82 @@ find_up (KEYDB_HANDLE kh, KsbaCert cert, const char *issuer)
           rc = keydb_search_issuer_sn (kh, s, authidno);
           if (rc)
               keydb_search_reset (kh);
+          if (rc == -1)
+            { /* And try the ephemeral DB. */
+              int old = keydb_set_ephemeral (kh, 1);
+              if (!old)
+                {
+                  rc = keydb_search_issuer_sn (kh, s, authidno);
+                  if (rc)
+                    keydb_search_reset (kh);
+                }
+              keydb_set_ephemeral (kh, old);
+            }
         }
       ksba_name_release (authid);
       xfree (authidno);
+      /* Fixme: don't know how to do dirmngr lookup with serial+issuer. */
     }
   
-  if (rc)
-    rc = keydb_search_subject (kh, issuer);
+  if (rc) /* not found via authorithyKeyIdentifier, try regular issuer name */
+      rc = keydb_search_subject (kh, issuer);
+  if (rc == -1)
+    {
+      /* Not found, lets see whether we have one in the ephemeral key DB. */
+      int old = keydb_set_ephemeral (kh, 1);
+      if (!old)
+        {
+          keydb_search_reset (kh);
+          rc = keydb_search_subject (kh, issuer);
+        }
+      keydb_set_ephemeral (kh, old);
+    }
+
+  if (rc == -1 && opt.auto_issuer_key_retrieve)
+    {
+      STRLIST names = NULL;
+      int count = 0;
+      char *pattern;
+      const char *s;
+      
+      if (opt.verbose)
+        log_info (_("looking up issuer at external location\n"));
+      /* dirmngr is confused about unknown attributes so has a quick
+         and ugly hack we locate the CN and use this and the
+         following.  Fixme: we should have far ebtter parsing in the
+         dirmngr. */
+      s = strstr (issuer, "CN=");
+      if (!s || s == issuer || s[-1] != ',')
+        s = issuer;
+
+      pattern = xtrymalloc (strlen (s)+2);
+      if (!pattern)
+        return GNUPG_Out_Of_Core;
+      strcpy (stpcpy (pattern, "/"), s);
+      add_to_strlist (&names, pattern);
+      xfree (pattern);
+      rc = gpgsm_dirmngr_lookup (NULL, names, find_up_store_certs_cb, &count);
+      free_strlist (names);
+      if (opt.verbose)
+        log_info (_("number of issuers matching: %d\n"), count);
+      if (rc) 
+        {
+          log_error ("external key lookup failed: %s\n", gnupg_strerror (rc));
+          rc = -1;
+        }
+      else if (!count)
+        rc = -1;
+      else
+        {
+          int old;
+          /* The issuers are currently stored in the ephemeral key
+             DB, so we temporary switch to ephemeral mode. */
+          old = keydb_set_ephemeral (kh, 1);
+          keydb_search_reset (kh);
+          rc = keydb_search_subject (kh, issuer);
+          keydb_set_ephemeral (kh, old);
+        }
+    }
   return rc;
 }
 
index 9d91cd9..7b1b0d7 100644 (file)
@@ -112,7 +112,7 @@ enum cmd_and_opt_values {
   oPolicyFile,
   oDisablePolicyChecks,
   oEnablePolicyChecks,
-
+  oAutoIssuerKeyRetrieve,
   
 
   oTextmode,
@@ -259,6 +259,9 @@ static ARGPARSE_OPTS opts[] = {
                            N_("do not check certificate policies")},
     { oEnablePolicyChecks, "enable-policy-checks", 0, "@"},
 
+    { oAutoIssuerKeyRetrieve, "auto-issuer-key-retrieve", 0, 
+      N_("fetch missing issuer certificates")},
+
 #if 0
     { oDefRecipient, "default-recipient" ,2,
                                  N_("|NAME|use NAME as default recipient")},
@@ -809,7 +812,10 @@ main ( int argc, char **argv)
         case oEnablePolicyChecks:
           opt.no_policy_check = 0;
           break;
-
+          
+        case oAutoIssuerKeyRetrieve:
+          opt.auto_issuer_key_retrieve = 1;
+          break;
 
         case oOutput: opt.outfile = pargs.r.ret_str; break;
 
index b4f7ebe..efa98de 100644 (file)
@@ -79,6 +79,8 @@ struct {
   char *policy_file;        /* full pathname of policy file */
   int no_policy_check;      /* ignore certificate policies */
   int no_path_validation;   /* Bypass all cert path validity tests */
+
+  int auto_issuer_key_retrieve; /* try to retrieve a missing issuer key. */
 } opt;
 
 
index bc47214..52f40f1 100644 (file)
@@ -59,7 +59,7 @@ struct keydb_handle {
   int locked;
   int found;
   int current;
-  int ephemeral;
+  int is_ephemeral;
   int used; /* items in active */
   struct resource_item active[MAX_KEYDB_RESOURCES];
 };
@@ -332,27 +332,34 @@ keydb_get_resource_name (KEYDB_HANDLE hd)
   return s? s: "";
 }
 
+/* Switch the handle into ephemeral mode and return the orginal value. */
 int
 keydb_set_ephemeral (KEYDB_HANDLE hd, int yes)
 {
   int i;
 
   if (!hd)
-    return GNUPG_Invalid_Value;
+    return 0;
 
-  for (i=0; i < hd->used; i++)
+  yes = !!yes;
+  if (hd->is_ephemeral != yes)
     {
-      switch (hd->active[i].type) 
+      for (i=0; i < hd->used; i++)
         {
-        case KEYDB_RESOURCE_TYPE_NONE:
-          break;
-        case KEYDB_RESOURCE_TYPE_KEYBOX:
-          keybox_set_ephemeral (hd->active[i].u.kr, yes);
-          break;
+          switch (hd->active[i].type) 
+            {
+            case KEYDB_RESOURCE_TYPE_NONE:
+              break;
+            case KEYDB_RESOURCE_TYPE_KEYBOX:
+              keybox_set_ephemeral (hd->active[i].u.kr, yes);
+              break;
+            }
         }
     }
-
-  return 0;
+      
+  i = hd->is_ephemeral;
+  hd->is_ephemeral = yes;
+  return i;
 }