aboutsummaryrefslogtreecommitdiffstats
path: root/g10/getkey.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--g10/getkey.c396
1 files changed, 242 insertions, 154 deletions
diff --git a/g10/getkey.c b/g10/getkey.c
index 3aa12033d..1756a3556 100644
--- a/g10/getkey.c
+++ b/g10/getkey.c
@@ -683,6 +683,182 @@ merge_keys_and_selfsig( KBNODE keyblock )
}
+static KBNODE
+find_by_name( KBNODE keyblock, PKT_public_key *pk, const char *name,
+ int mode, byte *namehash, int *use_namehash )
+{
+ KBNODE k, kk;
+
+ for(k=keyblock; k; k = k->next ) {
+ if( k->pkt->pkttype == PKT_USER_ID
+ && !compare_name( k->pkt->pkt.user_id->name,
+ k->pkt->pkt.user_id->len, name, mode)) {
+ /* we found a matching name, look for the key */
+ for(kk=keyblock; kk; kk = kk->next ) {
+ if( ( kk->pkt->pkttype == PKT_PUBLIC_KEY
+ || kk->pkt->pkttype == PKT_PUBLIC_SUBKEY )
+ && ( !pk->pubkey_algo
+ || pk->pubkey_algo
+ == kk->pkt->pkt.public_key->pubkey_algo)
+ && ( !pk->pubkey_usage
+ || !check_pubkey_algo2(
+ kk->pkt->pkt.public_key->pubkey_algo,
+ pk->pubkey_usage ))
+ )
+ break;
+ }
+ if( kk ) {
+ u32 aki[2];
+ keyid_from_pk( kk->pkt->pkt.public_key, aki );
+ cache_user_id( k->pkt->pkt.user_id, aki );
+ rmd160_hash_buffer( namehash,
+ k->pkt->pkt.user_id->name,
+ k->pkt->pkt.user_id->len );
+ *use_namehash = 1;
+ return kk;
+ }
+ else if( is_RSA(pk->pubkey_algo) )
+ log_error("RSA key cannot be used in this version\n");
+ else
+ log_error("No key for userid\n");
+ }
+ }
+ return NULL;
+}
+
+
+static KBNODE
+find_by_keyid( KBNODE keyblock, PKT_public_key *pk, u32 *keyid, int mode )
+{
+ KBNODE k;
+
+ if( DBG_CACHE )
+ log_debug("lookup keyid=%08lx%08lx req_algo=%d mode=%d\n",
+ (ulong)keyid[0], (ulong)keyid[1], pk->pubkey_algo, mode );
+
+ for(k=keyblock; k; k = k->next ) {
+ if( k->pkt->pkttype == PKT_PUBLIC_KEY
+ || k->pkt->pkttype == PKT_PUBLIC_SUBKEY ) {
+ u32 aki[2];
+ keyid_from_pk( k->pkt->pkt.public_key, aki );
+ if( DBG_CACHE )
+ log_debug(" aki=%08lx%08lx algo=%d\n",
+ (ulong)aki[0], (ulong)aki[1],
+ k->pkt->pkt.public_key->pubkey_algo );
+
+ if( aki[1] == keyid[1]
+ && ( mode == 10 || aki[0] == keyid[0] )
+ && ( !pk->pubkey_algo
+ || pk->pubkey_algo
+ == k->pkt->pkt.public_key->pubkey_algo) ){
+ KBNODE kk;
+ /* cache the userid */
+ for(kk=keyblock; kk; kk = kk->next )
+ if( kk->pkt->pkttype == PKT_USER_ID )
+ break;
+ if( kk )
+ cache_user_id( kk->pkt->pkt.user_id, aki );
+ else
+ log_error("No userid for key\n");
+ return k; /* found */
+ }
+ }
+ }
+ return NULL;
+}
+
+
+static KBNODE
+find_first( KBNODE keyblock, PKT_public_key *pk )
+{
+ KBNODE k;
+
+ for(k=keyblock; k; k = k->next ) {
+ if( k->pkt->pkttype == PKT_PUBLIC_KEY
+ || k->pkt->pkttype == PKT_PUBLIC_SUBKEY )
+ {
+ if( !pk->pubkey_algo
+ || pk->pubkey_algo == k->pkt->pkt.public_key->pubkey_algo )
+ return k;
+ }
+ }
+ return NULL;
+}
+
+
+static KBNODE
+find_by_fpr( KBNODE keyblock, PKT_public_key *pk, const char *name, int mode )
+{
+ KBNODE k;
+
+ for(k=keyblock; k; k = k->next ) {
+ if( k->pkt->pkttype == PKT_PUBLIC_KEY
+ || k->pkt->pkttype == PKT_PUBLIC_SUBKEY ) {
+ byte afp[MAX_FINGERPRINT_LEN];
+ size_t an;
+
+ fingerprint_from_pk(k->pkt->pkt.public_key, afp, &an );
+
+ if( DBG_CACHE ) {
+ u32 aki[2];
+ keyid_from_pk( k->pkt->pkt.public_key, aki );
+ log_debug(" aki=%08lx%08lx algo=%d mode=%d an=%u\n",
+ (ulong)aki[0], (ulong)aki[1],
+ k->pkt->pkt.public_key->pubkey_algo, mode, an );
+ }
+
+ if( an == mode
+ && !memcmp( afp, name, an)
+ && ( !pk->pubkey_algo
+ || pk->pubkey_algo == k->pkt->pkt.public_key->pubkey_algo) )
+ return k;
+ }
+ }
+ return NULL;
+}
+
+
+static void
+finish_lookup( KBNODE keyblock, PKT_public_key *pk, KBNODE k, byte *namehash,
+ int use_namehash, int primary )
+{
+ assert( k->pkt->pkttype == PKT_PUBLIC_KEY
+ || k->pkt->pkttype == PKT_PUBLIC_SUBKEY );
+ assert( keyblock->pkt->pkttype == PKT_PUBLIC_KEY );
+ if( primary && !pk->pubkey_usage ) {
+ copy_public_key_new_namehash( pk, keyblock->pkt->pkt.public_key,
+ use_namehash? namehash:NULL);
+ merge_one_pk_and_selfsig( keyblock, keyblock );
+ }
+ else {
+ if( primary && pk->pubkey_usage
+ && check_pubkey_algo2( k->pkt->pkt.public_key->pubkey_algo,
+ pk->pubkey_usage ) == G10ERR_WR_PUBKEY_ALGO ) {
+ /* if the usage is not correct, try to use a subkey */
+ KBNODE save_k = k;
+
+ for( ; k; k = k->next ) {
+ if( k->pkt->pkttype == PKT_PUBLIC_SUBKEY
+ && !check_pubkey_algo2(
+ k->pkt->pkt.public_key->pubkey_algo,
+ pk->pubkey_usage ) )
+ break;
+ }
+ if( !k )
+ k = save_k;
+ else
+ log_info(_("using secondary key %08lX "
+ "instead of primary key %08lX\n"),
+ (ulong)keyid_from_pk( k->pkt->pkt.public_key, NULL),
+ (ulong)keyid_from_pk( save_k->pkt->pkt.public_key, NULL)
+ );
+ }
+
+ copy_public_key_new_namehash( pk, k->pkt->pkt.public_key,
+ use_namehash? namehash:NULL);
+ merge_one_pk_and_selfsig( keyblock, k );
+ }
+}
@@ -709,175 +885,87 @@ lookup( PKT_public_key *pk, int mode, u32 *keyid,
{
int rc;
KBNODE keyblock = NULL;
+ KBNODE k;
KBPOS kbpos;
int oldmode = set_packet_list_mode(0);
byte namehash[20];
int use_namehash=0;
- rc = enum_keyblocks( 0, &kbpos, &keyblock );
- if( rc ) {
- if( rc == -1 )
- rc = G10ERR_NO_PUBKEY;
- else if( rc )
- log_error("enum_keyblocks(open) failed: %s\n", g10_errstr(rc) );
- goto leave;
- }
-
- while( !(rc = enum_keyblocks( 1, &kbpos, &keyblock )) ) {
- KBNODE k, kk;
- if( mode < 10 ) { /* name lookup */
- for(k=keyblock; k; k = k->next ) {
- if( k->pkt->pkttype == PKT_USER_ID
- && !compare_name( k->pkt->pkt.user_id->name,
- k->pkt->pkt.user_id->len, name, mode)) {
- /* we found a matching name, look for the key */
- for(kk=keyblock; kk; kk = kk->next ) {
- if( ( kk->pkt->pkttype == PKT_PUBLIC_KEY
- || kk->pkt->pkttype == PKT_PUBLIC_SUBKEY )
- && ( !pk->pubkey_algo
- || pk->pubkey_algo
- == kk->pkt->pkt.public_key->pubkey_algo)
- && ( !pk->pubkey_usage
- || !check_pubkey_algo2(
- kk->pkt->pkt.public_key->pubkey_algo,
- pk->pubkey_usage ))
- )
- break;
- }
- if( kk ) {
- u32 aki[2];
- keyid_from_pk( kk->pkt->pkt.public_key, aki );
- cache_user_id( k->pkt->pkt.user_id, aki );
- rmd160_hash_buffer( namehash,
- k->pkt->pkt.user_id->name,
- k->pkt->pkt.user_id->len );
- use_namehash = 1;
- k = kk;
- break;
- }
- else
- log_error("No key for userid\n");
- }
- }
- }
- else { /* keyid or fingerprint lookup */
- if( DBG_CACHE && (mode== 10 || mode==11) ) {
- log_debug("lookup keyid=%08lx%08lx req_algo=%d mode=%d\n",
- (ulong)keyid[0], (ulong)keyid[1],
- pk->pubkey_algo, mode );
- }
- for(k=keyblock; k; k = k->next ) {
- if( k->pkt->pkttype == PKT_PUBLIC_KEY
- || k->pkt->pkttype == PKT_PUBLIC_SUBKEY ) {
- if( mode == 10 || mode == 11 ) {
- u32 aki[2];
- keyid_from_pk( k->pkt->pkt.public_key, aki );
- if( DBG_CACHE ) {
- log_debug(" aki=%08lx%08lx algo=%d\n",
- (ulong)aki[0], (ulong)aki[1],
- k->pkt->pkt.public_key->pubkey_algo );
- }
- if( aki[1] == keyid[1]
- && ( mode == 10 || aki[0] == keyid[0] )
- && ( !pk->pubkey_algo
- || pk->pubkey_algo
- == k->pkt->pkt.public_key->pubkey_algo) ){
- /* cache the userid */
- for(kk=keyblock; kk; kk = kk->next )
- if( kk->pkt->pkttype == PKT_USER_ID )
- break;
- if( kk )
- cache_user_id( kk->pkt->pkt.user_id, aki );
- else
- log_error("No userid for key\n");
- break; /* found */
- }
- }
- else if( mode == 15 ) { /* get the first key */
- if( !pk->pubkey_algo
- || pk->pubkey_algo
- == k->pkt->pkt.public_key->pubkey_algo )
- break;
- }
- else if( mode == 16 || mode == 20 ) {
- byte afp[MAX_FINGERPRINT_LEN];
- size_t an;
+ /* try the quick functions */
+ k = NULL;
+ switch( mode ) {
+ case 10:
+ case 11:
+ rc = locate_keyblock_by_keyid( &kbpos, keyid, mode==10, 0 );
+ if( !rc )
+ rc = read_keyblock( &kbpos, &keyblock );
+ if( !rc )
+ k = find_by_keyid( keyblock, pk, keyid, mode );
+ break;
- fingerprint_from_pk(k->pkt->pkt.public_key, afp, &an );
+ case 16:
+ case 20:
+ rc = locate_keyblock_by_fpr( &kbpos, name, mode, 0 );
+ if( !rc )
+ rc = read_keyblock( &kbpos, &keyblock );
+ if( !rc )
+ k = find_by_fpr( keyblock, pk, name, mode );
+ break;
- if( DBG_CACHE ) {
- u32 aki[2];
- keyid_from_pk( k->pkt->pkt.public_key, aki );
- log_debug(" aki=%08lx%08lx algo=%d mode=%d an=%u\n",
- (ulong)aki[0], (ulong)aki[1],
- k->pkt->pkt.public_key->pubkey_algo,
- mode, an );
- }
- if( an == mode && !memcmp( afp, name, an)
- && ( !pk->pubkey_algo
- || pk->pubkey_algo
- == k->pkt->pkt.public_key->pubkey_algo) ) {
- break;
- }
- }
- else
- BUG();
- } /* end compare public keys */
- }
+ default: rc = G10ERR_UNSUPPORTED;
+ }
+ if( !rc ) {
+ if( !k ) {
+ log_error("lookup: key has been located but was not found\n");
+ rc = G10ERR_INV_KEYRING;
}
- if( k ) { /* found */
- assert( k->pkt->pkttype == PKT_PUBLIC_KEY
- || k->pkt->pkttype == PKT_PUBLIC_SUBKEY );
- assert( keyblock->pkt->pkttype == PKT_PUBLIC_KEY );
- if( primary && !pk->pubkey_usage ) {
- copy_public_key_new_namehash( pk, keyblock->pkt->pkt.public_key,
- use_namehash? namehash:NULL);
- merge_one_pk_and_selfsig( keyblock, keyblock );
- }
- else {
- if( primary && pk->pubkey_usage
- && check_pubkey_algo2( k->pkt->pkt.public_key->pubkey_algo,
- pk->pubkey_usage ) == G10ERR_WR_PUBKEY_ALGO ) {
- /* if the usage is not correct, try to use a subkey */
- KBNODE save_k = k;
-
- for( ; k; k = k->next ) {
- if( k->pkt->pkttype == PKT_PUBLIC_SUBKEY
- && !check_pubkey_algo2(
- k->pkt->pkt.public_key->pubkey_algo,
- pk->pubkey_usage ) )
- break;
- }
- if( !k )
- k = save_k;
- else
- log_info(_("using secondary key %08lX "
- "instead of primary key %08lX\n"),
- (ulong)keyid_from_pk( k->pkt->pkt.public_key, NULL),
- (ulong)keyid_from_pk( save_k->pkt->pkt.public_key, NULL)
- );
- }
+ else
+ finish_lookup( keyblock, pk, k, namehash, 0, primary );
+ }
- copy_public_key_new_namehash( pk, k->pkt->pkt.public_key,
- use_namehash? namehash:NULL);
- merge_one_pk_and_selfsig( keyblock, k );
- }
- if( ret_keyblock ) {
- *ret_keyblock = keyblock;
+ /* if this was not possible, loop over all keyblocks
+ * fixme: If one of the resources in the quick functions above
+ * works, but the key was not found, we will not find it
+ * in the other resources */
+ if( rc == G10ERR_UNSUPPORTED ) {
+ rc = enum_keyblocks( 0, &kbpos, &keyblock );
+ if( !rc ) {
+ while( !(rc = enum_keyblocks( 1, &kbpos, &keyblock )) ) {
+ if( mode < 10 )
+ k = find_by_name( keyblock, pk, name, mode,
+ namehash, &use_namehash);
+ else if( mode == 10 || mode == 11 )
+ k = find_by_keyid( keyblock, pk, keyid, mode );
+ else if( mode == 15 )
+ k = find_first( keyblock, pk );
+ else if( mode == 16 || mode == 20 )
+ k = find_by_fpr( keyblock, pk, name, mode );
+ else
+ BUG();
+ if( k ) {
+ finish_lookup( keyblock, pk, k, namehash,
+ use_namehash, primary );
+ break; /* found */
+ }
+ release_kbnode( keyblock );
keyblock = NULL;
}
- break; /* enumeration */
}
- release_kbnode( keyblock );
- keyblock = NULL;
+ enum_keyblocks( 2, &kbpos, &keyblock ); /* close */
+ if( rc && rc != -1 )
+ log_error("enum_keyblocks failed: %s\n", g10_errstr(rc));
}
- if( rc == -1 )
+
+ if( !rc ) {
+ if( ret_keyblock ) {
+ *ret_keyblock = keyblock;
+ keyblock = NULL;
+ }
+ }
+ else if( rc == -1 )
rc = G10ERR_NO_PUBKEY;
- else if( rc )
- log_error("enum_keyblocks(read) failed: %s\n", g10_errstr(rc));
- leave:
- enum_keyblocks( 2, &kbpos, &keyblock ); /* close */
+
release_kbnode( keyblock );
set_packet_list_mode(oldmode);
if( opt.debug & DBG_MEMSTAT_VALUE ) {