Merge branch 'STABLE-BRANCH-2-2' into master
[gnupg.git] / g10 / keyedit.c
index a7a5f72..2cb9bb2 100644 (file)
@@ -48,6 +48,8 @@
 #include "call-agent.h"
 #include "../common/host2net.h"
 #include "tofu.h"
+#include "key-check.h"
+#include "keyedit.h"
 
 static void show_prefs (PKT_user_id * uid, PKT_signature * selfsig,
                        int verbose);
@@ -71,7 +73,7 @@ static int menu_clean (ctrl_t ctrl, kbnode_t keyblock, int self_only);
 static void menu_delkey (KBNODE pub_keyblock);
 static int menu_addrevoker (ctrl_t ctrl, kbnode_t pub_keyblock, int sensitive);
 static gpg_error_t menu_expire (ctrl_t ctrl, kbnode_t pub_keyblock,
-                                int force_mainkey, u32 newexpiration);
+                                int unattended, u32 newexpiration);
 static int menu_changeusage (ctrl_t ctrl, kbnode_t keyblock);
 static int menu_backsign (ctrl_t ctrl, kbnode_t pub_keyblock);
 static int menu_set_primary_uid (ctrl_t ctrl, kbnode_t pub_keyblock);
@@ -105,17 +107,6 @@ static int update_trust = 0;
 
 #define CONTROL_D ('D' - 'A' + 1)
 
