[git] GnuPG - branch, master, updated. gnupg-2.2.7-325-gf97dc55

by Werner Koch cvs at cvs.gnupg.org
Tue Jan 22 10:06:38 CET 2019


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "The GNU Privacy Guard".

The branch, master has been updated
       via  f97dc55ff1b041071bc3cbe98aa761bf77bb7ac8 (commit)
       via  e6d613711a327d63511601dd42aeff34e09ec95a (commit)
       via  03cf23b43ec5fea8a355d3ba2200e86a8efc589b (commit)
      from  fa9d703de5c70ae925e8ca6604073506f24d641a (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit f97dc55ff1b041071bc3cbe98aa761bf77bb7ac8
Author: Werner Koch <wk at gnupg.org>
Date:   Tue Jan 22 10:06:15 2019 +0100

    gpg: Stop early when trying to create a primary Elgamal key.
    
    * g10/misc.c (openpgp_pk_test_algo2): Add extra check.
    --
    
    The problem is that --key-gen --batch with a parameter file didn't
    detect that Elgamal is not capable of signing and so an error was only
    triggered at the time the self-signature was created.  See the code
    comment for details.
    
    GnuPG-bug-id: 4329
    Signed-off-by: Werner Koch <wk at gnupg.org>

diff --git a/g10/misc.c b/g10/misc.c
index f129e83..a3f0c67 100644
--- a/g10/misc.c
+++ b/g10/misc.c
@@ -723,6 +723,13 @@ openpgp_pk_test_algo2 (pubkey_algo_t algo, unsigned int use)
   if (!ga)
     return gpg_error (GPG_ERR_PUBKEY_ALGO);
 
+  /* Elgamal in OpenPGP used to support signing and Libgcrypt still
+   * does.  However, we removed the signing capability from gpg ages
+   * ago.  This function should reflect this so that errors are thrown
+   * early and not only when we try to sign using Elgamal.  */
+  if (ga == GCRY_PK_ELG && (use & (PUBKEY_USAGE_CERT | PUBKEY_USAGE_SIG)))
+    return gpg_error (GPG_ERR_WRONG_PUBKEY_ALGO);
+
   /* Now check whether Libgcrypt has support for the algorithm.  */
   return gcry_pk_algo_info (ga, GCRYCTL_TEST_ALGO, NULL, &use_buf);
 }

commit e6d613711a327d63511601dd42aeff34e09ec95a
Author: Werner Koch <wk at gnupg.org>
Date:   Tue Jan 22 09:07:24 2019 +0100

    card-tool: Add skeleton for new tool
    
    * tools/gpg-card-tool.c: New.
    * tools/gpg-card-tool-w32info.rc: New.
    * tools/Makefile.am: Add new tool.
    --
    
    To support more cards than the OpenPGP card it is useful to have a
    separate tool.  It will have have the "gpg --card-edit" style
    interactive interface as well as direct command line options for all
    commands.  In a first step the OpenPGP card will be supported, to
    allow its use as an alternative to the gpg command, and the
    forthcoming PIV card support.
    
    The tool can be though as a direct interface to scdaemon.
    
    Signed-off-by: Werner Koch <wk at gnupg.org>

diff --git a/tools/Makefile.am b/tools/Makefile.am
index e4fd81c..4833bff 100644
--- a/tools/Makefile.am
+++ b/tools/Makefile.am
@@ -20,14 +20,17 @@ EXTRA_DIST = \
 	Manifest watchgnupg.c no-libgcrypt.c \
 	addgnupghome applygnupgdefaults \
 	lspgpot mail-signed-keys convert-from-106 sockprox.c \
-	ccidmon.c ChangeLog-2011 gpg-connect-agent-w32info.rc
-
+	ccidmon.c ChangeLog-2011 \
+	gpg-connect-agent-w32info.rc \
+	gpg-card-tool-w32info.rc
 
 AM_CPPFLAGS =
 include $(top_srcdir)/am/cmacros.am
 
 if HAVE_W32_SYSTEM
-resource_objs += gpg-connect-agent-w32info.o
+gpg_connect_agent_rc_objs = gpg-connect-agent-w32info.o
+gpg_card_tool_rc_objs     = gpg-card-tool-w32info.o
+resource_objs += $(gpg_connect_agent_rc_objs) $(gpg_card_tool_rc_objs)
 endif
 
 AM_CFLAGS = $(LIBGCRYPT_CFLAGS) $(GPG_ERROR_CFLAGS) $(LIBASSUAN_CFLAGS)
@@ -48,7 +51,7 @@ endif
 
 libexec_PROGRAMS = gpg-wks-client gpg-pair-tool
 
-bin_PROGRAMS = gpgconf gpg-connect-agent ${symcryptrun}
+bin_PROGRAMS = gpgconf gpg-connect-agent gpg-card-tool ${symcryptrun}
 if !HAVE_W32_SYSTEM
 bin_PROGRAMS += watchgnupg gpgparsemail ${gpg_wks_server}
 endif
@@ -118,7 +121,14 @@ gpg_connect_agent_LDADD = ../common/libgpgrl.a $(common_libs) \
 	                  $(LIBASSUAN_LIBS) $(LIBGCRYPT_LIBS) \
                           $(GPG_ERROR_LIBS) \
                           $(LIBREADLINE) $(LIBINTL) $(NETLIBS) $(LIBICONV) \
-                          $(resource_objs)
+                          $(gpg_connect_agent_rc_objs)
+
+gpg_card_tool_SOURCES   = gpg-card-tool.c
+gpg_card_tool_LDADD     = ../common/libgpgrl.a $(common_libs) \
+	                  $(LIBASSUAN_LIBS) $(LIBGCRYPT_LIBS) \
+			  $(GPG_ERROR_LIBS) \
+                          $(LIBREADLINE) $(LIBINTL) $(NETLIBS) $(LIBICONV) \
+                          $(gpg_card_tool_rc_objs)
 
 
 if !DISABLE_REGEX
