* tdbio.h, tdbio.c (tdbio_read_record, tdbio_write_record): Store trust
[gnupg.git] / g10 / getkey.c
index 43db3ab..ffd5042 100644 (file)
@@ -96,7 +96,6 @@ static int uid_cache_entries; /* number of entries in uid cache */
 
 static void merge_selfsigs( KBNODE keyblock );
 static int lookup( GETKEY_CTX ctx, KBNODE *ret_keyblock, int secmode );
-static int check_revocation_keys(PKT_public_key *pk,PKT_signature *sig);
 
 #if 0
 static void
@@ -372,6 +371,61 @@ 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.  */
+int
+get_pubkey_fast (PKT_public_key *pk, u32 *keyid)
+{
+  int rc = 0;
+  KEYDB_HANDLE hd;
+  KBNODE keyblock;
+  
+  assert (pk);
+#if MAX_PK_CACHE_ENTRIES
+  { /* Try to get it from the cache */
+    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);
+            return 0;
+          }
+      }
+  }
+#endif
+
+  hd = keydb_new (0);
+  rc = keydb_search_kid (hd, keyid);
+  if (rc == -1)
+    {
+      keydb_release (hd);
+      return G10ERR_NO_PUBKEY;
+    }
+  rc = keydb_get_keyblock (hd, &keyblock);
+  keydb_release (hd);
+  if (rc) 
+    {
+      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 );
+  release_kbnode (keyblock);
+
+  /* Not caching key here since it won't have all of the fields
+     properly set. */
+
+  return 0;
+}
+
+
+
 KBNODE
 get_pubkeyblock( u32 *keyid )
 {
@@ -852,6 +906,54 @@ get_pubkey_byfprint( PKT_public_key *pk,
     return rc;
 }
 
+
+/* Get a public key and store it into the allocated pk.  This function
+   differs from get_pubkey_byfprint() in that it does not do a check
+   of the key to avoid recursion.  It should be used only in very
+   certain cases.  PK may be NULL to check just for the existance of
+   the key. */
+int
+get_pubkey_byfprint_fast (PKT_public_key *pk,
+                          const byte *fprint, size_t fprint_len)
+{
+  int rc = 0;
+  KEYDB_HANDLE hd;
+  KBNODE keyblock;
+  byte fprbuf[MAX_FINGERPRINT_LEN];
+  int i;
+  
+  for (i=0; i < MAX_FINGERPRINT_LEN && i < fprint_len; i++)
+    fprbuf[i] = fprint[i];
+  while (i < MAX_FINGERPRINT_LEN) 
+    fprbuf[i++] = 0;
+
+  hd = keydb_new (0);
+  rc = keydb_search_fpr (hd, fprbuf);
+  if (rc == -1)
+    {
+      keydb_release (hd);
+      return G10ERR_NO_PUBKEY;
+    }
+  rc = keydb_get_keyblock (hd, &keyblock);
+  keydb_release (hd);
+  if (rc) 
+    {
+      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 );
+  if (pk)
+    copy_public_key (pk, keyblock->pkt->pkt.public_key );
+  release_kbnode (keyblock);
+
+  /* Not caching key here since it won't have all of the fields
+     properly set. */
+
+  return 0;
+}
+
 /****************
  * Search for a key with the given fingerprint and return the
  * complete keyblock which may have more than only this key.
@@ -1241,7 +1343,7 @@ merge_selfsigs_main( KBNODE keyblock, int *r_revoked )
 
     signode = NULL;
     sigdate = 0; /* helper to find the latest signature */
-    for(k=keyblock; k && k->pkt->pkttype != PKT_PUBLIC_SUBKEY; k = k->next ) {
+    for(k=keyblock; k && k->pkt->pkttype != PKT_USER_ID; k = k->next ) {
         if ( k->pkt->pkttype == PKT_SIGNATURE ) {
             PKT_signature *sig = k->pkt->pkt.signature;
             if ( sig->keyid[0] == kid[0] && sig->keyid[1]==kid[1] ) { 
@@ -1368,9 +1470,11 @@ merge_selfsigs_main( KBNODE keyblock, int *r_revoked )
              if(IS_KEY_REV(sig) &&
                 (sig->keyid[0]!=kid[0] || sig->keyid[1]!=kid[1]))
                { 
-                 if(check_revocation_keys(pk,sig))
-                   ; /* did not verify, or loop broken */
-                 else
+                 /* Failure here means the sig did not verify, is was
+                    not issued by a revocation key, or a revocation
+                    key loop was broken. */
+
+                 if(check_revocation_keys(pk,sig)==0)
                    *r_revoked=1;
 
                  /* In the future handle subkey and cert revocations?
@@ -1462,7 +1566,13 @@ merge_selfsigs_main( KBNODE keyblock, int *r_revoked )
 
                    ultimate_pk=m_alloc_clear(sizeof(*ultimate_pk));
 
-                   if(get_pubkey(ultimate_pk,sig->keyid)==0 &&
+                    /* We don't want to use the full get_pubkey to
+                       avoid infinite recursion in certain cases.
+                       There is no reason to check that an ultimately
+                       trusted key is still valid - if it has been
+                       revoked or the user should also renmove the
+                       ultimate trust flag.  */
+                   if(get_pubkey_fast(ultimate_pk,sig->keyid)==0 &&
                       check_key_signature(keyblock,k,NULL)==0 &&
                       get_ownertrust(ultimate_pk)==TRUST_ULTIMATE)
                      {
@@ -1534,6 +1644,7 @@ merge_selfsigs_main( KBNODE keyblock, int *r_revoked )
 
     pk->has_expired = key_expire >= curtime? 0 : key_expire;
     pk->expiredate = key_expire;
+
     /* Fixme: we should see how to get rid of the expiretime fields  but
      * this needs changes at other places too. */
 
@@ -1724,21 +1835,6 @@ merge_selfsigs( KBNODE keyblock )
     }
 
     merge_selfsigs_main ( keyblock, &revoked );
-    main_pk = keyblock->pkt->pkt.public_key;
-    if ( revoked ) {
-        /* if the primary key has been revoked we better set the revoke
-         * flag on that key and all subkeys */
-        for(k=keyblock; k; k = k->next ) {
-            if ( k->pkt->pkttype == PKT_PUBLIC_KEY
-                || k->pkt->pkttype == PKT_PUBLIC_SUBKEY ) {
-                PKT_public_key *pk = k->pkt->pkt.public_key;
-                pk->is_revoked = 1;
-                pk->main_keyid[0] = main_pk->main_keyid[0];
-                pk->main_keyid[1] = main_pk->main_keyid[1];
-            }
-       }
-        return;
-    }
 
     /* now merge in the data from each of the subkeys */
     for(k=keyblock; k; k = k->next ) {
@@ -1747,12 +1843,25 @@ merge_selfsigs( KBNODE keyblock )
         }
     }
 
-    /* If the main key is not valid, then the subkeys aren't either,
-       even if they have binding sigs. */
-    if(!main_pk->is_valid)
-      for(k=keyblock; k; k=k->next)
-       if(k->pkt->pkttype==PKT_PUBLIC_SUBKEY)
-         k->pkt->pkt.public_key->is_valid=0;
+    main_pk = keyblock->pkt->pkt.public_key;
+    if ( revoked || main_pk->has_expired || !main_pk->is_valid ) {
+        /* if the primary key is revoked, expired, or invalid we
+         * better set the appropriate flags on that key and all
+         * subkeys */
+        for(k=keyblock; k; k = k->next ) {
+            if ( k->pkt->pkttype == PKT_PUBLIC_KEY
+                || k->pkt->pkttype == PKT_PUBLIC_SUBKEY ) {
+                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(main_pk->has_expired)
+                 pk->has_expired = main_pk->has_expired;
+            }
+       }
+       return;
+    }
 
     /* set the preference list of all keys to those of the primary real
      * user ID.  Note: we use these preferences when we don't know by
@@ -1947,7 +2056,8 @@ finish_lookup (GETKEY_CTX ctx)
     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
-       do not understand signatures made by a signing subkey. */
+       do not understand signatures made by a signing subkey.  PGP 8
+       does. */
     int req_prim = (ctx->req_usage & PUBKEY_USAGE_CERT) ||
       ((opt.pgp6 || opt.pgp7) && (ctx->req_usage & PUBKEY_USAGE_SIG));
     u32 latest_date;
@@ -2223,6 +2333,9 @@ lookup( GETKEY_CTX ctx, KBNODE *ret_keyblock, int secmode )
  *                   b) to get the ultimately trusted keys.
  *        The a) usage might have some problems.
  *
+ * set with_subkeys true to include subkeys
+ * set with_spm true to include secret-parts-missing keys
+ *
  * Enumerate all primary secret keys.  Caller must use these procedure:
  *  1) create a void pointer and initialize it to NULL
  *  2) pass this void pointer by reference to this function
@@ -2233,7 +2346,8 @@ lookup( GETKEY_CTX ctx, KBNODE *ret_keyblock, int secmode )
  *     so that can free it's context.
  */
 int
-enum_secret_keys( void **context, PKT_secret_key *sk, int with_subkeys )
+enum_secret_keys( void **context, PKT_secret_key *sk,
+                 int with_subkeys, int with_spm )
 {
     int rc=0;
     struct {
@@ -2268,9 +2382,11 @@ enum_secret_keys( void **context, PKT_secret_key *sk, int with_subkeys )
     do {
         /* get the next secret key from the current keyblock */
         for (; c->node; c->node = c->node->next) {
-            if (c->node->pkt->pkttype == PKT_SECRET_KEY
+            if ((c->node->pkt->pkttype == PKT_SECRET_KEY
                 || (with_subkeys
-                    && c->node->pkt->pkttype == PKT_SECRET_SUBKEY) ) {
+                    && c->node->pkt->pkttype == PKT_SECRET_SUBKEY) )
+               && !(c->node->pkt->pkt.secret_key->protect.s2k.mode==1001
+                    && !with_spm)) {
                 copy_secret_key (sk, c->node->pkt->pkt.secret_key );
                 c->node = c->node->next;
                 return 0; /* found */
@@ -2406,69 +2522,8 @@ get_user_id_printable( u32 *keyid )
     return p;
 }
 
-
-
 KEYDB_HANDLE
 get_ctx_handle(GETKEY_CTX ctx)
 {
   return ctx->kr_handle;
 }
-
-/* Check the revocation keys to see if any of them have revoked our
-   pk.  sig is the revocation sig.  pk is the key it is on.  This code
-   will need to be modified if gpg ever becomes multi-threaded.  Note
-   that this is written so that a revoked revoker can still issue
-   revocations: i.e. If A revokes B, but A is revoked, B is still
-   revoked.  I'm not completely convinced this is the proper behavior,
-   but it matches how PGP does it. -dms */
-
-/* Return 0 if pk is revoked, non-0 if not revoked */
-static int
-check_revocation_keys(PKT_public_key *pk,PKT_signature *sig)
-{
-  static int busy=0;
-  int i,rc=-1;
-
-  assert(IS_KEY_REV(sig));
-  assert((sig->keyid[0]!=pk->keyid[0]) || (sig->keyid[0]!=pk->keyid[1]));
-
-  if(busy)
-    {
-      /* return -1 (i.e. not revoked), but mark the pk as uncacheable
-         as we don't really know its revocation status until it is
-         checked directly. */
-
-      pk->dont_cache=1;
-      return -1;
-    }
-
-  busy=1;
-
-  /*  printf("looking at %08lX with a sig from %08lX\n",(ulong)pk->keyid[1],
-      (ulong)sig->keyid[1]); */
-
-  /* is the issuer of the sig one of our revokers? */
-  if( !pk->revkey && pk->numrevkeys )
-     BUG();
-  else
-      for(i=0;i<pk->numrevkeys;i++) {
-          u32 keyid[2];
-    
-          keyid_from_fingerprint(pk->revkey[i].fpr,MAX_FINGERPRINT_LEN,keyid);
-    
-          if(keyid[0]==sig->keyid[0] && keyid[1]==sig->keyid[1]) {
-              MD_HANDLE md;
-    
-              md=md_open(sig->digest_algo,0);
-              hash_public_key(md,pk);
-              if(signature_check(sig,md)==0) {
-                  rc=0;
-                  break;
-              }
-          }
-      }
-
-  busy=0;
-
-  return rc;
-}