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);
|
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 --*/
|
/*-- gpgrlhelp.c --*/
|
||||||
void gnupg_rl_initialize (void);
|
void gnupg_rl_initialize (void);
|
||||||
|
@ -128,6 +128,7 @@ gpg_card_tool_SOURCES = \
|
|||||||
gpg-card-tool.c \
|
gpg-card-tool.c \
|
||||||
card-tool.h \
|
card-tool.h \
|
||||||
card-call-scd.c \
|
card-call-scd.c \
|
||||||
|
card-tool-keys.c \
|
||||||
card-tool-misc.c
|
card-tool-misc.c
|
||||||
|
|
||||||
gpg_card_tool_LDADD = ../common/libgpgrl.a $(common_libs) \
|
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_IPC (opt.debug & DBG_IPC_VALUE)
|
||||||
#define DBG_EXTPROG (opt.debug & DBG_EXTPROG_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. */
|
/* Enumeration of the known card application types. */
|
||||||
typedef enum
|
typedef enum
|
||||||
@ -76,9 +111,9 @@ struct key_attr
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
/* An object to store information pertaining to a key pair. This is
|
/* An object to store information pertaining to a key pair as stored
|
||||||
* commonly used as a linked list with all keys known for the current
|
* on a card. This is commonly used as a linked list with all keys
|
||||||
* card. */
|
* known for the current card. */
|
||||||
struct key_info_s
|
struct key_info_s
|
||||||
{
|
{
|
||||||
struct key_info_s *next;
|
struct key_info_s *next;
|
||||||
@ -144,6 +179,13 @@ struct card_info_s
|
|||||||
typedef struct card_info_s *card_info_t;
|
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 --*/
|
/*-- card-tool-misc.c --*/
|
||||||
key_info_t find_kinfo (card_info_t info, const char *keyref);
|
key_info_t find_kinfo (card_info_t info, const char *keyref);
|
||||||
|
|
||||||
|
@ -69,6 +69,9 @@ enum cmd_and_opt_values
|
|||||||
oLCctype,
|
oLCctype,
|
||||||
oLCmessages,
|
oLCmessages,
|
||||||
|
|
||||||
|
aTest,
|
||||||
|
|
||||||
|
|
||||||
oDummy
|
oDummy
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -76,6 +79,7 @@ enum cmd_and_opt_values
|
|||||||
/* The list of commands and options. */
|
/* The list of commands and options. */
|
||||||
static ARGPARSE_OPTS opts[] = {
|
static ARGPARSE_OPTS opts[] = {
|
||||||
ARGPARSE_group (300, ("@Commands:\n ")),
|
ARGPARSE_group (300, ("@Commands:\n ")),
|
||||||
|
ARGPARSE_c (aTest, "test", "test command"),
|
||||||
|
|
||||||
ARGPARSE_group (301, ("@\nOptions:\n ")),
|
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 oLCctype: opt.lc_ctype = pargs->r.ret_str; break;
|
||||||
case oLCmessages: opt.lc_messages = 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;
|
default: pargs->err = 2; break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -292,6 +300,12 @@ main (int argc, char **argv)
|
|||||||
/* Run the selected command. */
|
/* Run the selected command. */
|
||||||
switch (cmd)
|
switch (cmd)
|
||||||
{
|
{
|
||||||
|
case aTest:
|
||||||
|
if (!argc)
|
||||||
|
wrong_args ("--test KEYGRIP");
|
||||||
|
err = test_get_matching_keys (*argv);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
interactive_loop ();
|
interactive_loop ();
|
||||||
err = 0;
|
err = 0;
|
||||||
@ -580,14 +594,24 @@ mem_is_ff (const char *mem, unsigned int memlen)
|
|||||||
|
|
||||||
/* Helper to list a single keyref. */
|
/* Helper to list a single keyref. */
|
||||||
static void
|
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, " ");
|
tty_fprintf (fp, " ");
|
||||||
if (mem_is_zero (kinfo->grip, sizeof kinfo->grip))
|
if (mem_is_zero (kinfo->grip, sizeof kinfo->grip))
|
||||||
|
{
|
||||||
tty_fprintf (fp, "[none]\n");
|
tty_fprintf (fp, "[none]\n");
|
||||||
else
|
goto leave;
|
||||||
|
}
|
||||||
print_keygrip (fp, kinfo->grip);
|
print_keygrip (fp, kinfo->grip);
|
||||||
|
|
||||||
if (kinfo->fprlen && kinfo->created)
|
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",
|
tty_fprintf (fp, " created ....: %s\n",
|
||||||
isotimestamp (kinfo->created));
|
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
|
else
|
||||||
tty_fprintf (fp, " [none]\n");
|
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);
|
tty_fprintf (fp, "%s", labels[idx].label);
|
||||||
kinfo = find_kinfo (info, labels[idx].keyref);
|
kinfo = find_kinfo (info, labels[idx].keyref);
|
||||||
list_one_kinfo (kinfo, fp);
|
list_one_kinfo (info->kinfo, kinfo, fp);
|
||||||
if (kinfo)
|
if (kinfo)
|
||||||
kinfo->xflag = 1;
|
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++)
|
for (i=5+strlen (kinfo->keyref); i < 18; i++)
|
||||||
tty_fprintf (fp, ".");
|
tty_fprintf (fp, ".");
|
||||||
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