diff --git a/tools/gpg-connect-agent-w32info.rc b/tools/gpg-card-tool-w32info.rc
similarity index 83%
copy from tools/gpg-connect-agent-w32info.rc
copy to tools/gpg-card-tool-w32info.rc
index 4e7b19d..6937c3e 100644
--- a/tools/gpg-connect-agent-w32info.rc
+++ b/tools/gpg-card-tool-w32info.rc
@@ -1,5 +1,5 @@
-/* scdaemon-w32info.rc                                        -*- c -*-
- * Copyright (C) 2013 g10 Code GmbH
+/* gpg-card-toolt-w32info.rc                                         -*- c -*-
+ * Copyright (C) 2019 g10 Code GmbH
  *
  * This file is free software; as a special exception the author gives
  * unlimited permission to copy and/or distribute it, with or without
@@ -32,10 +32,10 @@
     BEGIN
         BLOCK "040904b0"  /* US English (0409), Unicode (04b0) */
         BEGIN
-            VALUE "FileDescription", L"GnuPG\x2019s command line access \
+            VALUE "FileDescription", L"GnuPG\x2019s card tool \
 to the agent\0"
-            VALUE "InternalName", "gpg-connect-agent\0"
-            VALUE "OriginalFilename", "gpg-connect-agent.exe\0"
+            VALUE "InternalName", "gpg-card-tool\0"
+            VALUE "OriginalFilename", "gpg-card-tool.exe\0"
             VALUE "ProductName",    W32INFO_PRODUCTNAME
             VALUE "ProductVersion", W32INFO_PRODUCTVERSION
             VALUE "CompanyName", W32INFO_COMPANYNAME
diff --git a/tools/gpg-card-tool.c b/tools/gpg-card-tool.c
new file mode 100644
index 0000000..91f0410
--- /dev/null
+++ b/tools/gpg-card-tool.c
@@ -0,0 +1,869 @@
+/* gpg-card-tool.c - An interactive tool to work with cards.
+ * Copyright (C) 2019 g10 Code GmbH Werner Koch
+ *
+ * This file is part of GnuPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser 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 <https://gnu.org/licenses/>.
+ * SPDX-License-Identifier: GPL-3.0+
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef HAVE_LIBREADLINE
+# define GNUPG_LIBREADLINE_H_INCLUDED
+# include <readline/readline.h>
+#endif /*HAVE_LIBREADLINE*/
+
+#include "../common/util.h"
+#include "../common/status.h"
+#include "../common/i18n.h"
+#include "../common/init.h"
+#include "../common/sysutils.h"
+#include "../common/asshelp.h"
+#include "../common/userids.h"
+#include "../common/ccparray.h"
+#include "../common/exectool.h"
+#include "../common/ttyio.h"
+
+#define CONTROL_D ('D' - 'A' + 1)
+
+/* Constants to identify the commands and options. */
+enum cmd_and_opt_values
+  {
+    aNull = 0,
+
+    oQuiet      = 'q',
+    oVerbose	= 'v',
+
+    oDebug      = 500,
+
+    oGpgProgram,
+    oGpgsmProgram,
+    oStatusFD,
+    oWithColons,
+
+    oDummy
+  };
+
+
+/* The list of commands and options. */
+static ARGPARSE_OPTS opts[] = {
+  ARGPARSE_group (300, ("@Commands:\n ")),
+
+  ARGPARSE_group (301, ("@\nOptions:\n ")),
+
+  ARGPARSE_s_n (oVerbose, "verbose", ("verbose")),
+  ARGPARSE_s_n (oQuiet,	"quiet",  ("be somewhat more quiet")),
+  ARGPARSE_s_s (oDebug, "debug", "@"),
+  ARGPARSE_s_s (oGpgProgram, "gpg", "@"),
+  ARGPARSE_s_s (oGpgsmProgram, "gpgsm", "@"),
+  ARGPARSE_s_i (oStatusFD, "status-fd", N_("|FD|write status info to this FD")),
+  ARGPARSE_s_n (oWithColons, "with-colons", "@"),
+
+  ARGPARSE_end ()
+};
+
+/* Debug values and macros.  */
+#define DBG_IPC_VALUE      1024 /* Debug assuan communication.  */
+#define DBG_EXTPROG_VALUE 16384 /* debug external program calls */
+
+
+/* The list of supported debug flags.  */
+static struct debug_flags_s debug_flags [] =
+  {
+    { DBG_IPC_VALUE    , "ipc"     },
+    { DBG_EXTPROG_VALUE, "extprog" },
+    { 0, NULL }
+  };
+
+
+
+/* We keep all global options in the structure OPT.  */
+struct
+{
+  int verbose;
+  unsigned int debug;
+  int quiet;
+  int with_colons;
+  const char *gpg_program;
+  const char *gpgsm_program;
+} opt;
+
+
+static void wrong_args (const char *text) GPGRT_ATTR_NORETURN;
+static void interactive_loop (void);
+#ifdef HAVE_LIBREADLINE
+static char **command_completion (const char *text, int start, int end);
+#endif /*HAVE_LIBREADLINE*/
+
+
+

