mirror of
git://git.gnupg.org/gnupg.git
synced 2024-12-31 11:41:32 +01:00
Add self-signature verification caching
This commit is contained in:
parent
fbbcb797c5
commit
0bd4fc7359
9
NEWS
9
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
|
||||
|
6
TODO
6
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?
|
||||
|
||||
|
@ -1,3 +1,19 @@
|
||||
2001-03-05 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* 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 <wk@gnupg.org>
|
||||
|
||||
* getkey.c: Introduced a new lookup context flag "exact" and used
|
||||
|
@ -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 )
|
||||
|
@ -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 ) {
|
||||
|
@ -108,6 +108,7 @@ enum cmd_and_opt_values { aNull = 0,
|
||||
aEnArmor,
|
||||
aGenRandom,
|
||||
aPipeMode,
|
||||
aRefreshCaches,
|
||||
|
||||
oTextmode,
|
||||
oFingerprint,
|
||||
|
17
g10/import.c
17
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
|
||||
|
@ -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 */
|
||||
|
@ -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 );
|
||||
|
@ -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;
|
||||
|
@ -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 );
|
||||
|
Loading…
x
Reference in New Issue
Block a user