aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWerner Koch <[email protected]>2019-01-30 14:01:34 +0000
committerWerner Koch <[email protected]>2019-01-30 14:01:34 +0000
commit833f27a6a7e059e38bccaf360f05e72e4403545a (patch)
tree3de745f43d9d3d12fa19d551ea7225f3f0854def
parentgpg: Emit an ERROR status if no key was found with --list-keys. (diff)
downloadgnupg-833f27a6a7e059e38bccaf360f05e72e4403545a.tar.gz
gnupg-833f27a6a7e059e38bccaf360f05e72e4403545a.zip
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 <[email protected]>
-rw-r--r--common/util.h7
-rw-r--r--tools/Makefile.am1
-rw-r--r--tools/card-tool-keys.c467
-rw-r--r--tools/card-tool.h48
-rw-r--r--tools/gpg-card-tool.c92
5 files changed, 605 insertions, 10 deletions
diff --git a/common/util.h b/common/util.h
index a4b1cbd79..863f9e36f 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 f74221b2d..ad0f223b4 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 000000000..af2425cbf
--- /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 b1d866228..d502ecb58 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 4f7962060..321426bdd 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);
}
}