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,6 +1,6 @@
Program: GnuPG
Maintainer: Werner Koch <wk@gnupg.org>
Bug reports: <bug-gnupg@gnu.org>
Bug reports: http://bugs.gnupg.org
Security related bug reports: <security@gnupg.org>
License: GPLv3+

View File

@ -1,3 +1,8 @@
2009-07-21 Werner Koch <wk@g10code.com>
* configure.ac (AH_BOTTOM): Add macros for estream-printf.
(estream_PRINTF_INIT): Add it.
2009-06-05 David Shaw <dshaw@jabberwocky.com>
* configure.ac: Remove Camellia restriction.

4
NEWS
View File

@ -8,6 +8,10 @@ Noteworthy changes in version 1.4.10 (unreleased)
* Fixed a memory leak which made imports of many keys very slow.
* Support v2 OpenPGP cards.
* FIXME: Anything else?
Noteworthy changes in version 1.4.9 (2008-03-26)
------------------------------------------------

View File

@ -499,6 +499,11 @@ is intended for making fat binary builds on OS X. */
#define SAFE_VERSION_DOT '.'
#define SAFE_VERSION_DASH '-'
/* We want to use our memory allocator for estream-printf. */
#define _ESTREAM_PRINTF_MALLOC xtrymalloc
#define _ESTREAM_PRINTF_FREE xfree
#define _ESTREAM_PRINTF_EXTRA_INCLUDE "memory.h"
#endif /*GNUPG_CONFIG_H_INCLUDED*/
])
@ -1049,6 +1054,12 @@ fi
GNUPG_CHECK_MLOCK
GNUPG_FUNC_MKDIR_TAKES_ONE_ARG
#
# Prepare building of estream-printf
#
estream_PRINTF_INIT
dnl
dnl Check whether we can use Linux capabilities as requested
dnl

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

View File

@ -1,3 +1,15 @@
2009-07-21 Werner Koch <wk@g10code.com>
* estream-printf.h: New. Taken from libestream.x
2009-07-20 Werner Koch <wk@g10code.com>
* types.h (strlist_t): Add new alias for STRLIST.
* memory.h (xtrymalloc,xtrystrdup): New.
* util.h: Add prototypes for util/convert.c.
2009-05-26 David Shaw <dshaw@jabberwocky.com>
* http.h: Pass in a STRLIST for additional headers on http_open

View File

@ -15,5 +15,6 @@ dynload.h
assuan.h
compat.h
srv.h
estream-printf.h
ChangeLog

110
include/estream-printf.h Normal file
View File

