diff --git a/NEWS b/NEWS
index 1de9000b6..648f0cef9 100644
--- a/NEWS
+++ b/NEWS
@@ -37,6 +37,18 @@
* The entire keyring management has been revamped.
+ * The way signature stati are store has changed, so that v3
+ signatures can be supported. To increase the speed of many
+ operations for existing keys you can use the new
+ --rebuild-keydb-caches command.
+
+ * The entire key validation process (trustdb) has been revamped.
+ See the man page entries for --update-trustdb, --check-trustdb
+ and --no-auto-check-trustdb.
+
+ * --trusted-keys is again obsolete, --edit can be used to set the
+ ownertrust of any key to ultimately trusted.
+
Noteworthy changes in version 1.0.6 (2001-05-29)
------------------------------------------------
diff --git a/doc/gpg.sgml b/doc/gpg.sgml
index 717f7e394..386b256e2 100644
--- a/doc/gpg.sgml
+++ b/doc/gpg.sgml
@@ -513,7 +513,6 @@ command --update-trustdb.
There are a few other options which control how this command works.
Most notable here is the --merge-only option which does not insert new keys
but does only the merging of new signatures, user-IDs and subkeys.
-See also the option --allow-secret-key-import.
@@ -1530,9 +1529,7 @@ Don't insert new keys into the keyrings while doing an import.
--allow-secret-key-import
-Allow import of secret keys. The import command normally skips secret
-keys because a secret key can otherwise be used to attack the trust
-calculation.
+This is an obsolete option and is not used anywhere.
diff --git a/g10/ChangeLog b/g10/ChangeLog
index 96ef0c6fa..e33e175d6 100644
--- a/g10/ChangeLog
+++ b/g10/ChangeLog
@@ -1,3 +1,31 @@
+2001-09-25 Werner Koch
+
+ * g10.c, options.h, import.c: Removed the entire
+ allow-secret-key-import stuff because the validity is now
+ controlled by other means.
+
+ * g10.c: New command --rebuild-keydb-caches.
+ * keydb.c (keydb_rebuild_caches): New.
+ * keyring.c (do_copy): Moved some code to
+ (create_tmp_file, rename_tmp_file, write_keyblock): new functions.
+ (keyring_rebuild_cache): New.
+
+ * packet.h (PKT_ring_trust): Add sigcache field.
+ * parse-packet.c (parse_trust): Parse sigcache.
+ * keyring.c (do_copy): Always insert a sigcache packet.
+ (keyring_get_keyblock): Copy the sigcache packet to the signature.
+ * sig-check.c (cache_sig_result): Renamed from
+ cache_selfsig_result. Changed implementation to use the flag bits
+ and changed all callers.
+ (mdc_kludge_check): Removed this unused code.
+ (do_check): Do not set the sig flags here.
+
+ * import.c (read_block): Make sure that ring_trust packets are
+ never imported.
+ * export.c (do_export_stream): and never export them.
+
+ * trustdb.c (make_key_array): Skip revoked and expired keys.
+
2001-09-24 Werner Koch
* g10.c, options.h: New option --no-auto-check-trustdb.
diff --git a/g10/build-packet.c b/g10/build-packet.c
index 1b7e0d838..271fd0920 100644
--- a/g10/build-packet.c
+++ b/g10/build-packet.c
@@ -135,7 +135,7 @@ build_packet( IOBUF out, PACKET *pkt )
rc = do_onepass_sig( out, ctb, pkt->pkt.onepass_sig );
break;
case PKT_RING_TRUST:
- break; /* ignore it */
+ break; /* ignore it (keyring.c does write it directly)*/
default:
log_bug("invalid packet type in build_packet()\n");
break;
diff --git a/g10/export.c b/g10/export.c
index 0c235233f..4c4a4de67 100644
--- a/g10/export.c
+++ b/g10/export.c
@@ -186,6 +186,9 @@ do_export_stream( IOBUF out, STRLIST users, int secret, int onlyrfc, int *any )
* secret keyring */
if( !secret && node->pkt->pkttype == PKT_COMMENT )
continue;
+ /* make sure that ring_trust packets never get exported */
+ if (node->pkt->pkttype == PKT_RING_TRUST)
+ continue;
/* do not export packets which are marked as not exportable */
if( node->pkt->pkttype == PKT_SIGNATURE ) {
const char *p;
diff --git a/g10/g10.c b/g10/g10.c
index 04b73e163..6210fe9e4 100644
--- a/g10/g10.c
+++ b/g10/g10.c
@@ -112,7 +112,7 @@ enum cmd_and_opt_values { aNull = 0,
aEnArmor,
aGenRandom,
aPipeMode,
- aRefreshCaches,
+ aRebuildKeydbCaches,
aRefreshKeys,
oTextmode,
@@ -441,6 +441,7 @@ static ARGPARSE_OPTS opts[] = {
{ oEnableSpecialFilenames, "enable-special-filenames", 0, "@" },
{ oNoExpensiveTrustChecks, "no-expensive-trust-checks", 0, "@" },
{ aDeleteSecretAndPublicKey, "delete-secret-and-public-key",256, "@" },
+ { aRebuildKeydbCaches, "rebuild-keydb-caches", 256, "@"},
{ oPreservePermissions, "preserve-permissions", 0, "@"},
{ oPreferenceList, "preference-list", 2, "@"},
{ oEmu3DESS2KBug, "emulate-3des-s2k-bug", 0, "@"},
@@ -848,6 +849,7 @@ main( int argc, char **argv )
case aExportOwnerTrust: set_cmd( &cmd, aExportOwnerTrust); break;
case aImportOwnerTrust: set_cmd( &cmd, aImportOwnerTrust); break;
case aPipeMode: set_cmd( &cmd, aPipeMode); break;
+ case aRebuildKeydbCaches: set_cmd( &cmd, aRebuildKeydbCaches); break;
case oArmor: opt.armor = 1; opt.no_armor=0; break;
case oOutput: opt.outfile = pargs.r.ret_str; break;
@@ -1078,7 +1080,7 @@ main( int argc, char **argv )
opt.override_session_key = pargs.r.ret_str;
break;
case oMergeOnly: opt.merge_only = 1; break;
- case oAllowSecretKeyImport: opt.allow_secret_key_import = 1; break;
+ case oAllowSecretKeyImport: /* obsolete */ break;
case oTryAllSecrets: opt.try_all_secrets = 1; break;
case oTrustedKey: register_trusted_key( pargs.r.ret_str ); break;
case oEnableSpecialFilenames:
@@ -1689,6 +1691,12 @@ main( int argc, char **argv )
run_in_pipemode ();
break;
+ case aRebuildKeydbCaches:
+ if (argc)
+ wrong_args ("--rebuild-keydb-caches");
+ keydb_rebuild_caches ();
+ break;
+
case aListPackets:
opt.list_packets=2;
default:
diff --git a/g10/import.c b/g10/import.c
index dc17505ef..e15f07c86 100644
--- a/g10/import.c
+++ b/g10/import.c
@@ -55,13 +55,13 @@ struct stats_s {
static int import( IOBUF inp, int fast, const char* fname,
- int allow_secret, struct stats_s *stats );
+ struct stats_s *stats );
static int read_block( IOBUF a, PACKET **pending_pkt, KBNODE *ret_root );
static void remove_bad_stuff (KBNODE keyblock);
static int import_one( const char *fname, KBNODE keyblock, int fast,
struct stats_s *stats);
static int import_secret_one( const char *fname, KBNODE keyblock,
- int allow, struct stats_s *stats );
+ struct stats_s *stats );
static int import_revoke_cert( const char *fname, KBNODE node,
struct stats_s *stats);
static int chk_self_sigs( const char *fname, KBNODE keyblock,
@@ -144,8 +144,7 @@ import_keys( char **fnames, int nnames, int fast, void *stats_handle )
if( !inp )
log_error(_("can't open `%s': %s\n"), fname, strerror(errno) );
else {
- int rc = import( inp, fast, fname,
- opt.allow_secret_key_import, stats );
+ int rc = import( inp, fast, fname, stats );
iobuf_close(inp);
if( rc )
log_error("import from `%s' failed: %s\n", fname,
@@ -170,8 +169,7 @@ import_keys_stream( IOBUF inp, int fast, void *stats_handle )
if (!stats)
stats = import_new_stats_handle ();
- rc = import( inp, fast, "[stream]",
- opt.allow_secret_key_import, stats );
+ rc = import( inp, fast, "[stream]", stats);
if (!stats_handle) {
import_print_stats (stats);
import_release_stats_handle (stats);
@@ -181,8 +179,7 @@ import_keys_stream( IOBUF inp, int fast, void *stats_handle )
}
static int
-import( IOBUF inp, int fast, const char* fname, int allow_secret,
- struct stats_s *stats )
+import( IOBUF inp, int fast, const char* fname, struct stats_s *stats )
{
PACKET *pending_pkt = NULL;
KBNODE keyblock;
@@ -201,8 +198,7 @@ import( IOBUF inp, int fast, const char* fname, int allow_secret,
if( keyblock->pkt->pkttype == PKT_PUBLIC_KEY )
rc = import_one( fname, keyblock, fast, stats );
else if( keyblock->pkt->pkttype == PKT_SECRET_KEY )
- rc = import_secret_one( fname, keyblock,
- allow_secret, stats );
+ rc = import_secret_one( fname, keyblock, stats );
else if( keyblock->pkt->pkttype == PKT_SIGNATURE
&& keyblock->pkt->pkt.signature->sig_class == 0x20 )
rc = import_revoke_cert( fname, keyblock, stats );
@@ -344,6 +340,11 @@ read_block( IOBUF a, PACKET **pending_pkt, KBNODE *ret_root )
init_packet(pkt);
break;
+ case PKT_RING_TRUST:
+ /* skip those packets */
+ free_packet( pkt );
+ init_packet(pkt);
+ break;
case PKT_PUBLIC_KEY:
case PKT_SECRET_KEY:
@@ -386,7 +387,8 @@ remove_bad_stuff (KBNODE keyblock)
for (node=keyblock; node; node = node->next ) {
if( node->pkt->pkttype == PKT_SIGNATURE ) {
- /* delete the subpackets we use for the verification cache */
+ /* delete the subpackets we used to use for the
+ verification cache */
delete_sig_subpkt (node->pkt->pkt.signature->unhashed,
SIGSUBPKT_PRIV_VERIFY_CACHE);
}
@@ -606,7 +608,7 @@ import_one( const char *fname, KBNODE keyblock, int fast,
* with the trust calculation.
*/
static int
-import_secret_one( const char *fname, KBNODE keyblock, int allow,
+import_secret_one( const char *fname, KBNODE keyblock,
struct stats_s *stats)
{
PKT_secret_key *sk;
@@ -634,12 +636,6 @@ import_secret_one( const char *fname, KBNODE keyblock, int allow,
putc('\n', stderr);
}
stats->secret_read++;
- if (!allow) {
- log_info ( _("secret key %08lX not imported "
- "(use %s to allow for it)\n"),
- (ulong)keyid[1], "--allow-secret-key-import");
- return 0;
- }
if( !uidnode ) {
log_error( _("key %08lX: no user ID\n"), (ulong)keyid[1]);
diff --git a/g10/keydb.c b/g10/keydb.c
index 7a7a43e3e..6cd3cf93f 100644
--- a/g10/keydb.c
+++ b/g10/keydb.c
@@ -320,7 +320,7 @@ lock_all (KEYDB_HANDLE hd)
}
if (rc) {
- /* revert the alreadt set locks */
+ /* revert the already set locks */
for (i--; i >= 0; i--) {
switch (hd->active[i].type) {
case KEYDB_RESOURCE_TYPE_NONE:
@@ -517,6 +517,22 @@ keydb_locate_writable (KEYDB_HANDLE hd, const char *reserved)
return rc;
}
+/*
+ * Rebuild the caches of all key resources.
+ */
+void
+keydb_rebuild_caches (void)
+{
+ int rc;
+
+ rc = keyring_rebuild_cache ();
+ if (rc)
+ log_error (_("failed to rebuild all keyring caches: %s\n"),
+ g10_errstr (rc));
+ /* add other types here */
+}
+
+
/*
* Start the next search on this handle right at the beginning
diff --git a/g10/keydb.h b/g10/keydb.h
index 67a9e10f2..ba7d58528 100644
--- a/g10/keydb.h
+++ b/g10/keydb.h
@@ -148,6 +148,7 @@ int keydb_update_keyblock (KEYDB_HANDLE hd, KBNODE kb);
int keydb_insert_keyblock (KEYDB_HANDLE hd, KBNODE kb);
int keydb_delete_keyblock (KEYDB_HANDLE hd);
int keydb_locate_writable (KEYDB_HANDLE hd, const char *reserved);
+void keydb_rebuild_caches (void);
int keydb_search_reset (KEYDB_HANDLE hd);
int keydb_search (KEYDB_HANDLE hd, KEYDB_SEARCH_DESC *desc, size_t ndesc);
int keydb_search_first (KEYDB_HANDLE hd);
diff --git a/g10/keyring.c b/g10/keyring.c
index a55dcc621..b0dabe740 100644
--- a/g10/keyring.c
+++ b/g10/keyring.c
@@ -32,6 +32,7 @@
#include "packet.h"
#include "keydb.h"
#include "options.h"
+#include "main.h" /*for check_key_signature()*/
#include "i18n.h"
typedef struct keyring_name *KR_NAME;
@@ -219,7 +220,7 @@ keyring_get_keyblock (KEYRING_HANDLE hd, KBNODE *ret_kb)
{
PACKET *pkt;
int rc;
- KBNODE keyblock = NULL, node;
+ KBNODE keyblock = NULL, node, lastnode;
IOBUF a;
int in_cert = 0;
int pk_no = 0;
@@ -246,6 +247,7 @@ keyring_get_keyblock (KEYRING_HANDLE hd, KBNODE *ret_kb)
pkt = m_alloc (sizeof *pkt);
init_packet (pkt);
hd->found.n_packets = 0;;
+ lastnode = NULL;
while ((rc=parse_packet (a, pkt)) != -1) {
hd->found.n_packets++;
if (rc == G10ERR_UNKNOWN_PACKET) {
@@ -273,36 +275,64 @@ keyring_get_keyblock (KEYRING_HANDLE hd, KBNODE *ret_kb)
}
in_cert = 1;
- node = new_kbnode (pkt);
- if (!keyblock)
- keyblock = node;
- else
- add_kbnode (keyblock, node);
-
- if ( pkt->pkttype == PKT_PUBLIC_KEY
- || pkt->pkttype == PKT_PUBLIC_SUBKEY
- || pkt->pkttype == PKT_SECRET_KEY
- || pkt->pkttype == PKT_SECRET_SUBKEY) {
- if (++pk_no == hd->found.pk_no)
- node->flag |= 1;
+ if (pkt->pkttype == PKT_RING_TRUST) {
+ /*(this code is duplicated after the loop)*/
+ if ( lastnode
+ && lastnode->pkt->pkttype == PKT_SIGNATURE
+ && (pkt->pkt.ring_trust->sigcache & 1) ) {
+ /* this is a ring trust packet with a checked signature
+ * status cache following directly a signature paket.
+ * Set the cache status into that signature packet */
+ PKT_signature *sig = lastnode->pkt->pkt.signature;
+
+ sig->flags.checked = 1;
+ sig->flags.valid = !!(pkt->pkt.ring_trust->sigcache & 2);
+ }
+ /* reset lastnode, so that we set the cache status only from
+ * the ring trust packet immediately folling a signature */
+ lastnode = NULL;
}
- else if ( pkt->pkttype == PKT_USER_ID) {
- if (++uid_no == hd->found.uid_no)
- node->flag |= 2;
+ else {
+ node = lastnode = new_kbnode (pkt);
+ if (!keyblock)
+ keyblock = node;
+ else
+ add_kbnode (keyblock, node);
+
+ if ( pkt->pkttype == PKT_PUBLIC_KEY
+ || pkt->pkttype == PKT_PUBLIC_SUBKEY
+ || pkt->pkttype == PKT_SECRET_KEY
+ || pkt->pkttype == PKT_SECRET_SUBKEY) {
+ if (++pk_no == hd->found.pk_no)
+ node->flag |= 1;
+ }
+ else if ( pkt->pkttype == PKT_USER_ID) {
+ if (++uid_no == hd->found.uid_no)
+ node->flag |= 2;
+ }
}
pkt = m_alloc (sizeof *pkt);
init_packet(pkt);
}
- if (rc == -1 && keyblock)
+ if (rc == -1 && keyblock)
rc = 0; /* got the entire keyblock */
if (rc || !ret_kb)
release_kbnode (keyblock);
- else
+ else {
+ /*(duplicated form the loop body)*/
+ if ( pkt && pkt->pkttype == PKT_RING_TRUST
+ && lastnode
+ && lastnode->pkt->pkttype == PKT_SIGNATURE
+ && (pkt->pkt.ring_trust->sigcache & 1) ) {
+ PKT_signature *sig = lastnode->pkt->pkt.signature;
+ sig->flags.checked = 1;
+ sig->flags.valid = !!(pkt->pkt.ring_trust->sigcache & 2);
+ }
*ret_kb = keyblock;
-
+ }
free_packet (pkt);
m_free (pkt);
iobuf_close(a);
@@ -874,6 +904,285 @@ keyring_search (KEYRING_HANDLE hd, KEYDB_SEARCH_DESC *desc, size_t ndesc)
}
+
+static int
+create_tmp_file (const char *template,
+ char **r_bakfname, char **r_tmpfname, IOBUF *r_fp)
+{
+ char *bakfname, *tmpfname;
+
+ *r_bakfname = NULL;
+ *r_tmpfname = NULL;
+
+# ifdef USE_ONLY_8DOT3
+ /* Here is another Windoze bug?:
+ * you cant rename("pubring.gpg.tmp", "pubring.gpg");
+ * but rename("pubring.gpg.tmp", "pubring.aaa");
+ * works. So we replace .gpg by .bak or .tmp
+ */
+ if (strlen (template) > 4
+ && !strcmp (template+strlen(template)-4, EXTSEP_S "gpg") )
+ {
+ bakfname = m_alloc (strlen (template) + 1);
+ strcpy (bakfname, template);
+ strcpy (bakfname+strlen(template)-4, EXTSEP_S "bak");
+
+ tmpfname = m_alloc (strlen( template ) + 1 );
+ strcpy (tmpfname,template);
+ strcpy (tmpfname+strlen(template)-4, EXTSEP_S "tmp");
+ }
+ else
+ { /* file does not end with gpg; hmmm */
+ bakfname = m_alloc (strlen( template ) + 5);
+ strcpy (stpcpy(bakfname, template), EXTSEP_S "bak");
+
+ tmpfname = m_alloc (strlen( template ) + 5);
+ strcpy (stpcpy(tmpfname, template), EXTSEP_S "tmp");
+ }
+# else /* Posix file names */
+ bakfname = m_alloc (strlen( template ) + 2);
+ strcpy (stpcpy (bakfname,template),"~");
+
+ tmpfname = m_alloc (strlen( template ) + 5);
+ strcpy (stpcpy(tmpfname,template), EXTSEP_S "tmp");
+# endif /* Posix filename */
+
+ *r_fp = iobuf_create (tmpfname);
+ if (!*r_fp) {
+ log_error ("can't create `%s': %s\n", tmpfname, strerror(errno) );
+ m_free (tmpfname);
+ m_free (bakfname);
+ return G10ERR_OPEN_FILE;
+ }
+
+ *r_bakfname = bakfname;
+ *r_tmpfname = tmpfname;
+ return 0;
+}
+
+
+static int
+rename_tmp_file (const char *bakfname, const char *tmpfname,
+ const char *fname, int secret )
+{
+ int rc=0;
+
+ /* restrict the permissions for secret keyrings */
+#ifndef HAVE_DOSISH_SYSTEM
+ if (secret && !opt.preserve_permissions)
+ {
+ if (chmod (tmpfname, S_IRUSR | S_IWUSR) )
+ {
+ log_error ("chmod of `%s' failed: %s\n",
+ tmpfname, strerror(errno) );
+ return G10ERR_WRITE_FILE;
+ }
+ }
+#endif
+
+ /* invalidate close caches*/
+ iobuf_ioctl (NULL, 2, 0, (char*)tmpfname );
+ iobuf_ioctl (NULL, 2, 0, (char*)bakfname );
+ iobuf_ioctl (NULL, 2, 0, (char*)fname );
+
+ /* first make a backup file except for secret keyrings */
+ if (!secret)
+ {
+#if defined(HAVE_DOSISH_SYSTEM) || defined(__riscos__)
+ remove (bakfname);
+#endif
+ if (rename (fname, bakfname) )
+ {
+ log_error ("renaming `%s' to `%s' failed: %s\n",
+ fname, bakfname, strerror(errno) );
+ return G10ERR_RENAME_FILE;
+ }
+ }
+
+ /* then rename the file */
+#if defined(HAVE_DOSISH_SYSTEM) || defined(__riscos__)
+ remove( fname );
+#endif
+ if (rename (tmpfname, fname) )
+ {
+ log_error ("renaming `%s' to `%s' failed: %s\n",
+ tmpfname, fname, strerror(errno) );
+ rc = G10ERR_RENAME_FILE;
+ if (secret)
+ {
+ log_info(_("WARNING: 2 files with confidential"
+ " information exists.\n"));
+ log_info(_("%s is the unchanged one\n"), fname );
+ log_info(_("%s is the new one\n"), tmpfname );
+ log_info(_("Please fix this possible security flaw\n"));
+ }
+ return rc;
+ }
+
+ return 0;
+}
+
+
+static int
+write_keyblock (IOBUF fp, KBNODE keyblock)
+{
+ KBNODE kbctx = NULL, node;
+ int rc;
+
+ while ( (node = walk_kbnode (keyblock, &kbctx, 0)) )
+ {
+ if (node->pkt->pkttype == PKT_RING_TRUST)
+ continue; /* we write it later on our own */
+
+ if ( (rc = build_packet (fp, node->pkt) ))
+ {
+ log_error ("build_packet(%d) failed: %s\n",
+ node->pkt->pkttype, g10_errstr(rc) );
+ return rc;
+ }
+ if (node->pkt->pkttype == PKT_SIGNATURE)
+ { /* always write a signature cache packet */
+ PKT_signature *sig = node->pkt->pkt.signature;
+ unsigned int cacheval = 0;
+
+ if (sig->flags.checked)
+ {
+ cacheval |= 1;
+ if (sig->flags.valid)
+ cacheval |= 2;
+ }
+ iobuf_put (fp, 0xb0); /* old style packet 12, 1 byte len*/
+ iobuf_put (fp, 2); /* 2 bytes */
+ iobuf_put (fp, 0); /* unused */
+ if (iobuf_put (fp, cacheval)) {
+ log_error ("writing sigcache packet failed\n");
+ return G10ERR_WRITE_FILE;
+ }
+ }
+ }
+ return 0;
+}
+
+/*
+ * Walk over all public keyrings, check the signatures and replace the
+ * keyring with a new one where the signature cache is then updated.
+ * This is only done for the public keyrings.
+ */
+int
+keyring_rebuild_cache ()
+{
+ KEYRING_HANDLE hd;
+ KEYDB_SEARCH_DESC desc;
+ KBNODE keyblock = NULL, node;
+ const char *lastresname = NULL, *resname;
+ IOBUF tmpfp = NULL;
+ char *tmpfilename = NULL;
+ char *bakfilename = NULL;
+ int rc;
+ ulong count = 0, sigcount = 0;
+
+ hd = keyring_new (0);
+ memset (&desc, 0, sizeof desc);
+ desc.mode = KEYDB_SEARCH_MODE_FIRST;
+
+ while ( !(rc = keyring_search (hd, &desc, 1)) )
+ {
+ desc.mode = KEYDB_SEARCH_MODE_NEXT;
+ resname = keyring_get_resource_name (hd);
+ if (lastresname != resname )
+ { /* we have switched to a new keyring - commit changes */
+ if (tmpfp)
+ {
+ if (iobuf_close (tmpfp))
+ {
+ log_error ("error closing `%s': %s\n",
+ tmpfilename, strerror (errno));
+ rc = G10ERR_CLOSE_FILE;
+ goto leave;
+ }
+ /* because we have switched resources, we can be sure that
+ * the original file is closed */
+ tmpfp = NULL;
+ }
+ rc = lastresname? rename_tmp_file (bakfilename, tmpfilename,
+ lastresname, 0) : 0;
+ m_free (tmpfilename); tmpfilename = NULL;
+ m_free (bakfilename); bakfilename = NULL;
+ if (rc)
+ goto leave;
+ lastresname = resname;
+ if (!opt.quiet)
+ log_info (_("checking keyring `%s'\n"), resname);
+ rc = create_tmp_file (resname, &bakfilename, &tmpfilename, &tmpfp);
+ if (rc)
+ goto leave;
+ }
+
+ release_kbnode (keyblock);
+ rc = keyring_get_keyblock (hd, &keyblock);
+ if (rc)
+ {
+ log_error ("keyring_get_keyblock failed: %s\n", g10_errstr(rc));
+ goto leave;
+ }
+ assert (keyblock->pkt->pkttype == PKT_PUBLIC_KEY);
+
+ /* check all signature to set the signature's cache flags */
+ for (node=keyblock; node; node=node->next)
+ {
+ if (node->pkt->pkttype == PKT_SIGNATURE)
+ {
+ check_key_signature (keyblock, node, NULL);
+ sigcount++;
+ }
+ }
+
+ /* write the keyblock to the temporary file */
+ rc = write_keyblock (tmpfp, keyblock);
+ if (rc)
+ goto leave;
+
+ if ( !(++count % 50) && !opt.quiet)
+ log_info(_("%lu keys so far checked (%lu signatures)\n"),
+ count, sigcount );
+
+ } /* end main loop */
+ if (rc == -1)
+ rc = 0;
+ if (rc)
+ {
+ log_error ("keyring_search failed: %s\n", g10_errstr(rc));
+ goto leave;
+ }
+ log_info(_("%lu keys checked (%lu signatures)\n"), count, sigcount );
+ if (tmpfp)
+ {
+ if (iobuf_close (tmpfp))
+ {
+ log_error ("error closing `%s': %s\n",
+ tmpfilename, strerror (errno));
+ rc = G10ERR_CLOSE_FILE;
+ goto leave;
+ }
+ /* because we have switched resources, we can be sure that
+ * the original file is closed */
+ tmpfp = NULL;
+ }
+ rc = lastresname? rename_tmp_file (bakfilename, tmpfilename,
+ lastresname, 0) : 0;
+ m_free (tmpfilename); tmpfilename = NULL;
+ m_free (bakfilename); bakfilename = NULL;
+
+ leave:
+ if (tmpfp)
+ iobuf_cancel (tmpfp);
+ m_free (tmpfilename);
+ m_free (bakfilename);
+ release_kbnode (keyblock);
+ keyring_release (hd);
+ return rc;
+}
+
/****************
* Perform insert/delete/update operation.
@@ -932,38 +1241,9 @@ do_copy (int mode, const char *fname, KBNODE root, int secret,
}
/* create the new file */
- #ifdef USE_ONLY_8DOT3
- /* Here is another Windoze bug?:
- * you cant rename("pubring.gpg.tmp", "pubring.gpg");
- * but rename("pubring.gpg.tmp", "pubring.aaa");
- * works. So we replace .gpg by .bak or .tmp
- */
- if( strlen (fname) > 4
- && !strcmp (fname+strlen(fname)-4, EXTSEP_S "gpg") ) {
- bakfname = m_alloc( strlen (fname) + 1 );
- strcpy(bakfname, fname);
- strcpy(bakfname+strlen(fname)-4, EXTSEP_S "bak");
- tmpfname = m_alloc( strlen( fname ) + 1 );
- strcpy(tmpfname,fname);
- strcpy(tmpfname+strlen(fname)-4, EXTSEP_S "tmp");
- }
- else { /* file does not end with gpg; hmmm */
- bakfname = m_alloc( strlen( fname ) + 5 );
- strcpy(stpcpy(bakfname, fname), EXTSEP_S "bak");
- tmpfname = m_alloc( strlen( fname ) + 5 );
- strcpy(stpcpy(tmpfname, fname), EXTSEP_S "tmp");
- }
- #else
- bakfname = m_alloc( strlen( fname ) + 2 );
- strcpy(stpcpy(bakfname,fname),"~");
- tmpfname = m_alloc( strlen( fname ) + 5 );
- strcpy(stpcpy(tmpfname,fname), EXTSEP_S "tmp");
- #endif
- newfp = iobuf_create (tmpfname);
- if (!newfp) {
- log_error ("%s: can't create: %s\n", tmpfname, strerror(errno) );
+ rc = create_tmp_file (fname, &bakfname, &tmpfname, &newfp);
+ if (rc) {
iobuf_close(fp);
- rc = G10ERR_OPEN_FILE;
goto leave;
}
@@ -1003,20 +1283,12 @@ do_copy (int mode, const char *fname, KBNODE root, int secret,
}
if( mode == 1 || mode == 3 ) { /* insert or update */
- KBNODE kbctx, node;
-
- /* append the new data */
- kbctx=NULL;
- while( (node = walk_kbnode( root, &kbctx, 0 )) ) {
- if( (rc = build_packet( newfp, node->pkt )) ) {
- log_error("build_packet(%d) failed: %s\n",
- node->pkt->pkttype, g10_errstr(rc) );
- iobuf_close(fp);
- iobuf_cancel(newfp);
- rc = G10ERR_WRITE_FILE;
- goto leave;
- }
- }
+ rc = write_keyblock (newfp, root);
+ if (rc) {
+ iobuf_close(fp);
+ iobuf_cancel(newfp);
+ goto leave;
+ }
}
if( mode == 2 || mode == 3 ) { /* delete or update */
@@ -1043,58 +1315,11 @@ do_copy (int mode, const char *fname, KBNODE root, int secret,
rc = G10ERR_CLOSE_FILE;
goto leave;
}
- /* if the new file is a secring, restrict the permissions */
- #ifndef HAVE_DOSISH_SYSTEM
- if( secret && !opt.preserve_permissions ) {
- if( chmod( tmpfname, S_IRUSR | S_IWUSR ) ) {
- log_error("%s: chmod failed: %s\n",
- tmpfname, strerror(errno) );
- rc = G10ERR_WRITE_FILE;
- goto leave;
- }
- }
- #endif
- /* rename and make backup file */
- if( !secret ) { /* but not for secret keyrings */
- iobuf_ioctl (NULL, 2, 0, (char *)bakfname );
- iobuf_ioctl (NULL, 2, 0, (char *)fname );
- #if defined(HAVE_DOSISH_SYSTEM) || defined(__riscos__)
- remove( bakfname );
- #endif
- if( rename( fname, bakfname ) ) {
- log_error("%s: rename to `%s' failed: %s\n",
- fname, bakfname, strerror(errno) );
- rc = G10ERR_RENAME_FILE;
- goto leave;
- }
- }
- iobuf_ioctl (NULL, 2, 0, (char*)tmpfname );
- iobuf_ioctl (NULL, 2, 0, (char*)fname );
- #if defined(HAVE_DOSISH_SYSTEM) || defined(__riscos__)
- remove( fname );
- #endif
- if( rename( tmpfname, fname ) ) {
- log_error("%s: rename to `%s' failed: %s\n",
- tmpfname, fname,strerror(errno) );
- rc = G10ERR_RENAME_FILE;
- if( secret ) {
- log_info(_(
- "WARNING: 2 files with confidential information exists.\n"));
- log_info(_("%s is the unchanged one\n"), fname );
- log_info(_("%s is the new one\n"), tmpfname );
- log_info(_("Please fix this possible security flaw\n"));
- }
- goto leave;
- }
+ rc = rename_tmp_file (bakfname, tmpfname, fname, secret);
leave:
m_free(bakfname);
m_free(tmpfname);
return rc;
}
-
-
-
-
-
diff --git a/g10/keyring.h b/g10/keyring.h
index 253b86eab..141df45ea 100644
--- a/g10/keyring.h
+++ b/g10/keyring.h
@@ -39,6 +39,6 @@ int keyring_insert_keyblock (KEYRING_HANDLE hd, KBNODE kb);
int keyring_delete_keyblock (KEYRING_HANDLE hd);
int keyring_search_reset (KEYRING_HANDLE hd);
int keyring_search (KEYRING_HANDLE hd, KEYDB_SEARCH_DESC *desc, size_t ndesc);
-
+int keyring_rebuild_cache (void);
#endif /*GPG_KEYRING_H*/
diff --git a/g10/keyring.o b/g10/keyring.o
index a188ed024..66731335e 100644
Binary files a/g10/keyring.o and b/g10/keyring.o differ
diff --git a/g10/options.h b/g10/options.h
index b6cf4a668..5995d7da6 100644
--- a/g10/options.h
+++ b/g10/options.h
@@ -109,7 +109,6 @@ struct {
int show_session_key;
int use_agent;
int merge_only;
- int allow_secret_key_import;
int try_all_secrets;
int no_expensive_trust_checks;
int no_sig_cache;
diff --git a/g10/packet.h b/g10/packet.h
index d3e7ddd91..4cdf04474 100644
--- a/g10/packet.h
+++ b/g10/packet.h
@@ -235,6 +235,7 @@ typedef struct {
typedef struct {
unsigned int trustval;
+ unsigned int sigcache;
} PKT_ring_trust;
typedef struct {
@@ -306,7 +307,7 @@ typedef enum {
SIGSUBPKT_SIGNERS_UID =28, /* signer's user id */
SIGSUBPKT_REVOC_REASON =29, /* reason for revocation */
SIGSUBPKT_FEATURES =30, /* feature flags */
- SIGSUBPKT_PRIV_VERIFY_CACHE =101, /* cache verification result */
+ SIGSUBPKT_PRIV_VERIFY_CACHE =101, /* cache verification result (obsolete)*/
SIGSUBPKT_FLAG_CRITICAL=128
} sigsubpkttype_t;
diff --git a/g10/parse-packet.c b/g10/parse-packet.c
index 696428d2a..4f935768b 100644
--- a/g10/parse-packet.c
+++ b/g10/parse-packet.c
@@ -883,7 +883,7 @@ dump_sig_subpkt( int hashed, int type, int critical,
printf(" %02x", buffer[i] );
break;
case SIGSUBPKT_PRIV_VERIFY_CACHE:
- p = "verification cache";
+ p = "obsolete verification cache";
break;
default: p = "?"; break;
}
@@ -936,7 +936,9 @@ parse_one_sig_subpkt( const byte *buffer, size_t n, int type )
break;
return 0;
case SIGSUBPKT_PRIV_VERIFY_CACHE:
- /* "GPG" 0x00
+ /* We used this in gpg 1.0.5 and 1.0.6 to cache signature
+ * verification results - it is no longer used.
+ * "GPG" 0x00
* where mode == 1: valid data, stat == 0: invalid signature
* stat == 1: valid signature
* (because we use private data, we check our marker) */
@@ -1732,8 +1734,18 @@ parse_trust( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *pkt )
c = iobuf_get_noeof(inp);
pkt->pkt.ring_trust = m_alloc( sizeof *pkt->pkt.ring_trust );
pkt->pkt.ring_trust->trustval = c;
+ pkt->pkt.ring_trust->sigcache = 0;
+ if (!c && pktlen==2) {
+ c = iobuf_get_noeof (inp);
+ /* we require that bit 7 of the sigcache is 0 (easier eof handling)*/
+ if ( !(c & 0x80) )
+ pkt->pkt.ring_trust->sigcache = c;
+ }
if( list_mode )
- printf(":trust packet: flag=%02x\n", c );
+ printf(":trust packet: flag=%02x sigcache=%02x\n",
+ pkt->pkt.ring_trust->trustval,
+ pkt->pkt.ring_trust->sigcache);
+
}
diff --git a/g10/sig-check.c b/g10/sig-check.c
index fe63a1381..754bc2fd7 100644
--- a/g10/sig-check.c
+++ b/g10/sig-check.c
@@ -120,96 +120,6 @@ do_signature_check( PKT_signature *sig, MD_HANDLE digest,
}
-#if 0 /* not anymore used */
-/****************
- * Check the MDC which is contained in SIG.
- * The MD_HANDLE should be currently open, so that this function
- * is able to append some data, before finalizing the digest.
- */
-int
-mdc_kludge_check( PKT_signature *sig, MD_HANDLE digest )
-{
- int rc=0;
-
- if( (rc=check_digest_algo(sig->digest_algo)) )
- return rc;
-
- /* make sure the digest algo is enabled (in case of a detached mdc??) */
- md_enable( digest, sig->digest_algo );
-
- /* complete the digest */
- if( sig->version >= 4 )
- md_putc( digest, sig->version );
- md_putc( digest, sig->sig_class );
- if( sig->version < 4 ) {
- u32 a = sig->timestamp;
- md_putc( digest, (a >> 24) & 0xff );
- md_putc( digest, (a >> 16) & 0xff );
- md_putc( digest, (a >> 8) & 0xff );
- md_putc( digest, a & 0xff );
- }
- else {
- byte buf[6];
- size_t n;
- md_putc( digest, sig->pubkey_algo );
- md_putc( digest, sig->digest_algo );
- if( sig->hashed ) {
- n = sig->hashed->len;
- md_putc (digest, (n >> 8) );
- md_putc (digest, n );
- md_write (digest, sig->hashed->data, n);
- n += 6;
- }
- else
- n = 6;
- /* add some magic */
- buf[0] = sig->version;
- buf[1] = 0xff;
- buf[2] = n >> 24;
- buf[3] = n >> 16;
- buf[4] = n >> 8;
- buf[5] = n;
- md_write( digest, buf, 6 );
- }
- md_final( digest );
-
- rc = G10ERR_BAD_SIGN;
- { const byte *s1 = md_read( digest, sig->digest_algo );
- int s1len = md_digest_length( sig->digest_algo );
-
- log_hexdump( "MDC calculated", s1, s1len );
-
- if( !sig->data[0] )
- log_debug("sig_data[0] is NULL\n");
- else {
- unsigned s2len;
- byte *s2;
- s2 = mpi_get_buffer( sig->data[0], &s2len, NULL );
- log_hexdump( "MDC stored ", s2, s2len );
-
- if( s2len != s1len )
- log_debug("MDC check: len differ: %d/%d\n", s1len, s2len);
- else if( memcmp( s1, s2, s1len ) )
- log_debug("MDC check: hashs differ\n");
- else
- rc = 0;
- m_free(s2);
- }
- }
-
- if( !rc && sig->flags.unknown_critical ) {
- log_info(_("assuming bad MDC due to an unknown critical bit\n"));
- rc = G10ERR_BAD_SIGN;
- }
- sig->flags.checked = 1;
- sig->flags.valid = !rc;
-
- /* FIXME: check that we are actually in an encrypted packet */
-
- return rc;
-}
-#endif
-
/****************
* This function gets called by pubkey_verify() if the algorithm needs it.
*/
@@ -402,8 +312,6 @@ do_check( PKT_public_key *pk, PKT_signature *sig, MD_HANDLE digest,
log_info(_("assuming bad signature due to an unknown critical bit\n"));
rc = G10ERR_BAD_SIGN;
}
- sig->flags.checked = 1;
- sig->flags.valid = !rc;
return rc;
}
@@ -442,31 +350,20 @@ hash_uid_node( KBNODE unode, MD_HANDLE md, PKT_signature *sig )
}
static void
-cache_selfsig_result ( PKT_signature *sig, int result )
+cache_sig_result ( PKT_signature *sig, int result )
{
- byte buf[6];
-
- if ( opt.no_sig_cache )
- return;
-
- buf[0] = 'G';
- buf[1] = 'P';
- buf[2] = 'G';
- buf[3] = 0;
if ( !result ) {
- buf[4] = 1; /* mark cache valid */
- buf[5] = 1; /* mark signature valid */
+ sig->flags.checked = 1;
+ sig->flags.valid = 1;
}
else if ( result == G10ERR_BAD_SIGN ) {
- buf[4] = 1; /* mark cache valid */
- buf[5] = 0; /* mark signature invalid */
+ sig->flags.checked = 1;
+ sig->flags.valid = 0;
}
else {
- buf[4] = 0; /* mark cache invalid */
- buf[5] = 0;
+ sig->flags.checked = 0;
+ sig->flags.valid = 0;
}
-
- build_sig_subpkt (sig, SIGSUBPKT_PRIV_VERIFY_CACHE, buf, 6 );
}
/****************
@@ -503,20 +400,9 @@ check_key_signature2( KBNODE root, KBNODE node, int *is_selfsig,
sig = node->pkt->pkt.signature;
algo = sig->digest_algo;
- #if 0 /* I am not sure whether this is a good thing to do */
- if( sig->flags.checked )
- log_debug("check_key_signature: already checked: %s\n",
- sig->flags.valid? "good":"bad" );
- #endif
-
- /* Check whether we have cached the result of a previous signature check.*/
+ /* check whether we have cached the result of a previous signature check.*/
if ( !opt.no_sig_cache ) {
- const byte *p;
- size_t len;
-
- p = parse_sig_subpkt( sig->unhashed,
- SIGSUBPKT_PRIV_VERIFY_CACHE, &len );
- if ( p && len >= 2 && p[0] == 1 ) { /* cache hit */
+ if (sig->flags.checked) { /*cached status available*/
if( is_selfsig ) {
u32 keyid[2];
@@ -524,7 +410,7 @@ check_key_signature2( KBNODE root, KBNODE node, int *is_selfsig,
if( keyid[0] == sig->keyid[0] && keyid[1] == sig->keyid[1] )
*is_selfsig = 1;
}
- return p[1] == 1? 0 : G10ERR_BAD_SIGN;
+ return sig->flags.valid? 0 : G10ERR_BAD_SIGN;
}
}
@@ -535,7 +421,7 @@ check_key_signature2( KBNODE root, KBNODE node, int *is_selfsig,
md = md_open( algo, 0 );
hash_public_key( md, pk );
rc = do_check( pk, sig, md, r_expired );
- cache_selfsig_result ( sig, rc );
+ cache_sig_result ( sig, rc );
md_close(md);
}
else if( sig->sig_class == 0x28 ) { /* subkey revocation */
@@ -546,7 +432,7 @@ check_key_signature2( KBNODE root, KBNODE node, int *is_selfsig,
hash_public_key( md, pk );
hash_public_key( md, snode->pkt->pkt.public_key );
rc = do_check( pk, sig, md, r_expired );
- cache_selfsig_result ( sig, rc );
+ cache_sig_result ( sig, rc );
md_close(md);
}
else {
@@ -571,7 +457,7 @@ check_key_signature2( KBNODE root, KBNODE node, int *is_selfsig,
hash_public_key( md, pk );
hash_public_key( md, snode->pkt->pkt.public_key );
rc = do_check( pk, sig, md, r_expired );
- cache_selfsig_result ( sig, rc );
+ cache_sig_result ( sig, rc );
md_close(md);
}
else {
@@ -585,7 +471,7 @@ check_key_signature2( KBNODE root, KBNODE node, int *is_selfsig,
md = md_open( algo, 0 );
hash_public_key( md, pk );
rc = do_check( pk, sig, md, r_expired );
- cache_selfsig_result ( sig, rc );
+ cache_sig_result ( sig, rc );
md_close(md);
}
else { /* all other classes */
@@ -602,11 +488,11 @@ check_key_signature2( KBNODE root, KBNODE node, int *is_selfsig,
if( is_selfsig )
*is_selfsig = 1;
rc = do_check( pk, sig, md, r_expired );
- cache_selfsig_result ( sig, rc );
}
else {
rc = do_signature_check( sig, md, r_expiredate, r_expired );
}
+ cache_sig_result ( sig, rc );
md_close(md);
}
else {
diff --git a/g10/tdbio.c b/g10/tdbio.c
index 0ef1ec086..59bcc8530 100644
--- a/g10/tdbio.c
+++ b/g10/tdbio.c
@@ -768,7 +768,7 @@ upd_hashtable( ulong table, byte *key, int keylen, ulong newrecnum )
rc = tdbio_read_record( rec.r.hlst.next,
&rec, RECTYPE_HLST);
if( rc ) {
- log_error( "scan keyhashtbl read hlst failed: %s\n",
+ log_error( "upd_hashtable: read hlst failed: %s\n",
g10_errstr(rc) );
return rc;
}
@@ -923,7 +923,7 @@ drop_from_hashtable( ulong table, byte *key, int keylen, ulong recnum )
rc = tdbio_read_record( rec.r.hlst.next,
&rec, RECTYPE_HLST);
if( rc ) {
- log_error( "scan keyhashtbl read hlst failed: %s\n",
+ log_error( "drop_from_hashtable: read hlst failed: %s\n",
g10_errstr(rc) );
return rc;
}
diff --git a/g10/trustdb.c b/g10/trustdb.c
index 9ed3a2860..fb06e858d 100644
--- a/g10/trustdb.c
+++ b/g10/trustdb.c
@@ -718,9 +718,11 @@ get_validity (PKT_public_key *pk, const byte *namehash)
if ( (trec.r.trust.ownertrust & TRUST_FLAG_DISABLED) )
validity |= TRUST_FLAG_DISABLED;
- /* for convenience set some flags from the key */
+ /* set some flags direct from the key */
if (pk->is_revoked)
validity |= TRUST_FLAG_REVOKED;
+ /* Note: expiration is a trust value and not a flag - don't know why
+ * I initially designed it that way */
if (pk->has_expired)
validity = (validity & ~TRUST_MASK) | TRUST_EXPIRED;
@@ -879,6 +881,9 @@ make_key_array (KEYDB_HANDLE hd, KeyHashTable visited,
desc.mode = KEYDB_SEARCH_MODE_NEXT; /* change mode */
do
{
+ PKT_public_key *pk;
+ u32 kid[2];
+
rc = keydb_get_keyblock (hd, &keyblock);
if (rc)
{
@@ -896,18 +901,25 @@ make_key_array (KEYDB_HANDLE hd, KeyHashTable visited,
continue;
}
+ /* prepare the keyblock for further processing */
+ merge_keys_and_selfsig (keyblock);
clear_kbnode_flags (keyblock);
- if (cmpfnc (keyblock, cmpval))
- {
- u32 kid[2];
+ pk = keyblock->pkt->pkt.public_key;
+ keyid_from_pk (pk, kid); /*(cheap: should already be cached in the pk)*/
+ if (pk->has_expired || pk->is_revoked)
+ {
+ /* it does not make sense to look further at those keys */
+ add_key_hash_table (visited, kid);
+ }
+ else if (cmpfnc (keyblock, cmpval))
+ {
if (nkeys == maxkeys) {
maxkeys += 1000;
keys = m_realloc (keys, (maxkeys+1) * sizeof *keys);
}
keys[nkeys++].keyblock = keyblock;
/* This key is signed - don't check it again */
- keyid_from_pk (keyblock->pkt->pkt.public_key, kid);
add_key_hash_table (visited, kid);
}
else
@@ -1018,10 +1030,11 @@ cmp_kid_for_make_key_array (KBNODE kb, void *opaque)
struct key_item *klist = opaque;
struct key_item *kr;
KBNODE node, uidnode=NULL;
+ PKT_public_key *pk = kb->pkt->pkt.public_key;
u32 main_kid[2];
int issigned=0, any_signed = 0, fully_count =0, marginal_count = 0;
- keyid_from_pk(kb->pkt->pkt.public_key, main_kid);
+ keyid_from_pk(pk, main_kid);
for (node=kb; node; node = node->next)
{
if (node->pkt->pkttype == PKT_USER_ID)