Merge branch 'master' into key-storage-work
authorWerner Koch <wk@gnupg.org>
Tue, 12 Feb 2013 18:17:42 +0000 (19:17 +0100)
committerWerner Koch <wk@gnupg.org>
Tue, 12 Feb 2013 18:17:42 +0000 (19:17 +0100)
26 files changed:
common/iobuf.c
common/logging.c
common/logging.h
g10/Makefile.am
g10/delkey.c
g10/export.c
g10/getkey.c
g10/gpg.c
g10/gpgv.c
g10/keydb.c
g10/keydb.h
g10/keyserver.c
g10/options.h
g10/pubkey-enc.c
g10/revoke.c
g10/trustdb.c
kbx/kbxutil.c
kbx/keybox-blob.c
kbx/keybox-defs.h
kbx/keybox-dump.c
kbx/keybox-file.c
kbx/keybox-init.c
kbx/keybox-openpgp.c
kbx/keybox-search.c
kbx/keybox-update.c
kbx/keybox.h

index 3ba3582..a305830 100644 (file)
@@ -2311,7 +2311,7 @@ iobuf_seek (iobuf_t a, off_t newpos)
        }
       clearerr (fp);
     }
-  else
+  else if (a->use != 3)  /* Not a temp stream.  */
     {
       for (; a; a = a->chain)
        {
@@ -2338,7 +2338,8 @@ iobuf_seek (iobuf_t a, off_t newpos)
        }
 #endif
     }
-  a->d.len = 0;                        /* discard buffer */
+  if (a->use != 3)
+    a->d.len = 0;      /* Discard the buffer  unless it is a temp stream.  */
   a->d.start = 0;
   a->nbytes = 0;
   a->nlimit = 0;
index f91671e..cdfd659 100644 (file)
@@ -857,6 +857,33 @@ log_printhex (const char *text, const void *buffer, size_t length)
 }
 
 
+void
+log_clock (const char *string)
+{
+#if 0
+  static unsigned long long initial;
+  struct timespec tv;
+  unsigned long long now;
+
+  if (clock_gettime (CLOCK_REALTIME, &tv))
+    {
+      log_debug ("error getting the realtime clock value\n");
+      return;
+    }
+  now = tv.tv_sec * 1000000000ull;
+  now += tv.tv_nsec;
+
+  if (!initial)
+    initial = now;
+
+  log_debug ("[%6llu] %s", (now - initial)/1000, string);
+#else
+  /* You need to link with -ltr to enable the above code.  */
+  log_debug ("[not enabled in the source] %s", string);
+#endif
+}
+
+
 #if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 5 )
 void
 bug_at( const char *file, int line, const char *func )
index b0d662b..89913e6 100644 (file)
@@ -96,5 +96,7 @@ void log_flush (void);
    by the hexdump and a final LF.  */
 void log_printhex (const char *text, const void *buffer, size_t length);
 
+void log_clock (const char *string);
+
 
 #endif /*LIBJNLIB_LOGGING_H*/
index e9f69b3..899677c 100644 (file)
@@ -27,7 +27,7 @@ include $(top_srcdir)/am/cmacros.am
 
 AM_CFLAGS = $(LIBGCRYPT_CFLAGS) $(LIBASSUAN_CFLAGS) $(GPG_ERROR_CFLAGS)
 
-needed_libs = $(libcommon) ../gl/libgnu.a
+needed_libs = ../kbx/libkeybox.a $(libcommon) ../gl/libgnu.a
 
 bin_PROGRAMS = gpg2
 if !HAVE_W32CE_SYSTEM
@@ -120,13 +120,18 @@ gpgv2_SOURCES = gpgv.c           \
 #             ks-db.h \
 #             $(common_source)
 
+# FIXME: Libkeybox.a links to libksba thus we need to add libksba
+# here, even that it is not used by gpg.  A proper solution would
+# either to split up libkeybox.a or to use a separate keybox daemon.
 LDADD =  $(needed_libs) ../common/libgpgrl.a \
          $(ZLIBS) $(DNSLIBS) $(LIBREADLINE) \
          $(LIBINTL) $(CAPLIBS) $(NETLIBS)
-gpg2_LDADD =  $(LDADD) $(LIBGCRYPT_LIBS) $(LIBASSUAN_LIBS) $(GPG_ERROR_LIBS) \
+gpg2_LDADD = $(LDADD) $(LIBGCRYPT_LIBS) \
+             $(KSBA_LIBS) $(LIBASSUAN_LIBS) $(GPG_ERROR_LIBS) \
             $(LIBICONV) $(extra_sys_libs)
 gpg2_LDFLAGS = $(extra_bin_ldflags)
-gpgv2_LDADD = $(LDADD) $(LIBGCRYPT_LIBS) $(LIBASSUAN_LIBS) $(GPG_ERROR_LIBS) \
+gpgv2_LDADD = $(LDADD) $(LIBGCRYPT_LIBS) \
+              $(KSBA_LIBS) $(LIBASSUAN_LIBS) $(GPG_ERROR_LIBS) \
              $(LIBICONV) $(extra_sys_libs)
 gpgv2_LDFLAGS = $(extra_bin_ldflags)
 
index 950af0e..22f2219 100644 (file)
@@ -68,7 +68,7 @@ do_delete_key( const char *username, int secret, int force, int *r_sec_avail )
                   || desc.mode == KEYDB_SEARCH_MODE_FPR16
                   || desc.mode == KEYDB_SEARCH_MODE_FPR20);
     if (!rc)
-      rc = keydb_search (hd, &desc, 1);
+      rc = keydb_search (hd, &desc, 1, NULL);
     if (rc) {
        log_error (_("key \"%s\" not found: %s\n"), username, g10_errstr (rc));
        write_status_text( STATUS_DELETE_PROBLEM, "1" );
index d8d9c05..7fbcb34 100644 (file)
@@ -803,7 +803,7 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret,
       kek = NULL;
     }
 
