[git] GnuPG - branch, master, updated. gnupg-2.2.7-347-g833f27a

by Werner Koch cvs at cvs.gnupg.org
Wed Jan 30 15:01:49 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  833f27a6a7e059e38bccaf360f05e72e4403545a (commit)
      from  140fda8c61422ec055c3f7e214cc35706c4320dd (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 833f27a6a7e059e38bccaf360f05e72e4403545a
Author: Werner Koch <wk at gnupg.org>
Date:   Wed Jan 30 15:01:34 2019 +0100

    card: Print matching OpenPGP and X.509 data.
    
    * tools/card-tool-keys.c: New.
    * tools/Makefile.am (gpg_card_tool_SOURCES): Add file.
    * tools/card-tool.h (struct pubkey_s, pubkey_t): New.
    (struct userid_s, userid_t): New.
    (struct keyblock_s, keyblock_t): New.
    * common/util.h (GNUPG_PROTOCOL_): New const
    * tools/gpg-card-tool.c (aTest): Add temporary command.
    (list_one_kinfo): Print info from gpg and gpgsm.
    
    Signed-off-by: Werner Koch <wk at gnupg.org>

diff --git a/common/util.h b/common/util.h
index a4b1cbd..863f9e3 100644
--- a/common/util.h
+++ b/common/util.h
@@ -262,6 +262,13 @@ void gnupg_module_name_flush_some (void);
 void gnupg_set_builddir (const char *newdir);
 
 
+/* A list of constants to identify protocols.  This is used by tools
+ * which need to distinguish between the different protocols
+ * implemented by GnuPG.  May be used as bit flags.  */
+#define GNUPG_PROTOCOL_OPENPGP    1   /* The one and only (gpg).      */
+#define GNUPG_PROTOCOL_CMS        2   /* The core of S/MIME (gpgsm)   */
+#define GNUPG_PROTOCOL_SSH_AGENT  4   /* Out ssh-agent implementation */
+
 
 /*-- gpgrlhelp.c --*/
 void gnupg_rl_initialize (void);
diff --git a/tools/Makefile.am b/tools/Makefile.am
index f74221b..ad0f223 100644
--- a/tools/Makefile.am
+++ b/tools/Makefile.am
@@ -128,6 +128,7 @@ gpg_card_tool_SOURCES   = \
 	gpg-card-tool.c \
 	card-tool.h     \
 	card-call-scd.c \
+	card-tool-keys.c \
 	card-tool-misc.c
 
 gpg_card_tool_LDADD     = ../common/libgpgrl.a $(common_libs) \
diff --git a/tools/card-tool-keys.c b/tools/card-tool-keys.c
new file mode 100644
index 0000000..af2425c
--- /dev/null
+++ b/tools/card-tool-keys.c
@@ -0,0 +1,467 @@
+/* card-tool-keys.c - OpenPGP and CMS related functions for gpg-card-tool
+ * Copyright (C) 2019 g10 Code GmbH
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG 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.
+ *
+ * GnuPG 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 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://www.gnu.org/licenses/>.
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "../common/util.h"
+#include "../common/i18n.h"
+#include "../common/ccparray.h"
+#include "../common/exectool.h"
+#include "../common/openpgpdefs.h"
+#include "card-tool.h"
+
+/* Release a keyblocm object.  */
+void
+release_keyblock (keyblock_t keyblock)
+{
+  pubkey_t pubkey;
+  userid_t uid;
+
+  while (keyblock)
+    {
+      keyblock_t keyblocknext = keyblock->next;
+      pubkey = keyblock->keys;
+      while (pubkey)
+        {
+          pubkey_t pubkeynext = pubkey->next;
+          xfree (pubkey);
+          pubkey = pubkeynext;
+        }
+      uid = keyblock->uids;
+      while (uid)
+        {
+          userid_t uidnext = uid->next;
+          xfree (uid->value);
+          xfree (uid);
+          uid = uidnext;
+        }
+      xfree (keyblock);
+      keyblock = keyblocknext;
+    }
+}
+
+
+
+/* Object to communicate with the status_cb. */
+struct status_cb_s
+{
+  const char *pgm; /* Name of the program for debug purposes. */
+  int no_pubkey;   /* Result flag.  */
+};
+
+
+/* Status callback helper for the exec functions.  */
+static void
+status_cb (void *opaque, const char *keyword, char *args)
+{
+  struct status_cb_s *c = opaque;
+  const char *s;
+
+  if (DBG_EXTPROG)
+    log_debug ("%s: status: %s %s\n", c->pgm, keyword, args);
+
+  if (!strcmp (keyword, "ERROR")
+      && (s=has_leading_keyword (args, "keylist.getkey"))
+      && gpg_err_code (atoi (s)) == GPG_ERR_NO_PUBKEY)
+    {
+      /* No public key was found.  gpg terminates with an error in
+       * this case and we can't change that behaviour.  Instead we
+       * detect this status and carry that error forward. */
+      c->no_pubkey = 1;
+    }
+
+}
+
+
+/* Helper for get_matching_keys to parse "pub" style records.  */
+static gpg_error_t
+parse_key_record (char **fields, int nfields, pubkey_t *r_pubkey)
+{
+  pubkey_t pubkey;
+
+  pubkey = xtrycalloc (1, sizeof *pubkey);
+  if (!pubkey)
+    return gpg_error_from_syserror ();
+  *r_pubkey = pubkey;
+  return 0;
+}
+
+
+/* Run gpg or gpgsm to get a list of all keys matching the 20 byte
+ * KEYGRIP.  PROTOCOL is one of or a combination of
+ * GNUPG_PROTOCOL_OPENPGP and GNUPG_PROTOCOL_CMS.  On success a new
+ * keyblock is stored at R_KEYBLOCK; on error NULL is stored there. */
+gpg_error_t
+get_matching_keys (const unsigned char *keygrip, int protocol,
+                   keyblock_t *r_keyblock)
+{
+  gpg_error_t err;
+  ccparray_t ccp;
+  const char **argv;
+  estream_t listing;
+  char hexgrip[1 + (2*KEYGRIP_LEN) + 1];
+  char *line = NULL;
+  size_t length_of_line = 0;
+  size_t maxlen;
+  ssize_t len;
+  char **fields = NULL;
+  int nfields;
+  int first_seen;
+  keyblock_t keyblock_head, *keyblock_tail, kb;
+  pubkey_t pubkey, pk;
+  size_t n;
+  struct status_cb_s status_cb_parm;
+
+  *r_keyblock = NULL;
+
+  keyblock_head = NULL;
+  keyblock_tail = &keyblock_head;
+  kb = NULL;
+
+  /* Shortcut to run a listing on both protocols.  */
+  if ((protocol & GNUPG_PROTOCOL_OPENPGP) && (protocol & GNUPG_PROTOCOL_CMS))
+    {
+      err = get_matching_keys (keygrip, GNUPG_PROTOCOL_OPENPGP, &kb);
+      if (!err || gpg_err_code (err) == GPG_ERR_NO_PUBKEY)
+        {
+          *keyblock_tail = kb;
+          keyblock_tail = &kb->next;
+          kb = NULL;
+          err = get_matching_keys (keygrip, GNUPG_PROTOCOL_CMS, &kb);
+          if (!err)
+            {
+              *keyblock_tail = kb;
+              keyblock_tail = &kb->next;
+              kb = NULL;
+            }
+          else if (gpg_err_code (err) == GPG_ERR_NO_PUBKEY)
+            err = 0;
+        }
+      if (err)
+        release_keyblock (keyblock_head);
+      else
+        *r_keyblock = keyblock_head;
+      return err;
+    }
+
+  /* Check that we have only one protocol.  */
+  if (protocol != GNUPG_PROTOCOL_OPENPGP && protocol != GNUPG_PROTOCOL_CMS)
+    return gpg_error (GPG_ERR_UNSUPPORTED_PROTOCOL);
+
+  /* Open a memory stream.  */
+  listing = es_fopenmem (0, "w+b");
+  if (!listing)
+    {
+      err = gpg_error_from_syserror ();
+      log_error ("error allocating memory buffer: %s\n", gpg_strerror (err));
+      return err;
+    }
+
+  status_cb_parm.pgm = protocol == GNUPG_PROTOCOL_OPENPGP? "gpg":"gpgsm";
+  status_cb_parm.no_pubkey = 0;
+
+  hexgrip[0] = '&';
+  bin2hex (keygrip, KEYGRIP_LEN, hexgrip+1);
+
+  ccparray_init (&ccp, 0);
+
+  if (opt.verbose > 1 || DBG_EXTPROG)
+    ccparray_put (&ccp, "--verbose");
+  else
+    ccparray_put (&ccp, "--quiet");
+  ccparray_put (&ccp, "--no-options");
+  ccparray_put (&ccp, "--batch");
+  ccparray_put (&ccp, "--status-fd=2");
+  ccparray_put (&ccp, "--with-colons");
+  ccparray_put (&ccp, "--with-keygrip");
+  ccparray_put (&ccp, "--list-keys");
+  ccparray_put (&ccp, hexgrip);
+
+  ccparray_put (&ccp, NULL);
+  argv = ccparray_get (&ccp, NULL);
+  if (!argv)
+    {
+      err = gpg_error_from_syserror ();
+      goto leave;
+    }
+  err = gnupg_exec_tool_stream (protocol == GNUPG_PROTOCOL_OPENPGP?
+                                opt.gpg_program : opt.gpgsm_program,
+                                argv, NULL, NULL, listing, status_cb,
+                                &status_cb_parm);
+  if (err)
+    {
+      if (status_cb_parm.no_pubkey)
+        err = gpg_error (GPG_ERR_NO_PUBKEY);
+      else if (gpg_err_code (err) != GPG_ERR_GENERAL)
+        log_error ("key listing failed: %s\n", gpg_strerror (err));
+      goto leave;
+    }
+
+  es_rewind (listing);
+  first_seen = 0;
+  maxlen = 8192; /* Set limit large enough for all escaped UIDs.  */
+  while ((len = es_read_line (listing, &line, &length_of_line, &maxlen)) > 0)
+    {
+      if (!maxlen)
+        {
+          log_error ("received line too long\n");
+          err = gpg_error (GPG_ERR_LINE_TOO_LONG);
+          goto leave;
+        }
+      /* Strip newline and carriage return, if present.  */
+      while (len > 0 && (line[len - 1] == '\n' || line[len - 1] == '\r'))
+	line[--len] = '\0';
+
+      xfree (fields);
+      fields = strtokenize (line, ":");
+      if (!fields)
+        {
+          err = gpg_error_from_syserror ();
+          log_error ("strtokenize failed: %s\n", gpg_strerror (err));
+          goto leave;
+        }
+      for (nfields = 0; fields[nfields]; nfields++)
+        ;
+      if (!nfields)
+        {
+          err = gpg_error (GPG_ERR_INV_ENGINE);
+          goto leave;
+        }
+
+      /* Skip over all records until we reach a pub or sec.  */
+      if (!first_seen
+          && (!strcmp (fields[0], "pub") || !strcmp (fields[0], "sec")
+              || !strcmp (fields[0], "crt") || !strcmp (fields[0], "crs")))
+        first_seen = 1;
+      if (!first_seen)
+        continue;
+
+      if (!strcmp (fields[0], "pub") || !strcmp (fields[0], "sec")
+          || !strcmp (fields[0], "crt") || !strcmp (fields[0], "crs"))
+        {
+          if (kb)  /* Finish the current keyblock.  */
+            {
+              *keyblock_tail = kb;
+              keyblock_tail = &kb->next;
+            }
+          kb = xtrycalloc (1, sizeof *kb);
+          if (!kb)
+            {
+              err = gpg_error_from_syserror ();
+              goto leave;
+            }
+          kb->protocol = protocol;
+          err = parse_key_record (fields, nfields, &pubkey);
+          if (err)
+            goto leave;
+          kb->keys = pubkey;
+          pubkey = NULL;
+        }
+      else if (!strcmp (fields[0], "sub") || !strcmp (fields[0], "ssb"))
+        {
+          log_assert (kb && kb->keys);
+          err = parse_key_record (fields, nfields, &pubkey);
+          if (err)
+            goto leave;
+          for (pk = kb->keys; pk->next; pk = pk->next)
+                ;
+          pk->next = pubkey;
+          pubkey = NULL;
+        }
+      else if (!strcmp (fields[0], "fpr") && nfields > 9)
+        {
+          log_assert (kb && kb->keys);
+          n = strlen (fields[9]);
+          if (n != 64 && n != 40 && n != 32)
+            {
+              log_debug ("bad length (%zu) in fpr record\n", n);
+              err = gpg_error (GPG_ERR_INV_ENGINE);
+              goto leave;
+            }
+          n /= 2;
+
+          for (pk = kb->keys; pk->next; pk = pk->next)
+            ;
+          if (pk->fprlen)
+            {
+              log_debug ("too many fpr records\n");
+              err = gpg_error (GPG_ERR_INV_ENGINE);
+              goto leave;
+            }
+          log_assert (n <= sizeof pk->fpr);
+          pk->fprlen = n;
+          if (hex2bin (fields[9], pk->fpr, n) < 0)
+            {
+              log_debug ("bad chars in fpr record\n");
+              err = gpg_error (GPG_ERR_INV_ENGINE);
+              goto leave;
+            }
+        }
+      else if (!strcmp (fields[0], "grp") && nfields > 9)
+        {
+          log_assert (kb && kb->keys);
+          n = strlen (fields[9]);
+          if (n != 2*KEYGRIP_LEN)
+            {
+              log_debug ("bad length (%zu) in grp record\n", n);
+              err = gpg_error (GPG_ERR_INV_ENGINE);
+              goto leave;
+            }
+          n /= 2;
+
+          for (pk = kb->keys; pk->next; pk = pk->next)
+            ;
+          if (pk->grip_valid)
+            {
+              log_debug ("too many grp records\n");
+              err = gpg_error (GPG_ERR_INV_ENGINE);
+              goto leave;
+            }
+          if (hex2bin (fields[9], pk->grip, KEYGRIP_LEN) < 0)
+            {
+              log_debug ("bad chars in fpr record\n");
+              err = gpg_error (GPG_ERR_INV_ENGINE);
+              goto leave;
+            }
+          pk->grip_valid = 1;
+          if (!memcmp (pk->grip, keygrip, KEYGRIP_LEN))
+            pk->requested = 1;
+        }
+      else if (!strcmp (fields[0], "uid") && nfields > 9)
+        {
+          userid_t uid, u;
+
+          uid = xtrycalloc (1, sizeof *uid);
+          if (!uid)
+            {
+              err = gpg_error_from_syserror ();
+              goto leave;
+            }
+          uid->value = decode_c_string (fields[9]);
+          if (!uid->value)
+            {
+              err = gpg_error_from_syserror ();
+              xfree (uid);
+              goto leave;
+            }
+          if (!kb->uids)
+            kb->uids = uid;
+          else
+            {
+              for (u = kb->uids; u->next; u = u->next)
+                ;
+              u->next = uid;
+            }
+        }
+    }
+  if (len < 0 || es_ferror (listing))
+    {
+      err = gpg_error_from_syserror ();
+      log_error ("error reading memory stream\n");
+      goto leave;
+    }
+
+  if (kb) /* Finish the current keyblock.  */
+    {
+      *keyblock_tail = kb;
+      keyblock_tail = &kb->next;
+      kb = NULL;
+    }
+
+  if (!keyblock_head)
+    err = gpg_error (GPG_ERR_NO_PUBKEY);
+
+ leave:
+  if (err)
+    release_keyblock (keyblock_head);
+  else
+    *r_keyblock = keyblock_head;
+  xfree (kb);
+  xfree (fields);
+  es_free (line);
+  xfree (argv);
+  es_fclose (listing);
+  return err;
+}
+
+
+void
+dump_keyblock (keyblock_t keyblock)
+{
+  keyblock_t kb;
+  pubkey_t pubkey;
+  userid_t uid;
+
+  for (kb = keyblock; kb; kb = kb->next)
+    {
+      log_info ("%s key:\n",
+                 kb->protocol == GNUPG_PROTOCOL_OPENPGP? "OpenPGP":"X.509");
+      for (pubkey = kb->keys; pubkey; pubkey = pubkey->next)
+        {
+          log_info ("  grip: ");
+          if (pubkey->grip_valid)
+            log_printhex (pubkey->grip, KEYGRIP_LEN, NULL);
+          log_printf ("%s\n", pubkey->requested? " (*)":"");
+
+          log_info ("   fpr: ");
+          log_printhex (pubkey->fpr, pubkey->fprlen, "");
+        }
+      for (uid = kb->uids; uid; uid = uid->next)
+        {
+          log_info ("   uid: %s\n", uid->value);
+        }
+    }
+}
+
+
+
+gpg_error_t
+test_get_matching_keys (const char *hexgrip)
+{
+  gpg_error_t err;
+  unsigned char grip[KEYGRIP_LEN];
+  keyblock_t keyblock;
+
+  if (strlen (hexgrip) != 40)
+    {
+      log_error ("error: invalid keygrip\n");
+      return 0;
+    }
+  if (hex2bin (hexgrip, grip, sizeof grip) < 0)
+    {
+      log_error ("error: bad kegrip\n");
+      return 0;
+    }
+  err = get_matching_keys (grip,
+                           (GNUPG_PROTOCOL_OPENPGP | GNUPG_PROTOCOL_CMS),
+                           &keyblock);
+  if (err)
+    {
+      log_error ("get_matching_keys failed: %s\n", gpg_strerror (err));
+      return err;
+    }
+
+  dump_keyblock (keyblock);
+  release_keyblock (keyblock);
+  return 0;
+}
diff --git a/tools/card-tool.h b/tools/card-tool.h
index b1d8662..d502ecb 100644
--- a/tools/card-tool.h
+++ b/tools/card-tool.h
@@ -50,6 +50,41 @@ struct
 #define DBG_IPC       (opt.debug & DBG_IPC_VALUE)
 #define DBG_EXTPROG   (opt.debug & DBG_EXTPROG_VALUE)
 
+/* The maximum length of a binary fingerprint.  */
+#define MAX_FINGERPRINT_LEN  32
+
+
+/*
+ * Data structures to store keyblocks (aka certificates).
+ */
+struct pubkey_s
+{
+  struct pubkey_s *next;   /* The next key.  */
+  unsigned char grip[KEYGRIP_LEN];
+  unsigned char fpr[MAX_FINGERPRINT_LEN];
+  unsigned char fprlen;     /* The used length of a FPR.  */
+  unsigned int grip_valid:1;/* The grip is valid.  */
+  unsigned int requested: 1;/* This is the requested grip.  */
+};
+typedef struct pubkey_s *pubkey_t;
+
+struct userid_s
+{
+  struct userid_s *next;
+  char *value;   /* Malloced.  */
+};
+typedef struct userid_s *userid_t;
+
+struct keyblock_s
+{
+  struct keyblock_s *next;  /* Allow to link several keyblocks.  */
+  int protocol;      /* GPGME_PROTOCOL_OPENPGP or _CMS. */
+  pubkey_t keys;     /* The key.  For OpenPGP primary + list of subkeys.  */
+  userid_t uids;     /* The list of user ids.  */
+};
+typedef struct keyblock_s *keyblock_t;
+
+
 
 /* Enumeration of the known card application types. */
 typedef enum
@@ -76,9 +111,9 @@ struct key_attr
   };
 };
 
