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)