gpg: Add experimental AKL method "wkd" and option --with-wkd-hash.
[gnupg.git] / g10 / gpg.c
index 93090eb..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", "@"),
@@ -1968,26 +1974,37 @@ parse_trust_model(const char *model)
 }
 #endif /*NO_TRUST_MODELS*/
 
+
 static int
-parse_tofu_policy (const char *policy)
+parse_tofu_policy (const char *policystr)
 {
 #ifdef USE_TOFU
-  if (ascii_strcasecmp (policy, "auto") == 0)
-    return TOFU_POLICY_AUTO;
-  else if (ascii_strcasecmp (policy, "good") == 0)
-    return TOFU_POLICY_GOOD;
-  else if (ascii_strcasecmp (policy, "unknown") == 0)
-    return TOFU_POLICY_UNKNOWN;
-  else if (ascii_strcasecmp (policy, "bad") == 0)
-    return TOFU_POLICY_BAD;
-  else if (ascii_strcasecmp (policy, "ask") == 0)
-    return TOFU_POLICY_ASK;
-  else
-#endif /*USE_TOFU*/
+  struct { const char *keyword; int policy; } list[] = {
+    { "auto",    TOFU_POLICY_AUTO },
+    { "good",    TOFU_POLICY_GOOD },
+    { "unknown", TOFU_POLICY_UNKNOWN },
+    { "bad",     TOFU_POLICY_BAD },
+    { "ask",     TOFU_POLICY_ASK }
+  };
+  int i;
+
+  if (!ascii_strcasecmp (policystr, "help"))
     {
-      log_error (_("unknown TOFU policy '%s'\n"), policy);
+      log_info (_("available TOFU policies:\n"));
+      for (i=0; i < DIM (list); i++)
+        log_info ("  %s\n", list[i].keyword);
       g10_exit (1);
     }
+
+  for (i=0; i < DIM (list); i++)
+    if (!ascii_strcasecmp (policystr, list[i].keyword))
+      return list[i].policy;
+#endif /*USE_TOFU*/
+
+  log_error (_("unknown TOFU policy '%s'\n"), policystr);
+  if (!opt.quiet)
+    log_info (_("(use \"help\" to list choices)\n"));
+  g10_exit (1);
 }
 
 static int
@@ -2000,10 +2017,17 @@ parse_tofu_db_format (const char *db_format)
     return TOFU_DB_SPLIT;
   else if (ascii_strcasecmp (db_format, "flat") == 0)
     return TOFU_DB_FLAT;
+  else if (ascii_strcasecmp (db_format, "help") == 0)
+    {
+      log_info ("available TOFU DB fomats: auto, split, flat\n");
+      g10_exit (1);
+    }
   else
 #endif /*USE_TOFU*/
     {
       log_error (_("unknown TOFU DB format '%s'\n"), db_format);
+      if (!opt.quiet)
+        log_info (_("(use \"help\" to list choices)\n"));
       g10_exit (1);
     }
 }
@@ -2083,232 +2107,6 @@ get_default_configname (void)
   return configname;
 }
 