+/* Print usage information and provide strings for help. */
+static const char *
+my_strusage( int level )
+{
+  const char *p;
+
+  switch (level)
+    {
+    case 11: p = "gpg-card-tool"; break;
+    case 12: p = "@GNUPG@"; break;
+    case 13: p = VERSION; break;
+    case 17: p = PRINTABLE_OS_NAME; break;
+    case 19: p = ("Please report bugs to <@EMAIL@>.\n"); break;
+
+    case 1:
+    case 40:
+      p = ("Usage: gpg-card-tool [command] [options] [args] (-h for help)");
+      break;
+    case 41:
+      p = ("Syntax: gpg-card-tool [command] [options] [args]\n"
+           "Tool to configure cards and tokens\n");
+      break;
+
+    default: p = NULL; break;
+    }
+  return p;
+}
+
+
+static void
+wrong_args (const char *text)
+{
+  es_fprintf (es_stderr, _("usage: %s [options] %s\n"), strusage (11), text);
+  exit (2);
+}
+
+
+

+/* Command line parsing.  */
+static enum cmd_and_opt_values
+parse_arguments (ARGPARSE_ARGS *pargs, ARGPARSE_OPTS *popts)
+{
+  enum cmd_and_opt_values cmd = 0;
+  int no_more_options = 0;
+
+  while (!no_more_options && optfile_parse (NULL, NULL, NULL, pargs, popts))
+    {
+      switch (pargs->r_opt)
+        {
+	case oQuiet:     opt.quiet = 1; break;
+        case oVerbose:   opt.verbose++; break;
+        case oDebug:
+          if (parse_debug_flag (pargs->r.ret_str, &opt.debug, debug_flags))
+            {
+              pargs->r_opt = ARGPARSE_INVALID_ARG;
+              pargs->err = ARGPARSE_PRINT_ERROR;
+            }
+          break;
+
+        case oGpgProgram:
+          opt.gpg_program = pargs->r.ret_str;
+          break;
+        case oGpgsmProgram:
+          opt.gpgsm_program = pargs->r.ret_str;
+          break;
+        case oStatusFD:
+          gnupg_set_status_fd (translate_sys2libc_fd_int (pargs->r.ret_int, 1));
+          break;
+        case oWithColons:
+          opt.with_colons = 1;
+          break;
+
+        default: pargs->err = 2; break;
+	}
+    }
+
+  return cmd;
+}
+
+
+

