[git] GnuPG - branch, key-storage-work, created. gnupg-2.1.0beta3-125-g79f08fb

by Werner Koch cvs at cvs.gnupg.org
Fri Dec 28 17:24:38 CET 2012


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "The GNU Privacy Guard".

The branch, key-storage-work has been created
        at  79f08fb0699f4a065e3a29bc7676a90534d7ba60 (commit)

- Log -----------------------------------------------------------------
commit 79f08fb0699f4a065e3a29bc7676a90534d7ba60
Author: Werner Koch <wk at gnupg.org>
Date:   Fri Dec 28 17:17:56 2012 +0100

    gpg: Add signature cache support to the keybox.
    
    * g10/keydb.c (parse_keyblock_image): Add arg SIGSTATUS.
    (keydb_get_keyblock): Handle it.
    (build_keyblock_image): Add arg SIGSTATUS.
    (keydb_insert_keyblock): Handle it.
    * kbx/keybox-blob.c (pgp_create_sig_part): Add arg SIGSTATUS.
    (_keybox_create_openpgp_blob): Ditto.
    * kbx/kbxutil.c (import_openpgp): Adjust for above change.
    * kbx/keybox.h (KEYBOX_FLAG_SIG_INFO): New.
    * kbx/keybox-search.c (_keybox_get_flag_location): Handle new flag.
    (keybox_get_keyblock): Add arg R_SIGSTATUS.
    * kbx/keybox-update.c (keybox_insert_keyblock): Add arg SIGSTATUS.
    --
    
    With this change a key listing using the keybox format is now double
    as fast as using a keyring.  The memory use dropped as well.  Measured
    with about 1500 keys.

diff --git a/g10/keydb.c b/g10/keydb.c
index acd7f8a..dff58cc 100644
--- a/g10/keydb.c
+++ b/g10/keydb.c
@@ -617,13 +617,14 @@ unlock_all (KEYDB_HANDLE hd)
 
 
 static gpg_error_t
-parse_keyblock_image (iobuf_t iobuf, kbnode_t *r_keyblock)
+parse_keyblock_image (iobuf_t iobuf, const u32 *sigstatus, kbnode_t *r_keyblock)
 {
   gpg_error_t err;
   PACKET *pkt;
   kbnode_t keyblock = NULL;
-  kbnode_t node;
+  kbnode_t node, *tail;
   int in_cert, save_mode;
+  u32 n_sigs;
 
   *r_keyblock = NULL;
 
@@ -633,6 +634,8 @@ parse_keyblock_image (iobuf_t iobuf, kbnode_t *r_keyblock)
   init_packet (pkt);
   save_mode = set_packet_list_mode (0);
   in_cert = 0;
+  n_sigs = 0;
+  tail = NULL;
   while ((err = parse_packet (iobuf, pkt)) != -1)
     {
       if (gpg_err_code (err) == GPG_ERR_UNKNOWN_PACKET)
@@ -665,25 +668,57 @@ parse_keyblock_image (iobuf_t iobuf, kbnode_t *r_keyblock)
 
       if (!in_cert && pkt->pkttype != PKT_PUBLIC_KEY)
         {
-          log_error ("error: first packet in a keybox blob is not a "
-                     "public key packet\n");
+          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 ("error: multiple keyblocks in a keybox blob\n");
+          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);
       if (!keyblock)
         keyblock = node;
       else
-        add_kbnode (keyblock, node);
+        *tail = node;
+      tail = &node->next;
       pkt = xtrymalloc (sizeof *pkt);
       if (!pkt)
         {
@@ -697,6 +732,12 @@ parse_keyblock_image (iobuf_t iobuf, kbnode_t *r_keyblock)
   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
@@ -737,11 +778,14 @@ keydb_get_keyblock (KEYDB_HANDLE hd, KBNODE *ret_kb)
     case KEYDB_RESOURCE_TYPE_KEYBOX:
       {
         iobuf_t iobuf;
+        u32 *sigstatus;
 
-        err = keybox_get_keyblock (hd->active[hd->found].u.kb, &iobuf);
+        err = keybox_get_keyblock (hd->active[hd->found].u.kb,
+                                   &iobuf, &sigstatus);
         if (!err)
           {
-            err = parse_keyblock_image (iobuf, ret_kb);
+            err = parse_keyblock_image (iobuf, sigstatus, ret_kb);
+            xfree (sigstatus);
             iobuf_close (iobuf);
           }
       }
@@ -753,18 +797,33 @@ keydb_get_keyblock (KEYDB_HANDLE hd, KBNODE *ret_kb)
 
 
 /* Build a keyblock image from KEYBLOCK.  Returns 0 on success and
-   only then stores a new iobuf object at R_IOBUF.  */
+   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)
+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; (node = walk_kbnode (keyblock, &kbctx, 0)); )
+  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)
@@ -787,9 +846,34 @@ build_keyblock_image (kbnode_t keyblock, iobuf_t *r_iobuf)
           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;
 }
 
