New gpg-agent command to list key information.

Gpgsm does now print the S/N of cards.
Consider ephemeral keys during listing an export.
This commit is contained in:
Werner Koch 2009-03-06 17:31:27 +00:00
parent 59d7a54e72
commit a9c317a95c
20 changed files with 601 additions and 180 deletions

6
NEWS
View File

@ -1,6 +1,12 @@
Noteworthy changes in version 2.0.12
-------------------------------------------------
* GPGSM now always lists ephemeral certificates if specified by
fingerprint or keygrip.
* New command "KEYINFO" for GPG_AGENT. GPGSM now also returns
information about smartcards.
Noteworthy changes in version 2.0.11 (2009-03-03)
-------------------------------------------------

View File

@ -1,3 +1,16 @@
2009-03-06 Werner Koch <wk@g10code.com>
* command.c (cmd_keyinfo): New command.
(register_commands): Register it.
(agent_write_status): Make sure not to print LR or CR.
* divert-scd.c (ask_for_card): Factor shadow info parsing out to ...
* protect.c (parse_shadow_info): New.
* findkey.c (agent_key_from_file): Use make_canon_sexp.
(agent_write_private_key, unprotect, read_key_file)
(agent_key_available): Use bin2hex.
(agent_key_info_from_file): New.
(read_key_file): Log no error message for ENOENT.
2009-03-05 Werner Koch <wk@g10code.com>
* divert-scd.c (getpin_cb): Support flag 'P'. Change max_digits
@ -2227,7 +2240,7 @@ Fri Aug 18 14:27:14 CEST 2000 Werner Koch <wk@openit.de>
Copyright 2001, 2002, 2003, 2004, 2005,
2007 Free Software Foundation, Inc.
2007, 2008, 2009 Free Software Foundation, Inc.
This file is free software; as a special exception the author gives
unlimited permission to copy and/or distribute it, with or without

View File

@ -233,6 +233,9 @@ gpg_error_t agent_public_key_from_file (ctrl_t ctrl,
const unsigned char *grip,
gcry_sexp_t *result);
int agent_key_available (const unsigned char *grip);
gpg_error_t agent_key_info_from_file (ctrl_t ctrl, const unsigned char *grip,
int *r_keytype,
unsigned char **r_shadow_info);
/*-- call-pinentry.c --*/
void initialize_module_call_pinentry (void);
@ -294,6 +297,8 @@ int agent_shadow_key (const unsigned char *pubkey,
unsigned char **result);
int agent_get_shadow_info (const unsigned char *shadowkey,
unsigned char const **shadow_info);
gpg_error_t parse_shadow_info (const unsigned char *shadow_info,
char **r_hexsn, char **r_idstr);
/*-- trustlist.c --*/

View File