+/* gpg-card-tool main. */
+int
+main (int argc, char **argv)
+{
+  gpg_error_t err;
+  ARGPARSE_ARGS pargs;
+  enum cmd_and_opt_values cmd;
+
+  gnupg_reopen_std ("gpg-card-tool");
+  set_strusage (my_strusage);
+  gnupg_rl_initialize ();
+  log_set_prefix ("gpg-card-tool", GPGRT_LOG_WITH_PREFIX);
+
+  /* Make sure that our subsystems are ready.  */
+  i18n_init();
+  init_common_subsystems (&argc, &argv);
+
+  assuan_set_gpg_err_source (GPG_ERR_SOURCE_DEFAULT);
+  setup_libassuan_logging (&opt.debug, NULL);
+
+  /* Parse the command line. */
+  pargs.argc  = &argc;
+  pargs.argv  = &argv;
+  pargs.flags = ARGPARSE_FLAG_KEEP;
+  cmd = parse_arguments (&pargs, opts);
+
+  if (log_get_errorcount (0))
+    exit (2);
+
+  /* Print a warning if an argument looks like an option.  */
+  if (!opt.quiet && !(pargs.flags & ARGPARSE_FLAG_STOP_SEEN))
+    {
+      int i;
+
+      for (i=0; i < argc; i++)
+        if (argv[i][0] == '-' && argv[i][1] == '-')
+          log_info (("NOTE: '%s' is not considered an option\n"), argv[i]);
+    }
+
+  /* Set defaults for non given options.  */
+  if (!opt.gpg_program)
+    opt.gpg_program = gnupg_module_name (GNUPG_MODULE_NAME_GPG);
+  if (!opt.gpgsm_program)
+    opt.gpgsm_program = gnupg_module_name (GNUPG_MODULE_NAME_GPGSM);
+
+  /* Run the selected command.  */
+  switch (cmd)
+    {
+    default:
+      interactive_loop ();
+      err = 0;
+      break;
+    }
+
+  if (err)
+    gnupg_status_printf (STATUS_FAILURE, "- %u", err);
+  else if (log_get_errorcount (0))
+    gnupg_status_printf (STATUS_FAILURE, "- %u", GPG_ERR_GENERAL);
+  else
+    gnupg_status_printf (STATUS_SUCCESS, NULL);
+  return log_get_errorcount (0)? 1:0;
+}
+
+
+
+/* Print all available information about the current card. */
+static void
+print_card_status (char *serialno, size_t serialnobuflen)
+{
+  /* struct agent_card_info_s info; */
+  /* PKT_public_key *pk = xcalloc (1, sizeof *pk); */
+  /* kbnode_t keyblock = NULL; */
+  /* int rc; */
+  /* unsigned int uval; */
+  /* const unsigned char *thefpr; */
+  /* unsigned int thefprlen; */
+  /* int i; */
+
+  /* if (serialno && serialnobuflen) */
+  /*   *serialno = 0; */
+
+  /* rc = agent_scd_learn (&info, 0); */
+  /* if (rc) */
+  /*   { */
+  /*     if (opt.with_colons) */
+  /*       es_fputs ("AID:::\n", fp); */
+  /*     log_error (_("OpenPGP card not available: %s\n"), gpg_strerror (rc)); */
+  /*     xfree (pk); */
+  /*     return; */
+  /*   } */
+
+  /* if (opt.with_colons) */
+  /*   es_fprintf (fp, "Reader:%s:", info.reader? info.reader : ""); */
+  /* else */
+  /*   tty_fprintf (fp, "Reader ...........: %s\n", */
+  /*                info.reader? info.reader : "[none]"); */
+  /* if (opt.with_colons) */
+  /*   es_fprintf (fp, "AID:%s:", info.serialno? info.serialno : ""); */
+  /* else */
+  /*   tty_fprintf (fp, "Application ID ...: %s\n", */
+  /*                info.serialno? info.serialno : "[none]"); */
+  /* if (!info.serialno || strncmp (info.serialno, "D27600012401", 12) */
+  /*     || strlen (info.serialno) != 32 ) */
+  /*   { */
+  /*     if (info.apptype && !strcmp (info.apptype, "NKS")) */
+  /*       { */
+  /*         if (opt.with_colons) */
+  /*           es_fputs ("netkey-card:\n", fp); */
+  /*         log_info ("this is a NetKey card\n"); */
+  /*       } */
+  /*     else if (info.apptype && !strcmp (info.apptype, "DINSIG")) */
+  /*       { */
+  /*         if (opt.with_colons) */
+  /*           es_fputs ("dinsig-card:\n", fp); */
+  /*         log_info ("this is a DINSIG compliant card\n"); */
+  /*       } */
+  /*     else if (info.apptype && !strcmp (info.apptype, "P15")) */
+  /*       { */
+  /*         if (opt.with_colons) */
+  /*           es_fputs ("pkcs15-card:\n", fp); */
+  /*         log_info ("this is a PKCS#15 compliant card\n"); */
+  /*       } */
+  /*     else if (info.apptype && !strcmp (info.apptype, "GELDKARTE")) */
+  /*       { */
+  /*         if (opt.with_colons) */
+  /*           es_fputs ("geldkarte-card:\n", fp); */
+  /*         log_info ("this is a Geldkarte compliant card\n"); */
+  /*       } */
+  /*     else */
+  /*       { */
+  /*         if (opt.with_colons) */
+  /*           es_fputs ("unknown:\n", fp); */
+  /*       } */
+  /*     log_info ("not an OpenPGP card\n"); */
+  /*     agent_release_card_info (&info); */
+  /*     xfree (pk); */
+  /*     return; */
+  /*   } */
+
+  /* if (!serialno) */
+  /*   ; */
+  /* else if (strlen (info.serialno)+1 > serialnobuflen) */
+  /*   log_error ("serial number longer than expected\n"); */
+  /* else */
+  /*   strcpy (serialno, info.serialno); */
+
+  /* if (opt.with_colons) */
+  /*   es_fputs ("openpgp-card:\n", fp); */
+
+
+  /*     tty_fprintf (fp, "Version ..........: %.1s%c.%.1s%c\n", */
+  /*                  info.serialno[12] == '0'?"":info.serialno+12, */
+  /*                  info.serialno[13], */
+  /*                  info.serialno[14] == '0'?"":info.serialno+14, */
+  /*                  info.serialno[15]); */
+  /*     tty_fprintf (fp, "Manufacturer .....: %s\n", */
+  /*                  get_manufacturer (xtoi_2(info.serialno+16)*256 */
+  /*                                    + xtoi_2 (info.serialno+18))); */
+  /*     tty_fprintf (fp, "Serial number ....: %.8s\n", info.serialno+20); */
+
+  /*     print_isoname (fp, "Name of cardholder: ", "name", info.disp_name); */
+  /*     print_name (fp, "Language prefs ...: ", info.disp_lang); */
+  /*     tty_fprintf (fp, "Salutation .......: %s\n", */
+  /*                  info.disp_sex == 1? _("Mr."): */
+  /*                  info.disp_sex == 2? _("Mrs.") : ""); */
+  /*     print_name (fp, "URL of public key : ", info.pubkey_url); */
+  /*     print_name (fp, "Login data .......: ", info.login_data); */
+  /*     if (info.private_do[0]) */
+  /*       print_name (fp, "Private DO 1 .....: ", info.private_do[0]); */
+  /*     if (info.private_do[1]) */
+  /*       print_name (fp, "Private DO 2 .....: ", info.private_do[1]); */
+  /*     if (info.private_do[2]) */
+  /*       print_name (fp, "Private DO 3 .....: ", info.private_do[2]); */
+  /*     if (info.private_do[3]) */
+  /*       print_name (fp, "Private DO 4 .....: ", info.private_do[3]); */
+  /*     if (info.cafpr1len) */
+  /*       { */
+  /*         tty_fprintf (fp, "CA fingerprint %d .:", 1); */
+  /*         print_shax_fpr (fp, info.cafpr1, info.cafpr1len); */
+  /*       } */
+  /*     if (info.cafpr2len) */
+  /*       { */
+  /*         tty_fprintf (fp, "CA fingerprint %d .:", 2); */
+  /*         print_shax_fpr (fp, info.cafpr2, info.cafpr2len); */
+  /*       } */
+  /*     if (info.cafpr3len) */
+  /*       { */
+  /*         tty_fprintf (fp, "CA fingerprint %d .:", 3); */
+  /*         print_shax_fpr (fp, info.cafpr3, info.cafpr3len); */
+  /*       } */
+  /*     tty_fprintf (fp,    "Signature PIN ....: %s\n", */
+  /*                  info.chv1_cached? _("not forced"): _("forced")); */
+  /*     if (info.key_attr[0].algo) */
+  /*       { */
+  /*         tty_fprintf (fp,    "Key attributes ...:"); */
+  /*         for (i=0; i < DIM (info.key_attr); i++) */
+  /*           if (info.key_attr[i].algo == PUBKEY_ALGO_RSA) */
+  /*             tty_fprintf (fp, " rsa%u", info.key_attr[i].nbits); */
+  /*           else if (info.key_attr[i].algo == PUBKEY_ALGO_ECDH */
+  /*                    || info.key_attr[i].algo == PUBKEY_ALGO_ECDSA */
+  /*                    || info.key_attr[i].algo == PUBKEY_ALGO_EDDSA) */
+  /*             { */
+  /*               const char *curve_for_print = "?"; */
+
+  /*               if (info.key_attr[i].curve) */
+  /*                 { */
+  /*                   const char *oid; */
+  /*                   oid = openpgp_curve_to_oid (info.key_attr[i].curve, NULL); */
+  /*                   if (oid) */
+  /*                     curve_for_print = openpgp_oid_to_curve (oid, 0); */
+  /*                 } */
+  /*               tty_fprintf (fp, " %s", curve_for_print); */
+  /*             } */
+  /*         tty_fprintf (fp, "\n"); */
+  /*       } */
+  /*     tty_fprintf (fp,    "Max. PIN lengths .: %d %d %d\n", */
+  /*                  info.chvmaxlen[0], info.chvmaxlen[1], info.chvmaxlen[2]); */
+  /*     tty_fprintf (fp,    "PIN retry counter : %d %d %d\n", */
+  /*                  info.chvretry[0], info.chvretry[1], info.chvretry[2]); */
+  /*     tty_fprintf (fp,    "Signature counter : %lu\n", info.sig_counter); */
+  /*     if (info.extcap.kdf) */
+  /*       { */
+  /*         tty_fprintf (fp, "KDF setting ......: %s\n", */
+  /*                      info.kdf_do_enabled ? "on" : "off"); */
+  /*       } */
+  /*     if (info.extcap.bt) */
+  /*       { */
+  /*         tty_fprintf (fp, "UIF setting ......: Sign=%s Decrypt=%s Auth=%s\n", */
+  /*                      info.uif[0] ? "on" : "off", info.uif[1] ? "on" : "off", */
+  /*                      info.uif[2] ? "on" : "off"); */
+  /*       } */
+  /*     tty_fprintf (fp, "Signature key ....:"); */
+  /*     print_shax_fpr (fp, info.fpr1len? info.fpr1:NULL, info.fpr1len); */
+  /*     if (info.fpr1len && info.fpr1time) */
+  /*       { */
+  /*         tty_fprintf (fp, "      created ....: %s\n", */
+  /*                      isotimestamp (info.fpr1time)); */
+  /*         print_keygrip (fp, info.grp1); */
+  /*       } */
+  /*     tty_fprintf (fp, "Encryption key....:"); */
+  /*     print_shax_fpr (fp, info.fpr2len? info.fpr2:NULL, info.fpr2len); */
+  /*     if (info.fpr2len && info.fpr2time) */
+  /*       { */
+  /*         tty_fprintf (fp, "      created ....: %s\n", */
+  /*                      isotimestamp (info.fpr2time)); */
+  /*         print_keygrip (fp, info.grp2); */
+  /*       } */
+  /*     tty_fprintf (fp, "Authentication key:"); */
+  /*     print_shax_fpr (fp, info.fpr3len? info.fpr3:NULL, info.fpr3len); */
+  /*     if (info.fpr3len && info.fpr3time) */
+  /*       { */
+  /*         tty_fprintf (fp, "      created ....: %s\n", */
+  /*                      isotimestamp (info.fpr3time)); */
+  /*         print_keygrip (fp, info.grp3); */
+  /*       } */
+  /*     tty_fprintf (fp, "General key info..: "); */
+
+  /*     thefpr = (info.fpr1len? info.fpr1 : info.fpr2len? info.fpr2 : */
+  /*               info.fpr3len? info.fpr3 : NULL); */
+  /*     thefprlen = (info.fpr1len? info.fpr1len : info.fpr2len? info.fpr2len : */
+  /*                  info.fpr3len? info.fpr3len : 0); */
+  /*     /\* If the fingerprint is all 0xff, the key has no associated */
+  /*        OpenPGP certificate.  *\/ */
+  /*     if ( thefpr && !fpr_is_ff (thefpr, thefprlen) */
+  /*          && !get_pubkey_byfprint (ctrl, pk, &keyblock, thefpr, thefprlen)) */
+  /*       { */
+  /*         print_pubkey_info (ctrl, fp, pk); */
+  /*         if (keyblock) */
+  /*           print_card_key_info (fp, keyblock); */
+  /*       } */
+  /*     else */
+  /*       tty_fprintf (fp, "[none]\n"); */
+
+  /* release_kbnode (keyblock); */
+  /* free_public_key (pk); */
+  /* agent_release_card_info (&info); */
+}
+
+
+

