aboutsummaryrefslogtreecommitdiffstats
path: root/g10/getkey.c
diff options
context:
space:
mode:
authorWerner Koch <[email protected]>2006-04-19 11:26:11 +0000
committerWerner Koch <[email protected]>2006-04-19 11:26:11 +0000
commit29b23dea9731e8f258211bc6fd733d205c18e2a8 (patch)
treeff2a0f66bda0c1f050e8fa00cbf610e18b91c9f7 /g10/getkey.c
parent2006-04-14 Marcus Brinkmann <[email protected]> (diff)
downloadgnupg-29b23dea9731e8f258211bc6fd733d205c18e2a8.tar.gz
gnupg-29b23dea9731e8f258211bc6fd733d205c18e2a8.zip
Merged with gpg 1.4.3 code.
The gpg part does not yet build.
Diffstat (limited to 'g10/getkey.c')
-rw-r--r--g10/getkey.c966
1 files changed, 676 insertions, 290 deletions
diff --git a/g10/getkey.c b/g10/getkey.c
index f51b8f2df..acd992c21 100644
--- a/g10/getkey.c
+++ b/g10/getkey.c
@@ -1,6 +1,6 @@
/* getkey.c - Get a key from the database
- * Copyright (C) 1998, 1999, 2000, 2001, 2002,
- * 2003 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
+ * 2006 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@@ -16,7 +16,8 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA.
*/
#include <config.h>
@@ -29,22 +30,21 @@
#include "gpg.h"
#include "util.h"
#include "packet.h"
-#include "memory.h"
#include "iobuf.h"
#include "keydb.h"
#include "options.h"
#include "main.h"
#include "trustdb.h"
#include "i18n.h"
+#include "keyserver-internal.h"
-#define MAX_PK_CACHE_ENTRIES 200
-#define MAX_UID_CACHE_ENTRIES 200
+#define MAX_PK_CACHE_ENTRIES PK_UID_CACHE_SIZE
+#define MAX_UID_CACHE_ENTRIES PK_UID_CACHE_SIZE
#if MAX_PK_CACHE_ENTRIES < 2
#error We need the cache for key creation
#endif
-
struct getkey_ctx_s {
int exact;
KBNODE keyblock;
@@ -154,7 +154,7 @@ cache_public_key( PKT_public_key *pk )
return;
}
pk_cache_entries++;
- ce = xmalloc ( sizeof *ce );
+ ce = xmalloc( sizeof *ce );
ce->next = pk_cache;
pk_cache = ce;
ce->pk = copy_public_key( NULL, pk );
@@ -164,6 +164,21 @@ cache_public_key( PKT_public_key *pk )
}
+/* Return a const utf-8 string with the text "[User ID not found]".
+ This fucntion is required so that we don't need to switch gettext's
+ encoding temporary. */
+static const char *
+user_id_not_found_utf8 (void)
+{
+ static char *text;
+
+ if (!text)
+ text = native_to_utf8 (_("[User ID not found]"));
+ return text;
+}
+
+
+
/*
* Return the user ID from the given keyblock.
* We use the primary uid flag which has been set by the merge_selfsigs
@@ -184,9 +199,7 @@ get_primary_uid ( KBNODE keyblock, size_t *uidlen )
return k->pkt->pkt.user_id->name;
}
}
- /* fixme: returning translatable constants instead of a user ID is
- * not good because they are probably not utf-8 encoded. */
- s = _("[User id not found]");
+ s = user_id_not_found_utf8 ();
*uidlen = strlen (s);
return s;
}
@@ -218,7 +231,7 @@ cache_user_id( KBNODE keyblock )
for (k=keyblock; k; k = k->next ) {
if ( k->pkt->pkttype == PKT_PUBLIC_KEY
|| k->pkt->pkttype == PKT_PUBLIC_SUBKEY ) {
- keyid_list_t a = xcalloc (1, sizeof *a );
+ keyid_list_t a = xmalloc_clear ( sizeof *a );
/* Hmmm: For a long list of keyids it might be an advantage
* to append the keys */
keyid_from_pk( k->pkt->pkt.public_key, a->keyid );
@@ -252,10 +265,10 @@ cache_user_id( KBNODE keyblock )
r = user_id_db;
user_id_db = r->next;
release_keyid_list ( r->keyids );
- xfree (r);
+ xfree(r);
uid_cache_entries--;
}
- r = xmalloc ( sizeof *r + uidlen-1 );
+ r = xmalloc( sizeof *r + uidlen-1 );
r->keyids = keyids;
r->len = uidlen;
memcpy(r->name, uid, r->len);
@@ -275,7 +288,7 @@ getkey_disable_caches()
for( ce = pk_cache; ce; ce = ce2 ) {
ce2 = ce->next;
free_public_key( ce->pk );
- xfree ( ce );
+ xfree( ce );
}
pk_cache_disabled=1;
pk_cache_entries = 0;
@@ -322,20 +335,25 @@ get_pubkey( PKT_public_key *pk, u32 *keyid )
int rc = 0;
#if MAX_PK_CACHE_ENTRIES
- { /* Try to get it from the cache */
+ if(pk)
+ {
+ /* Try to get it from the cache. We don't do this when pk is
+ NULL as it does not guarantee that the user IDs are
+ cached. */
pk_cache_entry_t ce;
- for( ce = pk_cache; ce; ce = ce->next ) {
- if( ce->keyid[0] == keyid[0] && ce->keyid[1] == keyid[1] ) {
- if( pk )
- copy_public_key( pk, ce->pk );
+ for( ce = pk_cache; ce; ce = ce->next )
+ {
+ if( ce->keyid[0] == keyid[0] && ce->keyid[1] == keyid[1] )
+ {
+ copy_public_key( pk, ce->pk );
return 0;
- }
- }
- }
+ }
+ }
+ }
#endif
/* more init stuff */
if( !pk ) {
- pk = xcalloc (1, sizeof *pk );
+ pk = xmalloc_clear( sizeof *pk );
internal++;
}
@@ -363,7 +381,7 @@ get_pubkey( PKT_public_key *pk, u32 *keyid )
if( !rc )
goto leave;
- rc = GPG_ERR_NO_PUBKEY;
+ rc = G10ERR_NO_PUBKEY;
leave:
if( !rc )
@@ -376,13 +394,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
@@ -406,29 +426,34 @@ get_pubkey_fast (PKT_public_key *pk, u32 *keyid)
if (rc == -1)
{
keydb_release (hd);
- return GPG_ERR_NO_PUBKEY;
+ return G10ERR_NO_PUBKEY;
}
rc = keydb_get_keyblock (hd, &keyblock);
keydb_release (hd);
if (rc)
{
- log_error ("keydb_get_keyblock failed: %s\n", gpg_strerror (rc));
- return GPG_ERR_NO_PUBKEY;
+ 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 )
{
@@ -496,7 +521,7 @@ get_seckey( PKT_secret_key *sk, u32 *keyid )
* check and does not tell us whether the secret key is valid. It
* merely tells other whether there is some secret key.
* Returns: 0 := key is available
- * GPG_ERR_NO_SECKEY := not availabe
+ * G10ERR_NO_SECKEY := not availabe
*/
int
seckey_available( u32 *keyid )
@@ -506,7 +531,7 @@ seckey_available( u32 *keyid )
rc = keydb_search_kid (hd, keyid);
if ( rc == -1 )
- rc = GPG_ERR_NO_SECKEY;
+ rc = G10ERR_NO_SECKEY;
keydb_release (hd);
return rc;
}
@@ -579,11 +604,13 @@ classify_user_id( const char *name, KEYDB_SEARCH_DESC *desc )
case 0: /* empty string is an error */
return 0;
+#if 0
case '.': /* an email address, compare from end */
mode = KEYDB_SEARCH_MODE_MAILEND;
s++;
desc->u.name = s;
break;
+#endif
case '<': /* an email address */
mode = KEYDB_SEARCH_MODE_MAIL;
@@ -608,11 +635,13 @@ classify_user_id( const char *name, KEYDB_SEARCH_DESC *desc )
desc->u.name = s;
break;
+#if 0
case '+': /* compare individual words */
mode = KEYDB_SEARCH_MODE_WORDS;
s++;
desc->u.name = s;
break;
+#endif
case '#': /* local user id */
return 0; /* This is now obsolete and van't not be used anymore*/
@@ -653,7 +682,7 @@ classify_user_id( const char *name, KEYDB_SEARCH_DESC *desc )
}
/* check if a hexadecimal number is terminated by EOS or blank */
- if (hexlength && s[hexlength] && !spacep (s+hexlength)) {
+ if (hexlength && s[hexlength] && !spacep(s+hexlength)) {
if (hexprefix) /* a "0x" prefix without correct */
return 0; /* termination is an error */
else /* The first chars looked like */
@@ -728,39 +757,60 @@ classify_user_id( const char *name, KEYDB_SEARCH_DESC *desc )
static int
-skip_disabled(void *dummy,u32 *keyid)
+skip_unusable(void *dummy,u32 *keyid,PKT_user_id *uid)
{
- int rc,disabled=0;
- PKT_public_key *pk=xcalloc (1,sizeof(PKT_public_key));
+ int unusable=0;
+ KBNODE keyblock;
- rc = get_pubkey(pk, keyid);
- if(rc)
+ keyblock=get_pubkeyblock(keyid);
+ if(!keyblock)
{
- log_error("error checking disabled status of %08lX: %s\n",
- (ulong)keyid[1],gpg_strerror (rc));
+ log_error("error checking usability status of %s\n",keystr(keyid));
goto leave;
}
-
- disabled=pk_is_disabled(pk);
+
+ /* Is the user ID in question revoked/expired? */
+ if(uid)
+ {
+ KBNODE node;
+
+ for(node=keyblock;node;node=node->next)
+ {
+ if(node->pkt->pkttype==PKT_USER_ID)
+ {
+ if(cmp_user_ids(uid,node->pkt->pkt.user_id)==0
+ && (node->pkt->pkt.user_id->is_revoked
+ || node->pkt->pkt.user_id->is_expired))
+ {
+ unusable=1;
+ break;
+ }
+ }
+ }
+ }
+
+ if(!unusable)
+ unusable=pk_is_disabled(keyblock->pkt->pkt.public_key);
leave:
- free_public_key(pk);
- return disabled;
+ release_kbnode(keyblock);
+ return unusable;
}
/****************
* 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/sk has the pubkey algo set, the function will only return
- * a pubkey with that algo.
- * The caller should provide storage for either the pk or the sk.
- * If ret_kb is not NULL the function will return the keyblock there.
+ * first pubkey certificate which has the given name in a user_id. if
+ * pk/sk has the pubkey algo set, the function will only return a
+ * pubkey with that algo. If namelist is NULL, the first key is
+ * returned. The caller should provide storage for either the pk or
+ * the sk. If ret_kb is not NULL the function will return the
+ * keyblock there.
*/
static int
key_byname( GETKEY_CTX *retctx, STRLIST namelist,
PKT_public_key *pk, PKT_secret_key *sk,
- int secmode, int include_disabled,
+ int secmode, int include_unusable,
KBNODE *ret_kb, KEYDB_HANDLE *ret_kdbhd )
{
int rc = 0;
@@ -777,29 +827,43 @@ key_byname( GETKEY_CTX *retctx, STRLIST namelist,
if (ret_kdbhd)
*ret_kdbhd = NULL;
- /* build the search context */
- for(n=0, r=namelist; r; r = r->next )
- n++;
- ctx = xcalloc (1,sizeof *ctx + (n-1)*sizeof ctx->items );
- ctx->nitems = n;
+ if(!namelist)
+ {
+ ctx = xmalloc_clear (sizeof *ctx);
+ ctx->nitems = 1;
+ ctx->items[0].mode=KEYDB_SEARCH_MODE_FIRST;
+ if(!include_unusable)
+ ctx->items[0].skipfnc=skip_unusable;
+ }
+ else
+ {
+ /* build the search context */
+ for(n=0, r=namelist; r; r = r->next )
+ n++;
- for(n=0, r=namelist; r; r = r->next, n++ ) {
- classify_user_id (r->d, &ctx->items[n]);
+ ctx = xmalloc_clear (sizeof *ctx + (n-1)*sizeof ctx->items );
+ ctx->nitems = n;
+
+ for(n=0, r=namelist; r; r = r->next, n++ )
+ {
+ classify_user_id (r->d, &ctx->items[n]);
- if (ctx->items[n].exact)
- ctx->exact = 1;
- if (!ctx->items[n].mode) {
- xfree (ctx);
- return GPG_ERR_INV_USER_ID;
- }
- if(!include_disabled
- && ctx->items[n].mode!=KEYDB_SEARCH_MODE_SHORT_KID
- && ctx->items[n].mode!=KEYDB_SEARCH_MODE_LONG_KID
- && ctx->items[n].mode!=KEYDB_SEARCH_MODE_FPR16
- && ctx->items[n].mode!=KEYDB_SEARCH_MODE_FPR20
- && ctx->items[n].mode!=KEYDB_SEARCH_MODE_FPR)
- ctx->items[n].skipfnc=skip_disabled;
- }
+ if (ctx->items[n].exact)
+ ctx->exact = 1;
+ if (!ctx->items[n].mode)
+ {
+ xfree (ctx);
+ return G10ERR_INV_USER_ID;
+ }
+ if(!include_unusable
+ && ctx->items[n].mode!=KEYDB_SEARCH_MODE_SHORT_KID
+ && ctx->items[n].mode!=KEYDB_SEARCH_MODE_LONG_KID
+ && ctx->items[n].mode!=KEYDB_SEARCH_MODE_FPR16
+ && ctx->items[n].mode!=KEYDB_SEARCH_MODE_FPR20
+ && ctx->items[n].mode!=KEYDB_SEARCH_MODE_FPR)
+ ctx->items[n].skipfnc=skip_unusable;
+ }
+ }
ctx->kr_handle = keydb_new (secmode);
if ( !ret_kb )
@@ -841,24 +905,141 @@ key_byname( GETKEY_CTX *retctx, STRLIST namelist,
return rc;
}
-/*
- * Find a public key from NAME and returh the keyblock or the key.
- * If ret_kdb is not NULL, the KEYDB handle used to locate this keyblock is
- * returned and the caller is responsible for closing it.
- */
+
+
+/* Find a public key from NAME and return the keyblock or the key. If
+ ret_kdb is not NULL, the KEYDB handle used to locate this keyblock
+ is returned and the caller is responsible for closing it. If a key
+ was not found and NAME is a valid RFC822 mailbox and PKA retrieval
+ has been enabled, we try to import the pkea via the PKA
+ mechanism. */
int
get_pubkey_byname (PKT_public_key *pk,
const char *name, KBNODE *ret_keyblock,
- KEYDB_HANDLE *ret_kdbhd, int include_disabled )
+ KEYDB_HANDLE *ret_kdbhd, int include_unusable )
{
- int rc;
- STRLIST namelist = NULL;
+ int rc;
+ STRLIST namelist = NULL;
- add_to_strlist( &namelist, name );
- rc = key_byname( NULL, namelist, pk, NULL, 0,
- include_disabled, ret_keyblock, ret_kdbhd);
- free_strlist( namelist );
- return rc;
+ add_to_strlist( &namelist, name );
+
+ rc = key_byname( NULL, namelist, pk, NULL, 0,
+ include_unusable, ret_keyblock, ret_kdbhd);
+
+ /* If the requested name resembles a valid mailbox and automatic
+ retrieval has been enabled, we try to import the key. */
+
+ if (rc == G10ERR_NO_PUBKEY && is_valid_mailbox(name))
+ {
+ struct akl *akl;
+
+ for(akl=opt.auto_key_locate;akl;akl=akl->next)
+ {
+ unsigned char *fpr;
+ size_t fpr_len;
+
+ switch(akl->type)
+ {
+ case AKL_CERT:
+ glo_ctrl.in_auto_key_retrieve++;
+ rc=keyserver_import_cert(name,&fpr,&fpr_len);
+ glo_ctrl.in_auto_key_retrieve--;
+
+ if(rc==0)
+ log_info(_("automatically retrieved `%s' via %s\n"),
+ name,"DNS CERT");
+ break;
+
+ case AKL_PKA:
+ glo_ctrl.in_auto_key_retrieve++;
+ rc=keyserver_import_pka(name,&fpr,&fpr_len);
+ glo_ctrl.in_auto_key_retrieve--;
+
+ if(rc==0)
+ log_info(_("automatically retrieved `%s' via %s\n"),
+ name,"PKA");
+ break;
+
+ case AKL_LDAP:
+ glo_ctrl.in_auto_key_retrieve++;
+ rc=keyserver_import_ldap(name,&fpr,&fpr_len);
+ glo_ctrl.in_auto_key_retrieve--;
+
+ if(rc==0)
+ log_info(_("automatically retrieved `%s' via %s\n"),
+ name,"LDAP");
+ break;
+
+ case AKL_KEYSERVER:
+ /* Strictly speaking, we don't need to only use a valid
+ mailbox for the getname search, but it helps cut down
+ on the problem of searching for something like "john"
+ and getting a whole lot of keys back. */
+ if(opt.keyserver)
+ {
+ glo_ctrl.in_auto_key_retrieve++;
+ rc=keyserver_import_name(name,&fpr,&fpr_len,opt.keyserver);
+ glo_ctrl.in_auto_key_retrieve--;
+
+ if(rc==0)
+ log_info(_("automatically retrieved `%s' via %s\n"),
+ name,opt.keyserver->uri);
+ }
+ break;
+
+ case AKL_SPEC:
+ {
+ struct keyserver_spec *keyserver;
+
+ keyserver=keyserver_match(akl->spec);
+ glo_ctrl.in_auto_key_retrieve++;
+ rc=keyserver_import_name(name,&fpr,&fpr_len,keyserver);
+ glo_ctrl.in_auto_key_retrieve--;
+
+ if(rc==0)
+ log_info(_("automatically retrieved `%s' via %s\n"),
+ name,akl->spec->uri);
+ }
+ break;
+ }
+
+ /* Use the fingerprint of the key that we actually fetched.
+ This helps prevent problems where the key that we fetched
+ doesn't have the same name that we used to fetch it. In
+ the case of CERT and PKA, this is an actual security
+ requirement as the URL might point to a key put in by an
+ attacker. By forcing the use of the fingerprint, we
+ won't use the attacker's key here. */
+ if(rc==0 && fpr)
+ {
+ int i;
+ char fpr_string[MAX_FINGERPRINT_LEN*2+1];
+
+ assert(fpr_len<=MAX_FINGERPRINT_LEN);
+
+ free_strlist(namelist);
+ namelist=NULL;
+
+ for(i=0;i<fpr_len;i++)
+ sprintf(fpr_string+2*i,"%02X",fpr[i]);
+
+ if(opt.verbose)
+ log_info("auto-key-locate found fingerprint %s\n",fpr_string);
+
+ add_to_strlist( &namelist, fpr_string );
+
+ xfree(fpr);
+ }
+
+ rc = key_byname( NULL, namelist, pk, NULL, 0,
+ include_unusable, ret_keyblock, ret_kdbhd);
+ if(rc!=G10ERR_NO_PUBKEY)
+ break;
+ }
+ }
+
+ free_strlist( namelist );
+ return rc;
}
int
@@ -880,7 +1061,6 @@ get_pubkey_next( GETKEY_CTX ctx, PKT_public_key *pk, KBNODE *ret_keyblock )
return rc;
}
-
void
get_pubkey_end( GETKEY_CTX ctx )
{
@@ -888,17 +1068,15 @@ get_pubkey_end( GETKEY_CTX ctx )
memset (&ctx->kbpos, 0, sizeof ctx->kbpos);
keydb_release (ctx->kr_handle);
if( !ctx->not_allocated )
- xfree ( ctx );
+ xfree( ctx );
}
}
-
-
/****************
* Search for a key with the given fingerprint.
* FIXME:
- * We should replace this with the _byname function. This can be done
+ * We should replace this with the _byname function. Thiscsan be done
* by creating a userID conforming to the unified fingerprint style.
*/
int
@@ -926,7 +1104,7 @@ get_pubkey_byfprint( PKT_public_key *pk,
get_pubkey_end( &ctx );
}
else
- rc = GPG_ERR_GENERAL; /* Oops */
+ rc = G10ERR_GENERAL; /* Oops */
return rc;
}
@@ -956,14 +1134,14 @@ get_pubkey_byfprint_fast (PKT_public_key *pk,
if (rc == -1)
{
keydb_release (hd);
- return GPG_ERR_NO_PUBKEY;
+ return G10ERR_NO_PUBKEY;
}
rc = keydb_get_keyblock (hd, &keyblock);
keydb_release (hd);
if (rc)
{
- log_error ("keydb_get_keyblock failed: %s\n", gpg_strerror (rc));
- return GPG_ERR_NO_PUBKEY;
+ log_error ("keydb_get_keyblock failed: %s\n", g10_errstr(rc));
+ return G10ERR_NO_PUBKEY;
}
assert ( keyblock->pkt->pkttype == PKT_PUBLIC_KEY
@@ -1002,7 +1180,7 @@ get_keyblock_byfprint( KBNODE *ret_keyblock, const byte *fprint,
get_pubkey_end( &ctx );
}
else
- rc = GPG_ERR_GENERAL; /* Oops */
+ rc = G10ERR_GENERAL; /* Oops */
return rc;
}
@@ -1014,44 +1192,31 @@ get_keyblock_byfprint( KBNODE *ret_keyblock, const byte *fprint,
*/
static int
get_seckey_byname2( GETKEY_CTX *retctx,
- PKT_secret_key *sk, const char *name, int unprotect,
- KBNODE *retblock )
+ PKT_secret_key *sk, const char *name, int unprotect,
+ KBNODE *retblock )
{
- STRLIST namelist = NULL;
- int rc;
+ STRLIST namelist = NULL;
+ int rc,include_unusable=1;
- if( !name && opt.def_secret_key && *opt.def_secret_key ) {
- add_to_strlist( &namelist, opt.def_secret_key );
- rc = key_byname( retctx, namelist, NULL, sk, 1, 1, retblock, NULL );
- }
- else if( !name ) { /* use the first one as default key */
- struct getkey_ctx_s ctx;
- KBNODE kb = NULL;
+ /* If we have no name, try to use the default secret key. If we
+ have no default, we'll use the first usable one. */
- assert (!retctx ); /* do we need this at all */
- assert (!retblock);
- memset( &ctx, 0, sizeof ctx );
- ctx.not_allocated = 1;
- ctx.kr_handle = keydb_new (1);
- ctx.nitems = 1;
- ctx.items[0].mode = KEYDB_SEARCH_MODE_FIRST;
- rc = lookup( &ctx, &kb, 1 );
- if (!rc && sk )
- sk_from_block ( &ctx, sk, kb );
- release_kbnode ( kb );
- get_seckey_end( &ctx );
- }
- else {
- add_to_strlist( &namelist, name );
- rc = key_byname( retctx, namelist, NULL, sk, 1, 1, retblock, NULL );
- }
+ if( !name && opt.def_secret_key && *opt.def_secret_key )
+ add_to_strlist( &namelist, opt.def_secret_key );
+ else if(name)
+ add_to_strlist( &namelist, name );
+ else
+ include_unusable=0;
- free_strlist( namelist );
+ rc = key_byname( retctx, namelist, NULL, sk, 1, include_unusable,
+ retblock, NULL );
- if( !rc && unprotect )
- rc = check_secret_key( sk, 0 );
+ free_strlist( namelist );
- return rc;
+ if( !rc && unprotect )
+ rc = check_secret_key( sk, 0 );
+
+ return rc;
}
int
@@ -1117,13 +1282,41 @@ get_seckey_byfprint( PKT_secret_key *sk,
if (!rc && sk )
sk_from_block ( &ctx, sk, kb );
release_kbnode ( kb );
- get_pubkey_end( &ctx );
+ get_seckey_end( &ctx );
}
else
- rc = GPG_ERR_GENERAL; /* Oops */
+ rc = G10ERR_GENERAL; /* Oops */
return rc;
}
+
+/* Search for a secret key with the given fingerprint and return the
+ complete keyblock which may have more than only this key. */
+int
+get_seckeyblock_byfprint (KBNODE *ret_keyblock, const byte *fprint,
+ size_t fprint_len )
+{
+ int rc;
+ struct getkey_ctx_s ctx;
+
+ if (fprint_len != 20 && fprint_len == 16)
+ return G10ERR_GENERAL; /* Oops */
+
+ memset (&ctx, 0, sizeof ctx);
+ ctx.not_allocated = 1;
+ ctx.kr_handle = keydb_new (1);
+ ctx.nitems = 1;
+ ctx.items[0].mode = (fprint_len==16
+ ? KEYDB_SEARCH_MODE_FPR16
+ : KEYDB_SEARCH_MODE_FPR20);
+ memcpy (ctx.items[0].u.fpr, fprint, fprint_len);
+ rc = lookup (&ctx, ret_keyblock, 1);
+ get_seckey_end (&ctx);
+
+ return rc;
+}
+
+
/************************************************
************* Merging stuff ********************
@@ -1220,6 +1413,59 @@ merge_keys_and_selfsig( KBNODE keyblock )
}
}
+static int
+parse_key_usage(PKT_signature *sig)
+{
+ int key_usage=0;
+ const byte *p;
+ size_t n;
+ byte flags;
+
+ p=parse_sig_subpkt(sig->hashed,SIGSUBPKT_KEY_FLAGS,&n);
+ if(p && n)
+ {
+ /* first octet of the keyflags */
+ flags=*p;
+
+ if(flags & 1)
+ {
+ key_usage |= PUBKEY_USAGE_CERT;
+ flags&=~1;
+ }
+
+ if(flags & 2)
+ {
+ key_usage |= PUBKEY_USAGE_SIG;
+ flags&=~2;
+ }
+
+ /* We do not distinguish between encrypting communications and
+ encrypting storage. */
+ if(flags & (0x04|0x08))
+ {
+ key_usage |= PUBKEY_USAGE_ENC;
+ flags&=~(0x04|0x08);
+ }
+
+ if(flags & 0x20)
+ {
+ key_usage |= PUBKEY_USAGE_AUTH;
+ flags&=~0x20;
+ }
+
+ if(flags)
+ key_usage |= PUBKEY_USAGE_UNKNOWN;
+ }
+
+ /* We set PUBKEY_USAGE_UNKNOWN to indicate that this key has a
+ capability that we do not handle. This serves to distinguish
+ between a zero key usage which we handle as the default
+ capabilities for that algorithm, and a usage that we do not
+ handle. */
+
+ return key_usage;
+}
+
/*
* Apply information from SIGNODE (which is the valid self-signature
* associated with that UID) to the UIDNODE:
@@ -1238,32 +1484,28 @@ fixup_uidnode ( KBNODE uidnode, KBNODE signode, u32 keycreated )
const byte *p, *sym, *hash, *zip;
size_t n, nsym, nhash, nzip;
+ sig->flags.chosen_selfsig = 1; /* we chose this one */
uid->created = 0; /* not created == invalid */
if ( IS_UID_REV ( sig ) ) {
uid->is_revoked = 1;
return; /* has been revoked */
}
+ uid->expiredate = sig->expiredate;
+
+ if(sig->flags.expired)
+ {
+ uid->is_expired = 1;
+ return; /* has expired */
+ }
+
uid->created = sig->timestamp; /* this one is okay */
uid->selfsigversion = sig->version;
/* If we got this far, it's not expired :) */
uid->is_expired = 0;
- uid->expiredate = sig->expiredate;
/* store the key flags in the helper variable for later processing */
- uid->help_key_usage = 0;
- p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_KEY_FLAGS, &n );
- if ( p && n ) {
- /* first octet of the keyflags */
- if ( (*p & 0x03) )
- uid->help_key_usage |= PUBKEY_USAGE_SIG;
- if ( (*p & 0x0c) )
- uid->help_key_usage |= PUBKEY_USAGE_ENC;
- /* Note: we do not set the CERT flag here because it can be assumed
- * that thre is no real policy to set it. */
- if ( (*p & 0x20) )
- uid->help_key_usage |= PUBKEY_USAGE_AUTH;
- }
+ uid->help_key_usage=parse_key_usage(sig);
/* ditto or the key expiration */
uid->help_key_expire = 0;
@@ -1318,20 +1560,29 @@ fixup_uidnode ( KBNODE uidnode, KBNODE signode, u32 keycreated )
}
/* see whether we have the MDC feature */
- uid->mdc_feature = 0;
+ uid->flags.mdc = 0;
p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_FEATURES, &n);
if (p && n && (p[0] & 0x01))
- uid->mdc_feature = 1;
+ uid->flags.mdc = 1;
/* and the keyserver modify flag */
- uid->ks_modify = 1;
+ uid->flags.ks_modify = 1;
p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_KS_FLAGS, &n);
if (p && n && (p[0] & 0x80))
- uid->ks_modify = 0;
+ uid->flags.ks_modify = 0;
+}
+
+static void
+sig_to_revoke_info(PKT_signature *sig,struct revoke_info *rinfo)
+{
+ rinfo->date = sig->timestamp;
+ rinfo->algo = sig->pubkey_algo;
+ rinfo->keyid[0] = sig->keyid[0];
+ rinfo->keyid[1] = sig->keyid[1];
}
static void
-merge_selfsigs_main( KBNODE keyblock, int *r_revoked )
+merge_selfsigs_main(KBNODE keyblock, int *r_revoked, struct revoke_info *rinfo)
{
PKT_public_key *pk = NULL;
KBNODE k;
@@ -1346,6 +1597,8 @@ merge_selfsigs_main( KBNODE keyblock, int *r_revoked )
byte sigversion = 0;
*r_revoked = 0;
+ memset(rinfo,0,sizeof(*rinfo));
+
if ( keyblock->pkt->pkttype != PKT_PUBLIC_KEY )
BUG ();
pk = keyblock->pkt->pkt.public_key;
@@ -1368,7 +1621,7 @@ merge_selfsigs_main( KBNODE keyblock, int *r_revoked )
*/
/* In case this key was already merged */
- xfree (pk->revkey);
+ xfree(pk->revkey);
pk->revkey=NULL;
pk->numrevkeys=0;
@@ -1391,6 +1644,7 @@ merge_selfsigs_main( KBNODE keyblock, int *r_revoked )
* that key.
*/
*r_revoked = 1;
+ sig_to_revoke_info(sig,rinfo);
}
else if ( IS_KEY_SIG (sig) ) {
/* Add any revocation keys onto the pk. This is
@@ -1459,42 +1713,34 @@ merge_selfsigs_main( KBNODE keyblock, int *r_revoked )
pk->numrevkeys*sizeof(struct revocation_key));
}
- if ( signode ) {
+ if ( signode )
+ {
/* some information from a direct key signature take precedence
* over the same information given in UID sigs.
*/
PKT_signature *sig = signode->pkt->pkt.signature;
const byte *p;
- size_t n;
-
- p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_KEY_FLAGS, &n );
- if ( p && n ) {
- /* first octet of the keyflags */
- if ( (*p & 0x03) )
- key_usage |= PUBKEY_USAGE_SIG;
- if ( (*p & 0x0c) )
- key_usage |= PUBKEY_USAGE_ENC;
- if ( (*p & 0x20) )
- key_usage |= PUBKEY_USAGE_AUTH;
- }
+
+ key_usage=parse_key_usage(sig);
p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_KEY_EXPIRE, NULL);
- if ( p ) {
- key_expire = keytimestamp + buffer_to_u32(p);
- key_expire_seen = 1;
- }
+ if ( p )
+ {
+ key_expire = keytimestamp + buffer_to_u32(p);
+ key_expire_seen = 1;
+ }
/* mark that key as valid: one direct key signature should
* render a key as valid */
pk->is_valid = 1;
- }
+ }
/* pass 1.5: look for key revocation signatures that were not made
by the key (i.e. did a revocation key issue a revocation for
us?). Only bother to do this if there is a revocation key in
- the first place. */
+ the first place and we're not revoked already. */
- if(pk->revkey)
+ if(!*r_revoked && pk->revkey)
for(k=keyblock; k && k->pkt->pkttype != PKT_USER_ID; k = k->next )
{
if ( k->pkt->pkttype == PKT_SIGNATURE )
@@ -1504,15 +1750,26 @@ merge_selfsigs_main( KBNODE keyblock, int *r_revoked )
if(IS_KEY_REV(sig) &&
(sig->keyid[0]!=kid[0] || sig->keyid[1]!=kid[1]))
{
- /* Failure here means the sig did not verify, is was
- not issued by a revocation key, or a revocation
- key loop was broken. */
+ int rc=check_revocation_keys(pk,sig);
+ if(rc==0)
+ {
+ *r_revoked=2;
+ sig_to_revoke_info(sig,rinfo);
+ /* don't continue checking since we can't be any
+ more revoked than this */
+ break;
+ }
+ else if(rc==G10ERR_NO_PUBKEY)
+ pk->maybe_revoked=1;
- if(check_revocation_keys(pk,sig)==0)
- *r_revoked=1;
+ /* A failure here means the sig did not verify, was
+ not issued by a revocation key, or a revocation
+ key loop was broken. If a revocation key isn't
+ findable, however, the key might be revoked and
+ we don't know it. */
- /* In the future handle subkey and cert revocations?
- PGP doesn't, but it's in 2440. */
+ /* TODO: In the future handle subkey and cert
+ revocations? PGP doesn't, but it's in 2440. */
}
}
}
@@ -1537,7 +1794,8 @@ merge_selfsigs_main( KBNODE keyblock, int *r_revoked )
if ( check_key_signature( keyblock, k, NULL ) )
; /* signature did not verify */
else if ( (IS_UID_SIG (sig) || IS_UID_REV (sig))
- && sig->timestamp >= sigdate ) {
+ && sig->timestamp >= sigdate )
+ {
/* Note: we allow to invalidate cert revocations
* by a newer signature. An attacker can't use this
* because a key should be revoced with a key revocation.
@@ -1546,20 +1804,13 @@ merge_selfsigs_main( KBNODE keyblock, int *r_revoked )
* the same email address may become valid again (hired,
* fired, hired again).
*/
- if(sig->flags.expired) {
- /* Expired uids don't get to be primary unless
- they are the only uid there is. */
- uidnode->pkt->pkt.user_id->is_primary=0;
- uidnode->pkt->pkt.user_id->is_expired=1;
- uidnode->pkt->pkt.user_id->expiredate=sig->expiredate;
- }
- else {
- sigdate = sig->timestamp;
- signode = k;
- if( sig->version > sigversion )
- sigversion = sig->version;
- }
- }
+
+ sigdate = sig->timestamp;
+ signode = k;
+ signode->pkt->pkt.signature->flags.chosen_selfsig=0;
+ if( sig->version > sigversion )
+ sigversion = sig->version;
+ }
}
}
}
@@ -1573,10 +1824,8 @@ merge_selfsigs_main( KBNODE keyblock, int *r_revoked )
if(!pk->is_valid && opt.allow_non_selfsigned_uid)
{
if(opt.verbose)
- log_info(_("Invalid key %08lX made valid by "
- "--allow-non-selfsigned-uid\n"),
- (ulong)keyid_from_pk(pk,NULL));
-
+ log_info(_("Invalid key %s made valid by"
+ " --allow-non-selfsigned-uid\n"),keystr_from_pk(pk));
pk->is_valid = 1;
}
@@ -1598,7 +1847,7 @@ merge_selfsigs_main( KBNODE keyblock, int *r_revoked )
{
PKT_public_key *ultimate_pk;
- ultimate_pk=xcalloc (1,sizeof(*ultimate_pk));
+ ultimate_pk=xmalloc_clear(sizeof(*ultimate_pk));
/* We don't want to use the full get_pubkey to
avoid infinite recursion in certain cases.
@@ -1608,7 +1857,7 @@ merge_selfsigs_main( KBNODE keyblock, int *r_revoked )
ultimate trust flag. */
if(get_pubkey_fast(ultimate_pk,sig->keyid)==0
&& check_key_signature2(keyblock,k,ultimate_pk,
- NULL, NULL, NULL, NULL)==0
+ NULL,NULL,NULL,NULL)==0
&& get_ownertrust(ultimate_pk)==TRUST_ULTIMATE)
{
free_public_key(ultimate_pk);
@@ -1659,7 +1908,9 @@ merge_selfsigs_main( KBNODE keyblock, int *r_revoked )
if ( x ) /* mask it down to the actual allowed usage */
key_usage &= x;
}
- pk->pubkey_usage = key_usage;
+
+ /* Whatever happens, it's a primary key, so it can certify. */
+ pk->pubkey_usage = key_usage|PUBKEY_USAGE_CERT;
if ( !key_expire_seen ) {
/* find the latest valid user ID with a key expiration set
@@ -1799,7 +2050,6 @@ merge_selfsigs_subkey( KBNODE keyblock, KBNODE subnode )
u32 keytimestamp = 0;
u32 key_expire = 0;
const byte *p;
- size_t n;
if ( subnode->pkt->pkttype != PKT_PUBLIC_SUBKEY )
BUG ();
@@ -1834,47 +2084,47 @@ merge_selfsigs_subkey( KBNODE keyblock, KBNODE subnode )
problem is in the distribution. Plus, PGP (7)
does this the same way. */
subpk->is_revoked = 1;
+ sig_to_revoke_info(sig,&subpk->revoked);
/* although we could stop now, we continue to
* figure out other information like the old expiration
* time */
}
- else if ( IS_SUBKEY_SIG (sig) && sig->timestamp >= sigdate ) {
+ else if ( IS_SUBKEY_SIG (sig) && sig->timestamp >= sigdate )
+ {
if(sig->flags.expired)
- ; /* signature has expired - ignore it */
- else {
+ ; /* signature has expired - ignore it */
+ else
+ {
sigdate = sig->timestamp;
signode = k;
- }
- }
+ signode->pkt->pkt.signature->flags.chosen_selfsig=0;
+ }
+ }
}
}
}
- if ( !signode ) {
- return; /* no valid key binding */
- }
+ /* no valid key binding */
+ if ( !signode )
+ return;
- subpk->is_valid = 1;
sig = signode->pkt->pkt.signature;
-
- p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_KEY_FLAGS, &n );
- if ( p && n ) {
- /* first octet of the keyflags */
- if ( (*p & 0x03) )
- key_usage |= PUBKEY_USAGE_SIG;
- if ( (*p & 0x0c) )
- key_usage |= PUBKEY_USAGE_ENC;
- if ( (*p & 0x20) )
- key_usage |= PUBKEY_USAGE_AUTH;
- }
- if ( !key_usage ) { /* no key flags at all: get it from the algo */
+ sig->flags.chosen_selfsig=1; /* so we know which selfsig we chose later */
+
+ key_usage=parse_key_usage(sig);
+ if ( !key_usage )
+ {
+ /* no key flags at all: get it from the algo */
key_usage = openpgp_pk_algo_usage ( subpk->pubkey_algo );
- }
- else { /* check that the usage matches the usage as given by the algo */
+ }
+ else
+ {
+ /* check that the usage matches the usage as given by the algo */
int x = openpgp_pk_algo_usage ( subpk->pubkey_algo );
if ( x ) /* mask it down to the actual allowed usage */
- key_usage &= x;
- }
+ key_usage &= x;
+ }
+
subpk->pubkey_usage = key_usage;
p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_KEY_EXPIRE, NULL);
@@ -1884,8 +2134,56 @@ merge_selfsigs_subkey( KBNODE keyblock, KBNODE subnode )
key_expire = 0;
subpk->has_expired = key_expire >= curtime? 0 : key_expire;
subpk->expiredate = key_expire;
-}
+ /* algo doesn't exist */
+ if(openpgp_pk_test_algo(subpk->pubkey_algo))
+ return;
+
+ subpk->is_valid = 1;
+
+ /* Find the first 0x19 embedded signature on our self-sig. */
+ if(subpk->backsig==0)
+ {
+ int seq=0;
+ size_t n;
+
+ /* We do this while() since there may be other embedded
+ signatures in the future. We only want 0x19 here. */
+ while((p=enum_sig_subpkt(sig->hashed,
+ SIGSUBPKT_SIGNATURE,&n,&seq,NULL)))
+ if(n>3 && ((p[0]==3 && p[2]==0x19) || (p[0]==4 && p[1]==0x19)))
+ break;
+
+ if(p==NULL)
+ {
+ seq=0;
+ /* It is safe to have this in the unhashed area since the
+ 0x19 is located on the selfsig for convenience, not
+ security. */
+ while((p=enum_sig_subpkt(sig->unhashed,SIGSUBPKT_SIGNATURE,
+ &n,&seq,NULL)))
+ if(n>3 && ((p[0]==3 && p[2]==0x19) || (p[0]==4 && p[1]==0x19)))
+ break;
+ }
+
+ if(p)
+ {
+ PKT_signature *backsig=xmalloc_clear(sizeof(PKT_signature));
+ IOBUF backsig_buf=iobuf_temp_with_content(p,n);
+
+ if(parse_signature(backsig_buf,PKT_SIGNATURE,n,backsig)==0)
+ {
+ if(check_backsig(mainpk,subpk,backsig)==0)
+ subpk->backsig=2;
+ else
+ subpk->backsig=1;
+ }
+
+ iobuf_close(backsig_buf);
+ free_seckey_enc(backsig);
+ }
+ }
+}
/*
@@ -1905,6 +2203,7 @@ merge_selfsigs( KBNODE keyblock )
{
KBNODE k;
int revoked;
+ struct revoke_info rinfo;
PKT_public_key *main_pk;
prefitem_t *prefs;
int mdc_feature;
@@ -1921,7 +2220,7 @@ merge_selfsigs( KBNODE keyblock )
BUG ();
}
- merge_selfsigs_main ( keyblock, &revoked );
+ merge_selfsigs_main ( keyblock, &revoked, &rinfo );
/* now merge in the data from each of the subkeys */
for(k=keyblock; k; k = k->next ) {
@@ -1941,8 +2240,11 @@ merge_selfsigs( KBNODE keyblock )
PKT_public_key *pk = k->pkt->pkt.public_key;
if(!main_pk->is_valid)
pk->is_valid = 0;
- if(revoked)
- pk->is_revoked = 1;
+ if(revoked && !pk->is_revoked)
+ {
+ pk->is_revoked = revoked;
+ memcpy(&pk->revoked,&rinfo,sizeof(rinfo));
+ }
if(main_pk->has_expired)
pk->has_expired = main_pk->has_expired;
}
@@ -1966,7 +2268,7 @@ merge_selfsigs( KBNODE keyblock )
&& !k->pkt->pkt.user_id->attrib_data
&& k->pkt->pkt.user_id->is_primary) {
prefs = k->pkt->pkt.user_id->prefs;
- mdc_feature = k->pkt->pkt.user_id->mdc_feature;
+ mdc_feature = k->pkt->pkt.user_id->flags.mdc;
break;
}
}
@@ -2076,14 +2378,14 @@ premerge_public_with_secret ( KBNODE pubblock, KBNODE secblock )
KBNODE next, ll;
if (opt.verbose)
- log_info ( _("no secret subkey "
- "for public subkey %08lX - ignoring\n"),
- (ulong)keyid_from_pk (pk,NULL) );
+ log_info (_("no secret subkey"
+ " for public subkey %s - ignoring\n"),
+ keystr_from_pk (pk));
/* we have to remove the subkey in this case */
assert ( last );
/* find the next subkey */
for (next=pub->next,ll=pub;
- next && pub->pkt->pkttype != PKT_PUBLIC_SUBKEY;
+ next && next->pkt->pkttype != PKT_PUBLIC_SUBKEY;
ll = next, next = next->next )
;
/* make new link */
@@ -2141,7 +2443,7 @@ finish_lookup (GETKEY_CTX ctx)
KBNODE k;
KBNODE foundk = NULL;
PKT_user_id *foundu = NULL;
-#define USAGE_MASK (PUBKEY_USAGE_SIG|PUBKEY_USAGE_ENC)
+#define USAGE_MASK (PUBKEY_USAGE_SIG|PUBKEY_USAGE_ENC|PUBKEY_USAGE_CERT)
unsigned int req_usage = ( ctx->req_usage & USAGE_MASK );
/* Request the primary if we're certifying another key, and also
if signing data while --pgp6 or --pgp7 is on since pgp 6 and 7
@@ -2303,12 +2605,14 @@ finish_lookup (GETKEY_CTX ctx)
ctx->found_key = latest_key;
- if (latest_key != keyblock && opt.verbose) {
- log_info(_("using secondary key %08lX "
- "instead of primary key %08lX\n"),
- (ulong)keyid_from_pk( latest_key->pkt->pkt.public_key, NULL),
- (ulong)keyid_from_pk( keyblock->pkt->pkt.public_key, NULL) );
- }
+ if (latest_key != keyblock && opt.verbose)
+ {
+ char *tempkeystr=
+ xstrdup(keystr_from_pk(latest_key->pkt->pkt.public_key));
+ log_info(_("using subkey %s instead of primary key %s\n"),
+ tempkeystr, keystr_from_pk(keyblock->pkt->pkt.public_key));
+ xfree(tempkeystr);
+ }
cache_user_id( keyblock );
@@ -2333,7 +2637,7 @@ lookup( GETKEY_CTX ctx, KBNODE *ret_keyblock, int secmode )
rc = keydb_get_keyblock (ctx->kr_handle, &ctx->keyblock);
if (rc) {
- log_error ("keydb_get_keyblock failed: %s\n", gpg_strerror (rc));
+ log_error ("keydb_get_keyblock failed: %s\n", g10_errstr(rc));
rc = 0;
goto skip;
}
@@ -2349,12 +2653,13 @@ lookup( GETKEY_CTX ctx, KBNODE *ret_keyblock, int secmode )
keyid_from_sk (k->pkt->pkt.secret_key, aki);
k = get_pubkeyblock (aki);
- if( !k ) {
+ if( !k )
+ {
if (!opt.quiet)
- log_info(_("key %08lX: secret key without public key "
- "- skipped\n"), (ulong)aki[1] );
+ log_info(_("key %s: secret key without public key"
+ " - skipped\n"), keystr(aki));
goto skip;
- }
+ }
secblock = ctx->keyblock;
ctx->keyblock = k;
@@ -2390,16 +2695,16 @@ lookup( GETKEY_CTX ctx, KBNODE *ret_keyblock, int secmode )
found:
if( rc && rc != -1 )
- log_error("keydb_search failed: %s\n", gpg_strerror (rc));
+ log_error("keydb_search failed: %s\n", g10_errstr(rc));
if( !rc ) {
*ret_keyblock = ctx->keyblock; /* return the keyblock */
ctx->keyblock = NULL;
}
else if (rc == -1 && no_suitable_key)
- rc = secmode ? GPG_ERR_UNUSABLE_SECKEY : GPG_ERR_UNUSABLE_PUBKEY;
+ rc = secmode ? G10ERR_UNU_SECKEY : G10ERR_UNU_PUBKEY;
else if( rc == -1 )
- rc = secmode ? GPG_ERR_NO_SECKEY : GPG_ERR_NO_PUBKEY;
+ rc = secmode ? G10ERR_NO_SECKEY : G10ERR_NO_PUBKEY;
if ( secmode ) {
release_kbnode( secblock );
@@ -2449,7 +2754,7 @@ enum_secret_keys( void **context, PKT_secret_key *sk,
if( !c ) { /* make a new context */
- c = xcalloc (1, sizeof *c );
+ c = xmalloc_clear( sizeof *c );
*context = c;
c->hd = keydb_new (1);
c->first = 1;
@@ -2460,7 +2765,7 @@ enum_secret_keys( void **context, PKT_secret_key *sk,
if( !sk ) { /* free the context */
keydb_release (c->hd);
release_kbnode (c->keyblock);
- xfree ( c );
+ xfree( c );
*context = NULL;
return 0;
}
@@ -2507,43 +2812,44 @@ enum_secret_keys( void **context, PKT_secret_key *sk,
/****************
* Return a string with a printable representation of the user_id.
- * this string must be freed by m_free.
+ * this string must be freed by xfree.
*/
char*
get_user_id_string( u32 *keyid )
{
- user_id_db_t r;
- char *p;
- int pass=0;
- /* try it two times; second pass reads from key resources */
- do {
- for(r=user_id_db; r; r = r->next ) {
- keyid_list_t a;
- for (a=r->keyids; a; a= a->next ) {
- if( a->keyid[0] == keyid[0] && a->keyid[1] == keyid[1] ) {
- p = xmalloc ( r->len + 10 );
- sprintf(p, "%08lX %.*s",
- (ulong)keyid[1], r->len, r->name );
- return p;
- }
- }
+ user_id_db_t r;
+ char *p;
+ int pass=0;
+ /* try it two times; second pass reads from key resources */
+ do
+ {
+ for(r=user_id_db; r; r = r->next )
+ {
+ keyid_list_t a;
+ for (a=r->keyids; a; a= a->next )
+ {
+ if( a->keyid[0] == keyid[0] && a->keyid[1] == keyid[1] )
+ {
+ p = xmalloc( keystrlen() + 1 + r->len + 1 );
+ sprintf(p, "%s %.*s", keystr(keyid), r->len, r->name );
+ return p;
+ }
+ }
}
} while( ++pass < 2 && !get_pubkey( NULL, keyid ) );
- p = xmalloc ( 15 );
- sprintf(p, "%08lX [?]", (ulong)keyid[1] );
- return p;
+ p = xmalloc( keystrlen() + 5 );
+ sprintf(p, "%s [?]", keystr(keyid));
+ return p;
}
char*
-get_user_id_string_printable ( u32 *keyid )
+get_user_id_string_native ( u32 *keyid )
{
- char *p = get_user_id_string( keyid );
- char *p2 = utf8_to_native( p, strlen(p), 0 );
- xfree (p);
- p = make_printable_string (p2, strlen (p2), 0);
- xfree (p2);
- return p;
+ char *p = get_user_id_string( keyid );
+ char *p2 = utf8_to_native( p, strlen(p), 0 );
+ xfree(p);
+ return p2;
}
@@ -2559,7 +2865,7 @@ get_long_user_id_string( u32 *keyid )
keyid_list_t a;
for (a=r->keyids; a; a= a->next ) {
if( a->keyid[0] == keyid[0] && a->keyid[1] == keyid[1] ) {
- p = xmalloc ( r->len + 20 );
+ p = xmalloc( r->len + 20 );
sprintf(p, "%08lX%08lX %.*s",
(ulong)keyid[0], (ulong)keyid[1],
r->len, r->name );
@@ -2568,7 +2874,7 @@ get_long_user_id_string( u32 *keyid )
}
}
} while( ++pass < 2 && !get_pubkey( NULL, keyid ) );
- p = xmalloc ( 25 );
+ p = xmalloc( 25 );
sprintf(p, "%08lX%08lX [?]", (ulong)keyid[0], (ulong)keyid[1] );
return p;
}
@@ -2586,7 +2892,7 @@ get_user_id( u32 *keyid, size_t *rn )
keyid_list_t a;
for (a=r->keyids; a; a= a->next ) {
if( a->keyid[0] == keyid[0] && a->keyid[1] == keyid[1] ) {
- p = xmalloc ( r->len );
+ p = xmalloc( r->len );
memcpy(p, r->name, r->len );
*rn = r->len;
return p;
@@ -2594,21 +2900,19 @@ get_user_id( u32 *keyid, size_t *rn )
}
}
} while( ++pass < 2 && !get_pubkey( NULL, keyid ) );
- p = xstrdup ( _("[User id not found]") );
+ p = xstrdup( user_id_not_found_utf8 () );
*rn = strlen(p);
return p;
}
char*
-get_user_id_printable( u32 *keyid )
+get_user_id_native( u32 *keyid )
{
- size_t rn;
- char *p = get_user_id( keyid, &rn );
- char *p2 = utf8_to_native( p, rn, 0 );
- xfree (p);
- p = make_printable_string (p2, strlen (p2), 0);
- xfree (p2);
- return p;
+ size_t rn;
+ char *p = get_user_id( keyid, &rn );
+ char *p2 = utf8_to_native( p, rn, 0 );
+ xfree(p);
+ return p2;
}
KEYDB_HANDLE
@@ -2616,3 +2920,85 @@ get_ctx_handle(GETKEY_CTX ctx)
{
return ctx->kr_handle;
}
+
+static void
+free_akl(struct akl *akl)
+{
+ if(akl->spec)
+ free_keyserver_spec(akl->spec);
+
+ xfree(akl);
+}
+
+void
+release_akl(void)
+{
+ while(opt.auto_key_locate)
+ {
+ struct akl *akl2=opt.auto_key_locate;
+ opt.auto_key_locate=opt.auto_key_locate->next;
+ free_akl(akl2);
+ }
+}
+
+int
+parse_auto_key_locate(char *options)
+{
+ char *tok;
+
+ while((tok=optsep(&options)))
+ {
+ struct akl *akl,*last;
+ int dupe=0;
+
+ if(tok[0]=='\0')
+ continue;
+
+ akl=xmalloc_clear(sizeof(*akl));
+
+ if(ascii_strcasecmp(tok,"ldap")==0)
+ akl->type=AKL_LDAP;
+ else if(ascii_strcasecmp(tok,"keyserver")==0)
+ akl->type=AKL_KEYSERVER;
+#ifdef USE_DNS_CERT
+ else if(ascii_strcasecmp(tok,"cert")==0)
+ akl->type=AKL_CERT;
+#endif
+#ifdef USE_DNS_PKA
+ else if(ascii_strcasecmp(tok,"pka")==0)
+ akl->type=AKL_PKA;
+#endif
+ else if((akl->spec=parse_keyserver_uri(tok,1,NULL,0)))
+ akl->type=AKL_SPEC;
+ else
+ {
+ free_akl(akl);
+ return 0;
+ }
+
+ /* We must maintain the order the user gave us */
+ for(last=opt.auto_key_locate;last && last->next;last=last->next)
+ {
+ /* Check for duplicates */
+ if(last && last->type==akl->type
+ && (akl->type!=AKL_SPEC
+ || (akl->type==AKL_SPEC
+ && strcmp(last->spec->uri,akl->spec->uri)==0)))
+ {
+ dupe=1;
+ free_akl(akl);
+ break;
+ }
+ }
+
+ if(!dupe)
+ {
+ if(last)
+ last->next=akl;
+ else
+ opt.auto_key_locate=akl;
+ }
+ }
+
+ return 1;
+}