aboutsummaryrefslogtreecommitdiffstats
path: root/g10/iso7816.c
diff options
context:
space:
mode:
Diffstat (limited to 'g10/iso7816.c')
-rw-r--r--g10/iso7816.c78
1 files changed, 66 insertions, 12 deletions
diff --git a/g10/iso7816.c b/g10/iso7816.c
index afd863858..5b985324f 100644
--- a/g10/iso7816.c
+++ b/g10/iso7816.c
@@ -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,