Various changes to eventually support openpgp keys in pgp-agent.
[gnupg.git] / g10 / getkey.c
index 96537b7..b5db65d 100644 (file)
@@ -46,6 +46,7 @@
 struct getkey_ctx_s
 {
   int exact;
+  int want_secret;       /* The caller requested only secret keys.  */
   KBNODE keyblock;
   KBPOS kbpos;
   KBNODE found_key;     /* Pointer into some keyblock. */
@@ -101,8 +102,8 @@ typedef struct user_id_db
 static user_id_db_t user_id_db;
 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 void merge_selfsigs (kbnode_t keyblock);
+static int lookup (getkey_ctx_t ctx, kbnode_t *ret_keyblock, int want_secret);
 
 #if 0
 static void
@@ -599,7 +600,7 @@ leave:
 
 
 /* Try to get the pubkey by the userid. This function looks for the
- * first pubkey certificate which has the given name in a user_id.  if
+ * first pubkey certificate which has the given name in a user_id.  If
  * pk/sk has the pubkey algo set, the function will only return a
  * pubkey with that algo.  If namelist is NULL, the first key is
  * returned.  The caller should provide storage for either the pk or
@@ -608,7 +609,7 @@ leave:
 static int
 key_byname (GETKEY_CTX * retctx, strlist_t namelist,
            PKT_public_key * pk, PKT_secret_key * sk,
-           int secmode, int include_unusable,
+           int want_secret, int include_unusable,
            KBNODE * ret_kb, KEYDB_HANDLE * ret_kdbhd)
 {
   int rc = 0;
@@ -617,6 +618,8 @@ key_byname (GETKEY_CTX * retctx, strlist_t namelist,
   GETKEY_CTX ctx;
   KBNODE help_kb = NULL;
 
+  /* FIXME: Eventually remove the SK argument.  */
+
   if (retctx)
     {
       /* Reset the returned context in case of error.  */
@@ -667,35 +670,25 @@ key_byname (GETKEY_CTX * retctx, strlist_t namelist,
        }
     }
 
-  ctx->kr_handle = keydb_new (secmode);
+  ctx->want_secret = want_secret;
+  ctx->kr_handle = keydb_new (0);
   if (!ret_kb)
     ret_kb = &help_kb;
 
-  if (secmode)
+  if (pk)
     {
-      if (sk)
-       {
-         ctx->req_algo = sk->req_algo;
-         ctx->req_usage = sk->req_usage;
-       }
-      rc = lookup (ctx, ret_kb, 1);
-      if (!rc && sk)
-       {
-         sk_from_block (ctx, sk, *ret_kb);
-       }
+      ctx->req_algo = pk->req_algo;
+      ctx->req_usage = pk->req_usage;
     }
-  else
+  else if (sk) /* FIXME:  We should remove this.  */
     {
-      if (pk)
-       {
-         ctx->req_algo = pk->req_algo;
-         ctx->req_usage = pk->req_usage;
-       }
-      rc = lookup (ctx, ret_kb, 0);
-      if (!rc && pk)
-       {
-         pk_from_block (ctx, pk, *ret_kb);
-       }
+      ctx->req_algo = sk->req_algo;
+      ctx->req_usage = sk->req_usage;
+    }
+  rc = lookup (ctx, ret_kb, want_secret);
+  if (!rc && pk)
+    {
+      pk_from_block (ctx, pk, *ret_kb);
     }
 
   release_kbnode (help_kb);
@@ -1219,115 +1212,102 @@ get_seckeyblock_byfprint (KBNODE * ret_keyblock, const byte * fprint,
   return rc;
 }
 
+
 \f
-/************************************************
- ************* Merging stuff ********************
- ************************************************/
+/* The new function to return a key.  
+   FIXME: Document it.  */
+gpg_error_t
+getkey_bynames (getkey_ctx_t *retctx, PKT_public_key *pk,
+                strlist_t names, int want_secret, kbnode_t *ret_keyblock)
+{
+  return key_byname (retctx, names, pk, NULL, want_secret, 1,
+                     ret_keyblock, NULL);
+}
 
-/* Merge all self-signatures with the keys.
 
- * FIXME: replace this at least for the public key parts
- *        by merge_selfsigs.
- *        It is still used in keyedit.c and
- *        at 2 or 3 other places - check whether it is really needed.
- *        It might be needed by the key edit and import stuff because
- *        the keylock is changed.  */
-void
-merge_keys_and_selfsig (KBNODE keyblock)
+/* Get a key by name and store it into PK.  If RETCTX is not NULL
+ * return the search context which needs to be released by the caller
+ * using getkey_end.  If NAME is NULL use the default key (see below).
+ * On success and if RET_KEYBLOCK is not NULL the found keyblock is
+ * stored at this address.  WANT_SECRET passed as true requires that a
+ * secret key is available for the selected key.
+ * 
+ * If WANT_SECRET is true and NAME is NULL and a default key has been
+ * defined that defined key is used.  In all other cases the first
+ * available key is used. 
+ * 
+ * FIXME: Explain what is up with unusable keys.
+ *
+ * FIXME: We also have the get_pubkey_byname fucntion which has a
+ * different semantic.  Should be merged with this one.
+ */
+gpg_error_t
+getkey_byname (getkey_ctx_t *retctx, PKT_public_key *pk,
+               const char *name, int want_secret, kbnode_t *ret_keyblock)
 {
-  PKT_public_key *pk = NULL;
-  PKT_secret_key *sk = NULL;
-  PKT_signature *sig;
-  KBNODE k;
-  u32 kid[2] = { 0, 0 };
-  u32 sigdate = 0;
+  gpg_error_t err;
+  strlist_t namelist = NULL;
+  int with_unusable = 1;
 
-  if (keyblock && keyblock->pkt->pkttype == PKT_PUBLIC_KEY)
-    {
-      /* Divert to our new function.  */
-      merge_selfsigs (keyblock);
-      return;
-    }
+  if (want_secret && !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
+    with_unusable = 0;
 
-  /* Still need the old one because the new one can't handle secret keys.  */
+  err = key_byname (retctx, namelist, pk, NULL, want_secret, with_unusable,
+                    ret_keyblock, NULL);
+  
+  /* FIXME: Check that we really return GPG_ERR_NO_SECKEY if
+     WANT_SECRET has been used.  */
 
-  for (k = keyblock; k; k = k->next)
-    {
-      if (k->pkt->pkttype == PKT_PUBLIC_KEY
-         || k->pkt->pkttype == PKT_PUBLIC_SUBKEY)
-       {
-         pk = k->pkt->pkt.public_key;
-         sk = NULL;
-         if (pk->version < 4)
-           pk = NULL; /* Not needed for old keys.  */
-         else if (k->pkt->pkttype == PKT_PUBLIC_KEY)
-           keyid_from_pk (pk, kid);
-         else if (!pk->expiredate)
-           {
-              /* and subkey */
-             /* insert the expiration date here */
-             /*FIXME!!! pk->expiredate = subkeys_expiretime( k, kid ); */
-           }
-         sigdate = 0;
-       }
-      else if (k->pkt->pkttype == PKT_SECRET_KEY
-              || k->pkt->pkttype == PKT_SECRET_SUBKEY)
-       {
-         pk = NULL;
-         sk = k->pkt->pkt.secret_key;
-         if (sk->version < 4)
-           sk = NULL;
-         else if (k->pkt->pkttype == PKT_SECRET_KEY)
-           keyid_from_sk (sk, kid);
-         sigdate = 0;
-       }
-      else if ((pk || sk) && k->pkt->pkttype == PKT_SIGNATURE
-              && (sig = k->pkt->pkt.signature)->sig_class >= 0x10
-              && sig->sig_class <= 0x30 && sig->version > 3
-              && !(sig->sig_class == 0x18 || sig->sig_class == 0x28)
-              && sig->keyid[0] == kid[0] && sig->keyid[1] == kid[1])
-       {
-         /* okay this is a self-signature which can be used.
-          * This is not used for subkey binding signature, becuase this
-          * is done above.
-          * FIXME: We should only use this if the signature is valid
-          *        but this is time consuming - we must provide another
-          *        way to handle this
-          */
-         const byte *p;
-         u32 ed;
-
-         p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_KEY_EXPIRE, NULL);
-         if (pk)
-           {
-             ed = p ? pk->timestamp + buffer_to_u32 (p) : 0;
-             if (sig->timestamp > sigdate)
-               {
-                 pk->expiredate = ed;
-                 sigdate = sig->timestamp;
-               }
-           }
-         else
-           {
-             ed = p ? sk->timestamp + buffer_to_u32 (p) : 0;
-             if (sig->timestamp > sigdate)
-               {
-                 sk->expiredate = ed;
-                 sigdate = sig->timestamp;
-               }
-           }
-       }
+  free_strlist (namelist);
 
-      if (pk && (pk->expiredate == 0 ||
-                (pk->max_expiredate && pk->expiredate > pk->max_expiredate)))
-       pk->expiredate = pk->max_expiredate;
+  return err;
+}
 
-      if (sk && (sk->expiredate == 0 ||
-                (sk->max_expiredate && sk->expiredate > sk->max_expiredate)))
-       sk->expiredate = sk->max_expiredate;
-    }
+
+/* The new function to return the next key.  */
+gpg_error_t
+getkey_next (getkey_ctx_t ctx, PKT_public_key *pk, kbnode_t *ret_keyblock)
+{
+  int rc; /* Fixme:  Make sure this is proper gpg_error */
+
+  rc = lookup (ctx, ret_keyblock, ctx->want_secret);
+  if (!rc && pk && ret_keyblock)
+    pk_from_block (ctx, pk, *ret_keyblock);
+
+  return rc;
 }
 
+
+/* The new function to finish a key listing.  */
+void
+getkey_end (getkey_ctx_t ctx)
+{
+  get_pubkey_end (ctx);
+}
+
+
+\f
+/************************************************
+ ************* Merging stuff ********************
+ ************************************************/
+
+/* Merge all self-signatures with the keys.  */
+void
+merge_keys_and_selfsig (KBNODE keyblock)
+{
+  if (!keyblock)
+    ;
+  else if (keyblock->pkt->pkttype == PKT_PUBLIC_KEY)
+    merge_selfsigs (keyblock);
+  else
+    log_debug ("FIXME: merging secret key blocks is not anymore available\n");
+}
+
+
 static int
 parse_key_usage (PKT_signature * sig)
 {
@@ -2309,146 +2289,10 @@ merge_selfsigs (KBNODE keyblock)
 }
 
 
-/*
- * Merge the secret keys from secblock into the pubblock thereby
- * replacing the public (sub)keys with their secret counterparts Hmmm:
- * It might be better to get away from the concept of entire secret
- * keys at all and have a way to store just the real secret parts
- * from the key.
- */
-static void
-merge_public_with_secret (KBNODE pubblock, KBNODE secblock)
-{
-  KBNODE pub;
-
-  assert (pubblock->pkt->pkttype == PKT_PUBLIC_KEY);
-  assert (secblock->pkt->pkttype == PKT_SECRET_KEY);
-
-  for (pub = pubblock; pub; pub = pub->next)
-    {
-      if (pub->pkt->pkttype == PKT_PUBLIC_KEY)
-       {
-         PKT_public_key *pk = pub->pkt->pkt.public_key;
-         PKT_secret_key *sk = secblock->pkt->pkt.secret_key;
-         assert (pub == pubblock); /* Only in the first node.  */
-         /* There is nothing to compare in this case, so just replace
-          * some information.  */
-         copy_public_parts_to_secret_key (pk, sk);
-         free_public_key (pk);
-         pub->pkt->pkttype = PKT_SECRET_KEY;
-         pub->pkt->pkt.secret_key = copy_secret_key (NULL, sk);
-       }
-      else if (pub->pkt->pkttype == PKT_PUBLIC_SUBKEY)
-       {
-         KBNODE sec;
-         PKT_public_key *pk = pub->pkt->pkt.public_key;
-
-         /* This is more complicated: It may happen that the sequence
-          * of the subkeys dosn't match, so we have to find the
-          * appropriate secret key.  */
-         for (sec = secblock->next; sec; sec = sec->next)
-           {
-             if (sec->pkt->pkttype == PKT_SECRET_SUBKEY)
-               {
-                 PKT_secret_key *sk = sec->pkt->pkt.secret_key;
-                 if (!cmp_public_secret_key (pk, sk))
-                   {
-                     copy_public_parts_to_secret_key (pk, sk);
-                     free_public_key (pk);
-                     pub->pkt->pkttype = PKT_SECRET_SUBKEY;
-                     pub->pkt->pkt.secret_key = copy_secret_key (NULL, sk);
-                     break;
-                   }
-               }
-           }
-         if (!sec)
-           BUG (); /* Already checked in premerge.  */
-       }
-    }
-}
-
-
-/* This function checks that for every public subkey a corresponding
- * secret subkey is available and deletes the public subkey otherwise.
- * We need this function because we can't delete it later when we
- * actually merge the secret parts into the pubring.
- * The function also plays some games with the node flags.  */
-static void
-premerge_public_with_secret (KBNODE pubblock, KBNODE secblock)
-{
-  KBNODE last, pub;
-
-  assert (pubblock->pkt->pkttype == PKT_PUBLIC_KEY);
-  assert (secblock->pkt->pkttype == PKT_SECRET_KEY);
-
-  for (pub = pubblock, last = NULL; pub; last = pub, pub = pub->next)
-    {
-      pub->flag &= ~3; /* Reset bits 0 and 1.  */
-      if (pub->pkt->pkttype == PKT_PUBLIC_SUBKEY)
-       {
-         KBNODE sec;
-         PKT_public_key *pk = pub->pkt->pkt.public_key;
-
-         for (sec = secblock->next; sec; sec = sec->next)
-           {
-             if (sec->pkt->pkttype == PKT_SECRET_SUBKEY)
-               {
-                 PKT_secret_key *sk = sec->pkt->pkt.secret_key;
-                 if (!cmp_public_secret_key (pk, sk))
-                   {
-                     if (sk->protect.s2k.mode == 1001)
-                       {
-                         /* The secret parts are not available so
-                            we can't use that key for signing etc.
-                            Fix the pubkey usage */
-                         pk->pubkey_usage &= ~(PUBKEY_USAGE_SIG
-                                               | PUBKEY_USAGE_AUTH);
-                       }
-                     /* Transfer flag bits 0 and 1 to the pubblock.  */
-                     pub->flag |= (sec->flag & 3);
-                     break;
-                   }
-               }
-           }
-         if (!sec)
-           {
-             KBNODE next, ll;
-
-             if (opt.verbose)
-               log_info (_("no secret subkey"
-                           " for public subkey %s - ignoring\n"),
-                         keystr_from_pk (pk));
-             /* We have to remove the subkey in this case.  */
-             assert (last);
-             /* Find the next subkey.  */
-             for (next = pub->next, ll = pub;
-                  next && next->pkt->pkttype != PKT_PUBLIC_SUBKEY;
-                  ll = next, next = next->next)
-               ;
-             /* Make new link.  */
-             last->next = next;
-             /* Release this public subkey with all sigs.  */
-             ll->next = NULL;
-             release_kbnode (pub);
-             /* Let the loop continue.  */
-             pub = last;
-           }
-       }
-    }
-  /* We need to copy the found bits (0 and 1) from the secret key to
-     the public key.  This has already been done for the subkeys but
-     got lost on the primary key - fix it here.  */
-  pubblock->flag |= (secblock->flag & 3);
-}
-
-
 \f
-/* See see whether the key fits our requirements and in case we do not
- * request the primary key, we should select a suitable subkey.
+/* See whether the key fits our requirements and in case we do not
+ * request the primary key, select a suitable subkey.
  *
- * FIXME: Check against PGP 7 whether we still need a kludge
- *        to favor type 16 keys over type 20 keys when type 20
- *        has not been explitely requested.
  * Returns: True when a suitable key has been found.
  *
  * We have to distinguish four cases:  FIXME!
@@ -2533,7 +2377,7 @@ finish_lookup (GETKEY_CTX ctx)
   if ((!foundk || foundk->pkt->pkttype == PKT_PUBLIC_SUBKEY) && !req_prim)
     {
       KBNODE nextk;
-      /* ceither start a loop or check just this one subkey.  */
+      /* Either start a loop or check just this one subkey.  */
       for (k = foundk ? foundk : keyblock; k; k = nextk)
        {
          PKT_public_key *pk;
@@ -2635,7 +2479,7 @@ finish_lookup (GETKEY_CTX ctx)
     {
       if (DBG_CACHE)
        log_debug ("\tno suitable key found -  giving up\n");
-      return 0;
+      return 0; /* Not found.  */
     }
 
 found:
@@ -2668,11 +2512,13 @@ found:
 }
 
 
+/* The main function to lookup a key.  On success the found keyblock
+   is stored at RET_KEYBLOCK and also in CTX.  If WANT_SECRET is true
+   a corresponding secret key is required.  */
 static int
-lookup (GETKEY_CTX ctx, KBNODE * ret_keyblock, int secmode)
+lookup (getkey_ctx_t ctx, kbnode_t *ret_keyblock, int want_secret)
 {
   int rc;
-  KBNODE secblock = NULL; /* Helper.  */
   int no_suitable_key = 0;
 
   rc = 0;
@@ -2692,30 +2538,8 @@ lookup (GETKEY_CTX ctx, KBNODE * ret_keyblock, int secmode)
          goto skip;
        }
 
-      if (secmode)
-       {
-         /* Find the correspondig public key and use this
-          * this one for the selection process.  */
-         u32 aki[2];
-         KBNODE k = ctx->keyblock;
-
-         if (k->pkt->pkttype != PKT_SECRET_KEY)
-           BUG ();
-
-         keyid_from_sk (k->pkt->pkt.secret_key, aki);
-         k = get_pubkeyblock (aki);
-         if (!k)
-           {
-             if (!opt.quiet)
-               log_info (_("key %s: secret key without public key"
-                           " - skipped\n"), keystr (aki));
-             goto skip;
-           }
-         secblock = ctx->keyblock;
-         ctx->keyblock = k;
-
-         premerge_public_with_secret (ctx->keyblock, secblock);
-       }
+      if (want_secret && have_secret_key (ctx->keyblock))
+        goto skip; /* No secret key available.  */
 
       /* Warning: node flag bits 0 and 1 should be preserved by
        * merge_selfsigs.  For secret keys, premerge did tranfer the
@@ -2724,12 +2548,6 @@ lookup (GETKEY_CTX ctx, KBNODE * ret_keyblock, int secmode)
       if (finish_lookup (ctx))
        {
          no_suitable_key = 0;
-         if (secmode)
-           {
-             merge_public_with_secret (ctx->keyblock, secblock);
-             release_kbnode (secblock);
-             secblock = NULL;
-           }
          goto found;
        }
       else
@@ -2737,15 +2555,10 @@ lookup (GETKEY_CTX ctx, KBNODE * ret_keyblock, int secmode)
 
     skip:
       /* Release resources and continue search. */
-      if (secmode)
-       {
-         release_kbnode (secblock);
-         secblock = NULL;
-       }
       release_kbnode (ctx->keyblock);
       ctx->keyblock = NULL;
     }
