summaryrefslogtreecommitdiffstats
path: root/scd/iso7816.c
diff options
context:
space:
mode:
Diffstat (limited to 'scd/iso7816.c')
-rw-r--r--scd/iso7816.c63
1 files changed, 62 insertions, 1 deletions
diff --git a/scd/iso7816.c b/scd/iso7816.c
index c878a03..35bf282 100644
--- a/scd/iso7816.c
+++ b/scd/iso7816.c
@@ -43,6 +43,7 @@
#define CMD_SELECT_FILE 0xA4
+#define CMD_SELECT_DATA 0xA5
#define CMD_VERIFY ISO7816_VERIFY
#define CMD_CHANGE_REFERENCE_DATA ISO7816_CHANGE_REFERENCE_DATA
#define CMD_RESET_RETRY_COUNTER ISO7816_RESET_RETRY_COUNTER
@@ -56,6 +57,7 @@
#define CMD_GET_CHALLENGE 0x84
#define CMD_READ_BINARY 0xB0
#define CMD_READ_RECORD 0xB2
+#define CMD_UPDATE_BINARY 0xD6
static gpg_error_t
map_sw (int sw)
@@ -444,6 +446,44 @@ iso7816_reset_retry_counter (int slot, int chvno,
}
+/* Perform a SELECT DATA command to OCCURANCE of TAG. */
+gpg_error_t
+iso7816_select_data (int slot, int occurrence, int tag)
+{
+ int sw;
+ int datalen;
+ unsigned char data[7];
+
+ data[0] = 0x60;
+ data[2] = 0x5c;
+ if (tag <= 0xff)
+ {
+ data[3] = 1;
+ data[4] = tag;
+ datalen = 5;
+ }
+ else if (tag <= 0xffff)
+ {
+ data[3] = 2;
+ data[4] = (tag >> 8);
+ data[5] = tag;
+ datalen = 6;
+ }
+ else
+ {
+ data[3] = 3;
+ data[4] = (tag >> 16);
+ data[5] = (tag >> 8);
+ data[6] = tag;
+ datalen = 7;
+ }
+ data[1] = datalen - 2;
+
+ sw = apdu_send_le (slot, 0, 0x00, CMD_SELECT_DATA,
+ occurrence, 0x04, datalen, data, 0, NULL, NULL);
+ return map_sw (sw);
+}
+
/* Perform a GET DATA command requesting TAG and storing the result in
a newly allocated buffer at the address passed by RESULT. Return
@@ -905,7 +945,7 @@ iso7816_read_binary_ext (int slot, int extended_mode,
if (r_sw)
*r_sw = sw;
- if (*result && sw == SW_BAD_P0_P1)
+ if (*result && (sw == SW_BAD_P0_P1 || sw == SW_INCORRECT_P0_P1))
{
/* Bad Parameter means that the offset is outside of the
EF. When reading all data we take this as an indication
@@ -1025,6 +1065,7 @@ iso7816_read_record_ext (int slot, int recno, int reccount, int short_ef,
return 0;
}
+
gpg_error_t
iso7816_read_record (int slot, int recno, int reccount, int short_ef,
unsigned char **result, size_t *resultlen)
@@ -1032,3 +1073,23 @@ iso7816_read_record (int slot, int recno, int reccount, int short_ef,
return iso7816_read_record_ext (slot, recno, reccount, short_ef,
result, resultlen, NULL);
}
+
+
+/* Perform an UPDATE BINARY command on card in SLOT. Write DATA of
+ * length DATALEN to a transparent file at OFFSET. */
+gpg_error_t
+iso7816_update_binary (int slot, int extended_mode, size_t offset,
+ const void *data, size_t datalen)
+{
+ int sw;
+
+ /* We can only encode 15 bits in p0,p1 to indicate an offset. Thus
+ * we check for this limit. */
+ if (offset > 32767)
+ return gpg_error (GPG_ERR_INV_VALUE);
+
+ sw = apdu_send_simple (slot, extended_mode, 0x00, CMD_UPDATE_BINARY,
+ ((offset>>8) & 0xff), (offset & 0xff),
+ datalen, (const char*)data);
+ return map_sw (sw);
+}