aboutsummaryrefslogtreecommitdiffstats
path: root/g10
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--g10/Makefile.am11
-rw-r--r--g10/delkey.c2
-rw-r--r--g10/export.c2
-rw-r--r--g10/getkey.c35
-rw-r--r--g10/gpg.c22
-rw-r--r--g10/gpgv.c7
-rw-r--r--g10/kbnode.c59
-rw-r--r--g10/keydb.c705
-rw-r--r--g10/keydb.h16
-rw-r--r--g10/keyserver.c2
-rw-r--r--g10/options.h2
-rw-r--r--g10/pubkey-enc.c10
-rw-r--r--g10/revoke.c4
-rw-r--r--g10/trustdb.c5
14 files changed, 748 insertions, 134 deletions
diff --git a/g10/Makefile.am b/g10/Makefile.am
index e9f69b34d..899677cc3 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/delkey.c b/g10/delkey.c
index 950af0ee0..22f2219e5 100644
--- a/g10/delkey.c
+++ b/g10/delkey.c
@@ -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" );
diff --git a/g10/export.c b/g10/export.c
index d8d9c05c2..7fbcb346b 100644
--- a/g10/export.c
+++ b/g10/export.c
@@ -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];
diff --git a/g10/getkey.c b/g10/getkey.c
index 8cc560100..4453a92d5 100644
--- a/g10/getkey.c
+++ b/g10/getkey.c
@@ -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])
@@ -2456,7 +2471,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.
@@ -2881,7 +2896,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);
diff --git a/g10/gpg.c b/g10/gpg.c
index 9adc21abc..a19c9a76a 100644
--- 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);
diff --git a/g10/gpgv.c b/g10/gpgv.c
index 07e4a2e37..5cb9c55b5 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/kbnode.c b/g10/kbnode.c
index 1a8b91e43..d4907408b 100644
--- a/g10/kbnode.c
+++ b/g10/kbnode.c
@@ -31,35 +31,58 @@
#define USE_UNUSED_NODES 1
+static int cleanup_registered;
static KBNODE unused_nodes;
-static KBNODE
-alloc_node(void)
+#if USE_UNUSED_NODES
+static void
+release_unused_nodes (void)
{
- KBNODE n;
+ while (unused_nodes)
+ {
+ kbnode_t next = unused_nodes->next;
+ xfree (unused_nodes);
+ unused_nodes = next;
+ }
+}
+#endif /*USE_UNUSED_NODES*/
- n = unused_nodes;
- if( n )
- unused_nodes = n->next;
- else
- n = xmalloc( sizeof *n );
- n->next = NULL;
- n->pkt = NULL;
- n->flag = 0;
- n->private_flag=0;
- n->recno = 0;
- return n;
+
+static kbnode_t
+alloc_node (void)
+{
+ kbnode_t n;
+
+ n = unused_nodes;
+ if (n)
+ unused_nodes = n->next;
+ else
+ {
+ if (!cleanup_registered)
+ {
+ cleanup_registered = 1;
+ register_mem_cleanup_func (release_unused_nodes);
+ }
+ n = xmalloc (sizeof *n);
+ }
+ n->next = NULL;
+ n->pkt = NULL;
+ n->flag = 0;
+ n->private_flag=0;
+ n->recno = 0;
+ return n;
}
static void
free_node( KBNODE n )
{
- if( n ) {
+ if (n)
+ {
#if USE_UNUSED_NODES
- n->next = unused_nodes;
- unused_nodes = n;
+ n->next = unused_nodes;
+ unused_nodes = n;
#else
- xfree( n );
+ xfree (n);
#endif
}
}
diff --git a/g10/keydb.c b/g10/keydb.c
index 75c036cf5..79ab5afc6 100644
--- a/g10/keydb.c
+++ b/g10/keydb.c
@@ -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);
}
diff --git a/g10/keydb.h b/g10/keydb.h
index fd80c2525..39e7826a9 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);
@@ -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);
diff --git a/g10/keyserver.c b/g10/keyserver.c
index 0be1e3fd5..0ec616bc0 100644
--- a/g10/keyserver.c
+++ b/g10/keyserver.c
@@ -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;
diff --git a/g10/options.h b/g10/options.h
index 223b11510..d44d7a14b 100644
--- a/g10/options.h
+++ b/g10/options.h
@@ -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
diff --git a/g10/pubkey-enc.c b/g10/pubkey-enc.c
index a98a7238b..a328e1adc 100644
--- a/g10/pubkey-enc.c
+++ b/g10/pubkey-enc.c
@@ -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);
diff --git a/g10/revoke.c b/g10/revoke.c
index 396b6d475..6e47691d9 100644
--- a/g10/revoke.c
+++ b/g10/revoke.c
@@ -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"),
diff --git a/g10/trustdb.c b/g10/trustdb.c
index 6b228d209..24ed9dffa 100644
--- a/g10/trustdb.c
+++ b/g10/trustdb.c
@@ -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));