mirror of
git://git.gnupg.org/gnupg.git
synced 2025-01-03 12:11:33 +01:00
Updated card stuff to support T=0 cards.
This commit is contained in:
parent
9a2a2904cc
commit
b4b9f891e2
2
README
2
README
@ -307,7 +307,7 @@
|
||||
certify that they know the owner of the keys they sign. If you then
|
||||
trust all the introducers to have correctly signed other keys, you
|
||||
can be be sure that the other key really belongs to the one who
|
||||
claims to own it..
|
||||
claims to own it.
|
||||
|
||||
There are 2 steps to validate a key:
|
||||
1. First check that there is a complete chain
|
||||
|
@ -782,7 +782,7 @@ The format of this file is as follows:
|
||||
Handle: <string>
|
||||
This is an optional parameter only used with the status lines
|
||||
KEY_CREATED and KEY_NOT_CREATED. STRING may be up to 100
|
||||
characters and should not contauin spaces. It is useful for
|
||||
characters and should not contain spaces. It is useful for
|
||||
batch key generation to associate a key parameter block with a
|
||||
status line.
|
||||
|
||||
|
@ -1,5 +1,20 @@
|
||||
2005-09-07 Werner Koch <wk@g10code.com>
|
||||
|
||||
* cardglue.h (GPG_ERR_TOO_LARGE): New.
|
||||
|
||||
* apdu.c, apdu.h, iso7816.c, iso7816.h
|
||||
* ccid-driver.c, ccid-driver.h: Updated from GnuPG 1.9 source.
|
||||
Changes are:
|
||||
* iso7816.c (iso7816_select_path): New.
|
||||
* iso7816.c (iso7816_read_binary): Use Le=0 when reading all
|
||||
data. Handle 6C00 error and take 6B00 as indication for EOF.
|
||||
* apdu.h (SW_EXACT_LENGTH_P): New.
|
||||
* apdu.c (new_reader_slot, reset_pcsc_reader, pcsc_get_status)
|
||||
(open_pcsc_reader): Set new reader state IS_T0.
|
||||
(apdu_send_le): When doing T=0 make sure not to send Lc and Le.
|
||||
Problem reported by Carl Meijer.
|
||||
(apdu_send_direct): Initialize RESULTLEN.
|
||||
|
||||
* misc.c (parse_options): Allow meta option "help" to list all
|
||||
options and to exit the program.
|
||||
|
||||
|
451
g10/apdu.c
451
g10/apdu.c
@ -21,6 +21,10 @@
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
/* NOTE: This module is also used by other software, thus the use of
|
||||
the macro USE_GNU_PTH is mandatory. For GnuPG this macro is
|
||||
guaranteed to be defined true. */
|
||||
|
||||
#include <config.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
@ -33,12 +37,7 @@
|
||||
# include <unistd.h>
|
||||
# include <fcntl.h>
|
||||
#endif
|
||||
#ifdef HAVE_OPENSC
|
||||
# include <opensc/opensc.h>
|
||||
# ifdef USE_GNU_PTH
|
||||
# undef USE_GNU_PTH
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
/* If requested include the definitions for the remote APDU protocol
|
||||
code. */
|
||||
@ -120,12 +119,6 @@ struct reader_table_s {
|
||||
pid_t pid;
|
||||
#endif /*NEED_PCSC_WRAPPER*/
|
||||
} pcsc;
|
||||
#ifdef HAVE_OPENSC
|
||||
struct {
|
||||
struct sc_context *ctx;
|
||||
struct sc_card *scard;
|
||||
} osc;
|
||||
#endif /*HAVE_OPENSC*/
|
||||
#ifdef USE_G10CODE_RAPDU
|
||||
struct {
|
||||
rapdu_t handle;
|
||||
@ -134,6 +127,7 @@ struct reader_table_s {
|
||||
char *rdrname; /* Name of the connected reader or NULL if unknown. */
|
||||
int last_status;
|
||||
int status;
|
||||
int is_t0; /* True if we know that we are running T=0. */
|
||||
unsigned char atr[33];
|
||||
size_t atrlen; /* A zero length indicates that the ATR has
|
||||
not yet been read; i.e. the card is not
|
||||
@ -151,12 +145,12 @@ static struct reader_table_s reader_table[MAX_READER];
|
||||
|
||||
|
||||
/* ct API function pointer. */
|
||||
static char (DLSTDCALL * CT_init) (unsigned short ctn, unsigned short Pn);
|
||||
static char (DLSTDCALL * CT_data) (unsigned short ctn, unsigned char *dad,
|
||||
static char (* DLSTDCALL CT_init) (unsigned short ctn, unsigned short Pn);
|
||||
static char (* DLSTDCALL CT_data) (unsigned short ctn, unsigned char *dad,
|
||||
unsigned char *sad, unsigned short lc,
|
||||
unsigned char *cmd, unsigned short *lr,
|
||||
unsigned char *rsp);
|
||||
static char (DLSTDCALL * CT_close) (unsigned short ctn);
|
||||
static char (* DLSTDCALL CT_close) (unsigned short ctn);
|
||||
|
||||
/* PC/SC constants and function pointer. */
|
||||
#define PCSC_SCOPE_USER 0
|
||||
@ -197,6 +191,28 @@ static char (DLSTDCALL * CT_close) (unsigned short ctn);
|
||||
#define PCSC_STATE_INUSE 0x0100 /* Shared mode. */
|
||||
#define PCSC_STATE_MUTE 0x0200 /* Unresponsive card. */
|
||||
|
||||
/* Some PC/SC error codes. */
|
||||
#define PCSC_E_CANCELLED 0x80100002
|
||||
#define PCSC_E_CANT_DISPOSE 0x8010000E
|
||||
#define PCSC_E_INSUFFICIENT_BUFFER 0x80100008
|
||||
#define PCSC_E_INVALID_ATR 0x80100015
|
||||
#define PCSC_E_INVALID_HANDLE 0x80100003
|
||||
#define PCSC_E_INVALID_PARAMETER 0x80100004
|
||||
#define PCSC_E_INVALID_TARGET 0x80100005
|
||||
#define PCSC_E_INVALID_VALUE 0x80100011
|
||||
#define PCSC_E_NO_MEMORY 0x80100006
|
||||
#define PCSC_E_UNKNOWN_READER 0x80100009
|
||||
#define PCSC_E_TIMEOUT 0x8010000A
|
||||
#define PCSC_E_SHARING_VIOLATION 0x8010000B
|
||||
#define PCSC_E_NO_SMARTCARD 0x8010000C
|
||||
#define PCSC_E_UNKNOWN_CARD 0x8010000D
|
||||
#define PCSC_E_PROTO_MISMATCH 0x8010000F
|
||||
#define PCSC_E_NOT_READY 0x80100010
|
||||
#define PCSC_E_SYSTEM_CANCELLED 0x80100012
|
||||
#define PCSC_E_NOT_TRANSACTED 0x80100016
|
||||
#define PCSC_E_READER_UNAVAILABLE 0x80100017
|
||||
#define PCSC_W_REMOVED_CARD 0x80100069
|
||||
|
||||
|
||||
struct pcsc_io_request_s
|
||||
{
|
||||
@ -218,49 +234,52 @@ struct pcsc_readerstate_s
|
||||
|
||||
typedef struct pcsc_readerstate_s *pcsc_readerstate_t;
|
||||
|
||||
long (DLSTDCALL * pcsc_establish_context) (unsigned long scope,
|
||||
long (* DLSTDCALL pcsc_establish_context) (unsigned long scope,
|
||||
const void *reserved1,
|
||||
const void *reserved2,
|
||||
unsigned long *r_context);
|
||||
long (DLSTDCALL * pcsc_release_context) (unsigned long context);
|
||||
long (DLSTDCALL * pcsc_list_readers) (unsigned long context,
|
||||
long (* DLSTDCALL pcsc_release_context) (unsigned long context);
|
||||
long (* DLSTDCALL pcsc_list_readers) (unsigned long context,
|
||||
const char *groups,
|
||||
char *readers, unsigned long*readerslen);
|
||||
long (DLSTDCALL * pcsc_get_status_change) (unsigned long context,
|
||||
long (* DLSTDCALL pcsc_get_status_change) (unsigned long context,
|
||||
unsigned long timeout,
|
||||
pcsc_readerstate_t readerstates,
|
||||
unsigned long nreaderstates);
|
||||
long (DLSTDCALL * pcsc_connect) (unsigned long context,
|
||||
long (* DLSTDCALL pcsc_connect) (unsigned long context,
|
||||
const char *reader,
|
||||
unsigned long share_mode,
|
||||
unsigned long preferred_protocols,
|
||||
unsigned long *r_card,
|
||||
unsigned long *r_active_protocol);
|
||||
long (DLSTDCALL * pcsc_reconnect) (unsigned long card,
|
||||
long (* DLSTDCALL pcsc_reconnect) (unsigned long card,
|
||||
unsigned long share_mode,
|
||||
unsigned long preferred_protocols,
|
||||
unsigned long initialization,
|
||||
unsigned long *r_active_protocol);
|
||||
long (DLSTDCALL * pcsc_disconnect) (unsigned long card,
|
||||
long (* DLSTDCALL pcsc_disconnect) (unsigned long card,
|
||||
unsigned long disposition);
|
||||
long (DLSTDCALL * pcsc_status) (unsigned long card,
|
||||
long (* DLSTDCALL pcsc_status) (unsigned long card,
|
||||
char *reader, unsigned long *readerlen,
|
||||
unsigned long *r_state,
|
||||
unsigned long *r_protocol,
|
||||
unsigned char *atr, unsigned long *atrlen);
|
||||
long (DLSTDCALL * pcsc_begin_transaction) (unsigned long card);
|
||||
long (DLSTDCALL * pcsc_end_transaction) (unsigned long card);
|
||||
long (DLSTDCALL * pcsc_transmit) (unsigned long card,
|
||||
long (* DLSTDCALL pcsc_begin_transaction) (unsigned long card);
|
||||
long (* DLSTDCALL pcsc_end_transaction) (unsigned long card);
|
||||
long (* DLSTDCALL pcsc_transmit) (unsigned long card,
|
||||
const pcsc_io_request_t send_pci,
|
||||
const unsigned char *send_buffer,
|
||||
unsigned long send_len,
|
||||
pcsc_io_request_t recv_pci,
|
||||
unsigned char *recv_buffer,
|
||||
unsigned long *recv_len);
|
||||
long (DLSTDCALL * pcsc_set_timeout) (unsigned long context,
|
||||
long (* DLSTDCALL pcsc_set_timeout) (unsigned long context,
|
||||
unsigned long timeout);
|
||||
|
||||
|
||||
/* Prototypes. */
|
||||
static int pcsc_get_status (int slot, unsigned int *status);
|
||||
|
||||
|
||||
|
||||
/*
|
||||
@ -305,6 +324,7 @@ new_reader_slot (void)
|
||||
|
||||
reader_table[reader].used = 1;
|
||||
reader_table[reader].last_status = 0;
|
||||
reader_table[reader].is_t0 = 1;
|
||||
#ifdef NEED_PCSC_WRAPPER
|
||||
reader_table[reader].pcsc.req_fd = -1;
|
||||
reader_table[reader].pcsc.rsp_fd = -1;
|
||||
@ -583,6 +603,10 @@ open_ct_reader (int port)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
PC/SC Interface
|
||||
*/
|
||||
|
||||
#ifdef NEED_PCSC_WRAPPER
|
||||
static int
|
||||
writen (int fd, const void *buf, size_t nbytes)
|
||||
@ -696,9 +720,34 @@ pcsc_error_string (long err)
|
||||
return s;
|
||||
}
|
||||
|
||||
/*
|
||||
PC/SC Interface
|
||||
*/
|
||||
/* Map PC/SC error codes to our special host status words. */
|
||||
static int
|
||||
pcsc_error_to_sw (long ec)
|
||||
{
|
||||
int rc;
|
||||
|
||||
switch (ec)
|
||||
{
|
||||
case 0: rc = 0; break;
|
||||
|
||||
case PCSC_E_CANCELLED: rc = SW_HOST_ABORTED; break;
|
||||
case PCSC_E_NO_MEMORY: rc = SW_HOST_OUT_OF_CORE; break;
|
||||
case PCSC_E_TIMEOUT: rc = SW_HOST_CARD_IO_ERROR; break;
|
||||
case PCSC_E_SHARING_VIOLATION: rc = SW_HOST_LOCKING_FAILED; break;
|
||||
case PCSC_E_NO_SMARTCARD: rc = SW_HOST_NO_CARD; break;
|
||||
case PCSC_W_REMOVED_CARD: rc = SW_HOST_NO_CARD; break;
|
||||
|
||||
case PCSC_E_INVALID_TARGET:
|
||||
case PCSC_E_INVALID_VALUE:
|
||||
case PCSC_E_INVALID_HANDLE:
|
||||
case PCSC_E_INVALID_PARAMETER:
|
||||
case PCSC_E_INSUFFICIENT_BUFFER: rc = SW_HOST_INV_VALUE; break;
|
||||
|
||||
default: rc = SW_HOST_GENERAL_ERROR; break;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void
|
||||
dump_pcsc_reader_status (int slot)
|
||||
@ -714,6 +763,8 @@ dump_pcsc_reader_status (int slot)
|
||||
}
|
||||
|
||||
|
||||
/* Send an PC/SC reset command and return a status word on error or 0
|
||||
on success. */
|
||||
static int
|
||||
reset_pcsc_reader (int slot)
|
||||
{
|
||||
@ -723,6 +774,8 @@ reset_pcsc_reader (int slot)
|
||||
size_t len;
|
||||
int i, n;
|
||||
unsigned char msgbuf[9];
|
||||
unsigned int dummy_status;
|
||||
int sw = SW_HOST_CARD_IO_ERROR;
|
||||
|
||||
slotp = reader_table + slot;
|
||||
|
||||
@ -731,7 +784,7 @@ reset_pcsc_reader (int slot)
|
||||
|| slotp->pcsc.pid == (pid_t)(-1) )
|
||||
{
|
||||
log_error ("pcsc_get_status: pcsc-wrapper not running\n");
|
||||
return SW_HOST_CARD_IO_ERROR;
|
||||
return sw;
|
||||
}
|
||||
|
||||
msgbuf[0] = 0x05; /* RESET command. */
|
||||
@ -763,17 +816,25 @@ reset_pcsc_reader (int slot)
|
||||
len -= 4; /* Already read the error code. */
|
||||
if (len > DIM (slotp->atr))
|
||||
{
|
||||
log_error ("PC/SC returned a too large ATR (len=%x)\n", len);
|
||||
log_error ("PC/SC returned a too large ATR (len=%lx)\n",
|
||||
(unsigned long)len);
|
||||
sw = SW_HOST_GENERAL_ERROR;
|
||||
goto command_failed;
|
||||
}
|
||||
err = (msgbuf[5] << 24) | (msgbuf[6] << 16) | (msgbuf[7] << 8 ) | msgbuf[8];
|
||||
if (err)
|
||||
{
|
||||
log_error ("PC/SC RESET failed: %s\n", pcsc_error_string (err));
|
||||
log_error ("PC/SC RESET failed: %s (0x%lx)\n",
|
||||
pcsc_error_string (err), err);
|
||||
/* If the error code is no smart card, we should not considere
|
||||
this a major error and close the wrapper. */
|
||||
sw = pcsc_error_to_sw (err);
|
||||
if (err == PCSC_E_NO_SMARTCARD)
|
||||
return sw;
|
||||
goto command_failed;
|
||||
}
|
||||
|
||||
/* The open fucntion may return a zero for the ATR length to
|
||||
/* The open function may return a zero for the ATR length to
|
||||
indicate that no card is present. */
|
||||
n = len;
|
||||
if (n)
|
||||
@ -787,6 +848,9 @@ reset_pcsc_reader (int slot)
|
||||
}
|
||||
slotp->atrlen = len;
|
||||
|
||||
/* Read the status so that IS_T0 will be set. */
|
||||
pcsc_get_status (slot, &dummy_status);
|
||||
|
||||
return 0;
|
||||
|
||||
command_failed:
|
||||
@ -797,7 +861,7 @@ reset_pcsc_reader (int slot)
|
||||
kill (slotp->pcsc.pid, SIGTERM);
|
||||
slotp->pcsc.pid = (pid_t)(-1);
|
||||
slotp->used = 0;
|
||||
return -1;
|
||||
return sw;
|
||||
|
||||
#else /* !NEED_PCSC_WRAPPER */
|
||||
long err;
|
||||
@ -828,7 +892,7 @@ reset_pcsc_reader (int slot)
|
||||
log_error ("pcsc_connect failed: %s (0x%lx)\n",
|
||||
pcsc_error_string (err), err);
|
||||
reader_table[slot].pcsc.card = 0;
|
||||
return SW_HOST_CARD_IO_ERROR;
|
||||
return pcsc_error_to_sw (err);
|
||||
}
|
||||
|
||||
|
||||
@ -843,11 +907,12 @@ reset_pcsc_reader (int slot)
|
||||
log_error ("pcsc_status failed: %s (0x%lx)\n",
|
||||
pcsc_error_string (err), err);
|
||||
reader_table[slot].atrlen = 0;
|
||||
return SW_HOST_CARD_IO_ERROR;
|
||||
return pcsc_error_to_sw (err);
|
||||
}
|
||||
if (atrlen >= DIM (reader_table[0].atr))
|
||||
log_bug ("ATR returned by pcsc_status is too large\n");
|
||||
reader_table[slot].atrlen = atrlen;
|
||||
reader_table[slot].is_t0 = !!(card_protocol & PCSC_PROTOCOL_T0);
|
||||
|
||||
return 0;
|
||||
#endif /* !NEED_PCSC_WRAPPER */
|
||||
@ -863,7 +928,8 @@ pcsc_get_status (int slot, unsigned int *status)
|
||||
size_t len, full_len;
|
||||
int i, n;
|
||||
unsigned char msgbuf[9];
|
||||
unsigned char buffer[12];
|
||||
unsigned char buffer[16];
|
||||
int sw = SW_HOST_CARD_IO_ERROR;
|
||||
|
||||
slotp = reader_table + slot;
|
||||
|
||||
@ -872,7 +938,7 @@ pcsc_get_status (int slot, unsigned int *status)
|
||||
|| slotp->pcsc.pid == (pid_t)(-1) )
|
||||
{
|
||||
log_error ("pcsc_get_status: pcsc-wrapper not running\n");
|
||||
return SW_HOST_CARD_IO_ERROR;
|
||||
return sw;
|
||||
}
|
||||
|
||||
msgbuf[0] = 0x04; /* STATUS command. */
|
||||
@ -907,19 +973,26 @@ pcsc_get_status (int slot, unsigned int *status)
|
||||
{
|
||||
log_error ("pcsc_status failed: %s (0x%lx)\n",
|
||||
pcsc_error_string (err), err);
|
||||
return SW_HOST_CARD_IO_ERROR;
|
||||
/* This is a proper error code, so return immediately. */
|
||||
return pcsc_error_to_sw (err);
|
||||
}
|
||||
|
||||
full_len = len;
|
||||
|
||||
n = 8 < len ? 8 : len;
|
||||
if ((i=readn (slotp->pcsc.rsp_fd, buffer, n, &len)) || len != 8)
|
||||
/* The current version returns 3 words but we allow also for old
|
||||
versions returning only 2 words. */
|
||||
n = 12 < len ? 12 : len;
|
||||
if ((i=readn (slotp->pcsc.rsp_fd, buffer, n, &len))
|
||||
|| (len != 8 && len != 12))
|
||||
{
|
||||
log_error ("error receiving PC/SC STATUS response: %s\n",
|
||||
i? strerror (errno) : "premature EOF");
|
||||
goto command_failed;
|
||||
}
|
||||
|
||||
slotp->is_t0 = (len == 12 && !!(buffer[11] & PCSC_PROTOCOL_T0));
|
||||
|
||||
|
||||
full_len -= len;
|
||||
/* Newer versions of the wrapper might send more status bytes.
|
||||
Read them. */
|
||||
@ -951,7 +1024,7 @@ pcsc_get_status (int slot, unsigned int *status)
|
||||
kill (slotp->pcsc.pid, SIGTERM);
|
||||
slotp->pcsc.pid = (pid_t)(-1);
|
||||
slotp->used = 0;
|
||||
return -1;
|
||||
return sw;
|
||||
|
||||
#else /*!NEED_PCSC_WRAPPER*/
|
||||
|
||||
@ -964,13 +1037,13 @@ pcsc_get_status (int slot, unsigned int *status)
|
||||
err = pcsc_get_status_change (reader_table[slot].pcsc.context,
|
||||
0,
|
||||
rdrstates, 1);
|
||||
if (err == 0x8010000a) /* Timeout. */
|
||||
err = 0;
|
||||
if (err == PCSC_E_TIMEOUT)
|
||||
err = 0; /* Timeout is no error error here. */
|
||||
if (err)
|
||||
{
|
||||
log_error ("pcsc_get_status_change failed: %s (0x%lx)\n",
|
||||
pcsc_error_string (err), err);
|
||||
return SW_HOST_CARD_IO_ERROR;
|
||||
return pcsc_error_to_sw (err);
|
||||
}
|
||||
|
||||
|
||||
@ -1017,6 +1090,7 @@ pcsc_send_apdu (int slot, unsigned char *apdu, size_t apdulen,
|
||||
size_t len, full_len;
|
||||
int i, n;
|
||||
unsigned char msgbuf[9];
|
||||
int sw = SW_HOST_CARD_IO_ERROR;
|
||||
|
||||
if (!reader_table[slot].atrlen
|
||||
&& (err = reset_pcsc_reader (slot)))
|
||||
@ -1032,7 +1106,7 @@ pcsc_send_apdu (int slot, unsigned char *apdu, size_t apdulen,
|
||||
|| slotp->pcsc.pid == (pid_t)(-1) )
|
||||
{
|
||||
log_error ("pcsc_send_apdu: pcsc-wrapper not running\n");
|
||||
return SW_HOST_CARD_IO_ERROR;
|
||||
return sw;
|
||||
}
|
||||
|
||||
msgbuf[0] = 0x03; /* TRANSMIT command. */
|
||||
@ -1068,7 +1142,7 @@ pcsc_send_apdu (int slot, unsigned char *apdu, size_t apdulen,
|
||||
{
|
||||
log_error ("pcsc_transmit failed: %s (0x%lx)\n",
|
||||
pcsc_error_string (err), err);
|
||||
return SW_HOST_CARD_IO_ERROR;
|
||||
return pcsc_error_to_sw (err);
|
||||
}
|
||||
|
||||
full_len = len;
|
||||
@ -1114,7 +1188,7 @@ pcsc_send_apdu (int slot, unsigned char *apdu, size_t apdulen,
|
||||
kill (slotp->pcsc.pid, SIGTERM);
|
||||
slotp->pcsc.pid = (pid_t)(-1);
|
||||
slotp->used = 0;
|
||||
return -1;
|
||||
return sw;
|
||||
|
||||
#else /*!NEED_PCSC_WRAPPER*/
|
||||
|
||||
@ -1143,7 +1217,7 @@ pcsc_send_apdu (int slot, unsigned char *apdu, size_t apdulen,
|
||||
log_error ("pcsc_transmit failed: %s (0x%lx)\n",
|
||||
pcsc_error_string (err), err);
|
||||
|
||||
return err? SW_HOST_CARD_IO_ERROR:0;
|
||||
return pcsc_error_to_sw (err);
|
||||
#endif /*!NEED_PCSC_WRAPPER*/
|
||||
}
|
||||
|
||||
@ -1200,7 +1274,7 @@ close_pcsc_reader (int slot)
|
||||
log_error ("pcsc_close failed: %s (0x%lx)\n",
|
||||
pcsc_error_string (err), err);
|
||||
|
||||
/* We will the wrapper in any case - errors are merely
|
||||
/* We will close the wrapper in any case - errors are merely
|
||||
informational. */
|
||||
|
||||
command_failed:
|
||||
@ -1223,6 +1297,7 @@ close_pcsc_reader (int slot)
|
||||
#endif /*!NEED_PCSC_WRAPPER*/
|
||||
}
|
||||
|
||||
/* Note: It is a pitty that we can't return proper error codes. */
|
||||
static int
|
||||
open_pcsc_reader (const char *portstr)
|
||||
{
|
||||
@ -1238,6 +1313,8 @@ open_pcsc_reader (const char *portstr)
|
||||
size_t len;
|
||||
unsigned char msgbuf[9];
|
||||
int err;
|
||||
unsigned int dummy_status;
|
||||
int sw = SW_HOST_CARD_IO_ERROR;
|
||||
|
||||
slot = new_reader_slot ();
|
||||
if (slot == -1)
|
||||
@ -1367,19 +1444,21 @@ open_pcsc_reader (const char *portstr)
|
||||
len -= 4; /* Already read the error code. */
|
||||
if (len > DIM (slotp->atr))
|
||||
{
|
||||
log_error ("PC/SC returned a too large ATR (len=%x)\n", len);
|
||||
log_error ("PC/SC returned a too large ATR (len=%lx)\n",
|
||||
(unsigned long)len);
|
||||
goto command_failed;
|
||||
}
|
||||
err = (msgbuf[5] << 24) | (msgbuf[6] << 16) | (msgbuf[7] << 8 ) | msgbuf[8];
|
||||
if (err)
|
||||
{
|
||||
log_error ("PC/SC OPEN failed: %s\n", pcsc_error_string (err));
|
||||
sw = pcsc_error_to_sw (err);
|
||||
goto command_failed;
|
||||
}
|
||||
|
||||
slotp->last_status = 0;
|
||||
|
||||
/* The open fucntion may return a zero for the ATR length to
|
||||
/* The open request may return a zero for the ATR length to
|
||||
indicate that no card is present. */
|
||||
n = len;
|
||||
if (n)
|
||||
@ -1402,6 +1481,9 @@ open_pcsc_reader (const char *portstr)
|
||||
reader_table[slot].send_apdu_reader = pcsc_send_apdu;
|
||||
reader_table[slot].dump_status_reader = dump_pcsc_reader_status;
|
||||
|
||||
/* Read the status so that IS_T0 will be set. */
|
||||
pcsc_get_status (slot, &dummy_status);
|
||||
|
||||
dump_reader_status (slot);
|
||||
return slot;
|
||||
|
||||
@ -1413,7 +1495,9 @@ open_pcsc_reader (const char *portstr)
|
||||
kill (slotp->pcsc.pid, SIGTERM);
|
||||
slotp->pcsc.pid = (pid_t)(-1);
|
||||
slotp->used = 0;
|
||||
/* There is no way to return SW. */
|
||||
return -1;
|
||||
|
||||
#else /*!NEED_PCSC_WRAPPER */
|
||||
long err;
|
||||
int slot;
|
||||
@ -1446,7 +1530,7 @@ open_pcsc_reader (const char *portstr)
|
||||
log_error ("error allocating memory for reader list\n");
|
||||
pcsc_release_context (reader_table[slot].pcsc.context);
|
||||
reader_table[slot].used = 0;
|
||||
return -1;
|
||||
return -1 /*SW_HOST_OUT_OF_CORE*/;
|
||||
}
|
||||
err = pcsc_list_readers (reader_table[slot].pcsc.context,
|
||||
NULL, list, &nreader);
|
||||
@ -1458,7 +1542,7 @@ open_pcsc_reader (const char *portstr)
|
||||
pcsc_release_context (reader_table[slot].pcsc.context);
|
||||
reader_table[slot].used = 0;
|
||||
xfree (list);
|
||||
return -1;
|
||||
return -1 /*pcsc_error_to_sw (err)*/;
|
||||
}
|
||||
|
||||
listlen = nreader;
|
||||
@ -1484,7 +1568,7 @@ open_pcsc_reader (const char *portstr)
|
||||
log_error ("error allocating memory for reader name\n");
|
||||
pcsc_release_context (reader_table[slot].pcsc.context);
|
||||
reader_table[slot].used = 0;
|
||||
return -1;
|
||||
return -1 /*SW_HOST_OUT_OF_CORE*/;
|
||||
}
|
||||
strcpy (reader_table[slot].rdrname, portstr? portstr : list);
|
||||
xfree (list);
|
||||
@ -1495,7 +1579,7 @@ open_pcsc_reader (const char *portstr)
|
||||
PCSC_PROTOCOL_T0|PCSC_PROTOCOL_T1,
|
||||
&reader_table[slot].pcsc.card,
|
||||
&reader_table[slot].pcsc.protocol);
|
||||
if (err == 0x8010000c) /* No smartcard. */
|
||||
if (err == PCSC_E_NO_SMARTCARD)
|
||||
reader_table[slot].pcsc.card = 0;
|
||||
else if (err)
|
||||
{
|
||||
@ -1506,7 +1590,7 @@ open_pcsc_reader (const char *portstr)
|
||||
reader_table[slot].rdrname = NULL;
|
||||
reader_table[slot].used = 0;
|
||||
xfree (list);
|
||||
return -1;
|
||||
return -1 /*pcsc_error_to_sw (err)*/;
|
||||
}
|
||||
|
||||
reader_table[slot].atrlen = 0;
|
||||
@ -1533,6 +1617,7 @@ open_pcsc_reader (const char *portstr)
|
||||
/* If we got to here we know that a card is present
|
||||
and usable. Thus remember this. */
|
||||
reader_table[slot].last_status = (1|2|4| 0x8000);
|
||||
reader_table[slot].is_t0 = !!(card_protocol & PCSC_PROTOCOL_T0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1702,224 +1787,6 @@ open_ccid_reader (const char *portstr)
|
||||
#endif /* HAVE_LIBUSB */
|
||||
|
||||
|
||||
|
||||
#ifdef HAVE_OPENSC
|
||||
/*
|
||||
OpenSC Interface.
|
||||
|
||||
This uses the OpenSC primitives to send APDUs. We need this
|
||||
because we can't mix OpenSC and native (i.e. ctAPI or PC/SC)
|
||||
access to a card for resource conflict reasons.
|
||||
*/
|
||||
|
||||
|
||||
static int
|
||||
close_osc_reader (int slot)
|
||||
{
|
||||
/* FIXME: Implement. */
|
||||
reader_table[slot].used = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
reset_osc_reader (int slot)
|
||||
{
|
||||
return SW_HOST_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
osc_get_status (int slot, unsigned int *status)
|
||||
{
|
||||
return SW_HOST_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
|
||||
/* Actually send the APDU of length APDULEN to SLOT and return a
|
||||
maximum of *BUFLEN data in BUFFER, the actual returned size will be
|
||||
set to BUFLEN. Returns: OpenSC error code. */
|
||||
static int
|
||||
osc_send_apdu (int slot, unsigned char *apdu, size_t apdulen,
|
||||
unsigned char *buffer, size_t *buflen)
|
||||
{
|
||||
long err;
|
||||
struct sc_apdu a;
|
||||
unsigned char data[SC_MAX_APDU_BUFFER_SIZE];
|
||||
unsigned char result[SC_MAX_APDU_BUFFER_SIZE];
|
||||
|
||||
if (DBG_CARD_IO)
|
||||
log_printhex (" APDU_data:", apdu, apdulen);
|
||||
|
||||
if (apdulen < 4)
|
||||
{
|
||||
log_error ("osc_send_apdu: APDU is too short\n");
|
||||
return SW_HOST_INV_VALUE;
|
||||
}
|
||||
|
||||
memset(&a, 0, sizeof a);
|
||||
a.cla = *apdu++;
|
||||
a.ins = *apdu++;
|
||||
a.p1 = *apdu++;
|
||||
a.p2 = *apdu++;
|
||||
apdulen -= 4;
|
||||
|
||||
if (!apdulen)
|
||||
a.cse = SC_APDU_CASE_1;
|
||||
else if (apdulen == 1)
|
||||
{
|
||||
a.le = *apdu? *apdu : 256;
|
||||
apdu++; apdulen--;
|
||||
a.cse = SC_APDU_CASE_2_SHORT;
|
||||
}
|
||||
else
|
||||
{
|
||||
a.lc = *apdu++; apdulen--;
|
||||
if (apdulen < a.lc)
|
||||
{
|
||||
log_error ("osc_send_apdu: APDU shorter than specified in Lc\n");
|
||||
return SW_HOST_INV_VALUE;
|
||||
|
||||
}
|
||||
memcpy(data, apdu, a.lc);
|
||||
apdu += a.lc; apdulen -= a.lc;
|
||||
|
||||
a.data = data;
|
||||
a.datalen = a.lc;
|
||||
|
||||
if (!apdulen)
|
||||
a.cse = SC_APDU_CASE_3_SHORT;
|
||||
else
|
||||
{
|
||||
a.le = *apdu? *apdu : 256;
|
||||
apdu++; apdulen--;
|
||||
if (apdulen)
|
||||
{
|
||||
log_error ("osc_send_apdu: APDU larger than specified\n");
|
||||
return SW_HOST_INV_VALUE;
|
||||
}
|
||||
a.cse = SC_APDU_CASE_4_SHORT;
|
||||
}
|
||||
}
|
||||
|
||||
a.resp = result;
|
||||
a.resplen = DIM(result);
|
||||
|
||||
err = sc_transmit_apdu (reader_table[slot].osc.scard, &a);
|
||||
if (err)
|
||||
{
|
||||
log_error ("sc_apdu_transmit failed: %s\n", sc_strerror (err));
|
||||
return SW_HOST_CARD_IO_ERROR;
|
||||
}
|
||||
|
||||
if (*buflen < 2 || a.resplen > *buflen - 2)
|
||||
{
|
||||
log_error ("osc_send_apdu: provided buffer too short to store result\n");
|
||||
return SW_HOST_INV_VALUE;
|
||||
}
|
||||
memcpy (buffer, a.resp, a.resplen);
|
||||
buffer[a.resplen] = a.sw1;
|
||||
buffer[a.resplen+1] = a.sw2;
|
||||
*buflen = a.resplen + 2;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
open_osc_reader (int portno)
|
||||
{
|
||||
int err;
|
||||
int slot;
|
||||
reader_table_t slotp;
|
||||
|
||||
slot = new_reader_slot ();
|
||||
if (slot == -1)
|
||||
return -1;
|
||||
slotp = reader_table + slot;
|
||||
|
||||
err = sc_establish_context (&slotp->osc.ctx, "scdaemon");
|
||||
if (err)
|
||||
{
|
||||
log_error ("failed to establish SC context: %s\n", sc_strerror (err));
|
||||
slotp->used = 0;
|
||||
return -1;
|
||||
}
|
||||
if (portno < 0 || portno >= slotp->osc.ctx->reader_count)
|
||||
{
|
||||
log_error ("no card reader available\n");
|
||||
sc_release_context (slotp->osc.ctx);
|
||||
slotp->used = 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Redirect to our logging facility. */
|
||||
slotp->osc.ctx->error_file = log_get_stream ();
|
||||
slotp->osc.ctx->debug = opt.debug_sc;
|
||||
slotp->osc.ctx->debug_file = log_get_stream ();
|
||||
|
||||
if (sc_detect_card_presence (slotp->osc.ctx->reader[portno], 0) != 1)
|
||||
{
|
||||
log_error ("no card present\n");
|
||||
sc_release_context (slotp->osc.ctx);
|
||||
slotp->used = 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* We want the standard ISO driver. */
|
||||
/*FIXME: OpenSC does not like "iso7816", so we use EMV for now. */
|
||||
err = sc_set_card_driver(slotp->osc.ctx, "emv");
|
||||
if (err)
|
||||
{
|
||||
log_error ("failed to select the iso7816 driver: %s\n",
|
||||
sc_strerror (err));
|
||||
sc_release_context (slotp->osc.ctx);
|
||||
slotp->used = 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Now connect the card and hope that OpenSC won't try to be too
|
||||
smart. */
|
||||
err = sc_connect_card (slotp->osc.ctx->reader[portno], 0,
|
||||
&slotp->osc.scard);
|
||||
if (err)
|
||||
{
|
||||
log_error ("failed to connect card in reader %d: %s\n",
|
||||
portno, sc_strerror (err));
|
||||
sc_release_context (slotp->osc.ctx);
|
||||
slotp->used = 0;
|
||||
return -1;
|
||||
}
|
||||
if (opt.verbose)
|
||||
log_info ("connected to card in opensc reader %d using driver `%s'\n",
|
||||
portno, slotp->osc.scard->driver->name);
|
||||
|
||||
err = sc_lock (slotp->osc.scard);
|
||||
if (err)
|
||||
{
|
||||
log_error ("can't lock card in reader %d: %s\n",
|
||||
portno, sc_strerror (err));
|
||||
sc_disconnect_card (slotp->osc.scard, 0);
|
||||
sc_release_context (slotp->osc.ctx);
|
||||
slotp->used = 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (slotp->osc.scard->atr_len >= DIM (slotp->atr))
|
||||
log_bug ("ATR returned by opensc is too large\n");
|
||||
slotp->atrlen = slotp->osc.scard->atr_len;
|
||||
memcpy (slotp->atr, slotp->osc.scard->atr, slotp->atrlen);
|
||||
|
||||
reader_table[slot].close_reader = close_osc_reader;
|
||||
reader_table[slot].reset_reader = reset_osc_reader;
|
||||
reader_table[slot].get_status_reader = osc_get_status;
|
||||
reader_table[slot].send_apdu_reader = osc_send_apdu;
|
||||
reader_table[slot].dump_status_reader = NULL;
|
||||
|
||||
dump_reader_status (slot);
|
||||
return slot;
|
||||
}
|
||||
|
||||
#endif /* HAVE_OPENSC */
|
||||
|
||||
|
||||
|
||||
#ifdef USE_G10CODE_RAPDU
|
||||
/*
|
||||
@ -2062,7 +1929,7 @@ my_rapdu_get_status (int slot, unsigned int *status)
|
||||
|
||||
/* Actually send the APDU of length APDULEN to SLOT and return a
|
||||
maximum of *BUFLEN data in BUFFER, the actual returned size will be
|
||||
set to BUFLEN. Returns: OpenSC error code. */
|
||||
set to BUFLEN. Returns: APDU error code. */
|
||||
static int
|
||||
my_rapdu_send_apdu (int slot, unsigned char *apdu, size_t apdulen,
|
||||
unsigned char *buffer, size_t *buflen)
|
||||
@ -2152,6 +2019,7 @@ open_rapdu_reader (int portno,
|
||||
return -1;
|
||||
}
|
||||
|
||||
rapdu_set_reader (slotp->rapdu.handle, portno);
|
||||
|
||||
rapdu_set_iofunc (slotp->rapdu.handle,
|
||||
readfnc, readfnc_value,
|
||||
@ -2257,8 +2125,7 @@ unlock_slot (int slot)
|
||||
|
||||
/* Open the reader and return an internal slot number or -1 on
|
||||
error. If PORTSTR is NULL we default to a suitable port (for ctAPI:
|
||||
the first USB reader. For PC/SC the first listed reader). If
|
||||
OpenSC support is compiled in, we first try to use OpenSC. */
|
||||
the first USB reader. For PC/SC the first listed reader). */
|
||||
int
|
||||
apdu_open_reader (const char *portstr)
|
||||
{
|
||||
@ -2284,16 +2151,6 @@ apdu_open_reader (const char *portstr)
|
||||
|
||||
#endif /* HAVE_LIBUSB */
|
||||
|
||||
#ifdef HAVE_OPENSC
|
||||
if (!opt.disable_opensc)
|
||||
{
|
||||
int port = portstr? atoi (portstr) : 0;
|
||||
|
||||
return open_osc_reader (port);
|
||||
}
|
||||
#endif /* HAVE_OPENSC */
|
||||
|
||||
|
||||
if (opt.ctapi_driver && *opt.ctapi_driver)
|
||||
{
|
||||
int port = portstr? atoi (portstr) : 32768;
|
||||
@ -2561,7 +2418,7 @@ apdu_activate (int slot)
|
||||
unsigned char *
|
||||
apdu_get_atr (int slot, size_t *atrlen)
|
||||
{
|
||||
char *buf;
|
||||
unsigned char *buf;
|
||||
|
||||
if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used )
|
||||
return NULL;
|
||||
@ -2684,7 +2541,7 @@ apdu_send_le(int slot, int class, int ins, int p0, int p1,
|
||||
|
||||
if (lc != -1 && (lc > 255 || lc < 0))
|
||||
return SW_WRONG_LENGTH;
|
||||
if (le != -1 && (le > 256 || le < 1))
|
||||
if (le != -1 && (le > 256 || le < 0))
|
||||
return SW_WRONG_LENGTH;
|
||||
if ((!data && lc != -1) || (data && lc == -1))
|
||||
return SW_HOST_INV_VALUE;
|
||||
@ -2702,9 +2559,13 @@ apdu_send_le(int slot, int class, int ins, int p0, int p1,
|
||||
apdu[apdulen++] = lc;
|
||||
memcpy (apdu+apdulen, data, lc);
|
||||
apdulen += lc;
|
||||
/* T=0 does not allow the use of Lc together with Le; thus
|
||||
disable Le in this case. */
|
||||
if (reader_table[slot].is_t0)
|
||||
le = -1;
|
||||
}
|
||||
if (le != -1)
|
||||
apdu[apdulen++] = le; /* Truncation is okay becuase 0 means 256. */
|
||||
apdu[apdulen++] = le; /* Truncation is okay because 0 means 256. */
|
||||
assert (sizeof (apdu) >= apdulen);
|
||||
/* As safeguard don't pass any garbage from the stack to the driver. */
|
||||
memset (apdu+apdulen, 0, sizeof (apdu) - apdulen);
|
||||
@ -2902,14 +2763,14 @@ apdu_send_direct (int slot, const unsigned char *apdudata, size_t apdudatalen,
|
||||
if ((sw = trylock_slot (slot)))
|
||||
return sw;
|
||||
|
||||
/* We simply trucntate a too long APDU. */
|
||||
/* We simply trunctate a too long APDU. */
|
||||
if (apdudatalen > sizeof apdu)
|
||||
apdudatalen = sizeof apdu;
|
||||
apdulen = apdudatalen;
|
||||
memcpy (apdu, apdudata, apdudatalen);
|
||||
class = apdulen? *apdu : 0;
|
||||
|
||||
|
||||
resultlen = RESULTLEN;
|
||||
rc = send_apdu (slot, apdu, apdulen, result, &resultlen);
|
||||
if (rc || resultlen < 2)
|
||||
{
|
||||
@ -3050,5 +2911,3 @@ apdu_send_direct (int slot, const unsigned char *apdudata, size_t apdudatalen,
|
||||
return 0;
|
||||
#undef RESULTLEN
|
||||
}
|
||||
|
||||
|
||||
|
@ -42,6 +42,7 @@ enum {
|
||||
SW_RECORD_NOT_FOUND = 0x6a83,
|
||||
SW_REF_NOT_FOUND = 0x6a88,
|
||||
SW_BAD_P0_P1 = 0x6b00,
|
||||
SW_EXACT_LENGTH = 0x6c00,
|
||||
SW_INS_NOT_SUP = 0x6d00,
|
||||
SW_CLA_NOT_SUP = 0x6e00,
|
||||
SW_SUCCESS = 0x9000,
|
||||
@ -66,6 +67,8 @@ enum {
|
||||
};
|
||||
|
||||
|
||||
#define SW_EXACT_LENGTH_P(a) (((a)&~0xff) == SW_EXACT_LENGTH)
|
||||
|
||||
|
||||
/* Note , that apdu_open_reader returns no status word but -1 on error. */
|
||||
int apdu_open_reader (const char *portstr);
|
||||
|
@ -112,6 +112,7 @@ typedef struct ctrl_ctx_s *ctrl_t;
|
||||
#define GPG_ERR_UNKNOWN_SEXP G10ERR_INV_ARG
|
||||
#define GPG_ERR_DUP_VALUE G10ERR_INV_ARG
|
||||
#define GPG_ERR_BAD_SECKEY G10ERR_BAD_SECKEY
|
||||
#define GPG_ERR_TOO_LARGE G10ERR_GENERAL
|
||||
|
||||
#define GPG_ERR_EBUSY G10ERR_GENERAL
|
||||
#define GPG_ERR_ENOENT G10ERR_OPEN_FILE
|
||||
|
@ -556,7 +556,7 @@ get_escaped_usb_string (usb_dev_handle *idev, int idx,
|
||||
all in a 2 bute Unicode encoding using little endian. */
|
||||
rc = usb_control_msg (idev, USB_ENDPOINT_IN, USB_REQ_GET_DESCRIPTOR,
|
||||
(USB_DT_STRING << 8), 0,
|
||||
buf, sizeof buf, 1000 /* ms timeout */);
|
||||
(char*)buf, sizeof buf, 1000 /* ms timeout */);
|
||||
if (rc < 4)
|
||||
langid = 0x0409; /* English. */
|
||||
else
|
||||
@ -564,7 +564,7 @@ get_escaped_usb_string (usb_dev_handle *idev, int idx,
|
||||
|
||||
rc = usb_control_msg (idev, USB_ENDPOINT_IN, USB_REQ_GET_DESCRIPTOR,
|
||||
(USB_DT_STRING << 8) + idx, langid,
|
||||
buf, sizeof buf, 1000 /* ms timeout */);
|
||||
(char*)buf, sizeof buf, 1000 /* ms timeout */);
|
||||
if (rc < 2 || buf[1] != USB_DT_STRING)
|
||||
return NULL; /* Error or not a string. */
|
||||
len = buf[0];
|
||||
@ -1156,7 +1156,7 @@ bulk_out (ccid_driver_t handle, unsigned char *msg, size_t msglen)
|
||||
|
||||
rc = usb_bulk_write (handle->idev,
|
||||
handle->ep_bulk_out,
|
||||
msg, msglen,
|
||||
(char*)msg, msglen,
|
||||
1000 /* ms timeout */);
|
||||
if (rc == msglen)
|
||||
return 0;
|
||||
@ -1189,7 +1189,7 @@ bulk_in (ccid_driver_t handle, unsigned char *buffer, size_t length,
|
||||
retry:
|
||||
rc = usb_bulk_read (handle->idev,
|
||||
handle->ep_bulk_in,
|
||||
buffer, length,
|
||||
(char*)buffer, length,
|
||||
timeout);
|
||||
if (rc < 0)
|
||||
{
|
||||
@ -1301,7 +1301,7 @@ ccid_poll (ccid_driver_t handle)
|
||||
|
||||
rc = usb_bulk_read (handle->idev,
|
||||
handle->ep_intr,
|
||||
msg, sizeof msg,
|
||||
(char*)msg, sizeof msg,
|
||||
0 /* ms timeout */ );
|
||||
if (rc < 0 && errno == ETIMEDOUT)
|
||||
return 0;
|
||||
@ -1445,7 +1445,7 @@ ccid_get_atr (ccid_driver_t handle,
|
||||
{
|
||||
tried_iso = 1;
|
||||
/* Try switching to ISO mode. */
|
||||
if (!send_escape_cmd (handle, "\xF1\x01", 2))
|
||||
if (!send_escape_cmd (handle, (const unsigned char*)"\xF1\x01", 2))
|
||||
goto again;
|
||||
}
|
||||
else if (CCID_COMMAND_FAILED (msg))
|
||||
@ -2027,7 +2027,7 @@ ccid_transceive_secure (ccid_driver_t handle,
|
||||
if (handle->id_vendor == VENDOR_SCM)
|
||||
{
|
||||
DEBUGOUT ("sending escape sequence to switch to a case 1 APDU\n");
|
||||
rc = send_escape_cmd (handle, "\x80\x02\x00", 3);
|
||||
rc = send_escape_cmd (handle, (const unsigned char*)"\x80\x02\x00", 3);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
|
@ -78,6 +78,7 @@ map_sw (int sw)
|
||||
case SW_RECORD_NOT_FOUND:ec= GPG_ERR_NOT_FOUND; break;
|
||||
case SW_REF_NOT_FOUND: ec = GPG_ERR_NO_OBJ; break;
|
||||
case SW_BAD_P0_P1: ec = GPG_ERR_INV_VALUE; break;
|
||||
case SW_EXACT_LENGTH: ec = GPG_ERR_INV_VALUE; break;
|
||||
case SW_INS_NOT_SUP: ec = GPG_ERR_CARD; break;
|
||||
case SW_CLA_NOT_SUP: ec = GPG_ERR_CARD; break;
|
||||
case SW_SUCCESS: ec = 0; break;
|
||||
@ -154,7 +155,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,
|
||||
p0, p1, 2, tagbuf );
|
||||
p0, p1, 2, (char*)tagbuf );
|
||||
return map_sw (sw);
|
||||
}
|
||||
|
||||
@ -162,6 +163,39 @@ iso7816_select_file (int slot, int tag, int is_dir,
|
||||
}
|
||||
|
||||
|
||||
/* Do a select file command with a direct path. */
|
||||
gpg_error_t
|
||||
iso7816_select_path (int slot, const unsigned short *path, size_t pathlen,
|
||||
unsigned char **result, size_t *resultlen)
|
||||
{
|
||||
int sw, p0, p1;
|
||||
unsigned char buffer[100];
|
||||
int buflen;
|
||||
|
||||
if (result || resultlen)
|
||||
{
|
||||
*result = NULL;
|
||||
*resultlen = 0;
|
||||
return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
|
||||
}
|
||||
|
||||
if (pathlen/2 >= sizeof buffer)
|
||||
return gpg_error (GPG_ERR_TOO_LARGE);
|
||||
|
||||
for (buflen = 0; pathlen; pathlen--, path++)
|
||||
{
|
||||
buffer[buflen++] = (*path >> 8);
|
||||
buffer[buflen++] = *path;
|
||||
}
|
||||
|
||||
p0 = 0x08;
|
||||
p1 = 0x0c; /* No FC return. */
|
||||
sw = apdu_send_simple (slot, 0x00, CMD_SELECT_FILE,
|
||||
p0, p1, buflen, (char*)buffer );
|
||||
return map_sw (sw);
|
||||
}
|
||||
|
||||
|
||||
/* This is a private command currently only working for TCOS cards. */
|
||||
gpg_error_t
|
||||
iso7816_list_directory (int slot, int list_dirs,
|
||||
@ -286,7 +320,7 @@ iso7816_put_data (int slot, int tag,
|
||||
|
||||
sw = apdu_send_simple (slot, 0x00, CMD_PUT_DATA,
|
||||
((tag >> 8) & 0xff), (tag & 0xff),
|
||||
datalen, data);
|
||||
datalen, (const char*)data);
|
||||
return map_sw (sw);
|
||||
}
|
||||
|
||||
@ -300,10 +334,11 @@ iso7816_manage_security_env (int slot, int p1, int p2,
|
||||
{
|
||||
int sw;
|
||||
|
||||
if (p1 < 0 || p1 > 255 || p2 < 0 || p2 > 255 || !data || !datalen)
|
||||
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, datalen, data);
|
||||
sw = apdu_send_simple (slot, 0x00, CMD_MSE, p1, p2,
|
||||
data? datalen : -1, (const char*)data);
|
||||
return map_sw (sw);
|
||||
}
|
||||
|
||||
@ -323,7 +358,7 @@ 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, data,
|
||||
sw = apdu_send (slot, 0x00, CMD_PSO, 0x9E, 0x9A, datalen, (const char*)data,
|
||||
result, resultlen);
|
||||
if (sw != SW_SUCCESS)
|
||||
{
|
||||
@ -364,13 +399,15 @@ 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, datalen+1, buf,
|
||||
sw = apdu_send (slot, 0x00, CMD_PSO, 0x80, 0x86,
|
||||
datalen+1, (char*)buf,
|
||||
result, resultlen);
|
||||
xfree (buf);
|
||||
}
|
||||
else
|
||||
{
|
||||
sw = apdu_send (slot, 0x00, CMD_PSO, 0x80, 0x86, datalen, data,
|
||||
sw = apdu_send (slot, 0x00, CMD_PSO, 0x80, 0x86,
|
||||
datalen, (const char *)data,
|
||||
result, resultlen);
|
||||
}
|
||||
if (sw != SW_SUCCESS)
|
||||
@ -399,7 +436,7 @@ iso7816_internal_authenticate (int slot,
|
||||
*resultlen = 0;
|
||||
|
||||
sw = apdu_send (slot, 0x00, CMD_INTERNAL_AUTHENTICATE, 0, 0,
|
||||
datalen, data, result, resultlen);
|
||||
datalen, (const char*)data, result, resultlen);
|
||||
if (sw != SW_SUCCESS)
|
||||
{
|
||||
/* Make sure that pending buffers are released. */
|
||||
@ -426,7 +463,7 @@ do_generate_keypair (int slot, int readonly,
|
||||
*resultlen = 0;
|
||||
|
||||
sw = apdu_send (slot, 0x00, CMD_GENERATE_KEYPAIR, readonly? 0x81:0x80, 0,
|
||||
datalen, data, result, resultlen);
|
||||
datalen, (const char*)data, result, resultlen);
|
||||
if (sw != SW_SUCCESS)
|
||||
{
|
||||
/* Make sure that pending buffers are released. */
|
||||
@ -522,8 +559,10 @@ iso7816_read_binary (int slot, size_t offset, size_t nmax,
|
||||
{
|
||||
buffer = NULL;
|
||||
bufferlen = 0;
|
||||
/* Fixme: Either the ccid driver or the TCOS cards have problems
|
||||
with an Le of 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
|
||||
@ -531,6 +570,21 @@ iso7816_read_binary (int slot, size_t offset, size_t nmax,
|
||||
sw = apdu_send_le (slot, 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,
|
||||
((offset>>8) & 0xff), (offset & 0xff) , -1, NULL,
|
||||
n, &buffer, &bufferlen);
|
||||
}
|
||||
|
||||
if (*result && sw == SW_BAD_P0_P1)
|
||||
{
|
||||
/* Bad Parameter means that the offset is outside of the
|
||||
EF. When reading all data we take this as an indication
|
||||
for EOF. */
|
||||
break;
|
||||
}
|
||||
|
||||
if (sw != SW_SUCCESS && sw != SW_EOF_REACHED)
|
||||
{
|
||||
@ -606,7 +660,7 @@ iso7816_read_record (int slot, int recno, int reccount, int short_ef,
|
||||
|
||||
buffer = NULL;
|
||||
bufferlen = 0;
|
||||
/* Fixme: Either the ccid driver of the TCOS cards have problems
|
||||
/* 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,
|
||||
recno,
|
||||
|
@ -34,6 +34,9 @@ gpg_error_t iso7816_select_application (int slot,
|
||||
const char *aid, size_t aidlen);
|
||||
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,
|
||||
const unsigned short *path, size_t pathlen,
|
||||
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_verify (int slot,
|
||||
|
Loading…
x
Reference in New Issue
Block a user