@@ -876,13 +960,16 @@ keydb_insert_keyblock (KEYDB_HANDLE hd, kbnode_t kb)
            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);
+        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));
+                                          iobuf_get_temp_length (iobuf),
+                                          sigstatus);
+            xfree (sigstatus);
             iobuf_close (iobuf);
           }
       }
diff --git a/kbx/kbxutil.c b/kbx/kbxutil.c
index cd9d120..8b2b900 100644
--- a/kbx/kbxutil.c
+++ b/kbx/kbxutil.c
@@ -411,7 +411,8 @@ import_openpgp (const char *filename, int dryrun)
             dump_openpgp_key (&info, p);
           else
             {
-              err = _keybox_create_openpgp_blob (&blob, &info, p, nparsed, 0);
+              err = _keybox_create_openpgp_blob (&blob, &info, p, nparsed,
+                                                 NULL, 0);
               if (err)
                 {
                   fflush (stdout);
diff --git a/kbx/keybox-blob.c b/kbx/keybox-blob.c
index c4a8982..855deaf 100644
--- a/kbx/keybox-blob.c
+++ b/kbx/keybox-blob.c
@@ -408,13 +408,13 @@ pgp_create_uid_part (KEYBOXBLOB blob, keybox_openpgp_info_t info)
 
 
 static void
-pgp_create_sig_part (KEYBOXBLOB blob)
+pgp_create_sig_part (KEYBOXBLOB blob, u32 *sigstatus)
 {
   int n;
 
   for (n=0; n < blob->nsigs; n++)
     {
-      blob->sigs[n] = 0;  /* FIXME: check the signature here */
+      blob->sigs[n] = sigstatus? sigstatus[n+1] : 0;
     }
 }
 
@@ -658,12 +658,14 @@ create_blob_finish (KEYBOXBLOB blob)
   return 0;
 }
 
+
 
 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)
 {
   gpg_error_t err;
@@ -674,6 +676,11 @@ _keybox_create_openpgp_blob (KEYBOXBLOB *r_blob,
   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 ();
@@ -704,7 +711,7 @@ _keybox_create_openpgp_blob (KEYBOXBLOB *r_blob,
   if (err)
     goto leave;
   pgp_create_uid_part (blob, info);
-  pgp_create_sig_part (blob);
+  pgp_create_sig_part (blob, sigstatus);
 
   init_membuf (&blob->bufbuf, 1024);
   blob->buf = &blob->bufbuf;
diff --git a/kbx/keybox-defs.h b/kbx/keybox-defs.h
index 8fdc54d..ad8e49d 100644
--- a/kbx/keybox-defs.h
+++ b/kbx/keybox-defs.h
@@ -160,6 +160,7 @@ 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,
diff --git a/kbx/keybox-search.c b/kbx/keybox-search.c
index 1e36be9..d683e14 100644
--- a/kbx/keybox-search.c
+++ b/kbx/keybox-search.c
@@ -102,7 +102,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 +116,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 +141,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 +160,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;
         }
@@ -961,15 +967,20 @@ keybox_search (KEYBOX_HANDLE hd, KEYBOX_SEARCH_DESC *desc, size_t ndesc)
 
 
 /* Return the last found keyblock.  Returns 0 on success and stores a
-   new iobuf at R_IOBUF in that case.  */
+   new iobuf at R_IOBUF and a signature status vector at R_SIGSTATUS
+   in that case.  */
 gpg_error_t
-keybox_get_keyblock (KEYBOX_HANDLE hd, iobuf_t *r_iobuf)
+keybox_get_keyblock (KEYBOX_HANDLE hd, iobuf_t *r_iobuf, u32 **r_sigstatus)
 {
-  const unsigned char *buffer;
+  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);
@@ -987,6 +998,21 @@ keybox_get_keyblock (KEYBOX_HANDLE hd, iobuf_t *r_iobuf)
   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_sigstatus = sigstatus;
   *r_iobuf = iobuf_temp_with_content (buffer+image_off, image_len);
   return 0;
 }
diff --git a/kbx/keybox-update.c b/kbx/keybox-update.c
index a4eedeb..6428bb2 100644
--- a/kbx/keybox-update.c
+++ b/kbx/keybox-update.c
@@ -371,9 +371,12 @@ blob_filecopy (int mode, const char *fname, KEYBOXBLOB blob,
 }
 
 
-/* Insert the OpenPGP keyblock {IMAGE,IMAGELEN} into HD.  */
+/* 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)
+keybox_insert_keyblock (KEYBOX_HANDLE hd, const void *image, size_t imagelen,
+                        u32 *sigstatus)
 {
   gpg_error_t err;
   const char *fname;
@@ -400,7 +403,7 @@ keybox_insert_keyblock (KEYBOX_HANDLE hd, const void *image, size_t imagelen)
     return err;
   assert (nparsed <= imagelen);
   err = _keybox_create_openpgp_blob (&blob, &info, image, imagelen,
-                                     hd->ephemeral);
+                                     sigstatus, hd->ephemeral);
   _keybox_destroy_openpgp_info (&info);
   if (!err)
     {
diff --git a/kbx/keybox.h b/kbx/keybox.h
index 15f05ed..03a9245 100644
--- a/kbx/keybox.h
+++ b/kbx/keybox.h
@@ -54,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.  */
@@ -80,7 +81,8 @@ int keybox_lock (KEYBOX_HANDLE hd, int yes);
 int _keybox_write_header_blob (FILE *fp);
 
 /*-- keybox-search.c --*/
-gpg_error_t keybox_get_keyblock (KEYBOX_HANDLE hd, iobuf_t *r_iobuf);
+gpg_error_t keybox_get_keyblock (KEYBOX_HANDLE hd,
+                                 iobuf_t *r_iobuf, u32 **sigstatus);
 #ifdef KEYBOX_WITH_X509
 int keybox_get_cert (KEYBOX_HANDLE hd, ksba_cert_t *ret_cert);
 #endif /*KEYBOX_WITH_X509*/
@@ -92,7 +94,8 @@ 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);
+                                    const void *image, size_t imagelen,
+                                    u32 *sigstatus);
 gpg_error_t keybox_update_keyblock (KEYBOX_HANDLE hd,
                                     const void *image, size_t imagelen);
 

