diff options
Diffstat (limited to 'g10/iso7816.c')
-rw-r--r-- | g10/iso7816.c | 78 |
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, |