From 2ca90f78cee91c43b8d538d1cb92728f8e1452d5 Mon Sep 17 00:00:00 2001
From: Werner Koch <wk@gnupg.org>
Date: Thu, 9 Oct 2014 21:01:49 +0200
Subject: [PATCH] gpg: Skip overlong keys and a print a warning.

* kbx/keybox-search.c (keybox_search): Add arg r_skipped and skip too
long blobs.
* sm/keydb.c (keydb_search): Call keybox_search with a dummy param.
* g10/keydb.c (struct keydb_handle): Add field skipped_long_blobs.
(keydb_search_reset): Reset that field.
(keydb_search): Update that field.
(keydb_get_skipped_counter): New.
* g10/keylist.c (list_all): Print count of skipped keys.

Signed-off-by: Werner Koch <wk@gnupg.org>
---
 g10/keydb.c         | 11 ++++++++++-
 g10/keydb.h         |  1 +
 g10/keylist.c       |  3 +++
 kbx/keybox-search.c | 13 +++++++++++--
 kbx/keybox.h        |  2 +-
 sm/keydb.c          |  4 +++-
 6 files changed, 29 insertions(+), 5 deletions(-)

diff --git a/g10/keydb.c b/g10/keydb.c
index a38795120..a9a975378 100644
--- a/g10/keydb.c
+++ b/g10/keydb.c
@@ -67,6 +67,7 @@ struct keydb_handle
 {
   int locked;
   int found;
+  unsigned long skipped_long_blobs;
   int current;
   int used;   /* Number of items in ACTIVE. */
   struct resource_item active[MAX_KEYDB_RESOURCES];
@@ -1289,6 +1290,13 @@ keydb_rebuild_caches (int noisy)
 }
 
 
+/* Return the number of skipped blocks since the last search reset.  */
+unsigned long
+keydb_get_skipped_counter (KEYDB_HANDLE hd)
+{
+  return hd ? hd->skipped_long_blobs : 0;
+}
+
 
 /*
  * Start the next search on this handle right at the beginning
@@ -1307,6 +1315,7 @@ keydb_search_reset (KEYDB_HANDLE hd)
   if (DBG_CLOCK)
     log_clock ("keydb_search_reset");
 
+  hd->skipped_long_blobs = 0;
   hd->current = 0;
   hd->found = -1;
   /* Now reset all resources.  */
@@ -1424,7 +1433,7 @@ keydb_search (KEYDB_HANDLE hd, KEYDB_SEARCH_DESC *desc,
           break;
         case KEYDB_RESOURCE_TYPE_KEYBOX:
           rc = keybox_search (hd->active[hd->current].u.kb, desc,
-                              ndesc, descindex);
+                              ndesc, descindex, &hd->skipped_long_blobs);
           break;
         }
       if (rc == -1 || gpg_err_code (rc) == GPG_ERR_EOF)
diff --git a/g10/keydb.h b/g10/keydb.h
index 23d0bcc26..78d151a51 100644
--- a/g10/keydb.h
+++ b/g10/keydb.h
@@ -142,6 +142,7 @@ gpg_error_t keydb_insert_keyblock (KEYDB_HANDLE hd, kbnode_t kb);
 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);
+unsigned long keydb_get_skipped_counter (KEYDB_HANDLE hd);
 gpg_error_t keydb_search_reset (KEYDB_HANDLE hd);
 gpg_error_t keydb_search (KEYDB_HANDLE hd, KEYDB_SEARCH_DESC *desc,
                           size_t ndesc, size_t *descindex);
diff --git a/g10/keylist.c b/g10/keylist.c
index 4a028205a..b5ea84d1c 100644
--- a/g10/keylist.c
+++ b/g10/keylist.c
@@ -499,6 +499,9 @@ list_all (int secret, int mark_secret)
   es_fflush (es_stdout);
   if (rc && gpg_err_code (rc) != GPG_ERR_NOT_FOUND)
     log_error ("keydb_search_next failed: %s\n", g10_errstr (rc));
+  if (keydb_get_skipped_counter (hd))
+    log_info (_("Warning: %lu key(s) skipped due to their large size\n"),
+              keydb_get_skipped_counter (hd));
 
   if (opt.check_sigs && !opt.with_colons)
     print_signature_stats (&stats);
diff --git a/kbx/keybox-search.c b/kbx/keybox-search.c
index ba284f9b5..bf47042a3 100644
--- a/kbx/keybox-search.c
+++ b/kbx/keybox-search.c
@@ -718,10 +718,12 @@ keybox_search_reset (KEYBOX_HANDLE hd)
 
 
 /* Note: When in ephemeral mode the search function does visit all
-   blobs but in standard mode, blobs flagged as ephemeral are ignored.  */
+   blobs but in standard mode, blobs flagged as ephemeral are ignored.
+   The value at R_SKIPPED is updated by the number of skipped long
+   records (counts PGP and X.509). */
 int
 keybox_search (KEYBOX_HANDLE hd, KEYBOX_SEARCH_DESC *desc, size_t ndesc,
-               size_t *r_descindex)
+               size_t *r_descindex, unsigned long *r_skipped)
 {
   int rc;
   size_t n;
@@ -852,6 +854,13 @@ keybox_search (KEYBOX_HANDLE hd, KEYBOX_SEARCH_DESC *desc, size_t ndesc,
 
       _keybox_release_blob (blob); blob = NULL;
       rc = _keybox_read_blob (&blob, hd->fp);
+      if (gpg_err_code (rc) == GPG_ERR_TOO_LARGE
+          && gpg_err_source (rc) == GPG_ERR_SOURCE_KEYBOX)
+        {
+          ++*r_skipped;
+          continue; /* Skip too large records.  */
+        }
+
       if (rc)
         break;
 
diff --git a/kbx/keybox.h b/kbx/keybox.h
index 9067fb8a4..b44f1b2ba 100644
--- a/kbx/keybox.h
+++ b/kbx/keybox.h
@@ -87,7 +87,7 @@ int keybox_get_flags (KEYBOX_HANDLE hd, int what, int idx, unsigned int *value);
 
 int keybox_search_reset (KEYBOX_HANDLE hd);
 int keybox_search (KEYBOX_HANDLE hd, KEYBOX_SEARCH_DESC *desc, size_t ndesc,
-                   size_t *r_descindex);
+                   size_t *r_descindex, unsigned long *r_skipped);
 
 
 /*-- keybox-update.c --*/
diff --git a/sm/keydb.c b/sm/keydb.c
index fb0947a93..83e573f28 100644
--- a/sm/keydb.c
+++ b/sm/keydb.c
@@ -958,6 +958,7 @@ int
 keydb_search (KEYDB_HANDLE hd, KEYDB_SEARCH_DESC *desc, size_t ndesc)
 {
   int rc = -1;
+  unsigned long skipped;
 
   if (!hd)
     return gpg_error (GPG_ERR_INV_VALUE);
@@ -970,7 +971,8 @@ keydb_search (KEYDB_HANDLE hd, KEYDB_SEARCH_DESC *desc, size_t ndesc)
           BUG(); /* we should never see it here */
           break;
         case KEYDB_RESOURCE_TYPE_KEYBOX:
-          rc = keybox_search (hd->active[hd->current].u.kr, desc, ndesc, NULL);
+          rc = keybox_search (hd->active[hd->current].u.kr, desc, ndesc,
+                              NULL, &skipped);
           break;
         }
       if (rc == -1) /* EOF -> switch to next resource */