1
0
Fork 0
mirror of git://git.gnupg.org/gnupg.git synced 2025-07-03 22:56:33 +02:00

First set of changes to backport the new card code from 2.0.

For compatibility reasons a few new files had to be added.
Also added estream-printf as this is now used in app-openpgp.c and provides
a better and generic asprintf implementation than the hack we used for the
W32 code in ttyio.c.  Card code is not yet finished.
This commit is contained in:
Werner Koch 2009-07-21 14:30:13 +00:00
parent b478389753
commit 3459c6b015
37 changed files with 7385 additions and 1694 deletions

View file

@ -1,3 +1,31 @@
2009-07-21 Werner Koch <wk@g10code.com>
* app-common.h, app-openpgp.c, iso7816.c, iso7816.h, apdu.c,
* apdu.h, ccid-driver.c, ccid-driver.h, card-util.c: Update from
GnuPG 2.0 SVN revision 5084.
* cardglue.h (GCRY_MD_SHA256): Add more GCRY_MD constants.
(gcry_handler_progress_t): Add definition.
(struct agent_card_info_s): Add fields apptype, is_v2, key_attr.
* cardglue.c (learn_status_cb): Set them.
(agent_release_card_info): Release APPTYPE.
(unescape_status_string, send_status_direct): New.
(gcry_mpi_release, gcry_mpi_set_opaque): New.
(gcry_md_algo_name): New.
(open_card): s/initialized/ref_count/.
(agent_learn): Pass new new flag arg to learn_status.
(agent_scd_genkey): Add new arg createtime.
* keygen.c (gen_card_key, gen_card_key_with_backup): Add new arg
TIMESTAMP.
(write_direct_sig, write_selfsigs, write_keybinding)
(make_backsig): Ditto.
(do_generate_keypair): Pass timestamp to all signing functions.
(generate_card_subkeypair): Ditto.
* keyedit.c (menu_backsign): Pass a new timestamp to all backsisg.
* gpg.c (main): Disable keypad support.
* options.h (struct): Add field disable_keypad.
2009-07-17 Werner Koch <wk@g10code.com>
* keyring.c (keyring_rebuild_cache): Replace the assert by a

1938
g10/apdu.c

File diff suppressed because it is too large Load diff

View file

