gpg: Add experimental AKL method "wkd" and option --with-wkd-hash.
[gnupg.git] / g10 / gpg.c
index 71f44ed..2f687fc 100644 (file)
--- a/g10/gpg.c
+++ b/g10/gpg.c
@@ -1,7 +1,7 @@
 /* gpg.c - The GnuPG utility (main for gpg)
  * Copyright (C) 1998-2011 Free Software Foundation, Inc.
- * Copyright (C) 1997-2014 Werner Koch
- * Copyright (C) 2015 g10 Code GmbH
+ * Copyright (C) 1997-2016 Werner Koch
+ * Copyright (C) 2015-2016 g10 Code GmbH
  *
  * This file is part of GnuPG.
  *
@@ -141,6 +141,7 @@ enum cmd_and_opt_values
     aExport,
     aExportSecret,
     aExportSecretSub,
+    aExportSshKey,
     aCheckKeys,
     aGenRevoke,
     aDesigRevoke,
@@ -184,6 +185,7 @@ enum cmd_and_opt_values
     oWithICAOSpelling,
     oWithKeygrip,
     oWithSecret,
+    oWithWKDHash,
     oAnswerYes,
     oAnswerNo,
     oKeyring,
@@ -453,6 +455,7 @@ static ARGPARSE_OPTS opts[] = {
   ARGPARSE_c (aFetchKeys, "fetch-keys" , "@" ),
   ARGPARSE_c (aExportSecret, "export-secret-keys" , "@" ),
   ARGPARSE_c (aExportSecretSub, "export-secret-subkeys" , "@" ),
+  ARGPARSE_c (aExportSshKey, "export-ssh-key", "@" ),
   ARGPARSE_c (aImport, "import", N_("import/merge keys")),
   ARGPARSE_c (aFastImport, "fast-import", "@"),
 #ifdef ENABLE_CARD_SUPPORT
@@ -484,7 +487,7 @@ static ARGPARSE_OPTS opts[] = {
   ARGPARSE_c (aGenRandom,"gen-random", "@" ),
   ARGPARSE_c (aServer,   "server",  N_("run in server mode")),
   ARGPARSE_c (aTOFUPolicy, "tofu-policy",
-             N_("|VALUE|set the TOFU policy for a key (good, unknown, bad, ask, auto)")),
+             N_("|VALUE|set the TOFU policy for a key")),
 
   ARGPARSE_group (301, N_("@\nOptions:\n ")),
 
@@ -679,7 +682,9 @@ static ARGPARSE_OPTS opts[] = {
   ARGPARSE_s_n (oSkipHiddenRecipients, "skip-hidden-recipients", "@"),
   ARGPARSE_s_n (oNoSkipHiddenRecipients, "no-skip-hidden-recipients", "@"),
   ARGPARSE_s_i (oDefCertLevel, "default-cert-check-level", "@"), /* old */
+#ifndef NO_TRUST_MODELS
   ARGPARSE_s_n (oAlwaysTrust, "always-trust", "@"),
+#endif
   ARGPARSE_s_s (oTrustModel, "trust-model", "@"),
   ARGPARSE_s_s (oTOFUDefaultPolicy, "tofu-default-policy", "@"),
   ARGPARSE_s_s (oTOFUDBFormat, "tofu-db-format", "@"),
@@ -717,6 +722,7 @@ static ARGPARSE_OPTS opts[] = {
   ARGPARSE_s_n (oWithICAOSpelling, "with-icao-spelling", "@"),
   ARGPARSE_s_n (oWithKeygrip,     "with-keygrip", "@"),
   ARGPARSE_s_n (oWithSecret,      "with-secret", "@"),
+  ARGPARSE_s_n (oWithWKDHash,     "with-wkd-hash", "@"),
   ARGPARSE_s_s (oDisableCipherAlgo,  "disable-cipher-algo", "@"),
   ARGPARSE_s_s (oDisablePubkeyAlgo,  "disable-pubkey-algo", "@"),
   ARGPARSE_s_n (oAllowNonSelfsignedUID,      "allow-non-selfsigned-uid", "@"),
@@ -2101,506 +2107,6 @@ get_default_configname (void)
   return configname;
 }
 