-  while (!(err = keydb_search2 (kdbhd, desc, ndesc, &descindex)))
+  while (!(err = keydb_search (kdbhd, desc, ndesc, &descindex)))
     {
       int skip_until_subkey = 0;
       u32 keyid[2];
index 9294273..60429b6 100644 (file)
@@ -128,7 +128,7 @@ void
 cache_public_key (PKT_public_key * pk)
 {
 #if MAX_PK_CACHE_ENTRIES
-  pk_cache_entry_t ce;
+  pk_cache_entry_t ce, ce2;
   u32 keyid[2];
 
   if (pk_cache_disabled)
@@ -158,11 +158,25 @@ cache_public_key (PKT_public_key * pk)
 
   if (pk_cache_entries >= MAX_PK_CACHE_ENTRIES)
     {
-      /* fixme: Use another algorithm to free some cache slots.  */
-      pk_cache_disabled = 1;
-      if (opt.verbose > 1)
-       log_info (_("too many entries in pk cache - disabled\n"));
-      return;
+      int n;
+
+      /* Remove the last 50% of the entries.  */
+      for (ce = pk_cache, n = 0; ce && n < pk_cache_entries/2; n++)
+        ce = ce->next;
+      if (ce != pk_cache && ce->next)
+        {
+          ce2 = ce->next;
+          ce->next = NULL;
+          ce = ce2;
+          for (; ce; ce = ce2)
+            {
+              ce2 = ce->next;
+              free_public_key (ce->pk);
+              xfree (ce);
+              pk_cache_entries--;
+            }
+        }
+      assert (pk_cache_entries < MAX_PK_CACHE_ENTRIES);
     }
   pk_cache_entries++;
   ce = xmalloc (sizeof *ce);
@@ -444,8 +458,9 @@ get_pubkey_fast (PKT_public_key * pk, u32 * keyid)
       return G10ERR_NO_PUBKEY;
     }
 
-  assert (keyblock->pkt->pkttype == PKT_PUBLIC_KEY
-         || keyblock->pkt->pkttype == PKT_PUBLIC_SUBKEY);
+  assert (keyblock && keyblock->pkt
+          && (keyblock->pkt->pkttype == PKT_PUBLIC_KEY
+              || keyblock->pkt->pkttype == PKT_PUBLIC_SUBKEY));
 
   keyid_from_pk (keyblock->pkt->pkt.public_key, pkid);
   if (keyid[0] == pkid[0] && keyid[1] == pkid[1])
@@ -2450,7 +2465,7 @@ lookup (getkey_ctx_t ctx, kbnode_t *ret_keyblock, int want_secret)
   int no_suitable_key = 0;
 
   rc = 0;
-  while (!(rc = keydb_search (ctx->kr_handle, ctx->items, ctx->nitems)))
+  while (!(rc = keydb_search (ctx->kr_handle, ctx->items, ctx->nitems, NULL)))
     {
       /* If we are searching for the first key we have to make sure
          that the next iteration does not do an implicit reset.
@@ -2875,7 +2890,7 @@ have_secret_key_with_kid (u32 *keyid)
   desc.mode = KEYDB_SEARCH_MODE_LONG_KID;
   desc.u.kid[0] = keyid[0];
   desc.u.kid[1] = keyid[1];
-  while (!result && !(err = keydb_search (kdbhd, &desc, 1)))
+  while (!result && !(err = keydb_search (kdbhd, &desc, 1, NULL)))
     {
       desc.mode = KEYDB_SEARCH_MODE_NEXT;
       err = keydb_get_keyblock (kdbhd, &keyblock);
index 9adc21a..a19c9a7 100644 (file)
--- a/g10/gpg.c
+++ b/g10/gpg.c
@@ -1032,7 +1032,7 @@ set_debug (const char *level)
   gcry_control (GCRYCTL_SET_VERBOSITY, (int)opt.verbose);
 
   if (opt.debug)
-    log_info ("enabled debug flags:%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
+    log_info ("enabled debug flags:%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
               (opt.debug & DBG_PACKET_VALUE )? " packet":"",
               (opt.debug & DBG_MPI_VALUE    )? " mpi":"",
               (opt.debug & DBG_CIPHER_VALUE )? " cipher":"",
@@ -1045,7 +1045,8 @@ set_debug (const char *level)
               (opt.debug & DBG_HASHING_VALUE)? " hashing":"",
               (opt.debug & DBG_EXTPROG_VALUE)? " extprog":"",
               (opt.debug & DBG_CARD_IO_VALUE)? " cardio":"",
-              (opt.debug & DBG_ASSUAN_VALUE )? " assuan":"");
+              (opt.debug & DBG_ASSUAN_VALUE )? " assuan":"",
+              (opt.debug & DBG_CLOCK_VALUE  )? " clock":"");
 }
 
 
@@ -2252,8 +2253,8 @@ main (int argc, char **argv)
          case oAnswerNo: opt.answer_no = 1; break;
          case oKeyring: append_to_strlist( &nrings, pargs.r.ret_str); break;
          case oPrimaryKeyring:
-           sl=append_to_strlist( &nrings, pargs.r.ret_str);
-           sl->flags=2;
+           sl = append_to_strlist (&nrings, pargs.r.ret_str);
+           sl->flags = KEYDB_RESOURCE_FLAG_PRIMARY;
            break;
          case oShowKeyring:
            deprecated_warning(configname,configlineno,"--show-keyring",
@@ -3126,6 +3127,8 @@ main (int argc, char **argv)
       }
 
     set_debug (debug_level);
+    if (DBG_CLOCK)
+      log_clock ("start");
 
     /* Do these after the switch(), so they can override settings. */
     if(PGP2)
@@ -3410,11 +3413,7 @@ main (int argc, char **argv)
     if( opt.verbose > 1 )
        set_packet_list_mode(1);
 
-    /* Add the keyrings, but not for some special commands.  Also
-       avoid adding the secret keyring for a couple of commands to
-       avoid unneeded access in case the secrings are stored on a
-       floppy.
-
+    /* Add the keyrings, but not for some special commands.
        We always need to add the keyrings if we are running under
        SELinux, this is so that the rings are added to the list of
        secured files. */
@@ -3422,7 +3421,8 @@ main (int argc, char **argv)
         || (cmd != aDeArmor && cmd != aEnArmor && cmd != aGPGConfTest) )
       {
        if (!nrings || default_keyring)  /* Add default ring. */
-           keydb_add_resource ("pubring" EXTSEP_S "gpg", 4);
+           keydb_add_resource ("pubring" EXTSEP_S "gpg",
+                                KEYDB_RESOURCE_FLAG_DEFAULT);
        for (sl = nrings; sl; sl = sl->next )
           keydb_add_resource (sl->d, sl->flags);
       }
@@ -4112,6 +4112,8 @@ void
 g10_exit( int rc )
 {
   gcry_control (GCRYCTL_UPDATE_RANDOM_SEED_FILE);
+  if (DBG_CLOCK)
+    log_clock ("stop");
   if ( (opt.debug & DBG_MEMSTAT_VALUE) )
     {
       gcry_control (GCRYCTL_DUMP_MEMORY_STATS);
index 07e4a2e..5cb9c55 100644 (file)
@@ -196,11 +196,12 @@ main( int argc, char **argv )
   if (opt.verbose > 1)
     set_packet_list_mode(1);
 
-  /* Note: We open all keyrings in read-only mode (flag value: 8).  */
+  /* Note: We open all keyrings in read-only mode.  */
   if (!nrings)  /* No keyring given: use default one. */
-    keydb_add_resource ("trustedkeys" EXTSEP_S "gpg", 8);
+    keydb_add_resource ("trustedkeys" EXTSEP_S "gpg",
+                        KEYDB_RESOURCE_FLAG_READONLY);
   for (sl = nrings; sl; sl = sl->next)
-    keydb_add_resource (sl->d, 8);
+    keydb_add_resource (sl->d, KEYDB_RESOURCE_FLAG_READONLY);
 
   FREE_STRLIST (nrings);
 
index 75c036c..79ab5af 100644 (file)
@@ -1,6 +1,6 @@
 /* keydb.c - key database dispatcher
  * Copyright (C) 2001, 2002, 2003, 2004, 2005,
- *               2008, 2009, 2011 Free Software Foundation, Inc.
+ *               2008, 2009, 2011, 2013 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -34,6 +34,7 @@
 #include "main.h" /*try_make_homedir ()*/
 #include "packet.h"
 #include "keyring.h"
+#include "../kbx/keybox.h"
 #include "keydb.h"
 #include "i18n.h"
 
@@ -42,7 +43,8 @@ static int active_handles;
 typedef enum
   {
     KEYDB_RESOURCE_TYPE_NONE = 0,
-    KEYDB_RESOURCE_TYPE_KEYRING
+    KEYDB_RESOURCE_TYPE_KEYRING,
+    KEYDB_RESOURCE_TYPE_KEYBOX
   } KeydbResourceType;
 #define MAX_KEYDB_RESOURCES 40
 
@@ -51,6 +53,7 @@ struct resource_item
   KeydbResourceType type;
   union {
     KEYRING_HANDLE kr;
+    KEYBOX_HANDLE kb;
   } u;
   void *token;
 };
@@ -69,16 +72,48 @@ struct keydb_handle
 };
 
 
+/* This is a simple cache used to return the last result of a
+   successful long kid search.  This works only for keybox resources
+   because (due to lack of a copy_keyblock function) we need to store
+   an image of the keyblock which is fortunately instantly available
+   for keyboxes.  */
+enum keyblock_cache_states {
+  KEYBLOCK_CACHE_EMPTY,
+  KEYBLOCK_CACHE_PREPARED,
+  KEYBLOCK_CACHE_FILLED
+};
+
+struct {
+  enum keyblock_cache_states state;
+  u32 kid[2];
+  iobuf_t iobuf; /* Image of the keyblock.  */
+  u32 *sigstatus;
+  int pk_no;
+  int uid_no;
+} keyblock_cache;
+
+
 static int lock_all (KEYDB_HANDLE hd);
 static void unlock_all (KEYDB_HANDLE hd);
 
 
-/* Handle the creation of a keyring if it does not yet exist.  Take
-   into acount that other processes might have the keyring already
-   locked.  This lock check does not work if the directory itself is
-   not yet available. */
+static void
+keyblock_cache_clear (void)
+{
+  keyblock_cache.state = KEYBLOCK_CACHE_EMPTY;
+  xfree (keyblock_cache.sigstatus);
+  keyblock_cache.sigstatus = NULL;
+  iobuf_close (keyblock_cache.iobuf);
+  keyblock_cache.iobuf = NULL;
+}
+
+
+/* Handle the creation of a keyring or a keybox if it does not yet
+   exist.  Take into acount that other processes might have the
+   keyring/keybox already locked.  This lock check does not work if
+   the directory itself is not yet available. */
 static int
-maybe_create_keyring (char *filename, int force)
+maybe_create_keyring_or_box (char *filename, int is_box, int force)
 {
   dotlock_t lockhd = NULL;
   IOBUF iobuf;
@@ -139,29 +174,31 @@ maybe_create_keyring (char *filename, int force)
   lockhd = dotlock_create (filename, 0);
   if (!lockhd)
     {
+      rc = gpg_error_from_syserror ();
       /* A reason for this to fail is that the directory is not
          writable. However, this whole locking stuff does not make
          sense if this is the case. An empty non-writable directory
          with no keyring is not really useful at all. */
       if (opt.verbose)
-        log_info ("can't allocate lock for '%s'\n", filename );
+        log_info ("can't allocate lock for '%s': %s\n",
+                  filename, gpg_strerror (rc));
 
       if (!force)
         return gpg_error (GPG_ERR_ENOENT);
       else
-        return gpg_error (GPG_ERR_GENERAL);
+        return rc;
     }
 
   if ( dotlock_take (lockhd, -1) )
     {
+      rc = gpg_error_from_syserror ();
       /* This is something bad.  Probably a stale lockfile.  */
-      log_info ("can't lock '%s'\n", filename );
-      rc = G10ERR_GENERAL;
+      log_info ("can't lock '%s': %s\n", filename, gpg_strerror (rc));
       goto leave;
     }
 
   /* Now the real test while we are locked. */
-  if (!access(filename, F_OK))
+  if (!access (filename, F_OK))
     {
       rc = 0;  /* Okay, we may access the file now.  */
       goto leave;
@@ -180,17 +217,51 @@ maybe_create_keyring (char *filename, int force)
   if (!iobuf)
     {
       rc = gpg_error_from_syserror ();
-      log_error ( _("error creating keyring '%s': %s\n"),
-                  filename, strerror(errno));
+      if (is_box)
+        log_error (_("error creating keybox '%s': %s\n"),
+                   filename, gpg_strerror (rc));
+      else
+        log_error (_("error creating keyring '%s': %s\n"),
+                   filename, gpg_strerror (rc));
       goto leave;
     }
 
-  if (!opt.quiet)
-    log_info (_("keyring '%s' created\n"), filename);
-
   iobuf_close (iobuf);
   /* Must invalidate that ugly cache */
   iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE, 0, filename);
+
+  /* Make sure that at least one record is in a new keybox file, so
+     that the detection magic will work the next time it is used.  */
+  if (is_box)
+    {
+      FILE *fp = fopen (filename, "w");
+      if (!fp)
+        rc = gpg_error_from_syserror ();
+      else
+        {
+          rc = _keybox_write_header_blob (fp);
+          fclose (fp);
+        }
+      if (rc)
+        {
+          if (is_box)
+            log_error (_("error creating keybox '%s': %s\n"),
+                       filename, gpg_strerror (rc));
+          else
+            log_error (_("error creating keyring '%s': %s\n"),
+                       filename, gpg_strerror (rc));
+          goto leave;
+        }
+    }
+
+  if (!opt.quiet)
+    {
+      if (is_box)
+        log_info (_("keybox '%s' created\n"), filename);
+      else
+        log_info (_("keyring '%s' created\n"), filename);
+    }
+
   rc = 0;
 
  leave:
@@ -204,51 +275,49 @@ maybe_create_keyring (char *filename, int force)
 
 
 /*
- * Register a resource (which currently may only be a keyring file).
- * The first keyring which is added by this function is
- * created if it does not exist.
- * Note: this function may be called before secure memory is
- * available.
- * Flag 1   - Force.
- * Flag 2   - Mark resource as primary.
- * Flag 4   - This is a default resources.
- * Flag 8   - Open as read-only.
+ * Register a resource (keyring or aeybox).  The first keyring or
+ * keybox which is added by this function is created if it does not
+ * exist.  FLAGS are a combination of the KEYDB_RESOURCE_FLAG_
+ * constants as defined in keydb.h.
  */
 gpg_error_t
-keydb_add_resource (const char *url, int flags)
+keydb_add_resource (const char *url, unsigned int flags)
 {
-  static int any_public;
+  static int any_registered;
   const char *resname = url;
   char *filename = NULL;
-  int force = (flags&1);
-  int read_only = !!(flags&8);
+  int create;
+  int read_only = !!(flags&KEYDB_RESOURCE_FLAG_READONLY);
   int rc = 0;
   KeydbResourceType rt = KEYDB_RESOURCE_TYPE_NONE;
   void *token;
 
-  if (read_only)
-    force = 0;
+  /* Create the resource if it is the first registered one.  */
+  create = (!read_only && !any_registered);
 
   /* Do we have an URL?
-   *   gnupg-ring:filename  := this is a plain keyring
+   *   gnupg-ring:filename  := this is a plain keyring.
+   *   gnupg-kbx:filename   := this is a keybox file.
    *   filename := See what is is, but create as plain keyring.
    */
-  if (strlen (resname) > 11)
+  if (strlen (resname) > 11 && !strncmp( resname, "gnupg-ring:", 11) )
     {
-      if (!strncmp( resname, "gnupg-ring:", 11) )
-        {
-          rt = KEYDB_RESOURCE_TYPE_KEYRING;
-          resname += 11;
-       }
+      rt = KEYDB_RESOURCE_TYPE_KEYRING;
+      resname += 11;
+    }
+  else if (strlen (resname) > 10 && !strncmp (resname, "gnupg-kbx:", 10) )
+    {
+      rt = KEYDB_RESOURCE_TYPE_KEYBOX;
+      resname += 10;
+    }
 #if !defined(HAVE_DRIVE_LETTERS) && !defined(__riscos__)
-      else if (strchr (resname, ':'))
-        {
-          log_error ("invalid key resource URL '%s'\n", url );
-          rc = gpg_error (GPG_ERR_GENERAL);
-          goto leave;
-        }
-#endif /* !HAVE_DRIVE_LETTERS && !__riscos__ */
+  else if (strchr (resname, ':'))
+    {
+      log_error ("invalid key resource URL '%s'\n", url );
+      rc = gpg_error (GPG_ERR_GENERAL);
+      goto leave;
     }
+#endif /* !HAVE_DRIVE_LETTERS && !__riscos__ */
 
   if (*resname != DIRSEP_C )
     {
@@ -261,9 +330,6 @@ keydb_add_resource (const char *url, int flags)
   else
     filename = xstrdup (resname);
 
-  if (!force && !read_only)
-    force = !any_public;
-
   /* See whether we can determine the filetype.  */
   if (rt == KEYDB_RESOURCE_TYPE_NONE)
     {
@@ -273,20 +339,25 @@ keydb_add_resource (const char *url, int flags)
         {
           u32 magic;
 
-          if (fread&magic, 4, 1, fp) == 1 )
+          if (fread (&magic, 4, 1, fp) == 1 )
             {
               if (magic == 0x13579ace || magic == 0xce9a5713)
                 ; /* GDBM magic - not anymore supported. */
+              else if (fread (&magic, 4, 1, fp) == 1
+                       && !memcmp (&magic, "\x01", 1)
+                       && fread (&magic, 4, 1, fp) == 1
+                       && !memcmp (&magic, "KBXf", 4))
+                rt = KEYDB_RESOURCE_TYPE_KEYBOX;
               else
                 rt = KEYDB_RESOURCE_TYPE_KEYRING;
            }
           else /* Maybe empty: assume keyring. */
             rt = KEYDB_RESOURCE_TYPE_KEYRING;
 
-          fclose( fp );
+          fclose (fp);
        }
-      else /* No file yet: create keyring.  */
-        rt = KEYDB_RESOURCE_TYPE_KEYRING;
+      else /* No file yet: create keybox. */
+        rt = KEYDB_RESOURCE_TYPE_KEYBOX;
     }
 
   switch (rt)
@@ -297,7 +368,7 @@ keydb_add_resource (const char *url, int flags)
       goto leave;
 
     case KEYDB_RESOURCE_TYPE_KEYRING:
-      rc = maybe_create_keyring (filename, force);
+      rc = maybe_create_keyring_or_box (filename, create, 0);
       if (rc)
         goto leave;
 
@@ -307,7 +378,7 @@ keydb_add_resource (const char *url, int flags)
             rc = gpg_error (GPG_ERR_RESOURCE_LIMIT);
           else
             {
-              if (flags&2)
+              if ((flags & KEYDB_RESOURCE_FLAG_PRIMARY))
                 primary_keyring = token;
               all_resources[used_resources].type = rt;
               all_resources[used_resources].u.kr = NULL; /* Not used here */
@@ -320,24 +391,61 @@ keydb_add_resource (const char *url, int flags)
           /* This keyring was already registered, so ignore it.
              However, we can still mark it as primary even if it was
              already registered.  */
-          if (flags&2)
+          if ((flags & KEYDB_RESOURCE_FLAG_PRIMARY))
             primary_keyring = token;
         }
       break;
 
+    case KEYDB_RESOURCE_TYPE_KEYBOX:
+      {
+        rc = maybe_create_keyring_or_box (filename, create, 1);
+        if (rc)
+          goto leave;
+
+        /* FIXME: How do we register a read-only keybox?  */
+        token = keybox_register_file (filename, 0);
+        if (token)
+          {
+            if (used_resources >= MAX_KEYDB_RESOURCES)
+              rc = gpg_error (GPG_ERR_RESOURCE_LIMIT);
+            else
+              {
+                /* if ((flags & KEYDB_RESOURCE_FLAG_PRIMARY)) */
+                /*   primary_keyring = token; */
+                all_resources[used_resources].type = rt;
+                all_resources[used_resources].u.kb = NULL; /* Not used here */
+                all_resources[used_resources].token = token;
+
+                /* FIXME: Do a compress run if needed and no other
+                   user is currently using the keybox. */
+
+                used_resources++;
+              }
+          }
+        else
+          {
+            /* Already registered.  We will mark it as the primary key
+               if requested.  */
+            /* FIXME: How to do that?  Change the keybox interface?  */
+            /* if ((flags & KEYDB_RESOURCE_FLAG_PRIMARY)) */
+            /*   primary_keyring = token; */
+          }
+      }
+      break;
+
       default:
        log_error ("resource type of '%s' not supported\n", url);
        rc = gpg_error (GPG_ERR_GENERAL);
        goto leave;
     }
 
-    /* fixme: check directory permissions and print a warning */
+  /* fixme: check directory permissions and print a warning */
 
  leave:
   if (rc)
     log_error (_("keyblock resource '%s': %s\n"), filename, gpg_strerror (rc));
   else
-    any_public = 1;
+    any_registered = 1;
   xfree (filename);
   return rc;
 }
@@ -351,6 +459,9 @@ keydb_new (void)
   KEYDB_HANDLE hd;
   int i, j;
 
+  if (DBG_CLOCK)
+    log_clock ("keydb_new");
+
   hd = xmalloc_clear (sizeof *hd);
   hd->found = -1;
 
@@ -371,6 +482,17 @@ keydb_new (void)
           }
           j++;
           break;
+        case KEYDB_RESOURCE_TYPE_KEYBOX:
+          hd->active[j].type   = all_resources[i].type;
+          hd->active[j].token  = all_resources[i].token;
+          hd->active[j].u.kb   = keybox_new (all_resources[i].token, 0);
+          if (!hd->active[j].u.kb)
+            {
+              xfree (hd);
+              return NULL; /* fixme: release all previously allocated handles*/
+            }
+          j++;
+          break;
         }
     }
   hd->used = j;
@@ -399,6 +521,9 @@ keydb_release (KEYDB_HANDLE hd)
         case KEYDB_RESOURCE_TYPE_KEYRING:
           keyring_release (hd->active[i].u.kr);
           break;
+        case KEYDB_RESOURCE_TYPE_KEYBOX:
+          keybox_release (hd->active[i].u.kb);
+          break;
         }
     }
 
@@ -438,6 +563,9 @@ keydb_get_resource_name (KEYDB_HANDLE hd)
     case KEYDB_RESOURCE_TYPE_KEYRING:
       s = keyring_get_resource_name (hd->active[idx].u.kr);
       break;
+    case KEYDB_RESOURCE_TYPE_KEYBOX:
+      s = keybox_get_resource_name (hd->active[idx].u.kb);
+      break;
     }
 
   return s? s: "";
@@ -450,6 +578,13 @@ lock_all (KEYDB_HANDLE hd)
 {
   int i, rc = 0;
 
+  /* Fixme: This locking scheme may lead to a deadlock if the resources
+     are not added in the same order by all processes.  We are
+     currently only allowing one resource so it is not a problem.
+     [Oops: Who claimed the latter]
+
+     To fix this we need to use a lock file to protect lock_all.  */
+
   for (i=0; !rc && i < hd->used; i++)
     {
       switch (hd->active[i].type)
@@ -459,12 +594,15 @@ lock_all (KEYDB_HANDLE hd)
         case KEYDB_RESOURCE_TYPE_KEYRING:
           rc = keyring_lock (hd->active[i].u.kr, 1);
           break;
+        case KEYDB_RESOURCE_TYPE_KEYBOX:
+          rc = keybox_lock (hd->active[i].u.kb, 1);
+          break;
         }
     }
 
   if (rc)
     {
-      /* Revert the already set locks.  */
+      /* Revert the already taken locks.  */
       for (i--; i >= 0; i--)
         {
           switch (hd->active[i].type)
@@ -474,6 +612,9 @@ lock_all (KEYDB_HANDLE hd)
             case KEYDB_RESOURCE_TYPE_KEYRING:
               keyring_lock (hd->active[i].u.kr, 0);
               break;
+            case KEYDB_RESOURCE_TYPE_KEYBOX:
+              rc = keybox_lock (hd->active[i].u.kb, 0);
+              break;
             }
         }
     }