commit 564d10ea5cd29685a00a4096d69ae2476b60506f
Author: Werner Koch <wk at gnupg.org>
Date:   Fri Dec 28 17:07:37 2012 +0100

    kbxutil: Improve format of the Sig-Expire lines.
    
    * kbx/keybox-dump.c (_keybox_dump_blob): Print the expirate timestamp.

diff --git a/kbx/keybox-dump.c b/kbx/keybox-dump.c
index ab31085..b603814 100644
--- a/kbx/keybox-dump.c
+++ b/kbx/keybox-dump.c
@@ -324,9 +324,9 @@ _keybox_dump_blob (KEYBOXBLOB blob, FILE *fp)
         else if (sflags < 0x10000000)
           fprintf (fp, "[bad flag %0lx]", sflags);
         else if (sflags == 0xffffffff)
-          fputs ("0", fp );
+          fputs ("[good - does not expire]", fp );
         else
-          fputs ("a time"/*strtimestamp( sflags )*/, fp );
+          fprintf (fp, "[good - expires at %lu]", sflags);
         putc ('\n', fp );
       }
     if (in_range)

commit a9863834244fc2a58d8950977243702d12e420a1
Author: Werner Koch <wk at gnupg.org>
Date:   Fri Dec 28 14:03:16 2012 +0100

    gpg: First working support for keyboxes.
    
    * g10/getkey.c (get_pubkey_fast): Improve the assertion.
    * kbx/keybox.h: Include iobuf.h.
    * kbx/keybox-blob.c (keyboxblob_uid): Add field OFF.
    (KEYBOX_WITH_OPENPGP): Remove use of this macro.
    (pgp_create_key_part_single): New.
    (pgp_temp_store_kid): Change to use the keybox-openpgp parser.
    (pgp_create_key_part): Ditto.
    (pgp_create_uid_part): Ditto.
    (pgp_create_sig_part): Ditto.
    (pgp_create_blob_keyblock): Ditto.
    (_keybox_create_openpgp_blob): Ditto.
    * kbx/keybox-search.c (keybox_get_keyblock): New.
    * kbx/keybox-update.c (keybox_insert_keyblock): New.
    * g10/keydb.c (parse_keyblock_image):
    (keydb_get_keyblock): Support keybox.
    (build_keyblock_image): New.
    (keydb_insert_keyblock): Support keybox.
    
    * kbx/kbxutil.c (import_openpgp, main): Add option --dry-run and print
    a kbx file to stdout.
    
    * kbx/keybox-file.c (_keybox_read_blob2): Allow keyblocks up to 10^6
    bytes.
    --
    
    Import and key listing does now work with the keybox format.  It is
    still quite slow and signature caching is completely missing.
    
    Increasing the maximum allowed length for a keyblock was required due
    to a 700k keyblock which inhibited kbxutil to list the file.
    kbxutil's option name --import-openpgp is not quite appropriate
    because it only creates KBX blobs from OpenPGP data.

