kbx: Fix handling of overlong keys.
authorWerner Koch <wk@gnupg.org>
Thu, 9 Oct 2014 18:19:05 +0000 (20:19 +0200)
committerWerner Koch <wk@gnupg.org>
Thu, 9 Oct 2014 18:19:05 +0000 (20:19 +0200)
* kbx/keybox-file.c (IMAGELEN_LIMIT): Change limit from 10^6 to 2MiB.
(_keybox_read_blob2): Skip too long record records.
(_keybox_write_blob): Do not accept too long record.
* kbx/keybox-dump.c (file_stats_s): Add field skipped_long_blobs.
(_keybox_dump_file): Print new counter.
(_keybox_dump_file): Skip too long records.
----

To test this feature you may set the limit back to 1MiB and use key
F7F0E70F307D56ED which is in my local copy close to 2MiB.  Without
this patch it was possible to import the key but access to that key
and all keys stored after it was not possible.

Signed-off-by: Werner Koch <wk@gnupg.org>
kbx/keybox-dump.c
kbx/keybox-file.c

index bfe7b48..dfa8200 100644 (file)
@@ -491,6 +491,7 @@ struct file_stats_s
   unsigned long non_flagged;
   unsigned long secret_flagged;
   unsigned long ephemeral_flagged;
+  unsigned long skipped_long_blobs;
 };
 
 static int
@@ -594,8 +595,25 @@ _keybox_dump_file (const char *filename, int stats_only, FILE *outfp)
   if (!(fp = open_file (&filename, outfp)))
     return gpg_error_from_syserror ();
 
-  while ( !(rc = _keybox_read_blob (&blob, fp)) )
+  for (;;)
     {
+      rc = _keybox_read_blob (&blob, fp);
+      if (gpg_err_code (rc) == GPG_ERR_TOO_LARGE
+          && gpg_err_source (rc) == GPG_ERR_SOURCE_KEYBOX)
+        {
+          if (stats_only)
+            stats.skipped_long_blobs++;
+          else
+            {
+              fprintf (outfp, "BEGIN-RECORD: %lu\n", count );
+              fprintf (outfp, "# Record too large\nEND-RECORD\n");
+            }
+          count++;
+          continue;
+        }
+      if (rc)
+        break;
+
       if (stats_only)
         {
           update_stats (blob, &stats);
@@ -612,7 +630,7 @@ _keybox_dump_file (const char *filename, int stats_only, FILE *outfp)
   if (rc == -1)
     rc = 0;
   if (rc)
-    fprintf (outfp, "error reading '%s': %s\n", filename, gpg_strerror (rc));
+    fprintf (outfp, "error reading '%s': %s\n", filename, gpg_strerror (rc));
 
   if (fp != stdin)
     fclose (fp);
@@ -636,14 +654,17 @@ _keybox_dump_file (const char *filename, int stats_only, FILE *outfp)
                stats.non_flagged,
                stats.secret_flagged,
                stats.ephemeral_flagged);
+        if (stats.skipped_long_blobs)
+          fprintf (outfp, "   skipped long blobs: %8lu\n",
+                   stats.skipped_long_blobs);
         if (stats.unknown_blob_count)
           fprintf (outfp, "   unknown blob types: %8lu\n",
                    stats.unknown_blob_count);
         if (stats.too_short_blobs)
-          fprintf (outfp, "      too short blobs: %8lu\n",
+          fprintf (outfp, "      too short blobs: %8lu (error)\n",
                    stats.too_short_blobs);
         if (stats.too_large_blobs)
-          fprintf (outfp, "      too large blobs: %8lu\n",
+          fprintf (outfp, "      too large blobs: %8lu (error)\n",
                    stats.too_large_blobs);
     }
 
index def896b..1ed5169 100644 (file)
@@ -27,6 +27,9 @@
 #include "keybox-defs.h"
 
 
+#define IMAGELEN_LIMIT (2*1024*1024)
+
+
 #if !defined(HAVE_FTELLO) && !defined(ftello)
 static off_t
 ftello (FILE *stream)
@@ -75,9 +78,6 @@ _keybox_read_blob2 (KEYBOXBLOB *r_blob, FILE *fp, int *skipped_deleted)
     }
 
   imagelen = (c1 << 24) | (c2 << 16) | (c3 << 8 ) | c4;
-  if (imagelen > 1000000) /* Sanity check. */
-    return gpg_error (GPG_ERR_TOO_LARGE);
-
   if (imagelen < 5)
     return gpg_error (GPG_ERR_TOO_SHORT);
 
@@ -90,6 +90,15 @@ _keybox_read_blob2 (KEYBOXBLOB *r_blob, FILE *fp, int *skipped_deleted)
       goto again;
     }
 
+  if (imagelen > IMAGELEN_LIMIT) /* Sanity check. */
+    {
+      /* Seek forward so that the caller may choose to ignore this
+         record.  */
+      if (fseek (fp, imagelen-5, SEEK_CUR))
+        return gpg_error_from_syserror ();
+      return gpg_error (GPG_ERR_TOO_LARGE);
+    }
+
   image = xtrymalloc (imagelen);
   if (!image)
     return gpg_error_from_syserror ();
@@ -124,6 +133,10 @@ _keybox_write_blob (KEYBOXBLOB blob, FILE *fp)
   size_t length;
 
   image = _keybox_get_blob_image (blob, &length);
+
+  if (length > IMAGELEN_LIMIT)
+    return gpg_error (GPG_ERR_TOO_LARGE);
+
   if (fwrite (image, length, 1, fp) != 1)
     return gpg_error_from_syserror ();
   return 0;