-struct result
-{
-  struct result *next;
-  kbnode_t keyblock;
-  int processed;
-};
-
-/* We show a warning when a key appears multiple times in the DB.  */
-static strlist_t key_dups;
-
-static gpg_error_t
-check_user_ids (strlist_t *sp,
-                int warn_possibly_ambiguous,
-                int error_if_not_found)
-{
-  strlist_t s = *sp;
-  strlist_t s2 = NULL;
-  strlist_t t;
-
-  gpg_error_t rc = 0;
-  gpg_error_t err;
-
-  KEYDB_HANDLE hd = NULL;
-
-  char fingerprint_formatted[MAX_FORMATTED_FINGERPRINT_LEN + 1];
-
-  /* A quick check to avoid allocating a new strlist if we can skip
-     all keys.  Handles also the case of !SP.  See below for details.  */
-  for (t = s; t && (!(t->flags & PK_LIST_CONFIG)
-                    && !(t->flags & PK_LIST_ENCRYPT_TO)); t = t->next)
-    ;
-  if (!t)
-    return 0;
-
-  for (t = s; t; t = t->next)
-    {
-      const char *option_str;
-      int option;
-
-      KEYDB_SEARCH_DESC desc;
-      struct result *results = NULL;
-      struct result *r;
-
-      int count;
-
-      /* We also potentially need a ! at the end.  */
-      char fingerprint[2 * MAX_FINGERPRINT_LEN + 1 + 1];
-      char fingerprint2[2 * MAX_FINGERPRINT_LEN + 1];
-
-      KBNODE best_kb;
-      PKT_public_key *best_pk;
-
-      /* Whether the key is for encryption or signing.  */
-      int encrypt = 1;
-
-      /* If the key has been given on the command line and it has not
-         been given by one of the encrypt-to options, we skip the
-         checks.  The reason is that the actual key selection code
-         does its own checks and provides proper status message to the
-         caller to detect the wrong keys.  */
-      if (!(t->flags & PK_LIST_CONFIG) && !(t->flags & PK_LIST_ENCRYPT_TO))
-        {
-          add_to_strlist (&s2, t->d);
-          s2->flags = t->flags;
-          continue;
-        }
-
-      option = t->flags >> PK_LIST_SHIFT;
-      switch (option)
-        {
-        case oDefaultKey:
-          option_str = "--default-key";
-          encrypt = 0;
-          break;
-        case oLocalUser:
-          option_str = "--local-user";
-          encrypt = 0;
-          break;
-
-        case oEncryptTo: option_str = "--encrypt-to"; break;
-        case oHiddenEncryptTo: option_str = "--hidden-encrypt-to"; break;
-        case oEncryptToDefaultKey: option_str = "--encrypt-to-default-key"; break;
-        case oRecipient: option_str = "--recipient"; break;
-        case oHiddenRecipient: option_str = "--hidden-recipient"; break;
-        default:
-          log_bug ("Unsupport option: %d\n", (t->flags >> PK_LIST_SHIFT));
-        }
-
-      if (DBG_LOOKUP)
-        {
-          log_debug ("\n");
-          log_debug ("%s: Checking %s=%s\n", __func__, option_str, t->d);
-        }
-
-      err = classify_user_id (t->d, &desc, 1);
-      if (err)
-        {
-          if (! rc)
-            rc = err;
-
-          log_error (_("key \"%s\" not found: %s\n"),
-                       t->d, gpg_strerror (err));
-          if (!opt.quiet)
-            log_info (_("(check argument of option '%s')\n"), option_str);
-          continue;
-        }
-
-      if (warn_possibly_ambiguous
-          && ! (desc.mode == KEYDB_SEARCH_MODE_LONG_KID
-                || desc.mode == KEYDB_SEARCH_MODE_FPR16
-                || desc.mode == KEYDB_SEARCH_MODE_FPR20
-                || desc.mode == KEYDB_SEARCH_MODE_FPR))
-        log_info (_("Warning: value '%s' for option '%s'"
-                    " should be a long key ID or a fingerprint\n"),
-                  t->d, option_str);
-
-      if (! hd)
-        {
-          hd = keydb_new ();
-          if (!hd)
-            {
-              rc = gpg_error_from_syserror ();
-              break;
-            }
-        }
-      else
-        keydb_search_reset (hd);
-
-      /* Gather all of the results.  */
-      count = 0;
-      while (1)
-        {
-          KBNODE kb;
-
-          err = keydb_search (hd, &desc, 1, NULL);
-          if (gpg_err_code (err) == GPG_ERR_NOT_FOUND
-              || gpg_err_code (err) == GPG_ERR_EOF)
-            /* No more results.   */
-            break;
-          else if (err)
-            /* An error (other than "not found").  */
-            {
-              log_error (_("error searching the keyring: %s\n"),
-                         gpg_strerror (err));
-              break;
-            }
-
-          err = keydb_get_keyblock (hd, &kb);
-          if (err)
-            {
-              log_error (_("error reading keyblock: %s\n"), gpg_strerror (err));
-              break;
-            }
-
-          /* Another result!  */
-          count ++;
-
-          r = xmalloc_clear (sizeof (*r));
-          r->keyblock = kb;
-          r->next = results;
-          results = r;
-        }
-
-      if (DBG_LOOKUP)
-        {
-          log_debug ("%s resulted in %d matches.\n", t->d, count);
-          for (r = results; r; r = r->next)
-            log_debug ("  %s\n",
-                       hexfingerprint (r->keyblock->pkt->pkt.public_key,
-                                       fingerprint, sizeof (fingerprint)));
-        }
-
-      if (! results && (gpg_err_code (err) == GPG_ERR_NOT_FOUND
-                        || gpg_err_code (err) == GPG_ERR_EOF))
-        /* No match.  */
-        {
-          if (DBG_LOOKUP)
-            log_debug ("%s: '%s' not found.\n", __func__, t->d);
-
-          if (error_if_not_found)
-            {
-              if (! rc)
-                rc = err;
-
-              log_error (_("key \"%s\" not found\n"), t->d);
-              if (!opt.quiet)
-                log_info (_("(check argument of option '%s')\n"), option_str);
-            }
-          continue;
-        }
-      else if (gpg_err_code (err) == GPG_ERR_NOT_FOUND
-               || gpg_err_code (err) == GPG_ERR_EOF)
-        /* No more matches.  */
-        ;
-      else if (err)
-        /* Some other error.  An error message was already printed
-           out.  Free RESULTS and continue.  */
-        {
-          if (! rc)
-            rc = err;
-
-          while ((r = results))
-            {
-              results = results->next;
-              release_kbnode (r->keyblock);
-              xfree (r);
-            }
-
-          continue;
-        }
-
-      /* Check for duplicates.  */
-
-      if (DBG_LOOKUP)
-        log_debug ("%s: Checking results of %s='%s' for dups\n",
-                   __func__, option_str, t->d);
-      while (1)
-        {
-          struct result **prevp;
-          struct result *next;
-          struct result *r2;
-          int dups = 0;
-
-          /* After checking a result, we set R->PROCESSED.  Find the
-             next unprocessed result.  */
-          for (r = results; r; r = r->next)
-            if (! r->processed)
-              break;
-
-          if (! r)
-            /* There is nothing left to check.  */
-            break;
-
-          hexfingerprint (r->keyblock->pkt->pkt.public_key,
-                          fingerprint, sizeof fingerprint);
-          r->processed = 1;
-
-          prevp = &results;
-          next = results;
-          while ((r2 = next))
-            {
-              if (r2->processed)
-                {
-                  prevp = &r2->next;
-                  next = r2->next;
-                  continue;
-                }
-
-              hexfingerprint (r2->keyblock->pkt->pkt.public_key,
-                              fingerprint2, sizeof fingerprint2);
-
-              if (strcmp (fingerprint, fingerprint2) != 0)
-                /* Not a dup.  */
-                {
-                  prevp = &r2->next;
-                  next = r2->next;
-                  continue;
-                }
-
-              dups ++;
-
-              /* Remove R2 from the list.  */
-              *prevp = r2->next;
-              release_kbnode (r2->keyblock);
-              next = r2->next;
-              xfree (r2);
-            }
-
-          if (dups && ! strlist_find (key_dups, fingerprint))
-            {
-              log_info (_("Warning: %s appears in the keyring %d times.\n"),
-                        format_hexfingerprint (fingerprint,
-                                               fingerprint_formatted,
-                                               sizeof fingerprint_formatted),
-                        1 + dups);
-              add_to_strlist (&key_dups, fingerprint);
-            }
-        }
-
-      if (DBG_LOOKUP)
-        {
-          log_debug ("After removing dups:\n");
-          for (r = results, count = 0; r; r = r->next)
-            {
-              count ++;
-              log_debug ("  %d: %s\n",
-                         count,
-                         hexfingerprint (r->keyblock->pkt->pkt.public_key,
-                                         fingerprint, sizeof fingerprint));
-            }
-        }
-
-      /* Now we find the best key.  */
-      assert (results);
-      /* Prune invalid keys.  */
-      {
-        int ambiguous = 0;
-
-        if (DBG_LOOKUP)
-          log_debug ("Pruning bad keys.\n");
-
-        best_pk = NULL;
-        for (r = results; r; r = r->next)
-          {
-            KBNODE kb = r->keyblock;
-            PKT_public_key *pk = kb->pkt->pkt.public_key;
-            KBNODE n;
-
-            /* Merge in the data from the self sigs so that things
-               like the revoked status are available.  */
-            merge_keys_and_selfsig (kb);
-
-            if (/* Using disabled keys with --encrypt-to is allowed.  */
-                ! (option == oEncryptTo || option == oHiddenEncryptTo)
-                && pk_is_disabled (pk))
-              {
-                if (DBG_LOOKUP)
-                  log_debug ("  Skipping disabled key: %s\n",
-                             hexfingerprint (pk, fingerprint,
-                                             sizeof fingerprint));
-                continue;
-              }
-            if (pk->flags.revoked)
-              {
-                if (DBG_LOOKUP)
-                  log_debug ("  Skipping revoked key: %s\n",
-                             hexfingerprint (pk, fingerprint,
-                                             sizeof fingerprint));
-                continue;
-              }
-            if (pk->has_expired)
-              {
-                if (DBG_LOOKUP)
-                  log_debug ("  Skipping expired key: %s\n",
-                             hexfingerprint (pk, fingerprint,
-                                             sizeof fingerprint));
-                continue;
-              }
-
-            /* Check for the required encryption or signing
-               capability.  */
-            n = kb;
-            do
-              {
-                PKT_public_key *key = n->pkt->pkt.public_key;
-
-                if ((/* Using disabled keys with --encrypt-to is allowed.  */
-                     pk_is_disabled (key)
-                     && ! (option == oEncryptTo
-                           || option == oHiddenEncryptTo))
-                    || key->flags.revoked
-                    || key->has_expired)
-                  /* Invalid.  */
-                  continue;
-
-                if (encrypt && ! (key->pubkey_usage & PUBKEY_USAGE_ENC))
-                  continue;
-                if (! encrypt && ! (key->pubkey_usage & PUBKEY_USAGE_SIG))
-                  continue;
-
-                /* Key passes basic tests.  */
-                break;
-              }
-            while ((n = find_next_kbnode (n, PKT_PUBLIC_SUBKEY)));
-
-            if (! n)
-              {
-                if (DBG_LOOKUP)
-                  log_debug ("  Skipping %s, which does not have %s capability.\n",
-                             hexfingerprint (r->keyblock->pkt->pkt.public_key,
-                                             fingerprint, sizeof fingerprint),
-                             encrypt ? "encrypt" : "sign");
-                continue;
-              }
-            else if (DBG_LOOKUP)
-              log_debug ("  %s is valid and has %s capability.\n",
-                         hexfingerprint (r->keyblock->pkt->pkt.public_key,
-                                         fingerprint, sizeof fingerprint),
-                         encrypt ? "encrypt" : "sign");
-
-
-            if (! best_pk)
-              {
-                best_pk = pk;
-                best_kb = kb;
-                continue;
-              }
-
-            /* We have multiple candidates.  Prefer the newer key.
-
-               XXX: we should also consider key capabilities (if we
-               are encrypting to the key, does it have an encryption
-               capability?).
-
-               XXX: if we are signing, then we should consider the
-               key that is actually available (e.g., if one is on a
-               smart card).  */
-            ambiguous = 1;
-            if (best_pk->timestamp < pk->timestamp)
-              best_pk = pk;
-          }
-
-        if (! results)
-          {
-            if (encrypt)
-              log_error (_("%s: no matching keys are valid encryption keys"),
-                         t->d);
-            else
-              log_error (_("%s: no matching keys are valid signing keys"),
-                         t->d);
-            if (!opt.quiet)
-              log_info (_("(check argument of option '%s')\n"), option_str);
-            continue;
-          }
-
-        if (ambiguous)
-          {
-            /* TRANSLATORS: The %s prints a key specification which
-               for example has been given at the command line.
-               Lines with fingerprints are printed after this
-               message.  */
-            log_error (_("key specification '%s' is ambiguous\n"),
-                       t->d);
-            if (!opt.quiet)
-              log_info (_("(check argument of option '%s')\n"),
-                        option_str);
-
-            log_info (_("'%s' matches at least:\n"), t->d);
-
-            for (r = results; r; r = r->next)
-              log_info ("  %s\n",
-                        format_hexfingerprint
-                        (hexfingerprint (r->keyblock->pkt->pkt.public_key,
-                                         fingerprint, sizeof fingerprint),
-                         fingerprint_formatted,
-                         sizeof fingerprint_formatted));
-
-            if (! rc)
-              rc = GPG_ERR_AMBIGUOUS_NAME;
-          }
-      }
-
-      if ((desc.mode == KEYDB_SEARCH_MODE_SHORT_KID
-           || desc.mode == KEYDB_SEARCH_MODE_LONG_KID
-           || desc.mode == KEYDB_SEARCH_MODE_FPR16
-           || desc.mode == KEYDB_SEARCH_MODE_FPR20)
-          && strchr (t->d, '!'))
-        /* Exact search.  In this case we want to set FINGERPRINT not
-           to the primary key, but the key (primary or sub) that
-           matched the search criteria.  Note: there will always be
-           exactly one match.  */
-        {
-          kbnode_t n = best_kb;
-          PKT_public_key *match = NULL;
-          int i;
-
-          do
-            {
-              if ((n->flag & 1))
-                /* The matched node.  */
-                {
-                  assert (! match);
-                  match = n->pkt->pkt.public_key;
-                }
-            }
-          while ((n = find_next_kbnode (n, PKT_PUBLIC_SUBKEY)));
-          assert (match);
-
-          hexfingerprint (match, fingerprint, sizeof fingerprint);
-          i = strlen (fingerprint);
-          fingerprint[i] = '!';
-          fingerprint[i + 1] = '\0';
-        }
-      else
-        hexfingerprint (best_pk, fingerprint, sizeof fingerprint);
-
-      add_to_strlist (&s2, fingerprint);
-      s2->flags = s->flags;
-
-      {
-        struct result *next = results;
-        while ((r = next))
-          {
-            next = r->next;
-            release_kbnode (r->keyblock);
-            xfree (r);
-          }
-      }
-    }
-
-  strlist_rev (&s2);
-
-  keydb_release (hd);
-
-  free_strlist (s);
-  *sp = s2;
-  return rc;
-}
-
-
 int
 main (int argc, char **argv)
 {
@@ -2724,7 +2230,8 @@ main (int argc, char **argv)
                           | VERIFY_SHOW_POLICY_URLS
                           | VERIFY_SHOW_STD_NOTATIONS
                           | VERIFY_SHOW_KEYSERVER_URLS);