-
-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;
-
-  if (! s)
-    return 0;
-
-  for (t = s; t; t = t->next)
-    {
-      const char *option;
-
-      KEYDB_SEARCH_DESC desc;
-      KBNODE kb;
-      PKT_public_key *pk;
-      char fingerprint_bin[MAX_FINGERPRINT_LEN];
-      size_t fingerprint_bin_len = sizeof (fingerprint_bin);
-      /* We also potentially need a ! at the end.  */
-      char fingerprint[2 * MAX_FINGERPRINT_LEN + 1 + 1];
-
-
-      switch (t->flags >> 2)
-        {
-        case oDefaultKey: option = "--default-key"; break;
-        case oEncryptTo: option = "--encrypt-to"; break;
-        case oHiddenEncryptTo: option = "--hidden-encrypt-to"; break;
-        case oEncryptToDefaultKey: option = "--encrypt-to-default-key"; break;
-        case oRecipient: option = "--recipient"; break;
-        case oHiddenRecipient: option = "--hidden-recipient"; break;
-        case oLocalUser: option = "--local-user"; break;
-        default: log_bug ("Unsupport option: %d\n", t->flags >> 2);
-        }
-
-      if (DBG_LOOKUP)
-        {
-          log_debug ("\n");
-          log_debug ("%s: Checking %s=%s\n", __func__, option, 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);
-          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);
-
-      if (! hd)
-        {
-          hd = keydb_new ();
-          if (!hd)
-            {
-              rc = gpg_error_from_syserror ();
-              break;
-            }
-        }
-      else
-        keydb_search_reset (hd);
-
-      err = keydb_search (hd, &desc, 1, NULL);
-      if (gpg_err_code (err) == GPG_ERR_NOT_FOUND)
-        {
-          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);
-            }
-          continue;
-        }
-      if (err)
-        {
-          if (! rc)
-            rc = err;
-
-          log_error (_("key \"%s\" not found: %s\n"), t->d, gpg_strerror (err));
-          break;
-        }
-
-      err = keydb_get_keyblock (hd, &kb);
-      if (err)
-        {
-          if (! rc)
-            rc = err;
-
-          log_error (_("error reading keyblock: %s\n"), gpg_strerror (err));
-          continue;
-        }
-
-      pk = kb->pkt->pkt.public_key;
-      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 = 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);
-
-          fingerprint_from_pk (match, fingerprint_bin, &fingerprint_bin_len);
-          assert (fingerprint_bin_len == sizeof (fingerprint_bin));
-          bin2hex (fingerprint_bin, MAX_FINGERPRINT_LEN, fingerprint);
-
-          i = strlen (fingerprint);
-          fingerprint[i] = '!';
-          fingerprint[i + 1] = '\0';
-        }
-      else
-        {
-          fingerprint_from_pk (pk, fingerprint_bin, &fingerprint_bin_len);
-          assert (fingerprint_bin_len == sizeof (fingerprint_bin));
-          bin2hex (fingerprint_bin, MAX_FINGERPRINT_LEN, fingerprint);
-        }
-
-      add_to_strlist (&s2, fingerprint);
-      s2->flags = s->flags;
-
-      release_kbnode (kb);
-
-      /* Continue the search.  */
-      if (DBG_LOOKUP)
-        log_debug ("%s: Check for duplicates for %s='%s'\n",
-                   __func__, option, t->d);
-      err = keydb_search (hd, &desc, 1, NULL);
-      if (! err)
-        /* Another result!  */
-        {
-          char fingerprint_bin2[MAX_FINGERPRINT_LEN];
-          size_t fingerprint_bin2_len = sizeof (fingerprint_bin2);
-          char fingerprint2[2 * MAX_FINGERPRINT_LEN + 1];
-
-          log_error (_("key specification '%s' is ambiguous\n"), t->d);
-          if (!opt.quiet)
-            log_info (_("(check argument of option '%s')\n"), option);
-
-          if (! rc)
-            rc = GPG_ERR_AMBIGUOUS_NAME;
-
-          err = keydb_get_keyblock (hd, &kb);
-          if (err)
-            log_error (_("error reading keyblock: %s\n"), gpg_strerror (err));
-          else
-            {
-              pk = kb->pkt->pkt.public_key;
-              fingerprint_from_pk (pk, fingerprint_bin2, &fingerprint_bin2_len);
-              assert (fingerprint_bin2_len == sizeof (fingerprint_bin2));
-              bin2hex (fingerprint_bin2, MAX_FINGERPRINT_LEN, fingerprint2);
-
-              /* TRANSLATORS: The %s prints a key specification which
-                 for example has been given at the command line.  Two
-                 lines with fingerprints are printed after this message.  */
-              log_info (_("'%s' matches at least:\n"), t->d);
-              log_info ("  %s\n", fingerprint);
-              log_info ("  %s\n", fingerprint2);
-
-              release_kbnode (kb);
-            }
-        }
-      else if (! (gpg_err_code (err) == GPG_ERR_NOT_FOUND
-                  || gpg_err_code (err) == GPG_ERR_EOF))
-        /* An error (other than "not found").  */
-        {
-          log_error (_("error searching the keyring: %s\n"),
-                     gpg_strerror (err));
-          if (! rc)
-            rc = err;
-        }
-    }
-
-  strlist_rev (&s2);
-
-  keydb_release (hd);
-
-  free_strlist (s);
-  *sp = s2;
-  return rc;
-}
-
-
 int
 main (int argc, char **argv)
 {
@@ -2320,7 +2118,9 @@ main (int argc, char **argv)
     const char *fname;
     char *username;
     int may_coredump;
-    strlist_t sl, remusr= NULL, locusr=NULL;
+    strlist_t sl;
+    strlist_t remusr = NULL;
+    strlist_t locusr = NULL;
     strlist_t nrings = NULL;
     armor_filter_context_t *afx = NULL;
     int detached_sig = 0;
@@ -2430,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
@@ -2606,6 +2407,7 @@ main (int argc, char **argv)
          case aListSigs:
          case aExportSecret:
          case aExportSecretSub:
+         case aExportSshKey:
          case aSym:
          case aClearsign:
          case aGenRevoke:
@@ -2775,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;
@@ -2810,7 +2616,9 @@ main (int argc, char **argv)
 #endif /*!NO_TRUST_MODELS*/
          case oDefaultKey:
             sl = add_to_strlist (&opt.def_secret_key, pargs.r.ret_str);
-            sl->flags = (pargs.r_opt << 2);
+            sl->flags = (pargs.r_opt << PK_LIST_SHIFT);
+            if (configfp)
+              sl->flags |= PK_LIST_CONFIG;
             break;
          case oDefRecipient:
             if( *pargs.r.ret_str )
@@ -3002,23 +2810,32 @@ main (int argc, char **argv)
          case oNoEncryptTo: opt.no_encrypt_to = 1; break;
          case oEncryptTo: /* store the recipient in the second list */
            sl = add_to_strlist2( &remusr, pargs.r.ret_str, utf8_strings );
-           sl->flags = (pargs.r_opt << 2) | 1;
+           sl->flags = ((pargs.r_opt << PK_LIST_SHIFT) | PK_LIST_ENCRYPT_TO);
+            if (configfp)
+              sl->flags |= PK_LIST_CONFIG;
            break;
          case oHiddenEncryptTo: /* store the recipient in the second list */
            sl = add_to_strlist2( &remusr, pargs.r.ret_str, utf8_strings );
-           sl->flags = (pargs.r_opt << 2) | 1|2;
+           sl->flags = ((pargs.r_opt << PK_LIST_SHIFT)
+                         | PK_LIST_ENCRYPT_TO|PK_LIST_HIDDEN);
+            if (configfp)
+              sl->flags |= PK_LIST_CONFIG;
            break;
           case oEncryptToDefaultKey:
-            opt.encrypt_to_default_key = 1;
+            opt.encrypt_to_default_key = configfp ? 2 : 1;
             break;
          case oRecipient: /* store the recipient */
            sl = add_to_strlist2( &remusr, pargs.r.ret_str, utf8_strings );
-           sl->flags = (pargs.r_opt << 2);
+           sl->flags = (pargs.r_opt << PK_LIST_SHIFT);
+            if (configfp)
+              sl->flags |= PK_LIST_CONFIG;
             any_explicit_recipient = 1;
            break;
          case oHiddenRecipient: /* store the recipient with a flag */
            sl = add_to_strlist2( &remusr, pargs.r.ret_str, utf8_strings );
-           sl->flags = (pargs.r_opt << 2) | 2;
+           sl->flags = ((pargs.r_opt << PK_LIST_SHIFT) | PK_LIST_HIDDEN);
+            if (configfp)
+              sl->flags |= PK_LIST_CONFIG;
             any_explicit_recipient = 1;
            break;
 
@@ -3062,7 +2879,9 @@ main (int argc, char **argv)
          case oNoAskCertLevel: opt.ask_cert_level = 0; break;
          case oLocalUser: /* store the local users */
            sl = add_to_strlist2( &locusr, pargs.r.ret_str, utf8_strings );
-            sl->flags = (pargs.r_opt << 2);
+            sl->flags = (pargs.r_opt << PK_LIST_SHIFT);
+            if (configfp)
+              sl->flags |= PK_LIST_CONFIG;
            break;
          case oCompress:
            /* this is the -z command line option */
@@ -3973,36 +3792,6 @@ main (int argc, char **argv)
         break;
       }
 