diff --git a/g10/getkey.c b/g10/getkey.c
index 9294273..002a2be 100644
--- a/g10/getkey.c
+++ b/g10/getkey.c
@@ -444,8 +444,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])
diff --git a/g10/keydb.c b/g10/keydb.c
index ab727b6..acd7f8a 100644
--- a/g10/keydb.c
+++ b/g10/keydb.c
@@ -616,6 +616,97 @@ unlock_all (KEYDB_HANDLE hd)
 }
 
 
+static gpg_error_t
+parse_keyblock_image (iobuf_t iobuf, kbnode_t *r_keyblock)
+{
+  gpg_error_t err;
+  PACKET *pkt;
+  kbnode_t keyblock = NULL;
+  kbnode_t node;
+  int in_cert, save_mode;
+
+  *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;
+  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 ("error: 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 ("error: multiple keyblocks in a keybox blob\n");
+          err = gpg_error (GPG_ERR_INV_KEYRING);
+          break;
+        }
+      in_cert = 1;
+
+      node = new_kbnode (pkt);
+      if (!keyblock)
+        keyblock = node;
+      else
+        add_kbnode (keyblock, node);
+      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)
+    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
@@ -627,6 +718,8 @@ 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);
 
@@ -641,16 +734,66 @@ 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: */
-    /*   err = keybox_get_keyblock (hd->active[hd->found].u.kb, ret_kb); */
-    /*   if (!err) */
-    /*     err = parse_keyblock (image, imagelen) */
-    /*   break; */
+    case KEYDB_RESOURCE_TYPE_KEYBOX:
+      {
+        iobuf_t iobuf;
+
+        err = keybox_get_keyblock (hd->active[hd->found].u.kb, &iobuf);
+        if (!err)
+          {
+            err = parse_keyblock_image (iobuf, ret_kb);
+            iobuf_close (iobuf);
+          }
+      }
+      break;
     }
 
   return err;
 }
 
+
+/* Build a keyblock image from KEYBLOCK.  Returns 0 on success and
+   only then stores a new iobuf object at R_IOBUF.  */
+static gpg_error_t
+build_keyblock_image (kbnode_t keyblock, iobuf_t *r_iobuf)
+{
+  gpg_error_t err;
+  iobuf_t iobuf;
+  kbnode_t kbctx, node;
+
+  *r_iobuf = NULL;
+
+  iobuf = iobuf_temp ();
+  for (kbctx = NULL; (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;
+        }
+    }
+
+  *r_iobuf = iobuf;
+  return 0;
+}
+
+
 /*
  * Update the current keyblock with the keyblock KB
  */