@ -0,0 +1,110 @@
/* estream-printf.h - Versatile C-99 compliant printf formatting.
* Copyright (C) 2007 g10 Code GmbH
*
* This file is part of Libestream.
*
* Libestream is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
* by the Free Software Foundation; either version 2 of the License,
* or (at your option) any later version.
*
* Libestream is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Libestream; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ESTREAM_PRINTF_H
#define ESTREAM_PRINTF_H
#include <stdarg.h>
#include <stdio.h>
/* To use this file with libraries the following macro is useful:
#define _ESTREAM_EXT_SYM_PREFIX _foo_
This prefixes all external symbols with "_foo_".
For the implementation of the code (estream-printf.c) the following
macros may be used to tune the implementation for certain systems:
#define _ESTREAM_PRINTF_MALLOC foo_malloc
#define _ESTREAM_PRINTF_FREE foo_free
Make estream_asprintf and estream_vasprintf use foo_malloc and
foo_free instead of the standard malloc and free functions to
allocate the memory returned to the caller.
#define _ESTREAM_PRINTF_EXTRA_INCLUDE "foo.h"
This includes the file "foo.h" which may provide prototypes for
the custom memory allocation functions.
*/
#ifdef _ESTREAM_EXT_SYM_PREFIX
#ifndef _ESTREAM_PREFIX
#define _ESTREAM_PREFIX1(x,y) x ## y
#define _ESTREAM_PREFIX2(x,y) _ESTREAM_PREFIX1(x,y)
#define _ESTREAM_PREFIX(x) _ESTREAM_PREFIX2(_ESTREAM_EXT_SYM_PREFIX,x)
#endif /*_ESTREAM_PREFIX*/
#define estream_printf_out_t _ESTREAM_PREFIX(estream_printf_out_t)
#define estream_format _ESTREAM_PREFIX(estream_format)
#define estream_printf _ESTREAM_PREFIX(estream_printf)
#define estream_fprintf _ESTREAM_PREFIX(estream_fprintf)
#define estream_vfprintf _ESTREAM_PREFIX(estream_vfprintf)
#define estream_snprintf _ESTREAM_PREFIX(estream_snprintf)
#define estream_vsnprintf _ESTREAM_PREFIX(estream_vsnprintf)
#define estream_asprintf _ESTREAM_PREFIX(estream_asprintf)
#define estream_vasprintf _ESTREAM_PREFIX(estream_vasprintf)
#endif /*_ESTREAM_EXT_SYM_PREFIX*/
#ifndef _ESTREAM_GCC_A_PRINTF
#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 5 )
# define _ESTREAM_GCC_A_PRINTF( f, a ) __attribute__ ((format (printf,f,a)))
#else
# define _ESTREAM_GCC_A_PRINTF( f, a )
#endif
#endif /*_ESTREAM_GCC_A_PRINTF*/
#ifdef __cplusplus
extern "C"
{
#if 0
}
#endif
#endif
typedef int (*estream_printf_out_t)
(void *outfncarg, const char *buf, size_t buflen);
int estream_format (estream_printf_out_t outfnc, void *outfncarg,
const char *format, va_list vaargs)
_ESTREAM_GCC_A_PRINTF(3,0);
int estream_printf (const char *format, ...)
_ESTREAM_GCC_A_PRINTF(1,2);
int estream_fprintf (FILE *fp, const char *format, ... )
_ESTREAM_GCC_A_PRINTF(2,3);
int estream_vfprintf (FILE *fp, const char *format, va_list arg_ptr)
_ESTREAM_GCC_A_PRINTF(2,0);
int estream_snprintf (char *buf, size_t bufsize, const char *format, ...)
_ESTREAM_GCC_A_PRINTF(3,4);
int estream_vsnprintf (char *buf,size_t bufsize,
const char *format, va_list arg_ptr)
_ESTREAM_GCC_A_PRINTF(3,0);
int estream_asprintf (char **bufp, const char *format, ...)
_ESTREAM_GCC_A_PRINTF(2,3);
int estream_vasprintf (char **bufp, const char *format, va_list arg_ptr)
_ESTREAM_GCC_A_PRINTF(2,0);
#ifdef __cplusplus
}
#endif
#endif /*ESTREAM_PRINTF_H*/

View File

@ -30,6 +30,7 @@
#define M_DBGINFO(a) "["__FILE__ ":" STR(a) "]"
#endif /* __riscos__ */
#define xmalloc(n) m_debug_alloc((n), M_DBGINFO( __LINE__ ) )
#define xtrymalloc(n) m_debug_trymalloc ((n), M_DBGINFO( __LINE__ ))
#define xmalloc_clear(n) m_debug_alloc_clear((n), M_DBGINFO(__LINE__) )
#define xmalloc_secure(n) m_debug_alloc_secure(n), M_DBGINFO(__LINE__) )
#define xmalloc_secure_clear(n) m_debug_alloc_secure_clear((n), M_DBGINFO(__LINE__) )
@ -38,8 +39,10 @@
#define m_check(n) m_debug_check((n), M_DBGINFO(__LINE__) )
/*#define m_copy(a) m_debug_copy((a), M_DBGINFO(__LINE__) )*/
#define xstrdup(a) m_debug_strdup((a), M_DBGINFO(__LINE__) )
#define xtrystrdup(a) m_debug_trystrdup((a), M_DBGINFO(__LINE__) )
void *m_debug_alloc( size_t n, const char *info );
void *m_debug_trymalloc (size_t n, const char *info);
void *m_debug_alloc_clear( size_t n, const char *info );
void *m_debug_alloc_secure( size_t n, const char *info );
void *m_debug_alloc_secure_clear( size_t n, const char *info );
@ -48,9 +51,11 @@ void m_debug_free( void *p, const char *info );
void m_debug_check( const void *a, const char *info );
/*void *m_debug_copy( const void *a, const char *info );*/
char *m_debug_strdup( const char *a, const char *info );
char *m_debug_trystrdup (const char *a, const char *info);
#else
void *xmalloc( size_t n );
void *xtrymalloc (size_t n);
void *xmalloc_clear( size_t n );
void *xmalloc_secure( size_t n );
void *xmalloc_secure_clear( size_t n );
@ -59,6 +64,7 @@ void xfree( void *p );
void m_check( const void *a );
/*void *m_copy( const void *a );*/
char *xstrdup( const char * a);
char *xtrystrdup (const char *a);
#endif
size_t m_size( const void *a );