@@ -501,12 +642,170 @@ unlock_all (KEYDB_HANDLE hd)
         case KEYDB_RESOURCE_TYPE_KEYRING:
           keyring_lock (hd->active[i].u.kr, 0);
           break;
+        case KEYDB_RESOURCE_TYPE_KEYBOX:
+          keybox_lock (hd->active[i].u.kb, 0);
+          break;
         }
     }
   hd->locked = 0;
 }
 
 
+static gpg_error_t
+parse_keyblock_image (iobuf_t iobuf, int pk_no, int uid_no,
+                      const u32 *sigstatus, kbnode_t *r_keyblock)
+{
+  gpg_error_t err;
+  PACKET *pkt;
+  kbnode_t keyblock = NULL;
+  kbnode_t node, *tail;
+  int in_cert, save_mode;
+  u32 n_sigs;
+  int pk_count, uid_count;
+
+  *r_keyblock = NULL;
+
+  pkt = xtrymalloc (sizeof *pkt);
+  if (!pkt)
+    return gpg_error_from_syserror ();
+  init_packet (pkt);
+  save_mode = set_packet_list_mode (0);
+  in_cert = 0;
+  n_sigs = 0;
+  tail = NULL;
+  pk_count = uid_count = 0;
+  while ((err = parse_packet (iobuf, pkt)) != -1)
+    {
+      if (gpg_err_code (err) == GPG_ERR_UNKNOWN_PACKET)
+        {
+          free_packet (pkt);
+          init_packet (pkt);
+          continue;
+       }
+      if (err)
+        {
+          log_error ("parse_keyblock_image: read error: %s\n",
+                     gpg_strerror (err));
+          err = gpg_error (GPG_ERR_INV_KEYRING);
+          break;
+        }
+      if (pkt->pkttype == PKT_COMPRESSED)
+        {
+          log_error ("skipped compressed packet in keybox blob\n");
+          free_packet(pkt);
+          init_packet(pkt);
+          continue;
+        }
+      if (pkt->pkttype == PKT_RING_TRUST)
+        {
+          log_info ("skipped ring trust packet in keybox blob\n");
+          free_packet(pkt);
+          init_packet(pkt);
+          continue;
+        }
+
+      if (!in_cert && pkt->pkttype != PKT_PUBLIC_KEY)
+        {
+          log_error ("parse_keyblock_image: first packet in a keybox blob "
+                     "is not a public key packet\n");
+          err = gpg_error (GPG_ERR_INV_KEYRING);
+          break;
+        }
+      if (in_cert && (pkt->pkttype == PKT_PUBLIC_KEY
+                      || pkt->pkttype == PKT_SECRET_KEY))
+        {
+          log_error ("parse_keyblock_image: "
+                     "multiple keyblocks in a keybox blob\n");
+          err = gpg_error (GPG_ERR_INV_KEYRING);
+          break;
+        }
+      in_cert = 1;
+
+      if (pkt->pkttype == PKT_SIGNATURE && sigstatus)
+        {
+          PKT_signature *sig = pkt->pkt.signature;
+
+          n_sigs++;
+          if (n_sigs > sigstatus[0])
+            {
+              log_error ("parse_keyblock_image: "
+                         "more signatures than found in the meta data\n");
+              err = gpg_error (GPG_ERR_INV_KEYRING);
+              break;
+
+            }
+          if (sigstatus[n_sigs])
+            {
+              sig->flags.checked = 1;
+              if (sigstatus[n_sigs] == 1 )
+                ; /* missing key */
+              else if (sigstatus[n_sigs] == 2 )
+                ; /* bad signature */
+              else if (sigstatus[n_sigs] < 0x10000000)
+                ; /* bad flag */
+              else
+                {
+                  sig->flags.valid = 1;
+                  /* Fixme: Shall we set the expired flag here?  */
+                }
+            }
+        }
+
+      node = new_kbnode (pkt);
+
+      switch (pkt->pkttype)
+        {
+        case PKT_PUBLIC_KEY:
+        case PKT_PUBLIC_SUBKEY:
+        case PKT_SECRET_KEY:
+        case PKT_SECRET_SUBKEY:
+          if (++pk_count == pk_no)
+            node->flag |= 1;
+          break;
+
+        case PKT_USER_ID:
+          if (++uid_count == uid_no)
+            node->flag |= 2;
+          break;
+
+        default:
+          break;
+        }
+
+      if (!keyblock)
+        keyblock = node;
+      else
+        *tail = node;
+      tail = &node->next;
+      pkt = xtrymalloc (sizeof *pkt);
+      if (!pkt)
+        {
+          err = gpg_error_from_syserror ();
+          break;
+        }
+      init_packet (pkt);
+    }
+  set_packet_list_mode (save_mode);
+
+  if (err == -1 && keyblock)
+    err = 0; /* Got the entire keyblock.  */
+
+  if (!err && sigstatus && n_sigs != sigstatus[0])
+    {
+      log_error ("parse_keyblock_image: signature count does not match\n");
+      err = gpg_error (GPG_ERR_INV_KEYRING);
+    }
+
+  if (err)
+    release_kbnode (keyblock);
+  else
+    *r_keyblock = keyblock;
+  free_packet (pkt);
+  xfree (pkt);
+  return err;
+}
+
+
 /*
  * Return the last found keyring.  Caller must free it.
  * The returned keyblock has the kbode flag bit 0 set for the node with
@@ -518,9 +817,24 @@ keydb_get_keyblock (KEYDB_HANDLE hd, KBNODE *ret_kb)
 {
   gpg_error_t err = 0;
 
+  *ret_kb = NULL;
+
   if (!hd)
     return gpg_error (GPG_ERR_INV_ARG);
 
+  if (keyblock_cache.state == KEYBLOCK_CACHE_FILLED)
+    {
+      iobuf_seek (keyblock_cache.iobuf, 0);
+      err = parse_keyblock_image (keyblock_cache.iobuf,
+                                  keyblock_cache.pk_no,
+                                  keyblock_cache.uid_no,
+                                  keyblock_cache.sigstatus,
+                                  ret_kb);
+      if (err)
+        keyblock_cache_clear ();
+      return err;
+    }
+
   if (hd->found < 0 || hd->found >= hd->used)
     return gpg_error (GPG_ERR_VALUE_NOT_FOUND);
 
@@ -532,11 +846,125 @@ keydb_get_keyblock (KEYDB_HANDLE hd, KBNODE *ret_kb)
     case KEYDB_RESOURCE_TYPE_KEYRING:
       err = keyring_get_keyblock (hd->active[hd->found].u.kr, ret_kb);
       break;
+    case KEYDB_RESOURCE_TYPE_KEYBOX:
+      {
+        iobuf_t iobuf;
+        u32 *sigstatus;
+        int pk_no, uid_no;
+
+        err = keybox_get_keyblock (hd->active[hd->found].u.kb,
+                                   &iobuf, &pk_no, &uid_no, &sigstatus);
+        if (!err)
+          {
+            err = parse_keyblock_image (iobuf, pk_no, uid_no, sigstatus,
+                                        ret_kb);
+            if (!err && keyblock_cache.state == KEYBLOCK_CACHE_PREPARED)
+              {
+                keyblock_cache.state     = KEYBLOCK_CACHE_FILLED;
+                keyblock_cache.sigstatus = sigstatus;
+                keyblock_cache.iobuf     = iobuf;
+                keyblock_cache.pk_no     = pk_no;
+                keyblock_cache.uid_no    = uid_no;
+              }
+            else
+              {
+                xfree (sigstatus);
+                iobuf_close (iobuf);
+              }
+          }
+      }
+      break;
     }
 
+  if (keyblock_cache.state != KEYBLOCK_CACHE_FILLED)
+    keyblock_cache_clear ();
+
   return err;
 }
 
+
+/* Build a keyblock image from KEYBLOCK.  Returns 0 on success and
+   only then stores a new iobuf object at R_IOBUF and a signature
+   status vecotor at R_SIGSTATUS.  */
+static gpg_error_t
+build_keyblock_image (kbnode_t keyblock, iobuf_t *r_iobuf, u32 **r_sigstatus)
+{
+  gpg_error_t err;
+  iobuf_t iobuf;
+  kbnode_t kbctx, node;
+  u32 n_sigs;
+  u32 *sigstatus;
+
+  *r_iobuf = NULL;
+  *r_sigstatus = NULL;
+
+  /* Allocate a vector for the signature cache.  This is an array of
+     u32 values with the first value giving the number of elements to
+     follow and each element descriping the cache status of the
+     signature.  */
+  for (kbctx = NULL, n_sigs = 0; (node = walk_kbnode (keyblock, &kbctx, 0));)
+    if (node->pkt->pkttype == PKT_SIGNATURE)
+      n_sigs++;
+  sigstatus = xtrycalloc (1+n_sigs, sizeof *sigstatus);
+  if (!sigstatus)
+    return gpg_error_from_syserror ();
+
+  iobuf = iobuf_temp ();
+  for (kbctx = NULL, n_sigs = 0; (node = walk_kbnode (keyblock, &kbctx, 0));)
+    {
+      /* Make sure to use only packets valid on a keyblock.  */
+      switch (node->pkt->pkttype)
+        {
+        case PKT_PUBLIC_KEY:
+        case PKT_PUBLIC_SUBKEY:
+        case PKT_SIGNATURE:
+        case PKT_USER_ID:
+        case PKT_ATTRIBUTE:
+          /* Note that we don't want the ring trust packets.  They are
+             not useful. */
+          break;
+        default:
+          continue;
+        }
+
+      err = build_packet (iobuf, node->pkt);
+      if (err)
+        {
+          iobuf_close (iobuf);
+          return err;
+        }
+
+      /* Build signature status vector.  */
+      if (node->pkt->pkttype == PKT_SIGNATURE)
+        {
+          PKT_signature *sig = node->pkt->pkt.signature;
+
+          n_sigs++;
+          /* Fixme: Detect tye "missing key" status.  */
+          if (sig->flags.checked)
+            {
+              if (sig->flags.valid)
+                {
+                  if (!sig->expiredate)
+                    sigstatus[n_sigs] = 0xffffffff;
+                  else if (sig->expiredate < 0x1000000)
+                    sigstatus[n_sigs] = 0x10000000;
+                  else
+                    sigstatus[n_sigs] = sig->expiredate;
+                }
+              else
+                sigstatus[n_sigs] = 0x00000002; /* Bad signature.  */
+            }
+        }
+    }
+  sigstatus[0] = n_sigs;
+
+  *r_iobuf = iobuf;
+  *r_sigstatus = sigstatus;
+  return 0;
+}
+
+
 /*
  * Update the current keyblock with the keyblock KB
  */
@@ -548,6 +976,8 @@ keydb_update_keyblock (KEYDB_HANDLE hd, kbnode_t kb)
   if (!hd)
     return gpg_error (GPG_ERR_INV_ARG);
 
+  keyblock_cache_clear ();
+
   if (hd->found < 0 || hd->found >= hd->used)
     return gpg_error (GPG_ERR_VALUE_NOT_FOUND);
 
@@ -566,6 +996,12 @@ keydb_update_keyblock (KEYDB_HANDLE hd, kbnode_t kb)
     case KEYDB_RESOURCE_TYPE_KEYRING:
       rc = keyring_update_keyblock (hd->active[hd->found].u.kr, kb);
       break;
+    /* case KEYDB_RESOURCE_TYPE_KEYRING: */
+    /*   rc = build_keyblock (kb, &image, &imagelen); */
+    /*   if (!rc) */
+    /*     rc = keybox_update_keyblock (hd->active[hd->found].u.kb, */
+    /*                                  image, imagelen); */
+    /*   break; */
     }
 
   unlock_all (hd);
@@ -579,12 +1015,14 @@ keydb_update_keyblock (KEYDB_HANDLE hd, kbnode_t kb)
 gpg_error_t
 keydb_insert_keyblock (KEYDB_HANDLE hd, kbnode_t kb)
 {
-  int rc;
+  gpg_error_t err;
   int idx;
 
   if (!hd)
     return gpg_error (GPG_ERR_INV_ARG);
 
+  keyblock_cache_clear ();
+
   if (opt.dry_run)
     return 0;
 
@@ -595,22 +1033,42 @@ keydb_insert_keyblock (KEYDB_HANDLE hd, kbnode_t kb)
   else
     return gpg_error (GPG_ERR_GENERAL);
 
-  rc = lock_all (hd);
-  if (rc)
-    return rc;
+  err = lock_all (hd);
+  if (err)
+    return err;
 
   switch (hd->active[idx].type)
     {
     case KEYDB_RESOURCE_TYPE_NONE:
-      rc = gpg_error (GPG_ERR_GENERAL); /* oops */
+      err = gpg_error (GPG_ERR_GENERAL); /* oops */
       break;
     case KEYDB_RESOURCE_TYPE_KEYRING:
-      rc = keyring_insert_keyblock (hd->active[idx].u.kr, kb);
+      err = keyring_insert_keyblock (hd->active[idx].u.kr, kb);
+      break;
+    case KEYDB_RESOURCE_TYPE_KEYBOX:
+      { /* We need to turn our kbnode_t list of packets into a proper
+           keyblock first.  This is required by the OpenPGP key parser
+           included in the keybox code.  Eventually we can change this
+           kludge to have the caller pass the image.  */
+        iobuf_t iobuf;
+        u32 *sigstatus;
+
+        err = build_keyblock_image (kb, &iobuf, &sigstatus);
+        if (!err)
+          {
+            err = keybox_insert_keyblock (hd->active[idx].u.kb,
+                                          iobuf_get_temp_buffer (iobuf),
+                                          iobuf_get_temp_length (iobuf),
+                                          sigstatus);
+            xfree (sigstatus);
+            iobuf_close (iobuf);
+          }
+      }
       break;
     }
 
   unlock_all (hd);
-  return rc;
+  return err;
 }
 
 
@@ -625,6 +1083,8 @@ keydb_delete_keyblock (KEYDB_HANDLE hd)
   if (!hd)
     return gpg_error (GPG_ERR_INV_ARG);
 
+  keyblock_cache_clear ();
+
   if (hd->found < 0 || hd->found >= hd->used)
     return gpg_error (GPG_ERR_VALUE_NOT_FOUND);
 
@@ -643,6 +1103,9 @@ keydb_delete_keyblock (KEYDB_HANDLE hd)
     case KEYDB_RESOURCE_TYPE_KEYRING:
       rc = keyring_delete_keyblock (hd->active[hd->found].u.kr);
       break;
