* main.h, seskey.c (encode_md_value): Modify to allow a q size greater
[gnupg.git] / g10 / getkey.c
index a3a1be8..1c85fb4 100644 (file)
@@ -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,
+ *               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>
@@ -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 );
@@ -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,140 @@ 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))
+    {
+      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);
+
+             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
@@ -931,7 +1053,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 );
     }
 }
 
@@ -1059,14 +1181,20 @@ get_seckey_byname2( GETKEY_CTX *retctx,
                    KBNODE *retblock )
 {
   STRLIST namelist = NULL;
-  int rc;
+  int rc,include_unusable=1;
+
+  /* If we have no name, try to use the default secret key.  If we
+     have no default, we'll use the first usable one. */
 
   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;
 
-  rc = key_byname( retctx, namelist, NULL, sk, 1, 1, retblock, NULL );
+  rc = key_byname( retctx, namelist, NULL, sk, 1, include_unusable,
+                  retblock, NULL );
 
   free_strlist( namelist );
 
@@ -1139,13 +1267,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;
+}
+
+
 \f
 /************************************************
  ************* Merging stuff ********************
@@ -1242,6 +1398,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:
@@ -1267,26 +1476,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;
@@ -1317,12 +1521,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;
@@ -1341,20 +1545,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;
@@ -1369,7 +1582,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;
@@ -1392,7 +1606,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;
 
@@ -1415,7 +1629,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
@@ -1429,7 +1643,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;i<sig->numrevkeys;i++)
@@ -1480,39 +1694,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
@@ -1533,7 +1739,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;
@@ -1573,7 +1779,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.
@@ -1582,22 +1789,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;
-                }
+                 }
             }
         }
     }
@@ -1634,7 +1832,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.
@@ -1695,7 +1893,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 
@@ -1835,7 +2035,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 ();
@@ -1870,19 +2069,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;
+                     }
+                 }
             }
         }
     }
@@ -1893,25 +2095,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);
@@ -1928,15 +2126,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)))
@@ -1946,7 +2143,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)))
@@ -1955,7 +2153,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)
@@ -1970,7 +2168,6 @@ merge_selfsigs_subkey( KBNODE keyblock, KBNODE subnode )
            free_seckey_enc(backsig);
          }
       }
-#endif
 }
 
 
@@ -1991,7 +2188,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;
@@ -2008,7 +2205,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 ) {
@@ -2031,7 +2228,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;
@@ -2056,7 +2253,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;
         }
     }    
@@ -2065,7 +2262,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;
         }
@@ -2231,7 +2428,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
@@ -2396,10 +2593,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 );
@@ -2542,7 +2739,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;
@@ -2553,7 +2750,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;
     }
@@ -2600,7 +2797,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 )
@@ -2618,14 +2815,14 @@ 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;
 }
@@ -2636,7 +2833,7 @@ 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);
+  xfree(p);
   return p2;
 }
 
@@ -2653,7 +2850,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 );
@@ -2662,7 +2859,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;
 }
@@ -2680,7 +2877,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;
@@ -2688,7 +2885,7 @@ 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;
 }
@@ -2699,7 +2896,7 @@ 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);
+  xfree(p);
   return p2;
 }
 
@@ -2708,3 +2905,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;
+}