@@ -699,7 +842,7 @@ 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)
@@ -715,27 +858,39 @@ 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;
+
+        err = build_keyblock_image (kb, &iobuf);
+        if (!err)
+          {
+            err = keybox_insert_keyblock (hd->active[idx].u.kb,
+                                          iobuf_get_temp_buffer (iobuf),
+                                          iobuf_get_temp_length (iobuf));
+            iobuf_close (iobuf);
+          }
+      }
       break;
-    /* case KEYDB_RESOURCE_TYPE_KEYBOX: */
-    /*   rc = build_keyblock (kb, &image, &imagelen); */
-    /*   if (!rc) */
-    /*     rc = keybox_insert_keyblock (hd->active[idx].u.kb, image, imagelen); */
-    /*   break; */
     }
 
   unlock_all (hd);
-  return rc;
+  return err;
 }
 
 
diff --git a/kbx/kbxutil.c b/kbx/kbxutil.c
index fee5570..cd9d120 100644
--- a/kbx/kbxutil.c
+++ b/kbx/kbxutil.c
@@ -371,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)
@@ -406,7 +407,30 @@ 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, 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;
@@ -424,6 +448,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);
@@ -481,6 +506,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;
@@ -537,11 +564,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
diff --git a/kbx/keybox-blob.c b/kbx/keybox-blob.c
index 998a770..c4a8982 100644
--- a/kbx/keybox-blob.c
+++ b/kbx/keybox-blob.c
@@ -47,7 +47,7 @@ X.509 specific are noted like [X.509: xxx]
  byte Blob type (2) [X509: 3]
  byte version number of this blob type (1)
  u16  Blob flags
-	bit 0 = contains secret key material
+	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 X509 DER encoded certificate
@@ -119,9 +119,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 +153,7 @@ struct keyboxblob_key {
   u16    flags;
 };
 struct keyboxblob_uid {
+  u32    off;
   ulong  off_addr;
   char   *name;     /* used only with x509 */
   u32    len;
@@ -311,33 +309,24 @@ add_fixup (KEYBOXBLOB blob, u32 off, u32 val)
 
 
 
-#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 +336,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)
 {
-  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] = 0;  /* FIXME: check the signature here */
     }
-  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*/
 
 
 #ifdef KEYBOX_WITH_X509
@@ -686,87 +659,78 @@ create_blob_finish (KEYBOXBLOB blob)
 }
 
 
-#ifdef KEYBOX_WITH_OPENPGP
-
-int
-_keybox_create_pgp_blob (KEYBOXBLOB *r_blob, KBNODE keyblock, int as_ephemeral)
+gpg_error_t
+_keybox_create_openpgp_blob (KEYBOXBLOB *r_blob,
+                             keybox_openpgp_info_t info,
+                             const unsigned char *image,
+                             size_t imagelen,
+                             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);
+
   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);
 
   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
 
diff --git a/kbx/keybox-defs.h b/kbx/keybox-defs.h
index c588016..8fdc54d 100644
--- a/kbx/keybox-defs.h
+++ b/kbx/keybox-defs.h
@@ -156,9 +156,11 @@ 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,
+                                         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);
diff --git a/kbx/keybox-file.c b/kbx/keybox-file.c
index ecfdfbe..027bcf8 100644
--- a/kbx/keybox-file.c
+++ b/kbx/keybox-file.c
@@ -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)
diff --git a/kbx/keybox-search.c b/kbx/keybox-search.c
index ef5cd95..1e36be9 100644
--- a/kbx/keybox-search.c
+++ b/kbx/keybox-search.c
@@ -1,5 +1,5 @@
 /* keybox-search.c - Search operations
- * Copyright (C) 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+ * Copyright (C) 2001, 2002, 2003, 2004, 2012 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -958,6 +958,40 @@ 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 in that case.  */
+gpg_error_t
+keybox_get_keyblock (KEYBOX_HANDLE hd, iobuf_t *r_iobuf)
+{
+  const unsigned char *buffer;
+  size_t length;
+  size_t image_off, image_len;
+
+  *r_iobuf = 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);
+
+  *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.
diff --git a/kbx/keybox-update.c b/kbx/keybox-update.c
index 0d052c9..a4eedeb 100644
--- a/kbx/keybox-update.c
+++ b/kbx/keybox-update.c
@@ -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,62 @@ blob_filecopy (int mode, const char *fname, KEYBOXBLOB blob,
 }
 
 
