Merge branch 'STABLE-BRANCH-2-2' into master
[gnupg.git] / g10 / keyedit.c
index 0a90cf5..2cb9bb2 100644 (file)
@@ -193,7 +193,8 @@ print_and_check_one_sig_colon (ctrl_t ctrl, kbnode_t keyblock, kbnode_t node,
  * always be printed.
  */
 int
-keyedit_print_one_sig (ctrl_t ctrl, int rc, kbnode_t keyblock, kbnode_t node,
+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)
 {
@@ -232,7 +233,7 @@ keyedit_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 <
@@ -248,38 +249,41 @@ keyedit_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.
@@ -287,7 +291,7 @@ keyedit_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)
         {
@@ -296,12 +300,12 @@ keyedit_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)));
         }
     }
 
@@ -317,7 +321,7 @@ 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 keyedit_print_one_sig (ctrl, rc,
+  return keyedit_print_one_sig (ctrl, NULL, rc,
                                keyblock, node, inv_sigs, no_key, oth_err,
                                *is_selfsig, print_without_key, extended);
 }
@@ -1130,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));
@@ -1166,7 +1172,7 @@ fix_keyblock (ctrl_t ctrl, kbnode_t *keyblockp)
 
   if (collapse_uids (keyblockp))
     changed++;
-  if (key_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. */
@@ -1219,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
 
@@ -1264,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. */
@@ -1278,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}
@@ -1402,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;
@@ -1444,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.  */
@@ -1544,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;
        }
 
@@ -1559,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));
@@ -1613,7 +1631,7 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
          break;
 
        case cmdCHECK:
-         if (key_check_all_keysigs (ctrl, keyblock,
+         if (key_check_all_keysigs (ctrl, -1, keyblock,
                                     count_selected_uids (keyblock),
                                     !strcmp (arg_string, "selfsig")))
             modified = 1;
@@ -1648,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)
                   {
@@ -2451,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);
 }
@@ -3045,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++)
        {
@@ -3099,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: "));
@@ -3109,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)
@@ -3147,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");
@@ -3298,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);
            }