X-Git-Url: http://git.gnupg.org/cgi-bin/gitweb.cgi?p=gnupg.git;a=blobdiff_plain;f=g10%2Fgetkey.c;h=81b15b2e21638e2d28f9d17f03dfbfc769ca501a;hp=0762a737da540bb67aefbe7a27c071ca5c24f719;hb=09e3b78ea26246ad7d180030b41b50bb09d543a0;hpb=7d74743c0ed48f31b8d00a7a0e11108c4ed1d254 diff --git a/g10/getkey.c b/g10/getkey.c index 0762a737d..81b15b2e2 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 - * 2004 Free Software Foundation, Inc. + * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, + * 2005 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 @@ -34,6 +35,7 @@ #include "main.h" #include "trustdb.h" #include "i18n.h" +#include "keyserver-internal.h" #define MAX_PK_CACHE_ENTRIES PK_UID_CACHE_SIZE #define MAX_UID_CACHE_ENTRIES PK_UID_CACHE_SIZE @@ -151,7 +153,7 @@ cache_public_key( PKT_public_key *pk ) return; } pk_cache_entries++; - ce = m_alloc( sizeof *ce ); + ce = xmalloc( sizeof *ce ); ce->next = pk_cache; pk_cache = ce; ce->pk = copy_public_key( NULL, pk ); @@ -183,7 +185,7 @@ get_primary_uid ( KBNODE keyblock, size_t *uidlen ) } /* 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]"); *uidlen = strlen (s); return s; } @@ -194,7 +196,7 @@ release_keyid_list ( keyid_list_t k ) { while ( k ) { keyid_list_t k2 = k->next; - m_free (k); + xfree (k); k = k2; } } @@ -215,7 +217,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 = m_alloc_clear ( 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 ); @@ -228,7 +230,7 @@ cache_user_id( KBNODE keyblock ) if( DBG_CACHE ) log_debug("cache_user_id: already in cache\n"); release_keyid_list ( keyids ); - m_free ( a ); + xfree ( a ); return; } } @@ -249,10 +251,10 @@ cache_user_id( KBNODE keyblock ) r = user_id_db; user_id_db = r->next; release_keyid_list ( r->keyids ); - m_free(r); + xfree(r); uid_cache_entries--; } - r = m_alloc( sizeof *r + uidlen-1 ); + r = xmalloc( sizeof *r + uidlen-1 ); r->keyids = keyids; r->len = uidlen; memcpy(r->name, uid, r->len); @@ -272,7 +274,7 @@ getkey_disable_caches() for( ce = pk_cache; ce; ce = ce2 ) { ce2 = ce->next; free_public_key( ce->pk ); - m_free( ce ); + xfree( ce ); } pk_cache_disabled=1; pk_cache_entries = 0; @@ -337,7 +339,7 @@ get_pubkey( PKT_public_key *pk, u32 *keyid ) #endif /* more init stuff */ if( !pk ) { - pk = m_alloc_clear( sizeof *pk ); + pk = xmalloc_clear( sizeof *pk ); internal++; } @@ -588,11 +590,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; @@ -617,11 +621,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*/ @@ -809,7 +815,7 @@ key_byname( GETKEY_CTX *retctx, STRLIST namelist, if(!namelist) { - ctx = m_alloc_clear (sizeof *ctx); + ctx = xmalloc_clear (sizeof *ctx); ctx->nitems = 1; ctx->items[0].mode=KEYDB_SEARCH_MODE_FIRST; if(!include_unusable) @@ -821,7 +827,7 @@ key_byname( GETKEY_CTX *retctx, STRLIST namelist, for(n=0, r=namelist; r; r = r->next ) n++; - ctx = m_alloc_clear (sizeof *ctx + (n-1)*sizeof ctx->items ); + ctx = xmalloc_clear (sizeof *ctx + (n-1)*sizeof ctx->items ); ctx->nitems = n; for(n=0, r=namelist; r; r = r->next, n++ ) @@ -832,7 +838,7 @@ key_byname( GETKEY_CTX *retctx, STRLIST namelist, ctx->exact = 1; if (!ctx->items[n].mode) { - m_free (ctx); + xfree (ctx); return G10ERR_INV_USER_ID; } if(!include_unusable @@ -885,24 +891,123 @@ 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_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_unusable, 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)) + { + int res; + struct akl *akl; + + for(akl=opt.auto_key_locate;akl;akl=akl->next) + { + switch(akl->type) + { + case AKL_CERT: + glo_ctrl.in_auto_key_retrieve++; + res=keyserver_import_cert(name); + glo_ctrl.in_auto_key_retrieve--; + + if(res==0) + log_info(_("Automatically retrieved `%s' via %s\n"), + name,"DNS CERT"); + break; + + case AKL_PKA: + { + unsigned char fpr[MAX_FINGERPRINT_LEN]; + + glo_ctrl.in_auto_key_retrieve++; + res=keyserver_import_pka(name,fpr); + glo_ctrl.in_auto_key_retrieve--; + + if(res==0) + { + int i; + char fpr_string[MAX_FINGERPRINT_LEN*2+1]; + + log_info(_("Automatically retrieved `%s' via %s\n"), + name,"PKA"); + + free_strlist(namelist); + namelist=NULL; + + for(i=0;iuri); + } + break; + + case AKL_SPEC: + glo_ctrl.in_auto_key_retrieve++; + res=keyserver_import_name(name,akl->spec); + glo_ctrl.in_auto_key_retrieve--; + + if(res==0) + log_info(_("Automatically retrieved `%s' via %s\n"), + name,akl->spec->uri); + break; + } + + 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 @@ -931,7 +1036,7 @@ get_pubkey_end( GETKEY_CTX ctx ) memset (&ctx->kbpos, 0, sizeof ctx->kbpos); keydb_release (ctx->kr_handle); if( !ctx->not_allocated ) - m_free( ctx ); + xfree( ctx ); } } @@ -1055,44 +1160,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 @@ -1158,13 +1250,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 = 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 ******************** @@ -1261,6 +1381,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: @@ -1286,26 +1459,21 @@ fixup_uidnode ( KBNODE uidnode, KBNODE signode, u32 keycreated ) 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 & 3) ) - uid->help_key_usage |= PUBKEY_USAGE_SIG; - if ( (*p & 12) ) - 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; @@ -1336,12 +1504,12 @@ fixup_uidnode ( KBNODE uidnode, KBNODE signode, u32 keycreated ) p = parse_sig_subpkt ( sig->hashed, SIGSUBPKT_PREF_COMPR, &n ); zip = p; nzip = p?n:0; if (uid->prefs) - m_free (uid->prefs); + xfree (uid->prefs); n = nsym + nhash + nzip; if (!n) uid->prefs = NULL; else { - uid->prefs = m_alloc (sizeof (*uid->prefs) * (n+1)); + uid->prefs = xmalloc (sizeof (*uid->prefs) * (n+1)); n = 0; for (; nsym; nsym--, n++) { uid->prefs[n].type = PREFTYPE_SYM; @@ -1360,20 +1528,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 -merge_selfsigs_main( KBNODE keyblock, int *r_revoked, u32 *r_revokedate ) +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, struct revoke_info *rinfo) { PKT_public_key *pk = NULL; KBNODE k; @@ -1388,7 +1565,8 @@ merge_selfsigs_main( KBNODE keyblock, int *r_revoked, u32 *r_revokedate ) byte sigversion = 0; *r_revoked = 0; - *r_revokedate = 0; + memset(rinfo,0,sizeof(*rinfo)); + if ( keyblock->pkt->pkttype != PKT_PUBLIC_KEY ) BUG (); pk = keyblock->pkt->pkt.public_key; @@ -1411,7 +1589,7 @@ merge_selfsigs_main( KBNODE keyblock, int *r_revoked, u32 *r_revokedate ) */ /* In case this key was already merged */ - m_free(pk->revkey); + xfree(pk->revkey); pk->revkey=NULL; pk->numrevkeys=0; @@ -1434,7 +1612,7 @@ merge_selfsigs_main( KBNODE keyblock, int *r_revoked, u32 *r_revokedate ) * that key. */ *r_revoked = 1; - *r_revokedate = sig->timestamp; + sig_to_revoke_info(sig,rinfo); } else if ( IS_KEY_SIG (sig) ) { /* Add any revocation keys onto the pk. This is @@ -1448,7 +1626,7 @@ merge_selfsigs_main( KBNODE keyblock, int *r_revoked, u32 *r_revokedate ) int i; pk->revkey= - m_realloc(pk->revkey,sizeof(struct revocation_key)* + xrealloc(pk->revkey,sizeof(struct revocation_key)* (pk->numrevkeys+sig->numrevkeys)); for(i=0;inumrevkeys;i++) @@ -1499,39 +1677,31 @@ merge_selfsigs_main( KBNODE keyblock, int *r_revoked, u32 *r_revokedate ) } if(changed) - pk->revkey=m_realloc(pk->revkey, + pk->revkey=xrealloc(pk->revkey, 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 & 3) ) - key_usage |= PUBKEY_USAGE_SIG; - if ( (*p & 12) ) - 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 @@ -1552,7 +1722,7 @@ merge_selfsigs_main( KBNODE keyblock, int *r_revoked, u32 *r_revokedate ) if(rc==0) { *r_revoked=2; - *r_revokedate=sig->timestamp; + sig_to_revoke_info(sig,rinfo); /* don't continue checking since we can't be any more revoked than this */ break; @@ -1592,7 +1762,8 @@ merge_selfsigs_main( KBNODE keyblock, int *r_revoked, u32 *r_revokedate ) 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. @@ -1601,22 +1772,13 @@ merge_selfsigs_main( KBNODE keyblock, int *r_revoked, u32 *r_revokedate ) * the same email address may become valid again (hired, * fired, hired again). */ - if(sig->flags.expired) - { - uidnode->pkt->pkt.user_id->is_expired=1; - signode = NULL; - } - else - { - uidnode->pkt->pkt.user_id->is_expired=0; - signode = k; - } sigdate = sig->timestamp; - uidnode->pkt->pkt.user_id->expiredate=sig->expiredate; + signode = k; + signode->pkt->pkt.signature->flags.chosen_selfsig=0; if( sig->version > sigversion ) sigversion = sig->version; - } + } } } } @@ -1653,7 +1815,7 @@ merge_selfsigs_main( KBNODE keyblock, int *r_revoked, u32 *r_revokedate ) { PKT_public_key *ultimate_pk; - ultimate_pk=m_alloc_clear(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. @@ -1714,7 +1876,9 @@ merge_selfsigs_main( KBNODE keyblock, int *r_revoked, u32 *r_revokedate ) 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 @@ -1854,7 +2018,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 (); @@ -1889,19 +2052,22 @@ merge_selfsigs_subkey( KBNODE keyblock, KBNODE subnode ) problem is in the distribution. Plus, PGP (7) does this the same way. */ subpk->is_revoked = 1; - subpk->revokedate = sig->timestamp; + 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; + } + } } } } @@ -1912,25 +2078,21 @@ merge_selfsigs_subkey( KBNODE keyblock, KBNODE subnode ) sig = signode->pkt->pkt.signature; sig->flags.chosen_selfsig=1; /* so we know which selfsig we chose later */ - - p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_KEY_FLAGS, &n ); - if ( p && n ) { - /* first octet of the keyflags */ - if ( (*p & 3) ) - key_usage |= PUBKEY_USAGE_SIG; - if ( (*p & 12) ) - 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 */ + + 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); @@ -1947,15 +2109,14 @@ merge_selfsigs_subkey( KBNODE keyblock, KBNODE subnode ) subpk->is_valid = 1; -#ifndef DO_BACKSIGS - /* Pretend the backsig is present and accounted for. */ - subpk->backsig=2; -#else /* 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))) @@ -1965,7 +2126,8 @@ merge_selfsigs_subkey( KBNODE keyblock, KBNODE subnode ) { seq=0; /* It is safe to have this in the unhashed area since the - 0x19 is located here for convenience, not security. */ + 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))) @@ -1974,7 +2136,7 @@ merge_selfsigs_subkey( KBNODE keyblock, KBNODE subnode ) if(p) { - PKT_signature *backsig=m_alloc_clear(sizeof(PKT_signature)); + 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) @@ -1989,7 +2151,6 @@ merge_selfsigs_subkey( KBNODE keyblock, KBNODE subnode ) free_seckey_enc(backsig); } } -#endif } @@ -2010,7 +2171,7 @@ merge_selfsigs( KBNODE keyblock ) { KBNODE k; int revoked; - u32 revokedate; + struct revoke_info rinfo; PKT_public_key *main_pk; prefitem_t *prefs; int mdc_feature; @@ -2027,7 +2188,7 @@ merge_selfsigs( KBNODE keyblock ) BUG (); } - merge_selfsigs_main ( keyblock, &revoked, &revokedate ); + merge_selfsigs_main ( keyblock, &revoked, &rinfo ); /* now merge in the data from each of the subkeys */ for(k=keyblock; k; k = k->next ) { @@ -2050,7 +2211,7 @@ merge_selfsigs( KBNODE keyblock ) if(revoked && !pk->is_revoked) { pk->is_revoked = revoked; - pk->revokedate = revokedate; + memcpy(&pk->revoked,&rinfo,sizeof(rinfo)); } if(main_pk->has_expired) pk->has_expired = main_pk->has_expired; @@ -2075,7 +2236,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; } } @@ -2084,7 +2245,7 @@ merge_selfsigs( KBNODE keyblock ) || k->pkt->pkttype == PKT_PUBLIC_SUBKEY ) { PKT_public_key *pk = k->pkt->pkt.public_key; if (pk->prefs) - m_free (pk->prefs); + xfree (pk->prefs); pk->prefs = copy_prefs (prefs); pk->mdc_feature = mdc_feature; } @@ -2192,7 +2353,7 @@ premerge_public_with_secret ( KBNODE pubblock, KBNODE secblock ) 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 */ @@ -2250,7 +2411,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 @@ -2415,10 +2576,10 @@ finish_lookup (GETKEY_CTX ctx) if (latest_key != keyblock && opt.verbose) { char *tempkeystr= - m_strdup(keystr_from_pk(latest_key->pkt->pkt.public_key)); - log_info(_("using secondary key %s instead of primary key %s\n"), + 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)); - m_free(tempkeystr); + xfree(tempkeystr); } cache_user_id( keyblock ); @@ -2561,7 +2722,7 @@ enum_secret_keys( void **context, PKT_secret_key *sk, if( !c ) { /* make a new context */ - c = m_alloc_clear( sizeof *c ); + c = xmalloc_clear( sizeof *c ); *context = c; c->hd = keydb_new (1); c->first = 1; @@ -2572,7 +2733,7 @@ enum_secret_keys( void **context, PKT_secret_key *sk, if( !sk ) { /* free the context */ keydb_release (c->hd); release_kbnode (c->keyblock); - m_free( c ); + xfree( c ); *context = NULL; return 0; } @@ -2619,7 +2780,7 @@ 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 ) @@ -2637,28 +2798,26 @@ get_user_id_string( u32 *keyid ) { if( a->keyid[0] == keyid[0] && a->keyid[1] == keyid[1] ) { - p = m_alloc( keystrlen() + 1 + r->len + 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 = m_alloc( keystrlen() + 5 ); + 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 ); - m_free(p); - p = make_printable_string (p2, strlen (p2), 0); - m_free (p2); - return p; + char *p = get_user_id_string( keyid ); + char *p2 = utf8_to_native( p, strlen(p), 0 ); + xfree(p); + return p2; } @@ -2674,7 +2833,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 = m_alloc( r->len + 20 ); + p = xmalloc( r->len + 20 ); sprintf(p, "%08lX%08lX %.*s", (ulong)keyid[0], (ulong)keyid[1], r->len, r->name ); @@ -2683,7 +2842,7 @@ get_long_user_id_string( u32 *keyid ) } } } while( ++pass < 2 && !get_pubkey( NULL, keyid ) ); - p = m_alloc( 25 ); + p = xmalloc( 25 ); sprintf(p, "%08lX%08lX [?]", (ulong)keyid[0], (ulong)keyid[1] ); return p; } @@ -2701,7 +2860,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 = m_alloc( r->len ); + p = xmalloc( r->len ); memcpy(p, r->name, r->len ); *rn = r->len; return p; @@ -2709,21 +2868,19 @@ get_user_id( u32 *keyid, size_t *rn ) } } } while( ++pass < 2 && !get_pubkey( NULL, keyid ) ); - p = m_strdup( _("[User id not found]") ); + p = xstrdup( _("[User ID not found]") ); *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 ); - m_free(p); - p = make_printable_string (p2, strlen (p2), 0); - m_free (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 @@ -2731,3 +2888,65 @@ 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); +} + +int +parse_auto_key_locate(char *options) +{ + char *tok; + + while((tok=optsep(&options))) + { + struct akl *akl,*last; + + if(tok[0]=='\0') + continue; + + akl=xmalloc_clear(sizeof(*akl)); + + if(ascii_strcasecmp(tok,"cert")==0) + akl->type=AKL_CERT; + else if(ascii_strcasecmp(tok,"pka")==0) + akl->type=AKL_PKA; + else if(ascii_strcasecmp(tok,"ldap")==0) + akl->type=AKL_LDAP; + else if(ascii_strcasecmp(tok,"keyserver")==0) + akl->type=AKL_KEYSERVER; + 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))) + { + free_akl(akl); + return 0; + } + } + + if(last) + last->next=akl; + else + opt.auto_key_locate=akl; + } + + return 1; +}