* trustdb.c (clean_uids_from_key): Don't keep a valid selfsig around
[gnupg.git] / g10 / getkey.c
index 8676758..5bd9907 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 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>
@@ -183,7 +184,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;
 }
@@ -1059,14 +1060,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 +1146,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 +1277,51 @@ 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 & 3)
+       {
+         key_usage |= PUBKEY_USAGE_SIG;
+         flags&=~3;
+       }
+
+      if(flags & 12)
+       {
+         key_usage |= PUBKEY_USAGE_ENC;
+         flags&=~12;
+       }
+
+      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 +1347,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;
@@ -1354,7 +1429,16 @@ fixup_uidnode ( KBNODE uidnode, KBNODE signode, u32 keycreated )
 }
 
 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 +1453,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;
@@ -1415,7 +1500,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
@@ -1484,35 +1569,27 @@ merge_selfsigs_main( KBNODE keyblock, int *r_revoked, u32 *r_revokedate )
                               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 +1610,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 +1650,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 +1660,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;
-                }
+                 }
             }
         }
     }
@@ -1835,7 +1904,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 +1938,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 +1964,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);
@@ -1936,6 +2003,7 @@ merge_selfsigs_subkey( KBNODE keyblock, KBNODE subnode )
     if(subpk->backsig==0)
       {
        int seq=0;
+       size_t n;
 
        while((p=enum_sig_subpkt(sig->hashed,
                                 SIGSUBPKT_SIGNATURE,&n,&seq,NULL)))
@@ -1991,7 +2059,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 +2076,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 +2099,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;
@@ -2397,7 +2465,7 @@ finish_lookup (GETKEY_CTX ctx)
       {
        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"),
+        log_info(_("using subkey %s instead of primary key %s\n"),
                  tempkeystr, keystr_from_pk(keyblock->pkt->pkt.public_key));
        m_free(tempkeystr);
       }
@@ -2688,7 +2756,7 @@ get_user_id( u32 *keyid, size_t *rn )
             }
         }
     } while( ++pass < 2 && !get_pubkey( NULL, keyid ) );
-    p = m_strdup( _("[User id not found]") );
+    p = m_strdup( _("[User ID not found]") );
     *rn = strlen(p);
     return p;
 }