diff options
-rw-r--r-- | .gitignore | 3 | ||||
-rw-r--r-- | common/init.c | 47 | ||||
-rw-r--r-- | common/init.h | 2 | ||||
-rw-r--r-- | common/iobuf.c | 5 | ||||
-rw-r--r-- | common/logging.c | 27 | ||||
-rw-r--r-- | common/logging.h | 2 | ||||
-rw-r--r-- | g10/Makefile.am | 11 | ||||
-rw-r--r-- | g10/delkey.c | 2 | ||||
-rw-r--r-- | g10/export.c | 2 | ||||
-rw-r--r-- | g10/getkey.c | 35 | ||||
-rw-r--r-- | g10/gpg.c | 22 | ||||
-rw-r--r-- | g10/gpgv.c | 7 | ||||
-rw-r--r-- | g10/kbnode.c | 59 | ||||
-rw-r--r-- | g10/keydb.c | 705 | ||||
-rw-r--r-- | g10/keydb.h | 16 | ||||
-rw-r--r-- | g10/keyserver.c | 2 | ||||
-rw-r--r-- | g10/options.h | 2 | ||||
-rw-r--r-- | g10/pubkey-enc.c | 10 | ||||
-rw-r--r-- | g10/revoke.c | 4 | ||||
-rw-r--r-- | g10/trustdb.c | 5 | ||||
-rw-r--r-- | kbx/kbxutil.c | 42 | ||||
-rw-r--r-- | kbx/keybox-blob.c | 481 | ||||
-rw-r--r-- | kbx/keybox-defs.h | 11 | ||||
-rw-r--r-- | kbx/keybox-dump.c | 136 | ||||
-rw-r--r-- | kbx/keybox-file.c | 2 | ||||
-rw-r--r-- | kbx/keybox-init.c | 17 | ||||
-rw-r--r-- | kbx/keybox-openpgp.c | 2 | ||||
-rw-r--r-- | kbx/keybox-search.c | 171 | ||||
-rw-r--r-- | kbx/keybox-update.c | 62 | ||||
-rw-r--r-- | kbx/keybox.h | 28 | ||||
-rw-r--r-- | po/de.po | 123 | ||||
-rw-r--r-- | po/fr.po | 126 |
32 files changed, 1613 insertions, 556 deletions
diff --git a/.gitignore b/.gitignore index b75b40416..6502072e7 100644 --- a/.gitignore +++ b/.gitignore @@ -154,6 +154,5 @@ tools/mk-tdata tools/symcryptrun tools/watchgnupg tools/gpgtar - - +private-keys-v1.d/ x.parm diff --git a/common/init.c b/common/init.c index e00b9b308..8a0b6a8e7 100644 --- a/common/init.c +++ b/common/init.c @@ -46,6 +46,21 @@ #include "util.h" +/* This object is used to register memory cleanup functions. + Technically they are not needed but they can avoid frequent + questions about un-released memory. Note that we use the system + malloc and not any wrappers. */ +struct mem_cleanup_item_s; +typedef struct mem_cleanup_item_s *mem_cleanup_item_t; + +struct mem_cleanup_item_s +{ + mem_cleanup_item_t next; + void (*func) (void); +}; + +static mem_cleanup_item_t mem_cleanup_list; + /* The default error source of the application. This is different from GPG_ERR_SOURCE_DEFAULT in that it does not depend on the @@ -65,6 +80,36 @@ sleep_on_exit (void) #endif /*HAVE_W32CE_SYSTEM*/ +static void +run_mem_cleanup (void) +{ + mem_cleanup_item_t next; + + while (mem_cleanup_list) + { + next = mem_cleanup_list->next; + mem_cleanup_list->func (); + free (mem_cleanup_list); + mem_cleanup_list = next; + } +} + + +void +register_mem_cleanup_func (void (*func)(void)) +{ + mem_cleanup_item_t item; + + item = malloc (sizeof *item); + if (item) + { + item->func = func; + item->next = mem_cleanup_list; + mem_cleanup_list = item; + } +} + + /* If STRING is not NULL write string to es_stdout or es_stderr. MODE must be 1 or 2. If STRING is NULL flush the respective stream. */ static int @@ -100,6 +145,8 @@ _init_common_subsystems (gpg_err_source_t errsource, int *argcp, char ***argvp) /* Store the error source in a gloabl variable. */ default_errsource = errsource; + atexit (run_mem_cleanup); + /* Try to auto set the character set. */ set_native_charset (NULL); diff --git a/common/init.h b/common/init.h index 633ffac52..eea2eb167 100644 --- a/common/init.h +++ b/common/init.h @@ -36,6 +36,8 @@ # error GPG_ERR_SOURCE_DEFAULT has default value #endif +void register_mem_cleanup_func (void (*func)(void)); + void _init_common_subsystems (gpg_err_source_t errsource, int *argcp, char ***argvp); #define init_common_subsystems(a,b) \ diff --git a/common/iobuf.c b/common/iobuf.c index 3ba3582d0..a3058303d 100644 --- a/common/iobuf.c +++ b/common/iobuf.c @@ -2311,7 +2311,7 @@ iobuf_seek (iobuf_t a, off_t newpos) } clearerr (fp); } - else + else if (a->use != 3) /* Not a temp stream. */ { for (; a; a = a->chain) { @@ -2338,7 +2338,8 @@ iobuf_seek (iobuf_t a, off_t newpos) } #endif } - a->d.len = 0; /* discard buffer */ + if (a->use != 3) + a->d.len = 0; /* Discard the buffer unless it is a temp stream. */ a->d.start = 0; a->nbytes = 0; a->nlimit = 0; diff --git a/common/logging.c b/common/logging.c index f91671e79..cdfd6597c 100644 --- a/common/logging.c +++ b/common/logging.c @@ -857,6 +857,33 @@ log_printhex (const char *text, const void *buffer, size_t length) } +void +log_clock (const char *string) +{ +#if 0 + static unsigned long long initial; + struct timespec tv; + unsigned long long now; + + if (clock_gettime (CLOCK_REALTIME, &tv)) + { + log_debug ("error getting the realtime clock value\n"); + return; + } + now = tv.tv_sec * 1000000000ull; + now += tv.tv_nsec; + + if (!initial) + initial = now; + + log_debug ("[%6llu] %s", (now - initial)/1000, string); +#else + /* You need to link with -ltr to enable the above code. */ + log_debug ("[not enabled in the source] %s", string); +#endif +} + + #if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 5 ) void bug_at( const char *file, int line, const char *func ) diff --git a/common/logging.h b/common/logging.h index b0d662b71..89913e6e5 100644 --- a/common/logging.h +++ b/common/logging.h @@ -96,5 +96,7 @@ void log_flush (void); by the hexdump and a final LF. */ void log_printhex (const char *text, const void *buffer, size_t length); +void log_clock (const char *string); + #endif /*LIBJNLIB_LOGGING_H*/ 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); @@ -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)); diff --git a/kbx/kbxutil.c b/kbx/kbxutil.c index 62e3dbe89..8b2b9000d 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); @@ -369,13 +371,14 @@ dump_openpgp_key (keybox_openpgp_info_t info, const unsigned char *image) static void -import_openpgp (const char *filename) +import_openpgp (const char *filename, int dryrun) { gpg_error_t err; char *buffer; size_t buflen, nparsed; unsigned char *p; struct _keybox_openpgp_info info; + KEYBOXBLOB blob; buffer = read_file (filename, &buflen); if (!buffer) @@ -404,7 +407,31 @@ import_openpgp (const char *filename) } else { - dump_openpgp_key (&info, p); + if (dryrun) + dump_openpgp_key (&info, p); + else + { + err = _keybox_create_openpgp_blob (&blob, &info, p, nparsed, + NULL, 0); + if (err) + { + fflush (stdout); + log_error ("%s: failed to create OpenPGP keyblock: %s\n", + filename, gpg_strerror (err)); + } + else + { + err = _keybox_write_blob (blob, stdout); + _keybox_release_blob (blob); + if (err) + { + fflush (stdout); + log_error ("%s: failed to write OpenPGP keyblock: %s\n", + filename, gpg_strerror (err)); + } + } + } + _keybox_destroy_openpgp_info (&info); } p += nparsed; @@ -422,6 +449,7 @@ main( int argc, char **argv ) ARGPARSE_ARGS pargs; enum cmd_and_opt_values cmd = 0; unsigned long from = 0, to = ULONG_MAX; + int dry_run = 0; set_strusage( my_strusage ); gcry_control (GCRYCTL_DISABLE_SECMEM); @@ -479,6 +507,8 @@ main( int argc, char **argv ) case oFrom: from = pargs.r.ret_ulong; break; case oTo: to = pargs.r.ret_ulong; break; + case oDryRun: dry_run = 1; break; + default: pargs.err = 2; break; @@ -535,11 +565,11 @@ main( int argc, char **argv ) else if (cmd == aImportOpenPGP) { if (!argc) - import_openpgp ("-"); + import_openpgp ("-", dry_run); else { for (; argc; argc--, argv++) - import_openpgp (*argv); + import_openpgp (*argv, dry_run); } } #if 0 diff --git a/kbx/keybox-blob.c b/kbx/keybox-blob.c index 998a77019..64935275e 100644 --- a/kbx/keybox-blob.c +++ b/kbx/keybox-blob.c @@ -17,93 +17,119 @@ * along with this program; if not, see <http://www.gnu.org/licenses/>. */ +/* +* The keybox data format + + The KeyBox uses an augmented OpenPGP/X.509 key format. This makes + random access to a keyblock/certificate easier and also gives the + opportunity to store additional information (e.g. the fingerprint) + along with the key. All integers are stored in network byte order, + offsets are counted from the beginning of the Blob. + +** Overview of blob types + + | Byte 4 | Blob type | + |--------+--------------| + | 0 | Empty blob | + | 1 | First blob | + | 2 | OpenPGP blob | + | 3 | X.509 blob | + +** The First blob + + The first blob of a plain KBX file has a special format: + + - u32 Length of this blob + - byte Blob type (1) + - byte Version number (1) + - byte RFU + - byte RFU + - b4 Magic 'KBXf' + - u32 RFU + - u32 file_created_at + - u32 last_maintenance_run + - u32 RFU + - u32 RFU + +** The OpenPGP and X.509 blobs + + The OpenPGP and X.509 blobs are very similiar, things which are + X.509 specific are noted like [X.509: xxx] + + - u32 Length of this blob (including these 4 bytes) + - byte Blob type + 2 = OpenPGP + 3 = X509 + - byte Version number of this blob type + 1 = The only defined value + - u16 Blob flags + bit 0 = contains secret key material (not used) + bit 1 = ephemeral blob (e.g. used while quering external resources) + - u32 Offset to the OpenPGP keyblock or the X.509 DER encoded + certificate + - u32 The length of the keyblock or certificate + - u16 [NKEYS] Number of keys (at least 1!) [X509: always 1] + - u16 Size of the key information structure (at least 28). + - NKEYS times: + - b20 The fingerprint of the key. + Fingerprints are always 20 bytes, MD5 left padded with zeroes. + - u32 Offset to the n-th key's keyID (a keyID is always 8 byte) + or 0 if not known which is the case only for X.509. + - u16 Key flags + bit 0 = qualified signature (not yet implemented} + - u16 RFU + - bN Optional filler up to the specified length of this + structure. + - u16 Size of the serial number (may be zero) + - bN The serial number. N as giiven above. + - u16 Number of user IDs + - u16 [NUIDS] Size of user ID information structure + - NUIDS times: + + For X509, the first user ID is the Issuer, the second the + Subject and the others are subjectAltNames. For OpenPGP we only + store the information from UserID packets here. + + - u32 Blob offset to the n-th user ID + - u32 Length of this user ID. + - u16 User ID flags. + (not yet used) + - byte Validity + - byte RFU + + - u16 [NSIGS] Number of signatures + - u16 Size of signature information (4) + - NSIGS times: + - u32 Expiration time of signature with some special values: + - 0x00000000 = not checked + - 0x00000001 = missing key + - 0x00000002 = bad signature + - 0x10000000 = valid and expires at some date in 1978. + - 0xffffffff = valid and does not expire + - u8 Assigned ownertrust [X509: not used] + - u8 All_Validity + OpenPGP: See ../g10/trustdb/TRUST_* [not yet used] + X509: Bit 4 set := key has been revoked. + Note that this value matches TRUST_FLAG_REVOKED + - u16 RFU + - u32 Recheck_after + - u32 Latest timestamp in the keyblock (useful for KS syncronsiation?) + - u32 Blob created at + - u32 [NRES] Size of reserved space (not including this field) + - bN Reserved space of size NRES for future use. + - bN Arbitrary space for example used to store data which is not + part of the keyblock or certificate. For example the v3 key + IDs go here. + - bN Space for the keyblock or certifciate. + - bN RFU + - b20 SHA-1 checksum (useful for KS syncronisation?) + Note, that KBX versions before GnuPG 2.1 used an MD5 + checksum. However it was only created but never checked. + Thus we do not expect problems if we switch to SHA-1. If + the checksum fails and the first 4 bytes are zero, we can + try again with MD5. SHA-1 has the advantage that it is + faster on CPUs with dedicated SHA-1 support. -/* The keybox data formats - -The KeyBox uses an augmented OpenPGP/X.509 key format. This makes -random access to a keyblock/certificate easier and also gives the -opportunity to store additional information (e.g. the fingerprint) -along with the key. All integers are stored in network byte order, -offsets are counted from the beginning of the Blob. - -The first record of a plain KBX file has a special format: - - u32 length of the first record - byte Blob type (1) - byte version number (1) - byte reserved - byte reserved - u32 magic 'KBXf' - u32 reserved - u32 file_created_at - u32 last_maintenance_run - u32 reserved - u32 reserved - -The OpenPGP and X.509 blob are very similiar, things which are -X.509 specific are noted like [X.509: xxx] - - u32 length of this blob (including these 4 bytes) - byte Blob type (2) [X509: 3] - byte version number of this blob type (1) - u16 Blob flags - bit 0 = contains secret key material - bit 1 = ephemeral blob (e.g. used while quering external resources) - - u32 offset to the OpenPGP keyblock or X509 DER encoded certificate - u32 and its length - u16 number of keys (at least 1!) [X509: always 1] - u16 size of additional key information - n times: - b20 The keys fingerprint - (fingerprints are always 20 bytes, MD5 left padded with zeroes) - u32 offset to the n-th key's keyID (a keyID is always 8 byte) - or 0 if not known which is the case only for X509. - u16 special key flags - bit 0 = qualified signature (not yet implemented} - u16 reserved - u16 size of serialnumber(may be zero) - n u16 (see above) bytes of serial number - u16 number of user IDs - u16 size of additional user ID information - n times: - u32 offset to the n-th user ID - u32 length of this user ID. - u16 special user ID flags. - bit 0 = - byte validity - byte reserved - [For X509, the first user ID is the Issuer, the second the Subject - and the others are subjectAltNames] - u16 number of signatures - u16 size of signature information (4) - u32 expiration time of signature with some special values: - 0x00000000 = not checked - 0x00000001 = missing key - 0x00000002 = bad signature - 0x10000000 = valid and expires at some date in 1978. - 0xffffffff = valid and does not expire - u8 assigned ownertrust [X509: not used] - u8 all_validity - OpenPGP: see ../g10/trustdb/TRUST_* [not yet used] - X509: Bit 4 set := key has been revoked. Note that this value - matches TRUST_FLAG_REVOKED - u16 reserved - u32 recheck_after - u32 Newest timestamp in the keyblock (useful for KS syncronsiation?) - u32 Blob created at - u32 size of reserved space (not including this field) - reserved space - - Here we might want to put other data - - Here comes the keyblock - - maybe we put a signature here later. - - b16 MD5 checksum (useful for KS syncronisation), we might also want to use - a mac here. - b4 reserved */ @@ -119,9 +145,6 @@ X.509 specific are noted like [X.509: xxx] #include "keybox-defs.h" #include <gcrypt.h> -#ifdef KEYBOX_WITH_OPENPGP -/* include stuff to parse the packets */ -#endif #ifdef KEYBOX_WITH_X509 #include <ksba.h> #endif @@ -156,6 +179,7 @@ struct keyboxblob_key { u16 flags; }; struct keyboxblob_uid { + u32 off; ulong off_addr; char *name; /* used only with x509 */ u32 len; @@ -237,7 +261,10 @@ put_membuf (struct membuf *mb, const void *buf, size_t len) } mb->buf = p; } - memcpy (mb->buf + mb->len, buf, len); + if (buf) + memcpy (mb->buf + mb->len, buf, len); + else + memset (mb->buf + mb->len, 0, len); mb->len += len; } @@ -287,6 +314,7 @@ put32 (struct membuf *mb, u32 a ) put_membuf (mb, tmp, 4); } + /* Store a value in the fixup list */ static void @@ -311,33 +339,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 +366,108 @@ pgp_temp_store_kid (KEYBOXBLOB blob, PKT_public_key *pk) return k->seqno; } -static int -pgp_create_key_part (KEYBOXBLOB blob, KBNODE keyblock) + +/* Helper for pgp_create_key_part. */ +static gpg_error_t +pgp_create_key_part_single (KEYBOXBLOB blob, int n, + struct _keybox_openpgp_key_info *kinfo) { - KBNODE node; size_t fprlen; - int n; + int off; - for (n=0, node = keyblock; node; node = node->next) + fprlen = kinfo->fprlen; + if (fprlen > 20) + fprlen = 20; + memcpy (blob->keys[n].fpr, kinfo->fpr, fprlen); + if (fprlen != 20) /* v3 fpr - shift right and fill with zeroes. */ { - if ( node->pkt->pkttype == PKT_PUBLIC_KEY - || node->pkt->pkttype == PKT_PUBLIC_SUBKEY ) - { - PKT_public_key *pk = node->pkt->pkt.public_key; - char tmp[20]; - - fingerprint_from_pk (pk, tmp , &fprlen); - memcpy (blob->keys[n].fpr, tmp, 20); - if ( fprlen != 20 ) /*v3 fpr - shift right and fill with zeroes*/ - { - assert (fprlen == 16); - memmove (blob->keys[n].fpr+4, blob->keys[n].fpr, 16); - memset (blob->keys[n].fpr, 0, 4); - blob->keys[n].off_kid = pgp_temp_store_kid (blob, pk); - } - else - { - blob->keys[n].off_kid = 0; /* will be fixed up later */ - } - blob->keys[n].flags = 0; - n++; - } - else if ( node->pkt->pkttype == PKT_SECRET_KEY - || node->pkt->pkttype == PKT_SECRET_SUBKEY ) - { - never_reached (); /* actually not yet implemented */ - } + memmove (blob->keys[n].fpr + 20 - fprlen, blob->keys[n].fpr, fprlen); + memset (blob->keys[n].fpr, 0, 20 - fprlen); + off = pgp_temp_store_kid (blob, kinfo); + if (off == -1) + return gpg_error_from_syserror (); + blob->keys[n].off_kid = off; } + else + blob->keys[n].off_kid = 0; /* Will be fixed up later */ + blob->keys[n].flags = 0; + return 0; +} + + +static gpg_error_t +pgp_create_key_part (KEYBOXBLOB blob, keybox_openpgp_info_t info) +{ + gpg_error_t err; + int n = 0; + struct _keybox_openpgp_key_info *kinfo; + + err = pgp_create_key_part_single (blob, n++, &info->primary); + if (err) + return err; + if (info->nsubkeys) + for (kinfo = &info->subkeys; kinfo; kinfo = kinfo->next) + if ((err=pgp_create_key_part_single (blob, n++, kinfo))) + return err; + assert (n == blob->nkeys); return 0; } -static int -pgp_create_uid_part (KEYBOXBLOB blob, KBNODE keyblock) + +static void +pgp_create_uid_part (KEYBOXBLOB blob, keybox_openpgp_info_t info) { - KBNODE node; - int n; + int n = 0; + struct _keybox_openpgp_uid_info *u; - for (n=0, node = keyblock; node; node = node->next) + if (info->nuids) { - if (node->pkt->pkttype == PKT_USER_ID) + for (u = &info->uids; u; u = u->next) { - PKT_user_id *u = node->pkt->pkt.user_id; - + blob->uids[n].off = u->off; blob->uids[n].len = u->len; blob->uids[n].flags = 0; blob->uids[n].validity = 0; n++; - } + } } + assert (n == blob->nuids); - return 0; } -static int -pgp_create_sig_part (KEYBOXBLOB blob, KBNODE keyblock) + +static void +pgp_create_sig_part (KEYBOXBLOB blob, u32 *sigstatus) { - KBNODE node; int n; - for (n=0, node = keyblock; node; node = node->next) + for (n=0; n < blob->nsigs; n++) { - if (node->pkt->pkttype == PKT_SIGNATURE) - { - PKT_signature *sig = node->pkt->pkt.signature; - - blob->sigs[n] = 0; /* FIXME: check the signature here */ - n++; - } + blob->sigs[n] = sigstatus? sigstatus[n+1] : 0; } - assert( n == blob->nsigs ); - return 0; } + static int -pgp_create_blob_keyblock (KEYBOXBLOB blob, KBNODE keyblock) +pgp_create_blob_keyblock (KEYBOXBLOB blob, + const unsigned char *image, size_t imagelen) { struct membuf *a = blob->buf; - KBNODE node; - int rc; int n; u32 kbstart = a->len; - add_fixup (blob, kbstart); + add_fixup (blob, 8, kbstart); - for (n = 0, node = keyblock; node; node = node->next) - { - rc = build_packet ( a, node->pkt ); - if ( rc ) { - gpg_log_error ("build_packet(%d) for keyboxblob failed: %s\n", - node->pkt->pkttype, gpg_errstr(rc) ); - return GPGERR_WRITE_FILE; - } - if ( node->pkt->pkttype == PKT_USER_ID ) - { - PKT_user_id *u = node->pkt->pkt.user_id; - /* build_packet has set the offset of the name into u ; - * now we can do the fixup */ - add_fixup (blob, blob->uids[n].off_addr, u->stored_at); - n++; - } - } - assert (n == blob->nuids); + for (n = 0; n < blob->nuids; n++) + add_fixup (blob, blob->uids[n].off_addr, kbstart + blob->uids[n].off); + + put_membuf (a, image, imagelen); - add_fixup (blob, a->len - kbstart); + add_fixup (blob, 12, a->len - kbstart); return 0; } -#endif /*KEYBOX_WITH_OPENPGP*/ #ifdef KEYBOX_WITH_X509 @@ -639,12 +642,10 @@ create_blob_finish (KEYBOXBLOB blob) struct membuf *a = blob->buf; unsigned char *p; unsigned char *pp; - int i; size_t n; - /* write a placeholder for the checksum */ - for (i = 0; i < 16; i++ ) - put32 (a, 0); /* Hmmm: why put32() ?? */ + /* Write a placeholder for the checksum */ + put_membuf (a, NULL, 20); /* get the memory area */ n = 0; /* (Just to avoid compiler warning.) */ @@ -672,8 +673,8 @@ create_blob_finish (KEYBOXBLOB blob) } } - /* calculate and store the MD5 checksum */ - gcry_md_hash_buffer (GCRY_MD_MD5, p + n - 16, p, n - 16); + /* Compute and store the SHA-1 checksum. */ + gcry_md_hash_buffer (GCRY_MD_SHA1, p + n - 20, p, n - 20); pp = xtrymalloc (n); if ( !pp ) @@ -685,88 +686,86 @@ create_blob_finish (KEYBOXBLOB blob) return 0; } - -#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, + u32 *sigstatus, + int as_ephemeral) { - int rc = 0; - KBNODE node; + gpg_error_t err; KEYBOXBLOB blob; *r_blob = NULL; + + if (!info->nuids || !info->nsigs) + return gpg_error (GPG_ERR_BAD_PUBKEY); + + /* If we have a signature status vector, check that the number of + elements matches the actual number of signatures. */ + if (sigstatus && sigstatus[0] != info->nsigs) + return gpg_error (GPG_ERR_INTERNAL); + blob = xtrycalloc (1, sizeof *blob); if (!blob) return gpg_error_from_syserror (); - /* fixme: Do some sanity checks on the keyblock */ - - /* count userids and keys so that we can allocate the arrays */ - for (node = keyblock; node; node = node->next) + blob->nkeys = 1 + info->nsubkeys; + blob->keys = xtrycalloc (blob->nkeys, sizeof *blob->keys ); + if (!blob->keys) { - switch (node->pkt->pkttype) - { - case PKT_PUBLIC_KEY: - case PKT_SECRET_KEY: - case PKT_PUBLIC_SUBKEY: - case PKT_SECRET_SUBKEY: blob->nkeys++; break; - case PKT_USER_ID: blob->nuids++; break; - case PKT_SIGNATURE: blob->nsigs++; break; - default: break; - } + err = gpg_error_from_syserror (); + goto leave; } - - blob->keys = xtrycalloc (blob->nkeys, sizeof *blob->keys ); + blob->nuids = info->nuids; blob->uids = xtrycalloc (blob->nuids, sizeof *blob->uids ); + if (!blob->uids) + { + err = gpg_error_from_syserror (); + goto leave; + } + blob->nsigs = info->nsigs; blob->sigs = xtrycalloc (blob->nsigs, sizeof *blob->sigs ); - if (!blob->keys || !blob->uids || !blob->sigs) + if (!blob->sigs) { - rc = gpg_error (GPG_ERR_ENOMEM); + err = gpg_error_from_syserror (); goto leave; } - rc = pgp_create_key_part ( blob, keyblock ); - if (rc) - goto leave; - rc = pgp_create_uid_part ( blob, keyblock ); - if (rc) - goto leave; - rc = pgp_create_sig_part ( blob, keyblock ); - if (rc) + err = pgp_create_key_part (blob, info); + if (err) goto leave; + pgp_create_uid_part (blob, info); + pgp_create_sig_part (blob, sigstatus); init_membuf (&blob->bufbuf, 1024); blob->buf = &blob->bufbuf; - rc = create_blob_header (blob, BLOBTYPE_OPENPGP, as_ephemeral); - if (rc) + err = create_blob_header (blob, BLOBTYPE_PGP, as_ephemeral); + if (err) goto leave; - rc = pgp_create_blob_keyblock (blob, keyblock); - if (rc) + err = pgp_create_blob_keyblock (blob, image, imagelen); + if (err) goto leave; - rc = create_blob_trailer (blob); - if (rc) + err = create_blob_trailer (blob); + if (err) goto leave; - rc = create_blob_finish ( blob ); - if (rc) + err = create_blob_finish (blob); + if (err) goto leave; - leave: release_kid_list (blob->temp_kids); blob->temp_kids = NULL; - if (rc) - { - keybox_release_blob (blob); - *r_blob = NULL; - } + if (err) + _keybox_release_blob (blob); else - { - *r_blob = blob; - } - return rc; + *r_blob = blob; + return err; } -#endif /*KEYBOX_WITH_OPENPGP*/ + #ifdef KEYBOX_WITH_X509 diff --git a/kbx/keybox-defs.h b/kbx/keybox-defs.h index ee48ca390..ad8e49d3f 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]; @@ -155,9 +156,12 @@ void _keybox_close_file (KEYBOX_HANDLE hd); /*-- keybox-blob.c --*/ -#ifdef KEYBOX_WITH_OPENPGP - /* fixme */ -#endif /*KEYBOX_WITH_OPENPGP*/ +gpg_error_t _keybox_create_openpgp_blob (KEYBOXBLOB *r_blob, + keybox_openpgp_info_t info, + const unsigned char *image, + size_t imagelen, + u32 *sigstatus, + int as_ephemeral); #ifdef KEYBOX_WITH_X509 int _keybox_create_x509_blob (KEYBOXBLOB *r_blob, ksba_cert_t cert, unsigned char *sha1_digest, int as_ephemeral); @@ -182,7 +186,6 @@ void _keybox_destroy_openpgp_info (keybox_openpgp_info_t info); int _keybox_read_blob (KEYBOXBLOB *r_blob, FILE *fp); int _keybox_read_blob2 (KEYBOXBLOB *r_blob, FILE *fp, int *skipped_deleted); int _keybox_write_blob (KEYBOXBLOB blob, FILE *fp); -int _keybox_write_header_blob (FILE *fp); /*-- keybox-search.c --*/ gpg_err_code_t _keybox_get_flag_location (const unsigned char *buffer, diff --git a/kbx/keybox-dump.c b/kbx/keybox-dump.c index c5f518e0f..c397f9c81 100644 --- a/kbx/keybox-dump.c +++ b/kbx/keybox-dump.c @@ -80,6 +80,57 @@ print_string (FILE *fp, const byte *p, size_t n, int delim) static int +print_checksum (const byte *buffer, size_t length, size_t unhashed, FILE *fp) +{ + const byte *p; + int i; + int hashlen; + unsigned char digest[20]; + + fprintf (fp, "Checksum: "); + if (unhashed && unhashed < 20) + { + fputs ("[specified unhashed sized too short]\n", fp); + return 0; + } + if (!unhashed) + { + unhashed = 16; + hashlen = 16; + } + else + hashlen = 20; + if (length < 5+unhashed) + { + fputs ("[blob too short for a checksum]\n", fp); + return 0; + } + + p = buffer + length - hashlen; + for (i=0; i < hashlen; p++, i++) + fprintf (fp, "%02x", *p); + + if (hashlen == 16) /* Compatibility method. */ + { + gcry_md_hash_buffer (GCRY_MD_MD5, digest, buffer, length - 16); + if (!memcmp (buffer + length - 16, digest, 16)) + fputs (" [valid]\n", fp); + else + fputs (" [bad]\n", fp); + } + else + { + gcry_md_hash_buffer (GCRY_MD_SHA1, digest, buffer, length - unhashed); + if (!memcmp (buffer + length - hashlen, digest, hashlen)) + fputs (" [valid]\n", fp); + else + fputs (" [bad]\n", fp); + } + return 0; +} + + +static int dump_header_blob (const byte *buffer, size_t length, FILE *fp) { unsigned long n; @@ -108,12 +159,13 @@ _keybox_dump_blob (KEYBOXBLOB blob, FILE *fp) { const byte *buffer; size_t length; - int type; + int type, i; ulong n, nkeys, keyinfolen; ulong nuids, uidinfolen; ulong nsigs, siginfolen; ulong rawdata_off, rawdata_len; ulong nserial; + ulong unhashed; const byte *p; buffer = _keybox_get_blob_image (blob, &length); @@ -189,8 +241,12 @@ _keybox_dump_blob (KEYBOXBLOB blob, FILE *fp) fprintf( fp, "Data-Offset: %lu\n", rawdata_off ); fprintf( fp, "Data-Length: %lu\n", rawdata_len ); if (rawdata_off > length || rawdata_len > length - || rawdata_off+rawdata_off > length) + || rawdata_off+rawdata_len > length + || rawdata_len + 4 > length + || rawdata_off+rawdata_len + 4 > length) fprintf (fp, "[Error: raw data larger than blob]\n"); + unhashed = get32 (buffer + rawdata_off + rawdata_len); + fprintf (fp, "Unhashed: %lu\n", unhashed); nkeys = get16 (buffer + 16); fprintf (fp, "Key-Count: %lu\n", nkeys ); @@ -205,7 +261,6 @@ _keybox_dump_blob (KEYBOXBLOB blob, FILE *fp) p = buffer + 20; for (n=0; n < nkeys; n++, p += keyinfolen) { - int i; ulong kidoff, kflags; fprintf (fp, "Key-Fpr[%lu]: ", n ); @@ -291,27 +346,50 @@ _keybox_dump_blob (KEYBOXBLOB blob, FILE *fp) fprintf (fp, "Sig-Info-Length: %lu\n", siginfolen ); /* fixme: check bounds */ p += 4; - for (n=0; n < nsigs; n++, p += siginfolen) - { - ulong sflags; - - sflags = get32 (p); - fprintf (fp, "Sig-Expire[%lu]: ", n ); - if (!sflags) - fputs ("[not checked]", fp); - else if (sflags == 1 ) - fputs ("[missing key]", fp); - else if (sflags == 2 ) - fputs ("[bad signature]", fp); - else if (sflags < 0x10000000) - fprintf (fp, "[bad flag %0lx]", sflags); - else if (sflags == 0xffffffff) - fputs ("0", fp ); - else - fputs ("a time"/*strtimestamp( sflags )*/, fp ); - putc ('\n', fp ); - } - + { + int in_range = 0; + ulong first = 0; + + for (n=0; n < nsigs; n++, p += siginfolen) + { + ulong sflags; + + sflags = get32 (p); + if (!in_range && !sflags) + { + in_range = 1; + first = n; + continue; + } + if (in_range && !sflags) + continue; + if (in_range) + { + fprintf (fp, "Sig-Expire[%lu-%lu]: [not checked]\n", first, n-1); + in_range = 0; + } + + fprintf (fp, "Sig-Expire[%lu]: ", n ); + if (!sflags) + fputs ("[not checked]", fp); + else if (sflags == 1 ) + fputs ("[missing key]", fp); + else if (sflags == 2 ) + fputs ("[bad signature]", fp); + else if (sflags < 0x10000000) + fprintf (fp, "[bad flag %0lx]", sflags); + else if (sflags == 0xffffffff) + fputs ("[good - does not expire]", fp ); + else + fprintf (fp, "[good - expires at %lu]", sflags); + putc ('\n', fp ); + } + if (in_range) + { + fprintf (fp, "Sig-Expire[%lu-%lu]: [not checked]\n", first, n-1); + in_range = 0; + } + } fprintf (fp, "Ownertrust: %d\n", p[0] ); fprintf (fp, "All-Validity: %d\n", p[1] ); p += 4; @@ -324,13 +402,17 @@ _keybox_dump_blob (KEYBOXBLOB blob, FILE *fp) n = get32 (p ); p += 4; fprintf (fp, "Reserved-Space: %lu\n", n ); - /* check that the keyblock is at the correct offset and other bounds */ - /*fprintf (fp, "Blob-Checksum: [MD5-hash]\n");*/ + if (unhashed >= 24) + { + n = get32 ( buffer + length - unhashed); + fprintf (fp, "Storage-Flags: %08lx\n", n ); + } + print_checksum (buffer, length, unhashed, fp); return 0; } -/* Compute the SHA_1 checksum of teh rawdata in BLOB and aput it into +/* Compute the SHA-1 checksum of the rawdata in BLOB and put it into DIGEST. */ static int hash_blob_rawdata (KEYBOXBLOB blob, unsigned char *digest) diff --git a/kbx/keybox-file.c b/kbx/keybox-file.c index ecfdfbe84..027bcf8d7 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-init.c b/kbx/keybox-init.c index 60594e313..d3299412a 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-openpgp.c b/kbx/keybox-openpgp.c index 37e2771a8..82bc93479 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; diff --git a/kbx/keybox-search.c b/kbx/keybox-search.c index ef5cd953e..5e6432fa6 100644 --- a/kbx/keybox-search.c +++ b/kbx/keybox-search.c @@ -1,5 +1,6 @@ /* keybox-search.c - Search operations - * Copyright (C) 2001, 2002, 2003, 2004 Free Software Foundation, Inc. + * Copyright (C) 2001, 2002, 2003, 2004, 2012, + * 2013 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -102,7 +103,7 @@ _keybox_get_flag_location (const unsigned char *buffer, size_t length, size_t nkeys, keyinfolen; size_t nuids, uidinfolen; size_t nserial; - size_t nsigs, siginfolen; + size_t nsigs, siginfolen, siginfooff; switch (what) { @@ -116,6 +117,7 @@ _keybox_get_flag_location (const unsigned char *buffer, size_t length, case KEYBOX_FLAG_OWNERTRUST: case KEYBOX_FLAG_VALIDITY: case KEYBOX_FLAG_CREATED_AT: + case KEYBOX_FLAG_SIG_INFO: if (length < 20) return GPG_ERR_INV_OBJ; /* Key info. */ @@ -140,6 +142,7 @@ _keybox_get_flag_location (const unsigned char *buffer, size_t length, if (pos+4 > length) return GPG_ERR_INV_OBJ ; /* Out of bounds. */ /* Signature info. */ + siginfooff = pos; nsigs = get16 (buffer + pos); pos += 2; siginfolen = get16 (buffer + pos); pos += 2; if (siginfolen < 4 ) @@ -158,6 +161,10 @@ _keybox_get_flag_location (const unsigned char *buffer, size_t length, *flag_size = 4; *flag_off += 1+2+4+4+4; break; + case KEYBOX_FLAG_SIG_INFO: + *flag_size = siginfolen * nsigs; + *flag_off = siginfooff; + break; default: break; } @@ -227,6 +234,9 @@ blob_cmp_sn (KEYBOXBLOB blob, const unsigned char *sn, int snlen) } +/* Returns 0 if not found or the number of the key which was found. + For X.509 this is always 1, for OpenPGP this is 1 for the primary + key and 2 and more for the subkeys. */ static int blob_cmp_fpr (KEYBOXBLOB blob, const unsigned char *fpr) { @@ -253,7 +263,7 @@ blob_cmp_fpr (KEYBOXBLOB blob, const unsigned char *fpr) { off = pos + idx*keyinfolen; if (!memcmp (buffer + off, fpr, 20)) - return 1; /* found */ + return idx+1; /* found */ } return 0; /* not found */ } @@ -285,7 +295,7 @@ blob_cmp_fpr_part (KEYBOXBLOB blob, const unsigned char *fpr, { off = pos + idx*keyinfolen; if (!memcmp (buffer + off + fproff, fpr, fprlen)) - return 1; /* found */ + return idx+1; /* found */ } return 0; /* not found */ } @@ -293,7 +303,7 @@ blob_cmp_fpr_part (KEYBOXBLOB blob, const unsigned char *fpr, static int blob_cmp_name (KEYBOXBLOB blob, int idx, - const char *name, size_t namelen, int substr) + const char *name, size_t namelen, int substr, int x509) { const unsigned char *buffer; size_t length; @@ -330,10 +340,9 @@ blob_cmp_name (KEYBOXBLOB blob, int idx, return 0; /* out of bounds */ if (idx < 0) - { /* compare all names starting with that (negated) index */ - idx = -idx; - - for ( ;idx < nuids; idx++) + { /* Compare all names. Note that for X.509 we start with index 1 + so to skip the issuer at index 0. */ + for (idx = !!x509; idx < nuids; idx++) { size_t mypos = pos; @@ -347,15 +356,14 @@ blob_cmp_name (KEYBOXBLOB blob, int idx, if (substr) { if (ascii_memcasemem (buffer+off, len, name, namelen)) - return 1; /* found */ + return idx+1; /* found */ } else { if (len == namelen && !memcmp (buffer+off, name, len)) - return 1; /* found */ + return idx+1; /* found */ } } - return 0; /* not found */ } else { @@ -371,20 +379,25 @@ blob_cmp_name (KEYBOXBLOB blob, int idx, if (substr) { - return !!ascii_memcasemem (buffer+off, len, name, namelen); + if (ascii_memcasemem (buffer+off, len, name, namelen)) + return idx+1; /* found */ } else { - return len == namelen && !memcmp (buffer+off, name, len); + if (len == namelen && !memcmp (buffer+off, name, len)) + return idx+1; /* found */ } } + return 0; /* not found */ } -/* compare all email addresses of the subject. With SUBSTR given as - True a substring search is done in the mail address */ +/* Compare all email addresses of the subject. With SUBSTR given as + True a substring search is done in the mail address. If X509 + states whether thr search is done on an X.509 blob. */ static int -blob_cmp_mail (KEYBOXBLOB blob, const char *name, size_t namelen, int substr) +blob_cmp_mail (KEYBOXBLOB blob, const char *name, size_t namelen, int substr, + int x509) { const unsigned char *buffer; size_t length; @@ -425,7 +438,9 @@ blob_cmp_mail (KEYBOXBLOB blob, const char *name, size_t namelen, int substr) if (namelen < 1) return 0; - for (idx=1 ;idx < nuids; idx++) + /* Note that for X.509 we start at index 1 becuase index 0 is used + for the issuer name. */ + for (idx=!!x509 ;idx < nuids; idx++) { size_t mypos = pos; @@ -434,6 +449,12 @@ blob_cmp_mail (KEYBOXBLOB blob, const char *name, size_t namelen, int substr) len = get32 (buffer+mypos+4); if (off+len > length) return 0; /* error: better stop here out of bounds */ + if (!x509) + { + /* For OpenPGP we need to forward to the mailbox part. */ + for ( ;len && buffer[off] != '<'; len--, off++) + ; + } if (len < 2 || buffer[off] != '<') continue; /* empty name or trailing 0 not stored */ len--; /* one back */ @@ -443,12 +464,12 @@ blob_cmp_mail (KEYBOXBLOB blob, const char *name, size_t namelen, int substr) if (substr) { if (ascii_memcasemem (buffer+off+1, len, name, namelen)) - return 1; /* found */ + return idx+1; /* found */ } else { if (len == namelen && !ascii_memcasecmp (buffer+off+1, name, len)) - return 1; /* found */ + return idx+1; /* found */ } } return 0; /* not found */ @@ -583,7 +604,7 @@ has_issuer (KEYBOXBLOB blob, const char *name) return 0; namelen = strlen (name); - return blob_cmp_name (blob, 0 /* issuer */, name, namelen, 0); + return blob_cmp_name (blob, 0 /* issuer */, name, namelen, 0, 1); } static inline int @@ -601,7 +622,7 @@ has_issuer_sn (KEYBOXBLOB blob, const char *name, namelen = strlen (name); return (blob_cmp_sn (blob, sn, snlen) - && blob_cmp_name (blob, 0 /* issuer */, name, namelen, 0)); + && blob_cmp_name (blob, 0 /* issuer */, name, namelen, 0, 1)); } static inline int @@ -625,22 +646,25 @@ has_subject (KEYBOXBLOB blob, const char *name) return 0; namelen = strlen (name); - return blob_cmp_name (blob, 1 /* subject */, name, namelen, 0); + return blob_cmp_name (blob, 1 /* subject */, name, namelen, 0, 1); } + static inline int -has_subject_or_alt (KEYBOXBLOB blob, const char *name, int substr) +has_username (KEYBOXBLOB blob, const char *name, int substr) { size_t namelen; + int btype; return_val_if_fail (name, 0); - if (blob_get_type (blob) != BLOBTYPE_X509) + btype = blob_get_type (blob); + if (btype != BLOBTYPE_PGP && btype != BLOBTYPE_X509) return 0; namelen = strlen (name); - return blob_cmp_name (blob, -1 /* all subject names*/, name, - namelen, substr); + return blob_cmp_name (blob, -1 /* all subject/user names */, name, + namelen, substr, (btype == BLOBTYPE_X509)); } @@ -648,16 +672,21 @@ static inline int has_mail (KEYBOXBLOB blob, const char *name, int substr) { size_t namelen; + int btype; return_val_if_fail (name, 0); - if (blob_get_type (blob) != BLOBTYPE_X509) + btype = blob_get_type (blob); + if (btype != BLOBTYPE_PGP && btype != BLOBTYPE_X509) return 0; + if (btype == BLOBTYPE_PGP && *name == '<') + name++; /* Hack to remove the leading '<' for gpg. */ + namelen = strlen (name); if (namelen && name[namelen-1] == '>') namelen--; - return blob_cmp_mail (blob, name, namelen, substr); + return blob_cmp_mail (blob, name, namelen, substr, (btype == BLOBTYPE_X509)); } @@ -711,6 +740,7 @@ keybox_search (KEYBOX_HANDLE hd, KEYBOX_SEARCH_DESC *desc, size_t ndesc) int need_words, any_skip; KEYBOXBLOB blob = NULL; struct sn_array_s *sn_array = NULL; + int pk_no, uid_no; if (!hd) return gpg_error (GPG_ERR_INV_VALUE); @@ -827,6 +857,7 @@ keybox_search (KEYBOX_HANDLE hd, KEYBOX_SEARCH_DESC *desc, size_t ndesc) } + pk_no = uid_no = 0; for (;;) { unsigned int blobflags; @@ -852,19 +883,23 @@ keybox_search (KEYBOX_HANDLE hd, KEYBOX_SEARCH_DESC *desc, size_t ndesc) never_reached (); break; case KEYDB_SEARCH_MODE_EXACT: - if (has_subject_or_alt (blob, desc[n].u.name, 0)) + uid_no = has_username (blob, desc[n].u.name, 0); + if (uid_no) goto found; break; case KEYDB_SEARCH_MODE_MAIL: - if (has_mail (blob, desc[n].u.name, 0)) + uid_no = has_mail (blob, desc[n].u.name, 0); + if (uid_no) goto found; break; case KEYDB_SEARCH_MODE_MAILSUB: - if (has_mail (blob, desc[n].u.name, 1)) + uid_no = has_mail (blob, desc[n].u.name, 1); + if (uid_no) goto found; break; case KEYDB_SEARCH_MODE_SUBSTR: - if (has_subject_or_alt (blob, desc[n].u.name, 1)) + uid_no = has_username (blob, desc[n].u.name, 1); + if (uid_no) goto found; break; case KEYDB_SEARCH_MODE_MAILEND: @@ -891,16 +926,19 @@ keybox_search (KEYBOX_HANDLE hd, KEYBOX_SEARCH_DESC *desc, size_t ndesc) goto found; break; case KEYDB_SEARCH_MODE_SHORT_KID: - if (has_short_kid (blob, desc[n].u.kid[1])) + pk_no = has_short_kid (blob, desc[n].u.kid[1]); + if (pk_no) goto found; break; case KEYDB_SEARCH_MODE_LONG_KID: - if (has_long_kid (blob, desc[n].u.kid[0], desc[n].u.kid[1])) + pk_no = has_long_kid (blob, desc[n].u.kid[0], desc[n].u.kid[1]); + if (pk_no) goto found; break; case KEYDB_SEARCH_MODE_FPR: case KEYDB_SEARCH_MODE_FPR20: - if (has_fingerprint (blob, desc[n].u.fpr)) + pk_no = has_fingerprint (blob, desc[n].u.fpr); + if (pk_no) goto found; break; case KEYDB_SEARCH_MODE_KEYGRIP: @@ -933,6 +971,8 @@ keybox_search (KEYBOX_HANDLE hd, KEYBOX_SEARCH_DESC *desc, size_t ndesc) if (!rc) { hd->found.blob = blob; + hd->found.pk_no = pk_no; + hd->found.uid_no = uid_no; } else if (rc == -1) { @@ -958,6 +998,65 @@ keybox_search (KEYBOX_HANDLE hd, KEYBOX_SEARCH_DESC *desc, size_t ndesc) Functions to return a certificate or a keyblock. To be used after a successful search operation. */ + + +/* Return the last found keyblock. Returns 0 on success and stores a + new iobuf at R_IOBUF and a signature status vector at R_SIGSTATUS + in that case. R_UID_NO and R_PK_NO are used to retun the number of + the key or user id which was matched the search criteria; if not + known they are set to 0. */ +gpg_error_t +keybox_get_keyblock (KEYBOX_HANDLE hd, iobuf_t *r_iobuf, + int *r_pk_no, int *r_uid_no, u32 **r_sigstatus) +{ + gpg_error_t err; + const unsigned char *buffer, *p; + size_t length; + size_t image_off, image_len; + size_t siginfo_off, siginfo_len; + u32 *sigstatus, n, n_sigs, sigilen; + + *r_iobuf = NULL; + *r_sigstatus = NULL; + + if (!hd) + return gpg_error (GPG_ERR_INV_VALUE); + if (!hd->found.blob) + return gpg_error (GPG_ERR_NOTHING_FOUND); + + if (blob_get_type (hd->found.blob) != BLOBTYPE_PGP) + return gpg_error (GPG_ERR_WRONG_BLOB_TYPE); + + buffer = _keybox_get_blob_image (hd->found.blob, &length); + if (length < 40) + return gpg_error (GPG_ERR_TOO_SHORT); + image_off = get32 (buffer+8); + image_len = get32 (buffer+12); + if (image_off+image_len > length) + return gpg_error (GPG_ERR_TOO_SHORT); + + err = _keybox_get_flag_location (buffer, length, KEYBOX_FLAG_SIG_INFO, + &siginfo_off, &siginfo_len); + if (err) + return err; + n_sigs = get16 (buffer + siginfo_off); + sigilen = get16 (buffer + siginfo_off + 2); + p = buffer + siginfo_off + 4; + sigstatus = xtrymalloc ((1+n_sigs) * sizeof *sigstatus); + if (!sigstatus) + return gpg_error_from_syserror (); + sigstatus[0] = n_sigs; + for (n=1; n <= n_sigs; n++, p += sigilen) + sigstatus[n] = get32 (p); + + *r_pk_no = hd->found.pk_no; + *r_uid_no = hd->found.uid_no; + *r_sigstatus = sigstatus; + *r_iobuf = iobuf_temp_with_content (buffer+image_off, image_len); + return 0; +} + + #ifdef KEYBOX_WITH_X509 /* Return the last found cert. Caller must free it. diff --git a/kbx/keybox-update.c b/kbx/keybox-update.c index 0d052c926..6428bb20a 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,65 @@ blob_filecopy (int mode, const char *fname, KEYBOXBLOB blob, } +/* Insert the OpenPGP keyblock {IMAGE,IMAGELEN} into HD. SIGSTATUS is + a vector describing the status of the signatures; its first element + gives the number of following elements. */ +gpg_error_t +keybox_insert_keyblock (KEYBOX_HANDLE hd, const void *image, size_t imagelen, + u32 *sigstatus) +{ + gpg_error_t err; + const char *fname; + KEYBOXBLOB blob; + size_t nparsed; + struct _keybox_openpgp_info info; + + if (!hd) + return gpg_error (GPG_ERR_INV_HANDLE); + if (!hd->kb) + return gpg_error (GPG_ERR_INV_HANDLE); + fname = hd->kb->fname; + if (!fname) + return gpg_error (GPG_ERR_INV_HANDLE); + + + /* Close this one otherwise we will mess up the position for a next + search. Fixme: it would be better to adjust the position after + the write operation. */ + _keybox_close_file (hd); + + err = _keybox_parse_openpgp (image, imagelen, &nparsed, &info); + if (err) + return err; + assert (nparsed <= imagelen); + err = _keybox_create_openpgp_blob (&blob, &info, image, imagelen, + sigstatus, hd->ephemeral); + _keybox_destroy_openpgp_info (&info); + if (!err) + { + err = blob_filecopy (1, fname, blob, hd->secret, 0); + _keybox_release_blob (blob); + /* if (!rc && !hd->secret && kb_offtbl) */ + /* { */ + /* update_offset_hash_table_from_kb (kb_offtbl, kb, 0); */ + /* } */ + } + return err; +} + + +/* Update the current key at HD with the given OpenPGP keyblock in + {IMAGE,IMAGELEN}. */ +gpg_error_t +keybox_update_keyblock (KEYBOX_HANDLE hd, const void *image, size_t imagelen) +{ + (void)hd; + (void)image; + (void)imagelen; + return gpg_error (GPG_ERR_NOT_IMPLEMENTED); +} + + #ifdef KEYBOX_WITH_X509 int diff --git a/kbx/keybox.h b/kbx/keybox.h index 52bbe21be..5b2943747 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,17 +26,12 @@ extern "C" { #endif #endif +#include "../common/iobuf.h" #include "keybox-search-desc.h" -#define KEYBOX_WITH_OPENPGP 1 #define KEYBOX_WITH_X509 1 -#ifdef KEYBOX_WITH_OPENPGP -# undef KEYBOX_WITH_OPENPGP -/*#include <lib-to-handle-gpg-data-structs.h>*/ -#endif - #ifdef KEYBOX_WITH_X509 # include <ksba.h> #endif @@ -53,7 +48,8 @@ typedef enum KEYBOX_FLAG_UID, /* The user ID flags; requires an uid index. */ KEYBOX_FLAG_UID_VALIDITY,/* The validity of a specific uid, requires an uid index. */ - KEYBOX_FLAG_CREATED_AT /* The date the block was created. */ + KEYBOX_FLAG_CREATED_AT, /* The date the block was created. */ + KEYBOX_FLAG_SIG_INFO, /* The signature info block. */ } keybox_flag_t; /* Flag values used with KEYBOX_FLAG_BLOB. */ @@ -71,8 +67,16 @@ void keybox_release (KEYBOX_HANDLE hd); const char *keybox_get_resource_name (KEYBOX_HANDLE hd); int keybox_set_ephemeral (KEYBOX_HANDLE hd, int yes); +int keybox_lock (KEYBOX_HANDLE hd, int yes); + +/*-- keybox-file.c --*/ +/* Fixme: This function does not belong here: Provide a better + interface to create a new keybox file. */ +int _keybox_write_header_blob (FILE *fp); /*-- keybox-search.c --*/ +gpg_error_t keybox_get_keyblock (KEYBOX_HANDLE hd, iobuf_t *r_iobuf, + int *r_uid_no, int *r_pk_no, u32 **sigstatus); #ifdef KEYBOX_WITH_X509 int keybox_get_cert (KEYBOX_HANDLE hd, ksba_cert_t *ret_cert); #endif /*KEYBOX_WITH_X509*/ @@ -83,6 +87,12 @@ int keybox_search (KEYBOX_HANDLE hd, KEYBOX_SEARCH_DESC *desc, size_t ndesc); /*-- keybox-update.c --*/ +gpg_error_t keybox_insert_keyblock (KEYBOX_HANDLE hd, + const void *image, size_t imagelen, + u32 *sigstatus); +gpg_error_t keybox_update_keyblock (KEYBOX_HANDLE hd, + const void *image, size_t imagelen); + #ifdef KEYBOX_WITH_X509 int keybox_insert_cert (KEYBOX_HANDLE hd, ksba_cert_t cert, unsigned char *sha1_digest); @@ -98,8 +108,6 @@ int keybox_compress (KEYBOX_HANDLE hd); /*-- --*/ #if 0 -int keybox_lock (KEYBOX_HANDLE hd, int yes); -int keybox_get_keyblock (KEYBOX_HANDLE hd, KBNODE *ret_kb); int keybox_locate_writable (KEYBOX_HANDLE hd); int keybox_search_reset (KEYBOX_HANDLE hd); int keybox_search (KEYBOX_HANDLE hd, KEYDB_SEARCH_DESC *desc, size_t ndesc); @@ -12,6 +12,7 @@ msgstr "" "PO-Revision-Date: 2012-08-24 10:19+0200\n" "Last-Translator: Werner Koch <[email protected]>\n" "Language-Team: German <[email protected]>\n" +"Language: de\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" @@ -98,12 +99,14 @@ msgstr "Passphrase" msgid "ssh keys greater than %d bits are not supported\n" msgstr "SSH Schlüssel von mehr als %d Bits werden nicht unterstützt\n" -#, c-format -msgid "can't create '%s': %s\n" +#, fuzzy, c-format +#| msgid "can't create '%s': %s\n" +msgid "can't create `%s': %s\n" msgstr "'%s' kann nicht erzeugt werden: %s\n" -#, c-format -msgid "can't open '%s': %s\n" +#, fuzzy, c-format +#| msgid "can't open '%s': %s\n" +msgid "can't open `%s': %s\n" msgstr "'%s' kann nicht geöffnet werden: %s\n" #, c-format @@ -135,8 +138,8 @@ msgid "" "An ssh process requested the use of key%%0A %s%%0A (%s)%%0ADo you want to " "allow this?" msgstr "" -"Ein SSH Processs möchte folgenden Schlüssel verwenden:%%0A %s%%0A (%s)%%" -"0AErlauben Sie dies?" +"Ein SSH Processs möchte folgenden Schlüssel verwenden:%%0A %s%%0A " +"(%s)%%0AErlauben Sie dies?" msgid "Allow" msgstr "Erlauben" @@ -147,16 +150,16 @@ msgstr "Verweigern" #, c-format msgid "Please enter the passphrase for the ssh key%%0A %F%%0A (%c)" msgstr "" -"Bitte geben Sie die Passphrase für den SSH-Schlüssel%%0A %F%%0A (%c)%%" -"0Aein." +"Bitte geben Sie die Passphrase für den SSH-Schlüssel%%0A %F%%0A " +"(%c)%%0Aein." msgid "Please re-enter this passphrase" msgstr "Bitte geben Sie die Passphrase noch einmal ein:" #, c-format msgid "" -"Please enter a passphrase to protect the received secret key%%0A %s%%0A %" -"s%%0Awithin gpg-agent's key storage" +"Please enter a passphrase to protect the received secret key%%0A %s%%0A " +"%s%%0Awithin gpg-agent's key storage" msgstr "" "Bitte geben Sie eine Passphrase ein, um den empfangenen geheimen\n" "Schlüssel%%0A %s%%0A %s%%0Aim Schlüsselspeicher des Gpg-Agenten zu " @@ -188,8 +191,9 @@ msgstr "PUK" msgid "Reset Code" msgstr "Rückstellcode" -#, c-format -msgid "%s%%0A%%0AUse the reader's keypad for input." +#, fuzzy, c-format +#| msgid "%s%%0A%%0AUse the reader's keypad for input." +msgid "%s%%0A%%0AUse the reader's pinpad for input." msgstr "%s%%0A%%0AZur Eingabe die Tastatur des Kartenlesers verwenden." msgid "Repeat this Reset Code" @@ -608,8 +612,9 @@ msgid "" "Do you ultimately trust%%0A \"%s\"%%0Ato correctly certify user " "certificates?" msgstr "" -"Wenn Sie vollständiges Vertrauen haben, daß%%0A \"%s\"%%" -"0ABenutzerzertifikate verläßlich zertifiziert, so antworten Sie mit \"Ja\"." +"Wenn Sie vollständiges Vertrauen haben, daß%%0A \"%s" +"\"%%0ABenutzerzertifikate verläßlich zertifiziert, so antworten Sie mit \"Ja" +"\"." msgid "Yes" msgstr "Ja" @@ -965,6 +970,10 @@ msgstr "Dirmngr benutzbar" msgid "No help available for '%s'." msgstr "Keine Hilfe für '%s' vorhanden." +#, c-format +msgid "can't open '%s': %s\n" +msgstr "'%s' kann nicht geöffnet werden: %s\n" + msgid "ignoring garbage line" msgstr "Zeile mit nicht identifizierten Zeichen wird ignoriert" @@ -1055,6 +1064,10 @@ msgid "error writing to '%s': %s\n" msgstr "Fehler beim Schreiben von %s: %s\n" #, c-format +msgid "can't create '%s': %s\n" +msgstr "'%s' kann nicht erzeugt werden: %s\n" + +#, c-format msgid "removing stale lockfile (created by %d)\n" msgstr "eine übriggebliebene Sperrdatei wird entfernt (erzeugt von %d)\n" @@ -1157,6 +1170,15 @@ msgid "not human readable" msgstr "nicht als Klartext darstellbar" #, c-format +msgid "failed to proxy %s inquiry to client\n" +msgstr "Die %s \"inquiry\" konnte nicht an den Client weitergeleitet werden\n" + +#, fuzzy +#| msgid "Enter passphrase\n" +msgid "Enter passphrase: " +msgstr "Geben Sie die Passphrase ein\n" + +#, c-format msgid "OpenPGP card not available: %s\n" msgstr "OpenPGP Karte ist nicht vorhanden: %s\n" @@ -1359,6 +1381,14 @@ msgstr " (3) Authentisierungs-Schlüssel\n" msgid "Invalid selection.\n" msgstr "Ungültige Auswahl.\n" +msgid "Please select where to store the key:\n" +msgstr "Wählen Sie den Speicherort für den Schlüssel:\n" + +#, fuzzy, c-format +#| msgid "read failed: %s\n" +msgid "KEYTOCARD failed: %s\n" +msgstr "Lesen schlug fehl: %s\n" + msgid "quit this menu" msgstr "Menü verlassen" @@ -1509,8 +1539,8 @@ msgstr "" msgid "" "WARNING: forcing symmetric cipher %s (%d) violates recipient preferences\n" msgstr "" -"WARNUNG: Erzwungene Verwendung des symmetrischen Verschlüsselungsverfahren %" -"s (%d) verletzt die Empfängervoreinstellungen\n" +"WARNUNG: Erzwungene Verwendung des symmetrischen Verschlüsselungsverfahren " +"%s (%d) verletzt die Empfängervoreinstellungen\n" #, c-format msgid "" @@ -1630,9 +1660,6 @@ msgstr " - übersprungen" msgid "WARNING: nothing exported\n" msgstr "WARNUNG: Nichts exportiert\n" -msgid "too many entries in pk cache - disabled\n" -msgstr "zu viele Einträge im pk-Cache - abgeschaltet\n" - msgid "[User ID not found]" msgstr "[User-ID nicht gefunden]" @@ -1957,8 +1984,8 @@ msgstr "Hinweis: Alte voreingestellte Optionendatei '%s' wurde ignoriert\n" #, c-format msgid "libgcrypt is too old (need %s, have %s)\n" msgstr "" -"Die Bibliothek \"libgcrypt\" ist zu alt (benötigt wird %s, vorhanden ist %" -"s)\n" +"Die Bibliothek \"libgcrypt\" ist zu alt (benötigt wird %s, vorhanden ist " +"%s)\n" #, c-format msgid "NOTE: %s is not for normal use!\n" @@ -1968,6 +1995,11 @@ msgstr "Hinweis: %s ist nicht für den üblichen Gebrauch gedacht!\n" msgid "'%s' is not a valid signature expiration\n" msgstr "`%s' ist kein gültiges Signaturablaufdatum\n" +#, fuzzy, c-format +#| msgid "Invalid subject name '%s'\n" +msgid "invalid pinentry mode '%s'\n" +msgstr "Ungültiger Subjekt-Name `%s'\n" + #, c-format msgid "'%s' is not a valid character set\n" msgstr "`%s' ist kein gültiger Zeichensatz\n" @@ -2658,10 +2690,18 @@ msgid "key %s: direct key signature added\n" msgstr "Schlüssel %s: \"direct-key\"-Signaturen hinzugefügt\n" #, c-format +msgid "error creating keybox '%s': %s\n" +msgstr "Die \"Keybox\" `%s' konnte nicht erstellt werden: %s\n" + +#, c-format msgid "error creating keyring '%s': %s\n" msgstr "Fehler beim Erzeugen des Schlüsselbundes `%s': %s\n" #, c-format +msgid "keybox '%s' created\n" +msgstr "Die \"Keybox\" `%s' wurde erstellt\n" + +#, c-format msgid "keyring '%s' created\n" msgstr "Schlüsselbund `%s' erstellt\n" @@ -5272,8 +5312,8 @@ msgstr "%d marginal-needed, %d complete-needed, %s Vertrauensmodell\n" msgid "" "depth: %d valid: %3d signed: %3d trust: %d-, %dq, %dn, %dm, %df, %du\n" msgstr "" -"Tiefe: %d gültig: %3d signiert: %3d Vertrauen: %d-, %dq, %dn, %dm, %df, %" -"du\n" +"Tiefe: %d gültig: %3d signiert: %3d Vertrauen: %d-, %dq, %dn, %dm, %df, " +"%du\n" #, c-format msgid "unable to update trustdb version record: write failed: %s\n" @@ -5528,7 +5568,9 @@ msgstr "" msgid "can't access %s - invalid OpenPGP card?\n" msgstr "Kann auf %s nicht zugreifen - ungültige OpenPGP-Karte?\n" -msgid "||Please enter your PIN at the reader's keypad" +#, fuzzy +#| msgid "||Please enter your PIN at the reader's keypad" +msgid "||Please enter your PIN at the reader's pinpad" msgstr "||Bitte die PIN auf der Tastatur des Kartenlesers eingeben" #. TRANSLATORS: Do not translate the "|*|" prefixes but @@ -5561,12 +5603,17 @@ msgstr "Den internen CCID Treiber nicht benutzen" msgid "|N|disconnect the card after N seconds of inactivity" msgstr "|N|Schalte die Karte nach N Sekunden Inaktivität ab" -msgid "do not use a reader's keypad" +#, fuzzy +#| msgid "do not use a reader's keypad" +msgid "do not use a reader's pinpad" msgstr "Die Tastatur des Kartenlesers nicht benutzen" msgid "deny the use of admin card commands" msgstr "Verweigere die Benutzung von \"Admin\"-Befehlen" +msgid "use variable length input for pinpad" +msgstr "" + msgid "Usage: scdaemon [options] (-h for help)" msgstr "Aufruf: scdaemon [Optionen] (-h für Hilfe)" @@ -5595,10 +5642,6 @@ msgid "invalid radix64 character %02x skipped\n" msgstr "Ungültiges Basis-64 Zeichen %02X wurde übersprungen\n" #, c-format -msgid "failed to proxy %s inquiry to client\n" -msgstr "Die %s \"inquiry\" konnte nicht an den Client weitergeleitet werden\n" - -#, c-format msgid "validation model requested by certificate: %s" msgstr "Durch Zertifikat angefordertes Gültigkeitsmodell: %s" @@ -6213,17 +6256,9 @@ msgstr "Fehler beim Importieren des Zertifikats: %s\n" msgid "error reading input: %s\n" msgstr "Fehler beim Lesen der Eingabe: %s\n" -#, c-format -msgid "error creating keybox '%s': %s\n" -msgstr "Die \"Keybox\" `%s' konnte nicht erstellt werden: %s\n" - msgid "you may want to start the gpg-agent first\n" msgstr "Sie sollten zuerst den gpg-agent starten\n" -#, c-format -msgid "keybox '%s' created\n" -msgstr "Die \"Keybox\" `%s' wurde erstellt\n" - msgid "failed to get the fingerprint\n" msgstr "Kann den Fingerprint nicht ermitteln\n" @@ -6339,8 +6374,8 @@ msgstr "Dies ist eine qualifizierte Signatur.\n" #, c-format msgid "can't initialize certificate cache lock: %s\n" msgstr "" -"Sperre für den Zertifikatzwischenspeicher kann nicht initialisiert werden: %" -"s\n" +"Sperre für den Zertifikatzwischenspeicher kann nicht initialisiert werden: " +"%s\n" #, c-format msgid "can't acquire read lock on the certificate cache: %s\n" @@ -6350,8 +6385,8 @@ msgstr "" #, c-format msgid "can't acquire write lock on the certificate cache: %s\n" msgstr "" -"Schreibsperre für den Zertifikatzwischenspeicher kann nicht gesetzt werden: %" -"s\n" +"Schreibsperre für den Zertifikatzwischenspeicher kann nicht gesetzt werden: " +"%s\n" #, c-format msgid "can't release lock on the certificate cache: %s\n" @@ -7949,6 +7984,9 @@ msgstr "" "Syntax: gpg-check-pattern [optionen] Musterdatei\n" "Die von stdin gelesene Passphrase gegen die Musterdatei prüfen\n" +#~ msgid "too many entries in pk cache - disabled\n" +#~ msgstr "zu viele Einträge im pk-Cache - abgeschaltet\n" + #~ msgid "failed to allocated keyDB handle\n" #~ msgstr "Ein keyDB Handle konnte nicht bereitgestellt werden\n" @@ -8095,9 +8133,6 @@ msgstr "" #~ msgid "can't fdopen pipe for reading: %s\n" #~ msgstr "Pipe kann nicht zum Lesen \"fdopen\"t werden: %s\n" -#~ msgid "Please select where to store the key:\n" -#~ msgstr "Wählen Sie den Speicherort für den Schlüssel:\n" - #~ msgid "secret key already stored on a card\n" #~ msgstr "Geheimer Schlüssel ist bereits auf einer Karte gespeichert\n" @@ -10,10 +10,10 @@ msgstr "" "PO-Revision-Date: 2012-08-21 15:44-0400\n" "Last-Translator: David Prévot <[email protected]>\n" "Language-Team: French <[email protected]>\n" +"Language: fr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8-bit\n" -"Language: fr\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" "X-Generator: Lokalize 1.4\n" @@ -97,12 +97,14 @@ msgstr "Phrase de passe" msgid "ssh keys greater than %d bits are not supported\n" msgstr "les clefs SSH plus grandes que %d bits ne sont pas prises en charge\n" -#, c-format -msgid "can't create '%s': %s\n" +#, fuzzy, c-format +#| msgid "can't create '%s': %s\n" +msgid "can't create `%s': %s\n" msgstr "impossible de créer « %s » : %s\n" -#, c-format -msgid "can't open '%s': %s\n" +#, fuzzy, c-format +#| msgid "can't open '%s': %s\n" +msgid "can't open `%s': %s\n" msgstr "impossible d'ouvrir « %s » : %s\n" #, c-format @@ -152,11 +154,11 @@ msgstr "Veuillez répéter cette phrase de passe" #, c-format msgid "" -"Please enter a passphrase to protect the received secret key%%0A %s%%0A %" -"s%%0Awithin gpg-agent's key storage" +"Please enter a passphrase to protect the received secret key%%0A %s%%0A " +"%s%%0Awithin gpg-agent's key storage" msgstr "" -"Veuillez entrer une phrase de passe pour protéger la clef secrète%%0A %s%%" -"0A %s%%0Areçue dans l'espace de stockage de clefs de gpg-agent" +"Veuillez entrer une phrase de passe pour protéger la clef secrète%%0A %s" +"%%0A %s%%0Areçue dans l'espace de stockage de clefs de gpg-agent" msgid "does not match - try again" msgstr "ne correspond pas — veuillez réessayer" @@ -182,8 +184,9 @@ msgstr "CDP" msgid "Reset Code" msgstr "Code de réinitialisation" -#, c-format -msgid "%s%%0A%%0AUse the reader's keypad for input." +#, fuzzy, c-format +#| msgid "%s%%0A%%0AUse the reader's keypad for input." +msgid "%s%%0A%%0AUse the reader's pinpad for input." msgstr "%s%%0A%%0AUtilisez le pavé numérique du lecteur en entrée." msgid "Repeat this Reset Code" @@ -274,8 +277,8 @@ msgid "" "You have not entered a passphrase - this is in general a bad idea!%0APlease " "confirm that you do not want to have any protection on your key." msgstr "" -"Aucune phrase de passe n'a été entrée — c'est souvent une mauvaise idée.%" -"0AVeuillez confirmer que vous ne voulez aucune protection pour la clef." +"Aucune phrase de passe n'a été entrée — c'est souvent une mauvaise idée." +"%0AVeuillez confirmer que vous ne voulez aucune protection pour la clef." msgid "Yes, protection is not needed" msgstr "Oui, aucune protection n'est nécessaire" @@ -965,6 +968,10 @@ msgstr "Dirmngr utilisable" msgid "No help available for '%s'." msgstr "Pas d'aide disponible pour « %s »." +#, c-format +msgid "can't open '%s': %s\n" +msgstr "impossible d'ouvrir « %s » : %s\n" + msgid "ignoring garbage line" msgstr "ligne inutile ignorée" @@ -1055,6 +1062,10 @@ msgid "error writing to '%s': %s\n" msgstr "erreur d'écriture sur « %s » : %s\n" #, c-format +msgid "can't create '%s': %s\n" +msgstr "impossible de créer « %s » : %s\n" + +#, c-format msgid "removing stale lockfile (created by %d)\n" msgstr "suppression du vieux fichier verrou (créé par %d)\n" @@ -1157,6 +1168,13 @@ msgid "not human readable" msgstr "non lisible par l'utilisateur" #, c-format +msgid "failed to proxy %s inquiry to client\n" +msgstr "échec de transfert de la demande %s au client\n" + +msgid "Enter passphrase: " +msgstr "Entrez la phrase de passe : " + +#, c-format msgid "OpenPGP card not available: %s\n" msgstr "la carte OpenPGP n'est pas disponible : %s\n" @@ -1359,6 +1377,14 @@ msgstr " (3) Clef d'authentification\n" msgid "Invalid selection.\n" msgstr "Choix incorrect.\n" +msgid "Please select where to store the key:\n" +msgstr "Veuillez sélectionner l'endroit où stocker la clef :\n" + +#, fuzzy, c-format +#| msgid "read failed: %s\n" +msgid "KEYTOCARD failed: %s\n" +msgstr "échec de read : %s\n" + msgid "quit this menu" msgstr "quitter ce menu" @@ -1466,7 +1492,8 @@ msgid "there is a secret key for public key \"%s\"!\n" msgstr "il y a une clef secrète pour la clef publique « %s ».\n" msgid "use option \"--delete-secret-keys\" to delete it first.\n" -msgstr "utiliser d'abord l'option « --delete-secret-keys » pour la supprimer.\n" +msgstr "" +"utiliser d'abord l'option « --delete-secret-keys » pour la supprimer.\n" #, c-format msgid "error creating passphrase: %s\n" @@ -1631,9 +1658,6 @@ msgstr " — ignoré" msgid "WARNING: nothing exported\n" msgstr "Attention : rien n'a été exporté\n" -msgid "too many entries in pk cache - disabled\n" -msgstr "trop d'entrées dans le cache de clefs publiques — désactivé\n" - msgid "[User ID not found]" msgstr "[identité introuvable]" @@ -1989,6 +2013,11 @@ msgstr "Remarque : %s n'est pas pour une utilisation normale.\n" msgid "'%s' is not a valid signature expiration\n" msgstr "« %s » n'est pas une date d'expiration de signature valable\n" +#, fuzzy, c-format +#| msgid "Invalid subject name '%s'\n" +msgid "invalid pinentry mode '%s'\n" +msgstr "Nom de sujet « %s » incorrect\n" + #, c-format msgid "'%s' is not a valid character set\n" msgstr "« %s » n'est pas un jeu de caractères valable\n" @@ -2667,10 +2696,18 @@ msgid "key %s: direct key signature added\n" msgstr "clef %s : ajout de la signature directe de clef\n" #, c-format +msgid "error creating keybox '%s': %s\n" +msgstr "erreur de création du trousseau local « %s » : %s\n" + +#, c-format msgid "error creating keyring '%s': %s\n" msgstr "erreur de création du porte-clefs « %s » : %s\n" #, c-format +msgid "keybox '%s' created\n" +msgstr "le trousseau local « %s » a été créé\n" + +#, c-format msgid "keyring '%s' created\n" msgstr "le porte-clefs « %s » a été créé\n" @@ -5578,7 +5615,9 @@ msgid "can't access %s - invalid OpenPGP card?\n" msgstr "" "impossible d'accéder à %s — la carte OpenPGP n'est peut-être pas valable\n" -msgid "||Please enter your PIN at the reader's keypad" +#, fuzzy +#| msgid "||Please enter your PIN at the reader's keypad" +msgid "||Please enter your PIN at the reader's pinpad" msgstr "" "||Veuillez entrer votre code personnel sur le pavé numérique du lecteur" @@ -5612,12 +5651,17 @@ msgstr "ne pas utiliser le pilote CCID interne" msgid "|N|disconnect the card after N seconds of inactivity" msgstr "|N|déconnecter la carte après N secondes d'inactivité " -msgid "do not use a reader's keypad" +#, fuzzy +#| msgid "do not use a reader's keypad" +msgid "do not use a reader's pinpad" msgstr "ne pas utiliser de pavé numérique du lecteur" msgid "deny the use of admin card commands" msgstr "refus d'utiliser les commandes d'administration de la carte" +msgid "use variable length input for pinpad" +msgstr "" + msgid "Usage: scdaemon [options] (-h for help)" msgstr "Utilisation : scdaemon [options] (-h pour l'aide)" @@ -5646,10 +5690,6 @@ msgid "invalid radix64 character %02x skipped\n" msgstr "caractère %02x incorrect en radix64, ignoré\n" #, c-format -msgid "failed to proxy %s inquiry to client\n" -msgstr "échec de transfert de la demande %s au client\n" - -#, c-format msgid "validation model requested by certificate: %s" msgstr "modèle de validation demandé par le certificat : %s" @@ -6278,17 +6318,9 @@ msgstr "erreur d'importation du certificat : %s\n" msgid "error reading input: %s\n" msgstr "erreur de lecture de l'entrée : %s\n" -#, c-format -msgid "error creating keybox '%s': %s\n" -msgstr "erreur de création du trousseau local « %s » : %s\n" - msgid "you may want to start the gpg-agent first\n" msgstr "vous pourriez d'abord démarrer l'agent GPG\n" -#, c-format -msgid "keybox '%s' created\n" -msgstr "le trousseau local « %s » a été créé\n" - msgid "failed to get the fingerprint\n" msgstr "impossible d'obtenir l'empreinte\n" @@ -6696,8 +6728,8 @@ msgstr "" #, c-format msgid "problem reading cache record for S/N %s: %s\n" msgstr "" -"problème de lecture d'enregistrement de cache pour le numéro de série %s : %" -"s\n" +"problème de lecture d'enregistrement de cache pour le numéro de série %s : " +"%s\n" #, c-format msgid "S/N %s is not valid; reason=%02X date=%.15s\n" @@ -6745,8 +6777,8 @@ msgstr "" #, c-format msgid "update times of this CRL: this=%s next=%s\n" msgstr "" -"dates de mises à jour de la liste de révocations de certificats : celle-ci=%" -"s prochaine=%s\n" +"dates de mises à jour de la liste de révocations de certificats : celle-ci=" +"%s prochaine=%s\n" msgid "nextUpdate not given; assuming a validity period of one day\n" msgstr "nextUpdate non donné ; période de validité supposée d'un jour\n" @@ -6774,8 +6806,8 @@ msgstr "" #, c-format msgid "CRL signature verification failed: %s\n" msgstr "" -"échec de vérification de signature de liste de révocations de certificats : %" -"s\n" +"échec de vérification de signature de liste de révocations de certificats : " +"%s\n" #, c-format msgid "error checking validity of CRL issuer certificate: %s\n" @@ -6836,8 +6868,8 @@ msgstr "" #, c-format msgid "error reading CRL extensions: %s\n" msgstr "" -"erreur de lecture des extensions de liste de révocations de certificats : %" -"s\n" +"erreur de lecture des extensions de liste de révocations de certificats : " +"%s\n" #, c-format msgid "creating cache file '%s'\n" @@ -6857,8 +6889,8 @@ msgstr "" #, c-format msgid "Begin CRL dump (retrieved via %s)\n" msgstr "" -"Démarrage du vidage de liste de révocations de certificats (récupérée par %" -"s)\n" +"Démarrage du vidage de liste de révocations de certificats (récupérée par " +"%s)\n" msgid "" " ERROR: The CRL will not be used because it was still too old after an " @@ -7196,7 +7228,8 @@ msgstr "les deux-points ne sont pas permis avec dans le nom de socket\n" #, c-format msgid "fetching CRL from '%s' failed: %s\n" msgstr "" -"échec de récupération de liste de révocations de certificats sur « %s » : %s\n" +"échec de récupération de liste de révocations de certificats sur « %s » : " +"%s\n" #, c-format msgid "processing CRL from '%s' failed: %s\n" @@ -8060,15 +8093,15 @@ msgstr "" "Vérifier une phrase de passe donnée sur l'entrée standard par rapport à " "ficmotif\n" +#~ msgid "too many entries in pk cache - disabled\n" +#~ msgstr "trop d'entrées dans le cache de clefs publiques — désactivé\n" + #~ msgid "failed to allocated keyDB handle\n" #~ msgstr "impossible d'allouer la gestion de base de clefs\n" #~ msgid "can't fdopen pipe for reading: %s\n" #~ msgstr "impossible d'ouvrir un tube en lecture avec fdopen : %s\n" -#~ msgid "Please select where to store the key:\n" -#~ msgstr "Veuillez sélectionner l'endroit où stocker la clef :\n" - #~ msgid "unknown key protection algorithm\n" #~ msgstr "algorithme de protection de clef inconnu\n" @@ -8704,9 +8737,6 @@ msgstr "" #~ msgid "can't query passphrase in batch mode\n" #~ msgstr "impossible de demander la phrase de passe en mode automatique\n" -#~ msgid "Enter passphrase: " -#~ msgstr "Entrez la phrase de passe : " - #~ msgid "Repeat passphrase: " #~ msgstr "Répétez la phrase de passe : " |