summaryrefslogtreecommitdiffstats
path: root/scd/iso7816.c
diff options
context:
space:
mode:
authorWerner Koch <wk@gnupg.org>2019-01-03 15:18:15 +0100
committerWerner Koch <wk@gnupg.org>2019-01-03 15:18:15 +0100
commit405feca2bdeeb620dc406667a702035a123ae848 (patch)
tree460c0507d00103e166ed826672065b4718cc960c /scd/iso7816.c
parentscd: Support "READKEY --advanced" for all cards. (diff)
downloadgnupg2-405feca2bdeeb620dc406667a702035a123ae848.tar.xz
gnupg2-405feca2bdeeb620dc406667a702035a123ae848.zip
scd: Add two variants to the set of ISO7816 functions.
* scd/iso7816.c (iso7816_select_application_ext): New. (iso7816_get_data_odd): New. Signed-off-by: Werner Koch <wk@gnupg.org>
Diffstat (limited to 'scd/iso7816.c')
-rw-r--r--scd/iso7816.c79
1 files changed, 79 insertions, 0 deletions
diff --git a/scd/iso7816.c b/scd/iso7816.c
index 01faca5b4..43c0bcd8e 100644
--- a/scd/iso7816.c
+++ b/scd/iso7816.c
@@ -138,6 +138,21 @@ iso7816_select_application (int slot, const char *aid, size_t aidlen,
}
+/* This is the same as iso7816_select_application but may return data
+ * at RESULT,RESULTLEN). */
+gpg_error_t
+iso7816_select_application_ext (int slot, const char *aid, size_t aidlen,
+ unsigned int flags,
+ unsigned char **result, size_t *resultlen)
+{
+ int sw;
+ sw = apdu_send (slot, 0, 0x00, CMD_SELECT_FILE, 4,
+ (flags&1)? 0:0x0c, aidlen, aid,
+ result, resultlen);
+ return map_sw (sw);
+}
+
+
gpg_error_t
iso7816_select_file (int slot, int tag, int is_dir)
{
@@ -396,6 +411,70 @@ iso7816_get_data (int slot, int extended_mode, int tag,
}
+/* Perform a GET DATA command requesting TAG and storing the result in
+ * a newly allocated buffer at the address passed by RESULT. Return
+ * the length of this data at the address of RESULTLEN. This variant
+ * is needed for long (3 octet) tags. */
+gpg_error_t
+iso7816_get_data_odd (int slot, int extended_mode, unsigned int tag,
+ unsigned char **result, size_t *resultlen)
+{
+ int sw;
+ int le;
+ int datalen;
+ unsigned char data[5];
+
+ if (!result || !resultlen)
+ return gpg_error (GPG_ERR_INV_VALUE);
+ *result = NULL;
+ *resultlen = 0;
+
+ if (extended_mode > 0 && extended_mode < 256)
+ le = 65534; /* Not 65535 in case it is used as some special flag. */
+ else if (extended_mode > 0)
+ le = extended_mode;
+ else
+ le = 256;
+
+ data[0] = 0x5c;
+ if (tag <= 0xff)
+ {
+ data[1] = 1;
+ data[2] = tag;
+ datalen = 3;
+ }
+ else if (tag <= 0xffff)
+ {
+ data[1] = 2;
+ data[2] = (tag >> 8);
+ data[3] = tag;
+ datalen = 4;
+ }
+ else
+ {
+ data[1] = 3;
+ data[2] = (tag >> 16);
+ data[3] = (tag >> 8);
+ data[4] = tag;
+ datalen = 5;
+ }
+
+ sw = apdu_send_le (slot, extended_mode, 0x00, CMD_GET_DATA + 1,
+ 0x3f, 0xff, datalen, data, le,
+ result, resultlen);
+ if (sw != SW_SUCCESS)
+ {
+ /* Make sure that pending buffers are released. */
+ xfree (*result);
+ *result = NULL;
+ *resultlen = 0;
+ return map_sw (sw);
+ }
+
+ return 0;
+}
+
+
/* Perform a PUT DATA command on card in SLOT. Write DATA of length
DATALEN to TAG. EXTENDED_MODE controls whether extended length
headers or command chaining is used instead of single length