@ -1,5 +1,5 @@
/* apdu.h - ISO 7816 APDU functions and low level I/O
* Copyright (C) 2003 Free Software Foundation, Inc.
* Copyright (C) 2003, 2008 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@ -29,8 +29,11 @@ enum {
SW_MORE_DATA = 0x6100, /* Note: that the low byte must be
masked of.*/
SW_EOF_REACHED = 0x6282,
SW_TERM_STATE = 0x6285, /* Selected file is in termination state. */
SW_EEPROM_FAILURE = 0x6581,
SW_WRONG_LENGTH = 0x6700,
SW_SM_NOT_SUP = 0x6882, /* Secure Messaging is not supported. */
SW_CC_NOT_SUP = 0x6884, /* Command Chaining is not supported. */
SW_CHV_WRONG = 0x6982,
SW_CHV_BLOCKED = 0x6983,
SW_USE_CONDITIONS = 0x6985,
@ -38,6 +41,7 @@ enum {
SW_NOT_SUPPORTED = 0x6a81,
SW_FILE_NOT_FOUND = 0x6a82,
SW_RECORD_NOT_FOUND = 0x6a83,
SW_BAD_LC = 0x6a87, /* Lc does not match command or p1/p2. */
SW_REF_NOT_FOUND = 0x6a88,
SW_BAD_P0_P1 = 0x6b00,
SW_EXACT_LENGTH = 0x6c00,
@ -62,13 +66,20 @@ enum {
SW_HOST_GENERAL_ERROR = 0x1000b,
SW_HOST_NO_READER = 0x1000c,
SW_HOST_ABORTED = 0x1000d,
SW_HOST_NO_KEYPAD = 0x1000e
SW_HOST_NO_KEYPAD = 0x1000e,
SW_HOST_ALREADY_CONNECTED = 0x1000f
};
#define SW_EXACT_LENGTH_P(a) (((a)&~0xff) == SW_EXACT_LENGTH)
/* Bit flags for the card status. */
#define APDU_CARD_USABLE (1) /* Card is present and ready for use. */
#define APDU_CARD_PRESENT (2) /* Card is just present. */
#define APDU_CARD_ACTIVE (4) /* Card is active. */
/* Note , that apdu_open_reader returns no status word but -1 on error. */
int apdu_open_reader (const char *portstr);
int apdu_open_remote_reader (const char *portstr,
@ -83,13 +94,19 @@ int apdu_open_remote_reader (const char *portstr,
void *closefnc_value);
int apdu_shutdown_reader (int slot);
int apdu_close_reader (int slot);
void apdu_prepare_exit (void);
int apdu_enum_reader (int slot, int *used);
unsigned char *apdu_get_atr (int slot, size_t *atrlen);
const char *apdu_strerror (int rc);
/* These apdu functions do return status words. */
/* These APDU functions return status words. */
int apdu_connect (int slot);
int apdu_disconnect (int slot);
int apdu_set_progress_cb (int slot, gcry_handler_progress_t cb, void *cb_arg);
int apdu_activate (int slot);
int apdu_reset (int slot);
@ -97,19 +114,21 @@ int apdu_get_status (int slot, int hang,
unsigned int *status, unsigned int *changed);
int apdu_check_keypad (int slot, int command, int pin_mode,
int pinlen_min, int pinlen_max, int pin_padlen);
int apdu_send_simple (int slot, int class, int ins, int p0, int p1,
int apdu_send_simple (int slot, int extended_mode,
int class, int ins, int p0, int p1,
int lc, const char *data);
int apdu_send_simple_kp (int slot, int class, int ins, int p0, int p1,
int lc, const char *data,
int pin_mode,
int pinlen_min, int pinlen_max, int pin_padlen);
int apdu_send (int slot, int class, int ins, int p0, int p1,
int lc, const char *data,
int apdu_send (int slot, int extended_mode,
int class, int ins, int p0, int p1, int lc, const char *data,
unsigned char **retbuf, size_t *retbuflen);
int apdu_send_le (int slot, int class, int ins, int p0, int p1,
int apdu_send_le (int slot, int extended_mode,
int class, int ins, int p0, int p1,
int lc, const char *data, int le,
unsigned char **retbuf, size_t *retbuflen);
int apdu_send_direct (int slot,
int apdu_send_direct (int slot, size_t extended_length,
const unsigned char *apdudata, size_t apdudatalen,
int handle_more,
unsigned char **retbuf, size_t *retbuflen);

View file

@ -1,5 +1,5 @@
/* app-common.h - Common declarations for all card applications
* Copyright (C) 2003, 2005 Free Software Foundation, Inc.
* Copyright (C) 2003, 2005, 2008 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@ -31,14 +31,26 @@
#endif
#define APP_CHANGE_FLAG_RESET 1
#define APP_CHANGE_FLAG_NULLPIN 2
struct app_local_s; /* Defined by all app-*.c. */
struct app_ctx_s {
int initialized; /* The application has been initialied and the
function pointers may be used. Note that for
unsupported operations the particular
function pointer is set to NULL */
int slot; /* Used reader. */
/* Number of connections currently using this application context.
If this is not 0 the application has been initialized and the
function pointers may be used. Note that for unsupported
operations the particular function pointer is set to NULL */
unsigned int ref_count;
/* Flag indicating that a reset has been done for that application
and that this context is merely lingering and just should not be
reused. */
int no_reuse;
/* Used reader slot. */
int slot;
/* If this is used by GnuPG 1.4 we need to know the assuan context
in case we need to divert the operation to an already running
@ -59,7 +71,7 @@ struct app_ctx_s {
struct app_local_s *app_local; /* Local to the application. */
struct {
void (*deinit) (app_t app);
gpg_error_t (*learn_status) (app_t app, ctrl_t ctrl);
gpg_error_t (*learn_status) (app_t app, ctrl_t ctrl, unsigned int flags);
gpg_error_t (*readcert) (app_t app, const char *certid,
unsigned char **cert, size_t *certlen);
gpg_error_t (*readkey) (app_t app, const char *certid,
@ -85,17 +97,23 @@ struct app_ctx_s {
void *pincb_arg,
const void *indata, size_t indatalen,
unsigned char **outdata, size_t *outdatalen);
gpg_error_t (*writecert) (app_t app, ctrl_t ctrl,
const char *certid,
gpg_error_t (*pincb)(void*,const char *,char **),
void *pincb_arg,
const unsigned char *data, size_t datalen);
gpg_error_t (*writekey) (app_t app, ctrl_t ctrl,
const char *certid, unsigned int flags,
const char *keyid, unsigned int flags,
gpg_error_t (*pincb)(void*,const char *,char **),
void *pincb_arg,
const unsigned char *pk, size_t pklen);
gpg_error_t (*genkey) (app_t app, ctrl_t ctrl,
const char *keynostr, unsigned int flags,
gpg_error_t (*pincb)(void*, const char *, char **),
void *pincb_arg);
const char *keynostr, unsigned int flags,
time_t createtime,
gpg_error_t (*pincb)(void*, const char *, char **),
void *pincb_arg);
gpg_error_t (*change_pin) (app_t app, ctrl_t ctrl,
const char *chvnostr, int reset_mode,
const char *chvnostr, unsigned int flags,
gpg_error_t (*pincb)(void*, const char *, char **),
void *pincb_arg);
gpg_error_t (*check_pin) (app_t app, const char *keyidstr,
@ -117,17 +135,23 @@ gpg_error_t app_openpgp_storekey (app_t app, int keyno,
void *pincb_arg);
#else
/*-- app-help.c --*/
unsigned int app_help_count_bits (const unsigned char *a, size_t len);
gpg_error_t app_help_get_keygrip_string (ksba_cert_t cert, char *hexkeygrip);
size_t app_help_read_length_of_cert (int slot, int fid, size_t *r_certoff);
/*-- app.c --*/
void app_dump_state (void);
void application_notify_card_reset (int slot);
gpg_error_t check_application_conflict (ctrl_t ctrl, const char *name);
gpg_error_t select_application (ctrl_t ctrl, int slot, const char *name,
app_t *r_app);
char *get_supported_applications (void);
void release_application (app_t app);
gpg_error_t app_munge_serialno (app_t app);
gpg_error_t app_get_serial_and_stamp (app_t app, char **serial, time_t *stamp);
gpg_error_t app_write_learn_status (app_t app, ctrl_t ctrl);
gpg_error_t app_write_learn_status (app_t app, ctrl_t ctrl,
unsigned int flags);
gpg_error_t app_readcert (app_t app, const char *certid,
unsigned char **cert, size_t *certlen);
gpg_error_t app_readkey (app_t app, const char *keyid,
@ -152,15 +176,21 @@ gpg_error_t app_decipher (app_t app, const char *keyidstr,
void *pincb_arg,
const void *indata, size_t indatalen,
unsigned char **outdata, size_t *outdatalen );
gpg_error_t app_writecert (app_t app, ctrl_t ctrl,
const char *certidstr,
gpg_error_t (*pincb)(void*, const char *, char **),
void *pincb_arg,
const unsigned char *keydata, size_t keydatalen);
gpg_error_t app_writekey (app_t app, ctrl_t ctrl,
const char *keyidstr, unsigned int flags,
gpg_error_t (*pincb)(void*, const char *, char **),
void *pincb_arg,
const unsigned char *keydata, size_t keydatalen);
gpg_error_t app_genkey (app_t app, ctrl_t ctrl,
const char *keynostr, unsigned int flags,
gpg_error_t (*pincb)(void*, const char *, char **),
void *pincb_arg);
const char *keynostr, unsigned int flags,
time_t createtime,
gpg_error_t (*pincb)(void*, const char *, char **),
void *pincb_arg);
gpg_error_t app_get_challenge (app_t app, size_t nbytes,
unsigned char *buffer);
gpg_error_t app_change_pin (app_t app, ctrl_t ctrl,
@ -184,6 +214,9 @@ gpg_error_t app_select_dinsig (app_t app);
/*-- app-p15.c --*/
gpg_error_t app_select_p15 (app_t app);
/*-- app-geldkarte.c --*/
gpg_error_t app_select_geldkarte (app_t app);
#endif

File diff suppressed because it is too large Load diff

View file

@ -1,5 +1,5 @@
/* card-util.c - Utility functions for the OpenPGP card.
* Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
* Copyright (C) 2003, 2004, 2005, 2009 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@ -25,7 +25,7 @@
#include <assert.h>
#if GNUPG_MAJOR_VERSION != 1
#include "gpg.h"
# include "gpg.h"
#endif /*GNUPG_MAJOR_VERSION != 1*/
#include "util.h"
#include "i18n.h"
@ -35,22 +35,46 @@
#include "main.h"
#include "keyserver-internal.h"
#if GNUPG_MAJOR_VERSION == 1
#ifdef HAVE_LIBREADLINE
#include <stdio.h>
#include <readline/readline.h>
#endif /*HAVE_LIBREADLINE*/
#include "cardglue.h"
# ifdef HAVE_LIBREADLINE
# define GNUPG_LIBREADLINE_H_INCLUDED
# include <stdio.h>
# include <readline/readline.h>
# endif /*HAVE_LIBREADLINE*/
# include "cardglue.h"
#else /*GNUPG_MAJOR_VERSION!=1*/
#include "call-agent.h"
# include "call-agent.h"
#endif /*GNUPG_MAJOR_VERSION!=1*/
#define CONTROL_D ('D' - 'A' + 1)
static void
write_sc_op_status (gpg_error_t err)
{
switch (gpg_err_code (err))
{
case 0:
write_status (STATUS_SC_OP_SUCCESS);
break;
#if GNUPG_MAJOR_VERSION != 1
case GPG_ERR_CANCELED:
write_status_text (STATUS_SC_OP_FAILURE, "1");
break;
case GPG_ERR_BAD_PIN:
write_status_text (STATUS_SC_OP_FAILURE, "2");
break;
default:
write_status (STATUS_SC_OP_FAILURE);
break;
#endif /* GNUPG_MAJOR_VERSION != 1 */
}
}
/* Change the PIN of a an OpenPGP card. This is an interactive
function. */
void
change_pin (int chvno, int allow_admin)
change_pin (int unblock_v2, int allow_admin)
{
struct agent_card_info_s info;
int rc;
@ -75,16 +99,31 @@ change_pin (int chvno, int allow_admin)
return;
}
if(!allow_admin)
if (unblock_v2)
{
if (!info.is_v2)
log_error (_("This command is only available for version 2 cards\n"));
else if (!info.chvretry[1])
log_error (_("Reset Code not or not anymore available\n"));
else
{
rc = agent_scd_change_pin (2, info.serialno);
write_sc_op_status (rc);
if (rc)
tty_printf ("Error changing the PIN: %s\n", gpg_strerror (rc));
else
tty_printf ("PIN changed.\n");
}
}
else if (!allow_admin)
{
rc = agent_scd_change_pin (1, info.serialno);
write_sc_op_status (rc);
if (rc)
tty_printf ("Error changing the PIN: %s\n", gpg_strerror (rc));
else
{
write_status (STATUS_SC_OP_SUCCESS);
tty_printf ("PIN changed.\n");
}
tty_printf ("PIN changed.\n");
}
else
for (;;)
@ -95,6 +134,7 @@ change_pin (int chvno, int allow_admin)
tty_printf ("1 - change PIN\n"
"2 - unblock PIN\n"
"3 - change Admin PIN\n"
"4 - set the Reset Code\n"
"Q - quit\n");
tty_printf ("\n");
@ -106,36 +146,44 @@ change_pin (int chvno, int allow_admin)
rc = 0;
if (*answer == '1')
{
/* Change PIN. */
rc = agent_scd_change_pin (1, info.serialno);
write_sc_op_status (rc);
if (rc)
tty_printf ("Error changing the PIN: %s\n", gpg_strerror (rc));
else
{
write_status (STATUS_SC_OP_SUCCESS);
tty_printf ("PIN changed.\n");
}
tty_printf ("PIN changed.\n");
}
else if (*answer == '2')
{
/* Unblock PIN. */
rc = agent_scd_change_pin (101, info.serialno);
write_sc_op_status (rc);
if (rc)
tty_printf ("Error unblocking the PIN: %s\n", gpg_strerror (rc));
else
{
write_status (STATUS_SC_OP_SUCCESS);
tty_printf ("PIN unblocked and new PIN set.\n");
}
tty_printf ("PIN unblocked and new PIN set.\n");
}
else if (*answer == '3')
{
/* Change Admin PIN. */
rc = agent_scd_change_pin (3, info.serialno);
write_sc_op_status (rc);
if (rc)
tty_printf ("Error changing the PIN: %s\n", gpg_strerror (rc));
else
{
write_status (STATUS_SC_OP_SUCCESS);
tty_printf ("PIN changed.\n");
}
tty_printf ("PIN changed.\n");
}
else if (*answer == '4')
{
/* Set a new Reset Code. */
rc = agent_scd_change_pin (102, info.serialno);
write_sc_op_status (rc);
if (rc)
tty_printf ("Error setting the Reset Code: %s\n",
gpg_strerror (rc));
else
tty_printf ("Reset Code set.\n");
}
else if (*answer == 'q' || *answer == 'Q')
{
@ -156,11 +204,13 @@ get_manufacturer (unsigned int no)
case 0x0002: return "Prism";
case 0x0003: return "OpenFortress";
case 0x0004: return "Wewid AB";
case 0x0005: return "ZeitControl";
case 0x002A: return "Magrathea";
/* 0x00000 and 0xFFFF are defined as test cards per spec,
0xFFF00 to 0xFFFE are assigned for use with randomly created
serial numbers. */
case 0:
case 0x0000:
case 0xffff: return "test card";
default: return (no & 0xff00) == 0xff00? "unmanaged S/N range":"unknown";
}
@ -287,6 +337,18 @@ fpr_is_zero (const char *fpr)
}
/* Return true if the SHA1 fingerprint FPR consists only of 0xFF. */
static int
fpr_is_ff (const char *fpr)
{
int i;
for (i=0; i < 20 && fpr[i] == '\xff'; i++)
;
return (i == 20);
}
/* Print all available information about the current card. */
void
card_status (FILE *fp, char *serialno, size_t serialnobuflen)
@ -320,8 +382,35 @@ card_status (FILE *fp, char *serialno, size_t serialnobuflen)
if (!info.serialno || strncmp (info.serialno, "D27600012401", 12)
|| strlen (info.serialno) != 32 )
{
if (opt.with_colons)
fputs ("unknown:\n", fp);
if (info.apptype && !strcmp (info.apptype, "NKS"))
{
if (opt.with_colons)
fputs ("netkey-card:\n", fp);
log_info ("this is a NetKey card\n");
}
else if (info.apptype && !strcmp (info.apptype, "DINSIG"))
{
if (opt.with_colons)
fputs ("dinsig-card:\n", fp);
log_info ("this is a DINSIG compliant card\n");
}
else if (info.apptype && !strcmp (info.apptype, "P15"))
{
if (opt.with_colons)
fputs ("pkcs15-card:\n", fp);
log_info ("this is a PKCS#15 compliant card\n");
}
else if (info.apptype && !strcmp (info.apptype, "GELDKARTE"))
{
if (opt.with_colons)
fputs ("geldkarte-card:\n", fp);
log_info ("this is a Geldkarte compliant card\n");
}
else
{
if (opt.with_colons)
fputs ("unknown:\n", fp);
}
log_info ("not an OpenPGP card\n");
agent_release_card_info (&info);
xfree (pk);
@ -367,6 +456,10 @@ card_status (FILE *fp, char *serialno, size_t serialnobuflen)
fputs (":\n", fp);
fprintf (fp, "forcepin:%d:::\n", !info.chv1_cached);
for (i=0; i < DIM (info.key_attr); i++)
if (info.key_attr[0].algo)
fprintf (fp, "keyattr:%d:%d:%u:\n", i+1,
info.key_attr[i].algo, info.key_attr[i].nbits);
fprintf (fp, "maxpinlen:%d:%d:%d:\n",
info.chvmaxlen[0], info.chvmaxlen[1], info.chvmaxlen[2]);
fprintf (fp, "pinretry:%d:%d:%d:\n",
@ -442,6 +535,16 @@ card_status (FILE *fp, char *serialno, size_t serialnobuflen)
}
tty_fprintf (fp, "Signature PIN ....: %s\n",
info.chv1_cached? _("not forced"): _("forced"));
if (info.key_attr[0].algo)
{
tty_fprintf (fp, "Key attributes ...:");
for (i=0; i < DIM (info.key_attr); i++)
tty_fprintf (fp, " %u%c",
info.key_attr[i].nbits,
info.key_attr[i].algo == 1? 'R':
info.key_attr[i].algo == 17? 'D': '?');
tty_fprintf (fp, "\n");
}
tty_fprintf (fp, "Max. PIN lengths .: %d %d %d\n",
info.chvmaxlen[0], info.chvmaxlen[1], info.chvmaxlen[2]);
tty_fprintf (fp, "PIN retry counter : %d %d %d\n",
@ -466,7 +569,10 @@ card_status (FILE *fp, char *serialno, size_t serialnobuflen)
thefpr = (info.fpr1valid? info.fpr1 : info.fpr2valid? info.fpr2 :
info.fpr3valid? info.fpr3 : NULL);
if ( thefpr && !get_pubkey_byfprint (pk, thefpr, 20))
/* If the fingerprint is all 0xff, the key has no asssociated
OpenPGP certificate. */
if ( thefpr && !fpr_is_ff (thefpr)
&& !get_pubkey_byfprint (pk, thefpr, 20))
{
KBNODE keyblock = NULL;
@ -599,6 +705,7 @@ change_url (void)
if (rc)
log_error ("error setting URL: %s\n", gpg_strerror (rc));
xfree (url);
write_sc_op_status (rc);
return rc;
}
@ -608,7 +715,6 @@ change_url (void)
static int
fetch_url(void)
{
#if GNUPG_MAJOR_VERSION == 1
int rc;
struct agent_card_info_s info;
@ -648,9 +754,91 @@ fetch_url(void)
}
return rc;
#else
return 0;
}
/* Read data from file FNAME up to MAXLEN characters. On error return
-1 and store NULL at R_BUFFER; on success return the number of
bytes read and store the address of a newly allocated buffer at
R_BUFFER. */
static int
get_data_from_file (const char *fname, size_t maxlen, char **r_buffer)
{
FILE *fp;
char *data;
int n;
*r_buffer = NULL;
fp = fopen (fname, "rb");
#if GNUPG_MAJOR_VERSION == 1
if (fp && is_secured_file (fileno (fp)))
{
fclose (fp);
fp = NULL;
errno = EPERM;
}
#endif
if (!fp)
{
tty_printf (_("can't open `%s': %s\n"), fname, strerror (errno));
return -1;
}
data = xtrymalloc (maxlen? maxlen:1);
if (!data)
{
tty_printf (_("error allocating enough memory: %s\n"), strerror (errno));
fclose (fp);
return -1;
}
if (maxlen)
n = fread (data, 1, maxlen, fp);
else
n = 0;
fclose (fp);
if (n < 0)
{
tty_printf (_("error reading `%s': %s\n"), fname, strerror (errno));
xfree (data);
return -1;
}
*r_buffer = data;
return n;
}
/* Write LENGTH bytes from BUFFER to file FNAME. Return 0 on
success. */
static int
put_data_to_file (const char *fname, const void *buffer, size_t length)
{
FILE *fp;
fp = fopen (fname, "wb");
#if GNUPG_MAJOR_VERSION == 1
if (fp && is_secured_file (fileno (fp)))
{
fclose (fp);
fp = NULL;
errno = EPERM;
}
#endif
if (!fp)
{
tty_printf (_("can't create `%s': %s\n"), fname, strerror (errno));
return -1;
}
if (length && fwrite (buffer, length, 1, fp) != 1)
{
tty_printf (_("error writing `%s': %s\n"), fname, strerror (errno));
fclose (fp);
return -1;
}
fclose (fp);
return 0;
}
@ -663,34 +851,11 @@ change_login (const char *args)
if (args && *args == '<') /* Read it from a file */
{
FILE *fp;
for (args++; spacep (args); args++)
;
fp = fopen (args, "rb");
#if GNUPG_MAJOR_VERSION == 1
if (fp && is_secured_file (fileno (fp)))
{
fclose (fp);
fp = NULL;
errno = EPERM;
}
#endif
if (!fp)
{
tty_printf (_("can't open `%s': %s\n"), args, strerror (errno));
return -1;
}
data = xmalloc (254);
n = fread (data, 1, 254, fp);
fclose (fp);
n = get_data_from_file (args, 254, &data);
if (n < 0)
{
tty_printf (_("error reading `%s': %s\n"), args, strerror (errno));
xfree (data);
return -1;
}
return -1;
}
else
{
@ -715,6 +880,7 @@ change_login (const char *args)
if (rc)
log_error ("error setting login data: %s\n", gpg_strerror (rc));
xfree (data);
write_sc_op_status (rc);
return rc;
}
@ -731,35 +897,11 @@ change_private_do (const char *args, int nr)
if (args && (args = strchr (args, '<'))) /* Read it from a file */
{
FILE *fp;
/* Fixme: Factor this duplicated code out. */
for (args++; spacep (args); args++)
;
fp = fopen (args, "rb");
#if GNUPG_MAJOR_VERSION == 1
if (fp && is_secured_file (fileno (fp)))
{
fclose (fp);
fp = NULL;
errno = EPERM;
}
#endif
if (!fp)
{
tty_printf (_("can't open `%s': %s\n"), args, strerror (errno));
return -1;
}
data = xmalloc (254);
n = fread (data, 1, 254, fp);
fclose (fp);
n = get_data_from_file (args, 254, &data);
if (n < 0)
{
tty_printf (_("error reading `%s': %s\n"), args, strerror (errno));
xfree (data);
return -1;
}
return -1;
}
else
{
@ -784,9 +926,74 @@ change_private_do (const char *args, int nr)
if (rc)
log_error ("error setting private DO: %s\n", gpg_strerror (rc));
xfree (data);
write_sc_op_status (rc);
return rc;
}
static int
change_cert (const char *args)
{
char *data;
int n;
int rc;
if (args && *args == '<') /* Read it from a file */
{
for (args++; spacep (args); args++)
;
n = get_data_from_file (args, 16384, &data);
if (n < 0)
return -1;
}
else
{
tty_printf ("usage error: redirectrion to file required\n");
return -1;
}
#warning need to implement this fucntion
rc = -1; /*agent_scd_writecert ("OPENPGP.3", data, n);*/
if (rc)
log_error ("error writing certificate to card: %s\n", gpg_strerror (rc));
xfree (data);
write_sc_op_status (rc);
return rc;
}
static int
read_cert (const char *args)
{
const char *fname;
void *buffer;
size_t length;
int rc;
if (args && *args == '>') /* Write it to a file */
{
for (args++; spacep (args); args++)
;
fname = args;
}
else
{
tty_printf ("usage error: redirectrion to file required\n");
return -1;
}
#warning need to implement this fucntion
rc = -1; /*agent_scd_readcert ("OPENPGP.3", &buffer, &length);*/
if (rc)
log_error ("error reading certificate from card: %s\n", gpg_strerror (rc));
else
rc = put_data_to_file (fname, buffer, length);
xfree (buffer);
write_sc_op_status (rc);
return rc;
}
static int
change_lang (void)
{
@ -820,6 +1027,7 @@ change_lang (void)
if (rc)
log_error ("error setting lang: %s\n", gpg_strerror (rc));
xfree (data);
write_sc_op_status (rc);
return rc;
}
@ -855,6 +1063,7 @@ change_sex (void)
if (rc)
log_error ("error setting sex: %s\n", gpg_strerror (rc));
xfree (data);
write_sc_op_status (rc);
return rc;
}
@ -899,6 +1108,7 @@ change_cafpr (int fprno)
fprno==3?"CA-FPR-3":"x", fpr, 20, NULL );
if (rc)
log_error ("error setting cafpr: %s\n", gpg_strerror (rc));
write_sc_op_status (rc);
return rc;
}
@ -924,6 +1134,7 @@ toggle_forcesig (void)
rc = agent_scd_setattr ("CHV-STATUS-1", newstate? "\x01":"", 1, NULL);
if (rc)
log_error ("error toggling signature PIN flag: %s\n", gpg_strerror (rc));
write_sc_op_status (rc);
}
@ -963,7 +1174,7 @@ check_pin_for_key_operation (struct agent_card_info_s *info, int *forced_chv1)
*forced_chv1 = !info->chv1_cached;
if (*forced_chv1)
{ /* Switch of the forced mode so that during key generation we
{ /* Switch off the forced mode so that during key generation we
don't get bothered with PIN queries for each
self-signature. */
rc = agent_scd_setattr ("CHV-STATUS-1", "\x01", 1, info->serialno);
@ -981,8 +1192,11 @@ check_pin_for_key_operation (struct agent_card_info_s *info, int *forced_chv1)
binding signature. */
rc = agent_scd_checkpin (info->serialno);
if (rc)
log_error ("error checking the PIN: %s\n", gpg_strerror (rc));
}
{
log_error ("error checking the PIN: %s\n", gpg_strerror (rc));
write_sc_op_status (rc);
}
}
return rc;
}
@ -1003,7 +1217,7 @@ restore_forced_chv1 (int *forced_chv1)
}
}
#if GNUPG_MAJOR_VERSION == 1
/* Helper for the key generation/edit functions. */
static void
show_card_key_info (struct agent_card_info_s *info)
@ -1016,9 +1230,8 @@ show_card_key_info (struct agent_card_info_s *info)
print_sha1_fpr (NULL, info->fpr3valid? info->fpr3:NULL);
tty_printf ("\n");
}
#endif
#if GNUPG_MAJOR_VERSION == 1
/* Helper for the key generation/edit functions. */
static int
replace_existing_key_p (struct agent_card_info_s *info, int keyno)
@ -1038,11 +1251,10 @@ replace_existing_key_p (struct agent_card_info_s *info, int keyno)
}
return 0;
}
#endif
static void
generate_card_keys (const char *serialno)
generate_card_keys (void)
{
struct agent_card_info_s info;
int forced_chv1;
@ -1094,12 +1306,8 @@ generate_card_keys (const char *serialno)
if (check_pin_for_key_operation (&info, &forced_chv1))
goto leave;
#if GNUPG_MAJOR_VERSION == 1
generate_keypair (NULL, info.serialno,
want_backup? opt.homedir:NULL);
#else
generate_keypair (NULL, info.serialno);
#endif
leave:
agent_release_card_info (&info);
@ -1112,7 +1320,6 @@ generate_card_keys (const char *serialno)
int
card_generate_subkey (KBNODE pub_keyblock, KBNODE sec_keyblock)
{
#if GNUPG_MAJOR_VERSION == 1
struct agent_card_info_s info;
int okay = 0;
int forced_chv1 = 0;
@ -1159,9 +1366,6 @@ card_generate_subkey (KBNODE pub_keyblock, KBNODE sec_keyblock)
agent_release_card_info (&info);
restore_forced_chv1 (&forced_chv1);
return okay;
#else
return 0;
#endif
}
@ -1172,7 +1376,6 @@ card_generate_subkey (KBNODE pub_keyblock, KBNODE sec_keyblock)
int
card_store_subkey (KBNODE node, int use)
{
#if GNUPG_MAJOR_VERSION == 1
struct agent_card_info_s info;
int okay = 0;
int rc;
@ -1192,7 +1395,8 @@ card_store_subkey (KBNODE node, int use)
show_card_key_info (&info);
if (!is_RSA (sk->pubkey_algo) || nbits_from_sk (sk) != 1024 )
if (!is_RSA (sk->pubkey_algo)
|| (!info.is_v2 && nbits_from_sk (sk) != 1024) )
{
tty_printf ("You may only store a 1024 bit RSA key on the card\n");
tty_printf ("\n");
@ -1260,7 +1464,10 @@ card_store_subkey (KBNODE node, int use)
rc = save_unprotected_key_to_card (sk, keyno);
if (rc)
goto leave;
{
log_error (_("error writing key to card: %s\n"), gpg_strerror (rc));
goto leave;
}
/* Get back to the maybe protected original secret key. */
if (copied_sk)
@ -1274,11 +1481,11 @@ card_store_subkey (KBNODE node, int use)
n = pubkey_get_nskey (sk->pubkey_algo);
for (i=pubkey_get_npkey (sk->pubkey_algo); i < n; i++)
{
mpi_free (sk->skey[i]);
gcry_mpi_release (sk->skey[i]);
sk->skey[i] = NULL;
}
i = pubkey_get_npkey (sk->pubkey_algo);
sk->skey[i] = mpi_set_opaque (NULL, xstrdup ("dummydata"), 10);
sk->skey[i] = gcry_mpi_set_opaque (NULL, xstrdup ("dummydata"), 10*8);
sk->is_protected = 1;
sk->protect.s2k.mode = 1002;
s = info.serialno;
@ -1293,9 +1500,6 @@ card_store_subkey (KBNODE node, int use)
free_secret_key (copied_sk);
agent_release_card_info (&info);
return okay;
#else
return 0;
#endif
}
@ -1307,7 +1511,8 @@ enum cmdids
cmdNOP = 0,
cmdQUIT, cmdADMIN, cmdHELP, cmdLIST, cmdDEBUG, cmdVERIFY,
cmdNAME, cmdURL, cmdFETCH, cmdLOGIN, cmdLANG, cmdSEX, cmdCAFPR,
cmdFORCESIG, cmdGENERATE, cmdPASSWD, cmdPRIVATEDO,
cmdFORCESIG, cmdGENERATE, cmdPASSWD, cmdPRIVATEDO, cmdWRITECERT,
cmdREADCERT, cmdUNBLOCK,
cmdINVCMD
};
@ -1338,8 +1543,11 @@ static struct
{ "generate", cmdGENERATE, 1, N_("generate new keys")},
{ "passwd" , cmdPASSWD, 0, N_("menu to change or unblock the PIN")},
{ "verify" , cmdVERIFY, 0, N_("verify the PIN and list all data")},
/* Note, that we do not announce this command yet. */
{ "unblock" , cmdUNBLOCK,0, N_("unblock the PIN using a Reset Code") },
/* Note, that we do not announce these command yet. */
{ "privatedo", cmdPRIVATEDO, 0, NULL },
{ "readcert", cmdREADCERT, 0, NULL },
{ "writecert", cmdWRITECERT, 1, NULL },
{ NULL, cmdINVCMD, 0, NULL }
};
@ -1392,13 +1600,13 @@ card_edit_completion(const char *text, int start, int end)
/* Menu to edit all user changeable values on an OpenPGP card. Only
Key creation is not handled here. */
void
card_edit (STRLIST commands)
card_edit (strlist_t commands)
{
enum cmdids cmd = cmdNOP;
int have_commands = !!commands;
int redisplay = 1;
char *answer = NULL;
int did_checkpin = 0, allow_admin=0;
int allow_admin=0;
char serialnobuf[50];
@ -1414,6 +1622,7 @@ card_edit (STRLIST commands)
{
int arg_number;
const char *arg_string = "";
const char *arg_rest = "";
char *p;
int i;
int cmd_admin_only;
@ -1482,6 +1691,11 @@ card_edit (STRLIST commands)
trim_spaces (p);
arg_number = atoi(p);
arg_string = p;
arg_rest = p;
while (digitp (arg_rest))
arg_rest++;
while (spacep (arg_rest))
arg_rest++;
}
for (i=0; cmds[i].name; i++ )
@ -1580,17 +1794,34 @@ card_edit (STRLIST commands)
change_private_do (arg_string, arg_number);
break;
case cmdWRITECERT:
if ( arg_number != 3 )
tty_printf ("usage: writecert 3 < FILE\n");
else
change_cert (arg_rest);
break;
case cmdREADCERT:
if ( arg_number != 3 )
tty_printf ("usage: readcert 3 > FILE\n");
else
read_cert (arg_rest);
break;
case cmdFORCESIG:
toggle_forcesig ();
break;
case cmdGENERATE:
generate_card_keys (serialnobuf);
generate_card_keys ();
break;
case cmdPASSWD:
change_pin (0, allow_admin);
did_checkpin = 0; /* Need to reset it of course. */
break;
case cmdUNBLOCK:
change_pin (1, allow_admin);
break;
case cmdQUIT:

View file

@ -190,6 +190,37 @@ send_status_info (ctrl_t ctrl, const char *keyword, ...)
va_end (arg_ptr);
}
/* Send a ready formatted status line via assuan. */
void
send_status_direct (ctrl_t ctrl, const char *keyword, const char *args)
{
char buf[950];
if (strchr (args, '\n'))
log_error ("error: LF detected in status line - not sending\n");
else
{
snprintf (buf, sizeof buf, "%s%s%s",
keyword, args? " ":"", args? args:"");
if (ctrl && ctrl->status_cb)
ctrl->status_cb (ctrl->status_cb_arg, buf);
}
}
void
gcry_mpi_release (MPI a)
{
mpi_free (a);
}
MPI
gcry_mpi_set_opaque (MPI a, void *p, unsigned int len)
{
return mpi_set_opaque (a, p, len);
}
/* Replacement function of the Libgcrypt onewhich is used in gnupg
1.9. Thus function computes the digest of ALGO from the data in
@ -208,6 +239,17 @@ gcry_md_hash_buffer (int algo, void *digest,
}
/* This function simply returns the name of the algorithm or some
constant string when there is no algo. It will never return
NULL. */
const char *
gcry_md_algo_name (int algorithm)
{
const char *s = digest_algo_to_string (algorithm);
return s ? s : "?";
}
/* This is a limited version of the one in 1.9 but it should be
sufficient here. */
void
@ -297,6 +339,7 @@ agent_release_card_info (struct agent_card_info_s *info)
return;
xfree (info->serialno); info->serialno = NULL;
xfree (info->apptype); info->apptype = NULL;
xfree (info->disp_name); info->disp_name = NULL;
xfree (info->disp_lang); info->disp_lang = NULL;
xfree (info->pubkey_url); info->pubkey_url = NULL;
@ -448,7 +491,7 @@ open_card (void)
}
ready:
app->initialized = 1;
app->ref_count = 1;
current_app = app;
if (is_status_enabled () )
{
@ -629,6 +672,15 @@ store_serialno (const char *line)
return p;
}
/* Return a new malloced string by unescaping the string S. Escaping
is percent escaping and '+'/space mapping. A binary nul will
silently be replaced by a 0xFF. Function returns NULL to indicate
an out of memory status. */
static char *
unescape_status_string (const unsigned char *s)
{
return unescape_percent_string (s);
}
static assuan_error_t
@ -649,6 +701,13 @@ learn_status_cb (void *opaque, const char *line)
{
xfree (parm->serialno);
parm->serialno = store_serialno (line);
parm->is_v2 = (strlen (parm->serialno) >= 16
&& xtoi_2 (parm->serialno+12) >= 2 );
}
else if (keywordlen == 7 && !memcmp (keyword, "APPTYPE", keywordlen))
{
xfree (parm->apptype);
parm->apptype = unescape_status_string (line);
}
else if (keywordlen == 9 && !memcmp (keyword, "DISP-NAME", keywordlen))
{
@ -761,6 +820,18 @@ learn_status_cb (void *opaque, const char *line)
xfree (parm->private_do[no]);
parm->private_do[no] = unescape_percent_string (line);
}
else if (keywordlen == 8 && !memcmp (keyword, "KEY-ATTR", keywordlen))
{
int keyno, algo, nbits;
sscanf (line, "%d %d %d", &keyno, &algo, &nbits);
keyno--;
if (keyno >= 0 && keyno < DIM (parm->key_attr))
{
parm->key_attr[keyno].algo = algo;
parm->key_attr[keyno].nbits = nbits;
}
}
return 0;
}
@ -801,7 +872,7 @@ agent_learn (struct agent_card_info_s *info)
send_status_info (&ctrl, "SERIALNO",
serial, strlen(serial), NULL, 0);
xfree (serial);
rc = app->fnc.learn_status (app, &ctrl);
rc = app->fnc.learn_status (app, &ctrl, 0);
}
}
@ -1132,7 +1203,7 @@ genkey_status_cb (void *opaque, const char *line)
/* Send a GENKEY command to the SCdaemon. */
int
agent_scd_genkey (struct agent_card_genkey_s *info, int keyno, int force,
const char *serialno)
const char *serialno, u32 *createtime)
{
app_t app;
char line[ASSUAN_LINELENGTH];
@ -1166,6 +1237,7 @@ agent_scd_genkey (struct agent_card_genkey_s *info, int keyno, int force,
ctrl.status_cb_arg = info;
rc = app->fnc.genkey (app, &ctrl, line,
force? 1:0,
*createtime,
pin_cb, &parm);
}

View file

@ -21,15 +21,21 @@
#ifdef ENABLE_CARD_SUPPORT
/*
Note, that most card related code has been taken from 1.9.x branch
Note, that most card related code has been taken from 2.x branch
and is maintained over there if at all possible. Thus, if you make
changes here, please check that a similar change has been commited
to the 1.9.x branch.
to the 2.x branch.
*/
/* We don't use libgcrypt but the shared codes uses a function type
from libgcrypt. Thus we have to provide this type here. */
typedef void (*gcry_handler_progress_t) (void *, const char *, int, int, int);
/* Object to hold all info about the card. */
struct agent_card_info_s {
int error; /* private. */
char *apptype; /* Malloced application type string. */
char *serialno; /* malloced hex string. */
char *disp_name; /* malloced. */
char *disp_lang; /* malloced. */
@ -56,8 +62,13 @@ struct agent_card_info_s {
int chv1_cached; /* True if a PIN is not required for each
signing. Note that the gpg-agent might cache
it anyway. */
int is_v2; /* True if this is a v2 card. */
int chvmaxlen[3]; /* Maximum allowed length of a CHV. */
int chvretry[3]; /* Allowed retries for the CHV; 0 = blocked. */
struct { /* Array with key attributes. */
int algo; /* Algorithm identifier. */
unsigned int nbits; /* Supported keysize. */
} key_attr[3];
};
struct agent_card_genkey_s {
@ -147,14 +158,24 @@ void card_set_reader_port (const char *portstr);
char *serialno_and_fpr_from_sk (const unsigned char *sn, size_t snlen,
PKT_secret_key *sk);
void send_status_info (ctrl_t ctrl, const char *keyword, ...);
void send_status_direct (ctrl_t ctrl, const char *keyword, const char *args);
void gcry_md_hash_buffer (int algo, void *digest,
const void *buffer, size_t length);
const char *gcry_md_algo_name (int algorithm);
void log_printf (const char *fmt, ...);
void log_printhex (const char *text, const void *buffer, size_t length);
#define GCRY_MD_SHA1 DIGEST_ALGO_SHA1
#define GCRY_MD_RMD160 DIGEST_ALGO_RMD160
#define GCRY_MD_SHA256 DIGEST_ALGO_SHA256
#define GCRY_MD_SHA384 DIGEST_ALGO_SHA384
#define GCRY_MD_SHA512 DIGEST_ALGO_SHA512
#define GCRY_MD_SHA224 DIGEST_ALGO_SHA224
void gcry_mpi_release (MPI a);
MPI gcry_mpi_set_opaque (MPI a, void *p, unsigned int len);
void card_close (void);
@ -183,7 +204,7 @@ int agent_scd_writekey (int keyno, const char *serialno,
/* Send a GENKEY command to the SCdaemon. */
int agent_scd_genkey (struct agent_card_genkey_s *info, int keyno, int force,
const char *serialno);
const char *serialno, u32 *createtime);
/* Send a PKSIGN command to the SCdaemon. */
int agent_scd_pksign (const char *keyid, int hashalgo,

File diff suppressed because it is too large Load diff

View file

@ -80,6 +80,9 @@ typedef struct ccid_driver_s *ccid_driver_t;
int ccid_set_debug_level (int level);
char *ccid_get_reader_list (void);
int ccid_open_reader (ccid_driver_t *handle, const char *readerid);
int ccid_set_progress_cb (ccid_driver_t handle,
void (*cb)(void *, const char *, int, int, int),
void *cb_arg);
int ccid_shutdown_reader (ccid_driver_t handle);
int ccid_close_reader (ccid_driver_t handle);
int ccid_get_atr (ccid_driver_t handle,

View file

@ -1932,6 +1932,7 @@ main (int argc, char **argv )
#else
opt.pcsc_driver = "libpcsclite.so";
#endif
opt.disable_keypad = 1; /* No keypad support; use gpg2 instead. */
#endif /*ENABLE_CARD_SUPPORT*/
/* check whether we have a config file on the commandline */

View file

@ -1,5 +1,5 @@
/* iso7816.c - ISO 7816 commands
* Copyright (C) 2003, 2004 Free Software Foundation, Inc.
* Copyright (C) 2003, 2004, 2008, 2009 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@ -45,9 +45,9 @@
#define CMD_SELECT_FILE 0xA4
#define CMD_VERIFY 0x20
#define CMD_CHANGE_REFERENCE_DATA 0x24
#define CMD_RESET_RETRY_COUNTER 0x2C
#define CMD_VERIFY ISO7816_VERIFY
#define CMD_CHANGE_REFERENCE_DATA ISO7816_CHANGE_REFERENCE_DATA
#define CMD_RESET_RETRY_COUNTER ISO7816_RESET_RETRY_COUNTER
#define CMD_GET_DATA 0xCA
#define CMD_PUT_DATA 0xDA
#define CMD_MSE 0x22
@ -66,7 +66,10 @@ map_sw (int sw)
switch (sw)
{
case SW_EEPROM_FAILURE: ec = GPG_ERR_HARDWARE; break;
case SW_TERM_STATE: ec = GPG_ERR_CARD; break;
case SW_WRONG_LENGTH: ec = GPG_ERR_INV_VALUE; break;
case SW_SM_NOT_SUP: ec = GPG_ERR_NOT_SUPPORTED; break;
case SW_CC_NOT_SUP: ec = GPG_ERR_NOT_SUPPORTED; break;
case SW_CHV_WRONG: ec = GPG_ERR_BAD_PIN; break;
case SW_CHV_BLOCKED: ec = GPG_ERR_PIN_BLOCKED; break;
case SW_USE_CONDITIONS: ec = GPG_ERR_USE_CONDITIONS; break;
@ -93,6 +96,7 @@ map_sw (int sw)
case SW_HOST_GENERAL_ERROR: ec = GPG_ERR_GENERAL; break;
case SW_HOST_NO_READER: ec = GPG_ERR_ENODEV; break;
case SW_HOST_ABORTED: ec = GPG_ERR_CANCELED; break;
case SW_HOST_NO_KEYPAD: ec = GPG_ERR_NOT_SUPPORTED; break;
default:
if ((sw & 0x010000))
@ -122,12 +126,15 @@ iso7816_map_sw (int sw)
requested application ID. The function can't be used to enumerate
AIDs and won't return the AID on success. The return value is 0
for okay or a GPG error code. Note that ISO error codes are
internally mapped. */
internally mapped. Bit 0 of FLAGS should be set if the card does
not understand P2=0xC0. */
gpg_error_t
iso7816_select_application (int slot, const char *aid, size_t aidlen)
iso7816_select_application (int slot, const char *aid, size_t aidlen,
unsigned int flags)
{
int sw;
sw = apdu_send_simple (slot, 0x00, CMD_SELECT_FILE, 4, 0, aidlen, aid);
sw = apdu_send_simple (slot, 0, 0x00, CMD_SELECT_FILE, 4,
(flags&1)? 0 :0x0c, aidlen, aid);
return map_sw (sw);
}
@ -152,7 +159,7 @@ iso7816_select_file (int slot, int tag, int is_dir,
{
p0 = (tag == 0x3F00)? 0: is_dir? 1:2;
p1 = 0x0c; /* No FC return. */
sw = apdu_send_simple (slot, 0x00, CMD_SELECT_FILE,
sw = apdu_send_simple (slot, 0, 0x00, CMD_SELECT_FILE,
p0, p1, 2, (char*)tagbuf );
return map_sw (sw);
}
@ -188,7 +195,7 @@ iso7816_select_path (int slot, const unsigned short *path, size_t pathlen,
p0 = 0x08;
p1 = 0x0c; /* No FC return. */
sw = apdu_send_simple (slot, 0x00, CMD_SELECT_FILE,
sw = apdu_send_simple (slot, 0, 0x00, CMD_SELECT_FILE,
p0, p1, buflen, (char*)buffer );
return map_sw (sw);
}
@ -206,7 +213,7 @@ iso7816_list_directory (int slot, int list_dirs,
*result = NULL;
*resultlen = 0;
sw = apdu_send (slot, 0x80, 0xAA, list_dirs? 1:2, 0, -1, NULL,
sw = apdu_send (slot, 0, 0x80, 0xAA, list_dirs? 1:2, 0, -1, NULL,
result, resultlen);
if (sw != SW_SUCCESS)
{
@ -219,27 +226,101 @@ iso7816_list_directory (int slot, int list_dirs,
}
/* This funcion sends an already formatted APDU to the card. With
HANDLE_MORE set to true a MORE DATA status will be handled
internally. The return value is a gpg error code (i.e. a mapped
status word). This is basically the same as apdu_send_direct but
it maps the status word and does not return it in the result
buffer. */
gpg_error_t
iso7816_apdu_direct (int slot, const void *apdudata, size_t apdudatalen,
int handle_more,
unsigned char **result, size_t *resultlen)
{
int sw;
if (!result || !resultlen)
return gpg_error (GPG_ERR_INV_VALUE);
*result = NULL;
*resultlen = 0;
sw = apdu_send_direct (slot, 0, apdudata, apdudatalen, handle_more,
result, resultlen);
if (!sw)
{
if (*resultlen < 2)
sw = SW_HOST_GENERAL_ERROR;
else
{
sw = ((*result)[*resultlen-2] << 8) | (*result)[*resultlen-1];
(*resultlen)--;
(*resultlen)--;
}
}
if (sw != SW_SUCCESS)
{
/* Make sure that pending buffers are released. */
xfree (*result);
*result = NULL;
*resultlen = 0;
}
return map_sw (sw);
}
/* Check whether the reader supports the ISO command code COMMAND on
the keypad. Returns 0 on success. */
gpg_error_t
iso7816_check_keypad (int slot, int command, iso7816_pininfo_t *pininfo)
{
int sw;
sw = apdu_check_keypad (slot, command,
pininfo->mode, pininfo->minlen, pininfo->maxlen,
pininfo->padlen);
return iso7816_map_sw (sw);
}
/* Perform a VERIFY command on SLOT using the card holder verification
vector CHVNO with a CHV of lenght CHVLEN. With PININFO non-NULL
the keypad of the reader will be used. Returns 0 on success. */
gpg_error_t
iso7816_verify_kp (int slot, int chvno, const char *chv, size_t chvlen,
iso7816_pininfo_t *pininfo)
{
int sw;
if (pininfo && pininfo->mode)
sw = apdu_send_simple_kp (slot, 0x00, CMD_VERIFY, 0, chvno, chvlen, chv,
pininfo->mode,
pininfo->minlen,
pininfo->maxlen,
pininfo->padlen);
else
sw = apdu_send_simple (slot, 0, 0x00, CMD_VERIFY, 0, chvno, chvlen, chv);
return map_sw (sw);
}
/* Perform a VERIFY command on SLOT using the card holder verification
vector CHVNO with a CHV of lenght CHVLEN. Returns 0 on success. */
gpg_error_t
iso7816_verify (int slot, int chvno, const char *chv, size_t chvlen)
{
int sw;
sw = apdu_send_simple (slot, 0x00, CMD_VERIFY, 0, chvno, chvlen, chv);
return map_sw (sw);
return iso7816_verify_kp (slot, chvno, chv, chvlen, NULL);
}
/* Perform a CHANGE_REFERENCE_DATA command on SLOT for the card holder
verification vector CHVNO. If the OLDCHV is NULL (and OLDCHVLEN
0), a "change reference data" is done, otherwise an "exchange
reference data". The new reference data is expected in NEWCHV of
length NEWCHVLEN. */
length NEWCHVLEN. With PININFO non-NULL the keypad of the reader
will be used. */
gpg_error_t
iso7816_change_reference_data (int slot, int chvno,
const char *oldchv, size_t oldchvlen,
const char *newchv, size_t newchvlen)
iso7816_change_reference_data_kp (int slot, int chvno,
const char *oldchv, size_t oldchvlen,
const char *newchv, size_t newchvlen,
iso7816_pininfo_t *pininfo)
{
int sw;
char *buf;
@ -256,45 +337,110 @@ iso7816_change_reference_data (int slot, int chvno,
memcpy (buf, oldchv, oldchvlen);
memcpy (buf+oldchvlen, newchv, newchvlen);
sw = apdu_send_simple (slot, 0x00, CMD_CHANGE_REFERENCE_DATA,
oldchvlen? 0 : 1, chvno, oldchvlen+newchvlen, buf);
if (pininfo && pininfo->mode)
sw = apdu_send_simple_kp (slot, 0x00, CMD_CHANGE_REFERENCE_DATA,
oldchvlen? 0 : 1, chvno, oldchvlen+newchvlen, buf,
pininfo->mode,
pininfo->minlen,
pininfo->maxlen,
pininfo->padlen);
else
sw = apdu_send_simple (slot, 0, 0x00, CMD_CHANGE_REFERENCE_DATA,
oldchvlen? 0 : 1, chvno, oldchvlen+newchvlen, buf);
xfree (buf);
return map_sw (sw);
}
/* Perform a CHANGE_REFERENCE_DATA command on SLOT for the card holder
verification vector CHVNO. If the OLDCHV is NULL (and OLDCHVLEN
0), a "change reference data" is done, otherwise an "exchange
reference data". The new reference data is expected in NEWCHV of
length NEWCHVLEN. */
gpg_error_t
iso7816_reset_retry_counter (int slot, int chvno,
const char *newchv, size_t newchvlen)
iso7816_change_reference_data (int slot, int chvno,
const char *oldchv, size_t oldchvlen,
const char *newchv, size_t newchvlen)
{
return iso7816_change_reference_data_kp (slot, chvno, oldchv, oldchvlen,
newchv, newchvlen, NULL);
}
gpg_error_t
iso7816_reset_retry_counter_kp (int slot, int chvno,
const char *newchv, size_t newchvlen,
iso7816_pininfo_t *pininfo)
{
int sw;
if (!newchv || !newchvlen )
return gpg_error (GPG_ERR_INV_VALUE);
sw = apdu_send_simple (slot, 0x00, CMD_RESET_RETRY_COUNTER,
2, chvno, newchvlen, newchv);
/* FIXME: The keypad mode has not yet been tested. */
if (pininfo && pininfo->mode)
sw = apdu_send_simple_kp (slot, 0x00, CMD_RESET_RETRY_COUNTER,
2, chvno, newchvlen, newchv,
pininfo->mode,
pininfo->minlen,
pininfo->maxlen,
pininfo->padlen);
else
sw = apdu_send_simple (slot, 0, 0x00, CMD_RESET_RETRY_COUNTER,
2, chvno, newchvlen, newchv);
return map_sw (sw);
}
gpg_error_t
iso7816_reset_retry_counter_with_rc (int slot, int chvno,
const char *data, size_t datalen)
{
int sw;
if (!data || !datalen )
return gpg_error (GPG_ERR_INV_VALUE);
sw = apdu_send_simple (slot, 0, 0x00, CMD_RESET_RETRY_COUNTER,
0, chvno, datalen, data);
return map_sw (sw);
}
gpg_error_t
iso7816_reset_retry_counter (int slot, int chvno,
const char *newchv, size_t newchvlen)
{
return iso7816_reset_retry_counter_kp (slot, chvno, newchv, newchvlen, NULL);
}
/* Perform a GET DATA command requesting TAG and storing the result in
a newly allocated buffer at the address passed by RESULT. Return
the length of this data at the address of RESULTLEN. */
gpg_error_t
iso7816_get_data (int slot, int tag,
iso7816_get_data (int slot, int extended_mode, int tag,
unsigned char **result, size_t *resultlen)
{
int sw;
int le;
if (!result || !resultlen)
return gpg_error (GPG_ERR_INV_VALUE);
*result = NULL;
*resultlen = 0;
sw = apdu_send (slot, 0x00, CMD_GET_DATA,
((tag >> 8) & 0xff), (tag & 0xff), -1, NULL,
result, resultlen);
if (extended_mode > 0 && extended_mode < 256)
le = 65534; /* Not 65535 in case it is used as some special flag. */
else if (extended_mode > 0)
le = extended_mode;
else
le = 256;
sw = apdu_send_le (slot, extended_mode, 0x00, CMD_GET_DATA,
((tag >> 8) & 0xff), (tag & 0xff), -1, NULL, le,
result, resultlen);
if (sw != SW_SUCCESS)
{
/* Make sure that pending buffers are released. */
@ -309,14 +455,29 @@ iso7816_get_data (int slot, int tag,
/* Perform a PUT DATA command on card in SLOT. Write DATA of length
DATALEN to TAG. */
DATALEN to TAG. EXTENDED_MODE controls whether extended length
headers or command chaining is used instead of single length
bytes. */
gpg_error_t
iso7816_put_data (int slot, int tag,
iso7816_put_data (int slot, int extended_mode, int tag,
const unsigned char *data, size_t datalen)
{
int sw;
sw = apdu_send_simple (slot, 0x00, CMD_PUT_DATA,
sw = apdu_send_simple (slot, extended_mode, 0x00, CMD_PUT_DATA,
((tag >> 8) & 0xff), (tag & 0xff),
datalen, (const char*)data);
return map_sw (sw);
}
/* Same as iso7816_put_data but uses an odd instruction byte. */
gpg_error_t
iso7816_put_data_odd (int slot, int extended_mode, int tag,
const unsigned char *data, size_t datalen)
{
int sw;
sw = apdu_send_simple (slot, extended_mode, 0x00, CMD_PUT_DATA+1,
((tag >> 8) & 0xff), (tag & 0xff),
datalen, (const char*)data);
return map_sw (sw);
@ -335,7 +496,7 @@ iso7816_manage_security_env (int slot, int p1, int p2,
if (p1 < 0 || p1 > 255 || p2 < 0 || p2 > 255 )
return gpg_error (GPG_ERR_INV_VALUE);
sw = apdu_send_simple (slot, 0x00, CMD_MSE, p1, p2,
sw = apdu_send_simple (slot, 0, 0x00, CMD_MSE, p1, p2,
data? datalen : -1, (const char*)data);
return map_sw (sw);
}
@ -344,9 +505,10 @@ iso7816_manage_security_env (int slot, int p1, int p2,
/* Perform the security operation COMPUTE DIGITAL SIGANTURE. On
success 0 is returned and the data is availavle in a newly
allocated buffer stored at RESULT with its length stored at
RESULTLEN. */
RESULTLEN. For LE see do_generate_keypair. */
gpg_error_t
iso7816_compute_ds (int slot, const unsigned char *data, size_t datalen,
iso7816_compute_ds (int slot, int extended_mode,
const unsigned char *data, size_t datalen, int le,
unsigned char **result, size_t *resultlen)
{
int sw;
@ -356,8 +518,16 @@ iso7816_compute_ds (int slot, const unsigned char *data, size_t datalen,
*result = NULL;
*resultlen = 0;
sw = apdu_send (slot, 0x00, CMD_PSO, 0x9E, 0x9A, datalen, (const char*)data,
result, resultlen);
if (!extended_mode)
le = 256; /* Ignore provided Le and use what apdu_send uses. */
else if (le >= 0 && le < 256)
le = 256;
sw = apdu_send_le (slot, extended_mode,
0x00, CMD_PSO, 0x9E, 0x9A,
datalen, (const char*)data,
le,
result, resultlen);
if (sw != SW_SUCCESS)
{
/* Make sure that pending buffers are released. */
@ -377,7 +547,8 @@ iso7816_compute_ds (int slot, const unsigned char *data, size_t datalen,
and the plaintext is available in a newly allocated buffer stored
at RESULT with its length stored at RESULTLEN. */
gpg_error_t
iso7816_decipher (int slot, const unsigned char *data, size_t datalen,
iso7816_decipher (int slot, int extended_mode,
const unsigned char *data, size_t datalen,
int padind, unsigned char **result, size_t *resultlen)
{
int sw;
@ -394,17 +565,19 @@ iso7816_decipher (int slot, const unsigned char *data, size_t datalen,
buf = xtrymalloc (datalen + 1);
if (!buf)
return gpg_error (gpg_err_code_from_errno (errno));
*buf = padind; /* Padding indicator. */
memcpy (buf+1, data, datalen);
sw = apdu_send (slot, 0x00, CMD_PSO, 0x80, 0x86,
sw = apdu_send (slot, extended_mode,
0x00, CMD_PSO, 0x80, 0x86,
datalen+1, (char*)buf,
result, resultlen);
xfree (buf);
}
else
{
sw = apdu_send (slot, 0x00, CMD_PSO, 0x80, 0x86,
sw = apdu_send (slot, extended_mode,
0x00, CMD_PSO, 0x80, 0x86,
datalen, (const char *)data,
result, resultlen);
}
@ -421,9 +594,11 @@ iso7816_decipher (int slot, const unsigned char *data, size_t datalen,
}
/* For LE see do_generate_keypair. */
gpg_error_t
iso7816_internal_authenticate (int slot,
iso7816_internal_authenticate (int slot, int extended_mode,
const unsigned char *data, size_t datalen,
int le,
unsigned char **result, size_t *resultlen)
{
int sw;
@ -433,8 +608,16 @@ iso7816_internal_authenticate (int slot,
*result = NULL;
*resultlen = 0;
sw = apdu_send (slot, 0x00, CMD_INTERNAL_AUTHENTICATE, 0, 0,
datalen, (const char*)data, result, resultlen);
if (!extended_mode)
le = 256; /* Ignore provided Le and use what apdu_send uses. */
else if (le >= 0 && le < 256)
le = 256;
sw = apdu_send_le (slot, extended_mode,
0x00, CMD_INTERNAL_AUTHENTICATE, 0, 0,
datalen, (const char*)data,
le,
result, resultlen);
if (sw != SW_SUCCESS)
{
/* Make sure that pending buffers are released. */
@ -448,10 +631,15 @@ iso7816_internal_authenticate (int slot,
}
/* LE is the expected return length. This is usually 0 except if
extended length mode is used and more than 256 byte will be
returned. In that case a value of -1 uses a large default
(e.g. 4096 bytes), a value larger 256 used that value. */
static gpg_error_t
do_generate_keypair (int slot, int readonly,
const unsigned char *data, size_t datalen,
unsigned char **result, size_t *resultlen)
do_generate_keypair (int slot, int extended_mode, int readonly,
const unsigned char *data, size_t datalen,
int le,
unsigned char **result, size_t *resultlen)
{
int sw;
@ -460,8 +648,11 @@ do_generate_keypair (int slot, int readonly,
*result = NULL;
*resultlen = 0;
sw = apdu_send (slot, 0x00, CMD_GENERATE_KEYPAIR, readonly? 0x81:0x80, 0,
datalen, (const char*)data, result, resultlen);
sw = apdu_send_le (slot, extended_mode,
0x00, CMD_GENERATE_KEYPAIR, readonly? 0x81:0x80, 0,
datalen, (const char*)data,
le >= 0 && le < 256? 256:le,
result, resultlen);
if (sw != SW_SUCCESS)
{
/* Make sure that pending buffers are released. */
@ -476,20 +667,24 @@ do_generate_keypair (int slot, int readonly,
gpg_error_t
iso7816_generate_keypair (int slot,
iso7816_generate_keypair (int slot, int extended_mode,
const unsigned char *data, size_t datalen,
int le,
unsigned char **result, size_t *resultlen)
{
return do_generate_keypair (slot, 0, data, datalen, result, resultlen);
return do_generate_keypair (slot, extended_mode, 0,
data, datalen, le, result, resultlen);
}
gpg_error_t
iso7816_read_public_key (int slot,
const unsigned char *data, size_t datalen,
unsigned char **result, size_t *resultlen)
iso7816_read_public_key (int slot, int extended_mode,
const unsigned char *data, size_t datalen,
int le,
unsigned char **result, size_t *resultlen)
{
return do_generate_keypair (slot, 1, data, datalen, result, resultlen);
return do_generate_keypair (slot, extended_mode, 1,
data, datalen, le, result, resultlen);
}
@ -508,8 +703,8 @@ iso7816_get_challenge (int slot, int length, unsigned char *buffer)
{
result = NULL;
n = length > 254? 254 : length;
sw = apdu_send_le (slot, 0x00, CMD_GET_CHALLENGE, 0, 0, -1, NULL,
n,
sw = apdu_send_le (slot, 0,
0x00, CMD_GET_CHALLENGE, 0, 0, -1, NULL, n,
&result, &resultlen);
if (sw != SW_SUCCESS)
{
@ -557,21 +752,14 @@ iso7816_read_binary (int slot, size_t offset, size_t nmax,
{
buffer = NULL;
bufferlen = 0;
/* Note, that we to set N to 254 due to problems either with the
ccid driver or some TCOS cards. It actually should be 0
which is the official ISO value to read a variable length
object. */
if (read_all || nmax > 254)
n = 254;
else
n = nmax;
sw = apdu_send_le (slot, 0x00, CMD_READ_BINARY,
n = read_all? 0 : nmax;
sw = apdu_send_le (slot, 0, 0x00, CMD_READ_BINARY,
((offset>>8) & 0xff), (offset & 0xff) , -1, NULL,
n, &buffer, &bufferlen);
if ( SW_EXACT_LENGTH_P(sw) )
{
n = (sw & 0x00ff);
sw = apdu_send_le (slot, 0x00, CMD_READ_BINARY,
sw = apdu_send_le (slot, 0, 0x00, CMD_READ_BINARY,
((offset>>8) & 0xff), (offset & 0xff) , -1, NULL,
n, &buffer, &bufferlen);
}
@ -598,7 +786,7 @@ iso7816_read_binary (int slot, size_t offset, size_t nmax,
unsigned char *p = xtryrealloc (*result, *resultlen + bufferlen);
if (!p)
{
gpg_error_t err = gpg_error_from_errno (errno);
gpg_error_t err = gpg_error_from_syserror ();
xfree (buffer);
xfree (*result);
*result = NULL;
@ -658,13 +846,11 @@ iso7816_read_record (int slot, int recno, int reccount, int short_ef,
buffer = NULL;
bufferlen = 0;
/* Fixme: Either the ccid driver or the TCOS cards have problems
with an Le of 0. */
sw = apdu_send_le (slot, 0x00, CMD_READ_RECORD,
sw = apdu_send_le (slot, 0, 0x00, CMD_READ_RECORD,
recno,
short_ef? short_ef : 0x04,
-1, NULL,
254, &buffer, &bufferlen);
0, &buffer, &bufferlen);
if (sw != SW_SUCCESS && sw != SW_EOF_REACHED)
{

View file

@ -26,10 +26,30 @@
#include "cardglue.h"
#endif
/* Command codes used by iso7816_check_keypad. */
#define ISO7816_VERIFY 0x20
#define ISO7816_CHANGE_REFERENCE_DATA 0x24
#define ISO7816_RESET_RETRY_COUNTER 0x2C
/* Information to be passed to keypad equipped readers. See
ccid-driver.c for details. */
struct iso7816_pininfo_s
{
int mode; /* A mode of 0 means: Do not use the keypad. */
int minlen;
int maxlen;
int padlen;
int padchar;
};
typedef struct iso7816_pininfo_s iso7816_pininfo_t;
gpg_error_t iso7816_map_sw (int sw);
gpg_error_t iso7816_select_application (int slot,
const char *aid, size_t aidlen);
const char *aid, size_t aidlen,
unsigned int flags);
gpg_error_t iso7816_select_file (int slot, int tag, int is_dir,
unsigned char **result, size_t *resultlen);
gpg_error_t iso7816_select_path (int slot,
@ -37,36 +57,62 @@ gpg_error_t iso7816_select_path (int slot,
unsigned char **result, size_t *resultlen);
gpg_error_t iso7816_list_directory (int slot, int list_dirs,
unsigned char **result, size_t *resultlen);
gpg_error_t iso7816_apdu_direct (int slot,
const void *apdudata, size_t apdudatalen,
int handle_more,
unsigned char **result, size_t *resultlen);
gpg_error_t iso7816_check_keypad (int slot, int command,
iso7816_pininfo_t *pininfo);
gpg_error_t iso7816_verify (int slot,
int chvno, const char *chv, size_t chvlen);
gpg_error_t iso7816_verify_kp (int slot,
int chvno, const char *chv, size_t chvlen,
iso7816_pininfo_t *pininfo);
gpg_error_t iso7816_change_reference_data (int slot, int chvno,
const char *oldchv, size_t oldchvlen,
const char *newchv, size_t newchvlen);
gpg_error_t iso7816_change_reference_data_kp (int slot, int chvno,
const char *oldchv, size_t oldchvlen,
const char *newchv, size_t newchvlen,
iso7816_pininfo_t *pininfo);
gpg_error_t iso7816_reset_retry_counter (int slot, int chvno,
const char *newchv, size_t newchvlen);
gpg_error_t iso7816_get_data (int slot, int tag,
gpg_error_t iso7816_reset_retry_counter_kp (int slot, int chvno,
const char *newchv,
size_t newchvlen,
iso7816_pininfo_t *pininfo);
gpg_error_t iso7816_reset_retry_counter_with_rc (int slot, int chvno,
const char *data,
size_t datalen);
gpg_error_t iso7816_get_data (int slot, int extended_mode, int tag,
unsigned char **result, size_t *resultlen);
gpg_error_t iso7816_put_data (int slot, int tag,
gpg_error_t iso7816_put_data (int slot, int extended_mode, int tag,
const unsigned char *data, size_t datalen);
gpg_error_t iso7816_put_data_odd (int slot, int extended_mode, int tag,
const unsigned char *data, size_t datalen);
gpg_error_t iso7816_manage_security_env (int slot, int p1, int p2,
const unsigned char *data,
size_t datalen);
gpg_error_t iso7816_compute_ds (int slot,
gpg_error_t iso7816_compute_ds (int slot, int extended_mode,
const unsigned char *data, size_t datalen,
int le,
unsigned char **result, size_t *resultlen);
gpg_error_t iso7816_decipher (int slot,
gpg_error_t iso7816_decipher (int slot, int extended_mode,
const unsigned char *data, size_t datalen,
int padind,
unsigned char **result, size_t *resultlen);
gpg_error_t iso7816_internal_authenticate (int slot,
const unsigned char *data, size_t datalen,
unsigned char **result, size_t *resultlen);
gpg_error_t iso7816_generate_keypair (int slot,
const unsigned char *data, size_t datalen,
unsigned char **result, size_t *resultlen);
gpg_error_t iso7816_read_public_key (int slot,
gpg_error_t iso7816_internal_authenticate (int slot, int extended_mode,
const unsigned char *data, size_t datalen,
int le,
unsigned char **result, size_t *resultlen);
gpg_error_t iso7816_generate_keypair (int slot, int extended_mode,
const unsigned char *data, size_t datalen,
int le,
unsigned char **result, size_t *resultlen);
gpg_error_t iso7816_read_public_key (int slot, int extended_mode,
const unsigned char *data, size_t datalen,
int le,
unsigned char **result, size_t *resultlen);
gpg_error_t iso7816_get_challenge (int slot,
int length, unsigned char *buffer);

View file

@ -3652,6 +3652,7 @@ menu_backsign(KBNODE pub_keyblock,KBNODE sec_keyblock)
PKT_public_key *main_pk;
PKT_secret_key *main_sk,*sub_sk=NULL;
KBNODE node;
u32 timestamp;
assert(pub_keyblock->pkt->pkttype==PKT_PUBLIC_KEY);
assert(sec_keyblock->pkt->pkttype==PKT_SECRET_KEY);
@ -3661,6 +3662,10 @@ menu_backsign(KBNODE pub_keyblock,KBNODE sec_keyblock)
main_sk=copy_secret_key(NULL,sec_keyblock->pkt->pkt.secret_key);
keyid_from_pk(main_pk,NULL);
/* We use the same timestamp for all backsigs so that we don't
reveal information about the used machine. */
timestamp = make_timestamp ();
for(node=pub_keyblock;node;node=node->next)
{
PKT_public_key *sub_pk=NULL;
@ -3748,7 +3753,8 @@ menu_backsign(KBNODE pub_keyblock,KBNODE sec_keyblock)
set_next_passphrase(passphrase);
xfree(passphrase);
rc=make_backsig(sig_pk->pkt->pkt.signature,main_pk,sub_pk,sub_sk);
rc = make_backsig (sig_pk->pkt->pkt.signature, main_pk, sub_pk, sub_sk,
timestamp);
if(rc==0)
{
PKT_signature *newsig;

View file

@ -1,6 +1,6 @@
/* keygen.c - generate a key pair
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
* 2007 Free Software Foundation, Inc.
* 2007, 2009 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@ -127,9 +127,11 @@ static int write_keyblock( IOBUF out, KBNODE node );
static int gen_card_key (int algo, int keyno, int is_primary,
KBNODE pub_root, KBNODE sec_root,
PKT_secret_key **ret_sk,
u32 *timestamp,
u32 expireval, struct para_data_s *para);
static int gen_card_key_with_backup (int algo, int keyno, int is_primary,
KBNODE pub_root, KBNODE sec_root,
u32 timestamp,
u32 expireval, struct para_data_s *para,
const char *backup_dir);
@ -770,17 +772,20 @@ keygen_add_revkey(PKT_signature *sig, void *opaque)
return 0;
}
/* Create a back-signature. If TIMESTAMP is not NULL, use it for the
signature creation time. */
int
make_backsig(PKT_signature *sig,PKT_public_key *pk,
PKT_public_key *sub_pk,PKT_secret_key *sub_sk)
make_backsig (PKT_signature *sig, PKT_public_key *pk,
PKT_public_key *sub_pk, PKT_secret_key *sub_sk,
u32 timestamp)
{
PKT_signature *backsig;
int rc;
cache_public_key(sub_pk);
rc=make_keysig_packet(&backsig,pk,NULL,sub_pk,sub_sk,0x19,0,0,
sub_pk->timestamp,0,NULL,NULL);
rc= make_keysig_packet (&backsig, pk, NULL, sub_pk, sub_sk, 0x19,
0, 0, timestamp, 0, NULL, NULL);
if(rc)
log_error("make_keysig_packet failed for backsig: %s\n",g10_errstr(rc));
else
@ -863,7 +868,7 @@ make_backsig(PKT_signature *sig,PKT_public_key *pk,
static int
write_direct_sig( KBNODE root, KBNODE pub_root, PKT_secret_key *sk,
struct revocation_key *revkey )
struct revocation_key *revkey, u32 timestamp)
{
PACKET *pkt;
PKT_signature *sig;
@ -885,8 +890,9 @@ write_direct_sig( KBNODE root, KBNODE pub_root, PKT_secret_key *sk,
cache_public_key (pk);
/* and make the signature */
rc = make_keysig_packet(&sig,pk,NULL,NULL,sk,0x1F,0,0,pk->timestamp,0,
keygen_add_revkey,revkey);
rc = make_keysig_packet (&sig, pk, NULL, NULL, sk, 0x1F,
0, 0, timestamp, 0,
keygen_add_revkey, revkey);
if( rc ) {
log_error("make_keysig_packet failed: %s\n", g10_errstr(rc) );
return rc;
@ -900,8 +906,8 @@ write_direct_sig( KBNODE root, KBNODE pub_root, PKT_secret_key *sk,
}
static int
write_selfsigs( KBNODE sec_root, KBNODE pub_root, PKT_secret_key *sk,
unsigned int use )
write_selfsigs (KBNODE sec_root, KBNODE pub_root, PKT_secret_key *sk,
unsigned int use, u32 timestamp)
{
PACKET *pkt;
PKT_signature *sig;
@ -929,8 +935,9 @@ write_selfsigs( KBNODE sec_root, KBNODE pub_root, PKT_secret_key *sk,
cache_public_key (pk);
/* and make the signature */
rc = make_keysig_packet( &sig, pk, uid, NULL, sk, 0x13, 0, 0,
pk->timestamp, 0, keygen_add_std_prefs, pk );
rc = make_keysig_packet (&sig, pk, uid, NULL, sk, 0x13,
0, 0, timestamp, 0,
keygen_add_std_prefs, pk);
if( rc ) {
log_error("make_keysig_packet failed: %s\n", g10_errstr(rc) );
return rc;
@ -949,9 +956,9 @@ write_selfsigs( KBNODE sec_root, KBNODE pub_root, PKT_secret_key *sk,
}
static int
write_keybinding( KBNODE root, KBNODE pub_root,
write_keybinding (KBNODE root, KBNODE pub_root,
PKT_secret_key *pri_sk, PKT_secret_key *sub_sk,
unsigned int use )
unsigned int use, u32 timestamp)
{
PACKET *pkt;
PKT_signature *sig;
@ -984,8 +991,8 @@ write_keybinding( KBNODE root, KBNODE pub_root,
/* and make the signature */
oduap.usage = use;
oduap.pk = sub_pk;
rc=make_keysig_packet(&sig, pri_pk, NULL, sub_pk, pri_sk, 0x18, 0, 0,
sub_pk->timestamp, 0,
rc=make_keysig_packet(&sig, pri_pk, NULL, sub_pk, pri_sk, 0x18,
0, 0, timestamp, 0,
keygen_add_key_flags_and_expire, &oduap );
if( rc ) {
log_error("make_keysig_packet failed: %s\n", g10_errstr(rc) );
@ -995,7 +1002,7 @@ write_keybinding( KBNODE root, KBNODE pub_root,
/* make a backsig */
if(use&PUBKEY_USAGE_SIG)
{
rc=make_backsig(sig,pri_pk,sub_pk,sub_sk);
rc = make_backsig (sig, pri_pk, sub_pk, sub_sk, timestamp);
if(rc)
return rc;
}
@ -3041,6 +3048,15 @@ do_generate_keypair (struct para_data_s *para,struct output_control_s *outctrl,
timestamp = get_parameter_u32 (para, pKEYCREATIONDATE);
/* Note that, depending on the backend (i.e. the used scdaemon
version or the internal code), the card key generation may
update TIMESTAMP for each key. Thus we need to pass TIMESTAMP
to all signing function to make sure that the binding signature
is done using the timestamp of the corresponding (sub)key and
not that of the primary key. An alternative implementation
could tell the signing function the node of the subkey but that
is more work than just to pass the current timestamp. */
if (!card)
{
rc = do_create( get_parameter_algo( para, pKEYTYPE ),
@ -3055,6 +3071,7 @@ do_generate_keypair (struct para_data_s *para,struct output_control_s *outctrl,
else
{
rc = gen_card_key (PUBKEY_ALGO_RSA, 1, 1, pub_root, sec_root, NULL,
&timestamp,
get_parameter_u32 (para, pKEYEXPIRE), para);
if (!rc)
{
@ -3065,9 +3082,9 @@ do_generate_keypair (struct para_data_s *para,struct output_control_s *outctrl,
if(!rc && (revkey=get_parameter_revkey(para,pREVOKER)))
{
rc=write_direct_sig(pub_root,pub_root,pri_sk,revkey);
if(!rc)
write_direct_sig(sec_root,pub_root,pri_sk,revkey);
rc = write_direct_sig (pub_root, pub_root, pri_sk, revkey, timestamp);
if (!rc)
write_direct_sig (sec_root, pub_root, pri_sk, revkey, timestamp);
}
if( !rc && (s=get_parameter_value(para, pUSERID)) )
@ -3076,9 +3093,10 @@ do_generate_keypair (struct para_data_s *para,struct output_control_s *outctrl,
if( !rc )
write_uid(sec_root, s );
if( !rc )
rc = write_selfsigs(sec_root, pub_root, pri_sk,
get_parameter_uint (para, pKEYUSAGE));
if (!rc)
rc = write_selfsigs (sec_root, pub_root, pri_sk,
get_parameter_uint (para, pKEYUSAGE),
timestamp);
}
/* Write the auth key to the card before the encryption key. This
@ -3091,12 +3109,15 @@ do_generate_keypair (struct para_data_s *para,struct output_control_s *outctrl,
if (!rc && card && get_parameter (para, pAUTHKEYTYPE))
{
rc = gen_card_key (PUBKEY_ALGO_RSA, 3, 0, pub_root, sec_root, NULL,
&timestamp,
get_parameter_u32 (para, pKEYEXPIRE), para);
if (!rc)
rc = write_keybinding (pub_root, pub_root, pri_sk, sub_sk, PUBKEY_USAGE_AUTH);
rc = write_keybinding (pub_root, pub_root, pri_sk, sub_sk,
PUBKEY_USAGE_AUTH, timestamp);
if (!rc)
rc = write_keybinding (sec_root, pub_root, pri_sk, sub_sk, PUBKEY_USAGE_AUTH);
rc = write_keybinding (sec_root, pub_root, pri_sk, sub_sk,
PUBKEY_USAGE_AUTH, timestamp);
}
if( !rc && get_parameter( para, pSUBKEYTYPE ) )
@ -3121,6 +3142,7 @@ do_generate_keypair (struct para_data_s *para,struct output_control_s *outctrl,
the card. Write a backup file. */
rc = gen_card_key_with_backup (PUBKEY_ALGO_RSA, 2, 0,
pub_root, sec_root,
timestamp,
get_parameter_u32 (para,
pKEYEXPIRE),
para, s);
@ -3128,15 +3150,18 @@ do_generate_keypair (struct para_data_s *para,struct output_control_s *outctrl,
else
rc = gen_card_key (PUBKEY_ALGO_RSA, 2, 0, pub_root, sec_root,
NULL,
&timestamp,
get_parameter_u32 (para, pKEYEXPIRE), para);
}
if( !rc )
rc = write_keybinding(pub_root, pub_root, pri_sk, sub_sk,
get_parameter_uint (para, pSUBKEYUSAGE));
rc = write_keybinding (pub_root, pub_root, pri_sk, sub_sk,
get_parameter_uint (para, pSUBKEYUSAGE),
timestamp );
if( !rc )
rc = write_keybinding(sec_root, pub_root, pri_sk, sub_sk,
get_parameter_uint (para, pSUBKEYUSAGE));
rc = write_keybinding (sec_root, pub_root, pri_sk, sub_sk,
get_parameter_uint (para, pSUBKEYUSAGE),
timestamp);
did_sub = 1;
}
@ -3351,16 +3376,19 @@ generate_subkeypair( KBNODE pub_keyblock, KBNODE sec_keyblock )
NULL, NULL );
}
rc = do_create( algo, nbits, pub_keyblock, sec_keyblock,
rc = do_create (algo, nbits, pub_keyblock, sec_keyblock,
dek, s2k, &sub_sk, timestamp, expire, 1 );
if( !rc )
rc = write_keybinding(pub_keyblock, pub_keyblock, pri_sk, sub_sk, use);
if( !rc )
rc = write_keybinding(sec_keyblock, pub_keyblock, pri_sk, sub_sk, use);
if( !rc ) {
if (!rc)
rc = write_keybinding (pub_keyblock, pub_keyblock, pri_sk, sub_sk,
use, timestamp);
if (!rc)
rc = write_keybinding (sec_keyblock, pub_keyblock, pri_sk, sub_sk,
use, timestamp);
if (!rc)
{
okay = 1;
write_status_text (STATUS_KEY_CREATED, "S");
}
}
leave:
if( rc )
@ -3466,11 +3494,13 @@ generate_card_subkeypair (KBNODE pub_keyblock, KBNODE sec_keyblock,
if (passphrase)
set_next_passphrase (passphrase);
rc = gen_card_key (algo, keyno, 0, pub_keyblock, sec_keyblock,
&sub_sk, expire, para);
&sub_sk, &timestamp, expire, para);
if (!rc)
rc = write_keybinding (pub_keyblock, pub_keyblock, pri_sk, sub_sk, use);
rc = write_keybinding (pub_keyblock, pub_keyblock, pri_sk, sub_sk, use,
timestamp);
if (!rc)
rc = write_keybinding (sec_keyblock, pub_keyblock, pri_sk, sub_sk, use);
rc = write_keybinding (sec_keyblock, pub_keyblock, pri_sk, sub_sk, use,
timestamp);
if (!rc)
{
okay = 1;
@ -3515,10 +3545,11 @@ write_keyblock( IOBUF out, KBNODE node )
}
/* Note that TIMESTAMP is an in/out arg. */
static int
gen_card_key (int algo, int keyno, int is_primary,
KBNODE pub_root, KBNODE sec_root, PKT_secret_key **ret_sk,
u32 expireval, struct para_data_s *para)
u32 *timestamp, u32 expireval, struct para_data_s *para)
{
#ifdef ENABLE_CARD_SUPPORT
int rc;
@ -3531,7 +3562,7 @@ gen_card_key (int algo, int keyno, int is_primary,
assert (algo == PUBKEY_ALGO_RSA);
/* Fixme: We don't have the serialnumber available, thus passing NULL. */
rc = agent_scd_genkey (&info, keyno, 1, NULL);
rc = agent_scd_genkey (&info, keyno, 1, NULL, timestamp);
/* if (gpg_err_code (rc) == GPG_ERR_EEXIST) */
/* { */
/* tty_printf ("\n"); */
@ -3555,6 +3586,9 @@ gen_card_key (int algo, int keyno, int is_primary,
return gpg_error (GPG_ERR_GENERAL);
}
if (*timestamp != info.created_at)
log_info ("Note that the key does not use the suggested creation date\n");
*timestamp = info.created_at;
pk = xcalloc (1, sizeof *pk );
sk = xcalloc (1, sizeof *sk );
@ -3602,6 +3636,7 @@ gen_card_key (int algo, int keyno, int is_primary,
static int
gen_card_key_with_backup (int algo, int keyno, int is_primary,
KBNODE pub_root, KBNODE sec_root,
u32 timestamp,
u32 expireval, struct para_data_s *para,
const char *backup_dir)
{
@ -3616,7 +3651,7 @@ gen_card_key_with_backup (int algo, int keyno, int is_primary,
sk_unprotected = NULL;
sk_protected = NULL;
rc = generate_raw_key (algo, 1024, make_timestamp (),
rc = generate_raw_key (algo, 1024, timestamp,
&sk_unprotected, &sk_protected);
if (rc)
return rc;

View file

@ -183,7 +183,8 @@ int keygen_add_keyserver_url(PKT_signature *sig, void *opaque);
int keygen_add_notations(PKT_signature *sig,void *opaque);
int keygen_add_revkey(PKT_signature *sig, void *opaque);
int make_backsig(PKT_signature *sig,PKT_public_key *pk,
PKT_public_key *sub_pk,PKT_secret_key *sub_sk);
PKT_public_key *sub_pk,PKT_secret_key *sub_sk,
u32 timestamp);
int generate_subkeypair( KBNODE pub_keyblock, KBNODE sec_keyblock );
#ifdef ENABLE_CARD_SUPPORT
int generate_card_subkeypair (KBNODE pub_keyblock, KBNODE sec_keyblock,

View file

@ -214,6 +214,7 @@ struct
const char *ctapi_driver; /* Library to access the ctAPI. */
const char *pcsc_driver; /* Library to access the PC/SC system. */
int disable_ccid; /* Disable the use of the internal CCID driver. */
int disable_keypad; /* Do not allow the use of a keypad. */
#endif /*ENABLE_CARD_SUPPORT*/
struct