-    opt.list_options   = LIST_SHOW_UID_VALIDITY;
+    opt.list_options   = (LIST_SHOW_UID_VALIDITY
+                          | LIST_SHOW_USAGE);
 #ifdef NO_TRUST_MODELS
     opt.trust_model = TM_ALWAYS;
 #else
@@ -2900,6 +2407,7 @@ main (int argc, char **argv)
          case aListSigs:
          case aExportSecret:
          case aExportSecretSub:
+         case aExportSshKey:
          case aSym:
          case aClearsign:
          case aGenRevoke:
@@ -3069,6 +2577,10 @@ main (int argc, char **argv)
             opt.with_secret = 1;
             break;
 
+         case oWithWKDHash:
+            opt.with_wkd_hash = 1;
+            break;
+
          case oSecretKeyring:
             /* Ignore this old option.  */
             break;
@@ -4280,18 +3792,6 @@ main (int argc, char **argv)
         break;
       }
 
-    {
-      rc = check_user_ids (&locusr, 1, 1);
-      if (rc)
-        g10_exit (1);
-      rc = check_user_ids (&remusr, 0, 1);
-      if (rc)
-        g10_exit (1);
-      rc = check_user_ids (&opt.def_secret_key, 1, 0);
-      if (rc)
-        g10_exit (1);
-    }
-
     /* The command dispatcher.  */
     switch( cmd )
       {
@@ -4453,7 +3953,6 @@ main (int argc, char **argv)
        break;
 
       case aVerify:
-        rc = 0;
        if (multifile)
          {
            if ((rc = verify_files (ctrl, argc, argv)))
@@ -4697,6 +4196,17 @@ main (int argc, char **argv)
        free_strlist(sl);
        break;
 
+      case aExportSshKey:
+        if (argc != 1)
+          wrong_args ("--export-ssh-key <user-id>");
+        rc = export_ssh_key (ctrl, argv[0]);
+        if (rc)
+          {
+            write_status_failure ("export-ssh-key", rc);
+            log_error (_("export as ssh key failed: %s\n"), gpg_strerror (rc));
+          }
+       break;
+
      case aSearchKeys:
        sl = NULL;
        for (; argc; argc--, argv++)