@ -1,6 +1,6 @@
/* command.c - gpg-agent command handler
* Copyright (C) 2001, 2002, 2003, 2004, 2005,
* 2006, 2008 Free Software Foundation, Inc.
* 2006, 2008, 2009 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@ -30,6 +30,9 @@
#include <ctype.h>
#include <unistd.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <assuan.h>
@ -308,8 +311,21 @@ agent_write_status (ctrl_t ctrl, const char *keyword, ...)
*p++ = ' ';
n++;
}
for ( ; *text && n < DIM (buf)-2; n++)
*p++ = *text++;
for ( ; *text && n < DIM (buf)-3; n++, text++)
{
if (*text == '\n')
{
*p++ = '\\';
*p++ = 'n';
}
else if (*text == '\r')
{
*p++ = '\\';
*p++ = 'r';
}
else
*p++ = *text;
}
}
*p = 0;
err = assuan_write_status (ctx, keyword, buf);
@ -806,7 +822,145 @@ cmd_readkey (assuan_context_t ctx, char *line)
}
/* KEYINFO [--list] <keygrip>
Return information about the key specified by the KEYGRIP. If the
key is not available GPG_ERR_NOT_FOUND is returned. If the option
--list is given the keygrip is ignored and information about all
available keys are returned. The information is returned as a
status line with this format:
KEYINFO <keygrip> <type> <serialno> <idstr>
KEYGRIP is the keygrip.
TYPE is describes the type of the key:
'D' - Regular key stored on disk,
'T' - Key is stored on a smartcard (token).
'-' - Unknown type.
SERIALNO is an ASCII string with the serial number of the
smartcard. If the serial number is not known a single
dash '-' is used instead.
IDSTR is the IDSTR used to distinguish keys on a smartcard. If it
is not known a dash is used instead.
More information may be added in the future.
*/
static gpg_error_t
do_one_keyinfo (ctrl_t ctrl, const unsigned char *grip)
{
gpg_error_t err;
char hexgrip[40+1];
int keytype;
unsigned char *shadow_info = NULL;
char *serialno = NULL;
char *idstr = NULL;
const char *keytypestr;
err = agent_key_info_from_file (ctrl, grip, &keytype, &shadow_info);
if (err)
goto leave;
/* Reformat the grip so that we use uppercase as good style. */
bin2hex (grip, 20, hexgrip);
if (keytype == PRIVATE_KEY_CLEAR
|| keytype == PRIVATE_KEY_PROTECTED)
keytypestr = "D";
else if (keytype == PRIVATE_KEY_SHADOWED)
keytypestr = "T";
else
keytypestr = "-";
if (shadow_info)
{
err = parse_shadow_info (shadow_info, &serialno, &idstr);
if (err)
goto leave;
}
err = agent_write_status (ctrl, "KEYINFO",
hexgrip,
keytypestr,
serialno? serialno : "-",
idstr? idstr : "-",
NULL);
leave:
xfree (shadow_info);
xfree (serialno);
xfree (idstr);
return err;
}
static int
cmd_keyinfo (assuan_context_t ctx, char *line)
{
ctrl_t ctrl = assuan_get_pointer (ctx);
int err;
unsigned char grip[20];
DIR *dir = NULL;
int list_mode;
list_mode = has_option (line, "--list");
line = skip_options (line);
if (list_mode)
{
char *dirname;
struct dirent *dir_entry;
char hexgrip[41];
dirname = make_filename_try (opt.homedir, GNUPG_PRIVATE_KEYS_DIR, NULL);
if (!dirname)
{
err = gpg_error_from_syserror ();
goto leave;
}
dir = opendir (dirname);
if (!dir)
{
err = gpg_error_from_syserror ();
xfree (dirname);
goto leave;
}
xfree (dirname);
while ( (dir_entry = readdir (dir)) )
{
if (strlen (dir_entry->d_name) != 44
|| strcmp (dir_entry->d_name + 40, ".key"))
continue;
strncpy (hexgrip, dir_entry->d_name, 40);
hexgrip[40] = 0;
if ( hex2bin (hexgrip, grip, 20) < 0 )
continue; /* Bad hex string. */
err = do_one_keyinfo (ctrl, grip);
if (err)
goto leave;
}
err = 0;
}
else
{
err = parse_keygrip (ctx, line, grip);
if (err)
goto leave;
err = do_one_keyinfo (ctrl, grip);
}
leave:
if (dir)
closedir (dir);
if (err && gpg_err_code (err) != GPG_ERR_NOT_FOUND)
log_error ("command keyinfo failed: %s\n", gpg_strerror (err));
return err;
}
@ -1574,6 +1728,7 @@ register_commands (assuan_context_t ctx)
{ "GETEVENTCOUNTER",cmd_geteventcounter },
{ "ISTRUSTED", cmd_istrusted },
{ "HAVEKEY", cmd_havekey },
{ "KEYINFO", cmd_keyinfo },
{ "SIGKEY", cmd_sigkey },
{ "SETKEY", cmd_sigkey },
{ "SETKEYDESC", cmd_setkeydesc },

View File

