mirror of
git://git.gnupg.org/gnupg.git
synced 2024-12-22 10:19:57 +01:00
Basically made Belgian EID cards work.
Signature creation has not yet been tested. Also other changes to better cope with T=0 cards.
This commit is contained in:
parent
0a09a6316e
commit
1b2f7cbe3b
@ -1,3 +1,30 @@
|
||||
2005-09-05 Werner Koch <wk@g10code.com>
|
||||
|
||||
* iso7816.c (iso7816_select_path): New.
|
||||
* app-p15.c (select_ef_by_path): Allow for direct path selection.
|
||||
(app_select_p15): Try using the beigian variant of pkcs#15.
|
||||
(read_home_df): New.
|
||||
(read_ef_odf): Generalized.
|
||||
(read_ef_tokeninfo): New.
|
||||
(read_p15_info): Set serialnumber from TokenInfo.
|
||||
(app_select_p15): Don't munge serialNumber - that must be done
|
||||
only once.
|
||||
|
||||
* 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.
|
||||
* pcsc-wrapper.c (handle_status): Return the current protocol as
|
||||
a new third word.
|
||||
|
||||
2005-08-05 Werner Koch <wk@g10code.com>
|
||||
|
||||
* apdu.c (open_rapdu_reader): Set the reader number.
|
||||
|
||||
2005-07-05 Werner Koch <wk@g10code.com>
|
||||
|
||||
* app-openpgp.c (do_readkey): Return a mallcoed copy of the key as
|
||||
|
45
scd/apdu.c
45
scd/apdu.c
@ -15,7 +15,8 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
||||
* USA.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
@ -126,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
|
||||
@ -275,6 +277,9 @@ long (* DLSTDCALL pcsc_set_timeout) (unsigned long context,
|
||||
unsigned long timeout);
|
||||
|
||||
|
||||
/* Prototypes. */
|
||||
static int pcsc_get_status (int slot, unsigned int *status);
|
||||
|
||||
|
||||
|
||||
/*
|
||||
@ -319,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;
|
||||
@ -768,6 +774,7 @@ 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;
|
||||
@ -841,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:
|
||||
@ -902,6 +912,7 @@ reset_pcsc_reader (int slot)
|
||||
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 */
|
||||
@ -917,7 +928,7 @@ 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;
|
||||
@ -968,14 +979,20 @@ pcsc_get_status (int slot, unsigned int *status)
|
||||
|
||||
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. */
|
||||
@ -1296,6 +1313,7 @@ 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 ();
|
||||
@ -1440,7 +1458,7 @@ open_pcsc_reader (const char *portstr)
|
||||
|
||||
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)
|
||||
@ -1463,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;
|
||||
|
||||
@ -1596,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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1997,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,
|
||||
@ -2518,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;
|
||||
@ -2536,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);
|
||||
@ -2736,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)
|
||||
{
|
||||
|
@ -15,7 +15,8 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
||||
* USA.
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
@ -41,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,
|
||||
@ -65,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);
|
||||
|
245
scd/app-p15.c
245
scd/app-p15.c
@ -74,7 +74,17 @@ static struct
|
||||
#undef X
|
||||
|
||||
|
||||
/* The Pin Types as defined in pkcs#15 v1.1 */
|
||||
/* The AID of PKCS15. */
|
||||
static char const pkcs15_aid[] = { 0xA0, 0, 0, 0, 0x63,
|
||||
0x50, 0x4B, 0x43, 0x53, 0x2D, 0x31, 0x35 };
|
||||
|
||||
/* The Belgian eID variant - they didn't understood why a shared AID
|
||||
is useful for a standard. Oh well. */
|
||||
static char const pkcs15be_aid[] = { 0xA0, 0, 0, 0x01, 0x77,
|
||||
0x50, 0x4B, 0x43, 0x53, 0x2D, 0x31, 0x35 };
|
||||
|
||||
|
||||
/* The PIN types as defined in pkcs#15 v1.1 */
|
||||
typedef enum
|
||||
{
|
||||
PIN_TYPE_BCD = 0,
|
||||
@ -261,6 +271,9 @@ struct app_local_s
|
||||
/* The type of the card. */
|
||||
card_type_t card_type;
|
||||
|
||||
/* Flag indicating whether we may use direct path selection. */
|
||||
int direct_path_selection;
|
||||
|
||||
/* Structure with the EFIDs of the objects described in the ODF
|
||||
file. */
|
||||
struct
|
||||
@ -276,6 +289,10 @@ struct app_local_s
|
||||
unsigned short auth_objects;
|
||||
} odf;
|
||||
|
||||
/* The PKCS#15 serialnumber from EF(TokeiNFo) or NULL. Malloced. */
|
||||
unsigned char *serialno;
|
||||
size_t serialnolen;
|
||||
|
||||
/* Information on all certificates. */
|
||||
cdf_object_t certificate_info;
|
||||
/* Information on all trusted certificates. */
|
||||
@ -363,6 +380,7 @@ do_deinit (app_t app)
|
||||
release_cdflist (app->app_local->useful_certificate_info);
|
||||
release_prkdflist (app->app_local->private_key_info);
|
||||
release_aodflist (app->app_local->auth_object_info);
|
||||
xfree (app->app_local->serialno);
|
||||
xfree (app->app_local);
|
||||
app->app_local = NULL;
|
||||
}
|
||||
@ -406,26 +424,44 @@ select_ef_by_path (app_t app, const unsigned short *path, size_t pathlen)
|
||||
gpg_error_t err;
|
||||
int i, j;
|
||||
|
||||
/* FIXME: Need code to remember the last PATH so that we can decide
|
||||
what select commands to send in case the path does not start off
|
||||
with 3F00. We might also want to use direct path selection if
|
||||
supported by the card. */
|
||||
if (!pathlen)
|
||||
return gpg_error (GPG_ERR_INV_VALUE);
|
||||
|
||||
if (pathlen && *path != 0x3f00 )
|
||||
log_debug ("WARNING: relative path selection not yet implemented\n");
|
||||
|
||||
for (i=0; i < pathlen; i++)
|
||||
if (app->app_local->direct_path_selection)
|
||||
{
|
||||
err = iso7816_select_file (app->slot, path[i],
|
||||
!(i+1 == pathlen), NULL, NULL);
|
||||
err = iso7816_select_path (app->slot, path+1, pathlen-1, NULL, NULL);
|
||||
if (err)
|
||||
{
|
||||
log_error ("error selecting part %d from path ", i);
|
||||
log_error ("error selecting path ");
|
||||
for (j=0; j < pathlen; j++)
|
||||
log_printf ("%04hX", path[j]);
|
||||
log_printf (": %s\n", gpg_strerror (err));
|
||||
return err;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* FIXME: Need code to remember the last PATH so that we can decide
|
||||
what select commands to send in case the path does not start off
|
||||
with 3F00. We might also want to use direct path selection if
|
||||
supported by the card. */
|
||||
for (i=0; i < pathlen; i++)
|
||||
{
|
||||
err = iso7816_select_file (app->slot, path[i],
|
||||
!(i+1 == pathlen), NULL, NULL);
|
||||
if (err)
|
||||
{
|
||||
log_error ("error selecting part %d from path ", i);
|
||||
for (j=0; j < pathlen; j++)
|
||||
log_printf ("%04hX", path[j]);
|
||||
log_printf (": %s\n", gpg_strerror (err));
|
||||
return err;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -586,12 +622,13 @@ read_ef_odf (app_t app, unsigned short odf_fid)
|
||||
}
|
||||
else if ( buflen >= 12
|
||||
&& (p[0] & 0xf0) == 0xA0
|
||||
&& !memcmp (p+1, "\x0a\x30\x08\x04\x06\x3F\x00\x50\x15", 9)
|
||||
&& app->app_local->home_df == 0x5015 )
|
||||
&& !memcmp (p+1, "\x0a\x30\x08\x04\x06\x3F\x00", 7)
|
||||
&& app->app_local->home_df == ((p[8]<<8)|p[9]) )
|
||||
{
|
||||
/* This format using a full path is used by a self-created
|
||||
test card of mine. I have not checked whether this is
|
||||
legal. We assume a home DF of 0x5015 here. */
|
||||
/* We only allow a full path if all files are at the same
|
||||
level and below the home directory. The extend this we
|
||||
would need to make use of new data type capable of
|
||||
keeping a full path. */
|
||||
offset = 10;
|
||||
}
|
||||
else
|
||||
@ -2158,12 +2195,81 @@ TokenFlags ::= BIT STRING {
|
||||
|
||||
|
||||
*/
|
||||
/* static gpg_error_t */
|
||||
/* read_ef_tokeninfo (app_t app) */
|
||||
/* { */
|
||||
/* unsigned short efid = 0x5032; */
|
||||
/* return 0; */
|
||||
/* } */
|
||||
static gpg_error_t
|
||||
read_ef_tokeninfo (app_t app)
|
||||
{
|
||||
gpg_error_t err;
|
||||
unsigned char *buffer = NULL;
|
||||
size_t buflen;
|
||||
const unsigned char *p;
|
||||
size_t n, objlen, hdrlen;
|
||||
int class, tag, constructed, ndef;
|
||||
unsigned long ul;
|
||||
|
||||
err = select_and_read_binary (app->slot, 0x5032, "TokenInfo",
|
||||
&buffer, &buflen);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
p = buffer;
|
||||
n = buflen;
|
||||
|
||||
err = parse_ber_header (&p, &n, &class, &tag, &constructed,
|
||||
&ndef, &objlen, &hdrlen);
|
||||
if (!err && (objlen > n || tag != TAG_SEQUENCE))
|
||||
err = gpg_error (GPG_ERR_INV_OBJ);
|
||||
if (err)
|
||||
{
|
||||
log_error ("error parsing TokenInfo: %s\n", gpg_strerror (err));
|
||||
goto leave;
|
||||
}
|
||||
|
||||
n = objlen;
|
||||
|
||||
/* Version. */
|
||||
err = parse_ber_header (&p, &n, &class, &tag, &constructed,
|
||||
&ndef, &objlen, &hdrlen);
|
||||
if (!err && (objlen > n || tag != TAG_INTEGER))
|
||||
err = gpg_error (GPG_ERR_INV_OBJ);
|
||||
if (err)
|
||||
goto leave;
|
||||
|
||||
for (ul=0; objlen; objlen--)
|
||||
{
|
||||
ul <<= 8;
|
||||
ul |= (*p++) & 0xff;
|
||||
n--;
|
||||
}
|
||||
if (ul)
|
||||
{
|
||||
log_error ("invalid version %lu in TokenInfo\n", ul);
|
||||
err = gpg_error (GPG_ERR_INV_OBJ);
|
||||
goto leave;
|
||||
}
|
||||
|
||||
/* serialNumber. */
|
||||
err = parse_ber_header (&p, &n, &class, &tag, &constructed,
|
||||
&ndef, &objlen, &hdrlen);
|
||||
if (!err && (objlen > n || tag != TAG_OCTET_STRING || !objlen))
|
||||
err = gpg_error (GPG_ERR_INV_OBJ);
|
||||
if (err)
|
||||
goto leave;
|
||||
|
||||
xfree (app->app_local->serialno);
|
||||
app->app_local->serialno = xtrymalloc (objlen);
|
||||
if (!app->app_local->serialno)
|
||||
{
|
||||
err = gpg_error_from_errno (errno);
|
||||
goto leave;
|
||||
}
|
||||
memcpy (app->app_local->serialno, p, objlen);
|
||||
app->app_local->serialnolen = objlen;
|
||||
log_printhex ("Serialnumber from EF(TokenInfo) is:", p, objlen);
|
||||
|
||||
leave:
|
||||
xfree (buffer);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
/* Get all the basic information from the pkcs#15 card, check the
|
||||
@ -2174,11 +2280,25 @@ read_p15_info (app_t app)
|
||||
{
|
||||
gpg_error_t err;
|
||||
|
||||
/* Fixme: We might need to read the tokeninfo to get a non-standard
|
||||
ODF FID. */
|
||||
if (!read_ef_tokeninfo (app))
|
||||
{
|
||||
/* If we don't have a serial number yet but the TokenInfo provides
|
||||
one, use that. */
|
||||
if (!app->serialno && app->app_local->serialno)
|
||||
{
|
||||
app->serialno = app->app_local->serialno;
|
||||
app->serialnolen = app->app_local->serialnolen;
|
||||
app->app_local->serialno = NULL;
|
||||
app->app_local->serialnolen = 0;
|
||||
err = app_munge_serialno (app);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
/* Read the ODF so that we know the location of all directory
|
||||
files. */
|
||||
/* Fixme: We might need to get a non-standard ODF FID from TokenInfo. */
|
||||
err = read_ef_odf (app, 0x5031);
|
||||
if (err)
|
||||
return err;
|
||||
@ -2895,22 +3015,88 @@ do_sign (app_t app, const char *keyidstr, int hashalgo,
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Assume that EF(DIR) has been selected. Read its content and figure
|
||||
out the home EF of pkcs#15. Return that home DF or 0 if not
|
||||
found. */
|
||||
static unsigned short
|
||||
read_home_df (int slot)
|
||||
{
|
||||
gpg_error_t err;
|
||||
unsigned char *buffer;
|
||||
const unsigned char *p, *pp;
|
||||
size_t buflen, n, nn;
|
||||
unsigned short result = 0;
|
||||
|
||||
err = iso7816_read_binary (slot, 0, 0, &buffer, &buflen);
|
||||
if (err)
|
||||
{
|
||||
log_error ("error reading EF{DIR}: %s\n", gpg_strerror (err));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* FIXME: We need to scan all records. */
|
||||
p = find_tlv (buffer, buflen, 0x61, &n);
|
||||
if (p && n)
|
||||
{
|
||||
pp = find_tlv (p, n, 0x4f, &nn);
|
||||
if (pp
|
||||
&& ((nn == sizeof pkcs15_aid && !memcmp (pp, pkcs15_aid, nn))
|
||||
||(nn == sizeof pkcs15be_aid && !memcmp (pp, pkcs15be_aid, nn))))
|
||||
{
|
||||
pp = find_tlv (p, n, 0x50, &nn);
|
||||
if (pp) /* fixme: Filter log value? */
|
||||
log_info ("pkcs#15 application label from EF(DIR) is `%.*s'\n",
|
||||
(int)nn, pp);
|
||||
pp = find_tlv (p, n, 0x51, &nn);
|
||||
if (pp && nn == 4 && *pp == 0x3f && !pp[1])
|
||||
{
|
||||
result = ((pp[2] << 8) | pp[3]);
|
||||
log_info ("pkcs#15 application directory is 0x%04hX\n", result);
|
||||
}
|
||||
}
|
||||
}
|
||||
xfree (buffer);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/* Select the PKCS#15 application on the card in SLOT. */
|
||||
/*
|
||||
Select the PKCS#15 application on the card in SLOT.
|
||||
*/
|
||||
gpg_error_t
|
||||
app_select_p15 (app_t app)
|
||||
{
|
||||
static char const aid[] = { 0xA0, 0, 0, 0, 0x63,
|
||||
0x50, 0x4B, 0x43, 0x53, 0x2D, 0x31, 0x35 };
|
||||
int slot = app->slot;
|
||||
int rc;
|
||||
unsigned short def_home_df = 0;
|
||||
card_type_t card_type = CARD_TYPE_UNKNOWN;
|
||||
int direct = 0;
|
||||
|
||||
rc = iso7816_select_application (slot, aid, sizeof aid);
|
||||
rc = iso7816_select_application (slot, pkcs15_aid, sizeof pkcs15_aid);
|
||||
if (rc)
|
||||
{
|
||||
rc = iso7816_select_application (slot, pkcs15be_aid, sizeof pkcs15be_aid);
|
||||
if (rc)
|
||||
{ /* Not found: Try to locate it from 2F00. We use direct path
|
||||
selection here because it seems that the Belgian eID card
|
||||
does only allow for that. Many other cards supports this
|
||||
selection method too. */
|
||||
unsigned short path[1] = { 0x2f00 };
|
||||
|
||||
rc = iso7816_select_path (app->slot, path, 1, NULL, NULL);
|
||||
if (!rc)
|
||||
{
|
||||
direct = 1;
|
||||
def_home_df = read_home_df (slot);
|
||||
if (def_home_df)
|
||||
{
|
||||
path[0] = def_home_df;
|
||||
rc = iso7816_select_path (app->slot, path, 1, NULL, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (rc)
|
||||
{ /* Still not found: Try the default DF. */
|
||||
def_home_df = 0x5015;
|
||||
rc = iso7816_select_file (slot, def_home_df, 1, NULL, NULL);
|
||||
}
|
||||
@ -2958,6 +3144,9 @@ app_select_p15 (app_t app)
|
||||
the common APP structure. */
|
||||
app->app_local->card_type = card_type;
|
||||
|
||||
/* Store whether we may and should use direct path selection. */
|
||||
app->app_local->direct_path_selection = direct;
|
||||
|
||||
/* Read basic information and thus check whether this is a real
|
||||
card. */
|
||||
rc = read_p15_info (app);
|
||||
@ -2989,8 +3178,6 @@ app_select_p15 (app_t app)
|
||||
app->serialno = p;
|
||||
}
|
||||
}
|
||||
else /* Use standard munging code. */
|
||||
rc = app_munge_serialno (app);
|
||||
|
||||
app->fnc.deinit = do_deinit;
|
||||
app->fnc.learn_status = do_learn_status;
|
||||
|
@ -77,6 +77,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;
|
||||
@ -161,6 +162,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,
|
||||
@ -524,8 +558,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
|
||||
@ -533,6 +569,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)
|
||||
{
|
||||
|
@ -33,6 +33,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,
|
||||
|
@ -15,7 +15,8 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
||||
* USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
@ -587,6 +588,11 @@ handle_status (unsigned char *argbuf, size_t arglen)
|
||||
buf[5] = (rdrstates[0].event_state >> 16);
|
||||
buf[6] = (rdrstates[0].event_state >> 8);
|
||||
buf[7] = (rdrstates[0].event_state >> 0);
|
||||
/* The third word is the protocol. */
|
||||
buf[8] = (pcsc_protocol >> 24);
|
||||
buf[9] = (pcsc_protocol >> 16);
|
||||
buf[10] = (pcsc_protocol >> 8);
|
||||
buf[11] = (pcsc_protocol);
|
||||
|
||||
request_succeeded (buf, 8);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user