mirror of
git://git.gnupg.org/gnupg.git
synced 2024-12-22 10:19:57 +01:00
First set of changes to backport the new card code from 2.0.
For compatibility reasons a few new files had to be added. Also added estream-printf as this is now used in app-openpgp.c and provides a better and generic asprintf implementation than the hack we used for the W32 code in ttyio.c. Card code is not yet finished.
This commit is contained in:
parent
b478389753
commit
3459c6b015
2
AUTHORS
2
AUTHORS
@ -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+
|
||||
|
||||
|
@ -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
4
NEWS
@ -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)
|
||||
------------------------------------------------
|
||||
|
11
configure.ac
11
configure.ac
@ -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
|
||||
|
@ -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
|
||||
|
1936
g10/apdu.c
1936
g10/apdu.c
File diff suppressed because it is too large
Load Diff
35
g10/apdu.h
35
g10/apdu.h
@ -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);
|
||||
|
@ -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
|
||||
|
||||
|
2001
g10/app-openpgp.c
2001
g10/app-openpgp.c
File diff suppressed because it is too large
Load Diff
459
g10/card-util.c
459
g10/card-util.c
@ -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:
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
1097
g10/ccid-driver.c
1097
g10/ccid-driver.c
File diff suppressed because it is too large
Load Diff
@ -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,
|
||||
|
@ -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 */
|
||||
|
326
g10/iso7816.c
326
g10/iso7816.c
@ -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;
|
||||
@ -397,14 +568,16 @@ iso7816_decipher (int slot, const unsigned char *data, size_t datalen,
|
||||
|
||||
*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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
119
g10/keygen.c
119
g10/keygen.c
@ -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,
|
||||
×tamp,
|
||||
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,
|
||||
×tamp,
|
||||
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,
|
||||
×tamp,
|
||||
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, ×tamp, 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;
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -15,5 +15,6 @@ dynload.h
|
||||
assuan.h
|
||||
compat.h
|
||||
srv.h
|
||||
estream-printf.h
|
||||
|
||||
ChangeLog
|
||||
|
110
include/estream-printf.h
Normal file
110
include/estream-printf.h
Normal 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*/
|
@ -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 );
|
||||
|
@ -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*/
|
||||
|
@ -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))
|
||||
|
@ -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.
|
||||
|
@ -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
48
m4/estream.m4
Normal 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])
|
||||
|
||||
])
|
@ -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.
|
||||
|
@ -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
249
util/convert.c
Normal 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
2110
util/estream-printf.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -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. */
|
||||
|
149
util/strgutil.c
149
util/strgutil.c
@ -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)
|
||||
{
|
||||
|
18
util/ttyio.c
18
util/ttyio.c
@ -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));
|
||||
|
Loading…
x
Reference in New Issue
Block a user