-/* An object to store information pertaining to a key pair.  This is
- * commonly used as a linked list with all keys known for the current
- * card.  */
+/* An object to store information pertaining to a key pair as stored
+ * on a card.  This is commonly used as a linked list with all keys
+ * known for the current card.  */
 struct key_info_s
 {
   struct key_info_s *next;
@@ -144,6 +179,13 @@ struct card_info_s
 typedef struct card_info_s *card_info_t;
 
 
+/*-- card-tool-keys.c --*/
+void release_keyblock (keyblock_t keyblock);
+gpg_error_t get_matching_keys (const unsigned char *keygrip, int protocol,
+                               keyblock_t *r_keyblock);
+gpg_error_t test_get_matching_keys (const char *hexgrip);
+
+
 /*-- card-tool-misc.c --*/
 key_info_t find_kinfo (card_info_t info, const char *keyref);
 
diff --git a/tools/gpg-card-tool.c b/tools/gpg-card-tool.c
index 4f79620..321426b 100644
--- a/tools/gpg-card-tool.c
+++ b/tools/gpg-card-tool.c
@@ -69,6 +69,9 @@ enum cmd_and_opt_values
     oLCctype,
     oLCmessages,
 
+    aTest,
+
+
     oDummy
   };
 
@@ -76,6 +79,7 @@ enum cmd_and_opt_values
 /* The list of commands and options. */
 static ARGPARSE_OPTS opts[] = {
   ARGPARSE_group (300, ("@Commands:\n ")),
+  ARGPARSE_c (aTest, "test", "test command"),
 
   ARGPARSE_group (301, ("@\nOptions:\n ")),
 
@@ -227,6 +231,10 @@ parse_arguments (ARGPARSE_ARGS *pargs, ARGPARSE_OPTS *popts)
         case oLCctype:     opt.lc_ctype = pargs->r.ret_str; break;
         case oLCmessages:  opt.lc_messages = pargs->r.ret_str; break;
 
+        case aTest:
+          cmd = pargs->r_opt;
+          break;
+
         default: pargs->err = 2; break;
 	}
     }
