mirror of
git://git.gnupg.org/gnupg.git
synced 2025-01-09 12:54:23 +01:00
* apdu.c (apdu_open_reader): Load pcsc_get_status_change fucntion.
(pcsc_get_status): Implemented. (reset_pcsc_reader): Implemented. (open_pcsc_reader): Succeed even with no card inserted. (open_ccid_reader): Set LAST_STATUS. * iso7816.c (iso7816_select_application): Always use 0 for P1.
This commit is contained in:
parent
3f769cb717
commit
27d06166d3
@ -1,3 +1,17 @@
|
|||||||
|
2004-10-20 Werner Koch <wk@g10code.com>
|
||||||
|
|
||||||
|
* apdu.c (apdu_open_reader): Load pcsc_get_status_change fucntion.
|
||||||
|
(pcsc_get_status): Implemented.
|
||||||
|
(reset_pcsc_reader): Implemented.
|
||||||
|
(open_pcsc_reader): Succeed even with no card inserted.
|
||||||
|
(open_ccid_reader): Set LAST_STATUS.
|
||||||
|
|
||||||
|
* iso7816.c (iso7816_select_application): Always use 0 for P1.
|
||||||
|
|
||||||
|
2004-10-18 Werner Koch <wk@g10code.com>
|
||||||
|
|
||||||
|
* ccid-driver.c (ccid_get_atr): Reset T=1 state info.
|
||||||
|
|
||||||
2004-10-17 Werner Koch <wk@g10code.com>
|
2004-10-17 Werner Koch <wk@g10code.com>
|
||||||
|
|
||||||
* passphrase.c (agent_get_passphrase): Cast UIDLEN to int. Noted
|
* passphrase.c (agent_get_passphrase): Cast UIDLEN to int. Noted
|
||||||
|
456
g10/apdu.c
456
g10/apdu.c
@ -125,6 +125,8 @@ struct reader_table_s {
|
|||||||
rapdu_t handle;
|
rapdu_t handle;
|
||||||
} rapdu;
|
} rapdu;
|
||||||
#endif /*USE_G10CODE_RAPDU*/
|
#endif /*USE_G10CODE_RAPDU*/
|
||||||
|
char *rdrname; /* Name of the connected reader or NULL if unknown. */
|
||||||
|
int last_status;
|
||||||
int status;
|
int status;
|
||||||
unsigned char atr[33];
|
unsigned char atr[33];
|
||||||
size_t atrlen; /* A zero length indicates that the ATR has
|
size_t atrlen; /* A zero length indicates that the ATR has
|
||||||
@ -169,13 +171,47 @@ static char (* DLSTDCALL CT_close) (unsigned short ctn);
|
|||||||
#define PCSC_UNPOWER_CARD 2
|
#define PCSC_UNPOWER_CARD 2
|
||||||
#define PCSC_EJECT_CARD 3
|
#define PCSC_EJECT_CARD 3
|
||||||
|
|
||||||
struct pcsc_io_request_s {
|
#define PCSC_UNKNOWN 0x0001
|
||||||
|
#define PCSC_ABSENT 0x0002 /* Card is absent. */
|
||||||
|
#define PCSC_PRESENT 0x0004 /* Card is present. */
|
||||||
|
#define PCSC_SWALLOWED 0x0008 /* Card is present and electrical connected. */
|
||||||
|
#define PCSC_POWERED 0x0010 /* Card is powered. */
|
||||||
|
#define PCSC_NEGOTIABLE 0x0020 /* Card is awaiting PTS. */
|
||||||
|
#define PCSC_SPECIFIC 0x0040 /* Card is ready for use. */
|
||||||
|
|
||||||
|
#define PCSC_STATE_UNAWARE 0x0000 /* Want status. */
|
||||||
|
#define PCSC_STATE_IGNORE 0x0001 /* Ignore this reader. */
|
||||||
|
#define PCSC_STATE_CHANGED 0x0002 /* State has changed. */
|
||||||
|
#define PCSC_STATE_UNKNOWN 0x0004 /* Reader unknown. */
|
||||||
|
#define PCSC_STATE_UNAVAILABLE 0x0008 /* Status unavailable. */
|
||||||
|
#define PCSC_STATE_EMPTY 0x0010 /* Card removed. */
|
||||||
|
#define PCSC_STATE_PRESENT 0x0020 /* Card inserted. */
|
||||||
|
#define PCSC_STATE_ATRMATCH 0x0040 /* ATR matches card. */
|
||||||
|
#define PCSC_STATE_EXCLUSIVE 0x0080 /* Exclusive Mode. */
|
||||||
|
#define PCSC_STATE_INUSE 0x0100 /* Shared mode. */
|
||||||
|
#define PCSC_STATE_MUTE 0x0200 /* Unresponsive card. */
|
||||||
|
|
||||||
|
|
||||||
|
struct pcsc_io_request_s
|
||||||
|
{
|
||||||
unsigned long protocol;
|
unsigned long protocol;
|
||||||
unsigned long pci_len;
|
unsigned long pci_len;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct pcsc_io_request_s *pcsc_io_request_t;
|
typedef struct pcsc_io_request_s *pcsc_io_request_t;
|
||||||
|
|
||||||
|
struct pcsc_readerstate_s
|
||||||
|
{
|
||||||
|
const char *reader;
|
||||||
|
void *user_data;
|
||||||
|
unsigned long current_state;
|
||||||
|
unsigned long event_state;
|
||||||
|
unsigned long atrlen;
|
||||||
|
unsigned char atr[33];
|
||||||
|
};
|
||||||
|
|
||||||
|
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 *reserved1,
|
||||||
const void *reserved2,
|
const void *reserved2,
|
||||||
@ -184,12 +220,21 @@ long (* DLSTDCALL pcsc_release_context) (unsigned long context);
|
|||||||
long (* DLSTDCALL pcsc_list_readers) (unsigned long context,
|
long (* DLSTDCALL pcsc_list_readers) (unsigned long context,
|
||||||
const char *groups,
|
const char *groups,
|
||||||
char *readers, unsigned long*readerslen);
|
char *readers, unsigned long*readerslen);
|
||||||
|
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,
|
const char *reader,
|
||||||
unsigned long share_mode,
|
unsigned long share_mode,
|
||||||
unsigned long preferred_protocols,
|
unsigned long preferred_protocols,
|
||||||
unsigned long *r_card,
|
unsigned long *r_card,
|
||||||
unsigned long *r_active_protocol);
|
unsigned long *r_active_protocol);
|
||||||
|
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);
|
unsigned long disposition);
|
||||||
long (* DLSTDCALL pcsc_status) (unsigned long card,
|
long (* DLSTDCALL pcsc_status) (unsigned long card,
|
||||||
@ -211,7 +256,6 @@ long (* DLSTDCALL pcsc_set_timeout) (unsigned long context,
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Helper
|
Helper
|
||||||
@ -254,11 +298,13 @@ new_reader_slot (void)
|
|||||||
reader_table[reader].dump_status_reader = NULL;
|
reader_table[reader].dump_status_reader = NULL;
|
||||||
|
|
||||||
reader_table[reader].used = 1;
|
reader_table[reader].used = 1;
|
||||||
|
reader_table[reader].last_status = 0;
|
||||||
#ifdef NEED_PCSC_WRAPPER
|
#ifdef NEED_PCSC_WRAPPER
|
||||||
reader_table[reader].pcsc.req_fd = -1;
|
reader_table[reader].pcsc.req_fd = -1;
|
||||||
reader_table[reader].pcsc.rsp_fd = -1;
|
reader_table[reader].pcsc.rsp_fd = -1;
|
||||||
reader_table[reader].pcsc.pid = (pid_t)(-1);
|
reader_table[reader].pcsc.pid = (pid_t)(-1);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return reader;
|
return reader;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -662,18 +708,293 @@ dump_pcsc_reader_status (int slot)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
reset_pcsc_reader (int slot)
|
||||||
|
{
|
||||||
|
#ifdef NEED_PCSC_WRAPPER
|
||||||
|
long err;
|
||||||
|
reader_table_t slotp;
|
||||||
|
size_t len;
|
||||||
|
int i, n;
|
||||||
|
unsigned char msgbuf[9];
|
||||||
|
|
||||||
|
slotp = reader_table + slot;
|
||||||
|
|
||||||
|
if (slotp->pcsc.req_fd == -1
|
||||||
|
|| slotp->pcsc.rsp_fd == -1
|
||||||
|
|| slotp->pcsc.pid == (pid_t)(-1) )
|
||||||
|
{
|
||||||
|
log_error ("pcsc_get_status: pcsc-wrapper not running\n");
|
||||||
|
return SW_HOST_CARD_IO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
msgbuf[0] = 0x05; /* RESET command. */
|
||||||
|
len = 0;
|
||||||
|
msgbuf[1] = (len >> 24);
|
||||||
|
msgbuf[2] = (len >> 16);
|
||||||
|
msgbuf[3] = (len >> 8);
|
||||||
|
msgbuf[4] = (len );
|
||||||
|
if ( writen (slotp->pcsc.req_fd, msgbuf, 5) )
|
||||||
|
{
|
||||||
|
log_error ("error sending PC/SC RESET request: %s\n",
|
||||||
|
strerror (errno));
|
||||||
|
goto command_failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read the response. */
|
||||||
|
if ((i=readn (slotp->pcsc.rsp_fd, msgbuf, 9, &len)) || len != 9)
|
||||||
|
{
|
||||||
|
log_error ("error receiving PC/SC RESET response: %s\n",
|
||||||
|
i? strerror (errno) : "premature EOF");
|
||||||
|
goto command_failed;
|
||||||
|
}
|
||||||
|
len = (msgbuf[1] << 24) | (msgbuf[2] << 16) | (msgbuf[3] << 8 ) | msgbuf[4];
|
||||||
|
if (msgbuf[0] != 0x81 || len < 4)
|
||||||
|
{
|
||||||
|
log_error ("invalid response header from PC/SC received\n");
|
||||||
|
goto command_failed;
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
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));
|
||||||
|
goto command_failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The open fucntion may return a zero for the ATR length to
|
||||||
|
indicate that no card is present. */
|
||||||
|
n = len;
|
||||||
|
if (n)
|
||||||
|
{
|
||||||
|
if ((i=readn (slotp->pcsc.rsp_fd, slotp->atr, n, &len)) || len != n)
|
||||||
|
{
|
||||||
|
log_error ("error receiving PC/SC RESET response: %s\n",
|
||||||
|
i? strerror (errno) : "premature EOF");
|
||||||
|
goto command_failed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
slotp->atrlen = len;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
command_failed:
|
||||||
|
close (slotp->pcsc.req_fd);
|
||||||
|
close (slotp->pcsc.rsp_fd);
|
||||||
|
slotp->pcsc.req_fd = -1;
|
||||||
|
slotp->pcsc.rsp_fd = -1;
|
||||||
|
kill (slotp->pcsc.pid, SIGTERM);
|
||||||
|
slotp->pcsc.pid = (pid_t)(-1);
|
||||||
|
slotp->used = 0;
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
#else /* !NEED_PCSC_WRAPPER */
|
||||||
|
long err;
|
||||||
|
char reader[250];
|
||||||
|
unsigned long nreader, atrlen;
|
||||||
|
unsigned long card_state, card_protocol;
|
||||||
|
|
||||||
|
if (reader_table[slot].pcsc.card)
|
||||||
|
{
|
||||||
|
err = pcsc_disconnect (reader_table[slot].pcsc.card, PCSC_LEAVE_CARD);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
log_error ("pcsc_disconnect failed: %s (0x%lx)\n",
|
||||||
|
pcsc_error_string (err), err);
|
||||||
|
return SW_HOST_CARD_IO_ERROR;
|
||||||
|
}
|
||||||
|
reader_table[slot].pcsc.card = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = pcsc_connect (reader_table[slot].pcsc.context,
|
||||||
|
reader_table[slot].rdrname,
|
||||||
|
PCSC_SHARE_EXCLUSIVE,
|
||||||
|
PCSC_PROTOCOL_T0|PCSC_PROTOCOL_T1,
|
||||||
|
&reader_table[slot].pcsc.card,
|
||||||
|
&reader_table[slot].pcsc.protocol);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
atrlen = 33;
|
||||||
|
nreader = sizeof reader - 1;
|
||||||
|
err = pcsc_status (reader_table[slot].pcsc.card,
|
||||||
|
reader, &nreader,
|
||||||
|
&card_state, &card_protocol,
|
||||||
|
reader_table[slot].atr, &atrlen);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
if (atrlen >= DIM (reader_table[0].atr))
|
||||||
|
log_bug ("ATR returned by pcsc_status is too large\n");
|
||||||
|
reader_table[slot].atrlen = atrlen;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
#endif /* !NEED_PCSC_WRAPPER */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
pcsc_get_status (int slot, unsigned int *status)
|
pcsc_get_status (int slot, unsigned int *status)
|
||||||
{
|
{
|
||||||
*status = 1|2|4; /* FIXME!!!! */
|
#ifdef NEED_PCSC_WRAPPER
|
||||||
return 0;
|
long err;
|
||||||
|
reader_table_t slotp;
|
||||||
|
size_t len, full_len;
|
||||||
|
int i, n;
|
||||||
|
unsigned char msgbuf[9];
|
||||||
|
unsigned char buffer[12];
|
||||||
|
|
||||||
|
slotp = reader_table + slot;
|
||||||
|
|
||||||
|
if (slotp->pcsc.req_fd == -1
|
||||||
|
|| slotp->pcsc.rsp_fd == -1
|
||||||
|
|| slotp->pcsc.pid == (pid_t)(-1) )
|
||||||
|
{
|
||||||
|
log_error ("pcsc_get_status: pcsc-wrapper not running\n");
|
||||||
|
return SW_HOST_CARD_IO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
msgbuf[0] = 0x04; /* STATUS command. */
|
||||||
reset_pcsc_reader (int slot)
|
len = 0;
|
||||||
|
msgbuf[1] = (len >> 24);
|
||||||
|
msgbuf[2] = (len >> 16);
|
||||||
|
msgbuf[3] = (len >> 8);
|
||||||
|
msgbuf[4] = (len );
|
||||||
|
if ( writen (slotp->pcsc.req_fd, msgbuf, 5) )
|
||||||
{
|
{
|
||||||
return SW_HOST_NOT_SUPPORTED;
|
log_error ("error sending PC/SC STATUS request: %s\n",
|
||||||
|
strerror (errno));
|
||||||
|
goto command_failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read the response. */
|
||||||
|
if ((i=readn (slotp->pcsc.rsp_fd, msgbuf, 9, &len)) || len != 9)
|
||||||
|
{
|
||||||
|
log_error ("error receiving PC/SC STATUS response: %s\n",
|
||||||
|
i? strerror (errno) : "premature EOF");
|
||||||
|
goto command_failed;
|
||||||
|
}
|
||||||
|
len = (msgbuf[1] << 24) | (msgbuf[2] << 16) | (msgbuf[3] << 8 ) | msgbuf[4];
|
||||||
|
if (msgbuf[0] != 0x81 || len < 4)
|
||||||
|
{
|
||||||
|
log_error ("invalid response header from PC/SC received\n");
|
||||||
|
goto command_failed;
|
||||||
|
}
|
||||||
|
len -= 4; /* Already read the error code. */
|
||||||
|
err = (msgbuf[5] << 24) | (msgbuf[6] << 16) | (msgbuf[7] << 8 ) | msgbuf[8];
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
log_error ("pcsc_status failed: %s (0x%lx)\n",
|
||||||
|
pcsc_error_string (err), err);
|
||||||
|
return SW_HOST_CARD_IO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
full_len = len;
|
||||||
|
|
||||||
|
n = 8 < len ? 8 : len;
|
||||||
|
if ((i=readn (slotp->pcsc.rsp_fd, buffer, n, &len)) || len != 8)
|
||||||
|
{
|
||||||
|
log_error ("error receiving PC/SC STATUS response: %s\n",
|
||||||
|
i? strerror (errno) : "premature EOF");
|
||||||
|
goto command_failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
full_len -= len;
|
||||||
|
/* Newer versions of the wrapper might send more status bytes.
|
||||||
|
Read them. */
|
||||||
|
while (full_len)
|
||||||
|
{
|
||||||
|
unsigned char dummybuf[128];
|
||||||
|
|
||||||
|
n = full_len < DIM (dummybuf) ? full_len : DIM (dummybuf);
|
||||||
|
if ((i=readn (slotp->pcsc.rsp_fd, dummybuf, n, &len)) || len != n)
|
||||||
|
{
|
||||||
|
log_error ("error receiving PC/SC TRANSMIT response: %s\n",
|
||||||
|
i? strerror (errno) : "premature EOF");
|
||||||
|
goto command_failed;
|
||||||
|
}
|
||||||
|
full_len -= n;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We are lucky: The wrapper already returns the data in the
|
||||||
|
required format. */
|
||||||
|
*status = buffer[3];
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
command_failed:
|
||||||
|
close (slotp->pcsc.req_fd);
|
||||||
|
close (slotp->pcsc.rsp_fd);
|
||||||
|
slotp->pcsc.req_fd = -1;
|
||||||
|
slotp->pcsc.rsp_fd = -1;
|
||||||
|
kill (slotp->pcsc.pid, SIGTERM);
|
||||||
|
slotp->pcsc.pid = (pid_t)(-1);
|
||||||
|
slotp->used = 0;
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
#else /*!NEED_PCSC_WRAPPER*/
|
||||||
|
|
||||||
|
long err;
|
||||||
|
struct pcsc_readerstate_s rdrstates[1];
|
||||||
|
|
||||||
|
memset (rdrstates, 0, sizeof *rdrstates);
|
||||||
|
rdrstates[0].reader = reader_table[slot].rdrname;
|
||||||
|
rdrstates[0].current_state = PCSC_STATE_UNAWARE;
|
||||||
|
err = pcsc_get_status_change (reader_table[slot].pcsc.context,
|
||||||
|
0,
|
||||||
|
rdrstates, 1);
|
||||||
|
if (err == 0x8010000a) /* Timeout. */
|
||||||
|
err = 0;
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
log_error ("pcsc_get_status_change failed: %s (0x%lx)\n",
|
||||||
|
pcsc_error_string (err), err);
|
||||||
|
return SW_HOST_CARD_IO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* log_debug */
|
||||||
|
/* ("pcsc_get_status_change: %s%s%s%s%s%s%s%s%s%s\n", */
|
||||||
|
/* (rdrstates[0].event_state & PCSC_STATE_IGNORE)? " ignore":"", */
|
||||||
|
/* (rdrstates[0].event_state & PCSC_STATE_CHANGED)? " changed":"", */
|
||||||
|
/* (rdrstates[0].event_state & PCSC_STATE_UNKNOWN)? " unknown":"", */
|
||||||
|
/* (rdrstates[0].event_state & PCSC_STATE_UNAVAILABLE)?" unavail":"", */
|
||||||
|
/* (rdrstates[0].event_state & PCSC_STATE_EMPTY)? " empty":"", */
|
||||||
|
/* (rdrstates[0].event_state & PCSC_STATE_PRESENT)? " present":"", */
|
||||||
|
/* (rdrstates[0].event_state & PCSC_STATE_ATRMATCH)? " atr":"", */
|
||||||
|
/* (rdrstates[0].event_state & PCSC_STATE_EXCLUSIVE)? " excl":"", */
|
||||||
|
/* (rdrstates[0].event_state & PCSC_STATE_INUSE)? " unuse":"", */
|
||||||
|
/* (rdrstates[0].event_state & PCSC_STATE_MUTE)? " mute":"" ); */
|
||||||
|
|
||||||
|
*status = 0;
|
||||||
|
if ( (rdrstates[0].event_state & PCSC_STATE_PRESENT) )
|
||||||
|
*status |= 2;
|
||||||
|
if ( !(rdrstates[0].event_state & PCSC_STATE_MUTE) )
|
||||||
|
*status |= 4;
|
||||||
|
/* We indicate a useful card if it is not in use by another
|
||||||
|
application. This is because we only use exclusive access
|
||||||
|
mode. */
|
||||||
|
if ( (*status & 6) == 6
|
||||||
|
&& !(rdrstates[0].event_state & PCSC_STATE_INUSE) )
|
||||||
|
*status |= 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
#endif /*!NEED_PCSC_WRAPPER*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -889,6 +1210,8 @@ close_pcsc_reader (int slot)
|
|||||||
#else /*!NEED_PCSC_WRAPPER*/
|
#else /*!NEED_PCSC_WRAPPER*/
|
||||||
|
|
||||||
pcsc_release_context (reader_table[slot].pcsc.context);
|
pcsc_release_context (reader_table[slot].pcsc.context);
|
||||||
|
xfree (reader_table[slot].rdrname);
|
||||||
|
reader_table[slot].rdrname = NULL;
|
||||||
reader_table[slot].used = 0;
|
reader_table[slot].used = 0;
|
||||||
return 0;
|
return 0;
|
||||||
#endif /*!NEED_PCSC_WRAPPER*/
|
#endif /*!NEED_PCSC_WRAPPER*/
|
||||||
@ -999,8 +1322,14 @@ open_pcsc_reader (const char *portstr)
|
|||||||
slotp->pcsc.rsp_fd = rp[0];
|
slotp->pcsc.rsp_fd = rp[0];
|
||||||
|
|
||||||
/* Wait for the intermediate child to terminate. */
|
/* Wait for the intermediate child to terminate. */
|
||||||
while ( (i=pth_waitpid (pid, NULL, 0)) == -1 && errno == EINTR)
|
#ifdef USE_GNU_PTH
|
||||||
|
#define WAIT pth_waitpid
|
||||||
|
#else
|
||||||
|
#define WAIT waitpid
|
||||||
|
#endif
|
||||||
|
while ( (i=WAIT (pid, NULL, 0)) == -1 && errno == EINTR)
|
||||||
;
|
;
|
||||||
|
#undef X
|
||||||
|
|
||||||
/* Now send the open request. */
|
/* Now send the open request. */
|
||||||
msgbuf[0] = 0x01; /* OPEN command. */
|
msgbuf[0] = 0x01; /* OPEN command. */
|
||||||
@ -1041,13 +1370,24 @@ open_pcsc_reader (const char *portstr)
|
|||||||
log_error ("PC/SC OPEN failed: %s\n", pcsc_error_string (err));
|
log_error ("PC/SC OPEN failed: %s\n", pcsc_error_string (err));
|
||||||
goto command_failed;
|
goto command_failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
slotp->last_status = 0;
|
||||||
|
|
||||||
|
/* The open fucntion may return a zero for the ATR length to
|
||||||
|
indicate that no card is present. */
|
||||||
n = len;
|
n = len;
|
||||||
|
if (n)
|
||||||
|
{
|
||||||
if ((i=readn (slotp->pcsc.rsp_fd, slotp->atr, n, &len)) || len != n)
|
if ((i=readn (slotp->pcsc.rsp_fd, slotp->atr, n, &len)) || len != n)
|
||||||
{
|
{
|
||||||
log_error ("error receiving PC/SC OPEN response: %s\n",
|
log_error ("error receiving PC/SC OPEN response: %s\n",
|
||||||
i? strerror (errno) : "premature EOF");
|
i? strerror (errno) : "premature EOF");
|
||||||
goto command_failed;
|
goto command_failed;
|
||||||
}
|
}
|
||||||
|
/* If we got to here we know that a card is present
|
||||||
|
and usable. Thus remember this. */
|
||||||
|
slotp->last_status = (1|2|4| 0x8000);
|
||||||
|
}
|
||||||
slotp->atrlen = len;
|
slotp->atrlen = len;
|
||||||
|
|
||||||
reader_table[slot].close_reader = close_pcsc_reader;
|
reader_table[slot].close_reader = close_pcsc_reader;
|
||||||
@ -1132,41 +1472,63 @@ open_pcsc_reader (const char *portstr)
|
|||||||
p += strlen (p) + 1;
|
p += strlen (p) + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
reader_table[slot].rdrname = xtrymalloc (strlen (portstr? portstr : list)+1);
|
||||||
|
if (!reader_table[slot].rdrname)
|
||||||
|
{
|
||||||
|
log_error ("error allocating memory for reader name\n");
|
||||||
|
pcsc_release_context (reader_table[slot].pcsc.context);
|
||||||
|
reader_table[slot].used = 0;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
strcpy (reader_table[slot].rdrname, portstr? portstr : list);
|
||||||
|
xfree (list);
|
||||||
|
|
||||||
err = pcsc_connect (reader_table[slot].pcsc.context,
|
err = pcsc_connect (reader_table[slot].pcsc.context,
|
||||||
portstr? portstr : list,
|
reader_table[slot].rdrname,
|
||||||
PCSC_SHARE_EXCLUSIVE,
|
PCSC_SHARE_EXCLUSIVE,
|
||||||
PCSC_PROTOCOL_T0|PCSC_PROTOCOL_T1,
|
PCSC_PROTOCOL_T0|PCSC_PROTOCOL_T1,
|
||||||
&reader_table[slot].pcsc.card,
|
&reader_table[slot].pcsc.card,
|
||||||
&reader_table[slot].pcsc.protocol);
|
&reader_table[slot].pcsc.protocol);
|
||||||
if (err)
|
if (err == 0x8010000c) /* No smartcard. */
|
||||||
|
reader_table[slot].pcsc.card = 0;
|
||||||
|
else if (err)
|
||||||
{
|
{
|
||||||
log_error ("pcsc_connect failed: %s (0x%lx)\n",
|
log_error ("pcsc_connect failed: %s (0x%lx)\n",
|
||||||
pcsc_error_string (err), err);
|
pcsc_error_string (err), err);
|
||||||
pcsc_release_context (reader_table[slot].pcsc.context);
|
pcsc_release_context (reader_table[slot].pcsc.context);
|
||||||
|
xfree (reader_table[slot].rdrname);
|
||||||
|
reader_table[slot].rdrname = NULL;
|
||||||
reader_table[slot].used = 0;
|
reader_table[slot].used = 0;
|
||||||
xfree (list);
|
xfree (list);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
reader_table[slot].atrlen = 0;
|
||||||
|
reader_table[slot].last_status = 0;
|
||||||
|
if (!err)
|
||||||
|
{
|
||||||
|
char reader[250];
|
||||||
|
unsigned long readerlen;
|
||||||
|
|
||||||
atrlen = 32;
|
atrlen = 32;
|
||||||
/* (We need to pass a dummy buffer. We use LIST because it ought to
|
readerlen = sizeof reader -1 ;
|
||||||
be large enough.) */
|
|
||||||
err = pcsc_status (reader_table[slot].pcsc.card,
|
err = pcsc_status (reader_table[slot].pcsc.card,
|
||||||
list, &listlen,
|
reader, &readerlen,
|
||||||
&card_state, &card_protocol,
|
&card_state, &card_protocol,
|
||||||
reader_table[slot].atr, &atrlen);
|
reader_table[slot].atr, &atrlen);
|
||||||
xfree (list);
|
|
||||||
if (err)
|
if (err)
|
||||||
|
log_error ("pcsc_status failed: %s (0x%lx) %lu\n",
|
||||||
|
pcsc_error_string (err), err, readerlen);
|
||||||
|
else
|
||||||
{
|
{
|
||||||
log_error ("pcsc_status failed: %s (0x%lx)\n",
|
|
||||||
pcsc_error_string (err), err);
|
|
||||||
pcsc_release_context (reader_table[slot].pcsc.context);
|
|
||||||
reader_table[slot].used = 0;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (atrlen >= DIM (reader_table[0].atr))
|
if (atrlen >= DIM (reader_table[0].atr))
|
||||||
log_bug ("ATR returned by pcsc_status is too large\n");
|
log_bug ("ATR returned by pcsc_status is too large\n");
|
||||||
reader_table[slot].atrlen = atrlen;
|
reader_table[slot].atrlen = atrlen;
|
||||||
|
/* 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].close_reader = close_pcsc_reader;
|
reader_table[slot].close_reader = close_pcsc_reader;
|
||||||
reader_table[slot].reset_reader = reset_pcsc_reader;
|
reader_table[slot].reset_reader = reset_pcsc_reader;
|
||||||
@ -1311,6 +1673,12 @@ open_ccid_reader (const char *portstr)
|
|||||||
slotp->atrlen = 0;
|
slotp->atrlen = 0;
|
||||||
err = 0;
|
err = 0;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* 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].close_reader = close_ccid_reader;
|
reader_table[slot].close_reader = close_ccid_reader;
|
||||||
reader_table[slot].shutdown_reader = shutdown_ccid_reader;
|
reader_table[slot].shutdown_reader = shutdown_ccid_reader;
|
||||||
@ -1970,11 +2338,21 @@ apdu_open_reader (const char *portstr)
|
|||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
if (!pcsc_list_readers)
|
if (!pcsc_list_readers)
|
||||||
pcsc_list_readers = dlsym (handle, "SCardListReadersA");
|
pcsc_list_readers = dlsym (handle, "SCardListReadersA");
|
||||||
|
#endif
|
||||||
|
pcsc_get_status_change = dlsym (handle, "SCardGetStatusChange");
|
||||||
|
#ifdef _WIN32
|
||||||
|
if (!pcsc_get_status_change)
|
||||||
|
pcsc_get_status_change = dlsym (handle, "SCardGetStatusChangeA");
|
||||||
#endif
|
#endif
|
||||||
pcsc_connect = dlsym (handle, "SCardConnect");
|
pcsc_connect = dlsym (handle, "SCardConnect");
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
if (!pcsc_connect)
|
if (!pcsc_connect)
|
||||||
pcsc_connect = dlsym (handle, "SCardConnectA");
|
pcsc_connect = dlsym (handle, "SCardConnectA");
|
||||||
|
#endif
|
||||||
|
pcsc_reconnect = dlsym (handle, "SCardReconnect");
|
||||||
|
#ifdef _WIN32
|
||||||
|
if (!pcsc_reconnect)
|
||||||
|
pcsc_reconnect = dlsym (handle, "SCardReconnectA");
|
||||||
#endif
|
#endif
|
||||||
pcsc_disconnect = dlsym (handle, "SCardDisconnect");
|
pcsc_disconnect = dlsym (handle, "SCardDisconnect");
|
||||||
pcsc_status = dlsym (handle, "SCardStatus");
|
pcsc_status = dlsym (handle, "SCardStatus");
|
||||||
@ -1990,7 +2368,9 @@ apdu_open_reader (const char *portstr)
|
|||||||
if (!pcsc_establish_context
|
if (!pcsc_establish_context
|
||||||
|| !pcsc_release_context
|
|| !pcsc_release_context
|
||||||
|| !pcsc_list_readers
|
|| !pcsc_list_readers
|
||||||
|
|| !pcsc_get_status_change
|
||||||
|| !pcsc_connect
|
|| !pcsc_connect
|
||||||
|
|| !pcsc_reconnect
|
||||||
|| !pcsc_disconnect
|
|| !pcsc_disconnect
|
||||||
|| !pcsc_status
|
|| !pcsc_status
|
||||||
|| !pcsc_begin_transaction
|
|| !pcsc_begin_transaction
|
||||||
@ -2001,11 +2381,13 @@ apdu_open_reader (const char *portstr)
|
|||||||
/* Note that set_timeout is currently not used and also not
|
/* Note that set_timeout is currently not used and also not
|
||||||
available under Windows. */
|
available under Windows. */
|
||||||
log_error ("apdu_open_reader: invalid PC/SC driver "
|
log_error ("apdu_open_reader: invalid PC/SC driver "
|
||||||
"(%d%d%d%d%d%d%d%d%d%d)\n",
|
"(%d%d%d%d%d%d%d%d%d%d%d%d)\n",
|
||||||
!!pcsc_establish_context,
|
!!pcsc_establish_context,
|
||||||
!!pcsc_release_context,
|
!!pcsc_release_context,
|
||||||
!!pcsc_list_readers,
|
!!pcsc_list_readers,
|
||||||
|
!!pcsc_get_status_change,
|
||||||
!!pcsc_connect,
|
!!pcsc_connect,
|
||||||
|
!!pcsc_reconnect,
|
||||||
!!pcsc_disconnect,
|
!!pcsc_disconnect,
|
||||||
!!pcsc_status,
|
!!pcsc_status,
|
||||||
!!pcsc_begin_transaction,
|
!!pcsc_begin_transaction,
|
||||||
@ -2106,9 +2488,17 @@ apdu_reset (int slot)
|
|||||||
if ((sw = lock_slot (slot)))
|
if ((sw = lock_slot (slot)))
|
||||||
return sw;
|
return sw;
|
||||||
|
|
||||||
|
reader_table[slot].last_status = 0;
|
||||||
if (reader_table[slot].reset_reader)
|
if (reader_table[slot].reset_reader)
|
||||||
sw = reader_table[slot].reset_reader (slot);
|
sw = reader_table[slot].reset_reader (slot);
|
||||||
|
|
||||||
|
if (!sw)
|
||||||
|
{
|
||||||
|
/* 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);
|
||||||
|
}
|
||||||
|
|
||||||
unlock_slot (slot);
|
unlock_slot (slot);
|
||||||
return sw;
|
return sw;
|
||||||
}
|
}
|
||||||
@ -2143,7 +2533,16 @@ apdu_activate (int slot)
|
|||||||
/* We don't have an ATR or a card is present though inactive:
|
/* We don't have an ATR or a card is present though inactive:
|
||||||
do a reset now. */
|
do a reset now. */
|
||||||
if (reader_table[slot].reset_reader)
|
if (reader_table[slot].reset_reader)
|
||||||
|
{
|
||||||
|
reader_table[slot].last_status = 0;
|
||||||
sw = reader_table[slot].reset_reader (slot);
|
sw = reader_table[slot].reset_reader (slot);
|
||||||
|
if (!sw)
|
||||||
|
{
|
||||||
|
/* 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2205,7 +2604,22 @@ apdu_get_status (int slot, int hang,
|
|||||||
unlock_slot (slot);
|
unlock_slot (slot);
|
||||||
|
|
||||||
if (sw)
|
if (sw)
|
||||||
|
{
|
||||||
|
reader_table[slot].last_status = 0;
|
||||||
return sw;
|
return sw;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Keep track of changes. We use one extra bit to test whether we
|
||||||
|
have checked the status at least once. */
|
||||||
|
if ( s != (reader_table[slot].last_status & 0x07ff)
|
||||||
|
|| !reader_table[slot].last_status )
|
||||||
|
{
|
||||||
|
reader_table[slot].change_counter++;
|
||||||
|
/* Make sure that the ATR is invalid so that a reset will be by
|
||||||
|
activate. */
|
||||||
|
reader_table[slot].atrlen = 0;
|
||||||
|
}
|
||||||
|
reader_table[slot].last_status = (s | 0x8000);
|
||||||
|
|
||||||
if (status)
|
if (status)
|
||||||
*status = s;
|
*status = s;
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program; if not, write to the Free Software
|
* along with this program; if not, write to the Free Software
|
||||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||||
|
*
|
||||||
|
* $Id$
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef APDU_H
|
#ifndef APDU_H
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program; if not, write to the Free Software
|
* along with this program; if not, write to the Free Software
|
||||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||||
|
*
|
||||||
|
* $Id$
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef GNUPG_SCD_APP_COMMON_H
|
#ifndef GNUPG_SCD_APP_COMMON_H
|
||||||
@ -95,6 +97,7 @@ size_t app_help_read_length_of_cert (int slot, int fid, size_t *r_certoff);
|
|||||||
/*-- app.c --*/
|
/*-- app.c --*/
|
||||||
app_t select_application (ctrl_t ctrl, int slot, const char *name);
|
app_t select_application (ctrl_t ctrl, int slot, const char *name);
|
||||||
void release_application (app_t app);
|
void release_application (app_t app);
|
||||||
|
int app_munge_serialno (app_t app);
|
||||||
int app_get_serial_and_stamp (app_t app, char **serial, time_t *stamp);
|
int app_get_serial_and_stamp (app_t app, char **serial, time_t *stamp);
|
||||||
int app_write_learn_status (app_t app, ctrl_t ctrl);
|
int app_write_learn_status (app_t app, ctrl_t ctrl);
|
||||||
int app_readcert (app_t app, const char *certid,
|
int app_readcert (app_t app, const char *certid,
|
||||||
@ -143,7 +146,6 @@ int app_openpgp_cardinfo (app_t app,
|
|||||||
unsigned char **fpr1,
|
unsigned char **fpr1,
|
||||||
unsigned char **fpr2,
|
unsigned char **fpr2,
|
||||||
unsigned char **fpr3);
|
unsigned char **fpr3);
|
||||||
#endif /* GNUPG_MAJOR_VERSION != 1 */
|
|
||||||
int app_openpgp_storekey (app_t app, int keyno,
|
int app_openpgp_storekey (app_t app, int keyno,
|
||||||
unsigned char *template, size_t template_len,
|
unsigned char *template, size_t template_len,
|
||||||
time_t created_at,
|
time_t created_at,
|
||||||
@ -154,16 +156,18 @@ int app_openpgp_storekey (app_t app, int keyno,
|
|||||||
int app_openpgp_readkey (app_t app, int keyno,
|
int app_openpgp_readkey (app_t app, int keyno,
|
||||||
unsigned char **m, size_t *mlen,
|
unsigned char **m, size_t *mlen,
|
||||||
unsigned char **e, size_t *elen);
|
unsigned char **e, size_t *elen);
|
||||||
#if GNUPG_MAJOR_VERSION == 1
|
|
||||||
#else
|
|
||||||
/*-- app-nks.c --*/
|
/*-- app-nks.c --*/
|
||||||
int app_select_nks (app_t app);
|
int app_select_nks (app_t app);
|
||||||
|
|
||||||
/*-- app-dinsig.c --*/
|
/*-- app-dinsig.c --*/
|
||||||
int app_select_dinsig (app_t app);
|
int app_select_dinsig (app_t app);
|
||||||
|
|
||||||
|
/*-- app-p15.c --*/
|
||||||
|
int app_select_p15 (app_t app);
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* GNUPG_MAJOR_VERSION != 1 */
|
|
||||||
|
|
||||||
|
|
||||||
#endif /*GNUPG_SCD_APP_COMMON_H*/
|
#endif /*GNUPG_SCD_APP_COMMON_H*/
|
||||||
|
@ -1307,6 +1307,8 @@ ccid_get_atr (ccid_driver_t handle,
|
|||||||
/* Note that we ignore the error code on purpose. */
|
/* Note that we ignore the error code on purpose. */
|
||||||
bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_Parameters, seqno);
|
bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_Parameters, seqno);
|
||||||
|
|
||||||
|
handle->t1_ns = 0;
|
||||||
|
handle->t1_nr = 0;
|
||||||
|
|
||||||
/* Send an S-Block with our maximun IFSD to the CCID. */
|
/* Send an S-Block with our maximun IFSD to the CCID. */
|
||||||
if (!handle->auto_ifsd)
|
if (!handle->auto_ifsd)
|
||||||
|
@ -50,6 +50,8 @@
|
|||||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* $Id$
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef CCID_DRIVER_H
|
#ifndef CCID_DRIVER_H
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program; if not, write to the Free Software
|
* along with this program; if not, write to the Free Software
|
||||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||||
|
*
|
||||||
|
* $Id$
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
@ -103,6 +105,17 @@ map_sw (int sw)
|
|||||||
return gpg_error (ec);
|
return gpg_error (ec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Map a status word from the APDU layer to a gpg-error code. */
|
||||||
|
gpg_error_t
|
||||||
|
iso7816_map_sw (int sw)
|
||||||
|
{
|
||||||
|
/* All APDU functions should return 0x9000 on success but for
|
||||||
|
historical reasons of the implementation some return 0 to
|
||||||
|
indicate success. We allow for that here. */
|
||||||
|
return sw? map_sw (sw) : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* This function is specialized version of the SELECT FILE command.
|
/* This function is specialized version of the SELECT FILE command.
|
||||||
SLOT is the card and reader as created for example by
|
SLOT is the card and reader as created for example by
|
||||||
apdu_open_reader (), AID is a buffer of size AIDLEN holding the
|
apdu_open_reader (), AID is a buffer of size AIDLEN holding the
|
||||||
@ -113,15 +126,8 @@ map_sw (int sw)
|
|||||||
gpg_error_t
|
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)
|
||||||
{
|
{
|
||||||
static char const openpgp_aid[] = { 0xD2, 0x76, 0x00, 0x01, 0x24, 0x01 };
|
|
||||||
int sw;
|
int sw;
|
||||||
int p1 = 0x0C; /* No FCI to be returned. */
|
sw = apdu_send_simple (slot, 0x00, CMD_SELECT_FILE, 4, 0, aidlen, aid);
|
||||||
|
|
||||||
if (aidlen == sizeof openpgp_aid
|
|
||||||
&& !memcmp (aid, openpgp_aid, sizeof openpgp_aid))
|
|
||||||
p1 = 0; /* The current openpgp cards don't allow 0x0c. */
|
|
||||||
|
|
||||||
sw = apdu_send_simple (slot, 0x00, CMD_SELECT_FILE, 4, p1, aidlen, aid);
|
|
||||||
return map_sw (sw);
|
return map_sw (sw);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program; if not, write to the Free Software
|
* along with this program; if not, write to the Free Software
|
||||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||||
|
*
|
||||||
|
* $Id$
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef ISO7816_H
|
#ifndef ISO7816_H
|
||||||
|
Loading…
x
Reference in New Issue
Block a user