+/* Insert the OpenPGP keyblock {IMAGE,IMAGELEN} into HD.  */
+gpg_error_t
+keybox_insert_keyblock (KEYBOX_HANDLE hd, const void *image, size_t imagelen)
+{
+  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,
+                                     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
diff --git a/kbx/keybox.h b/kbx/keybox.h
index 52c1638..15f05ed 100644
--- a/kbx/keybox.h
+++ b/kbx/keybox.h
@@ -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
@@ -79,6 +80,7 @@ int keybox_lock (KEYBOX_HANDLE hd, int yes);
 int _keybox_write_header_blob (FILE *fp);
 
 /*-- keybox-search.c --*/
+gpg_error_t keybox_get_keyblock (KEYBOX_HANDLE hd, iobuf_t *r_iobuf);
 #ifdef KEYBOX_WITH_X509
 int keybox_get_cert (KEYBOX_HANDLE hd, ksba_cert_t *ret_cert);
 #endif /*KEYBOX_WITH_X509*/
@@ -89,6 +91,11 @@ 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);
+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);

commit f7495f1004071a0ceac394007bb37f88d7a3467f
Author: Werner Koch <wk at gnupg.org>
Date:   Fri Dec 28 13:45:41 2012 +0100

    kbxutil: Print algo number and fold similar lines.
    
    * kbx/keybox-defs.h (_keybox_openpgp_key_info): Add field ALGO.
    * kbx/keybox-openpgp.c (parse_key): Store algo.
    * kbx/kbxutil.c (dump_openpgp_key): Print algo number.
    * kbx/keybox-dump.c (_keybox_dump_blob): Print identical Sig-Expire
    value lines with a range of indices.

diff --git a/kbx/kbxutil.c b/kbx/kbxutil.c
index 62e3dbe..fee5570 100644
--- a/kbx/kbxutil.c
+++ b/kbx/kbxutil.c
@@ -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);
diff --git a/kbx/keybox-defs.h b/kbx/keybox-defs.h
index 890e4dd..c588016 100644
--- a/kbx/keybox-defs.h
+++ b/kbx/keybox-defs.h
@@ -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];
diff --git a/kbx/keybox-dump.c b/kbx/keybox-dump.c
index c5f518e..ab31085 100644
--- a/kbx/keybox-dump.c
+++ b/kbx/keybox-dump.c
@@ -291,27 +291,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 ("0", fp );
+        else
+          fputs ("a time"/*strtimestamp( sflags )*/, fp );
+        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;
diff --git a/kbx/keybox-openpgp.c b/kbx/keybox-openpgp.c
index 37e2771..82bc934 100644
--- a/kbx/keybox-openpgp.c
+++ b/kbx/keybox-openpgp.c
@@ -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;

commit 91e61d52539b1808e209c43e51465c76cebb06f9
Author: Werner Koch <wk at gnupg.org>
Date:   Thu Dec 27 15:04:29 2012 +0100

    gpg: First patches to support a keybox storage backend.
    
    * kbx/keybox-defs.h (_keybox_write_header_blob): Move prototype to ..
    * kbx/keybox.h: here.
    * kbx/keybox-init.c (keybox_lock): Add dummy function
    * g10/keydb.c: Include keybox.h.
    (KeydbResourceType): Add KEYDB_RESOURCE_TYPE_KEYBOX.
    (struct resource_item): Add field kb.
    (maybe_create_keyring_or_box): Add error descriptions to diagnostics.
    Add arg IS_BOX.  Write a header for a new keybox file.
    (keydb_add_resource): No more need for the force flag.  Rename the
    local variable "force" to "create".  Add URL scheme "gnupg-kbx".  Add
    magic test to detect a keybox file.  Add basic support for keybox.
    (keydb_new, keydb_get_resource_name, keydb_delete_keyblock)
    (keydb_locate_writable, keydb_search_reset, keydb_search2): Add
    support for keybox.
    (lock_all, unlock_all): Ditto.
    * g10/Makefile.am (needed_libs): Add libkeybox.a.
    (gpg2_LDADD, gpgv2_LDADD): Add KSBA_LIBS as a workaround.
    
    * g10/keydb.h (KEYDB_RESOURCE_FLAG_PRIMARY)
    KEYDB_RESOURCE_FLAG_DEFAULT, KEYDB_RESOURCE_FLAG_READONLY): New.
    * g10/gpg.c, g10/gpgv.c (main): Use new constants.
    --
    
    I did most of these changes back in 2011 and only cleaned them up
    now.  More to follow soon.