+    case KEYDB_RESOURCE_TYPE_KEYBOX:
+      rc = keybox_delete (hd->active[hd->found].u.kb);
+      break;
     }
 
   unlock_all (hd);
@@ -700,6 +1163,10 @@ keydb_locate_writable (KEYDB_HANDLE hd, const char *reserved)
           if (keyring_is_writable (hd->active[hd->current].token))
             return 0; /* found (hd->current is set to it) */
           break;
+        case KEYDB_RESOURCE_TYPE_KEYBOX:
+          if (keybox_is_writable (hd->active[hd->current].token))
+            return 0; /* found (hd->current is set to it) */
+          break;
         }
     }
 
@@ -714,6 +1181,8 @@ keydb_rebuild_caches (int noisy)
 {
   int i, rc;
 
+  keyblock_cache_clear ();
+
   for (i=0; i < used_resources; i++)
     {
       if (!keyring_is_writable (all_resources[i].token))
@@ -746,6 +1215,11 @@ keydb_search_reset (KEYDB_HANDLE hd)
   if (!hd)
     return gpg_error (GPG_ERR_INV_ARG);
 
+  keyblock_cache_clear ();
+
+  if (DBG_CLOCK)
+    log_clock ("keydb_search_reset");
+
   hd->current = 0;
   hd->found = -1;
   /* Now reset all resources.  */
@@ -758,12 +1232,61 @@ keydb_search_reset (KEYDB_HANDLE hd)
         case KEYDB_RESOURCE_TYPE_KEYRING:
           rc = keyring_search_reset (hd->active[i].u.kr);
           break;
+        case KEYDB_RESOURCE_TYPE_KEYBOX:
+          rc = keybox_search_reset (hd->active[i].u.kb);
+          break;
         }
     }
   return rc;
 }
 
 
+static void
+dump_search_desc (const char *text, KEYDB_SEARCH_DESC *desc, size_t ndesc)
+{
+  int n;
+  const char *s;
+
+  for (n=0; n < ndesc; n++)
+    {
+      switch (desc[n].mode)
+        {
+        case KEYDB_SEARCH_MODE_NONE:      s = "none";      break;
+        case KEYDB_SEARCH_MODE_EXACT:     s = "exact";     break;
+        case KEYDB_SEARCH_MODE_SUBSTR:    s = "substr";    break;
+        case KEYDB_SEARCH_MODE_MAIL:      s = "mail";      break;
+        case KEYDB_SEARCH_MODE_MAILSUB:   s = "mailsub";   break;
+        case KEYDB_SEARCH_MODE_MAILEND:   s = "mailend";   break;
+        case KEYDB_SEARCH_MODE_WORDS:     s = "words";     break;
+        case KEYDB_SEARCH_MODE_SHORT_KID: s = "short_kid"; break;
+        case KEYDB_SEARCH_MODE_LONG_KID:  s = "long_kid";  break;
+        case KEYDB_SEARCH_MODE_FPR16:     s = "fpr16";     break;
+        case KEYDB_SEARCH_MODE_FPR20:     s = "fpr20";     break;
+        case KEYDB_SEARCH_MODE_FPR:       s = "fpr";       break;
+        case KEYDB_SEARCH_MODE_ISSUER:    s = "issuer";    break;
+        case KEYDB_SEARCH_MODE_ISSUER_SN: s = "issuer_sn"; break;
+        case KEYDB_SEARCH_MODE_SN:        s = "sn";        break;
+        case KEYDB_SEARCH_MODE_SUBJECT:   s = "subject";   break;
+        case KEYDB_SEARCH_MODE_KEYGRIP:   s = "keygrip";   break;
+        case KEYDB_SEARCH_MODE_FIRST:     s = "first";     break;
+        case KEYDB_SEARCH_MODE_NEXT:      s = "next";      break;
+        default:                          s = "?";         break;
+        }
+      if (!n)
+        log_debug ("%s: mode=%s", text, s);
+      else
+        log_debug ("%*s  mode=%s", (int)strlen (text), "", s);
+      if (desc[n].mode == KEYDB_SEARCH_MODE_LONG_KID)
+        log_printf (" %08lX%08lX", (unsigned long)desc[n].u.kid[0],
+                    (unsigned long)desc[n].u.kid[1]);
+      else if (desc[n].mode == KEYDB_SEARCH_MODE_SHORT_KID)
+        log_printf (" %08lX", (unsigned long)desc[n].u.kid[1]);
+      else if (desc[n].mode == KEYDB_SEARCH_MODE_SUBSTR)
+        log_printf (" '%s'", desc[n].u.name);
+    }
+}
+
+
 /*
  * Search through all keydb resources, starting at the current
  * position, for a keyblock which contains one of the keys described
@@ -771,14 +1294,30 @@ keydb_search_reset (KEYDB_HANDLE hd)
  * keyring was found.
  */
 gpg_error_t
-keydb_search2 (KEYDB_HANDLE hd, KEYDB_SEARCH_DESC *desc,
-              size_t ndesc, size_t *descindex)
+keydb_search (KEYDB_HANDLE hd, KEYDB_SEARCH_DESC *desc,
+              size_t ndesc, size_t *descindex)
 {
   gpg_error_t rc;
 
   if (!hd)
     return gpg_error (GPG_ERR_INV_ARG);
 
+  if (DBG_CLOCK)
+    log_clock ("keydb_search enter");
+
+  if (DBG_CACHE)
+    dump_search_desc ("keydb_search", desc, ndesc);
+
+  if (ndesc == 1 && desc[0].mode == KEYDB_SEARCH_MODE_LONG_KID
+      && keyblock_cache.state  == KEYBLOCK_CACHE_FILLED
+      && keyblock_cache.kid[0] == desc[0].u.kid[0]
+      && keyblock_cache.kid[1] == desc[0].u.kid[1])
+    {
+      if (DBG_CLOCK)
+        log_clock ("keydb_search leave (cached)");
+      return 0;
+    }
+
   rc = -1;
   while ((rc == -1 || gpg_err_code (rc) == GPG_ERR_EOF)
          && hd->current >= 0 && hd->current < hd->used)
@@ -792,6 +1331,9 @@ keydb_search2 (KEYDB_HANDLE hd, KEYDB_SEARCH_DESC *desc,
           rc = keyring_search (hd->active[hd->current].u.kr, desc,
                                ndesc, descindex);
           break;
+        case KEYDB_RESOURCE_TYPE_KEYBOX:
+          rc = keybox_search (hd->active[hd->current].u.kb, desc, ndesc);
+          break;
         }
       if (rc == -1 || gpg_err_code (rc) == GPG_ERR_EOF)
         {
@@ -802,9 +1344,22 @@ keydb_search2 (KEYDB_HANDLE hd, KEYDB_SEARCH_DESC *desc,
         hd->found = hd->current;
     }
 
-  return ((rc == -1 || gpg_err_code (rc) == GPG_ERR_EOF)
-          ? gpg_error (GPG_ERR_NOT_FOUND)
-          : rc);
+  rc = ((rc == -1 || gpg_err_code (rc) == GPG_ERR_EOF)
+        ? gpg_error (GPG_ERR_NOT_FOUND)
+        : rc);
+
+  keyblock_cache_clear ();
+  if (!rc && ndesc == 1 && desc[0].mode == KEYDB_SEARCH_MODE_LONG_KID)
+    {
+      keyblock_cache.state = KEYBLOCK_CACHE_PREPARED;
+      keyblock_cache.kid[0] = desc[0].u.kid[0];
+      keyblock_cache.kid[1] = desc[0].u.kid[1];
+    }
+
+  if (DBG_CLOCK)
+    log_clock (rc? "keydb_search leave (not found)"
+                 : "keydb_search leave (found)");
+  return rc;
 }
 
 
@@ -815,7 +1370,7 @@ keydb_search_first (KEYDB_HANDLE hd)
 
   memset (&desc, 0, sizeof desc);
   desc.mode = KEYDB_SEARCH_MODE_FIRST;
-  return keydb_search (hd, &desc, 1);
+  return keydb_search (hd, &desc, 1, NULL);
 }
 
 gpg_error_t
@@ -825,7 +1380,7 @@ keydb_search_next (KEYDB_HANDLE hd)
 
   memset (&desc, 0, sizeof desc);
   desc.mode = KEYDB_SEARCH_MODE_NEXT;
-  return keydb_search (hd, &desc, 1);
+  return keydb_search (hd, &desc, 1, NULL);
 }
 
 gpg_error_t
@@ -837,7 +1392,7 @@ keydb_search_kid (KEYDB_HANDLE hd, u32 *kid)
   desc.mode = KEYDB_SEARCH_MODE_LONG_KID;
   desc.u.kid[0] = kid[0];
   desc.u.kid[1] = kid[1];
-  return keydb_search (hd, &desc, 1);
+  return keydb_search (hd, &desc, 1, NULL);
 }
 
 gpg_error_t
@@ -848,5 +1403,5 @@ keydb_search_fpr (KEYDB_HANDLE hd, const byte *fpr)
   memset (&desc, 0, sizeof desc);
   desc.mode = KEYDB_SEARCH_MODE_FPR;
   memcpy (desc.u.fpr, fpr, MAX_FINGERPRINT_LEN);
-  return keydb_search (hd, &desc, 1);
+  return keydb_search (hd, &desc, 1, NULL);
 }
index fd80c25..39e7826 100644 (file)
@@ -128,11 +128,12 @@ union pref_hint
 
 /*-- keydb.c --*/
 
-/*
-  Flag 1 == force
-  Flag 2 == default
-*/
-gpg_error_t keydb_add_resource (const char *url, int flags);
+#define KEYDB_RESOURCE_FLAG_PRIMARY  2  /* The primary resource.  */
+#define KEYDB_RESOURCE_FLAG_DEFAULT  4  /* The default one.  */
+#define KEYDB_RESOURCE_FLAG_READONLY 8  /* Open in read only mode.  */
+
+gpg_error_t keydb_add_resource (const char *url, unsigned int flags);
+
 KEYDB_HANDLE keydb_new (void);
 void keydb_release (KEYDB_HANDLE hd);
 const char *keydb_get_resource_name (KEYDB_HANDLE hd);
@@ -143,9 +144,8 @@ gpg_error_t keydb_delete_keyblock (KEYDB_HANDLE hd);
 gpg_error_t keydb_locate_writable (KEYDB_HANDLE hd, const char *reserved);
 void keydb_rebuild_caches (int noisy);
 gpg_error_t keydb_search_reset (KEYDB_HANDLE hd);
-#define keydb_search(a,b,c) keydb_search2((a),(b),(c),NULL)
-gpg_error_t keydb_search2 (KEYDB_HANDLE hd, KEYDB_SEARCH_DESC *desc,
-                           size_t ndesc, size_t *descindex);
+gpg_error_t keydb_search (KEYDB_HANDLE hd, KEYDB_SEARCH_DESC *desc,
+                          size_t ndesc, size_t *descindex);
 gpg_error_t keydb_search_first (KEYDB_HANDLE hd);
 gpg_error_t keydb_search_next (KEYDB_HANDLE hd);
 gpg_error_t keydb_search_kid (KEYDB_HANDLE hd, u32 *kid);
index 0be1e3f..0ec616b 100644 (file)
@@ -1142,7 +1142,7 @@ keyidlist(strlist_t users,KEYDB_SEARCH_DESC **klist,int *count,int fakev3)
        }
     }
 
