gpg: Clear the symmetric passphrase cache for encrypted session keys.
[gnupg.git] / g10 / revoke.c
index 019c62c..8465232 100644 (file)
@@ -1,4 +1,4 @@
-/* revoke.c
+/* revoke.c - Create recovation certificates.
  * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003,
  *               2004 Free Software Foundation, Inc.
  *
@@ -15,7 +15,7 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
  */
 
 #include <config.h>
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
-#include <assert.h>
 #include <ctype.h>
 
 #include "gpg.h"
 #include "options.h"
 #include "packet.h"
-#include "status.h"
+#include "../common/status.h"
 #include "keydb.h"
-#include "util.h"
+#include "../common/util.h"
 #include "main.h"
-#include "ttyio.h"
-#include "status.h"
-#include "i18n.h"
+#include "../common/ttyio.h"
+#include "../common/i18n.h"
 #include "call-agent.h"
 
 struct revocation_reason_info {
@@ -90,7 +88,7 @@ export_minimal_pk(IOBUF out,KBNODE keyblock,
   if(!node)
     {
       log_error("key incomplete\n");
-      return G10ERR_GENERAL;
+      return GPG_ERR_GENERAL;
     }
 
   keyid_from_pk(node->pkt->pkt.public_key,keyid);
@@ -99,7 +97,7 @@ export_minimal_pk(IOBUF out,KBNODE keyblock,
   rc=build_packet(out,&pkt);
   if(rc)
     {
-      log_error(_("build_packet failed: %s\n"), g10_errstr(rc) );
+      log_error(_("build_packet failed: %s\n"), gpg_strerror (rc) );
       return rc;
     }
 
@@ -113,7 +111,7 @@ export_minimal_pk(IOBUF out,KBNODE keyblock,
       rc=build_packet(out,&pkt);
       if(rc)
        {
-         log_error(_("build_packet failed: %s\n"), g10_errstr(rc) );
+         log_error("build_packet failed: %s\n", gpg_strerror (rc) );
          return rc;
        }
     }
@@ -125,7 +123,7 @@ export_minimal_pk(IOBUF out,KBNODE keyblock,
       rc=build_packet(out,&pkt);
       if(rc)
        {
-         log_error(_("build_packet failed: %s\n"), g10_errstr(rc) );
+         log_error(_("build_packet failed: %s\n"), gpg_strerror (rc) );
          return rc;
        }
     }
@@ -143,7 +141,7 @@ export_minimal_pk(IOBUF out,KBNODE keyblock,
          else
            {
              log_error(_("key %s has no user IDs\n"),keystr(keyid));
-             return G10ERR_GENERAL;
+             return GPG_ERR_GENERAL;
            }
        }
 
@@ -171,7 +169,7 @@ export_minimal_pk(IOBUF out,KBNODE keyblock,
   rc=build_packet(out,&pkt);
   if(rc)
     {
-      log_error(_("build_packet failed: %s\n"), g10_errstr(rc) );
+      log_error(_("build_packet failed: %s\n"), gpg_strerror (rc) );
       return rc;
     }
 
@@ -183,7 +181,7 @@ export_minimal_pk(IOBUF out,KBNODE keyblock,
       rc=build_packet(out,&pkt);
       if(rc)
        {
-         log_error(_("build_packet failed: %s\n"), g10_errstr(rc) );
+         log_error(_("build_packet failed: %s\n"), gpg_strerror (rc) );
          return rc;
        }
     }
@@ -195,7 +193,7 @@ export_minimal_pk(IOBUF out,KBNODE keyblock,
  * Generate a revocation certificate for UNAME via a designated revoker
  */
 int
-gen_desig_revoke( const char *uname, strlist_t locusr )
+gen_desig_revoke (ctrl_t ctrl, const char *uname, strlist_t locusr)
 {
     int rc = 0;
     armor_filter_context_t *afx;
@@ -214,28 +212,33 @@ gen_desig_revoke( const char *uname, strlist_t locusr )
     if( opt.batch )
       {
        log_error(_("can't do this in batch mode\n"));
-       return G10ERR_GENERAL;
+       return GPG_ERR_GENERAL;
       }
 
     afx = new_armor_context ();
 
     kdbhd = keydb_new ();
+    if (!kdbhd)
+      {
+        rc = gpg_error_from_syserror ();
+        goto leave;
+      }
     rc = classify_user_id (uname, &desc, 1);
     if (!rc)
       rc = keydb_search (kdbhd, &desc, 1, NULL);
     if (rc) {
-       log_error (_("key \"%s\" not found: %s\n"),uname, g10_errstr (rc));
+       log_error (_("key \"%s\" not found: %s\n"),uname, gpg_strerror (rc));
        goto leave;
     }
 
     rc = keydb_get_keyblock (kdbhd, &keyblock );
     if( rc ) {
-       log_error (_("error reading keyblock: %s\n"), g10_errstr(rc) );
+       log_error (_("error reading keyblock: %s\n"), gpg_strerror (rc) );
        goto leave;
     }
 
     /* To parse the revkeys */
-    merge_keys_and_selfsig(keyblock);
+    merge_keys_and_selfsig (ctrl, keyblock);
 
     /* get the key from the keyblock */
     node = find_kbnode( keyblock, PKT_PUBLIC_KEY );
@@ -248,7 +251,7 @@ gen_desig_revoke( const char *uname, strlist_t locusr )
 
     if(locusr)
       {
-       rc=build_sk_list(locusr, &sk_list, PUBKEY_USAGE_CERT);
+       rc = build_sk_list (ctrl, locusr, &sk_list, PUBKEY_USAGE_CERT);
        if(rc)
          goto leave;
       }
@@ -291,7 +294,7 @@ gen_desig_revoke( const char *uname, strlist_t locusr )
        else
          {
            pk2 = xmalloc_clear (sizeof *pk2);
-           rc = get_pubkey_byfprint (pk2,
+           rc = get_pubkey_byfprint (ctrl, pk2, NULL,
                                       pk->revkey[i].fpr, MAX_FINGERPRINT_LEN);
          }
 
@@ -302,16 +305,23 @@ gen_desig_revoke( const char *uname, strlist_t locusr )
 
            any = 1;
 
-            print_pubkey_info (NULL, pk);
+            print_pubkey_info (ctrl, NULL, pk);
            tty_printf ("\n");
 
            tty_printf (_("To be revoked by:\n"));
-            print_seckey_info (pk2);
+            print_seckey_info (ctrl, pk2);
 
            if(pk->revkey[i].class&0x40)
              tty_printf(_("(This is a sensitive revocation key)\n"));
            tty_printf("\n");
 
+           rc = agent_probe_secret_key (ctrl, pk2);
+           if (rc)
+             {
+               tty_printf (_("Secret key is not available.\n"));
+               continue;
+             }
+
            if( !cpr_get_answer_is_yes("gen_desig_revoke.okay",
          _("Create a designated revocation certificate for this key? (y/N) ")))
              continue;
@@ -321,10 +331,6 @@ gen_desig_revoke( const char *uname, strlist_t locusr )
            if( !reason )
              continue;
 
-           rc = -1;/*FIXME: check_secret_key (pk2, 0 );*/
-           if (rc)
-             continue;
-
            if( !opt.armor )
              tty_printf(_("ASCII armored output forced.\n"));
 
@@ -337,12 +343,12 @@ gen_desig_revoke( const char *uname, strlist_t locusr )
            push_armor_filter (afx, out);
 
            /* create it */
-           rc = make_keysig_packet( &sig, pk, NULL, NULL, pk2, 0x20, 0,
-                                    0, 0, 0,
+           rc = make_keysig_packet (ctrl, &sig, pk, NULL, NULL, pk2, 0x20, 0,
+                                    0, 0,
                                     revocation_reason_build_cb, reason,
                                      NULL);
            if( rc ) {
-             log_error(_("make_keysig_packet failed: %s\n"), g10_errstr(rc));
+             log_error(_("make_keysig_packet failed: %s\n"), gpg_strerror (rc));
              goto leave;
            }
 
@@ -383,11 +389,11 @@ gen_desig_revoke( const char *uname, strlist_t locusr )
                    for(j=0;j<signode->pkt->pkt.signature->numrevkeys;j++)
                      {
                        if(pk->revkey[i].class==
-                          signode->pkt->pkt.signature->revkey[j]->class &&
+                          signode->pkt->pkt.signature->revkey[j].class &&
                           pk->revkey[i].algid==
-                          signode->pkt->pkt.signature->revkey[j]->algid &&
+                          signode->pkt->pkt.signature->revkey[j].algid &&
                           memcmp(pk->revkey[i].fpr,
-                                 signode->pkt->pkt.signature->revkey[j]->fpr,
+                                 signode->pkt->pkt.signature->revkey[j].fpr,
                                  MAX_FINGERPRINT_LEN)==0)
                          {
                            revkey=signode->pkt->pkt.signature;
@@ -435,11 +441,12 @@ gen_desig_revoke( const char *uname, strlist_t locusr )
    to stdout or the filename given by --output.  REASON describes the
    revocation reason.  PSK is the public primary key - we expect that
    a corresponding secret key is available.  KEYBLOCK is the entire
-   KEYBLOCK which is used in PGP mode to write a minimal key and not
+   KEYBLOCK which is used in PGP mode to write a minimal key and not
    just the naked revocation signature; it may be NULL.  If LEADINTEXT
    is not NULL, it is written right before the (armored) output.*/
 static int
-create_revocation (const char *filename,
+create_revocation (ctrl_t ctrl,
+                   const char *filename,
                    struct revocation_reason_info *reason,
                    PKT_public_key *psk,
                    kbnode_t keyblock,
@@ -464,13 +471,12 @@ create_revocation (const char *filename,
   afx->hdrlines = "Comment: This is a revocation certificate\n";
   push_armor_filter (afx, out);
 
-  rc = make_keysig_packet (&sig, psk, NULL, NULL, psk, 0x20, 0,
-                           opt.force_v4_certs? 4:0,
+  rc = make_keysig_packet (ctrl, &sig, psk, NULL, NULL, psk, 0x20, 0,
                            0, 0,
                            revocation_reason_build_cb, reason, cache_nonce);
   if (rc)
     {
-      log_error (_("make_keysig_packet failed: %s\n"), g10_errstr (rc));
+      log_error (_("make_keysig_packet failed: %s\n"), gpg_strerror (rc));
       goto leave;
     }
 
@@ -491,7 +497,7 @@ create_revocation (const char *filename,
       rc = build_packet (out, &pkt);
       if (rc)
         {
-          log_error (_("build_packet failed: %s\n"), g10_errstr (rc));
+          log_error (_("build_packet failed: %s\n"), gpg_strerror (rc));
           goto leave;
         }
     }
@@ -515,7 +521,7 @@ create_revocation (const char *filename,
    key must be available.  CACHE_NONCE is optional but can be used to
    help gpg-agent to avoid an extra passphrase prompt. */
 int
-gen_standard_revoke (PKT_public_key *psk, const char *cache_nonce)
+gen_standard_revoke (ctrl_t ctrl, PKT_public_key *psk, const char *cache_nonce)
 {
   int rc;
   estream_t memfp;
@@ -524,12 +530,26 @@ gen_standard_revoke (PKT_public_key *psk, const char *cache_nonce)
   void *leadin;
   size_t len;
   u32 keyid[2];
-  char pkstrbuf[PUBKEY_STRING_SIZE];
+  int kl;
   char *orig_codeset;
+  char *old_outfile;
 
-  dir = get_openpgp_revocdir (opt.homedir);
-  tmpstr = hexfingerprint (psk);
-  fname = xstrconcat (dir, DIRSEP_S, tmpstr, NULL);
+  dir = get_openpgp_revocdir (gnupg_homedir ());
+  tmpstr = hexfingerprint (psk, NULL, 0);
+  if (!tmpstr)
+    {
+      rc = gpg_error_from_syserror ();
+      xfree (dir);
+      return rc;
+    }
+  fname = strconcat (dir, DIRSEP_S, tmpstr, NULL);
+  if (!fname)
+    {
+      rc = gpg_error_from_syserror ();
+      xfree (tmpstr);
+      xfree (dir);
+      return rc;
+    }
   xfree (tmpstr);
   xfree (dir);
 
@@ -544,27 +564,32 @@ gen_standard_revoke (PKT_public_key *psk, const char *cache_nonce)
   es_fprintf (memfp, "%s\n\n",
               _("This is a revocation certificate for the OpenPGP key:"));
 
-  es_fprintf (memfp, "pub  %s/%s %s\n",
-              pubkey_string (psk, pkstrbuf, sizeof pkstrbuf),
-              keystr (keyid),
-              datestr_from_pk (psk));
+  print_key_line (ctrl, memfp, psk, 0);
+
+  if (opt.keyid_format != KF_NONE)
+    print_fingerprint (ctrl, memfp, psk, 3);
 
-  print_fingerprint (memfp, psk, 3);
+  kl = opt.keyid_format == KF_NONE? 0 : keystrlen ();
 
-  tmpstr = get_user_id (keyid, &len);
+  tmpstr = get_user_id (ctrl, keyid, &len);
   es_fprintf (memfp, "uid%*s%.*s\n\n",
-              (int)keystrlen () + 10, "",
+              kl + 10, "",
               (int)len, tmpstr);
   xfree (tmpstr);
 
-  es_fprintf (memfp, "%s\n\n%s\n\n:",
+  es_fprintf (memfp, "%s\n\n%s\n\n%s\n\n:",
+     _("A revocation certificate is a kind of \"kill switch\" to publicly\n"
+       "declare that a key shall not anymore be used.  It is not possible\n"
+       "to retract such a revocation certificate once it has been published."),
      _("Use it to revoke this key in case of a compromise or loss of\n"
        "the secret key.  However, if the secret key is still accessible,\n"
        "it is better to generate a new revocation certificate and give\n"
-       "a reason for the revocation."),
+       "a reason for the revocation.  For details see the description of\n"
+       "of the gpg command \"--generate-revocation\" in the "
+       "GnuPG manual."),
      _("To avoid an accidental use of this file, a colon has been inserted\n"
        "before the 5 dashes below.  Remove this colon with a text editor\n"
-       "before making use of this revocation certificate."));
+       "before importing and publishing this revocation certificate."));
 
   es_putc (0, memfp);
 
@@ -575,7 +600,14 @@ gen_standard_revoke (PKT_public_key *psk, const char *cache_nonce)
 
   reason.code = 0x00; /* No particular reason.  */
   reason.desc = NULL;
-  rc = create_revocation (fname, &reason, psk, NULL, leadin, 3, cache_nonce);
+  old_outfile = opt.outfile;
+  opt.outfile = NULL;
+  rc = create_revocation (ctrl,
+                          fname, &reason, psk, NULL, leadin, 3, cache_nonce);
+  opt.outfile = old_outfile;
+  if (!rc && !opt.quiet)
+    log_info (_("revocation certificate stored as '%s.rev'\n"), fname);
+
   xfree (leadin);
   xfree (fname);
 
@@ -588,7 +620,7 @@ gen_standard_revoke (PKT_public_key *psk, const char *cache_nonce)
  * Generate a revocation certificate for UNAME
  */
 int
-gen_revoke (const char *uname)
+gen_revoke (ctrl_t ctrl, const char *uname)
 {
   int rc = 0;
   PKT_public_key *psk;
@@ -602,25 +634,77 @@ gen_revoke (const char *uname)
   if( opt.batch )
     {
       log_error(_("can't do this in batch mode\n"));
-      return G10ERR_GENERAL;
+      return GPG_ERR_GENERAL;
     }
 
   /* Search the userid; we don't want the whole getkey stuff here.  */
   kdbhd = keydb_new ();
+  if (!kdbhd)
+    {
+      rc = gpg_error_from_syserror ();
+      goto leave;
+    }
   rc = classify_user_id (uname, &desc, 1);
   if (!rc)
     rc = keydb_search (kdbhd, &desc, 1, NULL);
   if (rc)
     {
-      log_error (_("secret key \"%s\" not found: %s\n"),
-                 uname, g10_errstr (rc));
+      if (gpg_err_code (rc) == GPG_ERR_NOT_FOUND)
+        log_error (_("secret key \"%s\" not found\n"), uname);
+      else
+        log_error (_("secret key \"%s\" not found: %s\n"),
+                   uname, gpg_strerror (rc));
       goto leave;
     }
 
   rc = keydb_get_keyblock (kdbhd, &keyblock );
   if (rc)
     {
-      log_error (_("error reading keyblock: %s\n"), g10_errstr(rc) );
+      log_error (_("error reading keyblock: %s\n"), gpg_strerror (rc) );
+      goto leave;
+    }
+
+  rc = keydb_search (kdbhd, &desc, 1, NULL);
+  if (gpg_err_code (rc) == GPG_ERR_NOT_FOUND)
+    /* Not ambiguous.  */
+    {
+    }
+  else if (rc == 0)
+    /* Ambiguous.  */
+    {
+      char *info;
+
+      /* TRANSLATORS: The %s prints a key specification which
+         for example has been given at the command line.  Several lines
+         lines with secret key infos are printed after this message.  */
+      log_error (_("'%s' matches multiple secret keys:\n"), uname);
+
+      info = format_seckey_info (ctrl, keyblock->pkt->pkt.public_key);
+      log_error ("  %s\n", info);
+      xfree (info);
+      release_kbnode (keyblock);
+
+      rc = keydb_get_keyblock (kdbhd, &keyblock);
+      while (! rc)
+        {
+          info = format_seckey_info (ctrl, keyblock->pkt->pkt.public_key);
+          log_info ("  %s\n", info);
+          xfree (info);
+          release_kbnode (keyblock);
+          keyblock = NULL;
+
+          rc = keydb_search (kdbhd, &desc, 1, NULL);
+          if (! rc)
+            rc = keydb_get_keyblock (kdbhd, &keyblock);
+        }
+
+      rc = GPG_ERR_AMBIGUOUS_NAME;
+
+      goto leave;
+    }
+  else
+    {
+      log_error (_("error searching the keyring: %s\n"), gpg_strerror (rc));
       goto leave;
     }
 
@@ -639,7 +723,7 @@ gen_revoke (const char *uname)
     }
 
   keyid_from_pk (psk, keyid );
-  print_seckey_info (psk);
+  print_seckey_info (ctrl, psk);
 
   tty_printf("\n");
   if (!cpr_get_answer_is_yes ("gen_revoke.okay",
@@ -649,22 +733,19 @@ gen_revoke (const char *uname)
       goto leave;
     }
 
-  if (psk->version >= 4 || opt.force_v4_certs)
+  /* Get the reason for the revocation.  */
+  reason = ask_revocation_reason (1, 0, 1);
+  if (!reason)
     {
-      /* Get the reason for the revocation.  */
-      reason = ask_revocation_reason (1, 0, 1);
-      if (!reason)
-        {
-          /* user decided to cancel */
-          rc = 0;
-          goto leave;
-        }
+      /* User decided to cancel.  */
+      rc = 0;
+      goto leave;
     }
 
   if (!opt.armor)
     tty_printf (_("ASCII armored output forced.\n"));
 
-  rc = create_revocation (NULL, reason, psk, keyblock, NULL, 0, NULL);
+  rc = create_revocation (ctrl, NULL, reason, psk, keyblock, NULL, 0, NULL);
   if (rc)
     goto leave;
 
@@ -800,6 +881,16 @@ ask_revocation_reason( int key_rev, int cert_rev, int hint )
     return reason;
 }
 
+struct revocation_reason_info *
+get_default_uid_revocation_reason(void)
+{
+  struct revocation_reason_info *reason;
+  reason = xmalloc( sizeof *reason );
+  reason->code = 0x20; /* uid is no longer valid */
+  reason->desc = strdup(""); /* no text */
+  return reason;
+}
+
 void
 release_revocation_reason_info( struct revocation_reason_info *reason )
 {