-#define NODFLG_BADSIG (1<<0)   /* Bad signature.  */
-#define NODFLG_NOKEY  (1<<1)   /* No public key.  */
-#define NODFLG_SIGERR (1<<2)   /* Other sig error.  */
-
-#define NODFLG_MARK_A (1<<4)   /* Temporary mark.  */
-#define NODFLG_DELSIG (1<<5)   /* To be deleted.  */
-
-#define NODFLG_SELUID (1<<8)   /* Indicate the selected userid. */
-#define NODFLG_SELKEY (1<<9)   /* Indicate the selected key.  */
-#define NODFLG_SELSIG (1<<10)  /* Indicate a selected signature.  */
-
 struct sign_attrib
 {
   int non_exportable, non_revocable;
@@ -201,10 +192,11 @@ print_and_check_one_sig_colon (ctrl_t ctrl, kbnode_t keyblock, kbnode_t node,
  * packet.  With EXTENDED set all possible signature list options will
  * always be printed.
  */
-static int
-print_one_sig (ctrl_t ctrl, int rc, kbnode_t keyblock, kbnode_t node,
-               int *inv_sigs, int *no_key, int *oth_err,
-               int is_selfsig, int print_without_key, int extended)
+int
+keyedit_print_one_sig (ctrl_t ctrl, estream_t fp,
+                       int rc, kbnode_t keyblock, kbnode_t node,
+                      int *inv_sigs, int *no_key, int *oth_err,
+                      int is_selfsig, int print_without_key, int extended)
 {
   PKT_signature *sig = node->pkt->pkt.signature;
   int sigrc;
@@ -241,7 +233,7 @@ print_one_sig (ctrl_t ctrl, int rc, kbnode_t keyblock, kbnode_t node,
     }
   if (sigrc != '?' || print_without_key)
     {
-      tty_printf ("%s%c%c %c%c%c%c%c%c %s %s",
+      tty_fprintf (fp, "%s%c%c %c%c%c%c%c%c %s %s",
                  is_rev ? "rev" : "sig", sigrc,
                  (sig->sig_class - 0x10 > 0 &&
                   sig->sig_class - 0x10 <
@@ -257,38 +249,41 @@ print_one_sig (ctrl_t ctrl, int rc, kbnode_t keyblock, kbnode_t node,
                   keystr (sig->keyid),
                  datestr_from_sig (sig));
       if ((opt.list_options & LIST_SHOW_SIG_EXPIRE) || extended )
-       tty_printf (" %s", expirestr_from_sig (sig));
-      tty_printf ("  ");
+       tty_fprintf (fp, " %s", expirestr_from_sig (sig));
+      tty_fprintf (fp, "  ");
       if (sigrc == '%')
-       tty_printf ("[%s] ", gpg_strerror (rc));
+       tty_fprintf (fp, "[%s] ", gpg_strerror (rc));
       else if (sigrc == '?')
        ;
       else if (is_selfsig)
        {
-         tty_printf (is_rev ? _("[revocation]") : _("[self-signature]"));
+         tty_fprintf (fp, is_rev ? _("[revocation]") : _("[self-signature]"));
           if (extended && sig->flags.chosen_selfsig)
-            tty_printf ("*");
+            tty_fprintf (fp, "*");
        }
       else
        {
          size_t n;
          char *p = get_user_id (ctrl, sig->keyid, &n);
-         tty_print_utf8_string2 (NULL, p, n,
+         tty_print_utf8_string2 (fp, p, n,
                                  opt.screen_columns - keystrlen () - 26 -
                                  ((opt.
                                    list_options & LIST_SHOW_SIG_EXPIRE) ? 11
                                   : 0));
          xfree (p);
        }
-      tty_printf ("\n");
+      if (fp == log_get_stream ())
+        log_printf ("\n");
+      else
+        tty_fprintf (fp, "\n");
 
       if (sig->flags.policy_url
           && ((opt.list_options & LIST_SHOW_POLICY_URLS) || extended))
-       show_policy_url (sig, 3, -1);
+       show_policy_url (sig, 3, (!fp? -1 : fp == log_get_stream ()? 1 : 0));
 
       if (sig->flags.notation
           && ((opt.list_options & LIST_SHOW_NOTATIONS) || extended))
-       show_notation (sig, 3, -1,
+       show_notation (sig, 3, (!fp? -1 : fp == log_get_stream ()? 1 : 0),
                       ((opt.
                         list_options & LIST_SHOW_STD_NOTATIONS) ? 1 : 0) +
                       ((opt.
@@ -296,7 +291,7 @@ print_one_sig (ctrl_t ctrl, int rc, kbnode_t keyblock, kbnode_t node,
 
       if (sig->flags.pref_ks
           && ((opt.list_options & LIST_SHOW_KEYSERVER_URLS) || extended))
-       show_keyserver_url (sig, 3, -1);
+       show_keyserver_url (sig, 3, (!fp? -1 : fp == log_get_stream ()? 1 : 0));
 
       if (extended)
         {
@@ -305,12 +300,12 @@ print_one_sig (ctrl_t ctrl, int rc, kbnode_t keyblock, kbnode_t node,
 
           s = parse_sig_subpkt (sig->hashed, SIGSUBPKT_PRIMARY_UID, NULL);
           if (s && *s)
-            tty_printf ("             [primary]\n");
+            tty_fprintf (fp, "             [primary]\n");
 
           s = parse_sig_subpkt (sig->hashed, SIGSUBPKT_KEY_EXPIRE, NULL);
           if (s && buf32_to_u32 (s))
-            tty_printf ("             [expires: %s]\n",
-                        isotimestamp (pk->timestamp + buf32_to_u32 (s)));
+            tty_fprintf (fp, "             [expires: %s]\n",
+                         isotimestamp (pk->timestamp + buf32_to_u32 (s)));
         }
     }
 
@@ -326,618 +321,9 @@ print_and_check_one_sig (ctrl_t ctrl, kbnode_t keyblock, kbnode_t node,
   int rc;
 
   rc = check_key_signature (ctrl, keyblock, node, is_selfsig);
-  return print_one_sig (ctrl, rc,
-                        keyblock, node, inv_sigs, no_key, oth_err,
-                        *is_selfsig, print_without_key, extended);
-}
-
-
-
-/* Order two signatures.  The actual ordering isn't important.  Our
-   goal is to ensure that identical signatures occur together.  */
-static int
-sig_comparison (const void *av, const void *bv)
-{
-  const KBNODE an = *(const KBNODE *) av;
-  const KBNODE bn = *(const KBNODE *) bv;
-  const PKT_signature *a;
-  const PKT_signature *b;
-  int ndataa;
-  int ndatab;
-  int i;
-
-  log_assert (an->pkt->pkttype == PKT_SIGNATURE);
-  log_assert (bn->pkt->pkttype == PKT_SIGNATURE);
-
-  a = an->pkt->pkt.signature;
-  b = bn->pkt->pkt.signature;
-
-  if (a->digest_algo < b->digest_algo)
-    return -1;
-  if (a->digest_algo > b->digest_algo)
-    return 1;
-
-  ndataa = pubkey_get_nsig (a->pubkey_algo);
-  ndatab = pubkey_get_nsig (b->pubkey_algo);
-  if (ndataa != ndatab)
-    return (ndataa < ndatab)? -1 : 1;
-
-  for (i = 0; i < ndataa; i ++)
-    {
-      int c = gcry_mpi_cmp (a->data[i], b->data[i]);
-      if (c != 0)
-        return c;
-    }
-
-  /* Okay, they are equal.  */
-  return 0;
-}
-
-/* Perform a few sanity checks on a keyblock is okay and possibly
-   repair some damage.  Concretely:
-
-     - Detect duplicate signatures and remove them.
-
-     - Detect out of order signatures and relocate them (e.g., a sig
-       over user id X located under subkey Y).
-
-   Note: this function does not remove signatures that don't belong or
-   components that are not signed!  (Although it would be trivial to
-   do so.)
-
-   If ONLY_SELFSIGS is true, then this function only reorders self
-   signatures (it still checks all signatures for duplicates,
-   however).
-
-   Returns 1 if the keyblock was modified, 0 otherwise.  */
-static int
-check_all_keysigs (ctrl_t ctrl, kbnode_t kb,
-                   int only_selected, int only_selfsigs)
-{
-  gpg_error_t err;
-  PKT_public_key *pk;
-  KBNODE n, n_next, *n_prevp, n2;
-  char *pending_desc = NULL;
-  PKT_public_key *issuer;
-  KBNODE last_printed_component;
-  KBNODE current_component = NULL;
-  int dups = 0;
-  int missing_issuer = 0;
-  int reordered = 0;
-  int bad_signature = 0;
-  int missing_selfsig = 0;
-  int modified = 0;
-
-  log_assert (kb->pkt->pkttype == PKT_PUBLIC_KEY);
-  pk = kb->pkt->pkt.public_key;
-
-  /* First we look for duplicates.  */
-  {
-    int nsigs;
-    kbnode_t *sigs;
-    int i;
-    int last_i;
-
-    /* Count the sigs.  */
-    for (nsigs = 0, n = kb; n; n = n->next)
-      {
-        if (is_deleted_kbnode (n))
-          continue;
-        else if (n->pkt->pkttype == PKT_SIGNATURE)
-          nsigs ++;
-      }
-
-    if (!nsigs)
-      return 0; /* No signatures at all.  */
-
-    /* Add them all to the SIGS array.  */
-    sigs = xtrycalloc (nsigs, sizeof *sigs);
-    if (!sigs)
-      {
-        log_error (_("error allocating memory: %s\n"),
-                   gpg_strerror (gpg_error_from_syserror ()));
-        return 0;
-      }
-
-    i = 0;
-    for (n = kb; n; n = n->next)
-      {
-        if (is_deleted_kbnode (n))
-          continue;
-
-        if (n->pkt->pkttype != PKT_SIGNATURE)
-          continue;
-
-        sigs[i] = n;
-        i ++;
-      }
-    log_assert (i == nsigs);
-
-    qsort (sigs, nsigs, sizeof (sigs[0]), sig_comparison);
-
-    last_i = 0;
-    for (i = 1; i < nsigs; i ++)
-      {
-        log_assert (sigs[last_i]);
-        log_assert (sigs[last_i]->pkt->pkttype == PKT_SIGNATURE);
-        log_assert (sigs[i]);
-        log_assert (sigs[i]->pkt->pkttype == PKT_SIGNATURE);
-
-        if (sig_comparison (&sigs[last_i], &sigs[i]) == 0)
-          /* They are the same.  Kill the latter.  */
-          {
-            if (DBG_PACKET)
-              {
-                PKT_signature *sig = sigs[i]->pkt->pkt.signature;
-
-                log_debug ("Signature appears multiple times, "
-                           "deleting duplicate:\n");
-                log_debug ("  sig: class 0x%x, issuer: %s,"
-                           " timestamp: %s (%lld), digest: %02x %02x\n",
-                           sig->sig_class, keystr (sig->keyid),
-                           isotimestamp (sig->timestamp),
-                           (long long) sig->timestamp,
-                           sig->digest_start[0], sig->digest_start[1]);
-              }
-
-            /* Remove sigs[i] from the keyblock.  */
-            {
-              KBNODE z, *prevp;
-              int to_kill = last_i;
-              last_i = i;
-
-              for (prevp = &kb, z = kb; z; prevp = &z->next, z = z->next)
-                if (z == sigs[to_kill])
-                  break;
-
-              *prevp = sigs[to_kill]->next;
-
-              sigs[to_kill]->next = NULL;
-              release_kbnode (sigs[to_kill]);
-              sigs[to_kill] = NULL;
-
-              dups ++;
-              modified = 1;
-            }
-          }
-        else
-          last_i = i;
-      }
-
-    xfree (sigs);
-  }
-
-  /* Make sure the sigs occur after the component (public key, subkey,
-     user id) that they sign.  */
-  issuer = NULL;
-  last_printed_component = NULL;
-  for (n_prevp = &kb, n = kb;
-       n;
-       /* If we moved n, then n_prevp is need valid.  */
-       n_prevp = (n->next == n_next ? &n->next : n_prevp), n = n_next)
-    {
-      PACKET *p;
-      int processed_current_component;
-      PKT_signature *sig;
-      int rc;
-      int dump_sig_params = 0;
-
-      n_next = n->next;
-
-      if (is_deleted_kbnode (n))
-        continue;
-
-      p = n->pkt;
-
-      if (issuer && issuer != pk)
-        {
-          free_public_key (issuer);
-          issuer = NULL;
-        }
-
-      xfree (pending_desc);
-      pending_desc = NULL;
-
-      switch (p->pkttype)
-        {
-        case PKT_PUBLIC_KEY:
-          log_assert (p->pkt.public_key == pk);
-          if (only_selected && ! (n->flag & NODFLG_SELKEY))
-            {
-              current_component = NULL;
-              break;
-            }
-
-          if (DBG_PACKET)
-            log_debug ("public key %s: timestamp: %s (%lld)\n",
-                       pk_keyid_str (pk),
-                       isotimestamp (pk->timestamp),
-                       (long long) pk->timestamp);
-          current_component = n;
-          break;
-        case PKT_PUBLIC_SUBKEY:
-          if (only_selected && ! (n->flag & NODFLG_SELKEY))
-            {
-              current_component = NULL;
-              break;
-            }
-
-          if (DBG_PACKET)
-            log_debug ("subkey %s: timestamp: %s (%lld)\n",
-                       pk_keyid_str (p->pkt.public_key),
-                       isotimestamp (p->pkt.public_key->timestamp),
-                       (long long) p->pkt.public_key->timestamp);
-          current_component = n;
-          break;
-        case PKT_USER_ID:
-          if (only_selected && ! (n->flag & NODFLG_SELUID))
-            {
-              current_component = NULL;
-              break;
-            }
-
-          if (DBG_PACKET)
-            log_debug ("user id: %s\n",
-                       p->pkt.user_id->attrib_data
-                       ? "[ photo id ]"
-                       : p->pkt.user_id->name);
-          current_component = n;
-          break;
-        case PKT_SIGNATURE:
-          if (! current_component)
-            /* The current component is not selected, don't check the
-               sigs under it.  */
-            break;
-
-          sig = n->pkt->pkt.signature;
-
-          pending_desc = xasprintf ("  sig: class: 0x%x, issuer: %s,"
-                                    " timestamp: %s (%lld), digest: %02x %02x",
-                                    sig->sig_class,
-                                    keystr (sig->keyid),
-                                    isotimestamp (sig->timestamp),
-                                    (long long) sig->timestamp,
-                                    sig->digest_start[0], sig->digest_start[1]);
-
-
-          if (keyid_cmp (pk_keyid (pk), sig->keyid) == 0)
-            issuer = pk;
-          else /* Issuer is a different key.  */
-            {
-              if (only_selfsigs)
-                continue;
-
-              issuer = xmalloc (sizeof (*issuer));
-              err = get_pubkey (ctrl, issuer, sig->keyid);
-              if (err)
-                {
-                  xfree (issuer);
-                  issuer = NULL;
-                  if (DBG_PACKET)
-                    {
-                      if (pending_desc)
-                        log_debug ("%s", pending_desc);
-                      log_debug ("    Can't check signature allegedly"
-                                 " issued by %s: %s\n",
-                                 keystr (sig->keyid), gpg_strerror (err));
-                    }
-                  missing_issuer ++;
-                  break;
-                }
-            }
-
-          if ((err = openpgp_pk_test_algo (sig->pubkey_algo)))
-            {
-              if (DBG_PACKET && pending_desc)
-                log_debug ("%s", pending_desc);
-              tty_printf (_("can't check signature with unsupported"
-                            " public-key algorithm (%d): %s.\n"),
-                          sig->pubkey_algo, gpg_strerror (err));
-              break;
-            }
-          if ((err = openpgp_md_test_algo (sig->digest_algo)))
-            {
-              if (DBG_PACKET && pending_desc)
-                log_debug ("%s", pending_desc);
-              tty_printf (_("can't check signature with unsupported"
-                            " message-digest algorithm %d: %s.\n"),
-                          sig->digest_algo, gpg_strerror (err));
-              break;
-            }
-
-          /* We iterate over the keyblock.  Most likely, the matching
-             component is the current component so always try that
-             first.  */
-          processed_current_component = 0;
-          for (n2 = current_component;
-               n2;
-               n2 = (processed_current_component ? n2->next : kb),
-                 processed_current_component = 1)
-            if (is_deleted_kbnode (n2))
-              continue;
-            else if (processed_current_component && n2 == current_component)
-              /* Don't process it twice.  */
-              continue;
-            else
-              {
-                err = check_signature_over_key_or_uid (ctrl,
-                                                       issuer, sig, kb, n2->pkt,
-                                                       NULL, NULL);
-                if (! err)
-                  break;
-              }
-
-          /* n/sig is a signature and n2 is the component (public key,
-             subkey or user id) that it signs, if any.
-             current_component is that component that it appears to
-             apply to (according to the ordering).  */
-
-          if (current_component == n2)
-            {
-              if (DBG_PACKET)
-                {
-                  log_debug ("%s", pending_desc);
-                  log_debug ("    Good signature over last key or uid!\n");
-                }
-
-              rc = 0;
-            }
-          else if (n2)
-            {
-              log_assert (n2->pkt->pkttype == PKT_USER_ID
-                          || n2->pkt->pkttype == PKT_PUBLIC_KEY
-                          || n2->pkt->pkttype == PKT_PUBLIC_SUBKEY);
-
-              if (DBG_PACKET)
-                {
-                  log_debug ("%s", pending_desc);
-                  log_debug ("    Good signature out of order!"
-                             "  (Over %s (%d) '%s')\n",
-                             n2->pkt->pkttype == PKT_USER_ID
-                             ? "user id"
-                             : n2->pkt->pkttype == PKT_PUBLIC_SUBKEY
-                             ? "subkey"
-                             : "primary key",
-                             n2->pkt->pkttype,
-                             n2->pkt->pkttype == PKT_USER_ID
-                             ? n2->pkt->pkt.user_id->name
-                             : pk_keyid_str (n2->pkt->pkt.public_key));
-                }
-
-              /* Reorder the packets: move the signature n to be just
-                 after n2.  */
-
-              /* Unlink the signature.  */
-              log_assert (n_prevp);
-              *n_prevp = n->next;
-
-              /* Insert the sig immediately after the component.  */
-              n->next = n2->next;
-              n2->next = n;
-
-              reordered ++;
-              modified = 1;
-
-              rc = 0;
-            }
-          else
-            {
-              if (DBG_PACKET)
-                {
-                  log_debug ("%s", pending_desc);
-                  log_debug ("    Bad signature.\n");
-                }
-
-              if (DBG_PACKET)
-                dump_sig_params = 1;
-
-              bad_signature ++;
-
-              rc = GPG_ERR_BAD_SIGNATURE;
-            }
-
-          /* We don't cache the result here, because we haven't
-             completely checked that the signature is legitimate.  For
-             instance, if we have a revocation certificate on Alice's
-             key signed by Bob, the signature may be good, but we
-             haven't checked that Bob is a designated revoker.  */
-          /* cache_sig_result (sig, rc); */
-
-          {
-            int has_selfsig = 0;
-            if (! rc && issuer == pk)
-              {
-                if (n2->pkt->pkttype == PKT_PUBLIC_KEY
-                    && (/* Direct key signature.  */
-                        sig->sig_class == 0x1f
-                        /* Key revocation signature.  */
-                        || sig->sig_class == 0x20))
-                  has_selfsig = 1;
-                if (n2->pkt->pkttype == PKT_PUBLIC_SUBKEY
-                    && (/* Subkey binding sig.  */
-                        sig->sig_class == 0x18
-                        /* Subkey revocation sig.  */
-                        || sig->sig_class == 0x28))
-                  has_selfsig = 1;
-                if (n2->pkt->pkttype == PKT_USER_ID
-                    && (/* Certification sigs.  */
-                        sig->sig_class == 0x10
-                        || sig->sig_class == 0x11
-                        || sig->sig_class == 0x12
-                        || sig->sig_class == 0x13
-                        /* Certification revocation sig.  */
-                        || sig->sig_class == 0x30))
-                  has_selfsig = 1;
-              }
-
-            if ((n2 && n2 != last_printed_component)
-                || (! n2 && last_printed_component != current_component))
-              {
-                int is_reordered = n2 && n2 != current_component;
-                if (n2)
-                  last_printed_component = n2;
-                else
-                  last_printed_component = current_component;
-
-                if (!modified)
-                  ;
-                else if (last_printed_component->pkt->pkttype == PKT_USER_ID)
-                  {
-                    tty_printf ("uid  ");
-                    tty_print_utf8_string (last_printed_component
-                                           ->pkt->pkt.user_id->name,
-                                           last_printed_component
-                                           ->pkt->pkt.user_id->len);
-                  }
-                else if (last_printed_component->pkt->pkttype
-                         == PKT_PUBLIC_KEY)
-                  tty_printf ("pub  %s",
-                              pk_keyid_str (last_printed_component
-                                            ->pkt->pkt.public_key));
-                else
-                  tty_printf ("sub  %s",
-                              pk_keyid_str (last_printed_component
-                                            ->pkt->pkt.public_key));
-
-                if (modified)
-                  {
-                    if (is_reordered)
-                      tty_printf (_(" (reordered signatures follow)"));
-                    tty_printf ("\n");
-                  }
-              }
-
-            if (modified)
-              print_one_sig (ctrl, rc, kb, n, NULL, NULL, NULL, has_selfsig,
-                             0, only_selfsigs);
-          }
-
-          if (dump_sig_params)
-            {
-              int i;
-
-              for (i = 0; i < pubkey_get_nsig (sig->pubkey_algo); i ++)
-                {
-                  char buffer[1024];
-                  size_t len;
-                  char *printable;
-                  gcry_mpi_print (GCRYMPI_FMT_USG,
-                                  buffer, sizeof (buffer), &len,
-                                  sig->data[i]);
-                  printable = bin2hex (buffer, len, NULL);
-                  log_info ("        %d: %s\n", i, printable);
-                  xfree (printable);
-                }
-            }
-          break;
-        default:
-          if (DBG_PACKET)
-            log_debug ("unhandled packet: %d\n", p->pkttype);
-          break;
-        }
-    }
-
-  xfree (pending_desc);
-  pending_desc = NULL;
-
-  if (issuer != pk)
-    free_public_key (issuer);
-  issuer = NULL;
-
-  /* Identify keys / uids that don't have a self-sig.  */
-  {
-    int has_selfsig = 0;
-    PACKET *p;
-    PKT_signature *sig;
-
-    current_component = NULL;
-    for (n = kb; n; n = n->next)
-      {
-        if (is_deleted_kbnode (n))
-          continue;
-
-        p = n->pkt;
-
-        switch (p->pkttype)
-          {
-          case PKT_PUBLIC_KEY:
-          case PKT_PUBLIC_SUBKEY:
-          case PKT_USER_ID:
-            if (current_component && ! has_selfsig)
-              missing_selfsig ++;
-            current_component = n;
-            has_selfsig = 0;
-            break;
-
-          case PKT_SIGNATURE:
-            if (! current_component || has_selfsig)
-              break;
-
-            sig = n->pkt->pkt.signature;
-
-            if (! (sig->flags.checked && sig->flags.valid))
-              break;
-
-            if (keyid_cmp (pk_keyid (pk), sig->keyid) != 0)
-              /* Different issuer, couldn't be a self-sig.  */
-              break;
-
-            if (current_component->pkt->pkttype == PKT_PUBLIC_KEY
-                && (/* Direct key signature.  */
-                    sig->sig_class == 0x1f
-                    /* Key revocation signature.  */
-                    || sig->sig_class == 0x20))
-              has_selfsig = 1;
-            if (current_component->pkt->pkttype == PKT_PUBLIC_SUBKEY
-                && (/* Subkey binding sig.  */
-                    sig->sig_class == 0x18
-                    /* Subkey revocation sig.  */
-                    || sig->sig_class == 0x28))
-              has_selfsig = 1;
-            if (current_component->pkt->pkttype == PKT_USER_ID
-                && (/* Certification sigs.  */
-                    sig->sig_class == 0x10
-                    || sig->sig_class == 0x11
-                    || sig->sig_class == 0x12
-                    || sig->sig_class == 0x13
-                    /* Certification revocation sig.  */
-                    || sig->sig_class == 0x30))
-              has_selfsig = 1;
-
-            break;
-
-          default:
-            if (current_component && ! has_selfsig)
-              missing_selfsig ++;
-            current_component = NULL;
-          }
-      }
-  }
-
-  if (dups || missing_issuer || bad_signature || reordered)
-    tty_printf (_("key %s:\n"), pk_keyid_str (pk));
-
-  if (dups)
-    tty_printf (ngettext ("%d duplicate signature removed\n",
-                          "%d duplicate signatures removed\n", dups), dups);
-  if (missing_issuer)
-    tty_printf (ngettext ("%d signature not checked due to a missing key\n",
-                          "%d signatures not checked due to missing keys\n",
-                          missing_issuer), missing_issuer);
-  if (bad_signature)
-    tty_printf (ngettext ("%d bad signature\n",
-                          "%d bad signatures\n",
-                          bad_signature), bad_signature);
-  if (reordered)
-    tty_printf (ngettext ("%d signature reordered\n",
-                          "%d signatures reordered\n",
-                          reordered), reordered);
-
-  if (only_selfsigs && (bad_signature || reordered))
-    tty_printf (_("Warning: errors found and only checked self-signatures,"
-                  " run '%s' to check all signatures.\n"), "check");
-
-  return modified;
+  return keyedit_print_one_sig (ctrl, NULL, rc,
+                               keyblock, node, inv_sigs, no_key, oth_err,
+                               *is_selfsig, print_without_key, extended);
 }
 
 
@@ -1593,7 +979,7 @@ sign_uids (ctrl_t ctrl, estream_t fp,
        continue;
 
       /* Now we can sign the user ids.  */
-    reloop:  /* (Must use this, because we are modifing the list.)  */
+    reloop:  /* (Must use this, because we are modifying the list.)  */
       primary_pk = NULL;
       for (node = keyblock; node; node = node->next)
        {
@@ -1748,15 +1134,17 @@ change_passphrase (ctrl_t ctrl, kbnode_t keyblock)
           if (err)
             goto leave;
 
+          /* Note that when using --dry-run we don't change the
+           * passphrase but merely verify the current passphrase.  */
           desc = gpg_format_keydesc (ctrl, pk, FORMAT_KEYDESC_NORMAL, 1);
-          err = agent_passwd (ctrl, hexgrip, desc, 0,
+          err = agent_passwd (ctrl, hexgrip, desc, !!opt.dry_run,
                               &cache_nonce, &passwd_nonce);
           xfree (desc);
 
           if (err)
             log_log ((gpg_err_code (err) == GPG_ERR_CANCELED
                       || gpg_err_code (err) == GPG_ERR_FULLY_CANCELED)
-                     ? GPGRT_LOG_INFO : GPGRT_LOG_ERROR,
+                     ? GPGRT_LOGLVL_INFO : GPGRT_LOGLVL_ERROR,
                      _("key %s: error changing passphrase: %s\n"),
                        keystr_with_sub (keyid, subid),
                        gpg_strerror (err));
@@ -1784,7 +1172,7 @@ fix_keyblock (ctrl_t ctrl, kbnode_t *keyblockp)
 
   if (collapse_uids (keyblockp))
     changed++;
-  if (check_all_keysigs (ctrl, *keyblockp, 0, 1))
+  if (key_check_all_keysigs (ctrl, 1, *keyblockp, 0, 1))
     changed++;
   reorder_keyblock (*keyblockp);
   /* If we modified the keyblock, make sure the flags are right. */
@@ -1837,10 +1225,8 @@ parse_sign_type (const char *str, int *localsig, int *nonrevokesig,
 
 /* Need an SK for this command */
 #define KEYEDIT_NEED_SK 1
-/* Cannot be viewing the SK for this command */
-#define KEYEDIT_NOT_SK  2
-/* Must be viewing the SK for this command */
-#define KEYEDIT_ONLY_SK 4
+/* Need an SUB KEY for this command */
+#define KEYEDIT_NEED_SUBSK 2
 /* Match the tail of the string */
 #define KEYEDIT_TAIL_MATCH 8
 
@@ -1882,12 +1268,12 @@ static struct
   { "key", cmdSELKEY, 0, N_("select subkey N")},
   { "check", cmdCHECK, 0, N_("check signatures")},
   { "c", cmdCHECK, 0, NULL},
-  { "change-usage", cmdCHANGEUSAGE, KEYEDIT_NOT_SK | KEYEDIT_NEED_SK, NULL},
-  { "cross-certify", cmdBACKSIGN, KEYEDIT_NOT_SK | KEYEDIT_NEED_SK, NULL},
-  { "backsign", cmdBACKSIGN, KEYEDIT_NOT_SK | KEYEDIT_NEED_SK, NULL},
-  { "sign", cmdSIGN, KEYEDIT_NOT_SK | KEYEDIT_TAIL_MATCH,
+  { "change-usage", cmdCHANGEUSAGE, KEYEDIT_NEED_SK, NULL},
+  { "cross-certify", cmdBACKSIGN, KEYEDIT_NEED_SK, NULL},
+  { "backsign", cmdBACKSIGN,  KEYEDIT_NEED_SK, NULL},
+  { "sign", cmdSIGN,  KEYEDIT_TAIL_MATCH,
     N_("sign selected user IDs [* see below for related commands]")},
-  { "s", cmdSIGN, KEYEDIT_NOT_SK, NULL},
+  { "s", cmdSIGN, 0, NULL},
     /* "lsign" and friends will never match since "sign" comes first
        and it is a tail match.  They are just here so they show up in
        the help menu. */
@@ -1896,62 +1282,62 @@ static struct
   { "nrsign", cmdNOP, 0,
     N_("sign selected user IDs with a non-revocable signature")},
   { "debug", cmdDEBUG, 0, NULL},
-  { "adduid", cmdADDUID, KEYEDIT_NOT_SK | KEYEDIT_NEED_SK, N_("add a user ID")},
-  { "addphoto", cmdADDPHOTO, KEYEDIT_NOT_SK | KEYEDIT_NEED_SK,
+  { "adduid", cmdADDUID,  KEYEDIT_NEED_SK, N_("add a user ID")},
+  { "addphoto", cmdADDPHOTO,  KEYEDIT_NEED_SK,
     N_("add a photo ID")},
-  { "deluid", cmdDELUID, KEYEDIT_NOT_SK, N_("delete selected user IDs")},
+  { "deluid", cmdDELUID, 0, N_("delete selected user IDs")},
     /* delphoto is really deluid in disguise */
-  { "delphoto", cmdDELUID, KEYEDIT_NOT_SK, NULL},
-  { "addkey", cmdADDKEY, KEYEDIT_NOT_SK | KEYEDIT_NEED_SK, N_("add a subkey")},
+  { "delphoto", cmdDELUID, 0, NULL},
+  { "addkey", cmdADDKEY,  KEYEDIT_NEED_SK, N_("add a subkey")},
 #ifdef ENABLE_CARD_SUPPORT
-  { "addcardkey", cmdADDCARDKEY, KEYEDIT_NOT_SK | KEYEDIT_NEED_SK,
+  { "addcardkey", cmdADDCARDKEY,  KEYEDIT_NEED_SK,
     N_("add a key to a smartcard")},
-  { "keytocard", cmdKEYTOCARD, KEYEDIT_NEED_SK | KEYEDIT_ONLY_SK,
+  { "keytocard", cmdKEYTOCARD, KEYEDIT_NEED_SK | KEYEDIT_NEED_SUBSK,
     N_("move a key to a smartcard")},
-  { "bkuptocard", cmdBKUPTOCARD, KEYEDIT_NEED_SK | KEYEDIT_ONLY_SK,
+  { "bkuptocard", cmdBKUPTOCARD, KEYEDIT_NEED_SK | KEYEDIT_NEED_SUBSK,
     N_("move a backup key to a smartcard")},
 #endif /*ENABLE_CARD_SUPPORT */
-  { "delkey", cmdDELKEY, KEYEDIT_NOT_SK, N_("delete selected subkeys")},
-  { "addrevoker", cmdADDREVOKER, KEYEDIT_NOT_SK | KEYEDIT_NEED_SK,
+  { "delkey", cmdDELKEY, 0, N_("delete selected subkeys")},
+  { "addrevoker", cmdADDREVOKER,  KEYEDIT_NEED_SK,
     N_("add a revocation key")},
-  { "delsig", cmdDELSIG, KEYEDIT_NOT_SK,
+  { "delsig", cmdDELSIG, 0,
     N_("delete signatures from the selected user IDs")},
-  { "expire", cmdEXPIRE, KEYEDIT_NOT_SK | KEYEDIT_NEED_SK,
+  { "expire", cmdEXPIRE,  KEYEDIT_NEED_SK | KEYEDIT_NEED_SUBSK,
     N_("change the expiration date for the key or selected subkeys")},
-  { "primary", cmdPRIMARY, KEYEDIT_NOT_SK | KEYEDIT_NEED_SK,
+  { "primary", cmdPRIMARY,  KEYEDIT_NEED_SK,
     N_("flag the selected user ID as primary")},
   { "toggle", cmdTOGGLE, KEYEDIT_NEED_SK, NULL},  /* Dummy command.  */
   { "t", cmdTOGGLE, KEYEDIT_NEED_SK, NULL},
-  { "pref", cmdPREF, KEYEDIT_NOT_SK, N_("list preferences (expert)")},
-  { "showpref", cmdSHOWPREF, KEYEDIT_NOT_SK, N_("list preferences (verbose)")},
-  { "setpref", cmdSETPREF, KEYEDIT_NOT_SK | KEYEDIT_NEED_SK,
+  { "pref", cmdPREF, 0, N_("list preferences (expert)")},
+  { "showpref", cmdSHOWPREF, 0, N_("list preferences (verbose)")},
+  { "setpref", cmdSETPREF,  KEYEDIT_NEED_SK,
     N_("set preference list for the selected user IDs")},
-  { "updpref", cmdSETPREF, KEYEDIT_NOT_SK | KEYEDIT_NEED_SK, NULL},
-  { "keyserver", cmdPREFKS, KEYEDIT_NOT_SK | KEYEDIT_NEED_SK,
+  { "updpref", cmdSETPREF,  KEYEDIT_NEED_SK, NULL},
+  { "keyserver", cmdPREFKS,  KEYEDIT_NEED_SK,
     N_("set the preferred keyserver URL for the selected user IDs")},
-  { "notation", cmdNOTATION, KEYEDIT_NOT_SK | KEYEDIT_NEED_SK,
+  { "notation", cmdNOTATION,  KEYEDIT_NEED_SK,
     N_("set a notation for the selected user IDs")},
-  { "passwd", cmdPASSWD, KEYEDIT_NOT_SK | KEYEDIT_NEED_SK,
+  { "passwd", cmdPASSWD,  KEYEDIT_NEED_SK | KEYEDIT_NEED_SUBSK,
     N_("change the passphrase")},
-  { "password", cmdPASSWD, KEYEDIT_NOT_SK | KEYEDIT_NEED_SK, NULL},
+  { "password", cmdPASSWD,  KEYEDIT_NEED_SK | KEYEDIT_NEED_SUBSK, NULL},
 #ifndef NO_TRUST_MODELS
-  { "trust", cmdTRUST, KEYEDIT_NOT_SK, N_("change the ownertrust")},
+  { "trust", cmdTRUST, 0, N_("change the ownertrust")},
 #endif /*!NO_TRUST_MODELS*/
-  { "revsig", cmdREVSIG, KEYEDIT_NOT_SK,
+  { "revsig", cmdREVSIG, 0,
     N_("revoke signatures on the selected user IDs")},
-  { "revuid", cmdREVUID, KEYEDIT_NOT_SK | KEYEDIT_NEED_SK,
+  { "revuid", cmdREVUID,  KEYEDIT_NEED_SK,
     N_("revoke selected user IDs")},
-  { "revphoto", cmdREVUID, KEYEDIT_NOT_SK | KEYEDIT_NEED_SK, NULL},
-  { "revkey", cmdREVKEY, KEYEDIT_NOT_SK | KEYEDIT_NEED_SK,
+  { "revphoto", cmdREVUID,  KEYEDIT_NEED_SK, NULL},
+  { "revkey", cmdREVKEY,  KEYEDIT_NEED_SK,
     N_("revoke key or selected subkeys")},
 #ifndef NO_TRUST_MODELS
-  { "enable", cmdENABLEKEY, KEYEDIT_NOT_SK, N_("enable key")},
-  { "disable", cmdDISABLEKEY, KEYEDIT_NOT_SK, N_("disable key")},
+  { "enable", cmdENABLEKEY, 0, N_("enable key")},
+  { "disable", cmdDISABLEKEY, 0, N_("disable key")},
 #endif /*!NO_TRUST_MODELS*/
   { "showphoto", cmdSHOWPHOTO, 0, N_("show selected photo IDs")},
-  { "clean", cmdCLEAN, KEYEDIT_NOT_SK,
+  { "clean", cmdCLEAN, 0,
     N_("compact unusable user IDs and remove unusable signatures from key")},
-  { "minimize", cmdMINIMIZE, KEYEDIT_NOT_SK,
+  { "minimize", cmdMINIMIZE, 0,
     N_("compact unusable user IDs and remove all signatures from key")},
 
   { NULL, cmdNONE, 0, NULL}
@@ -2020,6 +1406,7 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
   KBNODE keyblock = NULL;
   KEYDB_HANDLE kdbhd = NULL;
   int have_seckey = 0;
+  int have_anyseckey = 0;
   char *answer = NULL;
   int redisplay = 1;
   int modified = 0;
@@ -2062,9 +1449,18 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
   /* See whether we have a matching secret key.  */
   if (seckey_check)
     {
-      have_seckey = !agent_probe_any_secret_key (ctrl, keyblock);
+      have_anyseckey = !agent_probe_any_secret_key (ctrl, keyblock);
+      if (have_anyseckey
+          && !agent_probe_secret_key (ctrl, keyblock->pkt->pkt.public_key))
+        {
+          /* The primary key is also available.   */
+          have_seckey = 1;
+        }
+
       if (have_seckey && !quiet)
-       tty_printf (_("Secret key is available.\n"));
+        tty_printf (_("Secret key is available.\n"));
+      else if (have_anyseckey && !quiet)
+        tty_printf (_("Secret subkeys are available.\n"));
     }
 
   /* Main command loop.  */
@@ -2162,12 +1558,14 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
              else if (!ascii_strcasecmp (answer, cmds[i].name))
                break;
            }
-         if ((cmds[i].flags & KEYEDIT_NEED_SK) && !have_seckey)
+         if ((cmds[i].flags & (KEYEDIT_NEED_SK|KEYEDIT_NEED_SUBSK))
+              && !(((cmds[i].flags & KEYEDIT_NEED_SK) && have_seckey)
+                   || ((cmds[i].flags & KEYEDIT_NEED_SUBSK) && have_anyseckey)))
            {
              tty_printf (_("Need the secret key to do this.\n"));
              cmd = cmdNOP;
            }
-         else
+          else
            cmd = cmds[i].id;
        }
 
@@ -2177,7 +1575,9 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
        case cmdHELP:
          for (i = 0; cmds[i].name; i++)
            {
-             if ((cmds[i].flags & KEYEDIT_NEED_SK) && !have_seckey)
+              if ((cmds[i].flags & (KEYEDIT_NEED_SK|KEYEDIT_NEED_SUBSK))
+                  && !(((cmds[i].flags & KEYEDIT_NEED_SK) && have_seckey)
+                       ||((cmds[i].flags&KEYEDIT_NEED_SUBSK)&&have_anyseckey)))
                ; /* Skip those item if we do not have the secret key.  */
              else if (cmds[i].desc)
                tty_printf ("%-11s %s\n", cmds[i].name, _(cmds[i].desc));
@@ -2231,9 +1631,9 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
          break;
 
        case cmdCHECK:
-         if (check_all_keysigs (ctrl, keyblock,
-                                 count_selected_uids (keyblock),
-                                 !strcmp (arg_string, "selfsig")))
+         if (key_check_all_keysigs (ctrl, -1, keyblock,
+                                    count_selected_uids (keyblock),
+                                    !strcmp (arg_string, "selfsig")))
             modified = 1;
          break;
 
@@ -2266,11 +1666,11 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
                 if (opt.only_sign_text_ids)
                   result = cpr_get_answer_is_yes
                     ("keyedit.sign_all.okay",
-                     _("Really sign all user IDs? (y/N) "));
+                     _("Really sign all text user IDs? (y/N) "));
                 else
                   result = cpr_get_answer_is_yes
                     ("keyedit.sign_all.okay",
-                     _("Really sign all text user IDs? (y/N) "));
+                     _("Really sign all user IDs? (y/N) "));
 
                 if (! result)
                   {
@@ -2314,7 +1714,7 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
          if (RFC2440)
            {
              tty_printf (_("This command is not allowed while in %s mode.\n"),
-                         compliance_option_string ());
+                         gnupg_compliance_option_string (opt.compliance));
              break;
            }
          photo = 1;
@@ -3069,7 +2469,10 @@ keyedit_quick_revuid (ctrl_t ctrl, const char *username, const char *uidtorev)
 
  leave:
   if (err)
-    log_error (_("revoking the user ID failed: %s\n"), gpg_strerror (err));
+    {
+      log_error (_("revoking the user ID failed: %s\n"), gpg_strerror (err));
+      write_status_error ("keyedit.revoke.uid", err);
+    }
   release_kbnode (keyblock);
   keydb_release (kdbhd);
 }
@@ -3426,18 +2829,24 @@ keyedit_quick_addkey (ctrl_t ctrl, const char *fpr, const char *algostr,
 }
 
 
-/* Unattended expiration setting function for the main key.
- *
+/* Unattended expiration setting function for the main key.  If
+ * SUBKEYFPRS is not NULL and SUBKEYSFPRS[0] is neither NULL, it is
+ * expected to be an array of fingerprints for subkeys to change. It
+ * may also be an array which just one item "*" to indicate that all
+ * keys shall be set to that expiration date.
  */
 void
-keyedit_quick_set_expire (ctrl_t ctrl, const char *fpr, const char *expirestr)
+keyedit_quick_set_expire (ctrl_t ctrl, const char *fpr, const char *expirestr,
+                          char **subkeyfprs)
 {
   gpg_error_t err;
-  kbnode_t keyblock;
+  kbnode_t keyblock, node;
   KEYDB_HANDLE kdbhd;
   int modified = 0;
   PKT_public_key *pk;
   u32 expire;
+  int primary_only = 0;
+  int idx;
 
 #ifdef HAVE_W32_SYSTEM
   /* See keyedit_menu for why we need this.  */
@@ -3464,7 +2873,6 @@ keyedit_quick_set_expire (ctrl_t ctrl, const char *fpr, const char *expirestr)
       goto leave;
     }
 
-
   expire = parse_expire_string (expirestr);
   if (expire == (u32)-1 )
     {
@@ -3475,8 +2883,78 @@ keyedit_quick_set_expire (ctrl_t ctrl, const char *fpr, const char *expirestr)
   if (expire)
     expire += make_timestamp ();
 
+  /* Check whether a subkey's expiration time shall be changed or the
+   * expiration time of all keys.  */
+  if (!subkeyfprs || !subkeyfprs[0])
+    primary_only = 1;
+  else if ( !strcmp (subkeyfprs[0], "*") && !subkeyfprs[1])
+    {
+      /* Change all subkeys keys which have not been revoked and are
+       * not yet expired.  */
+      merge_keys_and_selfsig (ctrl, keyblock);
+      for (node = keyblock; node; node = node->next)
+        {
+          if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY
+              && (pk = node->pkt->pkt.public_key)
+              && !pk->flags.revoked
+              && !pk->has_expired)
+            node->flag |= NODFLG_SELKEY;
+        }
+    }
+  else
+    {
+      /* Change specified subkeys.  */
+      KEYDB_SEARCH_DESC desc;
+      byte fprbin[MAX_FINGERPRINT_LEN];
+      size_t fprlen;
+
+      err = 0;
+      merge_keys_and_selfsig (ctrl, keyblock);
+      for (idx=0; subkeyfprs[idx]; idx++)
+        {
+          int any = 0;
+
+          /* Parse the fingerprint.  */
+          if (classify_user_id (subkeyfprs[idx], &desc, 1)
+              || !(desc.mode == KEYDB_SEARCH_MODE_FPR
+                   || desc.mode == KEYDB_SEARCH_MODE_FPR20))
+            {
+              log_error (_("\"%s\" is not a proper fingerprint\n"),
+                         subkeyfprs[idx] );
+              if (!err)
+                err = gpg_error (GPG_ERR_INV_NAME);
+              continue;
+            }
+
+          /* Set the flag for the matching non revoked subkey.  */
+          for (node = keyblock; node; node = node->next)
+            {
+              if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY
+                  && (pk = node->pkt->pkt.public_key)
+                  && !pk->flags.revoked )
+                {
+                  fingerprint_from_pk (pk, fprbin, &fprlen);
+                  if (fprlen == 20 && !memcmp (fprbin, desc.u.fpr, 20))
+                    {
+                      node->flag |= NODFLG_SELKEY;
+                      any = 1;
+                    }
+                }
+            }
+          if (!any)
+            {
+              log_error (_("subkey \"%s\" not found\n"), subkeyfprs[idx]);
+              if (!err)
+                err = gpg_error (GPG_ERR_NOT_FOUND);
+            }
+        }
+
+      if (err)
+        goto leave;
+    }
+
   /* Set the new expiration date.  */
-  err = menu_expire (ctrl, keyblock, 1, expire);
+  err = menu_expire (ctrl, keyblock, primary_only? 1 : 2, expire);
   if (gpg_err_code (err) == GPG_ERR_TRUE)
     modified = 1;
   else if (err)
@@ -3588,6 +3066,23 @@ show_prefs (PKT_user_id * uid, PKT_signature * selfsig, int verbose)
          tty_printf ("%s", openpgp_cipher_algo_name (CIPHER_ALGO_3DES));
        }
       tty_printf ("\n     ");
+      tty_printf (_("AEAD: "));
+      for (i = any = 0; prefs[i].type; i++)
+       {
+         if (prefs[i].type == PREFTYPE_AEAD)
+           {
+             if (any)
+               tty_printf (", ");
+             any = 1;
+             /* We don't want to display strings for experimental algos */
+             if (!openpgp_aead_test_algo (prefs[i].value)
+                 && prefs[i].value < 100)
+               tty_printf ("%s", openpgp_aead_algo_name (prefs[i].value));
+             else
+               tty_printf ("[%d]", prefs[i].value);
+           }
+       }
+      tty_printf ("\n     ");
       tty_printf (_("Digest: "));
       for (i = any = 0; prefs[i].type; i++)
        {
@@ -3642,7 +3137,7 @@ show_prefs (PKT_user_id * uid, PKT_signature * selfsig, int verbose)
            }
          tty_printf ("%s", compress_algo_to_string (COMPRESS_ALGO_NONE));
        }
-      if (uid->flags.mdc || !uid->flags.ks_modify)
+      if (uid->flags.mdc || uid->flags.aead || !uid->flags.ks_modify)
        {
          tty_printf ("\n     ");
          tty_printf (_("Features: "));
@@ -3652,6 +3147,12 @@ show_prefs (PKT_user_id * uid, PKT_signature * selfsig, int verbose)
              tty_printf ("MDC");
              any = 1;
            }
+         if (!uid->flags.aead)
+           {
+             if (any)
+               tty_printf (", ");
+             tty_printf ("AEAD");
+           }
          if (!uid->flags.ks_modify)
            {
              if (any)
@@ -3690,12 +3191,15 @@ show_prefs (PKT_user_id * uid, PKT_signature * selfsig, int verbose)
       for (i = 0; prefs[i].type; i++)
        {
          tty_printf (" %c%d", prefs[i].type == PREFTYPE_SYM ? 'S' :
+                     prefs[i].type == PREFTYPE_AEAD ? 'A' :
                      prefs[i].type == PREFTYPE_HASH ? 'H' :
                      prefs[i].type == PREFTYPE_ZIP ? 'Z' : '?',
                      prefs[i].value);
        }
       if (uid->flags.mdc)
        tty_printf (" [mdc]");
+      if (uid->flags.aead)
+       tty_printf (" [aead]");
       if (!uid->flags.ks_modify)
        tty_printf (" [no-ks-modify]");
       tty_printf ("\n");
@@ -3841,6 +3345,8 @@ show_key_with_all_names_colon (ctrl_t ctrl, estream_t fp, kbnode_t keyblock)
                }
              if (uid->flags.mdc)
                es_fputs (",mdc", fp);
+             if (uid->flags.aead)
+               es_fputs (",aead", fp);
              if (!uid->flags.ks_modify)
                es_fputs (",no-ks-modify", fp);
            }
@@ -4104,7 +3610,7 @@ show_key_with_all_names (ctrl_t ctrl, estream_t fp,
               && pk->seckey_info->is_protected
               && pk->seckey_info->s2k.mode == 1002)
            {
-              /* FIXME: Check wether this code path is still used.  */
+              /* FIXME: Check whether this code path is still used.  */
              tty_fprintf (fp, "%*s%s", opt.legacy_list_mode? 21:5, "",
                            _("card-no: "));
              if (pk->seckey_info->ivlen == 16
@@ -4901,30 +4407,34 @@ fail:
 
 
 /* With FORCE_MAINKEY cleared this function handles the interactive
- * menu option "expire".  With FORCE_MAINKEY set this functions only
+ * menu option "expire".  With UNATTENDED set to 1 this function only
  * sets the expiration date of the primary key to NEWEXPIRATION and
- * avoid all interactivity.  Retirns 0 if nothing was done,
+ * avoid all interactivity; with a value of 2 only the flagged subkeys
+ * are set to NEWEXPIRATION.  Returns 0 if nothing was done,
  * GPG_ERR_TRUE if the key was modified, or any other error code. */
 static gpg_error_t
 menu_expire (ctrl_t ctrl, kbnode_t pub_keyblock,
-             int force_mainkey, u32 newexpiration)
+             int unattended, u32 newexpiration)
 {
   int signumber, rc;
   u32 expiredate;
-  int mainkey = 0;
+  int only_mainkey;  /* Set if only the mainkey is to be updated.  */
   PKT_public_key *main_pk, *sub_pk;
   PKT_user_id *uid;
   kbnode_t node;
   u32 keyid[2];
 
-  if (force_mainkey)
+  if (unattended)
     {
-      mainkey = 1;
+      only_mainkey = (unattended == 1);
       expiredate = newexpiration;
     }
   else
     {
-      int n1 = count_selected_keys (pub_keyblock);
+      int n1;
+
+      only_mainkey = 0;
+      n1 = count_selected_keys (pub_keyblock);
       if (n1 > 1)
         {
           if (!cpr_get_answer_is_yes
@@ -4938,7 +4448,7 @@ menu_expire (ctrl_t ctrl, kbnode_t pub_keyblock,
       else
         {
           tty_printf (_("Changing expiration time for the primary key.\n"));
-          mainkey = 1;
+          only_mainkey = 1;
           no_primary_warning (pub_keyblock);
         }
 
@@ -4960,8 +4470,10 @@ menu_expire (ctrl_t ctrl, kbnode_t pub_keyblock,
        }
       else if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
        {
-          if ((node->flag & NODFLG_SELKEY) && !force_mainkey)
+          if ((node->flag & NODFLG_SELKEY) && unattended != 1)
             {
+              /* The flag is set and we do not want to set the
+               * expiration date only for the main key.  */
               sub_pk = node->pkt->pkt.public_key;
               sub_pk->expiredate = expiredate;
             }
@@ -4971,14 +4483,14 @@ menu_expire (ctrl_t ctrl, kbnode_t pub_keyblock,
       else if (node->pkt->pkttype == PKT_USER_ID)
        uid = node->pkt->pkt.user_id;
       else if (main_pk && node->pkt->pkttype == PKT_SIGNATURE
-              && (mainkey || sub_pk))
+              && (only_mainkey || sub_pk))
        {
          PKT_signature *sig = node->pkt->pkt.signature;
 
          if (keyid[0] == sig->keyid[0] && keyid[1] == sig->keyid[1]
-             && ((mainkey && uid
+             && ((only_mainkey && uid
                   && uid->created && (sig->sig_class & ~3) == 0x10)
-                 || (!mainkey && sig->sig_class == 0x18))
+                 || (!only_mainkey && sig->sig_class == 0x18))
              && sig->flags.chosen_selfsig)
            {
              /* This is a self-signature which is to be replaced.  */
@@ -4987,15 +4499,15 @@ menu_expire (ctrl_t ctrl, kbnode_t pub_keyblock,
 
              signumber++;
 
-             if ((mainkey && main_pk->version < 4)
-                 || (!mainkey && sub_pk->version < 4))
+             if ((only_mainkey && main_pk->version < 4)
+                 || (!only_mainkey && sub_pk->version < 4))
                {
                  log_info
                     (_("You can't change the expiration date of a v3 key\n"));
                  return gpg_error (GPG_ERR_LEGACY_KEY);
                }
 
-             if (mainkey)
+             if (only_mainkey)
                rc = update_keysig_packet (ctrl,
                                            &newsig, sig, main_pk, uid, NULL,
                                           main_pk, keygen_add_key_expire,
@@ -6361,7 +5873,7 @@ menu_revsig (ctrl_t ctrl, kbnode_t keyblock)
     }
 
   /* now we can sign the user ids */
-reloop:                        /* (must use this, because we are modifing the list) */
+reloop:                        /* (must use this, because we are modifying the list) */
   primary_pk = keyblock->pkt->pkt.public_key;
   for (node = keyblock; node; node = node->next)
     {
@@ -6641,7 +6153,7 @@ menu_revsubkey (ctrl_t ctrl, kbnode_t pub_keyblock)
   if (!reason)
       return 0; /* User decided to cancel.  */
 
- reloop: /* (better this way because we are modifing the keyring) */
+ reloop: /* (better this way because we are modifying the keyring) */
   mainpk = pub_keyblock->pkt->pkt.public_key;
   for (node = pub_keyblock; node; node = node->next)
     {