aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--NEWS9
-rw-r--r--TODO6
-rw-r--r--g10/ChangeLog16
-rw-r--r--g10/build-packet.c96
-rw-r--r--g10/export.c4
-rw-r--r--g10/g10.c1
-rw-r--r--g10/import.c17
-rw-r--r--g10/keylist.c2
-rw-r--r--g10/packet.h3
-rw-r--r--g10/parse-packet.c18
-rw-r--r--g10/sig-check.c50
11 files changed, 205 insertions, 17 deletions
diff --git a/NEWS b/NEWS
index 426f81135..0729c5c11 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,12 @@
+
+ * The verification status of self-signatures are now cached. To increase
+ the speed of key list operations for existing keys you can do the
+ following in yout GnuPG homedir (~/.gnupg):
+ $ cp pubring.gpg pubring.gpg.save
+ $ gpg --export-all >x
+ $ rm pubring.gpg
+ $ gpg --import x
+ Note, that only v4 keys (i.e no old RSA keys) benefit from this caching.
* WARNING: The semantics of --verify have changed to address a problem
with detached signature detection. --verify now ignores signed material
diff --git a/TODO b/TODO
index 447667a06..564c37daf 100644
--- a/TODO
+++ b/TODO
@@ -1,6 +1,10 @@
+ * Dlopen does not yet work under W32.
+
+ * key selection is far too slow (due to all the signature checks)
+
* check whether we can remove all the expire stuff in trustdb because this
- is now done getkey.
+ is now done in getkey.
* ask for alternate filename?
diff --git a/g10/ChangeLog b/g10/ChangeLog
index e21ec46e9..9518b5402 100644
--- a/g10/ChangeLog
+++ b/g10/ChangeLog
@@ -1,3 +1,19 @@
+2001-03-05 Werner Koch <[email protected]>
+
+ * packet.h: Replaced sigsubpkt_t value 101 by PRIV_VERIFY_CACHE.
+ We have never used the old value, so we can do this without any harm.
+ * parse-packet.c (dump_sig_subpkt): Ditto.
+ (parse_one_sig_subpkt): Parse that new sub packet.
+ * build-packet.c (build_sig_subpkt): Removed the old one from the
+ hashed area.
+ (delete_sig_subpkt): New.
+ (build_sig_subpkt): Allow an update of that new subpkt.
+ * sig-check.c (check_key_signature2): Add verification caching
+ (cache_selfsig_result): New.
+ * export.c (do_export_stream): Delete that sig subpkt before exporting.
+ * import.c (remove_bad_stuff): New.
+ (import): Apply that function to all imported data
+
2001-03-03 Werner Koch <[email protected]>
* getkey.c: Introduced a new lookup context flag "exact" and used
diff --git a/g10/build-packet.c b/g10/build-packet.c
index 0f297b0e7..c4fcb1345 100644
--- a/g10/build-packet.c
+++ b/g10/build-packet.c
@@ -648,13 +648,83 @@ find_subpkt( byte *buffer, sigsubpkttype_t reqtype,
return NULL;
}
+/****************
+ * Delete all subpackets of type REQTYPE and return the number of bytes
+ * which are now unused at the end of the buffer.
+ */
+size_t
+delete_sig_subpkt( byte *buffer, sigsubpkttype_t reqtype )
+{
+ int buflen, orig_buflen;
+ sigsubpkttype_t type;
+ byte *bufstart, *orig_buffer;
+ size_t n;
+ size_t unused = 0;
+ int okay = 0;
+
+ if( !buffer )
+ return 0;
+ orig_buffer = buffer;
+ buflen = (*buffer << 8) | buffer[1];
+ buffer += 2;
+ orig_buflen = buflen;
+ for(;;) {
+ if( !buflen ) {
+ okay = 1;
+ break;
+ }
+ bufstart = buffer;
+ n = *buffer++; buflen--;
+ if( n == 255 ) {
+ if( buflen < 4 )
+ break;
+ n = (buffer[0] << 24) | (buffer[1] << 16)
+ | (buffer[2] << 8) | buffer[3];
+ buffer += 4;
+ buflen -= 4;
+ }
+ else if( n >= 192 ) {
+ if( buflen < 2 )
+ break;
+ n = (( n - 192 ) << 8) + *buffer + 192;
+ buffer++;
+ buflen--;
+ }
+ if( buflen < n )
+ break;
+ type = *buffer & 0x7f;
+ if( type == reqtype ) {
+ buffer++;
+ buflen--;
+ n--;
+ if( n > buflen )
+ break;
+ memmove (bufstart, buffer + n, n + (buffer-bufstart)); /* shift */
+ unused += n + (buffer-bufstart);
+ buffer = bufstart;
+ buflen -= n;
+ }
+ else {
+ buffer += n; buflen -=n;
+ }
+ }
+
+ if (!okay)
+ log_error("delete_subpkt: buffer shorter than subpacket\n");
+ assert (unused <= orig_buflen);
+ orig_buflen -= unused;
+ orig_buffer[0] = (orig_buflen >> 8) & 0xff;
+ orig_buffer[1] = orig_buflen & 0xff;
+ return unused;
+}
+
/****************
* Create or update a signature subpacket for SIG of TYPE.
* This functions knows where to put the data (hashed or unhashed).
- * The function may move data from the unhased part to the hashed one.
+ * The function may move data from the unhashed part to the hashed one.
* Note: All pointers into sig->[un]hashed are not valid after a call
- * to this function. The data to but into the subpaket should be
+ * to this function. The data to put into the subpaket should be
* in buffer with a length of buflen.
*/
void
@@ -666,6 +736,7 @@ build_sig_subpkt( PKT_signature *sig, sigsubpkttype_t type,
int found=0;
int critical, hashed, realloced;
size_t n, n0;
+ size_t unused = 0;
critical = (type & SIGSUBPKT_FLAG_CRITICAL);
type &= ~SIGSUBPKT_FLAG_CRITICAL;
@@ -677,6 +748,12 @@ build_sig_subpkt( PKT_signature *sig, sigsubpkttype_t type,
else if( (data = find_subpkt( sig->unhashed_data, type, &hlen, &dlen )))
found = 2;
+ if (found==2 && type == SIGSUBPKT_PRIV_VERIFY_CACHE) {
+ unused = delete_sig_subpkt (sig->unhashed_data, type);
+ assert (unused);
+ found = 0;
+ }
+
if( found )
log_bug("build_sig_packet: update nyi\n");
if( (buflen+1) >= 8384 )
@@ -688,7 +765,6 @@ build_sig_subpkt( PKT_signature *sig, sigsubpkttype_t type,
switch( type ) {
case SIGSUBPKT_SIG_CREATED:
- case SIGSUBPKT_PRIV_ADD_SIG:
case SIGSUBPKT_PREF_SYM:
case SIGSUBPKT_PREF_HASH:
case SIGSUBPKT_PREF_COMPR:
@@ -713,9 +789,17 @@ build_sig_subpkt( PKT_signature *sig, sigsubpkttype_t type,
n0 = sig->unhashed_data ? ((*sig->unhashed_data << 8)
| sig->unhashed_data[1]) : 0;
n = n0 + nlen + 1 + buflen; /* length, type, buffer */
- realloced = !!sig->unhashed_data;
- data = sig->unhashed_data ? m_realloc( sig->unhashed_data, n+2 )
- : m_alloc( n+2 );
+ if ( sig->unhashed_data && (nlen + 1 + buflen) <= unused ) {
+ /* does fit into the freed area */
+ data = sig->unhashed_data;
+ realloced = 1;
+ log_debug ("updating area of type %d\n", type );
+ }
+ else {
+ realloced = !!sig->unhashed_data;
+ data = sig->unhashed_data ? m_realloc( sig->unhashed_data, n+2 )
+ : m_alloc( n+2 );
+ }
}
if( critical )
diff --git a/g10/export.c b/g10/export.c
index 4c70c7ce5..9e90b560c 100644
--- a/g10/export.c
+++ b/g10/export.c
@@ -197,6 +197,10 @@ do_export_stream( IOBUF out, STRLIST users, int secret, int onlyrfc, int *any )
SIGSUBPKT_EXPORTABLE, NULL );
if( p && !*p )
continue; /* not exportable */
+
+ /* delete our verification cache */
+ delete_sig_subpkt (node->pkt->pkt.signature->unhashed_data,
+ SIGSUBPKT_PRIV_VERIFY_CACHE);
}
if( secret == 2 && node->pkt->pkttype == PKT_SECRET_KEY ) {
diff --git a/g10/g10.c b/g10/g10.c
index f09b4d774..3db9eee3a 100644
--- a/g10/g10.c
+++ b/g10/g10.c
@@ -108,6 +108,7 @@ enum cmd_and_opt_values { aNull = 0,
aEnArmor,
aGenRandom,
aPipeMode,
+ aRefreshCaches,
oTextmode,
oFingerprint,
diff --git a/g10/import.c b/g10/import.c
index fe0512b94..ff721be70 100644
--- a/g10/import.c
+++ b/g10/import.c
@@ -57,6 +57,7 @@ static struct {
static int import( IOBUF inp, int fast, const char* fname, int allow_secret );
static void print_stats(void);
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 );
static int import_secret_one( const char *fname, KBNODE keyblock, int allow );
static int import_revoke_cert( const char *fname, KBNODE node );
@@ -171,6 +172,7 @@ import( IOBUF inp, int fast, const char* fname, int allow_secret )
}
while( !(rc = read_block( inp, &pending_pkt, &keyblock) )) {
+ remove_bad_stuff (keyblock);
if( keyblock->pkt->pkttype == PKT_PUBLIC_KEY )
rc = import_one( fname, keyblock, fast );
else if( keyblock->pkt->pkttype == PKT_SECRET_KEY )
@@ -349,6 +351,21 @@ read_block( IOBUF a, PACKET **pending_pkt, KBNODE *ret_root )
}
+static void
+remove_bad_stuff (KBNODE keyblock)
+{
+ KBNODE node;
+
+ for (node=keyblock; node; node = node->next ) {
+ if( node->pkt->pkttype == PKT_SIGNATURE ) {
+ /* delete the subpackets we use for the verification cache */
+ delete_sig_subpkt (node->pkt->pkt.signature->unhashed_data,
+ SIGSUBPKT_PRIV_VERIFY_CACHE);
+ }
+ }
+}
+
+
/****************
* Try to import one keyblock. Return an error only in serious cases, but
* never for an invalid keyblock. It uses log_error to increase the
diff --git a/g10/keylist.c b/g10/keylist.c
index da7fdb0d2..07a77a1e0 100644
--- a/g10/keylist.c
+++ b/g10/keylist.c
@@ -515,7 +515,7 @@ list_keyblock( KBNODE keyblock, int secret )
if( opt.with_colons )
printf(":%02x:", sig->sig_class );
putchar('\n');
- /* FIXME: check or list other sigs here (subpkt PRIV_ADD_SIG)*/
+ /* fixme: check or list other sigs here */
}
}
if( !any ) {/* oops, no user id */
diff --git a/g10/packet.h b/g10/packet.h
index aef7938b9..cd43dde47 100644
--- a/g10/packet.h
+++ b/g10/packet.h
@@ -272,7 +272,7 @@ typedef enum {
SIGSUBPKT_KEY_FLAGS =27, /* key flags */
SIGSUBPKT_SIGNERS_UID =28, /* signer's user id */
SIGSUBPKT_REVOC_REASON =29, /* reason for revocation */
- SIGSUBPKT_PRIV_ADD_SIG =101,/* signatur is also valid for this uid */
+ SIGSUBPKT_PRIV_VERIFY_CACHE =101, /* cache verification result */
SIGSUBPKT_FLAG_CRITICAL=128
} sigsubpkttype_t;
@@ -331,6 +331,7 @@ void hash_public_key( MD_HANDLE md, PKT_public_key *pk );
void build_sig_subpkt( PKT_signature *sig, sigsubpkttype_t type,
const byte *buffer, size_t buflen );
void build_sig_subpkt_from_sig( PKT_signature *sig );
+size_t delete_sig_subpkt( byte *buffer, sigsubpkttype_t type );
/*-- free-packet.c --*/
void free_symkey_enc( PKT_symkey_enc *enc );
diff --git a/g10/parse-packet.c b/g10/parse-packet.c
index c97e312df..c443b878b 100644
--- a/g10/parse-packet.c
+++ b/g10/parse-packet.c
@@ -848,8 +848,8 @@ dump_sig_subpkt( int hashed, int type, int critical,
printf("%02X", buffer[i] );
}
break;
- case SIGSUBPKT_PRIV_ADD_SIG:
- p = "signs additional user ID";
+ case SIGSUBPKT_PRIV_VERIFY_CACHE:
+ p = "verification cache";
break;
default: p = "?"; break;
}
@@ -900,13 +900,17 @@ parse_one_sig_subpkt( const byte *buffer, size_t n, int type )
if ( n != 1 )
break;
return 0;
- case SIGSUBPKT_PRIV_ADD_SIG:
- /* because we use private data, we check the GNUPG marker */
- if( n < 24 )
+ case SIGSUBPKT_PRIV_VERIFY_CACHE:
+ /* "GPG" 0x00 <mode> <stat>
+ * where mode == 1: valid data, stat == 0: invalid signature
+ * stat == 1: valid signature
+ * (because we use private data, we check our marker) */
+ if( n < 6 )
break;
- if( buffer[0] != 'G' || buffer[1] != 'P' || buffer[2] != 'G' )
+ if( buffer[0] != 'G' || buffer[1] != 'P'
+ || buffer[2] != 'G' || buffer[3] )
return -2;
- return 3;
+ return 4;
default: return -1;
}
return -3;
diff --git a/g10/sig-check.c b/g10/sig-check.c
index 686cf09ff..f8bfe47ee 100644
--- a/g10/sig-check.c
+++ b/g10/sig-check.c
@@ -437,6 +437,31 @@ hash_uid_node( KBNODE unode, MD_HANDLE md, PKT_signature *sig )
}
}
+static void
+cache_selfsig_result ( PKT_signature *sig, int result )
+{
+ byte buf[6];
+
+ 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 */
+ }
+ else if ( result == G10ERR_BAD_SIGN ) {
+ buf[4] = 1; /* mark cache valid */
+ buf[5] = 0; /* mark signature invalid */
+ }
+ else {
+ buf[4] = 0; /* mark cache invalid */
+ buf[5] = 0;
+ }
+
+ build_sig_subpkt (sig, SIGSUBPKT_PRIV_VERIFY_CACHE, buf, 6 );
+}
+
/****************
* check the signature pointed to by NODE. This is a key signature.
* If the function detects a self-signature, it uses the PK from
@@ -477,13 +502,33 @@ check_key_signature2( KBNODE root, KBNODE node, int *is_selfsig,
sig->flags.valid? "good":"bad" );
#endif
+ /* Check whether we have cached the result of a previous signature check.*/
+ {
+ const byte *p;
+ size_t len;
+
+ p = parse_sig_subpkt( sig->unhashed_data,
+ SIGSUBPKT_PRIV_VERIFY_CACHE, &len );
+ if ( p && len >= 2 && p[0] == 1 ) { /* cache hit */
+ if( is_selfsig ) {
+ u32 keyid[2];
+
+ keyid_from_pk( pk, keyid );
+ if( keyid[0] == sig->keyid[0] && keyid[1] == sig->keyid[1] )
+ *is_selfsig = 1;
+ }
+ return p[1] == 1? 0 : G10ERR_BAD_SIGN;
+ }
+ }
+
if( (rc=check_digest_algo(algo)) )
return rc;
- if( sig->sig_class == 0x20 ) {
+ if( sig->sig_class == 0x20 ) { /* key revocation */
md = md_open( algo, 0 );
hash_public_key( md, pk );
rc = do_check( pk, sig, md, r_expired );
+ cache_selfsig_result ( sig, rc );
md_close(md);
}
else if( sig->sig_class == 0x28 ) { /* subkey revocation */
@@ -494,6 +539,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 );
md_close(md);
}
else {
@@ -516,6 +562,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 );
md_close(md);
}
else {
@@ -537,6 +584,7 @@ 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 );