aboutsummaryrefslogtreecommitdiffstats
path: root/g10/getkey.c
diff options
context:
space:
mode:
Diffstat (limited to 'g10/getkey.c')
-rw-r--r--g10/getkey.c340
1 files changed, 245 insertions, 95 deletions
diff --git a/g10/getkey.c b/g10/getkey.c
index 1756a3556..e322d60c6 100644
--- a/g10/getkey.c
+++ b/g10/getkey.c
@@ -18,6 +18,8 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
+#define DEFINES_GETKEY_CTX 1
+
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
@@ -33,10 +35,30 @@
#include "main.h"
#include "i18n.h"
-#define MAX_UNK_CACHE_ENTRIES 1000
+#define MAX_UNK_CACHE_ENTRIES 1000 /* we use a linked list - so I guess
+ * this is a reasonable limit */
#define MAX_PK_CACHE_ENTRIES 50
#define MAX_UID_CACHE_ENTRIES 50
+
+struct getkey_ctx_s {
+ int mode;
+ int internal;
+ u32 keyid[2];
+ char *namebuf;
+ const char *name;
+ int primary;
+ KBNODE keyblock;
+ KBPOS kbpos;
+ int last_rc;
+ ulong count;
+};
+
+
+
+
+
+
static struct {
int any;
int okay_count;
@@ -82,9 +104,12 @@ static int uid_cache_entries; /* number of entries in uid cache */
-static int lookup( PKT_public_key *pk,
+static int lookup( GETKEY_CTX *ctx, PKT_public_key *pk,
int mode, u32 *keyid, const char *name,
KBNODE *ret_keyblock, int primary );
+static void lookup_close( GETKEY_CTX ctx );
+static int lookup_read( GETKEY_CTX ctx,
+ PKT_public_key *pk, KBNODE *ret_keyblock );
static int lookup_sk( PKT_secret_key *sk,
int mode, u32 *keyid, const char *name, int primary );
@@ -223,7 +248,7 @@ get_pubkey( PKT_public_key *pk, u32 *keyid )
/* do a lookup */
- rc = lookup( pk, 11, keyid, NULL, NULL, 0 );
+ rc = lookup( NULL, pk, 11, keyid, NULL, NULL, 0 );
if( !rc )
goto leave;
@@ -251,7 +276,7 @@ get_pubkey( PKT_public_key *pk, u32 *keyid )
if( !rc )
cache_public_key( pk );
if( internal )
- m_free(pk);
+ free_public_key(pk);
return rc;
}
@@ -282,12 +307,24 @@ hextobyte( const byte *s )
}
+
/****************
- * Try to get the pubkey by the userid. This function looks for the
- * first pubkey certificate which has the given name in a user_id.
- * if pk has the pubkey algo set, the function will only return
- * a pubkey with that algo.
+ * Return the type of the user id:
*
+ * 0 = Invalid user ID
+ * 1 = exact match
+ * 2 = match a substring
+ * 3 = match an email address
+ * 4 = match a substring of an email address
+ * 5 = match an email address, but compare from end
+ * 10 = it is a short KEYID (don't care about keyid[0])
+ * 11 = it is a long KEYID
+ * 16 = it is a 16 byte fingerprint
+ * 20 = it is a 20 byte fingerprint
+ *
+ * if fprint is not NULL, it should be an array of at least 20 bytes.
+ *
+ * Rules used:
* - If the username starts with 8,9,16 or 17 hex-digits (the first one
* must be in the range 0..9), this is considered a keyid; depending
* on the length a short or complete one.
@@ -301,19 +338,14 @@ hextobyte( const byte *s )
* email address
* - If the userid start with an '=' an exact compare is done.
* - If the userid starts with a '*' a case insensitive substring search is
- * done (This is also the default).
+ * done (This is the default).
*/
-
-static int
-key_byname( int secret,
- PKT_public_key *pk, PKT_secret_key *sk, const char *name )
+int
+classify_user_id( const char *name, u32 *keyid, byte *fprint,
+ const char **retstr, size_t *retlen )
{
- int internal = 0;
- int rc = 0;
const char *s;
- u32 keyid[2] = {0}; /* init to avoid compiler warning */
- byte fprint[20];
int mode = 0;
/* check what kind of name it is */
@@ -328,11 +360,14 @@ key_byname( int secret,
for(i=0; isxdigit(s[i]); i++ )
;
if( s[i] && !isspace(s[i]) ) /* not terminated by EOS or blank*/
- rc = G10ERR_INV_USER_ID;
+ return 0;
else if( i == 8 || (i == 9 && *s == '0') ) { /* short keyid */
if( i==9 )
s++;
- keyid[1] = strtoul( s, NULL, 16 );
+ if( keyid ) {
+ keyid[0] = 0;
+ keyid[1] = strtoul( s, NULL, 16 );
+ }
mode = 10;
}
else if( i == 16 || (i == 17 && *s == '0') ) { /* complete keyid */
@@ -347,29 +382,27 @@ key_byname( int secret,
if( i==33 )
s++;
memset(fprint+16, 4, 0);
- for(j=0; !rc && j < 16; j++, s+=2 ) {
+ for(j=0; j < 16; j++, s+=2 ) {
int c = hextobyte( s );
if( c == -1 )
- rc = G10ERR_INV_USER_ID;
- else
- fprint[j] = c;
+ return 0;
+ fprint[j] = c;
}
mode = 16;
}
else if( i == 40 || ( i == 41 && *s == '0' ) ) { /* sha1/rmd160 fprint*/
if( i==33 )
s++;
- for(j=0; !rc && j < 20; j++, s+=2 ) {
+ for(j=0; j < 20; j++, s+=2 ) {
int c = hextobyte( s );
if( c == -1 )
- rc = G10ERR_INV_USER_ID;
- else
- fprint[j] = c;
+ return 0;
+ fprint[j] = c;
}
mode = 20;
}
else
- rc = G10ERR_INV_USER_ID;
+ return 0;
}
else if( *s == '=' ) { /* exact search */
mode = 1;
@@ -391,15 +424,47 @@ key_byname( int secret,
s++;
}
else if( *s == '#' ) { /* use local id */
- rc = G10ERR_INV_USER_ID; /* not yet implemented */
+ return 0;
}
else if( !*s ) /* empty string */
- rc = G10ERR_INV_USER_ID;
+ return 0;
else
mode = 2;
- if( rc )
+ if( retstr )
+ *retstr = s;
+ if( retlen )
+ *retlen = strlen(s);
+
+ return mode;
+}
+
+
+
+/****************
+ * Try to get the pubkey by the userid. This function looks for the
+ * first pubkey certificate which has the given name in a user_id.
+ * if pk has the pubkey algo set, the function will only return
+ * a pubkey with that algo.
+ */
+
+static int
+key_byname( int secret, GETKEY_CTX *retctx,
+ PKT_public_key *pk, PKT_secret_key *sk,
+ const char *name, KBNODE *ret_kb )
+{
+ int internal = 0;
+ int rc = 0;
+ const char *s;
+ u32 keyid[2] = {0}; /* init to avoid compiler warning */
+ byte fprint[20];
+ int mode;
+
+ mode = classify_user_id( name, keyid, fprint, &s, NULL );
+ if( !mode ) {
+ rc = G10ERR_INV_USER_ID;
goto leave;
+ }
if( secret ) {
if( !sk ) {
@@ -414,8 +479,8 @@ key_byname( int secret,
pk = m_alloc_clear( sizeof *pk );
internal++;
}
- rc = mode < 16? lookup( pk, mode, keyid, s, NULL, 1 )
- : lookup( pk, mode, keyid, fprint, NULL, 1 );
+ rc = mode < 16? lookup( retctx, pk, mode, keyid, s, ret_kb, 1 )
+ : lookup( retctx, pk, mode, keyid, fprint, ret_kb, 1 );
}
@@ -428,11 +493,46 @@ key_byname( int secret,
}
int
-get_pubkey_byname( PKT_public_key *pk, const char *name )
+get_pubkey_byname( GETKEY_CTX *retctx, PKT_public_key *pk,
+ const char *name, KBNODE *ret_keyblock )
{
- return key_byname( 0, pk, NULL, name );
+ int rc;
+
+ if( !pk ) {
+ /* fixme: key_byname should not need a pk in this case */
+ pk = m_alloc_clear( sizeof *pk );
+ rc = key_byname( 0, retctx, pk, NULL, name, ret_keyblock );
+ free_public_key( pk );
+ }
+ else
+ rc = key_byname( 0, retctx, pk, NULL, name, ret_keyblock );
+ return rc;
}
+int
+get_pubkey_next( GETKEY_CTX ctx, PKT_public_key *pk, KBNODE *ret_keyblock )
+{
+ int rc;
+
+ if( !pk ) {
+ /* fixme: lookup_read should not need a pk in this case */
+ pk = m_alloc_clear( sizeof *pk );
+ rc = lookup_read( ctx, pk, ret_keyblock );
+ free_public_key( pk );
+ }
+ else
+ rc = lookup_read( ctx, pk, ret_keyblock );
+ return rc;
+}
+
+void
+get_pubkey_end( GETKEY_CTX ctx )
+{
+ if( ctx ) {
+ lookup_close( ctx );
+ m_free( ctx );
+ }
+}
/****************
* Search for a key with the given fingerprint.
@@ -443,7 +543,7 @@ get_pubkey_byfprint( PKT_public_key *pk, const byte *fprint, size_t fprint_len)
int rc;
if( fprint_len == 20 || fprint_len == 16 )
- rc = lookup( pk, fprint_len, NULL, fprint, NULL, 0 );
+ rc = lookup( NULL, pk, fprint_len, NULL, fprint, NULL, 0 );
else
rc = G10ERR_GENERAL; /* Oops */
return rc;
@@ -461,7 +561,7 @@ get_keyblock_byfprint( KBNODE *ret_keyblock, const byte *fprint,
PKT_public_key *pk = m_alloc_clear( sizeof *pk );
if( fprint_len == 20 || fprint_len == 16 )
- rc = lookup( pk, fprint_len, NULL, fprint, ret_keyblock, 0 );
+ rc = lookup( NULL, pk, fprint_len, NULL, fprint, ret_keyblock, 0 );
else
rc = G10ERR_GENERAL; /* Oops */
@@ -517,11 +617,11 @@ get_seckey_byname( PKT_secret_key *sk, const char *name, int unprotect )
int rc;
if( !name && opt.def_secret_key && *opt.def_secret_key )
- rc = key_byname( 1, NULL, sk, opt.def_secret_key );
+ rc = key_byname( 1, NULL, NULL, sk, opt.def_secret_key, NULL );
else if( !name ) /* use the first one as default key */
rc = lookup_sk( sk, 15, NULL, NULL, 1 );
else
- rc = key_byname( 1, NULL, sk, name );
+ rc = key_byname( 1, NULL, NULL, sk, name, NULL );
if( !rc && unprotect )
rc = check_secret_key( sk, 0 );
@@ -860,8 +960,6 @@ finish_lookup( KBNODE keyblock, PKT_public_key *pk, KBNODE k, byte *namehash,
}
}
-
-
/****************
* Lookup a key by scanning all keyresources
* mode 1 = lookup by NAME (exact)
@@ -880,93 +978,142 @@ finish_lookup( KBNODE keyblock, PKT_public_key *pk, KBNODE k, byte *namehash,
* and the caller must release it.
*/
static int
-lookup( PKT_public_key *pk, int mode, u32 *keyid,
+lookup( GETKEY_CTX *retctx, PKT_public_key *pk, int mode, u32 *keyid,
const char *name, KBNODE *ret_keyblock, int primary )
{
+ struct getkey_ctx_s help_ctx;
+ GETKEY_CTX ctx;
+ int rc;
+
+ if( !retctx )
+ ctx = &help_ctx;
+ else {
+ ctx = m_alloc( sizeof *ctx );
+ *retctx = ctx;
+ }
+
+ memset( ctx, 0, sizeof *ctx );
+ ctx->mode = mode;
+ if( keyid ) {
+ ctx->keyid[0] = keyid[0];
+ ctx->keyid[1] = keyid[1];
+ }
+ if( retctx ) {
+ ctx->namebuf = name? m_strdup(name) : NULL;
+ ctx->name = ctx->namebuf;
+ }
+ else
+ ctx->name = name;
+ ctx->primary = primary;
+ rc = lookup_read( ctx, pk, ret_keyblock );
+ if( !retctx )
+ lookup_close( ctx );
+ return rc;
+}
+
+static void
+lookup_close( GETKEY_CTX ctx )
+{
+ enum_keyblocks( 2, &ctx->kbpos, NULL ); /* close */
+ m_free( ctx->namebuf );
+}
+
+static int
+lookup_read( GETKEY_CTX ctx, PKT_public_key *pk, KBNODE *ret_keyblock )
+{
int rc;
- KBNODE keyblock = NULL;
KBNODE k;
- KBPOS kbpos;
int oldmode = set_packet_list_mode(0);
byte namehash[20];
int use_namehash=0;
/* 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;
+ if( !ctx->count ) {
+ k = NULL;
+ switch( ctx->mode ) {
+ case 10:
+ case 11:
+ rc = locate_keyblock_by_keyid( &ctx->kbpos, ctx->keyid,
+ ctx->mode==10, 0 );
+ if( !rc )
+ rc = read_keyblock( &ctx->kbpos, &ctx->keyblock );
+ if( !rc )
+ k = find_by_keyid( ctx->keyblock, pk, ctx->keyid, ctx->mode );
+ break;
- 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;
+ case 16:
+ case 20:
+ rc = locate_keyblock_by_fpr( &ctx->kbpos, ctx->name, ctx->mode, 0 );
+ if( !rc )
+ rc = read_keyblock( &ctx->kbpos, &ctx->keyblock );
+ if( !rc )
+ k = find_by_fpr( ctx->keyblock, pk, ctx->name, ctx->mode );
+ break;
- default: rc = G10ERR_UNSUPPORTED;
- }
- if( !rc ) {
- if( !k ) {
- log_error("lookup: key has been located but was not found\n");
- rc = G10ERR_INV_KEYRING;
+ default: rc = G10ERR_UNSUPPORTED;
+ }
+ if( !rc ) {
+ if( !k ) {
+ log_error("lookup: key has been located but was not found\n");
+ rc = G10ERR_INV_KEYRING;
+ }
+ else
+ finish_lookup( ctx->keyblock, pk, k, namehash, 0, ctx->primary );
}
- else
- finish_lookup( keyblock, pk, k, namehash, 0, primary );
}
+ else
+ rc = G10ERR_UNSUPPORTED;
/* 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( !ctx->count )
+ rc = enum_keyblocks( 0, &ctx->kbpos, &ctx->keyblock );
+ else
+ rc = 0;
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 );
+ while( !(rc = enum_keyblocks( 1, &ctx->kbpos, &ctx->keyblock )) ) {
+ /* fixme: we don�t enum the complete keyblock, but
+ * use the first match and that continue with the next keyblock
+ */
+ if( ctx->mode < 10 )
+ k = find_by_name( ctx->keyblock, pk, ctx->name, ctx->mode,
+ namehash, &use_namehash);
+ else if( ctx->mode == 10 ||ctx-> mode == 11 )
+ k = find_by_keyid( ctx->keyblock, pk, ctx->keyid,
+ ctx->mode );
+ else if( ctx->mode == 15 )
+ k = find_first( ctx->keyblock, pk );
+ else if( ctx->mode == 16 || ctx->mode == 20 )
+ k = find_by_fpr( ctx->keyblock, pk, ctx->name, ctx->mode );
else
BUG();
if( k ) {
- finish_lookup( keyblock, pk, k, namehash,
- use_namehash, primary );
+ finish_lookup( ctx->keyblock, pk, k, namehash,
+ use_namehash, ctx->primary );
break; /* found */
}
- release_kbnode( keyblock );
- keyblock = NULL;
+ release_kbnode( ctx->keyblock );
+ ctx->keyblock = NULL;
}
}
- enum_keyblocks( 2, &kbpos, &keyblock ); /* close */
if( rc && rc != -1 )
log_error("enum_keyblocks failed: %s\n", g10_errstr(rc));
}
if( !rc ) {
if( ret_keyblock ) {
- *ret_keyblock = keyblock;
- keyblock = NULL;
+ *ret_keyblock = ctx->keyblock;
+ ctx->keyblock = NULL;
}
}
else if( rc == -1 )
rc = G10ERR_NO_PUBKEY;
-
- release_kbnode( keyblock );
+ release_kbnode( ctx->keyblock );
+ ctx->keyblock = NULL;
set_packet_list_mode(oldmode);
if( opt.debug & DBG_MEMSTAT_VALUE ) {
static int initialized;
@@ -976,19 +1123,22 @@ lookup( PKT_public_key *pk, int mode, u32 *keyid,
atexit( print_stats );
}
- assert( mode < DIM(lkup_stats) );
- lkup_stats[mode].any = 1;
+ assert( ctx->mode < DIM(lkup_stats) );
+ lkup_stats[ctx->mode].any = 1;
if( !rc )
- lkup_stats[mode].okay_count++;
+ lkup_stats[ctx->mode].okay_count++;
else if ( rc == G10ERR_NO_PUBKEY )
- lkup_stats[mode].nokey_count++;
+ lkup_stats[ctx->mode].nokey_count++;
else
- lkup_stats[mode].error_count++;
+ lkup_stats[ctx->mode].error_count++;
}
+ ctx->last_rc = rc;
+ ctx->count++;
return rc;
}
+
/****************
* Ditto for secret keys
*/