diff --git a/g10/Makefile.am b/g10/Makefile.am
index e9f69b3..899677c 100644
--- a/g10/Makefile.am
+++ b/g10/Makefile.am
@@ -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)
 
diff --git a/g10/gpg.c b/g10/gpg.c
index b614a94..5773d5e 100644
--- a/g10/gpg.c
+++ b/g10/gpg.c
@@ -2249,8 +2249,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",
@@ -3398,11 +3398,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. */
@@ -3410,7 +3406,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);
       }
diff --git a/g10/gpgv.c b/g10/gpgv.c
index 07e4a2e..5cb9c55 100644
--- a/g10/gpgv.c
+++ b/g10/gpgv.c
@@ -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);
 
diff --git a/g10/keydb.c b/g10/keydb.c
index 75c036c..ab727b6 100644
--- a/g10/keydb.c
+++ b/g10/keydb.c
@@ -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;
 };
@@ -73,12 +76,12 @@ 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. */
+/* 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 +142,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 +185,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 +243,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 +298,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 +307,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 +336,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 +346,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 +359,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;
 }
@@ -371,6 +447,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 +486,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 +528,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 +543,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 +559,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 +577,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,6 +607,9 @@ 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;
@@ -532,6 +641,11 @@ 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: */
+    /*   err = keybox_get_keyblock (hd->active[hd->found].u.kb, ret_kb); */
+    /*   if (!err) */
+    /*     err = parse_keyblock (image, imagelen) */
+    /*   break; */
     }
 
   return err;
@@ -566,6 +680,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);
@@ -607,6 +727,11 @@ keydb_insert_keyblock (KEYDB_HANDLE hd, kbnode_t kb)
     case KEYDB_RESOURCE_TYPE_KEYRING:
       rc = keyring_insert_keyblock (hd->active[idx].u.kr, kb);
       break;
+    /* case KEYDB_RESOURCE_TYPE_KEYBOX: */
+    /*   rc = build_keyblock (kb, &image, &imagelen); */
+    /*   if (!rc) */
+    /*     rc = keybox_insert_keyblock (hd->active[idx].u.kb, image, imagelen); */
+    /*   break; */
     }
 
   unlock_all (hd);
@@ -643,6 +768,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 +828,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;
         }
     }
 
@@ -758,6 +890,9 @@ 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;
@@ -792,6 +927,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)
         {
diff --git a/g10/keydb.h b/g10/keydb.h
index 22c2b67..3ba9573 100644
--- a/g10/keydb.h
+++ b/g10/keydb.h
@@ -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);
diff --git a/kbx/keybox-defs.h b/kbx/keybox-defs.h
index ee48ca3..890e4dd 100644
--- a/kbx/keybox-defs.h
+++ b/kbx/keybox-defs.h
@@ -182,7 +182,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,
diff --git a/kbx/keybox-init.c b/kbx/keybox-init.c
index 60594e3..d329941 100644
--- a/kbx/keybox-init.c
+++ b/kbx/keybox-init.c
@@ -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;
+}
diff --git a/kbx/keybox.h b/kbx/keybox.h
index 52bbe21..52c1638 100644
--- a/kbx/keybox.h
+++ b/kbx/keybox.h
@@ -71,6 +71,12 @@ 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 --*/
 #ifdef KEYBOX_WITH_X509
@@ -98,7 +104,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);

-----------------------------------------------------------------------


hooks/post-receive
-- 
The GNU Privacy Guard
http://git.gnupg.org




More information about the Gnupg-commits mailing list