scd: Add two variants to the set of ISO7816 functions.
authorWerner Koch <wk@gnupg.org>
Thu, 3 Jan 2019 14:18:15 +0000 (15:18 +0100)
committerWerner Koch <wk@gnupg.org>
Thu, 3 Jan 2019 14:18:15 +0000 (15:18 +0100)
* scd/iso7816.c (iso7816_select_application_ext): New.
(iso7816_get_data_odd): New.

Signed-off-by: Werner Koch <wk@gnupg.org>
scd/iso7816.c
scd/iso7816.h

index 01faca5..43c0bcd 100644 (file)
@@ -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)
 {
 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
 /* 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
index 4c71bbd..332fc0e 100644 (file)
@@ -51,6 +51,11 @@ gpg_error_t iso7816_map_sw (int sw);
 gpg_error_t iso7816_select_application (int slot,
                                         const char *aid, size_t aidlen,
                                         unsigned int flags);
 gpg_error_t iso7816_select_application (int slot,
                                         const char *aid, size_t aidlen,
                                         unsigned int flags);
+gpg_error_t iso7816_select_application_ext (int slot,
+                                            const char *aid, size_t aidlen,
+                                            unsigned int flags,
+                                            unsigned char **result,
+                                            size_t *resultlen);
 gpg_error_t iso7816_select_file (int slot, int tag, int is_dir);
 gpg_error_t iso7816_select_path (int slot,
                                  const unsigned short *path, size_t pathlen);
 gpg_error_t iso7816_select_file (int slot, int tag, int is_dir);
 gpg_error_t iso7816_select_path (int slot,
                                  const unsigned short *path, size_t pathlen);
@@ -78,6 +83,8 @@ gpg_error_t iso7816_reset_retry_counter_with_rc (int slot, int chvno,
                                                  size_t datalen);
 gpg_error_t iso7816_get_data (int slot, int extended_mode, int tag,
                               unsigned char **result, size_t *resultlen);
                                                  size_t datalen);
 gpg_error_t iso7816_get_data (int slot, int extended_mode, int tag,
                               unsigned char **result, size_t *resultlen);
+gpg_error_t iso7816_get_data_odd (int slot, int extended_mode, unsigned int tag,
+                                  unsigned char **result, size_t *resultlen);
 gpg_error_t iso7816_put_data (int slot, int extended_mode, int tag,
                               const void *data, size_t datalen);
 gpg_error_t iso7816_put_data_odd (int slot, int extended_mode, int tag,
 gpg_error_t iso7816_put_data (int slot, int extended_mode, int tag,
                               const void *data, size_t datalen);
 gpg_error_t iso7816_put_data_odd (int slot, int extended_mode, int tag,