+static void
+cmd_verify (void)
+{
+  /* agent_scd_checkpin (serialnobuf); */
+}
+
+
+static void
+cmd_name (void)
+{
+  /* change_name (); */
+}
+
+
+static void
+cmd_url (void)
+{
+  /* change_url (); */
+}
+
+
+static void
+cmd_fetch (void)
+{
+  /* fetch_url (); */
+}
+
+
+static void
+cmd_login (char *arg_string)
+{
+  /* change_login (arg_string); */
+}
+
+
+static void
+cmd_lang (void)
+{
+  /* change_lang (); */
+}
+
+
+static void
+cmd_salut (void)
+{
+  /* change_salut (); */
+}
+
+
+static void
+cmd_cafpr (int arg_number)
+{
+  if ( arg_number < 1 || arg_number > 3 )
+    tty_printf ("usage: cafpr N\n"
+                "       1 <= N <= 3\n");
+  /* else */
+  /*   change_cafpr (arg_number); */
+}
+
+
+static void
+cmd_privatedo (int arg_number, char *arg_string)
+{
+  if ( arg_number < 1 || arg_number > 4 )
+    tty_printf ("usage: privatedo N\n"
+                "       1 <= N <= 4\n");
+  /* else */
+  /*   change_private_do (arg_string, arg_number); */
+}
+
+
+static void
+cmd_writecert (int arg_number, char *arg_rest)
+{
+  if ( arg_number != 3 )
+    tty_printf ("usage: writecert 3 < FILE\n");
+  /* else */
+  /*   change_cert (arg_rest); */
+}
+
+
+static void
+cmd_readcert (int arg_number, char *arg_rest)
+{
+  if ( arg_number != 3 )
+    tty_printf ("usage: readcert 3 > FILE\n");
+  /* else */
+  /*   read_cert (arg_rest); */
+}
+
+
+static void
+cmd_forcesig (void)
+{
+  /* toggle_forcesig (); */
+}
+
+
+static void
+cmd_generate (void)
+{
+  /* generate_card_keys (); */
+}
+
+
+static void
+cmd_passwd (int allow_admin)
+{
+  /* change_pin (0, allow_admin); */
+}
+
+
+static void
+cmd_unblock (int allow_admin)
+{
+  /* change_pin (1, allow_admin); */
+}
+
+
+static void
+cmd_factoryreset (void)
+{
+  /* factory_reset (); */
+}
+
+
+static void
+cmd_kdfsetup (char *argstring)
+{
+  /* kdf_setup (arg_string); */
+}
+
+
+static void
+cmd_keyattr (void)
+{
+  /* key_attr (); */
+}
+
+
+static void
+cmd_uif (int arg_number, char *arg_rest)
+{
+  if ( arg_number < 1 || arg_number > 3 )
+    tty_printf ("usage: uif N [on|off|permanent]\n"
+                "       1 <= N <= 3\n");
+  /* else */
+  /*   uif (arg_number, arg_rest); */
+}
+
+
+

