* main.h, seskey.c (encode_md_value): Modify to allow a q size greater
[gnupg.git] / g10 / getkey.c
index 59f18f6..1c85fb4 100644 (file)
@@ -1,6 +1,6 @@
 /* getkey.c -  Get a key from the database
- * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004,
- *               2005 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.
  *
@@ -590,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;
@@ -619,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*/
@@ -901,41 +905,122 @@ get_pubkey_byname (PKT_public_key *pk,
                    KEYDB_HANDLE *ret_kdbhd, int include_unusable )
 {
   int rc;
-  int again = 0;
   STRLIST namelist = NULL;
 
   add_to_strlist( &namelist, name );
- retry:
+
   rc = key_byname( NULL, namelist, pk, NULL, 0,
                    include_unusable, ret_keyblock, ret_kdbhd);
-  if (rc == G10ERR_NO_PUBKEY
-      && !again
-      && (opt.keyserver_options.options&KEYSERVER_AUTO_PKA_RETRIEVE)
-      && is_valid_mailbox (name))
+
+  /* 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))
     {
-      /* If the requested name resembles a valid mailbox and
-         automatic retrieval via PKA records has been enabled, we
-         try to import the key via the URI and try again. */
-      unsigned char fpr[MAX_FINGERPRINT_LEN];
-      char *uri;
-      struct keyserver_spec *spec;
-      
-      uri = get_pka_info (name, fpr);
-      if (uri)
-        {
-          spec = parse_keyserver_uri (uri, 0, NULL, 0);
-          if (spec)
-            {
-              glo_ctrl.in_auto_key_retrieve++;
-              if (!keyserver_import_fprint (fpr, 20, spec))
-                again = 1;
-              glo_ctrl.in_auto_key_retrieve--;
-              free_keyserver_spec (spec);
-            }
-          xfree (uri);
-        }
-      if (again)
-        goto retry;
+      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 );
@@ -1327,16 +1412,24 @@ parse_key_usage(PKT_signature *sig)
       /* first octet of the keyflags */
       flags=*p;
 
-      if(flags & 3)
+      if(flags & 1)
+       {
+         key_usage |= PUBKEY_USAGE_CERT;
+         flags&=~1;
+       }
+
+      if(flags & 2)
        {
          key_usage |= PUBKEY_USAGE_SIG;
-         flags&=~3;
+         flags&=~2;
        }
 
-      if(flags & 12)
+      /* We do not distinguish between encrypting communications and
+        encrypting storage. */
+      if(flags & (0x04|0x08))
        {
          key_usage |= PUBKEY_USAGE_ENC;
-         flags&=~12;
+         flags&=~(0x04|0x08);
        }
 
       if(flags & 0x20)
@@ -1452,16 +1545,16 @@ 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
@@ -1800,7 +1893,9 @@ merge_selfsigs_main(KBNODE keyblock, int *r_revoked, struct revoke_info *rinfo)
         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 
@@ -2031,16 +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)))
@@ -2050,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)))
@@ -2074,7 +2168,6 @@ merge_selfsigs_subkey( KBNODE keyblock, KBNODE subnode )
            free_seckey_enc(backsig);
          }
       }
-#endif
 }
 
 
@@ -2160,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;
         }
     }    
@@ -2335,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
@@ -2812,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;
+}