diff --git a/g10/ChangeLog b/g10/ChangeLog index 723196857..07cc6f5a2 100644 --- a/g10/ChangeLog +++ b/g10/ChangeLog @@ -1,3 +1,26 @@ +2003-12-10 David Shaw + + * packet.h, build-packet.c (hash_public_key): Remove function ... + + * keydb.h, keyid.c (hash_public_key, do_fingerprint_md): ... and + make a new one here that shares code with the fingerprint + calculations. This removes some duplicated functionality, and is + also around 14% faster. (Every bit helps). + + * import.c (import_one): No longer need the Elgamal import + warning. + + * getkey.c (get_pubkey_fast): This one is sort of obscure. + get_pubkey_fast returns the primary key when requesting a subkey, + so if a user has a key signed by a subkey (we don't do this, but + used to), AND that key is not self-signed, AND the algorithm of + the subkey in question is not present in GnuPG, AND the algorithm + of the primary key that owns the subkey in question is present in + GnuPG, then we will try and verify the subkey signature using the + primary key algorithm and hit a BUG(). The fix is to not return a + hit if the keyid is not the primary. All other users of + get_pubkey_fast already expect a primary only. + 2003-12-09 David Shaw * keyid.c (do_fingerprint_md): Remove the rules to hash the old v3 diff --git a/g10/build-packet.c b/g10/build-packet.c index cd0bb8a81..c1022fff5 100644 --- a/g10/build-packet.c +++ b/g10/build-packet.c @@ -254,85 +254,6 @@ do_public_key( IOBUF out, int ctb, PKT_public_key *pk ) } -/**************** - * Make a hash value from the public key certificate - */ -void -hash_public_key( MD_HANDLE md, PKT_public_key *pk ) -{ - PACKET pkt; - int rc = 0; - int ctb; - ulong pktlen; - int c; - IOBUF a = iobuf_temp(); -#if 0 - FILE *fp = fopen("dump.pk", "a"); - int i=0; - - fprintf(fp, "\nHashing PK (v%d):\n", pk->version); -#endif - - /* build the packet */ - init_packet(&pkt); - pkt.pkttype = PKT_PUBLIC_KEY; - pkt.pkt.public_key = pk; - if( (rc = build_packet( a, &pkt )) ) - log_fatal("build public_key for hashing failed: %s\n", g10_errstr(rc)); - - if( !(pk->version == 3 && pk->pubkey_algo == 16) ) { - /* skip the constructed header but don't do this for our very old - * v3 ElG keys */ - ctb = iobuf_get_noeof(a); - pktlen = 0; - if( (ctb & 0x40) ) { - c = iobuf_get_noeof(a); - if( c < 192 ) - pktlen = c; - else if( c < 224 ) { - pktlen = (c - 192) * 256; - c = iobuf_get_noeof(a); - pktlen += c + 192; - } - else if( c == 255 ) { - pktlen = iobuf_get_noeof(a) << 24; - pktlen |= iobuf_get_noeof(a) << 16; - pktlen |= iobuf_get_noeof(a) << 8; - pktlen |= iobuf_get_noeof(a); - } - } - else { - int lenbytes = ((ctb&3)==3)? 0 : (1<<(ctb & 3)); - for( ; lenbytes; lenbytes-- ) { - pktlen <<= 8; - pktlen |= iobuf_get_noeof(a); - } - } - /* hash a header */ - md_putc( md, 0x99 ); - pktlen &= 0xffff; /* can't handle longer packets */ - md_putc( md, pktlen >> 8 ); - md_putc( md, pktlen & 0xff ); - } - /* hash the packet body */ - while( (c=iobuf_get(a)) != -1 ) { -#if 0 - fprintf( fp," %02x", c ); - if( (++i == 24) ) { - putc('\n', fp); - i=0; - } -#endif - md_putc( md, c ); - } -#if 0 - putc('\n', fp); - fclose(fp); -#endif - iobuf_cancel(a); -} - - static int do_secret_key( IOBUF out, int ctb, PKT_secret_key *sk ) { diff --git a/g10/getkey.c b/g10/getkey.c index 72b80ba76..7d437a07a 100644 --- a/g10/getkey.c +++ b/g10/getkey.c @@ -374,13 +374,15 @@ get_pubkey( PKT_public_key *pk, u32 *keyid ) /* Get a public key and store it into the allocated pk. This function differs from get_pubkey() in that it does not do a check of the key - to avoid recursion. It should be used only in very certain cases. */ + to avoid recursion. It should be used only in very certain cases. + It will only retrieve primary keys. */ int get_pubkey_fast (PKT_public_key *pk, u32 *keyid) { int rc = 0; KEYDB_HANDLE hd; KBNODE keyblock; + u32 pkid[2]; assert (pk); #if MAX_PK_CACHE_ENTRIES @@ -413,20 +415,25 @@ get_pubkey_fast (PKT_public_key *pk, u32 *keyid) log_error ("keydb_get_keyblock failed: %s\n", g10_errstr(rc)); return G10ERR_NO_PUBKEY; } - + assert ( keyblock->pkt->pkttype == PKT_PUBLIC_KEY || keyblock->pkt->pkttype == PKT_PUBLIC_SUBKEY ); - copy_public_key (pk, keyblock->pkt->pkt.public_key ); + + keyid_from_pk(keyblock->pkt->pkt.public_key,pkid); + if(keyid[0]==pkid[0] && keyid[1]==pkid[1]) + copy_public_key (pk, keyblock->pkt->pkt.public_key ); + else + rc=G10ERR_NO_PUBKEY; + release_kbnode (keyblock); /* Not caching key here since it won't have all of the fields properly set. */ - return 0; + return rc; } - KBNODE get_pubkeyblock( u32 *keyid ) { diff --git a/g10/import.c b/g10/import.c index c5bcb595c..d13357b6a 100644 --- a/g10/import.c +++ b/g10/import.c @@ -559,10 +559,6 @@ import_one( const char *fname, KBNODE keyblock, keyid_from_pk( pk, keyid ); uidnode = find_next_kbnode( keyblock, PKT_USER_ID ); - if(pk->pubkey_algo==PUBKEY_ALGO_ELGAMAL) - log_info(_("key %08lX: Elgamal primary key -" - " this may take some time to import\n"),(ulong)keyid[1]); - if( opt.verbose && !opt.interactive ) { log_info( "pub %4u%c/%08lX %s ", nbits_from_pk( pk ), diff --git a/g10/keydb.h b/g10/keydb.h index 900d0267c..0d2a143a0 100644 --- a/g10/keydb.h +++ b/g10/keydb.h @@ -1,5 +1,5 @@ /* keydb.h - Key database - * Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc. + * Copyright (C) 1998, 1999, 2000, 2001, 2003 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -237,6 +237,7 @@ KEYDB_HANDLE get_ctx_handle(GETKEY_CTX ctx); /*-- keyid.c --*/ int pubkey_letter( int algo ); +void hash_public_key( MD_HANDLE md, PKT_public_key *pk ); u32 keyid_from_sk( PKT_secret_key *sk, u32 *keyid ); u32 keyid_from_pk( PKT_public_key *pk, u32 *keyid ); u32 keyid_from_sig( PKT_signature *sig, u32 *keyid ); @@ -250,13 +251,11 @@ const char *datestr_from_sig( PKT_signature *sig ); const char *expirestr_from_pk( PKT_public_key *pk ); const char *expirestr_from_sk( PKT_secret_key *sk ); const char *expirestr_from_sig( PKT_signature *sig ); - const char *colon_strtime (u32 t); const char *colon_datestr_from_pk (PKT_public_key *pk); const char *colon_datestr_from_sk (PKT_secret_key *sk); const char *colon_datestr_from_sig (PKT_signature *sig); const char *colon_expirestr_from_sig (PKT_signature *sig); - byte *fingerprint_from_sk( PKT_secret_key *sk, byte *buf, size_t *ret_len ); byte *fingerprint_from_pk( PKT_public_key *pk, byte *buf, size_t *ret_len ); diff --git a/g10/keyid.c b/g10/keyid.c index 8641f7d94..3648e0579 100644 --- a/g10/keyid.c +++ b/g10/keyid.c @@ -47,59 +47,80 @@ pubkey_letter( int algo ) } } +/* This function is useful for v4 fingerprints and v3 or v4 key + signing. */ +void +hash_public_key( MD_HANDLE md, PKT_public_key *pk ) +{ + unsigned n=6; + unsigned nb[PUBKEY_MAX_NPKEY]; + unsigned nn[PUBKEY_MAX_NPKEY]; + byte *pp[PUBKEY_MAX_NPKEY]; + int i; + int npkey = pubkey_get_npkey( pk->pubkey_algo ); + + /* Two extra bytes for the expiration date in v3 */ + if(pk->version<4) + n+=2; + + if(npkey==0 && pk->pkey[0] && mpi_is_opaque(pk->pkey[0])) + { + pp[0]=mpi_get_opaque(pk->pkey[0],&nn[0]); + n+=nn[0]; + } + else + for(i=0; i < npkey; i++ ) + { + nb[i] = mpi_get_nbits(pk->pkey[i]); + pp[i] = mpi_get_buffer( pk->pkey[i], nn+i, NULL ); + n += 2 + nn[i]; + } + + md_putc( md, 0x99 ); /* ctb */ + /* What does it mean if n is greater than than 0xFFFF ? */ + md_putc( md, n >> 8 ); /* 2 byte length header */ + md_putc( md, n ); + md_putc( md, pk->version ); + + md_putc( md, pk->timestamp >> 24 ); + md_putc( md, pk->timestamp >> 16 ); + md_putc( md, pk->timestamp >> 8 ); + md_putc( md, pk->timestamp ); + + if(pk->version<4) + { + u16 days=0; + if(pk->expiredate) + days=(u16)((pk->expiredate - pk->timestamp) / 86400L); + + md_putc( md, days >> 8 ); + md_putc( md, days ); + } + + md_putc( md, pk->pubkey_algo ); + + if(npkey==0 && pk->pkey[0] && mpi_is_opaque(pk->pkey[0])) + md_write(md,pp[0],nn[0]); + else + for(i=0; i < npkey; i++ ) + { + md_putc( md, nb[i]>>8); + md_putc( md, nb[i] ); + md_write( md, pp[i], nn[i] ); + m_free(pp[i]); + } +} + static MD_HANDLE do_fingerprint_md( PKT_public_key *pk ) { - MD_HANDLE md; - unsigned n=6; - unsigned nb[PUBKEY_MAX_NPKEY]; - unsigned nn[PUBKEY_MAX_NPKEY]; - byte *pp[PUBKEY_MAX_NPKEY]; - int i; - int npkey = pubkey_get_npkey( pk->pubkey_algo ); + MD_HANDLE md; - md = md_open( DIGEST_ALGO_SHA1, 0); + md = md_open( DIGEST_ALGO_SHA1, 0); + hash_public_key(md,pk); + md_final( md ); - if(npkey==0 && pk->pkey[0] && mpi_is_opaque(pk->pkey[0])) - { - pp[0]=mpi_get_opaque(pk->pkey[0],&nn[0]); - n+=nn[0]; - } - else - for(i=0; i < npkey; i++ ) - { - nb[i] = mpi_get_nbits(pk->pkey[i]); - pp[i] = mpi_get_buffer( pk->pkey[i], nn+i, NULL ); - n += 2 + nn[i]; - } - - md_putc( md, 0x99 ); /* ctb */ - /* What does it mean if n is greater than than 0xFFFF ? */ - md_putc( md, n >> 8 ); /* 2 byte length header */ - md_putc( md, n ); - md_putc( md, 4 ); - - md_putc( md, pk->timestamp >> 24 ); - md_putc( md, pk->timestamp >> 16 ); - md_putc( md, pk->timestamp >> 8 ); - md_putc( md, pk->timestamp ); - - md_putc( md, pk->pubkey_algo ); - - if(npkey==0 && pk->pkey[0] && mpi_is_opaque(pk->pkey[0])) - md_write(md,pp[0],nn[0]); - else - for(i=0; i < npkey; i++ ) - { - md_putc( md, nb[i]>>8); - md_putc( md, nb[i] ); - md_write( md, pp[i], nn[i] ); - m_free(pp[i]); - } - - md_final( md ); - - return md; + return md; } static MD_HANDLE @@ -122,7 +143,6 @@ do_fingerprint_md_sk( PKT_secret_key *sk ) return do_fingerprint_md( &pk ); } - /**************** * Get the keyid from the secret key and put it into keyid * if this is not NULL. Return the 32 low bits of the keyid. diff --git a/g10/packet.h b/g10/packet.h index d75ff413a..57306e6e7 100644 --- a/g10/packet.h +++ b/g10/packet.h @@ -1,6 +1,6 @@ /* packet.h - packet definitions - * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 - * Free Software Foundation, Inc. + * Copyright (C) 1998, 1999, 2000, 2001, 2002, + * 2003 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -424,7 +424,6 @@ PACKET *create_gpg_control ( ctrlpkttype_t type, /*-- build-packet.c --*/ int build_packet( IOBUF inp, PACKET *pkt ); u32 calc_packet_length( PACKET *pkt ); -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 );