-
+  
 found:
   if (rc && rc != -1)
     log_error ("keydb_search failed: %s\n", g10_errstr (rc));
@@ -2756,15 +2569,10 @@ found:
       ctx->keyblock = NULL;
     }
   else if (rc == -1 && no_suitable_key)
-    rc = secmode ? G10ERR_UNU_SECKEY : G10ERR_UNU_PUBKEY;
+    rc = want_secret? G10ERR_UNU_SECKEY : G10ERR_UNU_PUBKEY;
   else if (rc == -1)
-    rc = secmode ? G10ERR_NO_SECKEY : G10ERR_NO_PUBKEY;
+    rc = want_secret? G10ERR_NO_SECKEY : G10ERR_NO_PUBKEY;
 
-  if (secmode)
-    {
-      release_kbnode (secblock);
-      secblock = NULL;
-    }
   release_kbnode (ctx->keyblock);
   ctx->keyblock = NULL;
 
@@ -3083,3 +2891,180 @@ parse_auto_key_locate (char *options)
 
   return 1;
 }
+
+
+/* Return 0 if a secret key is available for the key described by
+   KEYBLOCK.  FIXME: How do we handel subkeys?  */
+gpg_error_t
+have_secret_key (kbnode_t keyblock)
+{
+  gpg_error_t err;
+  unsigned char fpr[MAX_FINGERPRINT_LEN];
+  size_t fprlen;
+  KEYDB_HANDLE kdh;
+
+  if (!keyblock || keyblock->pkt->pkttype != PKT_PUBLIC_KEY)
+    return gpg_error (GPG_ERR_NO_PUBKEY);  /* Should not happen.  */
+
+  fingerprint_from_pk (keyblock->pkt->pkt.public_key, fpr, &fprlen);
+  while (fprlen < MAX_FINGERPRINT_LEN) 
+    fpr[fprlen++] = 0;
+
+  /* FIXME: Always allocating a new handle is too slow.  However this
+     entire implementation is anyway a temporary solution until we can
+     ask gpg-agent for the secret key.  */
+  kdh = keydb_new (1);
+  if (!kdh)
+    return gpg_error (GPG_ERR_GENERAL);
+
+  err = keydb_search_fpr (kdh, fpr);
+  if (err == -1 || gpg_err_code (err) == GPG_ERR_EOF)
+    err = gpg_error (GPG_ERR_NO_SECKEY);
+
+  keydb_release (kdh);
+
+  return err;
+}
+
+
+
+#if 0
+/*
+ * Merge the secret keys from secblock into the pubblock thereby
+ * replacing the public (sub)keys with their secret counterparts Hmmm:
+ * It might be better to get away from the concept of entire secret
+ * keys at all and have a way to store just the real secret parts
+ * from the key.
+ *
+ * FIXME: this is not anymore needed but we keep it as example code for the
+ * new code we need to write for the import/export feature.
+ */
+static void
+merge_public_with_secret (KBNODE pubblock, KBNODE secblock)
+{
+  KBNODE pub;
+
+  assert (pubblock->pkt->pkttype == PKT_PUBLIC_KEY);
+  assert (secblock->pkt->pkttype == PKT_SECRET_KEY);
+
+  for (pub = pubblock; pub; pub = pub->next)
+    {
+      if (pub->pkt->pkttype == PKT_PUBLIC_KEY)
+       {
+         PKT_public_key *pk = pub->pkt->pkt.public_key;
+         PKT_secret_key *sk = secblock->pkt->pkt.secret_key;
+         assert (pub == pubblock); /* Only in the first node.  */
+         /* There is nothing to compare in this case, so just replace
+          * some information.  */
+         copy_public_parts_to_secret_key (pk, sk);
+         free_public_key (pk);
+         pub->pkt->pkttype = PKT_SECRET_KEY;
+         pub->pkt->pkt.secret_key = copy_secret_key (NULL, sk);
+       }
+      else if (pub->pkt->pkttype == PKT_PUBLIC_SUBKEY)
+       {
+         KBNODE sec;
+         PKT_public_key *pk = pub->pkt->pkt.public_key;
+
+         /* This is more complicated: It may happen that the sequence
+          * of the subkeys dosn't match, so we have to find the
+          * appropriate secret key.  */
+         for (sec = secblock->next; sec; sec = sec->next)
+           {
+             if (sec->pkt->pkttype == PKT_SECRET_SUBKEY)
+               {
+                 PKT_secret_key *sk = sec->pkt->pkt.secret_key;
+                 if (!cmp_public_secret_key (pk, sk))
+                   {
+                     copy_public_parts_to_secret_key (pk, sk);
+                     free_public_key (pk);
+                     pub->pkt->pkttype = PKT_SECRET_SUBKEY;
+                     pub->pkt->pkt.secret_key = copy_secret_key (NULL, sk);
+                     break;
+                   }
+               }
+           }
+         if (!sec)
+           BUG (); /* Already checked in premerge.  */
+       }
+    }
+}
+
+
+/* This function checks that for every public subkey a corresponding
+ * secret subkey is available and deletes the public subkey otherwise.
+ * We need this function because we can't delete it later when we
+ * actually merge the secret parts into the pubring.
+ * The function also plays some games with the node flags.
+ *
+ * FIXME: this is not anymore needed but we keep it as example code for the
+ * new code we need to write for the import/export feature.
+ */
+static void
+premerge_public_with_secret (KBNODE pubblock, KBNODE secblock)
+{
+  KBNODE last, pub;
+
+  assert (pubblock->pkt->pkttype == PKT_PUBLIC_KEY);
+  assert (secblock->pkt->pkttype == PKT_SECRET_KEY);
+
+  for (pub = pubblock, last = NULL; pub; last = pub, pub = pub->next)
+    {
+      pub->flag &= ~3; /* Reset bits 0 and 1.  */
+      if (pub->pkt->pkttype == PKT_PUBLIC_SUBKEY)
+       {
+         KBNODE sec;
+         PKT_public_key *pk = pub->pkt->pkt.public_key;
+
+         for (sec = secblock->next; sec; sec = sec->next)
+           {
+             if (sec->pkt->pkttype == PKT_SECRET_SUBKEY)
+               {
+                 PKT_secret_key *sk = sec->pkt->pkt.secret_key;
+                 if (!cmp_public_secret_key (pk, sk))
+                   {
+                     if (sk->protect.s2k.mode == 1001)
+                       {
+                         /* The secret parts are not available so
+                            we can't use that key for signing etc.
+                            Fix the pubkey usage */
+                         pk->pubkey_usage &= ~(PUBKEY_USAGE_SIG
+                                               | PUBKEY_USAGE_AUTH);
+                       }
+                     /* Transfer flag bits 0 and 1 to the pubblock.  */
+                     pub->flag |= (sec->flag & 3);
+                     break;
+                   }
+               }
+           }
+         if (!sec)
+           {
+             KBNODE next, ll;
+
+             if (opt.verbose)
+               log_info (_("no secret subkey"
+                           " for public subkey %s - ignoring\n"),
+                         keystr_from_pk (pk));
+             /* We have to remove the subkey in this case.  */
+             assert (last);
+             /* Find the next subkey.  */
+             for (next = pub->next, ll = pub;
+                  next && next->pkt->pkttype != PKT_PUBLIC_SUBKEY;
+                  ll = next, next = next->next)
+               ;
+             /* Make new link.  */
+             last->next = next;
+             /* Release this public subkey with all sigs.  */
+             ll->next = NULL;
+             release_kbnode (pub);
+             /* Let the loop continue.  */
+             pub = last;
+           }
+       }
+    }
+  /* We need to copy the found bits (0 and 1) from the secret key to
+     the public key.  This has already been done for the subkeys but
+     got lost on the primary key - fix it here.  */
+  pubblock->flag |= (secblock->flag & 3);
+}
+#endif /*0*/