-  while (!(rc = keydb_search (kdbhd, desc, ndesc)))
+  while (!(rc = keydb_search (kdbhd, desc, ndesc, NULL)))
     {
       if (!users)
        desc[0].mode = KEYDB_SEARCH_MODE_NEXT;
index 223b115..d44d7a1 100644 (file)
@@ -272,6 +272,7 @@ struct {
 #define DBG_HASHING_VALUE 512  /* debug hashing operations */
 #define DBG_EXTPROG_VALUE 1024  /* debug external program calls */
 #define DBG_CARD_IO_VALUE 2048  /* debug smart card I/O.  */
+#define DBG_CLOCK_VALUE   4096
 
 /* Fixme: For now alias this value.  */
 #define DBG_ASSUAN_VALUE  DBG_EXTPROG_VALUE
@@ -287,6 +288,7 @@ struct {
 #define DBG_EXTPROG (opt.debug & DBG_EXTPROG_VALUE)
 #define DBG_CARD_IO (opt.debug & DBG_CARD_IO_VALUE)
 #define DBG_ASSUAN  (opt.debug & DBG_ASSUAN_VALUE)
+#define DBG_CLOCK   (opt.debug & DBG_CLOCK_VALUE)
 
 /* FIXME: We need to check whey we did not put this into opt. */
 #define DBG_MEMORY    memory_debug_mode
index a98a723..a328e1a 100644 (file)
@@ -77,6 +77,9 @@ get_session_key (PKT_pubkey_enc * k, DEK * dek)
   PKT_public_key *sk = NULL;
   int rc;
 
+  if (DBG_CLOCK)
+    log_clock ("get_session_key enter");
+
   rc = openpgp_pk_test_algo2 (k->pubkey_algo, PUBKEY_USAGE_ENC);
   if (rc)
     goto leave;
@@ -129,6 +132,8 @@ get_session_key (PKT_pubkey_enc * k, DEK * dek)
 
 leave:
   free_public_key (sk);
+  if (DBG_CLOCK)
+    log_clock ("get_session_key leave");
   return rc;
 }
 
@@ -149,6 +154,9 @@ get_it (PKT_pubkey_enc *enc, DEK *dek, PKT_public_key *sk, u32 *keyid)
   size_t fpn;
   const int pkalgo = map_pk_openpgp_to_gcry (sk->pubkey_algo);
 
+  if (DBG_CLOCK)
+    log_clock ("decryption start");
+
   /* Get the keygrip.  */
   err = hexkeygrip_from_pk (sk, &keygrip);
   if (err)
@@ -323,6 +331,8 @@ get_it (PKT_pubkey_enc *enc, DEK *dek, PKT_public_key *sk, u32 *keyid)
       err = gpg_error (GPG_ERR_WRONG_SECKEY);
       goto leave;
     }
+  if (DBG_CLOCK)
+    log_clock ("decryption ready");
   if (DBG_CIPHER)
     log_printhex ("DEK is:", dek->key, dek->keylen);
 
index 396b6d4..6e47691 100644 (file)
@@ -222,7 +222,7 @@ gen_desig_revoke( const char *uname, strlist_t locusr )
     kdbhd = keydb_new ();
     rc = classify_user_id (uname, &desc, 1);
     if (!rc)
-      rc = keydb_search (kdbhd, &desc, 1);
+      rc = keydb_search (kdbhd, &desc, 1, NULL);
     if (rc) {
        log_error (_("key \"%s\" not found: %s\n"),uname, g10_errstr (rc));
        goto leave;
@@ -463,7 +463,7 @@ gen_revoke (const char *uname)
   kdbhd = keydb_new ();
   rc = classify_user_id (uname, &desc, 1);
   if (!rc)
-    rc = keydb_search (kdbhd, &desc, 1);
+    rc = keydb_search (kdbhd, &desc, 1, NULL);
   if (rc)
     {
       log_error (_("secret key \"%s\" not found: %s\n"),
index 6b228d2..24ed9df 100644 (file)
@@ -2110,7 +2110,7 @@ validate_key_list (KEYDB_HANDLE hd, KeyHashTable full_trust,
   desc.mode = KEYDB_SEARCH_MODE_FIRST;
   desc.skipfnc = search_skipfnc;
   desc.skipfncvalue = full_trust;
-  rc = keydb_search (hd, &desc, 1);
+  rc = keydb_search (hd, &desc, 1, NULL);
   if (gpg_err_code (rc) == GPG_ERR_NOT_FOUND)
     {
       keys[nkeys].keyblock = NULL;
@@ -2184,7 +2184,8 @@ validate_key_list (KEYDB_HANDLE hd, KeyHashTable full_trust,
       release_kbnode (keyblock);
       keyblock = NULL;
     }
-  while ( !(rc = keydb_search (hd, &desc, 1)) );
+  while (!(rc = keydb_search (hd, &desc, 1, NULL)));
+
   if (rc && gpg_err_code (rc) != GPG_ERR_NOT_FOUND)
     {
       log_error ("keydb_search_next failed: %s\n", g10_errstr(rc));
index 62e3dbe..8b2b900 100644 (file)
@@ -332,7 +332,8 @@ dump_fpr (const unsigned char *buffer, size_t len)
 static void
 dump_openpgp_key (keybox_openpgp_info_t info, const unsigned char *image)
 {
-  printf ("pub %02X%02X%02X%02X",
+  printf ("pub %2d %02X%02X%02X%02X",
+          info->primary.algo,
           info->primary.keyid[4], info->primary.keyid[5],
           info->primary.keyid[6], info->primary.keyid[7] );
   dump_fpr (info->primary.fpr, info->primary.fprlen);
@@ -344,7 +345,8 @@ dump_openpgp_key (keybox_openpgp_info_t info, const unsigned char *image)
       k = &info->subkeys;
       do
         {
-          printf ("sub %02X%02X%02X%02X",
+          printf ("sub %2d %02X%02X%02X%02X",
+                  k->algo,
                   k->keyid[4], k->keyid[5],
                   k->keyid[6], k->keyid[7] );
           dump_fpr (k->fpr, k->fprlen);
@@ -369,13 +371,14 @@ dump_openpgp_key (keybox_openpgp_info_t info, const unsigned char *image)
 
 
 static void
-import_openpgp (const char *filename)
+import_openpgp (const char *filename, int dryrun)
 {
   gpg_error_t err;
   char *buffer;
   size_t buflen, nparsed;
   unsigned char *p;
   struct _keybox_openpgp_info info;
+  KEYBOXBLOB blob;
 
   buffer = read_file (filename, &buflen);
   if (!buffer)
@@ -404,7 +407,31 @@ import_openpgp (const char *filename)
         }
       else
         {
-          dump_openpgp_key (&info, p);
+          if (dryrun)
+            dump_openpgp_key (&info, p);
+          else
+            {
+              err = _keybox_create_openpgp_blob (&blob, &info, p, nparsed,
+                                                 NULL, 0);
+              if (err)
+                {
+                  fflush (stdout);
+                  log_error ("%s: failed to create OpenPGP keyblock: %s\n",
+                             filename, gpg_strerror (err));
+                }
+              else
+                {
+                  err = _keybox_write_blob (blob, stdout);
+                  _keybox_release_blob (blob);
+                  if (err)
+                    {
+                      fflush (stdout);
+                      log_error ("%s: failed to write OpenPGP keyblock: %s\n",
+                                 filename, gpg_strerror (err));
+                    }
+                }
+            }
+
           _keybox_destroy_openpgp_info (&info);
         }
       p += nparsed;
@@ -422,6 +449,7 @@ main( int argc, char **argv )
   ARGPARSE_ARGS pargs;
   enum cmd_and_opt_values cmd = 0;
   unsigned long from = 0, to = ULONG_MAX;
+  int dry_run = 0;
 
   set_strusage( my_strusage );
   gcry_control (GCRYCTL_DISABLE_SECMEM);
@@ -479,6 +507,8 @@ main( int argc, char **argv )
         case oFrom: from = pargs.r.ret_ulong; break;
         case oTo: to = pargs.r.ret_ulong; break;
 
+        case oDryRun: dry_run = 1; break;
+
         default:
           pargs.err = 2;
           break;
@@ -535,11 +565,11 @@ main( int argc, char **argv )
   else if (cmd == aImportOpenPGP)
     {
       if (!argc)
-        import_openpgp ("-");
+        import_openpgp ("-", dry_run);
       else
         {
           for (; argc; argc--, argv++)
-            import_openpgp (*argv);
+            import_openpgp (*argv, dry_run);
         }
     }
 #if 0
index 998a770..6493527 100644 (file)
  * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
+/*
+* The keybox data format
+
+   The KeyBox uses an augmented OpenPGP/X.509 key format.  This makes
+   random access to a keyblock/certificate easier and also gives the
+   opportunity to store additional information (e.g. the fingerprint)
+   along with the key.  All integers are stored in network byte order,
+   offsets are counted from the beginning of the Blob.
+
+** Overview of blob types
+
+   | Byte 4 | Blob type    |
+   |--------+--------------|
+   |      0 | Empty blob   |
+   |      1 | First blob   |
+   |      2 | OpenPGP blob |
+   |      3 | X.509 blob   |
+
+** The First blob
+
+   The first blob of a plain KBX file has a special format:
+
+   - u32  Length of this blob
+   - byte Blob type (1)
+   - byte Version number (1)
+   - byte RFU
+   - byte RFU
+   - b4   Magic 'KBXf'
+   - u32  RFU
+   - u32  file_created_at
+   - u32  last_maintenance_run
+   - u32  RFU
+   - u32  RFU
+
+** The OpenPGP and X.509 blobs
+
+   The OpenPGP and X.509 blobs are very similiar, things which are
+   X.509 specific are noted like [X.509: xxx]
+
+   - u32  Length of this blob (including these 4 bytes)
+   - byte Blob type
+           2 = OpenPGP
+           3 = X509
+   - byte Version number of this blob type
+           1 = The only defined value
+   - u16  Blob flags
+          bit 0 = contains secret key material (not used)
+          bit 1 = ephemeral blob (e.g. used while quering external resources)
+   - u32  Offset to the OpenPGP keyblock or the X.509 DER encoded
+          certificate
+   - u32  The length of the keyblock or certificate
+   - u16  [NKEYS] Number of keys (at least 1!) [X509: always 1]
+   - u16  Size of the key information structure (at least 28).
+   - NKEYS times:
+      - b20  The fingerprint of the key.
+             Fingerprints are always 20 bytes, MD5 left padded with zeroes.
+      - u32  Offset to the n-th key's keyID (a keyID is always 8 byte)
+             or 0 if not known which is the case only for X.509.
+      - u16  Key flags
+             bit 0 = qualified signature (not yet implemented}
+      - u16  RFU
+      - bN   Optional filler up to the specified length of this
+             structure.
+   - u16  Size of the serial number (may be zero)
+      -  bN  The serial number. N as giiven above.
+   - u16  Number of user IDs
+   - u16  [NUIDS] Size of user ID information structure
+   - NUIDS times:
+
+      For X509, the first user ID is the Issuer, the second the
+      Subject and the others are subjectAltNames.  For OpenPGP we only
+      store the information from UserID packets here.
+
+      - u32  Blob offset to the n-th user ID
+      - u32  Length of this user ID.
+      - u16  User ID flags.
+             (not yet used)
+      - byte Validity
+      - byte RFU
+
+   - u16  [NSIGS] Number of signatures
+   - u16  Size of signature information (4)
+   - NSIGS times:
+      - u32  Expiration time of signature with some special values:
+             - 0x00000000 = not checked
+             - 0x00000001 = missing key
+             - 0x00000002 = bad signature
+             - 0x10000000 = valid and expires at some date in 1978.
+             - 0xffffffff = valid and does not expire
+   - u8        Assigned ownertrust [X509: not used]
+   - u8        All_Validity
+        OpenPGP: See ../g10/trustdb/TRUST_* [not yet used]
+        X509: Bit 4 set := key has been revoked.
+                           Note that this value matches TRUST_FLAG_REVOKED
+   - u16  RFU
+   - u32  Recheck_after
+   - u32  Latest timestamp in the keyblock (useful for KS syncronsiation?)
+   - u32  Blob created at
+   - u32  [NRES] Size of reserved space (not including this field)
+   - bN   Reserved space of size NRES for future use.
+   - bN   Arbitrary space for example used to store data which is not
+          part of the keyblock or certificate.  For example the v3 key
+          IDs go here.
+   - bN   Space for the keyblock or certifciate.
+   - bN   RFU
+   - b20  SHA-1 checksum (useful for KS syncronisation?)
+          Note, that KBX versions before GnuPG 2.1 used an MD5
+          checksum.  However it was only created but never checked.
+          Thus we do not expect problems if we switch to SHA-1.  If
+          the checksum fails and the first 4 bytes are zero, we can
+          try again with MD5.  SHA-1 has the advantage that it is
+          faster on CPUs with dedicated SHA-1 support.
 
-/* The keybox data formats
-
-The KeyBox uses an augmented OpenPGP/X.509 key format.  This makes
-random access to a keyblock/certificate easier and also gives the
-opportunity to store additional information (e.g. the fingerprint)
-along with the key.  All integers are stored in network byte order,
-offsets are counted from the beginning of the Blob.
-
-The first record of a plain KBX file has a special format:
-
- u32  length of the first record
- byte Blob type (1)
- byte version number (1)
- byte reserved
- byte reserved
- u32  magic 'KBXf'
- u32  reserved
- u32  file_created_at
- u32  last_maintenance_run
- u32  reserved
- u32  reserved
-
-The OpenPGP and X.509 blob are very similiar, things which are
-X.509 specific are noted like [X.509: xxx]
-
- u32  length of this blob (including these 4 bytes)
- byte Blob type (2) [X509: 3]
- byte version number of this blob type (1)
- u16  Blob flags
-       bit 0 = contains secret key material
-        bit 1 = ephemeral blob (e.g. used while quering external resources)
-
- u32  offset to the OpenPGP keyblock or X509 DER encoded certificate
- u32  and its length
- u16  number of keys (at least 1!) [X509: always 1]
- u16  size of additional key information
- n times:
-   b20 The keys fingerprint
-       (fingerprints are always 20 bytes, MD5 left padded with zeroes)
-   u32 offset to the n-th key's keyID (a keyID is always 8 byte)
-        or 0 if not known which is the case only for X509.
-   u16 special key flags
-        bit 0 = qualified signature (not yet implemented}
-   u16 reserved
- u16  size of serialnumber(may be zero)
-   n  u16 (see above) bytes of serial number
- u16  number of user IDs
- u16  size of additional user ID information
- n times:
-   u32 offset to the n-th user ID
-   u32 length of this user ID.
-   u16 special user ID flags.
-        bit 0 =
-   byte validity
-   byte reserved
-   [For X509, the first user ID is the Issuer, the second the Subject
-   and the others are subjectAltNames]
- u16  number of signatures
- u16  size of signature information (4)
-   u32 expiration time of signature with some special values:
-       0x00000000 = not checked
-       0x00000001 = missing key
-       0x00000002 = bad signature
-       0x10000000 = valid and expires at some date in 1978.
-       0xffffffff = valid and does not expire
- u8    assigned ownertrust [X509: not used]
- u8    all_validity
-           OpenPGP:  see ../g10/trustdb/TRUST_* [not yet used]
-           X509: Bit 4 set := key has been revoked.  Note that this value
-                              matches TRUST_FLAG_REVOKED
- u16   reserved
- u32   recheck_after
- u32   Newest timestamp in the keyblock (useful for KS syncronsiation?)
- u32   Blob created at
- u32   size of reserved space (not including this field)
-      reserved space
-
-    Here we might want to put other data
-
-    Here comes the keyblock
-
-    maybe we put a signature here later.
-
- b16   MD5 checksum  (useful for KS syncronisation), we might also want to use
-    a mac here.
- b4    reserved
 
 */
 
@@ -119,9 +145,6 @@ X.509 specific are noted like [X.509: xxx]
 #include "keybox-defs.h"
 #include <gcrypt.h>
 
-#ifdef KEYBOX_WITH_OPENPGP
-/* include stuff to parse the packets */
-#endif
 #ifdef KEYBOX_WITH_X509
 #include <ksba.h>
 #endif
@@ -156,6 +179,7 @@ struct keyboxblob_key {
   u16    flags;
 };
 struct keyboxblob_uid {
+  u32    off;
   ulong  off_addr;
   char   *name;     /* used only with x509 */
   u32    len;
@@ -237,7 +261,10 @@ put_membuf (struct membuf *mb, const void *buf, size_t len)
         }
       mb->buf = p;
     }
-  memcpy (mb->buf + mb->len, buf, len);
+  if (buf)
+    memcpy (mb->buf + mb->len, buf, len);
+  else
+    memset (mb->buf + mb->len, 0, len);
   mb->len += len;
 }
 
@@ -287,6 +314,7 @@ put32 (struct membuf *mb, u32 a )
   put_membuf (mb, tmp, 4);
 }
 
+
 \f
 /* Store a value in the fixup list */
 static void
@@ -311,33 +339,24 @@ add_fixup (KEYBOXBLOB blob, u32 off, u32 val)
 
 
 \f
-#ifdef KEYBOX_WITH_OPENPGP
 /*
   OpenPGP specific stuff
 */
 
 
-/*
-  We must store the keyid at some place because we can't calculate the
-  offset yet. This is only used for v3 keyIDs.  Function returns an
-  index value for later fixup or -1 for out of core. The value must be
-  a non-zero value */
+/* We must store the keyid at some place because we can't calculate
+   the offset yet. This is only used for v3 keyIDs.  Function returns
+   an index value for later fixup or -1 for out of core.  The value
+   must be a non-zero value. */
 static int
-pgp_temp_store_kid (KEYBOXBLOB blob, PKT_public_key *pk)
+pgp_temp_store_kid (KEYBOXBLOB blob, struct _keybox_openpgp_key_info *kinfo)
 {
   struct keyid_list *k, *r;
 
   k = xtrymalloc (sizeof *k);
   if (!k)
     return -1;
-  k->kid[0] = pk->keyid[0] >> 24 ;
-  k->kid[1] = pk->keyid[0] >> 16 ;
-  k->kid[2] = pk->keyid[0] >>  8 ;
-  k->kid[3] = pk->keyid[0]        ;
-  k->kid[4] = pk->keyid[0] >> 24 ;
-  k->kid[5] = pk->keyid[0] >> 16 ;
-  k->kid[6] = pk->keyid[0] >>  8 ;
-  k->kid[7] = pk->keyid[0]        ;
+  memcpy (k->kid, kinfo->keyid, 8);
   k->seqno = 0;
   k->next = blob->temp_kids;
   blob->temp_kids = k;
@@ -347,124 +366,108 @@ pgp_temp_store_kid (KEYBOXBLOB blob, PKT_public_key *pk)
   return k->seqno;
 }
 
-static int
-pgp_create_key_part (KEYBOXBLOB blob, KBNODE keyblock)
+
+/* Helper for pgp_create_key_part.  */
+static gpg_error_t
+pgp_create_key_part_single (KEYBOXBLOB blob, int n,
+                            struct _keybox_openpgp_key_info *kinfo)
 {
-  KBNODE node;
   size_t fprlen;
-  int n;
+  int off;
 
-  for (n=0, node = keyblock; node; node = node->next)
+  fprlen = kinfo->fprlen;
+  if (fprlen > 20)
+    fprlen = 20;
+  memcpy (blob->keys[n].fpr, kinfo->fpr, fprlen);
+  if (fprlen != 20) /* v3 fpr - shift right and fill with zeroes. */
     {
-      if ( node->pkt->pkttype == PKT_PUBLIC_KEY
-           || node->pkt->pkttype == PKT_PUBLIC_SUBKEY )
-        {
-          PKT_public_key *pk = node->pkt->pkt.public_key;
-          char tmp[20];
-
-          fingerprint_from_pk (pk, tmp , &fprlen);
-          memcpy (blob->keys[n].fpr, tmp, 20);
-          if ( fprlen != 20 ) /*v3 fpr - shift right and fill with zeroes*/
-            {
-              assert (fprlen == 16);
-              memmove (blob->keys[n].fpr+4, blob->keys[n].fpr, 16);
-              memset (blob->keys[n].fpr, 0, 4);
-              blob->keys[n].off_kid = pgp_temp_store_kid (blob, pk);
-           }
-          else
-            {
-              blob->keys[n].off_kid = 0; /* will be fixed up later */
-           }
-          blob->keys[n].flags = 0;
-          n++;
-       }
-      else if ( node->pkt->pkttype == PKT_SECRET_KEY
-                 || node->pkt->pkttype == PKT_SECRET_SUBKEY )
-        {
-          never_reached (); /* actually not yet implemented */
-       }
+      memmove (blob->keys[n].fpr + 20 - fprlen, blob->keys[n].fpr, fprlen);
+      memset (blob->keys[n].fpr, 0, 20 - fprlen);
+      off = pgp_temp_store_kid (blob, kinfo);
+      if (off == -1)
+        return gpg_error_from_syserror ();
+      blob->keys[n].off_kid = off;
     }
+  else
+    blob->keys[n].off_kid = 0; /* Will be fixed up later */
+  blob->keys[n].flags = 0;
+  return 0;
+}
+
+
+static gpg_error_t
+pgp_create_key_part (KEYBOXBLOB blob, keybox_openpgp_info_t info)
+{
+  gpg_error_t err;
+  int n = 0;
+  struct _keybox_openpgp_key_info *kinfo;
+
+  err = pgp_create_key_part_single (blob, n++, &info->primary);
+  if (err)
+    return err;
+  if (info->nsubkeys)
+    for (kinfo = &info->subkeys; kinfo; kinfo = kinfo->next)
+      if ((err=pgp_create_key_part_single (blob, n++, kinfo)))
+        return err;
+
   assert (n == blob->nkeys);
   return 0;
 }
 
-static int
-pgp_create_uid_part (KEYBOXBLOB blob, KBNODE keyblock)
+
+static void
+pgp_create_uid_part (KEYBOXBLOB blob, keybox_openpgp_info_t info)
 {
-  KBNODE node;
-  int n;
+  int n = 0;
+  struct _keybox_openpgp_uid_info *u;
 
-  for (n=0, node = keyblock; node; node = node->next)
+  if (info->nuids)
     {
-      if (node->pkt->pkttype == PKT_USER_ID)
+      for (u = &info->uids; u; u = u->next)
         {
-          PKT_user_id *u = node->pkt->pkt.user_id;
-
+          blob->uids[n].off = u->off;
           blob->uids[n].len = u->len;
           blob->uids[n].flags = 0;
           blob->uids[n].validity = 0;
           n++;
-       }
+        }
     }
+
   assert (n == blob->nuids);
-  return 0;
 }
 
-static int
-pgp_create_sig_part (KEYBOXBLOB blob, KBNODE keyblock)
+
+static void
+pgp_create_sig_part (KEYBOXBLOB blob, u32 *sigstatus)
 {
-  KBNODE node;
   int n;
 
-  for (n=0, node = keyblock; node; node = node->next)
+  for (n=0; n < blob->nsigs; n++)
     {
-      if (node->pkt->pkttype == PKT_SIGNATURE)
-        {
-          PKT_signature *sig = node->pkt->pkt.signature;
-
-          blob->sigs[n] = 0;   /* FIXME: check the signature here */
-          n++;
-       }
+      blob->sigs[n] = sigstatus? sigstatus[n+1] : 0;
     }
-  assert( n == blob->nsigs );
-  return 0;
 }
 
+
 static int
-pgp_create_blob_keyblock (KEYBOXBLOB blob, KBNODE keyblock)
+pgp_create_blob_keyblock (KEYBOXBLOB blob,
+                          const unsigned char *image, size_t imagelen)
 {
   struct membuf *a = blob->buf;
-  KBNODE node;
-  int rc;
   int n;
   u32 kbstart = a->len;
 
-  add_fixup (blob, kbstart);
+  add_fixup (blob, 8, kbstart);
 
-  for (n = 0, node = keyblock; node; node = node->next)
-    {
-      rc = build_packet ( a, node->pkt );
-      if ( rc ) {
-        gpg_log_error ("build_packet(%d) for keyboxblob failed: %s\n",
-                      node->pkt->pkttype, gpg_errstr(rc) );
-        return GPGERR_WRITE_FILE;
-      }
-      if ( node->pkt->pkttype == PKT_USER_ID )
-        {
-          PKT_user_id *u = node->pkt->pkt.user_id;
-          /* build_packet has set the offset of the name into u ;
-           * now we can do the fixup */
-          add_fixup (blob, blob->uids[n].off_addr, u->stored_at);
-          n++;
-       }
-    }
-  assert (n == blob->nuids);
+  for (n = 0; n < blob->nuids; n++)
+    add_fixup (blob, blob->uids[n].off_addr, kbstart + blob->uids[n].off);
+
+  put_membuf (a, image, imagelen);
 
-  add_fixup (blob, a->len - kbstart);
+  add_fixup (blob, 12, a->len - kbstart);
   return 0;
 }
 
-#endif /*KEYBOX_WITH_OPENPGP*/
 
 \f
 #ifdef KEYBOX_WITH_X509
@@ -639,12 +642,10 @@ create_blob_finish (KEYBOXBLOB blob)
   struct membuf *a = blob->buf;
   unsigned char *p;
   unsigned char *pp;
-  int i;
   size_t n;
 
-  /* write a placeholder for the checksum */
-  for (i = 0; i < 16; i++ )
-    put32 (a, 0);  /* Hmmm: why put32() ?? */
+  /* Write a placeholder for the checksum */
+  put_membuf (a, NULL, 20);
 
   /* get the memory area */
   n = 0; /* (Just to avoid compiler warning.) */
@@ -672,8 +673,8 @@ create_blob_finish (KEYBOXBLOB blob)
       }
   }
 
-  /* calculate and store the MD5 checksum */
-  gcry_md_hash_buffer (GCRY_MD_MD5, p + n - 16, p, n - 16);
+  /* Compute and store the SHA-1 checksum. */
+  gcry_md_hash_buffer (GCRY_MD_SHA1, p + n - 20, p, n - 20);
 
   pp = xtrymalloc (n);
   if ( !pp )
@@ -685,88 +686,86 @@ create_blob_finish (KEYBOXBLOB blob)
   return 0;
 }
 
-\f
-#ifdef KEYBOX_WITH_OPENPGP
 
-int
-_keybox_create_pgp_blob (KEYBOXBLOB *r_blob, KBNODE keyblock, int as_ephemeral)
+\f
+gpg_error_t
+_keybox_create_openpgp_blob (KEYBOXBLOB *r_blob,
+                             keybox_openpgp_info_t info,
+                             const unsigned char *image,
+                             size_t imagelen,
+                             u32 *sigstatus,
+                             int as_ephemeral)
 {
-  int rc = 0;
-  KBNODE node;
+  gpg_error_t err;
   KEYBOXBLOB blob;
 
   *r_blob = NULL;
+
+  if (!info->nuids || !info->nsigs)
+    return gpg_error (GPG_ERR_BAD_PUBKEY);
+
+  /* If we have a signature status vector, check that the number of
+     elements matches the actual number of signatures.  */
+  if (sigstatus && sigstatus[0] != info->nsigs)
+    return gpg_error (GPG_ERR_INTERNAL);
+
   blob = xtrycalloc (1, sizeof *blob);
   if (!blob)
     return gpg_error_from_syserror ();
 
-  /* fixme: Do some sanity checks on the keyblock */
-
-  /* count userids and keys so that we can allocate the arrays */
-  for (node = keyblock; node; node = node->next)
+  blob->nkeys = 1 + info->nsubkeys;
+  blob->keys = xtrycalloc (blob->nkeys, sizeof *blob->keys );
+  if (!blob->keys)
     {
-      switch (node->pkt->pkttype)
-        {
-        case PKT_PUBLIC_KEY:
-        case PKT_SECRET_KEY:
-        case PKT_PUBLIC_SUBKEY:
-        case PKT_SECRET_SUBKEY: blob->nkeys++; break;
-        case PKT_USER_ID:  blob->nuids++; break;
-        case PKT_SIGNATURE: blob->nsigs++; break;
-        default: break;
-       }
+      err = gpg_error_from_syserror ();
+      goto leave;
     }
-
-  blob->keys = xtrycalloc (blob->nkeys, sizeof *blob->keys );
+  blob->nuids = info->nuids;
   blob->uids = xtrycalloc (blob->nuids, sizeof *blob->uids );
+  if (!blob->uids)
+    {
+      err = gpg_error_from_syserror ();
+      goto leave;
+    }
+  blob->nsigs = info->nsigs;
   blob->sigs = xtrycalloc (blob->nsigs, sizeof *blob->sigs );
-  if (!blob->keys || !blob->uids || !blob->sigs)
+  if (!blob->sigs)
     {
-      rc = gpg_error (GPG_ERR_ENOMEM);
+      err = gpg_error_from_syserror ();
       goto leave;
     }
 
-  rc = pgp_create_key_part ( blob, keyblock );
-  if (rc)
-    goto leave;
-  rc = pgp_create_uid_part ( blob, keyblock );
-  if (rc)
-    goto leave;
-  rc = pgp_create_sig_part ( blob, keyblock );
-  if (rc)
+  err = pgp_create_key_part (blob, info);
+  if (err)
     goto leave;
+  pgp_create_uid_part (blob, info);
+  pgp_create_sig_part (blob, sigstatus);
 
   init_membuf (&blob->bufbuf, 1024);
   blob->buf = &blob->bufbuf;
-  rc = create_blob_header (blob, BLOBTYPE_OPENPGP, as_ephemeral);
-  if (rc)
+  err = create_blob_header (blob, BLOBTYPE_PGP, as_ephemeral);
+  if (err)
     goto leave;
-  rc = pgp_create_blob_keyblock (blob, keyblock);
-  if (rc)
+  err = pgp_create_blob_keyblock (blob, image, imagelen);
+  if (err)
     goto leave;
-  rc = create_blob_trailer (blob);
-  if (rc)
+  err = create_blob_trailer (blob);
+  if (err)
     goto leave;
-  rc = create_blob_finish ( blob );
-  if (rc)
+  err = create_blob_finish (blob);
+  if (err)
     goto leave;
 
-
  leave:
   release_kid_list (blob->temp_kids);
   blob->temp_kids = NULL;
-  if (rc)
-    {
-      keybox_release_blob (blob);
-      *r_blob = NULL;
-    }
+  if (err)
+    _keybox_release_blob (blob);
   else
-    {
-      *r_blob = blob;
-    }
-  return rc;
+    *r_blob = blob;
+  return err;
 }
-#endif /*KEYBOX_WITH_OPENPGP*/
+
 
 #ifdef KEYBOX_WITH_X509
 
index ee48ca3..ad8e49d 100644 (file)
@@ -111,6 +111,7 @@ struct keybox_handle {
 struct _keybox_openpgp_key_info
 {
   struct _keybox_openpgp_key_info *next;
+  int algo;
   unsigned char keyid[8];
   int fprlen;  /* Either 16 or 20 */
   unsigned char fpr[20];
@@ -155,9 +156,12 @@ void _keybox_close_file (KEYBOX_HANDLE hd);
 
 
 /*-- keybox-blob.c --*/
-#ifdef KEYBOX_WITH_OPENPGP
-  /* fixme */
-#endif /*KEYBOX_WITH_OPENPGP*/
+gpg_error_t _keybox_create_openpgp_blob (KEYBOXBLOB *r_blob,
+                                         keybox_openpgp_info_t info,
+                                         const unsigned char *image,
+                                         size_t imagelen,
+                                         u32 *sigstatus,
+                                         int as_ephemeral);
 #ifdef KEYBOX_WITH_X509
 int _keybox_create_x509_blob (KEYBOXBLOB *r_blob, ksba_cert_t cert,
                               unsigned char *sha1_digest, int as_ephemeral);
@@ -182,7 +186,6 @@ void _keybox_destroy_openpgp_info (keybox_openpgp_info_t info);
 int _keybox_read_blob (KEYBOXBLOB *r_blob, FILE *fp);
 int _keybox_read_blob2 (KEYBOXBLOB *r_blob, FILE *fp, int *skipped_deleted);
 int _keybox_write_blob (KEYBOXBLOB blob, FILE *fp);
-int _keybox_write_header_blob (FILE *fp);
 
 /*-- keybox-search.c --*/
 gpg_err_code_t _keybox_get_flag_location (const unsigned char *buffer,
index c5f518e..c397f9c 100644 (file)
@@ -80,6 +80,57 @@ print_string (FILE *fp, const byte *p, size_t n, int delim)
 
 
 static int
+print_checksum (const byte *buffer, size_t length, size_t unhashed, FILE *fp)
+{
+  const byte *p;
+  int i;
+  int hashlen;
+  unsigned char digest[20];
+
+  fprintf (fp, "Checksum: ");
+  if (unhashed && unhashed < 20)
+    {
+      fputs ("[specified unhashed sized too short]\n", fp);
+      return 0;
+    }
+  if (!unhashed)
+    {
+      unhashed = 16;
+      hashlen = 16;
+    }
+  else
+    hashlen = 20;
+  if (length < 5+unhashed)
+    {
+      fputs ("[blob too short for a checksum]\n", fp);
+      return 0;
+    }
+
+  p = buffer + length - hashlen;
+  for (i=0; i < hashlen; p++, i++)
+    fprintf (fp, "%02x", *p);
+
+  if (hashlen == 16) /* Compatibility method.  */
+    {
+      gcry_md_hash_buffer (GCRY_MD_MD5, digest, buffer, length - 16);
+      if (!memcmp (buffer + length - 16, digest, 16))
+        fputs (" [valid]\n", fp);
+      else
+        fputs (" [bad]\n", fp);
+    }
+  else
+    {
+      gcry_md_hash_buffer (GCRY_MD_SHA1, digest, buffer, length - unhashed);
+      if (!memcmp (buffer + length - hashlen, digest, hashlen))
+        fputs (" [valid]\n", fp);
+      else
+        fputs (" [bad]\n", fp);
+    }
+  return 0;
+}
+
+
+static int
 dump_header_blob (const byte *buffer, size_t length, FILE *fp)
 {
   unsigned long n;
@@ -108,12 +159,13 @@ _keybox_dump_blob (KEYBOXBLOB blob, FILE *fp)
 {
   const byte *buffer;
   size_t length;
-  int type;
+  int type, i;
   ulong n, nkeys, keyinfolen;
   ulong nuids, uidinfolen;
   ulong nsigs, siginfolen;
   ulong rawdata_off, rawdata_len;
   ulong nserial;
+  ulong unhashed;
   const byte *p;
 
   buffer = _keybox_get_blob_image (blob, &length);
@@ -189,8 +241,12 @@ _keybox_dump_blob (KEYBOXBLOB blob, FILE *fp)
   fprintf( fp, "Data-Offset: %lu\n", rawdata_off );
   fprintf( fp, "Data-Length: %lu\n", rawdata_len );
   if (rawdata_off > length || rawdata_len > length
-      || rawdata_off+rawdata_off > length)
+      || rawdata_off+rawdata_len > length
+      || rawdata_len + 4 > length
+      || rawdata_off+rawdata_len + 4 > length)
     fprintf (fp, "[Error: raw data larger than blob]\n");
+  unhashed = get32 (buffer + rawdata_off + rawdata_len);
+  fprintf (fp, "Unhashed: %lu\n", unhashed);
 
   nkeys = get16 (buffer + 16);
   fprintf (fp, "Key-Count: %lu\n", nkeys );
@@ -205,7 +261,6 @@ _keybox_dump_blob (KEYBOXBLOB blob, FILE *fp)
   p = buffer + 20;
   for (n=0; n < nkeys; n++, p += keyinfolen)
     {
-      int i;
       ulong kidoff, kflags;
 
       fprintf (fp, "Key-Fpr[%lu]: ", n );
@@ -291,27 +346,50 @@ _keybox_dump_blob (KEYBOXBLOB blob, FILE *fp)
   fprintf (fp, "Sig-Info-Length: %lu\n", siginfolen );
   /* fixme: check bounds  */
   p += 4;
-  for (n=0; n < nsigs; n++, p += siginfolen)
-    {
-      ulong sflags;
-
-      sflags = get32 (p);
-      fprintf (fp, "Sig-Expire[%lu]: ", n );
-      if (!sflags)
-        fputs ("[not checked]", fp);
-      else if (sflags == 1 )
-        fputs ("[missing key]", fp);
-      else if (sflags == 2 )
-        fputs ("[bad signature]", fp);
-      else if (sflags < 0x10000000)
-        fprintf (fp, "[bad flag %0lx]", sflags);
-      else if (sflags == 0xffffffff)
-        fputs ("0", fp );
-      else
-        fputs ("a time"/*strtimestamp( sflags )*/, fp );
-      putc ('\n', fp );
-    }
-
+  {
+    int in_range = 0;
+    ulong first = 0;
+
+    for (n=0; n < nsigs; n++, p += siginfolen)
+      {
+        ulong sflags;
+
+        sflags = get32 (p);
+        if (!in_range && !sflags)
+          {
+            in_range = 1;
+            first = n;
+            continue;
+          }
+        if (in_range && !sflags)
+          continue;
+        if (in_range)
+          {
+            fprintf (fp, "Sig-Expire[%lu-%lu]: [not checked]\n", first, n-1);
+            in_range = 0;
+          }
+
+        fprintf (fp, "Sig-Expire[%lu]: ", n );
+        if (!sflags)
+          fputs ("[not checked]", fp);
+        else if (sflags == 1 )
+          fputs ("[missing key]", fp);
+        else if (sflags == 2 )
+          fputs ("[bad signature]", fp);
+        else if (sflags < 0x10000000)
+          fprintf (fp, "[bad flag %0lx]", sflags);
+        else if (sflags == 0xffffffff)
+          fputs ("[good - does not expire]", fp );
+        else
+          fprintf (fp, "[good - expires at %lu]", sflags);
+        putc ('\n', fp );
+      }
+    if (in_range)
+      {
+        fprintf (fp, "Sig-Expire[%lu-%lu]: [not checked]\n", first, n-1);
+        in_range = 0;
+      }
+  }
   fprintf (fp, "Ownertrust: %d\n", p[0] );
   fprintf (fp, "All-Validity: %d\n", p[1] );
   p += 4;
@@ -324,13 +402,17 @@ _keybox_dump_blob (KEYBOXBLOB blob, FILE *fp)
   n = get32 (p ); p += 4;
   fprintf (fp, "Reserved-Space: %lu\n", n );
 
-  /* check that the keyblock is at the correct offset and other bounds */
-  /*fprintf (fp, "Blob-Checksum: [MD5-hash]\n");*/
+  if (unhashed >= 24)
+    {
+      n = get32 ( buffer + length - unhashed);
+      fprintf (fp, "Storage-Flags: %08lx\n", n );
+    }
+  print_checksum (buffer, length, unhashed, fp);
   return 0;
 }
 
 
-/* Compute the SHA_1 checksum of teh rawdata in BLOB and aput it into
+/* Compute the SHA-1 checksum of the rawdata in BLOB and put it into
    DIGEST. */
 static int
 hash_blob_rawdata (KEYBOXBLOB blob, unsigned char *digest)
index ecfdfbe..027bcf8 100644 (file)
@@ -74,7 +74,7 @@ _keybox_read_blob2 (KEYBOXBLOB *r_blob, FILE *fp, int *skipped_deleted)
     }
 
   imagelen = (c1 << 24) | (c2 << 16) | (c3 << 8 ) | c4;
-  if (imagelen > 500000) /* Sanity check. */
+  if (imagelen > 1000000) /* Sanity check. */
     return gpg_error (GPG_ERR_TOO_LARGE);
 
   if (imagelen < 5)
index 60594e3..d329941 100644 (file)
@@ -200,3 +200,20 @@ _keybox_close_file (KEYBOX_HANDLE hd)
       }
   assert (!hd->fp);
 }
+
+
+/*
+ * Lock the keybox at handle HD, or unlock if YES is false.  Note that
+ * we currently ignore the handle and lock all registered keyboxes.
+ */
+int
+keybox_lock (KEYBOX_HANDLE hd, int yes)
+{
+  /* FIXME: We need to implement it before we can use it with gpg.
+     gpgsm does the locking in its local keydb.c driver; this should
+     be changed as well.  */
+
+  (void)hd;
+  (void)yes;
+  return 0;
+}
index 37e2771..82bc934 100644 (file)
@@ -223,6 +223,8 @@ parse_key (const unsigned char *data, size_t datalen,
       return gpg_error (GPG_ERR_UNKNOWN_ALGORITHM);
     }
 
+  ki->algo = algorithm;
+
   for (i=0; i < npkey; i++ )
     {
       unsigned int nbits, nbytes;
index ef5cd95..5e6432f 100644 (file)
@@ -1,5 +1,6 @@
 /* keybox-search.c - Search operations
- * Copyright (C) 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+ * Copyright (C) 2001, 2002, 2003, 2004, 2012,
+ *               2013 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -102,7 +103,7 @@ _keybox_get_flag_location (const unsigned char *buffer, size_t length,
   size_t nkeys, keyinfolen;
   size_t nuids, uidinfolen;
   size_t nserial;
-  size_t nsigs, siginfolen;
+  size_t nsigs, siginfolen, siginfooff;
 
   switch (what)
     {
@@ -116,6 +117,7 @@ _keybox_get_flag_location (const unsigned char *buffer, size_t length,
     case KEYBOX_FLAG_OWNERTRUST:
     case KEYBOX_FLAG_VALIDITY:
     case KEYBOX_FLAG_CREATED_AT:
+    case KEYBOX_FLAG_SIG_INFO:
       if (length < 20)
         return GPG_ERR_INV_OBJ;
       /* Key info. */
@@ -140,6 +142,7 @@ _keybox_get_flag_location (const unsigned char *buffer, size_t length,
       if (pos+4 > length)
         return GPG_ERR_INV_OBJ ; /* Out of bounds. */
       /* Signature info. */
+      siginfooff = pos;
       nsigs = get16 (buffer + pos); pos += 2;
       siginfolen = get16 (buffer + pos); pos += 2;
       if (siginfolen < 4 )
@@ -158,6 +161,10 @@ _keybox_get_flag_location (const unsigned char *buffer, size_t length,
           *flag_size = 4;
           *flag_off += 1+2+4+4+4;
           break;
+        case KEYBOX_FLAG_SIG_INFO:
+          *flag_size = siginfolen * nsigs;
+          *flag_off = siginfooff;
+          break;
         default:
           break;
         }
@@ -227,6 +234,9 @@ blob_cmp_sn (KEYBOXBLOB blob, const unsigned char *sn, int snlen)
 }
 
 
+/* Returns 0 if not found or the number of the key which was found.
+   For X.509 this is always 1, for OpenPGP this is 1 for the primary
+   key and 2 and more for the subkeys.  */
 static int
 blob_cmp_fpr (KEYBOXBLOB blob, const unsigned char *fpr)
 {
@@ -253,7 +263,7 @@ blob_cmp_fpr (KEYBOXBLOB blob, const unsigned char *fpr)
     {
       off = pos + idx*keyinfolen;
       if (!memcmp (buffer + off, fpr, 20))
-        return 1; /* found */
+        return idx+1; /* found */
     }
   return 0; /* not found */
 }
@@ -285,7 +295,7 @@ blob_cmp_fpr_part (KEYBOXBLOB blob, const unsigned char *fpr,
     {
       off = pos + idx*keyinfolen;
       if (!memcmp (buffer + off + fproff, fpr, fprlen))
-        return 1; /* found */
+        return idx+1; /* found */
     }
   return 0; /* not found */
 }
@@ -293,7 +303,7 @@ blob_cmp_fpr_part (KEYBOXBLOB blob, const unsigned char *fpr,
 
 static int
 blob_cmp_name (KEYBOXBLOB blob, int idx,
-               const char *name, size_t namelen, int substr)
+               const char *name, size_t namelen, int substr, int x509)
 {
   const unsigned char *buffer;
   size_t length;
@@ -330,10 +340,9 @@ blob_cmp_name (KEYBOXBLOB blob, int idx,
     return 0; /* out of bounds */
 
   if (idx < 0)
-    { /* compare all names starting with that (negated) index */
-      idx = -idx;
-
-      for ( ;idx < nuids; idx++)
+    { /* Compare all names.  Note that for X.509 we start with index 1
+         so to skip the issuer at index 0.  */
+      for (idx = !!x509; idx < nuids; idx++)
         {
           size_t mypos = pos;
 
@@ -347,15 +356,14 @@ blob_cmp_name (KEYBOXBLOB blob, int idx,
           if (substr)
             {
               if (ascii_memcasemem (buffer+off, len, name, namelen))
-                return 1; /* found */
+                return idx+1; /* found */
             }
           else
             {
               if (len == namelen && !memcmp (buffer+off, name, len))
-                return 1; /* found */
+                return idx+1; /* found */
             }
         }
-      return 0; /* not found */
     }
   else
     {
@@ -371,20 +379,25 @@ blob_cmp_name (KEYBOXBLOB blob, int idx,
 
       if (substr)
         {
-          return !!ascii_memcasemem (buffer+off, len, name, namelen);
+          if (ascii_memcasemem (buffer+off, len, name, namelen))
+            return idx+1; /* found */
         }
       else
         {
-          return len == namelen && !memcmp (buffer+off, name, len);
+          if (len == namelen && !memcmp (buffer+off, name, len))
+            return idx+1; /* found */
         }
     }
+  return 0; /* not found */
 }
 
 
-/* compare all email addresses of the subject.  With SUBSTR given as
-   True a substring search is done in the mail address */
+/* Compare all email addresses of the subject.  With SUBSTR given as
+   True a substring search is done in the mail address.  If X509
+   states whether thr search is done on an X.509 blob.  */
 static int
-blob_cmp_mail (KEYBOXBLOB blob, const char *name, size_t namelen, int substr)
+blob_cmp_mail (KEYBOXBLOB blob, const char *name, size_t namelen, int substr,
+               int x509)
 {
   const unsigned char *buffer;
   size_t length;
@@ -425,7 +438,9 @@ blob_cmp_mail (KEYBOXBLOB blob, const char *name, size_t namelen, int substr)
   if (namelen < 1)
     return 0;
 
-  for (idx=1 ;idx < nuids; idx++)
+  /* Note that for X.509 we start at index 1 becuase index 0 is used
+     for the issuer name.  */
+  for (idx=!!x509 ;idx < nuids; idx++)
     {
       size_t mypos = pos;
 
@@ -434,6 +449,12 @@ blob_cmp_mail (KEYBOXBLOB blob, const char *name, size_t namelen, int substr)
       len = get32 (buffer+mypos+4);
       if (off+len > length)
         return 0; /* error: better stop here out of bounds */
+      if (!x509)
+        {
+          /* For OpenPGP we need to forward to the mailbox part.  */
+          for ( ;len && buffer[off] != '<'; len--, off++)
+            ;
+        }
       if (len < 2 || buffer[off] != '<')
         continue; /* empty name or trailing 0 not stored */
       len--; /* one back */
@@ -443,12 +464,12 @@ blob_cmp_mail (KEYBOXBLOB blob, const char *name, size_t namelen, int substr)
       if (substr)
         {
           if (ascii_memcasemem (buffer+off+1, len, name, namelen))
-            return 1; /* found */
+            return idx+1; /* found */
         }
       else
         {
           if (len == namelen && !ascii_memcasecmp (buffer+off+1, name, len))
-            return 1; /* found */
+            return idx+1; /* found */
         }
     }
   return 0; /* not found */
@@ -583,7 +604,7 @@ has_issuer (KEYBOXBLOB blob, const char *name)
     return 0;
 
   namelen = strlen (name);
-  return blob_cmp_name (blob, 0 /* issuer */, name, namelen, 0);
+  return blob_cmp_name (blob, 0 /* issuer */, name, namelen, 0, 1);
 }
 
 static inline int
@@ -601,7 +622,7 @@ has_issuer_sn (KEYBOXBLOB blob, const char *name,
   namelen = strlen (name);
 
   return (blob_cmp_sn (blob, sn, snlen)
-          && blob_cmp_name (blob, 0 /* issuer */, name, namelen, 0));
+          && blob_cmp_name (blob, 0 /* issuer */, name, namelen, 0, 1));
 }
 
 static inline int
@@ -625,22 +646,25 @@ has_subject (KEYBOXBLOB blob, const char *name)
     return 0;
 
   namelen = strlen (name);
-  return blob_cmp_name (blob, 1 /* subject */, name, namelen, 0);
+  return blob_cmp_name (blob, 1 /* subject */, name, namelen, 0, 1);
 }
 
+
 static inline int
-has_subject_or_alt (KEYBOXBLOB blob, const char *name, int substr)
+has_username (KEYBOXBLOB blob, const char *name, int substr)
 {
   size_t namelen;
+  int btype;
 
   return_val_if_fail (name, 0);
 
-  if (blob_get_type (blob) != BLOBTYPE_X509)
+  btype = blob_get_type (blob);
+  if (btype != BLOBTYPE_PGP && btype != BLOBTYPE_X509)
     return 0;
 
   namelen = strlen (name);
-  return blob_cmp_name (blob, -1 /* all subject names*/, name,
-                        namelen, substr);
+  return blob_cmp_name (blob, -1 /* all subject/user names */, name,
+                        namelen, substr, (btype == BLOBTYPE_X509));
 }
 
 
@@ -648,16 +672,21 @@ static inline int
 has_mail (KEYBOXBLOB blob, const char *name, int substr)
 {
   size_t namelen;
+  int btype;
 
   return_val_if_fail (name, 0);
 
-  if (blob_get_type (blob) != BLOBTYPE_X509)
+  btype = blob_get_type (blob);
+  if (btype != BLOBTYPE_PGP && btype != BLOBTYPE_X509)
     return 0;
 
+  if (btype == BLOBTYPE_PGP && *name == '<')
+    name++; /* Hack to remove the leading '<' for gpg.  */
+
   namelen = strlen (name);
   if (namelen && name[namelen-1] == '>')
     namelen--;
-  return blob_cmp_mail (blob, name, namelen, substr);
+  return blob_cmp_mail (blob, name, namelen, substr, (btype == BLOBTYPE_X509));
 }
 
 
@@ -711,6 +740,7 @@ keybox_search (KEYBOX_HANDLE hd, KEYBOX_SEARCH_DESC *desc, size_t ndesc)
   int need_words, any_skip;
   KEYBOXBLOB blob = NULL;
   struct sn_array_s *sn_array = NULL;
+  int pk_no, uid_no;
 
   if (!hd)
     return gpg_error (GPG_ERR_INV_VALUE);
@@ -827,6 +857,7 @@ keybox_search (KEYBOX_HANDLE hd, KEYBOX_SEARCH_DESC *desc, size_t ndesc)
     }
 
 
+  pk_no = uid_no = 0;
   for (;;)
     {
       unsigned int blobflags;
@@ -852,19 +883,23 @@ keybox_search (KEYBOX_HANDLE hd, KEYBOX_SEARCH_DESC *desc, size_t ndesc)
               never_reached ();
               break;
             case KEYDB_SEARCH_MODE_EXACT:
-              if (has_subject_or_alt (blob, desc[n].u.name, 0))
+              uid_no = has_username (blob, desc[n].u.name, 0);
+              if (uid_no)
                 goto found;
               break;
             case KEYDB_SEARCH_MODE_MAIL:
-              if (has_mail (blob, desc[n].u.name, 0))
+              uid_no = has_mail (blob, desc[n].u.name, 0);
+              if (uid_no)
                 goto found;
               break;
             case KEYDB_SEARCH_MODE_MAILSUB:
-              if (has_mail (blob, desc[n].u.name, 1))
+              uid_no = has_mail (blob, desc[n].u.name, 1);
+              if (uid_no)
                 goto found;
               break;
             case KEYDB_SEARCH_MODE_SUBSTR:
-              if (has_subject_or_alt (blob, desc[n].u.name, 1))
+              uid_no =  has_username (blob, desc[n].u.name, 1);
+              if (uid_no)
                 goto found;
               break;
             case KEYDB_SEARCH_MODE_MAILEND:
@@ -891,16 +926,19 @@ keybox_search (KEYBOX_HANDLE hd, KEYBOX_SEARCH_DESC *desc, size_t ndesc)
                 goto found;
               break;
             case KEYDB_SEARCH_MODE_SHORT_KID:
-              if (has_short_kid (blob, desc[n].u.kid[1]))
+              pk_no = has_short_kid (blob, desc[n].u.kid[1]);
+              if (pk_no)
                 goto found;
               break;
             case KEYDB_SEARCH_MODE_LONG_KID:
-              if (has_long_kid (blob, desc[n].u.kid[0], desc[n].u.kid[1]))
+              pk_no = has_long_kid (blob, desc[n].u.kid[0], desc[n].u.kid[1]);
+              if (pk_no)
                 goto found;
               break;
             case KEYDB_SEARCH_MODE_FPR:
             case KEYDB_SEARCH_MODE_FPR20:
-              if (has_fingerprint (blob, desc[n].u.fpr))
+              pk_no = has_fingerprint (blob, desc[n].u.fpr);
+              if (pk_no)
                 goto found;
               break;
             case KEYDB_SEARCH_MODE_KEYGRIP:
@@ -933,6 +971,8 @@ keybox_search (KEYBOX_HANDLE hd, KEYBOX_SEARCH_DESC *desc, size_t ndesc)
   if (!rc)
     {
       hd->found.blob = blob;
+      hd->found.pk_no = pk_no;
+      hd->found.uid_no = uid_no;
     }
   else if (rc == -1)
     {
@@ -958,6 +998,65 @@ keybox_search (KEYBOX_HANDLE hd, KEYBOX_SEARCH_DESC *desc, size_t ndesc)
    Functions to return a certificate or a keyblock.  To be used after
    a successful search operation.
 */
+
+
+/* Return the last found keyblock.  Returns 0 on success and stores a
+   new iobuf at R_IOBUF and a signature status vector at R_SIGSTATUS
+   in that case.  R_UID_NO and R_PK_NO are used to retun the number of
+   the key or user id which was matched the search criteria; if not
+   known they are set to 0. */
+gpg_error_t
+keybox_get_keyblock (KEYBOX_HANDLE hd, iobuf_t *r_iobuf,
+                     int *r_pk_no, int *r_uid_no, u32 **r_sigstatus)
+{
+  gpg_error_t err;
+  const unsigned char *buffer, *p;
+  size_t length;
+  size_t image_off, image_len;
+  size_t siginfo_off, siginfo_len;
+  u32 *sigstatus, n, n_sigs, sigilen;
+
+  *r_iobuf = NULL;
+  *r_sigstatus = NULL;
+
+  if (!hd)
+    return gpg_error (GPG_ERR_INV_VALUE);
+  if (!hd->found.blob)
+    return gpg_error (GPG_ERR_NOTHING_FOUND);
+
+  if (blob_get_type (hd->found.blob) != BLOBTYPE_PGP)
+    return gpg_error (GPG_ERR_WRONG_BLOB_TYPE);
+
+  buffer = _keybox_get_blob_image (hd->found.blob, &length);
+  if (length < 40)
+    return gpg_error (GPG_ERR_TOO_SHORT);
+  image_off = get32 (buffer+8);
+  image_len = get32 (buffer+12);
+  if (image_off+image_len > length)
+    return gpg_error (GPG_ERR_TOO_SHORT);
+
+  err = _keybox_get_flag_location (buffer, length, KEYBOX_FLAG_SIG_INFO,
+                                   &siginfo_off, &siginfo_len);
+  if (err)
+    return err;
+  n_sigs  = get16 (buffer + siginfo_off);
+  sigilen = get16 (buffer + siginfo_off + 2);
+  p = buffer + siginfo_off + 4;
+  sigstatus = xtrymalloc ((1+n_sigs) * sizeof *sigstatus);
+  if (!sigstatus)
+    return gpg_error_from_syserror ();
+  sigstatus[0] = n_sigs;
+  for (n=1; n <= n_sigs; n++, p += sigilen)
+    sigstatus[n] = get32 (p);
+
+  *r_pk_no  = hd->found.pk_no;
+  *r_uid_no = hd->found.uid_no;
+  *r_sigstatus = sigstatus;
+  *r_iobuf = iobuf_temp_with_content (buffer+image_off, image_len);
+  return 0;
+}
+
+
 #ifdef KEYBOX_WITH_X509
 /*
   Return the last found cert.  Caller must free it.
index 0d052c9..6428bb2 100644 (file)
@@ -1,5 +1,5 @@
 /* keybox-update.c - keybox update operations
- *     Copyright (C) 2001, 2003, 2004 Free Software Foundation, Inc.
+ * Copyright (C) 2001, 2003, 2004, 2012 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -24,6 +24,7 @@
 #include <errno.h>
 #include <time.h>
 #include <unistd.h>
+#include <assert.h>
 
 #include "keybox-defs.h"
 #include "../common/sysutils.h"
@@ -370,6 +371,65 @@ blob_filecopy (int mode, const char *fname, KEYBOXBLOB blob,
 }
 
 
+/* Insert the OpenPGP keyblock {IMAGE,IMAGELEN} into HD.  SIGSTATUS is
+   a vector describing the status of the signatures; its first element
+   gives the number of following elements.  */
+gpg_error_t
+keybox_insert_keyblock (KEYBOX_HANDLE hd, const void *image, size_t imagelen,
+                        u32 *sigstatus)
+{
+  gpg_error_t err;
+  const char *fname;
+  KEYBOXBLOB blob;
+  size_t nparsed;
+  struct _keybox_openpgp_info info;
+
+  if (!hd)
+    return gpg_error (GPG_ERR_INV_HANDLE);
+  if (!hd->kb)
+    return gpg_error (GPG_ERR_INV_HANDLE);
+  fname = hd->kb->fname;
+  if (!fname)
+    return gpg_error (GPG_ERR_INV_HANDLE);
+
+
+  /* Close this one otherwise we will mess up the position for a next
+     search.  Fixme: it would be better to adjust the position after
+     the write operation.  */
+  _keybox_close_file (hd);
+
+  err = _keybox_parse_openpgp (image, imagelen, &nparsed, &info);
+  if (err)
+    return err;
+  assert (nparsed <= imagelen);
+  err = _keybox_create_openpgp_blob (&blob, &info, image, imagelen,
+                                     sigstatus, hd->ephemeral);
+  _keybox_destroy_openpgp_info (&info);
+  if (!err)
+    {
+      err = blob_filecopy (1, fname, blob, hd->secret, 0);
+      _keybox_release_blob (blob);
+      /*    if (!rc && !hd->secret && kb_offtbl) */
+      /*      { */
+      /*        update_offset_hash_table_from_kb (kb_offtbl, kb, 0); */
+      /*      } */
+    }
+  return err;
+}
+
+
+/* Update the current key at HD with the given OpenPGP keyblock in
+   {IMAGE,IMAGELEN}.  */
+gpg_error_t
+keybox_update_keyblock (KEYBOX_HANDLE hd, const void *image, size_t imagelen)
+{
+  (void)hd;
+  (void)image;
+  (void)imagelen;
+  return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+}
+
+
 
 #ifdef KEYBOX_WITH_X509
 int
index 52bbe21..4f7e23d 100644 (file)
@@ -1,5 +1,5 @@
 /* keybox.h - Keybox operations
- *     Copyright (C) 2001, 2003 Free Software Foundation, Inc.
+ * Copyright (C) 2001, 2003, 2012 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -26,6 +26,7 @@ extern "C" {
 #endif
 #endif
 
+#include "../common/iobuf.h"
 #include "keybox-search-desc.h"
 
 #define KEYBOX_WITH_OPENPGP 1
@@ -53,7 +54,8 @@ typedef enum
     KEYBOX_FLAG_UID,        /* The user ID flags; requires an uid index. */
     KEYBOX_FLAG_UID_VALIDITY,/* The validity of a specific uid, requires
                                an uid index. */
-    KEYBOX_FLAG_CREATED_AT  /* The date the block was created. */
+    KEYBOX_FLAG_CREATED_AT, /* The date the block was created. */
+    KEYBOX_FLAG_SIG_INFO,   /* The signature info block.  */
   } keybox_flag_t;
 
 /* Flag values used with KEYBOX_FLAG_BLOB.  */
@@ -71,8 +73,16 @@ void keybox_release (KEYBOX_HANDLE hd);
 const char *keybox_get_resource_name (KEYBOX_HANDLE hd);
 int keybox_set_ephemeral (KEYBOX_HANDLE hd, int yes);
 
+int keybox_lock (KEYBOX_HANDLE hd, int yes);
+
+/*-- keybox-file.c --*/
+/* Fixme: This function does not belong here: Provide a better
+   interface to create a new keybox file.  */
+int _keybox_write_header_blob (FILE *fp);
 
 /*-- keybox-search.c --*/
+gpg_error_t keybox_get_keyblock (KEYBOX_HANDLE hd, iobuf_t *r_iobuf,
+                                 int *r_uid_no, int *r_pk_no, u32 **sigstatus);
 #ifdef KEYBOX_WITH_X509
 int keybox_get_cert (KEYBOX_HANDLE hd, ksba_cert_t *ret_cert);
 #endif /*KEYBOX_WITH_X509*/
@@ -83,6 +93,12 @@ int keybox_search (KEYBOX_HANDLE hd, KEYBOX_SEARCH_DESC *desc, size_t ndesc);
 
 
 /*-- keybox-update.c --*/
+gpg_error_t keybox_insert_keyblock (KEYBOX_HANDLE hd,
+                                    const void *image, size_t imagelen,
+                                    u32 *sigstatus);
+gpg_error_t keybox_update_keyblock (KEYBOX_HANDLE hd,
+                                    const void *image, size_t imagelen);
+
 #ifdef KEYBOX_WITH_X509
 int keybox_insert_cert (KEYBOX_HANDLE hd, ksba_cert_t cert,
                         unsigned char *sha1_digest);
@@ -98,8 +114,6 @@ int keybox_compress (KEYBOX_HANDLE hd);
 /*--  --*/
 
 #if 0
-int keybox_lock (KEYBOX_HANDLE hd, int yes);
-int keybox_get_keyblock (KEYBOX_HANDLE hd, KBNODE *ret_kb);
 int keybox_locate_writable (KEYBOX_HANDLE hd);
 int keybox_search_reset (KEYBOX_HANDLE hd);
 int keybox_search (KEYBOX_HANDLE hd, KEYDB_SEARCH_DESC *desc, size_t ndesc);