+/* Data used by the command parser.  This needs to be outside of the
+ * function scope to allow readline based command completion.  */
+enum cmdids
+  {
+    cmdNOP = 0,
+    cmdQUIT, cmdADMIN, cmdHELP, cmdLIST, cmdDEBUG, cmdVERIFY,
+    cmdNAME, cmdURL, cmdFETCH, cmdLOGIN, cmdLANG, cmdSALUT, cmdCAFPR,
+    cmdFORCESIG, cmdGENERATE, cmdPASSWD, cmdPRIVATEDO, cmdWRITECERT,
+    cmdREADCERT, cmdUNBLOCK, cmdFACTORYRESET, cmdKDFSETUP,
+    cmdKEYATTR, cmdUIF,
+    cmdINVCMD
+  };
+
+static struct
+{
+  const char *name;
+  enum cmdids id;
+  int admin_only;
+  const char *desc;
+} cmds[] = {
+  { "quit"    , cmdQUIT  , 0, N_("quit this menu")},
+  { "q"       , cmdQUIT  , 0, NULL },
+  { "admin"   , cmdADMIN , 0, N_("show admin commands")},
+  { "help"    , cmdHELP  , 0, N_("show this help")},
+  { "?"       , cmdHELP  , 0, NULL },
+  { "list"    , cmdLIST  , 0, N_("list all available data")},
+  { "l"       , cmdLIST  , 0, NULL },
+  { "debug"   , cmdDEBUG , 0, NULL },
+  { "name"    , cmdNAME  , 1, N_("change card holder's name")},
+  { "url"     , cmdURL   , 1, N_("change URL to retrieve key")},
+  { "fetch"   , cmdFETCH , 0, N_("fetch the key specified in the card URL")},
+  { "login"   , cmdLOGIN , 1, N_("change the login name")},
+  { "lang"    , cmdLANG  , 1, N_("change the language preferences")},
+  { "salutation",cmdSALUT, 1, N_("change card holder's salutation")},
+  { "cafpr"   , cmdCAFPR , 1, N_("change a CA fingerprint")},
+  { "forcesig", cmdFORCESIG, 1, N_("toggle the signature force PIN flag")},
+  { "generate", cmdGENERATE, 1, N_("generate new keys")},
+  { "passwd"  , cmdPASSWD, 0, N_("menu to change or unblock the PIN")},
+  { "verify"  , cmdVERIFY, 0, N_("verify the PIN and list all data")},
+  { "unblock" , cmdUNBLOCK,0, N_("unblock the PIN using a Reset Code")},
+  { "factory-reset", cmdFACTORYRESET, 1, N_("destroy all keys and data")},
+  { "kdf-setup", cmdKDFSETUP, 1, N_("setup KDF for PIN authentication")},
+  { "key-attr", cmdKEYATTR, 1, N_("change the key attribute")},
+  { "uif", cmdUIF, 1, N_("change the User Interaction Flag")},
+  /* Note, that we do not announce these command yet. */
+  { "privatedo", cmdPRIVATEDO, 0, NULL },
+  { "readcert", cmdREADCERT, 0, NULL },
+  { "writecert", cmdWRITECERT, 1, NULL },
+  { NULL, cmdINVCMD, 0, NULL }
+};
+
+
+/* The main loop.  */
+static void
+interactive_loop (void)
+{
+  char *answer = NULL;         /* The input line.  */
+  enum cmdids cmd = cmdNOP;    /* The command.  */
+  int cmd_admin_only;          /* The command is an admin only command.  */
+  int arg_number;              /* The first argument as a number.  */
+  char *arg_string = "";       /* The first argument as a string.  */
+  char *arg_rest = "";         /* The remaining arguments.  */
+  int redisplay = 1;           /* Whether to redisplay the main info.  */
+  int allow_admin = 0;         /* Whether admin commands are allowed.  */
+  char serialnobuf[50];
+  char *p;
+  int i;
+
+  for (;;)
+    {
+
+      tty_printf ("\n");
+      if (redisplay)
+        {
+          print_card_status (serialnobuf, DIM (serialnobuf));
+          tty_printf("\n");
+          redisplay = 0;
+	}
+
+      do
+        {
+          xfree (answer);
+          tty_enable_completion (command_completion);
+          answer = tty_get (_("gpg/card> "));
+          tty_kill_prompt();
+          tty_disable_completion ();
+          trim_spaces(answer);
+	}
+      while ( *answer == '#' );
+
+      arg_number = 0;
+      cmd_admin_only = 0;
+      if (!*answer)
+        cmd = cmdLIST; /* We default to the list command */
+      else if (*answer == CONTROL_D)
+        cmd = cmdQUIT;
+      else
+        {
+          if ((p=strchr (answer,' ')))
+            {
+              *p++ = 0;
+              trim_spaces (answer);
+              trim_spaces (p);
+              arg_number = atoi (p);
+              arg_string = p;
+              arg_rest = p;
+              while (digitp (arg_rest))
+                arg_rest++;
+              while (spacep (arg_rest))
+                arg_rest++;
+            }
+
+          for (i=0; cmds[i].name; i++ )
+            if (!ascii_strcasecmp (answer, cmds[i].name ))
+              break;
+
+          cmd = cmds[i].id;
+          cmd_admin_only = cmds[i].admin_only;
+        }
+
+      if (!allow_admin && cmd_admin_only)
+	{
+          tty_printf ("\n");
+          tty_printf (_("Admin-only command\n"));
+          continue;
+        }
+
+      switch (cmd)
+        {
+        case cmdNOP:
+          break;
+
+        case cmdQUIT:
+          goto leave;
+
+        case cmdHELP:
+          for (i=0; cmds[i].name; i++ )
+            if(cmds[i].desc
+	       && (!cmds[i].admin_only || (cmds[i].admin_only && allow_admin)))
+              tty_printf("%-14s %s\n", cmds[i].name, _(cmds[i].desc) );
+          break;
+
+	case cmdADMIN:
+          if ( !strcmp (arg_string, "on") )
+            allow_admin = 1;
+          else if ( !strcmp (arg_string, "off") )
+            allow_admin = 0;
+          else if ( !strcmp (arg_string, "verify") )
+            {
+              /* Force verification of the Admin Command.  However,
+                 this is only done if the retry counter is at initial
+                 state.  */
+              /* FIXME: Must depend on the type of the card.  */
+              /* char *tmp = xmalloc (strlen (serialnobuf) + 6 + 1); */
+              /* strcpy (stpcpy (tmp, serialnobuf), "[CHV3]"); */
+              /* allow_admin = !agent_scd_checkpin (tmp); */
+              /* xfree (tmp); */
+            }
+          else /* Toggle. */
+            allow_admin=!allow_admin;
+	  if(allow_admin)
+	    tty_printf(_("Admin commands are allowed\n"));
+	  else
+	    tty_printf(_("Admin commands are not allowed\n"));
+	  break;
+
+        case cmdVERIFY:    cmd_verify (); redisplay = 1; break;
+        case cmdLIST:                     redisplay = 1; break;
+        case cmdNAME:      cmd_name ();   break;
+        case cmdURL:       cmd_url ();    break;
+	case cmdFETCH:     cmd_fetch ();  break;
+        case cmdLOGIN:     cmd_login (arg_string); break;
+        case cmdLANG:      cmd_lang ();   break;
+        case cmdSALUT:     cmd_salut ();  break;
+        case cmdCAFPR:     cmd_cafpr (arg_number); break;
+        case cmdPRIVATEDO: cmd_privatedo (arg_number, arg_string); break;
+        case cmdWRITECERT: cmd_writecert (arg_number, arg_rest); break;
+        case cmdREADCERT:  cmd_readcert (arg_number, arg_rest); break;
+        case cmdFORCESIG:  cmd_forcesig (); break;
+        case cmdGENERATE:  cmd_generate (); break;
+        case cmdPASSWD:    cmd_passwd (allow_admin); break;
+        case cmdUNBLOCK:   cmd_unblock (allow_admin); break;
+        case cmdFACTORYRESET: cmd_factoryreset (); break;
+        case cmdKDFSETUP:  cmd_kdfsetup (arg_string); break;
+        case cmdKEYATTR:   cmd_keyattr (); break;
+        case cmdUIF:       cmd_uif (arg_number, arg_rest); break;
+
+        case cmdINVCMD:
+        default:
+          tty_printf ("\n");
+          tty_printf (_("Invalid command  (try \"help\")\n"));
+          break;
+        } /* End command switch. */
+    } /* End of main menu loop. */
+
+ leave:
+  xfree (answer);
+}
+
+#ifdef HAVE_LIBREADLINE
+/* Helper function for readline's command completion. */
+static char *
+command_generator (const char *text, int state)
+{
+  static int list_index, len;
+  const char *name;
+
+  /* If this is a new word to complete, initialize now.  This includes
+   * saving the length of TEXT for efficiency, and initializing the
+   index variable to 0. */
+  if (!state)
+    {
+      list_index = 0;
+      len = strlen(text);
+    }
+
+  /* Return the next partial match */
+  while ((name = cmds[list_index].name))
+    {
+      /* Only complete commands that have help text. */
+      if (cmds[list_index++].desc && !strncmp (name, text, len))
+	return strdup(name);
+    }
+
+  return NULL;
+}
+
+/* Second helper function for readline's command completion.  */
+static char **
+command_completion (const char *text, int start, int end)
+{
+  (void)end;
+
+  /* If we are at the start of a line, we try and command-complete.
+   * If not, just do nothing for now. */
+  if (!start)
+    return rl_completion_matches (text, command_generator);
+
+  rl_attempted_completion_over = 1;
+
+  return NULL;
+}
+#endif /*HAVE_LIBREADLINE*/
diff --git a/tools/gpg-connect-agent-w32info.rc b/tools/gpg-connect-agent-w32info.rc
index 4e7b19d..8c67359 100644
--- a/tools/gpg-connect-agent-w32info.rc
+++ b/tools/gpg-connect-agent-w32info.rc
@@ -1,4 +1,4 @@
-/* scdaemon-w32info.rc                                        -*- c -*-
+/* gpg-connect-agent-w32info.rc                               -*- c -*-
  * Copyright (C) 2013 g10 Code GmbH
  *
  * This file is free software; as a special exception the author gives

commit 03cf23b43ec5fea8a355d3ba2200e86a8efc589b
Author: Werner Koch <wk at gnupg.org>
Date:   Tue Jan 22 09:02:17 2019 +0100

    common: Add generic status print function.
    
    * common/status.c (gnupg_set_status_fd): New.
    (gnupg_status_printf): New.
    * po/Makevars (XGETTEXT_OPTIONS): Add gnupg-status_printf.
    --
    
    Some of the extra tools take a --status-fd option to print certain
    status messages.  A generic printf style print function thus makes
    sense.
    
    Signed-off-by: Werner Koch <wk at gnupg.org>

diff --git a/common/status.c b/common/status.c
index 50afce4..269ffea 100644
--- a/common/status.c
+++ b/common/status.c
@@ -34,6 +34,10 @@
 #include "status.h"
 #include "status-codes.h"
 
+/* The stream to output the status information.  Output is disabled if
+ * this is NULL.  */
+static estream_t statusfp;
+
 
 /* Return the status string for code NO. */
 const char *
