diff options
author | Werner Koch <wk@gnupg.org> | 2019-01-03 15:18:15 +0100 |
---|---|---|
committer | Werner Koch <wk@gnupg.org> | 2019-01-03 15:18:15 +0100 |
commit | 405feca2bdeeb620dc406667a702035a123ae848 (patch) | |
tree | 460c0507d00103e166ed826672065b4718cc960c /scd/iso7816.c | |
parent | scd: Support "READKEY --advanced" for all cards. (diff) | |
download | gnupg2-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.c | 79 |
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 |