-    {
-      int have_def_secret_key = opt.def_secret_key != NULL;
-
-      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);
-
-      if (opt.encrypt_to_default_key)
-        {
-          const char *default_key = parse_def_secret_key (ctrl);
-          if (default_key)
-            {
-              sl = add_to_strlist2 (&remusr, default_key, utf8_strings);
-              sl->flags = (oEncryptToDefaultKey << 2) | 1;
-            }
-          else if (have_def_secret_key)
-            log_info (_("option '%s' given, but no valid default keys given\n"),
-                      "--encrypt-to-default-key");
-          else
-            log_info (_("option '%s' given, but option '%s' not given\n"),
-                      "--encrypt-to-default-key", "--default-key");
-        }
-    }
-
     /* The command dispatcher.  */
     switch( cmd )
       {
@@ -4164,7 +3953,6 @@ main (int argc, char **argv)
        break;
 
       case aVerify:
-        rc = 0;
        if (multifile)
          {
            if ((rc = verify_files (ctrl, argc, argv)))
@@ -4408,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++)
@@ -4727,7 +4526,7 @@ main (int argc, char **argv)
          KEYDB_HANDLE hd;
 
          if (argc < 2)
-           wrong_args("--tofu-policy POLICY KEYID [KEYID...]");
+           wrong_args ("--tofu-policy POLICY KEYID [KEYID...]");
 
          policy = parse_tofu_policy (argv[0]);