@@ -47,6 +51,60 @@ get_status_string ( int no )
 }
 
 
+/* Set a global status FD.  */
+void
+gnupg_set_status_fd (int fd)
+{
+  static int last_fd = -1;
+
+  if (fd != -1 && last_fd == fd)
+    return;
+
+  if (statusfp && statusfp != es_stdout && statusfp != es_stderr)
+    es_fclose (statusfp);
+  statusfp = NULL;
+  if (fd == -1)
+    return;
+
+  if (fd == 1)
+    statusfp = es_stdout;
+  else if (fd == 2)
+    statusfp = es_stderr;
+  else
+    statusfp = es_fdopen (fd, "w");
+  if (!statusfp)
+    {
+      log_fatal ("can't open fd %d for status output: %s\n",
+                 fd, gpg_strerror (gpg_error_from_syserror ()));
+    }
+  last_fd = fd;
+}
+
+
+/* Write a status line with code NO followed by the output of the
+ * printf style FORMAT.  The caller needs to make sure that LFs and
+ * CRs are not printed.  */
+void
+gnupg_status_printf (int no, const char *format, ...)
+{
+  va_list arg_ptr;
+
+  if (!statusfp)
+    return;  /* Not enabled.  */
+
+  es_fputs ("[GNUPG:] ", statusfp);
+  es_fputs (get_status_string (no), statusfp);
+  if (format)
+    {
+      es_putc (' ', statusfp);
+      va_start (arg_ptr, format);
+      es_vfprintf (statusfp, format, arg_ptr);
+      va_end (arg_ptr);
+    }
+  es_putc ('\n', statusfp);
+}
+
+
 const char *
 get_inv_recpsgnr_code (gpg_error_t err)
 {
diff --git a/common/status.h b/common/status.h
index dc62f36..aeab542 100644
--- a/common/status.h
+++ b/common/status.h
@@ -163,6 +163,10 @@ enum
 
 
 const char *get_status_string (int code);
+void gnupg_set_status_fd (int fd);
+void gnupg_status_printf (int no, const char *format,
+                          ...) GPGRT_ATTR_PRINTF(2,3);
+
 const char *get_inv_recpsgnr_code (gpg_error_t err);
 
 
diff --git a/po/Makevars b/po/Makevars
index 20d6ae9..07778e0 100644
--- a/po/Makevars
+++ b/po/Makevars
@@ -61,6 +61,7 @@ XGETTEXT_OPTIONS = \
 	--flag=ks_printf_help:2:c-format         \
 	--flag=print_further_info:1:c-format     \
 	--flag=write_status_printf:2:c-format    \
+	--flag=gnupg_printf_status:2:c-format    \
 	--flag=kbxd_print_status:3:c-format      \
 	--flag=gpgconf_write_status:2:c-format   \
         --flag=send_status_printf:3:c-format     \

-----------------------------------------------------------------------

Summary of changes:
 common/status.c                                    |  58 ++
 common/status.h                                    |   4 +
 g10/misc.c                                         |   7 +
 po/Makevars                                        |   1 +
 tools/Makefile.am                                  |  20 +-
 ...t-agent-w32info.rc => gpg-card-tool-w32info.rc} |  10 +-
 tools/gpg-card-tool.c                              | 869 +++++++++++++++++++++
 tools/gpg-connect-agent-w32info.rc                 |   2 +-
 8 files changed, 960 insertions(+), 11 deletions(-)
 copy tools/{gpg-connect-agent-w32info.rc => gpg-card-tool-w32info.rc} (83%)
 create mode 100644 tools/gpg-card-tool.c


hooks/post-receive
-- 
The GNU Privacy Guard
http://git.gnupg.org




More information about the Gnupg-commits mailing list