mirror of
git://git.gnupg.org/gnupg.git
synced 2024-12-22 10:19:57 +01:00
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@gnupg.org>
This commit is contained in:
parent
140fda8c61
commit
833f27a6a7
@ -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);
|
||||
|
@ -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) \
|
||||
|
467
tools/card-tool-keys.c
Normal file
467
tools/card-tool-keys.c
Normal file
@ -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;
|
||||
}
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user