@@ -292,6 +300,12 @@ main (int argc, char **argv)
   /* Run the selected command.  */
   switch (cmd)
     {
+    case aTest:
+      if (!argc)
+        wrong_args ("--test KEYGRIP");
+      err = test_get_matching_keys (*argv);
+      break;
+
     default:
       interactive_loop ();
       err = 0;
@@ -580,15 +594,25 @@ mem_is_ff (const char *mem, unsigned int memlen)
 

 /* Helper to list a single keyref.  */
 static void
-list_one_kinfo (key_info_t kinfo, estream_t fp)
+list_one_kinfo (key_info_t firstkinfo, key_info_t kinfo, estream_t fp)
 {
-  if (kinfo)
+  gpg_error_t err;
+  keyblock_t keyblock = NULL;
+  keyblock_t kb;
+  pubkey_t pubkey;
+  userid_t uid;
+  key_info_t ki;
+  const char *s;
+
+  if (firstkinfo && kinfo)
     {
       tty_fprintf (fp, " ");
       if (mem_is_zero (kinfo->grip, sizeof kinfo->grip))
-        tty_fprintf (fp, "[none]\n");
-      else
-        print_keygrip (fp, kinfo->grip);
+        {
+          tty_fprintf (fp, "[none]\n");
+          goto leave;
+        }
+      print_keygrip (fp, kinfo->grip);
 
       if (kinfo->fprlen && kinfo->created)
         {
@@ -597,9 +621,63 @@ list_one_kinfo (key_info_t kinfo, estream_t fp)
           tty_fprintf (fp, "      created ....: %s\n",
                        isotimestamp (kinfo->created));
         }
+      err = get_matching_keys (kinfo->grip,
+                               (GNUPG_PROTOCOL_OPENPGP | GNUPG_PROTOCOL_CMS),
+                               &keyblock);
+      if (err)
+        {
+          if (gpg_err_code (err) != GPG_ERR_NO_PUBKEY)
+            tty_fprintf (fp, "      error ......: %s\n", gpg_strerror (err));
+          goto leave;
+        }
+      for (kb = keyblock; kb; kb = kb->next)
+        {
+          tty_fprintf (fp, "      used for ...: %s\n",
+                       kb->protocol == GNUPG_PROTOCOL_OPENPGP? "OpenPGP" :
+                       kb->protocol == GNUPG_PROTOCOL_CMS? "X.509" : "?");
+          pubkey = kb->keys;
+          /* If this is not the primary key print the primary key's
+           * fingerprint or a reference to it.  */
+          if (kb->protocol == GNUPG_PROTOCOL_OPENPGP)
+            {
+              tty_fprintf (fp, "        main key .:");
+              for (ki=firstkinfo; ki; ki = ki->next)
+                if (pubkey->grip_valid
+                    && !memcmp (ki->grip, pubkey->grip, KEYGRIP_LEN))
+                  break;
+              if (ki)
+                {
+                  /* Fixme: Replace mapping by a table lookup.  */
+                  if (!memcmp (kinfo->grip, pubkey->grip, KEYGRIP_LEN))
+                    s = "this";
+                  else if (!strcmp (ki->keyref, "OPENPGP.1"))
+                    s = "Signature key";
+                  else if (!strcmp (ki->keyref, "OPENPGP.2"))
+                    s = "Encryption key";
+                  else if (!strcmp (ki->keyref, "OPENPGP.3"))
+                    s = "Authentication key";
+                  else
+                    s = NULL;
+                  if (s)
+                    tty_fprintf (fp, " <%s>\n", s);
+                  else
+                    tty_fprintf (fp, " <Key %s>\n", ki->keyref);
+                }
+              else
+                print_shax_fpr (fp, pubkey->fpr, pubkey->fprlen);
+            }
+          for (uid = kb->uids; uid; uid = uid->next)
+            {
+              print_string (fp, "        user id ..: ", uid->value);
+            }
+
+        }
     }
   else
     tty_fprintf (fp, " [none]\n");
+
+ leave:
+  release_keyblock (keyblock);
 }
 
 
@@ -620,7 +698,7 @@ list_all_kinfo (card_info_t info, keyinfolabel_t labels, estream_t fp)
         {
           tty_fprintf (fp, "%s", labels[idx].label);
           kinfo = find_kinfo (info, labels[idx].keyref);
-          list_one_kinfo (kinfo, fp);
+          list_one_kinfo (info->kinfo, kinfo, fp);
           if (kinfo)
             kinfo->xflag = 1;
         }
@@ -633,7 +711,7 @@ list_all_kinfo (card_info_t info, keyinfolabel_t labels, estream_t fp)
       for (i=5+strlen (kinfo->keyref); i < 18; i++)
         tty_fprintf (fp, ".");
       tty_fprintf (fp, ":");
-      list_one_kinfo (kinfo, fp);
+      list_one_kinfo (info->kinfo, kinfo, fp);
     }
 }
 

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

Summary of changes:
 common/util.h          |   7 +
 tools/Makefile.am      |   1 +
 tools/card-tool-keys.c | 467 +++++++++++++++++++++++++++++++++++++++++++++++++
 tools/card-tool.h      |  48 ++++-
 tools/gpg-card-tool.c  |  92 +++++++++-
 5 files changed, 605 insertions(+), 10 deletions(-)
 create mode 100644 tools/card-tool-keys.c


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




More information about the Gnupg-commits mailing list