@ -28,16 +28,14 @@
#include <sys/stat.h>
#include "agent.h"
#include "sexp-parse.h"
#include "i18n.h"
#include "sexp-parse.h"
static int
ask_for_card (ctrl_t ctrl, const unsigned char *shadow_info, char **r_kid)
{
int rc, i;
const unsigned char *s;
size_t n;
char *serialno;
int no_card = 0;
char *desc;
@ -45,39 +43,19 @@ ask_for_card (ctrl_t ctrl, const unsigned char *shadow_info, char **r_kid)
int want_sn_displen;
*r_kid = NULL;
s = shadow_info;
if (*s != '(')
return gpg_error (GPG_ERR_INV_SEXP);
s++;
n = snext (&s);
if (!n)
return gpg_error (GPG_ERR_INV_SEXP);
want_sn = xtrymalloc (n*2+1);
if (!want_sn)
return out_of_core ();
for (i=0; i < n; i++)
sprintf (want_sn+2*i, "%02X", s[i]);
s += n;
rc = parse_shadow_info (shadow_info, &want_sn, &want_kid);
if (rc)
return rc;
/* We assume that a 20 byte serial number is a standard one which
seems to have the property to have a zero in the last nibble. We
don't display this '0' because it may confuse the user */
has the property to have a zero in the last nibble (Due to BCD
representation). We don't display this '0' because it may
confuse the user. */
want_sn_displen = strlen (want_sn);
if (want_sn_displen == 20 && want_sn[19] == '0')
want_sn_displen--;
n = snext (&s);
if (!n)
return gpg_error (GPG_ERR_INV_SEXP);
want_kid = xtrymalloc (n+1);
if (!want_kid)
{
gpg_error_t tmperr = out_of_core ();
xfree (want_sn);
return tmperr;
}
memcpy (want_kid, s, n);
want_kid[n] = 0;
for (;;)
{
rc = agent_card_serialno (ctrl, &serialno);

View File

@ -56,14 +56,12 @@ int
agent_write_private_key (const unsigned char *grip,
const void *buffer, size_t length, int force)
{
int i;
char *fname;
FILE *fp;
char hexgrip[40+4+1];
int fd;
for (i=0; i < 20; i++)
sprintf (hexgrip+2*i, "%02X", grip[i]);
bin2hex (grip, 20, hexgrip);
strcpy (hexgrip+40, ".key");
fname = make_filename (opt.homedir, GNUPG_PRIVATE_KEYS_DIR, hexgrip, NULL);
@ -307,14 +305,12 @@ unprotect (ctrl_t ctrl, const char *desc_text,
{
struct pin_entry_info_s *pi;
struct try_unprotect_arg_s arg;
int rc, i;
int rc;
unsigned char *result;
size_t resultlen;
char hexgrip[40+1];
for (i=0; i < 20; i++)
sprintf (hexgrip+2*i, "%02X", grip[i]);
hexgrip[40] = 0;
bin2hex (grip, 20, hexgrip);
/* First try to get it from the cache - if there is none or we can't
unprotect it, we fall back to ask the user */
@ -425,7 +421,7 @@ unprotect (ctrl_t ctrl, const char *desc_text,
static gpg_error_t
read_key_file (const unsigned char *grip, gcry_sexp_t *result)
{
int i, rc;
int rc;
char *fname;
FILE *fp;
struct stat st;
@ -436,8 +432,7 @@ read_key_file (const unsigned char *grip, gcry_sexp_t *result)
*result = NULL;
for (i=0; i < 20; i++)
sprintf (hexgrip+2*i, "%02X", grip[i]);
bin2hex (grip, 20, hexgrip);
strcpy (hexgrip+40, ".key");
fname = make_filename (opt.homedir, GNUPG_PRIVATE_KEYS_DIR, hexgrip, NULL);
@ -445,7 +440,8 @@ read_key_file (const unsigned char *grip, gcry_sexp_t *result)
if (!fp)
{
rc = gpg_error_from_syserror ();
log_error ("can't open `%s': %s\n", fname, strerror (errno));
if (gpg_err_code (rc) != GPG_ERR_ENOENT)
log_error ("can't open `%s': %s\n", fname, strerror (errno));
xfree (fname);
return rc;
}
@ -488,11 +484,11 @@ read_key_file (const unsigned char *grip, gcry_sexp_t *result)
/* Return the secret key as an S-Exp in RESULT after locating it using
the grip. Returns NULL in RESULT if the operation should be
diverted to a token; SHADOW_INFO will point then to an allocated
S-Expression with the shadow_info part from the file. CACHE_MODE
defines now the cache shall be used. DESC_TEXT may be set to
present a custom description for the pinentry. */
the GRIP. Stores NULL at RESULT if the operation shall be diverted
to a token; in this case an allocated S-expression with the
shadow_info part from the file is stored at SHADOW_INFO.
CACHE_MODE defines now the cache shall be used. DESC_TEXT may be
set to present a custom description for the pinentry. */
gpg_error_t
agent_key_from_file (ctrl_t ctrl, const char *desc_text,
const unsigned char *grip, unsigned char **shadow_info,
@ -513,20 +509,11 @@ agent_key_from_file (ctrl_t ctrl, const char *desc_text,
return rc;
/* For use with the protection functions we also need the key as an
canonical encoded S-expression in abuffer. Create this buffer
canonical encoded S-expression in a buffer. Create this buffer
now. */
len = gcry_sexp_sprint (s_skey, GCRYSEXP_FMT_CANON, NULL, 0);
assert (len);
buf = xtrymalloc (len);
if (!buf)
{
rc = gpg_error_from_syserror ();
gcry_sexp_release (s_skey);
return rc;
}
len = gcry_sexp_sprint (s_skey, GCRYSEXP_FMT_CANON, buf, len);
assert (len);
rc = make_canon_sexp (s_skey, &buf, &len);
if (rc)
return rc;
switch (agent_private_key_type (buf))
{
@ -842,19 +829,94 @@ agent_public_key_from_file (ctrl_t ctrl,
int
agent_key_available (const unsigned char *grip)
{
int i;
int result;
char *fname;
char hexgrip[40+4+1];
for (i=0; i < 20; i++)
sprintf (hexgrip+2*i, "%02X", grip[i]);
bin2hex (grip, 20, hexgrip);
strcpy (hexgrip+40, ".key");
fname = make_filename (opt.homedir, GNUPG_PRIVATE_KEYS_DIR, hexgrip, NULL);
i = !access (fname, R_OK)? 0 : -1;
result = !access (fname, R_OK)? 0 : -1;
xfree (fname);
return i;
return result;
}
/* Return the information about the secret key specified by the binary
keygrip GRIP. If the key is a shadowed one the shadow information
will be stored at the address R_SHADOW_INFO as an allocated
S-expression. */
gpg_error_t
agent_key_info_from_file (ctrl_t ctrl, const unsigned char *grip,
int *r_keytype, unsigned char **r_shadow_info)
{
gpg_error_t err;
unsigned char *buf;
size_t len;
int keytype;
(void)ctrl;
if (r_keytype)
*r_keytype = PRIVATE_KEY_UNKNOWN;
if (r_shadow_info)
*r_shadow_info = NULL;
{
gcry_sexp_t sexp;
err = read_key_file (grip, &sexp);
if (err)
{
if (gpg_err_code (err) == GPG_ERR_ENOENT)
return gpg_error (GPG_ERR_NOT_FOUND);
else
return err;
}
err = make_canon_sexp (sexp, &buf, &len);
gcry_sexp_release (sexp);
if (err)
return err;
}
keytype = agent_private_key_type (buf);
switch (keytype)
{
case PRIVATE_KEY_CLEAR:
break;
case PRIVATE_KEY_PROTECTED:
/* If we ever require it we could retrieve the comment fields
from such a key. */
break;
case PRIVATE_KEY_SHADOWED:
if (r_shadow_info)
{
const unsigned char *s;
size_t n;
err = agent_get_shadow_info (buf, &s);
if (!err)
{
n = gcry_sexp_canon_len (s, 0, NULL, NULL);
assert (n);
*r_shadow_info = xtrymalloc (n);
if (!*r_shadow_info)
err = gpg_error_from_syserror ();
else
memcpy (*r_shadow_info, s, n);
}
}
break;
default:
err = gpg_error (GPG_ERR_BAD_SECKEY);
break;
}
if (!err && r_keytype)
*r_keytype = keytype;
xfree (buf);
return err;
}

View File

@ -1,6 +1,6 @@
/* protect.c - Un/Protect a secret key
* Copyright (C) 1998, 1999, 2000, 2001, 2002,
* 2003, 2007 Free Software Foundation, Inc.
* 2003, 2007, 2009 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@ -1105,3 +1105,68 @@ agent_get_shadow_info (const unsigned char *shadowkey,
return 0;
}
/* Parse the canonical encoded SHADOW_INFO S-expression. On success
the hex encoded serial number is returned as a malloced strings at
R_HEXSN and the Id string as a malloced string at R_IDSTR. On
error an error code is returned and NULL is stored at the result
parameters addresses. If the serial number or the ID string is not
required, NULL may be passed for them. */
gpg_error_t
parse_shadow_info (const unsigned char *shadow_info,
char **r_hexsn, char **r_idstr)
{
const unsigned char *s;
size_t n;
if (r_hexsn)
*r_hexsn = NULL;
if (r_idstr)
*r_idstr = NULL;
s = shadow_info;
if (*s != '(')
return gpg_error (GPG_ERR_INV_SEXP);
s++;
n = snext (&s);
if (!n)
return gpg_error (GPG_ERR_INV_SEXP);
if (r_hexsn)
{
*r_hexsn = bin2hex (s, n, NULL);
if (!*r_hexsn)
return gpg_error_from_syserror ();
}
s += n;
n = snext (&s);
if (!n)
{
if (r_hexsn)
{
xfree (*r_hexsn);
*r_hexsn = NULL;
}
return gpg_error (GPG_ERR_INV_SEXP);
}
if (r_idstr)
{
*r_idstr = xtrymalloc (n+1);
if (!*r_idstr)
{
if (r_hexsn)
{
xfree (*r_hexsn);
*r_hexsn = NULL;
}
return gpg_error_from_syserror ();
}
memcpy (*r_idstr, s, n);
(*r_idstr)[n] = 0;
}
return 0;
}

View File

@ -1,3 +1,7 @@
2009-03-06 Werner Koch <wk@g10code.com>
* sexputil.c (make_canon_sexp): New.
2009-03-03 Werner Koch <wk@g10code.com>
* exechelp.c (do_exec): Make sure that /dev/null connected FDs are

View File

@ -1,5 +1,5 @@
/* sexputil.c - Utility functions for S-expressions.
* Copyright (C) 2005, 2007 Free Software Foundation, Inc.
* Copyright (C) 2005, 2007, 2009 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@ -34,6 +34,42 @@
#include "util.h"
#include "sexp-parse.h"
/* Helper function to create a a canonical encoded S-expression from a
Libgcrypt S-expression object. The function returns 0 on success
and the malloced canonical S-expression is stored at R_BUFFER and
the allocated length at R_BUFLEN. On error an error code is
returned and (NULL, 0) stored at R_BUFFER and R_BUFLEN. If the
allocated buffer length is not required, NULL by be used for
R_BUFLEN. */
gpg_error_t
make_canon_sexp (gcry_sexp_t sexp, unsigned char **r_buffer, size_t *r_buflen)
{
size_t len;
unsigned char *buf;
*r_buffer = NULL;
if (r_buflen)
*r_buflen = 0;;
len = gcry_sexp_sprint (sexp, GCRYSEXP_FMT_CANON, NULL, 0);
if (!len)
return gpg_error (GPG_ERR_BUG);
buf = xtrymalloc (len);
if (!buf)
return gpg_error_from_syserror ();
len = gcry_sexp_sprint (sexp, GCRYSEXP_FMT_CANON, buf, len);
if (!len)
return gpg_error (GPG_ERR_BUG);
*r_buffer = buf;
if (r_buflen)
*r_buflen = len;
return 0;
}
/* Return the so called "keygrip" which is the SHA-1 hash of the
public key parameters expressed in a way depended on the algorithm.

View File

@ -1,5 +1,5 @@
/* util.h - Utility functions for GnuPG
* Copyright (C) 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
* Copyright (C) 2001, 2002, 2003, 2004, 2009 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@ -183,6 +183,8 @@ gpg_error_t b64dec_finish (struct b64state *state);
/*-- sexputil.c */
gpg_error_t make_canon_sexp (gcry_sexp_t sexp,
unsigned char **r_buffer, size_t *r_buflen);
gpg_error_t keygrip_from_canon_sexp (const unsigned char *key, size_t keylen,
unsigned char *grip);
int cmp_simple_canon_sexp (const unsigned char *a, const unsigned char *b);

View File

@ -240,10 +240,12 @@ optional @var{pattern}. Those pattern consist of a list of user ids
(@pxref{how-to-specify-a-user-id}). When used along with the
@option{--armor} option a few informational lines are prepended before
each block. There is one limitation: As there is no commonly agreed
upon way to pack more than one certificate into an ASN.1 structure, the
binary export (i.e. without using @option{armor}) works only for the
export of one certificate. Thus it is required to specify a
@var{pattern} which yields exactly one certificate.
upon way to pack more than one certificate into an ASN.1 structure,
the binary export (i.e. without using @option{armor}) works only for
the export of one certificate. Thus it is required to specify a
@var{pattern} which yields exactly one certificate. Ephemeral
certificate are only exported if all @var{pattern} are given as
fingerprints or keygrips.
@item --export-secret-key-p12 @var{key-id}
@opindex export
@ -601,7 +603,9 @@ forth to @var{epoch} which is the number of seconds elapsed since the year
@item --with-ephemeral-keys
@opindex with-ephemeral-keys
Include ephemeral flagged keys in the output of key listings.
Include ephemeral flagged keys in the output of key listings. Note
that they are included anyway if the key specification for a listing
is given as fingerprint or keygrip.
@item --debug-level @var{level}
@opindex debug-level

View File

@ -457,7 +457,7 @@ blob_cmp_mail (KEYBOXBLOB blob, const char *name, size_t namelen, int substr)
#ifdef KEYBOX_WITH_X509
/* Return true if the key in BLOB matches the 20 bytes keygrip GRIP.
We don't have the keygrips as meta data, thus wen need to parse the
We don't have the keygrips as meta data, thus we need to parse the
certificate. Fixme: We might want to return proper error codes
instead of failing a search for invalid certificates etc. */
static int

View File

@ -1,3 +1,10 @@
2009-03-06 Werner Koch <wk@g10code.com>
* app-nks.c (do_learn_status): Factor code out to..
(do_learn_status_core): .. new.
(do_readcert, do_sign, do_decipher): Switch to SigG if needed.
(verify_pin): Use DESC also for keypad based verify.
2009-03-05 Werner Koch <wk@g10code.com>
* app-openpgp.c (verify_a_chv): Remove special case for keypads.

View File

@ -308,17 +308,20 @@ do_getattr (app_t app, ctrl_t ctrl, const char *name)
static gpg_error_t
do_learn_status (app_t app, ctrl_t ctrl)
static void
do_learn_status_core (app_t app, ctrl_t ctrl, int is_sigg)
{
gpg_error_t err;
char ct_buf[100], id_buf[100];
int i;
const char *tag;
err = switch_application (app, 0);
if (err)
return err;
if (is_sigg)
tag = "SIGG";
else if (app->app_local->nks_version < 3)
tag = "DF01";
else
tag = "NKS3";
/* Output information about all useful objects in the NKS application. */
for (i=0; filelist[i].fid; i++)
@ -326,7 +329,7 @@ do_learn_status (app_t app, ctrl_t ctrl)
if (filelist[i].nks_ver > app->app_local->nks_version)
continue;
if (filelist[i].is_sigg)
if (!!filelist[i].is_sigg != !!is_sigg)
continue;
if (filelist[i].certtype)
@ -342,8 +345,7 @@ do_learn_status (app_t app, ctrl_t ctrl)
read that many bytes. */
snprintf (ct_buf, sizeof ct_buf, "%d", filelist[i].certtype);
snprintf (id_buf, sizeof id_buf, "NKS-%s.%04X",
app->app_local->nks_version < 3? "DF01":"NKS3",
filelist[i].fid);
tag, filelist[i].fid);
send_status_info (ctrl, "CERTINFO",
ct_buf, strlen (ct_buf),
id_buf, strlen (id_buf),
@ -361,8 +363,7 @@ do_learn_status (app_t app, ctrl_t ctrl)
else
{
snprintf (id_buf, sizeof id_buf, "NKS-%s.%04X",
app->app_local->nks_version < 3? "DF01":"NKS3",
filelist[i].fid);
tag, filelist[i].fid);
send_status_info (ctrl, "KEYPAIRINFO",
gripstr, 40,
id_buf, strlen (id_buf),
@ -371,58 +372,26 @@ do_learn_status (app_t app, ctrl_t ctrl)
}
}
}
static gpg_error_t
do_learn_status (app_t app, ctrl_t ctrl)
{
gpg_error_t err;
err = switch_application (app, 0);
if (err)
return err;
do_learn_status_core (app, ctrl, 0);
err = switch_application (app, 1);
if (err)
return 0; /* Silently ignore if we can't swicth to SigG. */
for (i=0; filelist[i].fid; i++)
{
if (filelist[i].nks_ver > app->app_local->nks_version)
continue;
if (!filelist[i].is_sigg)
continue;
if (filelist[i].certtype)
{
size_t len;
len = app_help_read_length_of_cert (app->slot,
filelist[i].fid, NULL);
if (len)
{
/* FIXME: We should store the length in the application's
context so that a following readcert does only need to
read that many bytes. */
snprintf (ct_buf, sizeof ct_buf, "%d", filelist[i].certtype);
snprintf (id_buf, sizeof id_buf, "NKS-SIGG.%04X",
filelist[i].fid);
send_status_info (ctrl, "CERTINFO",
ct_buf, strlen (ct_buf),
id_buf, strlen (id_buf),
NULL, (size_t)0);
}
}
else if (filelist[i].iskeypair)
{
char gripstr[40+1];
err = keygripstr_from_pk_file (app, filelist[i].fid, gripstr);
if (err)
log_error ("can't get keygrip from FID 0x%04X: %s\n",
filelist[i].fid, gpg_strerror (err));
else
{
snprintf (id_buf, sizeof id_buf, "NKS-SIGG.%04X",
filelist[i].fid);
send_status_info (ctrl, "KEYPAIRINFO",
gripstr, 40,
id_buf, strlen (id_buf),
NULL, (size_t)0);
}
}
}
return 0; /* Silently ignore if we can't switch to SigG. */
do_learn_status_core (app, ctrl, 1);
return 0;
}
@ -446,20 +415,24 @@ do_readcert (app_t app, const char *certid,
int class, tag, constructed, ndef;
size_t totobjlen, objlen, hdrlen;
int rootca = 0;
int is_sigg = 0;
*cert = NULL;
*certlen = 0;
err = switch_application (app, 0);
if (err)
return err;
if (!strncmp (certid, "NKS-NKS3.", 9))
;
else if (!strncmp (certid, "NKS-DF01.", 9))
;
else if (!strncmp (certid, "NKS-SIGG.", 9))
is_sigg = 1;
else
return gpg_error (GPG_ERR_INV_ID);
err = switch_application (app, is_sigg);
if (err)
return err;
certid += 9;
if (!hexdigitp (certid) || !hexdigitp (certid+1)
|| !hexdigitp (certid+2) || !hexdigitp (certid+3)
@ -603,9 +576,7 @@ verify_pin (app_t app, int pwid, const char *desc,
if (!opt.disable_keypad
&& !iso7816_check_keypad (app->slot, ISO7816_VERIFY, &pininfo) )
{
rc = pincb (pincb_arg,
_("||Please enter your PIN at the reader's keypad"),
NULL);
rc = pincb (pincb_arg, desc, NULL);
if (rc)
{
log_info (_("PIN callback returned error: %s\n"),
@ -613,11 +584,8 @@ verify_pin (app_t app, int pwid, const char *desc,
return rc;
}
/* Although it is possible to use a local PIN, we use the global
PIN for this application. */
rc = iso7816_verify_kp (app->slot, 0, "", 0, &pininfo);
/* Dismiss the prompt. */
pincb (pincb_arg, NULL, NULL);
rc = iso7816_verify_kp (app->slot, pwid, "", 0, &pininfo);
pincb (pincb_arg, NULL, NULL); /* Dismiss the prompt. */
}
else
{
@ -630,8 +598,6 @@ verify_pin (app_t app, int pwid, const char *desc,
return rc;
}
/* The following limits are due to TCOS but also defined in the
NKS specs. */
rc = basic_pin_checks (pinvalue, pininfo.minlen, pininfo.maxlen);
if (rc)
{
@ -675,6 +641,7 @@ do_sign (app_t app, const char *keyidstr, int hashalgo,
{ 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x24, 0x03,
0x02, 0x01, 0x05, 0x00, 0x04, 0x14 };
int rc, i;
int is_sigg = 0;
int fid;
unsigned char data[35]; /* Must be large enough for a SHA-1 digest
+ the largest OID _prefix above. */
@ -684,19 +651,22 @@ do_sign (app_t app, const char *keyidstr, int hashalgo,
if (indatalen != 20 && indatalen != 16 && indatalen != 35)
return gpg_error (GPG_ERR_INV_VALUE);
rc = switch_application (app, 0);
if (rc)
return rc;
/* Check that the provided ID is valid. This is not really needed
but we do it to enforce correct usage by the caller. */
if (!strncmp (keyidstr, "NKS-NKS3.", 9) )
;
else if (!strncmp (keyidstr, "NKS-DF01.", 9) )
;
else if (!strncmp (keyidstr, "NKS-SIGG.", 9) )
is_sigg = 1;
else
return gpg_error (GPG_ERR_INV_ID);
keyidstr += 9;
rc = switch_application (app, is_sigg);
if (rc)
return rc;
if (!hexdigitp (keyidstr) || !hexdigitp (keyidstr+1)
|| !hexdigitp (keyidstr+2) || !hexdigitp (keyidstr+3)
|| keyidstr[4])
@ -743,7 +713,6 @@ do_sign (app_t app, const char *keyidstr, int hashalgo,
/* Decrypt the data in INDATA and return the allocated result in OUTDATA.
If a PIN is required the PINCB will be used to ask for the PIN; it
should return the PIN in an allocated buffer and put it into PIN. */
@ -759,24 +728,28 @@ do_decipher (app_t app, const char *keyidstr,
0x84, 1, 0x81 /* Select local secret key 1 for decryption. */
};
int rc, i;
int is_sigg = 0;
int fid;
if (!keyidstr || !*keyidstr || !indatalen)
return gpg_error (GPG_ERR_INV_VALUE);
rc = switch_application (app, 0);
if (rc)
return rc;
/* Check that the provided ID is valid. This is not really needed
but we do it to to enforce correct usage by the caller. */
if (!strncmp (keyidstr, "NKS-NKS3.", 9) )
;
else if (!strncmp (keyidstr, "NKS-DF01.", 9) )
;
else if (!strncmp (keyidstr, "NKS-SIGG.", 9) )
is_sigg = 1;
else
return gpg_error (GPG_ERR_INV_ID);
keyidstr += 9;
rc = switch_application (app, is_sigg);
if (rc)
return rc;
if (!hexdigitp (keyidstr) || !hexdigitp (keyidstr+1)
|| !hexdigitp (keyidstr+2) || !hexdigitp (keyidstr+3)
|| keyidstr[4])

View File

@ -1,3 +1,14 @@
2009-03-06 Werner Koch <wk@g10code.com>
* call-agent.c (gpgsm_agent_keyinfo, keyinfo_status_cb): New.
* keylist.c (list_cert_colon): Print card S/N.
* keylist.c (list_internal_keys): Always list ephemeral keys if
specified by keygrip or fingerprint.
(list_cert_raw): Always show ephemeral flag.
* export.c (gpgsm_export): Export ephemeral keys if specified by
keygrip.
2009-02-09 Werner Koch <wk@g10code.com>
* gpgsm.c (main): Change default cipher back to 3DES.
@ -2451,7 +2462,7 @@ h2007-11-22 Werner Koch <wk@g10code.com>
Copyright 2001, 2002, 2003, 2004, 2005, 2006,
2007, 2008 Free Software Foundation, Inc.
2007, 2008, 2009 Free Software Foundation, Inc.
This file is free software; as a special exception the author gives
unlimited permission to copy and/or distribute it, with or without

View File

@ -1,6 +1,6 @@
/* call-agent.c - Divert GPGSM operations to the agent
* Copyright (C) 2001, 2002, 2003, 2005, 2007,
* 2008 Free Software Foundation, Inc.
* 2008, 2009 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@ -836,3 +836,68 @@ gpgsm_agent_send_nop (ctrl_t ctrl)
}
static int
keyinfo_status_cb (void *opaque, const char *line)
{
char **serialno = opaque;
const char *s, *s2;
if (!strncmp (line, "KEYINFO ", 8) && !*serialno)
{
s = strchr (line+8, ' ');
if (s && s[1] == 'T' && s[2] == ' ' && s[3])
{
s += 3;
s2 = strchr (s, ' ');
if ( s2 > s )
{
*serialno = xtrymalloc ((s2 - s)+1);
if (*serialno)
{
memcpy (*serialno, s, s2 - s);
(*serialno)[s2 - s] = 0;
}
}
}
}
return 0;
}
/* Return the serial number for a secret key. If the returned serial
number is NULL, the key is not stored on a smartcard. Caller needs
to free R_SERIALNO. */
gpg_error_t
gpgsm_agent_keyinfo (ctrl_t ctrl, const char *hexkeygrip, char **r_serialno)
{
gpg_error_t err;
char line[ASSUAN_LINELENGTH];
char *serialno = NULL;
*r_serialno = NULL;
err = start_agent (ctrl);
if (err)
return err;
if (!hexkeygrip || strlen (hexkeygrip) != 40)
return gpg_error (GPG_ERR_INV_VALUE);
snprintf (line, DIM(line)-1, "KEYINFO %s", hexkeygrip);
line[DIM(line)-1] = 0;
err = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL,
keyinfo_status_cb, &serialno);
if (!err && serialno)
{
/* Sanity check for bad characters. */
if (strpbrk (serialno, ":\n\r"))
err = GPG_ERR_INV_VALUE;
}
if (err)
xfree (serialno);
else
*r_serialno = serialno;
return err;
}

View File

@ -1,5 +1,5 @@
/* export.c - Export certificates and private keys.
* Copyright (C) 2002, 2003, 2004, 2007 Free Software Foundation, Inc.
* Copyright (C) 2002, 2003, 2004, 2007, 2009 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@ -37,11 +37,11 @@
/* A table to store a fingerprint as used in a duplicates table. We
don't need to hash here because a fingerprint is alrady a perfect
don't need to hash here because a fingerprint is already a perfect
hash value. This we use the most significant bits to index the
table and then use a linked list for the overflow. Possible
enhancement for very large number of certictates: Add a second
level table and then resort to a linked list. */
enhancement for very large number of certificates: Add a second
level table and then resort to a linked list. */
struct duptable_s
{
struct duptable_s *next;
@ -192,18 +192,16 @@ gpgsm_export (ctrl_t ctrl, strlist_t names, FILE *fp, estream_t stream)
}
}
/* If all specifications are done by fingerprint, we switch to
ephemeral mode so that _all_ currently available and matching
certificates are exported.
fixme: we should in this case keep a list of certificates to
avoid accidential export of duplicate certificates. */
/* If all specifications are done by fingerprint or keygrip, we
switch to ephemeral mode so that _all_ currently available and
matching certificates are exported. */
if (names && ndesc)
{
for (i=0; (i < ndesc
&& (desc[i].mode == KEYDB_SEARCH_MODE_FPR
|| desc[i].mode == KEYDB_SEARCH_MODE_FPR20
|| desc[i].mode == KEYDB_SEARCH_MODE_FPR16)); i++)
|| desc[i].mode == KEYDB_SEARCH_MODE_FPR16
|| desc[i].mode == KEYDB_SEARCH_MODE_KEYGRIP)); i++)
;
if (i == ndesc)
keydb_set_ephemeral (hd, 1);
@ -228,7 +226,7 @@ gpgsm_export (ctrl_t ctrl, strlist_t names, FILE *fp, estream_t stream)
rc = insert_duptable (dtable, fpr, &exists);
if (rc)
{
log_error ("inserting into duplicates table fauiled: %s\n",
log_error ("inserting into duplicates table failed: %s\n",
gpg_strerror (rc));
goto leave;
}

View File

@ -196,8 +196,8 @@ gpgsm_get_keygrip (ksba_cert_t cert, unsigned char *array)
return array;
}
/* Return an allocated buffer with the keygrip of CERT in from of an
hexstring. NULL is returned in case of error */
/* Return an allocated buffer with the keygrip of CERT encoded as a
hexstring. NULL is returned in case of error. */
char *
gpgsm_get_keygrip_hexstring (ksba_cert_t cert)
{

View File

@ -395,6 +395,8 @@ int gpgsm_agent_learn (ctrl_t ctrl);
int gpgsm_agent_passwd (ctrl_t ctrl, const char *hexkeygrip, const char *desc);
gpg_error_t gpgsm_agent_get_confirmation (ctrl_t ctrl, const char *desc);
gpg_error_t gpgsm_agent_send_nop (ctrl_t ctrl);
gpg_error_t gpgsm_agent_keyinfo (ctrl_t ctrl, const char *hexkeygrip,
char **r_serialno);
/*-- call-dirmngr.c --*/
int gpgsm_dirmngr_isvalid (ctrl_t ctrl,

View File

@ -1,6 +1,6 @@
/* keylist.c - Print certificates in various formats.
* Copyright (C) 1998, 1999, 2000, 2001, 2003,
* 2004, 2005, 2008 Free Software Foundation, Inc.
* 2004, 2005, 2008, 2009 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@ -481,7 +481,24 @@ list_cert_colon (ctrl_t ctrl, ksba_cert_t cert, unsigned int validity,
es_putc (':', fp);
/* Field 12, capabilities: */
print_capabilities (cert, fp);
/* Field 13, not used: */
es_putc (':', fp);
if (have_secret)
{
char *cardsn;
p = gpgsm_get_keygrip_hexstring (cert);
if (!gpgsm_agent_keyinfo (ctrl, p, &cardsn) && cardsn)
{
/* Field 14, not used: */
es_putc (':', fp);
/* Field 15: Token serial number. */
es_fputs (cardsn, fp);
es_putc (':', fp);
}
xfree (cardsn);
xfree (p);
}
es_putc ('\n', fp);
/* FPR record */
@ -989,7 +1006,7 @@ list_cert_raw (ctrl_t ctrl, KEYDB_HANDLE hd,
es_fprintf (fp, " [certificate is bad: %s]\n", gpg_strerror (err));
}
if (opt.with_ephemeral_keys && hd)
if (hd)
{
unsigned int blobflags;
@ -1275,6 +1292,7 @@ list_internal_keys (ctrl_t ctrl, strlist_t names, estream_t fp,
gpg_error_t rc = 0;
const char *lastresname, *resname;
int have_secret;
int want_ephemeral = opt.with_ephemeral_keys;
hd = keydb_new (0);
if (!hd)
@ -1319,7 +1337,24 @@ list_internal_keys (ctrl_t ctrl, strlist_t names, estream_t fp,
}
if (opt.with_ephemeral_keys)
/* If all specifications are done by fingerprint or keygrip, we
switch to ephemeral mode so that _all_ currently available and
matching certificates are listed. */
if (!want_ephemeral && names && ndesc)
{
int i;
for (i=0; (i < ndesc
&& (desc[i].mode == KEYDB_SEARCH_MODE_FPR
|| desc[i].mode == KEYDB_SEARCH_MODE_FPR20
|| desc[i].mode == KEYDB_SEARCH_MODE_FPR16
|| desc[i].mode == KEYDB_SEARCH_MODE_KEYGRIP)); i++)
;
if (i == ndesc)
want_ephemeral = 1;
}
if (want_ephemeral)
keydb_set_ephemeral (hd, 1);
/* It would be nice to see which of the given users did actually