1
0
mirror of git://git.gnupg.org/gnupg.git synced 2024-06-17 00:39:50 +02:00

Updated card stuff to support T=0 cards.

This commit is contained in:
Werner Koch 2005-09-07 17:05:42 +00:00
parent 9a2a2904cc
commit b4b9f891e2
9 changed files with 394 additions and 459 deletions

2
README
View File

@ -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

View File

@ -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.

View File

@ -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.

View File

@ -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
}

View File

@ -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);

View File

@ -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

View 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;
}

View File

@ -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,

View File

@ -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,