mirror of
git://git.gnupg.org/gnupg.git
synced 2024-12-22 10:19:57 +01:00
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:
parent
59d7a54e72
commit
a9c317a95c
6
NEWS
6
NEWS
@ -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)
|
||||
-------------------------------------------------
|
||||
|
@ -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
|
||||
|
@ -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 --*/
|
||||
|
161
agent/command.c
161
agent/command.c
@ -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 },
|
||||
|
@ -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);
|
||||
|
126
agent/findkey.c
126
agent/findkey.c
@ -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,6 +440,7 @@ read_key_file (const unsigned char *grip, gcry_sexp_t *result)
|
||||
if (!fp)
|
||||
{
|
||||
rc = gpg_error_from_syserror ();
|
||||
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);
|
||||
rc = make_canon_sexp (s_skey, &buf, &len);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
len = gcry_sexp_sprint (s_skey, GCRYSEXP_FMT_CANON, buf, len);
|
||||
assert (len);
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
139
scd/app-nks.c
139
scd/app-nks.c
@ -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])
|
||||
|
13
sm/ChangeLog
13
sm/ChangeLog
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
20
sm/export.c
20
sm/export.c
@ -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,10 +37,10 @@
|
||||
|
||||
|
||||
/* 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
|
||||
enhancement for very large number of certificates: Add a second
|
||||
level table and then resort to a linked list. */
|
||||
struct duptable_s
|
||||
{
|
||||
@ -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;
|
||||
}
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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,
|
||||
|
41
sm/keylist.c
41
sm/keylist.c
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user