View File

@ -131,10 +131,12 @@ typedef union {
double g;
} PROPERLY_ALIGNED_TYPE;
typedef struct string_list {
struct string_list {
struct string_list *next;
unsigned int flags;
char d[1];
} *STRLIST;
};
typedef struct string_list *STRLIST;
typedef struct string_list *strlist_t;
#endif /*G10_TYPES_H*/

View File

@ -240,11 +240,13 @@ char *read_w32_registry_string( const char *root,
int write_w32_registry_string(const char *root, const char *dir,
const char *name, const char *value);
/*-- strgutil.c --*/
int vasprintf (char **result, const char *format, va_list args);
int asprintf (char **buf, const char *fmt, ...);
#endif /*_WIN32*/
/*-- strgutil.c --*/
char *xasprintf (const char *fmt, ...);
char *xtryasprintf (const char *fmt, ...);
/*-- pka.c --*/
char *get_pka_info (const char *address, unsigned char *fpr);
@ -252,6 +254,16 @@ char *get_pka_info (const char *address, unsigned char *fpr);
int get_cert(const char *name,size_t max_size,IOBUF *iobuf,
unsigned char **fpr,size_t *fpr_len,char **url);
/*-- convert.c --*/
int hex2bin (const char *string, void *buffer, size_t length);
int hexcolon2bin (const char *string, void *buffer, size_t length);
char *bin2hex (const void *buffer, size_t length, char *stringbuf);
char *bin2hexcolon (const void *buffer, size_t length, char *stringbuf);
const char *hex2str (const char *hexstring,
char *buffer, size_t bufsize, size_t *buflen);
char *hex2str_alloc (const char *hexstring, size_t *r_count);
/**** other missing stuff ****/
#ifndef HAVE_ATEXIT /* For SunOS */
#define atexit(a) (on_exit((a),0))

View File

@ -1,3 +1,7 @@
2009-07-21 Werner Koch <wk@g10code.com>
* estream.m4: New. Taken from libestream.
2007-12-17 Werner Koch <wk@g10code.com>
* ldap.m4: Test for ldap_start_tls_sA.

View File

@ -6,6 +6,7 @@ EXTRA_DIST = glibc2.m4 intl.m4 intldir.m4 lock.m4 visibility.m4 intmax.m4 longdo
po.m4 progtest.m4 stdint_h.m4 uintmax_t.m4 ulonglong.m4 \
readline.m4 libcurl.m4 libusb.m4 tar-ustar.m4 \
ldap.m4 \
noexecstack.m4 autobuild.m4
noexecstack.m4 autobuild.m4 estream.m4

48
m4/estream.m4 Normal file
View File

@ -0,0 +1,48 @@
dnl Autoconf macros for libestream
dnl Copyright (C) 2007 g10 Code GmbH
dnl
dnl This file is free software; as a special exception the author gives
dnl unlimited permission to copy and/or distribute it, with or without
dnl modifications, as long as this notice is preserved.
dnl
dnl This file is distributed in the hope that it will be useful, but
dnl WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
dnl implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
dnl estream_PRINTF_INIT
dnl Prepare build of source included estream-printf.c
dnl
AC_DEFUN([estream_PRINTF_INIT],
[
AC_MSG_NOTICE([checking system features for estream-printf])
AC_TYPE_LONG_LONG_INT
AC_TYPE_LONG_DOUBLE
AC_TYPE_INTMAX_T
AC_TYPE_UINTMAX_T
AC_CHECK_TYPES([ptrdiff_t])
AC_CHECK_SIZEOF([unsigned long])
AC_CHECK_SIZEOF([void *])
AC_CACHE_CHECK([for nl_langinfo and THOUSANDS_SEP],
estream_cv_langinfo_thousands_sep,
[AC_TRY_LINK([#include <langinfo.h>],
[char* cs = nl_langinfo(THOUSANDS_SEP); return !cs;],
estream_cv_langinfo_thousands_sep=yes,
estream_cv_langinfo_thousands_sep=no)
])
if test $estream_cv_langinfo_thousands_sep = yes; then
AC_DEFINE(HAVE_LANGINFO_THOUSANDS_SEP, 1,
[Define if you have <langinfo.h> and nl_langinfo(THOUSANDS_SEP).])
fi
])
dnl estream_INIT
dnl Prepare build of source included estream.c
dnl
AC_DEFUN([estream_INIT],
[
AC_REQUIRE([estream_PRINTF_INIT])
AC_MSG_NOTICE([checking system features for estream])
])

View File

@ -1,3 +1,20 @@
2009-07-21 Werner Koch <wk@g10code.com>
* ttyio.c (tty_printf): Replace vasprintf by xtryasprintf.
(tty_fprintf): Ditto.
* strgutil.c: Include estream-printf.h.
(xasprintf, xtryasprintf): New.
(vasprintf, asprintf): Remove.
* estream-printf.c: New. Taken from libestream.
* Makefile.am (libutil_a_SOURCES): Add it.
* memory.c (trymalloc,trystrdup): New.
* convert.c: New. Taken from GnuPG 2.0 SVN.
* Makefile.am (libutil_a_SOURCES): Add it.
2009-05-26 David Shaw <dshaw@jabberwocky.com>
* http.c (send_request): Pass in a STRLIST for additional headers.

View File

@ -23,7 +23,8 @@ noinst_LIBRARIES = libutil.a libcompat.a
libutil_a_SOURCES = logger.c fileutil.c miscutil.c strgutil.c \
ttyio.c argparse.c memory.c secmem.c errors.c iobuf.c \
dotlock.c http.c pka.c membuf.c cert.c \
dotlock.c http.c pka.c membuf.c cert.c convert.c \
estream-printf.c \
$(libcompat_a_SOURCES)
if USE_SIMPLE_GETTEXT

249
util/convert.c Normal file
View File

@ -0,0 +1,249 @@
/* convert.c - Hex conversion functions.
* Copyright (C) 2006, 2008 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
* GnuPG is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* GnuPG is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <stdlib.h>
#include <errno.h>
#include <ctype.h>
#include "util.h"
#define tohex(n) ((n) < 10 ? ((n) + '0') : (((n) - 10) + 'A'))
/* Convert STRING consisting of hex characters into its binary
representation and store that at BUFFER. BUFFER needs to be of
LENGTH bytes. The function checks that the STRING will convert
exactly to LENGTH bytes. The string is delimited by either end of
string or a white space character. The function returns -1 on
error or the length of the parsed string. */
int
hex2bin (const char *string, void *buffer, size_t length)
{
int i;
const char *s = string;
for (i=0; i < length; )
{
if (!hexdigitp (s) || !hexdigitp (s+1))
return -1; /* Invalid hex digits. */
((unsigned char*)buffer)[i++] = xtoi_2 (s);
s += 2;
}
if (*s && (!isascii (*s) || !isspace (*s)) )
return -1; /* Not followed by Nul or white space. */
if (i != length)
return -1; /* Not of expected length. */
if (*s)
s++; /* Skip the delimiter. */
return s - string;
}
/* Convert STRING consisting of hex characters into its binary representation
and store that at BUFFER. BUFFER needs to be of LENGTH bytes. The
function check that the STRING will convert exactly to LENGTH
bytes. Colons inbetween the hex digits are allowed, if one colon
has been given a colon is expected very 2 characters. The string
is delimited by either end of string or a white space character.
The function returns -1 on error or the length of the parsed
string. */
int
hexcolon2bin (const char *string, void *buffer, size_t length)
{
int i;
const char *s = string;
int need_colon = 0;
for (i=0; i < length; )
{
if (i==1 && *s == ':') /* Skip colons between hex digits. */
{
need_colon = 1;
s++;
}
else if (need_colon && *s == ':')
s++;
else if (need_colon)
return -1; /* Colon expected. */
if (!hexdigitp (s) || !hexdigitp (s+1))
return -1; /* Invalid hex digits. */
((unsigned char*)buffer)[i++] = xtoi_2 (s);
s += 2;
}
if (*s == ':')
return -1; /* Trailing colons are not allowed. */
if (*s && (!isascii (*s) || !isspace (*s)) )
return -1; /* Not followed by Nul or white space. */
if (i != length)
return -1; /* Not of expected length. */
if (*s)
s++; /* Skip the delimiter. */
return s - string;
}
static char *
do_bin2hex (const void *buffer, size_t length, char *stringbuf, int with_colon)
{
const unsigned char *s;
char *p;
if (!stringbuf)
{
/* Not really correct for with_colon but we don't care about the
one wasted byte. */
size_t n = with_colon? 3:2;
size_t nbytes = n * length + 1;
if (length && (nbytes-1) / n != length)
{
errno = ENOMEM;
return NULL;
}
stringbuf = xtrymalloc (nbytes);
if (!stringbuf)
return NULL;
}
for (s = buffer, p = stringbuf; length; length--, s++)
{
if (with_colon && s != buffer)
*p++ = ':';
*p++ = tohex ((*s>>4)&15);
*p++ = tohex (*s&15);
}
*p = 0;
return stringbuf;
}
/* Convert LENGTH bytes of data in BUFFER into hex encoding and store
that at the provided STRINGBUF. STRINGBUF must be allocated of at
least (2*LENGTH+1) bytes or be NULL so that the function mallocs an
appropriate buffer. Returns STRINGBUF or NULL on error (which may
only occur if STRINGBUF has been NULL and the internal malloc
failed). */
char *
bin2hex (const void *buffer, size_t length, char *stringbuf)
{
return do_bin2hex (buffer, length, stringbuf, 0);
}
/* Convert LENGTH bytes of data in BUFFER into hex encoding and store
that at the provided STRINGBUF. STRINGBUF must be allocated of at
least (3*LENGTH+1) bytes or be NULL so that the function mallocs an
appropriate buffer. Returns STRINGBUF or NULL on error (which may
only occur if STRINGBUF has been NULL and the internal malloc
failed). */
char *
bin2hexcolon (const void *buffer, size_t length, char *stringbuf)
{
return do_bin2hex (buffer, length, stringbuf, 1);
}
/* Convert HEXSTRING consisting of hex characters into string and
store that at BUFFER. HEXSTRING is either delimited by end of
string or a white space character. The function makes sure that
the resulting string in BUFFER is terminated by a Nul character.
BUFSIZE is the availabe length of BUFFER; if the converted result
plus a possible required Nul character does not fit into this
buffer, the function returns NULL and won't change the existing
conent of buffer. In-place conversion is possible as long as
BUFFER points to HEXSTRING.
If BUFFER is NULL and bufsize is 0 the function scans HEXSTRING but
does not store anything. This may be used to find the end of
hexstring.
On sucess the function returns a pointer to the next character
after HEXSTRING (which is either end-of-string or a the next white
space). If BUFLEN is not NULL the strlen of buffer is stored
there; this will even be done if BUFFER has been passed as NULL. */
const char *
hex2str (const char *hexstring, char *buffer, size_t bufsize, size_t *buflen)
{
const char *s = hexstring;
int idx, count;
int need_nul = 0;
if (buflen)
*buflen = 0;
for (s=hexstring, count=0; hexdigitp (s) && hexdigitp (s+1); s += 2, count++)
;
if (*s && (!isascii (*s) || !isspace (*s)) )
return NULL; /* Not followed by Nul or white space. */
/* We need to append a nul character. However we don't want that if
the hexstring already ends with "00". */
need_nul = ((s == hexstring) || !(s[-2] == '0' && s[-1] == '0'));
if (need_nul)
count++;
if (buffer)
{
if (count > bufsize)
return NULL; /* Too long. */
for (s=hexstring, idx=0; hexdigitp (s) && hexdigitp (s+1); s += 2)
((unsigned char*)buffer)[idx++] = xtoi_2 (s);
if (need_nul)
buffer[idx] = 0;
}
if (buflen)
*buflen = count - 1;
return s;
}
/* Same as hex2str but this function allocated a new string. Returns
NULL on error. If R_COUNT is not NULL, the number of scanned bytes
will be stored there. ERRNO is set on error. */
char *
hex2str_alloc (const char *hexstring, size_t *r_count)
{
const char *tail;
size_t nbytes;
char *result;
tail = hex2str (hexstring, NULL, 0, &nbytes);
if (!tail)
{
if (r_count)
*r_count = 0;
errno = EINVAL;
return NULL;
}
if (r_count)
*r_count = tail - hexstring;
result = xtrymalloc (nbytes+1);
if (!result)
return NULL;
if (!hex2str (hexstring, result, nbytes+1, NULL))
BUG ();
return result;
}

2110
util/estream-printf.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -62,6 +62,7 @@
#define M_GUARD 1
#endif
#undef xmalloc
#undef xtrymalloc
#undef xmalloc_clear
#undef xmalloc_secure
#undef xmalloc_secure_clear
@ -69,6 +70,7 @@
#undef xfree
#undef m_check
#undef xstrdup
#undef xtrystrdup
#define FNAME(a) m_debug_ ##a
#define FNAMEX(a) m_debug_ ##a
#define FNAMEXM(a) m_debug_ ##a
@ -444,6 +446,30 @@ FNAMEXM(alloc)( size_t n FNAMEPRT )
#endif
}
/* Allocate memory of size n. This function returns NULL if we do not
have enough memory. */
void *
FNAMEX(trymalloc)(size_t n FNAMEPRT)
{
#ifdef M_GUARD
char *p;
if (!n)
n = 1;
p = malloc (n + EXTRA_ALIGN+5);
if (!p)
return NULL;
store_len(p,n,0);
used_memory += n;
p[4+EXTRA_ALIGN+n] = MAGIC_END_BYTE;
return p+EXTRA_ALIGN+4;
#else
/* Mallocing zero bytes is undefined by ISO-C, so we better make
sure that it won't happen. */
return malloc (n? n: 1);
#endif
}
/****************
* Allocate memory of size n from the secure memory pool.
* This function gives up if we do not have enough memory
@ -616,6 +642,16 @@ FNAMEX(strdup)( const char *a FNAMEPRT )
return p;
}
char *
FNAMEX(trystrdup)(const char *a FNAMEPRT)
{
size_t n = strlen (a);
char *p = FNAMEX(trymalloc)(n+1 FNAMEARG);
if (p)
strcpy (p, a);
return p;
}
/* Wrapper around xmalloc_clear to take the usual 2 arguments of a
calloc style function. */

View File

@ -1,6 +1,6 @@
/* strgutil.c - string utilities
* Copyright (C) 1994, 1998, 1999, 2000, 2001,
* 2003, 2004, 2005 Free Software Foundation, Inc.
* 2003, 2004, 2005, 2009 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@ -47,6 +47,14 @@
#include "memory.h"
#include "i18n.h"
#include "dynload.h"
#include "estream-printf.h"
/* Our xasprintf replacements are expected to work with our memory
allocator. Let's test for this here. */
#if !defined(_ESTREAM_PRINTF_MALLOC) || !defined(_ESTREAM_PRINTF_FREE)
#error Please define _ESTREAM_PRINTF_MALLOC and _FREE
#endif
#ifndef USE_GNUPG_ICONV
@ -1040,6 +1048,40 @@ utf8_to_native( const char *string, size_t length, int delim )
}
}
/* Same as asprintf but return an allocated buffer suitable to be
freed using xfree. This function simply dies on memory failure,
thus no extra check is required. */
char *
xasprintf (const char *fmt, ...)
{
va_list ap;
char *buf;
va_start (ap, fmt);
if (estream_vasprintf (&buf, fmt, ap) < 0)
log_fatal ("estream_asprintf failed: %s\n", strerror (errno));
va_end (ap);
return buf;
}
/* Same as above but return NULL on memory failure. */
char *
xtryasprintf (const char *fmt, ...)
{
int rc;
va_list ap;
char *buf;
va_start (ap, fmt);
rc = estream_vasprintf (&buf, fmt, ap);
va_end (ap);
if (rc < 0)
return NULL;
return buf;
}
/****************************************************
******** locale insensitive ctype functions ********
****************************************************/
@ -1127,111 +1169,6 @@ strncasecmp( const char *a, const char *b, size_t n )
#ifdef _WIN32
/*
* Like vsprintf but provides a pointer to malloc'd storage, which
* must be freed by the caller (xfree). Taken from libiberty as
* found in gcc-2.95.2 and a little bit modernized.
* FIXME: Write a new CRT for W32.
*/
int
vasprintf (char **result, const char *format, va_list args)
{
const char *p = format;
/* Add one to make sure that it is never zero, which might cause malloc
to return NULL. */
int total_width = strlen (format) + 1;
va_list ap;
/* this is not really portable but works under Windows */
memcpy ( &ap, &args, sizeof (va_list));
while (*p != '\0')
{
if (*p++ == '%')
{
while (strchr ("-+ #0", *p))
++p;
if (*p == '*')
{
++p;
total_width += abs (va_arg (ap, int));
}
else
{
char *endp;
total_width += strtoul (p, &endp, 10);
p = endp;
}
if (*p == '.')
{
++p;
if (*p == '*')
{
++p;
total_width += abs (va_arg (ap, int));
}
else
{
char *endp;
total_width += strtoul (p, &endp, 10);
p = endp;
}
}
while (strchr ("hlL", *p))
++p;
/* Should be big enough for any format specifier except %s
and floats. */
total_width += 30;
switch (*p)
{
case 'd':
case 'i':
case 'o':
case 'u':
case 'x':
case 'X':
case 'c':
(void) va_arg (ap, int);
break;
case 'f':
case 'e':
case 'E':
case 'g':
case 'G':
(void) va_arg (ap, double);
/* Since an ieee double can have an exponent of 307, we'll
make the buffer wide enough to cover the gross case. */
total_width += 307;
case 's':
total_width += strlen (va_arg (ap, char *));
break;
case 'p':
case 'n':
(void) va_arg (ap, char *);
break;
}
}
}
*result = xmalloc (total_width);
if (*result != NULL)
return vsprintf (*result, format, args);
else
return 0;
}
int
asprintf (char **buf, const char *fmt, ...)
{
int status;
va_list ap;
va_start (ap, fmt);
status = vasprintf (buf, fmt, ap);
va_end (ap);
return status;
}
const char *
w32_strerror (int w32_errno)
{

View File

@ -239,13 +239,14 @@ tty_printf( const char *fmt, ... )
va_start( arg_ptr, fmt ) ;
#ifdef _WIN32
{
char *buf = NULL;
char *buf;
int n;
DWORD nwritten;
n = vasprintf(&buf, fmt, arg_ptr);
if( !buf )
log_bug("vasprintf() failed\n");
buf = xtryasprintf(fmt, arg_ptr);
if (!buf)
log_bug("xtryasprintf() failed\n");
n = strlen (buf);
if (!WriteConsoleA (con.out, buf, n, &nwritten, NULL))
log_fatal ("WriteConsole failed: %s", w32_strerror (0));
@ -286,13 +287,14 @@ tty_fprintf (FILE *fp, const char *fmt, ... )
va_start( arg_ptr, fmt ) ;
#ifdef _WIN32
{
char *buf = NULL;
char *buf;
int n;
DWORD nwritten;
n = vasprintf(&buf, fmt, arg_ptr);
if( !buf )
log_bug("vasprintf() failed\n");
buf = xtryasprintf (fmt, arg_ptr);
if (!buf)
log_bug ("xtryasprintf() failed\n");
n = strlen (buf);
if (!WriteConsoleA (con.out, buf, n, &nwritten, NULL))
log_fatal ("WriteConsole failed: %s", w32_strerror (0));