[Spice-devel] [PATCH libcacard v2 28/35] cac, cac-aca: Implement other undocumented encoding for extended properties
Jakub Jelen
jjelen at redhat.com
Thu Aug 2 09:44:00 UTC 2018
* These modifiers nor format is not documented anywhere, but ActivClient
expects them and cards happily answer them
* This is a kind of more compressed form of other ACA buffers, but it is
extended with some additional values of unknown meaning.
* This is somehow consistent with the standard GET ACR parameters, but if
P1 | 0x40 is set, the response should come in this new format.
* This affects also GET PROPERTIES APDU, where we get also other bunch of
TLVs in case of this bit is set.
Signed-off-by: Jakub Jelen <jjelen at redhat.com>
Reviewed-by: Robert Relyea <rrelyea at redhat.com>
---
src/cac-aca.c | 293 ++++++++++++++++++++++++++++++++++++++++++++--
src/cac-aca.h | 9 +-
src/cac.c | 268 +++++++++++++++++++++++++++++++++++-------
src/cac.h | 6 +-
tests/common.c | 45 ++++++-
tests/libcacard.c | 56 +++++++++
6 files changed, 621 insertions(+), 56 deletions(-)
diff --git a/src/cac-aca.c b/src/cac-aca.c
index aae06a1..a915689 100644
--- a/src/cac-aca.c
+++ b/src/cac-aca.c
@@ -370,6 +370,7 @@ cac_aca_get_service_table(size_t *r_len, unsigned int pki_applets)
* Can be pulled from existing card using the OpenSC:
* $ opensc-tool -s 00A4040007A0000000790300 -s 804C100000
*/
+
enum {
ACR_INS_CONFIG_NONE = 0x00,
ACR_INS_CONFIG_P1 = 0x01,
@@ -950,6 +951,16 @@ struct amp_table amp_table = {
}
};
+static unsigned char amp_table_extended[] = {
+ 0x1F, 0x00, 0x07, 0xA0, 0x00, 0x00, 0x00, 0x79, 0x03, 0x00,
+ 0x12, 0x00, 0x00, 0x00,
+ /* Sometimes it can be 1E 00 07 A0 00 00 00 79 03 00 10 00 00 00 */
+ 0x1E, 0x00, 0x07, 0xA0, 0x00, 0x00, 0x00, 0x79, 0x03, 0x00,
+ 0x10, 0x01, 0x00, 0x00,
+ 0x1D, 0x00, 0x07, 0xA0, 0x00, 0x00, 0x00, 0x79, 0x03, 0x00,
+ 0x01, 0x00, 0x00, 0x00,
+};
+
static struct simpletlv_member *
cac_aca_get_amp(size_t *amp_len)
{
@@ -1013,10 +1024,72 @@ cac_aca_get_properties(size_t *properties_len)
return aca_properties;
}
+/*
+ * This is ACR table in undocumented compressed form
+ *
+ * |ACRID ACRType AMPid:keyID
+ * 06 00 00 00 00 00 00 | 00 00
+ * 06 01 01 00 01 00 00 | 01 01
+ * 06 02 00 1F 00 00 00 | 02 00
+ * 06 06 06 00 1E 00 00 | 06 06 1E:00
+ * 06 04 04 1F 1F 21 00 | 04 04 1F:21
+ * 08 08 03 00 9D 01 1E 01 00 | 08 03 9D:01 1E:01
+ * 06 09 02 00 1D 02 00 | 09 02 1D:02
+ * 08 0A 03 00 9D 03 1E 01 00 | 0A 03 9D:03 1E:01
+ * 06 0B 02 00 1D 04 00 | 0B 02 1D:04
+ * 06 10 00 1E 00 00 00 | 10 00
+ * 06 11 00 1D 00 00 00 | 11 00
+ * len | | ? | |
+ * ACRID | ? | |
+ * ACRType | |
+ * AMPid |
+ * KeyIdOrReference
+ */
+static VCardResponse *
+cac_aca_get_acr_response_extended(VCard *card, int Le, unsigned char *acrid)
+{
+ size_t buffer_len;
+ unsigned char *buffer = NULL, *p;
+ VCardResponse *r = NULL;
+ size_t i, j;
+ buffer_len = acr_table.num_entries * (7 + 2 * (MAX_ACCESS_METHODS - 1));
+ buffer = g_malloc_n(buffer_len, sizeof(unsigned char));
+ p = buffer;
-VCardResponse *
-cac_aca_get_acr_response(VCard *card, int Le, unsigned char *acrid)
+ for (i = 0; i < acr_table.num_entries; i++) {
+ struct acr_entry *a = &acr_table.entries[i];
+ g_assert_cmpint(a->num_access_methods, <=, MAX_ACCESS_METHODS);
+ *p++ = a->num_access_methods == 2 ? 0x08 : 0x06;
+ *p++ = a->acrid;
+ *p++ = a->acrtype;
+ *p++ = a->applet_id;
+
+ for (j = 0; j < a->num_access_methods; j++) {
+ *p++ = a->access_methods[j].provider_id;
+ *p++ = a->access_methods[j].keyIDOrReference;
+ }
+ if (a->num_access_methods == 0) {
+ *p++ = 0x00;
+ *p++ = 0x00;
+ }
+ *p++ = 0x00;
+ }
+ g_assert((unsigned long)(p - buffer) <= buffer_len);
+ buffer_len = (p - buffer);
+
+ r = vcard_response_new(card, buffer, buffer_len, Le,
+ VCARD7816_STATUS_SUCCESS);
+ g_debug("%s: response bytes: %s", __func__,
+ hex_dump(buffer, buffer_len, NULL, 0));
+ g_free(buffer);
+ return r;
+}
+
+
+
+static VCardResponse *
+cac_aca_get_acr_response_simpletlv(VCard *card, int Le, unsigned char *acrid)
{
size_t acr_buffer_len;
unsigned char *acr_buffer = NULL;
@@ -1061,9 +1134,21 @@ failure:
}
VCardResponse *
-cac_aca_get_applet_acr_response(VCard *card, int Le, unsigned int pki_applets,
- unsigned char *aid, unsigned int aid_len,
- unsigned char *coid)
+cac_aca_get_acr_response(VCard *card, int Le, unsigned char *acrid, int format)
+{
+ if (format == CAC_FORMAT_SIMPLETLV) {
+ return cac_aca_get_acr_response_simpletlv(card, Le, acrid);
+ } else {
+ return cac_aca_get_acr_response_extended(card, Le, acrid);
+ }
+}
+
+static VCardResponse *
+cac_aca_get_applet_acr_response_simpletlv(VCard *card, int Le,
+ unsigned int pki_applets,
+ unsigned char *aid,
+ unsigned int aid_len,
+ unsigned char *coid)
{
size_t acr_buffer_len;
unsigned char *acr_buffer = NULL;
@@ -1080,7 +1165,7 @@ cac_aca_get_applet_acr_response(VCard *card, int Le, unsigned int pki_applets,
if (coid != NULL) {
g_debug("%s: Called. COID = %s", __func__, hex_dump(coid, 2, NULL, 0));
- /* getting the table for COID (2B) */
+ /* getting the table for Card Object ID (2B) */
acr_len = 1; // returns exactly one element if found
acr = cac_aca_get_applet_acr_coid(pki_applets, coid);
if (!acr) {
@@ -1125,8 +1210,112 @@ failure:
return r;
}
+/*
+ * This is Applet/Object ACR Table in undocumented compressed format.
+ *
+ * Len
+ * | Applet Id
+ * | | Num Objects
+ * | | | Len [OID] INS+Config+ACRID
+ * 1C 1F 01
+ * 19 FF FF
+ * 26 80 00
+ * 2C 80 04
+ * 24 81 80 04
+ * 24 81 01 00
+ * 24 80 06
+ * 20 00 00
+ * D8 80 04
+ * 24 4F 02
+ * 08 DB 00
+ * 58 00 04
+ * 52 00 00
+ * 18 FF FF
+ * 82 01 00 11
+ * 50 80 02
+ * 82 80 02
+ * F0 80 04
+ * 34 80 04
+ * 84 00 11
+ * 20 00 10
+ * [...]
+ */
+static VCardResponse *
+cac_aca_get_applet_acr_response_extended(VCard *card, int Le,
+ unsigned int pki_applets,
+ unsigned char *aid,
+ unsigned int aid_len,
+ unsigned char *coid)
+{
+ size_t buffer_len, i, j, plen;
+ unsigned char *buffer = NULL, *p;
+ VCardResponse *r = NULL;
+ unsigned int num_applets = applets_table.num_static_applets + pki_applets;
+
+ buffer_len = num_applets * (3 + ACR_MAX_APPLET_OBJECTS
+ * ( 3 + ACR_MAX_INSTRUCTIONS * 6));
+ buffer = g_malloc_n(buffer_len, sizeof(unsigned char));
+ p = buffer;
+ plen = buffer_len;
+
+ for (i = 0; i < applets_table.num_applets; i++) {
+ struct acr_applet *a;
+ unsigned char *len;
+ /* Skip unused PKI applets */
+ if (i >= pki_applets && i < 10)
+ continue;
+
+ a = &applets_table.applets[i];
+ if (plen < 3)
+ goto failure;
+ len = p++; /* here we will store the length later */
+ *p++ = a->id;
+ *p++ = a->num_objects;
+ plen -= 3;
+ for (j = 0; j < a->num_objects; j++) {
+ struct acr_object *o = &a->objects[j];
+ unsigned char *len2;
+ unsigned int olen;
+
+ len2 = p++; /* here we will store the length later */
+ /* the encoding from here on is the same as in specification */
+ p = acr_applet_object_encode(o, p, plen, &olen);
+ if (!p)
+ goto failure;
+ plen -= olen;
+ *len2 = olen;
+ }
+ *len = (p - len - 1);
+ }
+ g_assert((unsigned long)(p - buffer) <= buffer_len);
+ buffer_len = (p - buffer);
+
+ r = vcard_response_new(card, buffer, buffer_len, Le,
+ VCARD7816_STATUS_SUCCESS);
+ g_debug("%s: response bytes: %s", __func__,
+ hex_dump(buffer, buffer_len, NULL, 0));
+failure:
+ g_free(buffer);
+ return r;
+}
+
VCardResponse *
-cac_aca_get_amp_response(VCard *card, int Le)
+cac_aca_get_applet_acr_response(VCard *card, int Le, unsigned int pki_applets,
+ unsigned char *aid, unsigned int aid_len,
+ unsigned char *coid, int format)
+{
+ if (format == CAC_FORMAT_SIMPLETLV) {
+ return cac_aca_get_applet_acr_response_simpletlv(card, Le,
+ pki_applets, aid, aid_len, coid);
+ } else {
+ return cac_aca_get_applet_acr_response_extended(card, Le,
+ pki_applets, aid, aid_len, coid);
+ }
+}
+
+
+static VCardResponse *
+cac_aca_get_amp_response_simpletlv(VCard *card, int Le)
{
size_t amp_buffer_len;
unsigned char *amp_buffer = NULL;
@@ -1168,7 +1357,84 @@ failure:
}
VCardResponse *
-cac_aca_get_service_response(VCard *card, int Le, unsigned int pki_applets)
+cac_aca_get_amp_response(VCard *card, int Le, int format)
+{
+ if (format == CAC_FORMAT_SIMPLETLV) {
+ return cac_aca_get_amp_response_simpletlv(card, Le);
+ } else {
+ /* 1F 00 07 A0 00 00 00 79 03 00 12 00 00 00
+ * 1E 00 07 A0 00 00 00 79 03 00 10 01 00 00
+ * 1D 00 07 A0 00 00 00 79 03 00 01 00 00 00
+ * LEN [ AID ] [OID]
+ */
+ return vcard_response_new(card, amp_table_extended,
+ sizeof(amp_table_extended), Le, VCARD7816_STATUS_SUCCESS);
+ }
+}
+
+/*
+ * This is Service Applet table in undocumented compressed format
+ *
+ * Applet ID
+ * | Len [ AID ]
+ * 40 00 07 A0 00 00 01 16 30 00
+ * 4F 00 07 A0 00 00 01 16 DB 00
+ * 4B 00 07 A0 00 00 00 79 02 FB
+ * 41 00 07 A0 00 00 00 79 02 00
+ * 42 00 07 A0 00 00 00 79 02 01
+ * 4E 00 07 A0 00 00 00 79 02 FE
+ * 4D 00 07 A0 00 00 00 79 02 FD
+ * 50 00 07 A0 00 00 00 79 02 F2
+ * 63 00 07 A0 00 00 00 79 01 02
+ * 51 00 07 A0 00 00 00 79 02 F0
+ * 61 00 07 A0 00 00 00 79 01 00
+ * 52 00 07 A0 00 00 00 79 02 F1
+ * 62 00 07 A0 00 00 00 79 01 01
+ * 44 00 07 A0 00 00 00 79 12 01
+ * 45 00 07 A0 00 00 00 79 12 02
+ */
+static VCardResponse *
+cac_aca_get_service_response_extended(VCard *card, int Le,
+ unsigned int pki_applets)
+{
+ size_t buffer_len;
+ unsigned char *buffer = NULL, *p;
+ VCardResponse *r = NULL;
+ size_t num_entries, i;
+
+ num_entries = service_table.num_static_entries + pki_applets;
+
+ buffer_len = num_entries * (3 + MAX_AID_LEN);
+ buffer = g_malloc(buffer_len);
+ p = buffer;
+
+ for (i = 0; i < service_table.num_entries; i++) {
+ struct applet_entry *e;
+ /* Skip unused PKI applets */
+ if (i >= pki_applets && i < 10)
+ continue;
+
+ e = &service_table.entries[i];
+ *p++ = e->applet_id;
+ *p++ = 0;
+ *p++ = e->applet_aid_len;
+ memcpy(p, e->applet_aid, e->applet_aid_len);
+ p += e->applet_aid_len;
+ }
+ g_assert((unsigned long)(p - buffer) <= buffer_len);
+ buffer_len = (p - buffer);
+
+ r = vcard_response_new(card, buffer, buffer_len, Le,
+ VCARD7816_STATUS_SUCCESS);
+ g_debug("%s: response bytes: %s", __func__,
+ hex_dump(buffer, buffer_len, NULL, 0));
+ g_free(buffer);
+ return r;
+}
+
+static VCardResponse *
+cac_aca_get_service_response_simpletlv(VCard *card, int Le,
+ unsigned int pki_applets)
{
size_t service_buffer_len;
unsigned char *service_buffer = NULL;
@@ -1209,4 +1475,15 @@ failure:
return r;
}
+VCardResponse *
+cac_aca_get_service_response(VCard *card, int Le,
+ unsigned int pki_applets, int format)
+{
+ if (format == CAC_FORMAT_SIMPLETLV) {
+ return cac_aca_get_service_response_simpletlv(card, Le, pki_applets);
+ } else {
+ return cac_aca_get_service_response_extended(card, Le, pki_applets);
+ }
+}
+
/* vim: set ts=4 sw=4 tw=0 noet expandtab: */
diff --git a/src/cac-aca.h b/src/cac-aca.h
index cb3a606..34dde2d 100644
--- a/src/cac-aca.h
+++ b/src/cac-aca.h
@@ -19,14 +19,15 @@
#include <string.h>
VCardResponse *
-cac_aca_get_acr_response(VCard *card, int Le, unsigned char *acrid);
+cac_aca_get_acr_response(VCard *card, int Le, unsigned char *acrid, int format);
VCardResponse *
cac_aca_get_applet_acr_response(VCard *card, int Le, unsigned int pki_applets,
unsigned char *aid, unsigned int aid_len,
- unsigned char *coid);
+ unsigned char *coid, int format);
VCardResponse *
-cac_aca_get_amp_response(VCard *card, int Le);
+cac_aca_get_amp_response(VCard *card, int Le, int format);
VCardResponse *
-cac_aca_get_service_response(VCard *card, int Le, unsigned int pki_applets);
+cac_aca_get_service_response(VCard *card, int Le, unsigned int pki_applets,
+ int format);
diff --git a/src/cac.c b/src/cac.c
index b96ba8c..ba63685 100644
--- a/src/cac.c
+++ b/src/cac.c
@@ -4,6 +4,15 @@
* Adaptation to GSC-IS 2.1:
* https://nvlpubs.nist.gov/nistpubs/Legacy/IR/nistir6887e2003.pdf
*
+ * and NIST SP 800-73-4
+ * https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-73-4.pdf
+ *
+ * Copyright 2010 - 2018 Red Hat, Inc.
+ *
+ * Authors: Robert Relyea <rrelyea at redhat.com>
+ * Alon Levy <alevy at redhat.com>
+ * Jakub Jelen <jjelen at redhat.com>
+ *
* This code is licensed under the GNU LGPL, version 2.1 or later.
* See the COPYING file in the top-level directory.
*/
@@ -86,6 +95,7 @@ struct VCardAppletPrivateStruct {
int val_buffer_len;
struct simpletlv_member *properties;
unsigned int properties_len;
+ unsigned int long_properties_len;
/* TODO we should also keep a state, which OID is selected,
* but it does not matter now, because we do not have anything different
* in either buffer
@@ -263,6 +273,7 @@ cac_common_process_apdu(VCard *card, VCardAPDU *apdu, VCardResponse **response)
ret = VCARD_DONE;
break;
}
+
switch (apdu->a_p1) {
case 0x00:
/* Get a GSC-IS v2.0 compatible properties response message. */
@@ -278,8 +289,11 @@ cac_common_process_apdu(VCard *card, VCardAPDU *apdu, VCardResponse **response)
ret = VCARD_DONE;
break;
}
+ /* TODO the properties buffer should be shorter for P1 = 0x01 */
+
*response = get_properties(card, applet_private->properties,
applet_private->properties_len, NULL, 0, apdu->a_Le);
+
break;
case 0x02:
/* Get the properties of the tags provided in list of tags in
@@ -293,12 +307,20 @@ cac_common_process_apdu(VCard *card, VCardAPDU *apdu, VCardResponse **response)
*response = get_properties(card, applet_private->properties,
applet_private->properties_len, apdu->a_body, apdu->a_Lc, apdu->a_Le);
break;
+ case 0x40:
+ /* XXX This is undocumented P1 argument, which returns properties
+ * extended with some more values of unknown meaning.
+ */
+ *response = get_properties(card, applet_private->properties,
+ applet_private->long_properties_len, NULL, 0, apdu->a_Le);
+ break;
default:
/* unknown params returns (SW1=0x6A, SW2=0x86) */
*response = vcard_make_response(
VCARD7816_STATUS_ERROR_P1_P2_INCORRECT);
break;
}
+
ret = VCARD_DONE;
break;
case VCARD7816_INS_SELECT_FILE:
@@ -341,7 +363,7 @@ cac_common_process_apdu(VCard *card, VCardAPDU *apdu, VCardResponse **response)
break;
default:
*response = vcard_make_response(
- VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED);
+ VCARD7816_STATUS_ERROR_INS_CODE_INVALID);
ret = VCARD_DONE;
break;
}
@@ -489,6 +511,7 @@ cac_applet_pki_process_apdu(VCard *card, VCardAPDU *apdu,
if (apdu->a_p2 != 0) {
*response = vcard_make_response(
VCARD7816_STATUS_ERROR_P1_P2_INCORRECT);
+ ret = VCARD_DONE;
break;
}
size = apdu->a_Lc;
@@ -548,6 +571,7 @@ cac_applet_aca_process_apdu(VCard *card, VCardAPDU *apdu,
VCardStatus ret = VCARD_FAIL;
CACACAAppletData *aca_applet;
VCardAppletPrivate *applet_private;
+ int format;
applet_private = vcard_get_current_applet_private(card, apdu->a_channel);
assert(applet_private);
@@ -565,15 +589,23 @@ cac_applet_aca_process_apdu(VCard *card, VCardAPDU *apdu,
ret = VCARD_DONE;
break;
}
+
+ format = ((apdu->a_p1 & 0x40)
+ ? CAC_FORMAT_EXTENDED
+ : CAC_FORMAT_SIMPLETLV);
+
switch (apdu->a_p1) {
case 0x00:
+ case 0x40:
+ case 0x41: /* This one returns the same as 0x40 for some reason */
/* All ACR table entries are to be extracted */
if (apdu->a_Lc != 0) {
*response = vcard_make_response(
VCARD7816_STATUS_ERROR_DATA_INVALID);
break;
}
- *response = cac_aca_get_acr_response(card, apdu->a_Le, NULL);
+ *response = cac_aca_get_acr_response(card, apdu->a_Le, NULL,
+ format);
break;
case 0x01:
@@ -583,9 +615,14 @@ cac_applet_aca_process_apdu(VCard *card, VCardAPDU *apdu,
VCARD7816_STATUS_ERROR_DATA_INVALID);
break;
}
- *response = cac_aca_get_acr_response(card, apdu->a_Le, apdu->a_body);
+ *response = cac_aca_get_acr_response(card, apdu->a_Le,
+ apdu->a_body, format);
break;
+
case 0x10:
+ case 0x50:
+ case 0x51: /* returns the same as 0x50 for some reason */
+ case 0x52: /* returns the same as 0x50 for some reason */
/* All Applet/Object ACR table entries are to be extracted */
if (apdu->a_Lc != 0) {
*response = vcard_make_response(
@@ -593,7 +630,7 @@ cac_applet_aca_process_apdu(VCard *card, VCardAPDU *apdu,
break;
}
*response = cac_aca_get_applet_acr_response(card, apdu->a_Le,
- aca_applet->pki_applets, NULL, 0, NULL);
+ aca_applet->pki_applets, NULL, 0, NULL, format);
break;
case 0x11:
@@ -605,7 +642,8 @@ cac_applet_aca_process_apdu(VCard *card, VCardAPDU *apdu,
break;
}
*response = cac_aca_get_applet_acr_response(card, apdu->a_Le,
- aca_applet->pki_applets, apdu->a_body, apdu->a_Lc, NULL);
+ aca_applet->pki_applets, apdu->a_body, apdu->a_Lc, NULL,
+ format);
break;
case 0x12:
@@ -617,19 +655,22 @@ cac_applet_aca_process_apdu(VCard *card, VCardAPDU *apdu,
break;
}
*response = cac_aca_get_applet_acr_response(card, apdu->a_Le,
- aca_applet->pki_applets, NULL, 0, apdu->a_body);
+ aca_applet->pki_applets, NULL, 0, apdu->a_body, format);
break;
case 0x20:
+ case 0x60:
/* The Access Method Provider table is extracted. */
if (apdu->a_Lc != 0) {
*response = vcard_make_response(
VCARD7816_STATUS_ERROR_DATA_INVALID);
break;
}
- *response = cac_aca_get_amp_response(card, apdu->a_Le);
+ *response = cac_aca_get_amp_response(card, apdu->a_Le, format);
break;
+
case 0x21:
+ case 0x61:
/* The Service Applet table is extracted. */
if (apdu->a_Lc != 0) {
*response = vcard_make_response(
@@ -637,8 +678,9 @@ cac_applet_aca_process_apdu(VCard *card, VCardAPDU *apdu,
break;
}
*response = cac_aca_get_service_response(card, apdu->a_Le,
- aca_applet->pki_applets);
+ aca_applet->pki_applets, format);
break;
+
default:
*response = vcard_make_response(
VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED);
@@ -646,6 +688,15 @@ cac_applet_aca_process_apdu(VCard *card, VCardAPDU *apdu,
}
ret = VCARD_DONE;
break;
+ /* XXX unknown APDU from ActivClient after PIN verification */
+ case 0x5A:
+ /* ???
+ * 80 5A 00 00 00
+ * HW response: 90 00
+ */
+ *response = vcard_make_response(VCARD7816_STATUS_SUCCESS);
+ ret = VCARD_DONE;
+ break;
default:
ret = cac_common_process_apdu(card, apdu, response);
break;
@@ -721,7 +772,7 @@ cac_delete_pki_applet_private(VCardAppletPrivate *applet_private)
g_free(applet_private->val_buffer);
g_free(applet_private->coids);
/* this one is cloned so needs to be freed */
- simpletlv_free(applet_private->properties, applet_private->properties_len);
+ simpletlv_free(applet_private->properties, applet_private->long_properties_len);
if (pki_applet_data->key != NULL) {
vcard_emul_delete_key(pki_applet_data->key);
}
@@ -814,34 +865,65 @@ cac_new_pki_applet_private(int i, const unsigned char *cert,
* 10 Key length bytes /8
* 01 Private key initialized
* 01 Public key initialized
+ *
+ * Long Properties:
+ * PKI applet:
+ * 01 05 Applet Information
+ * 10 02 06 02 03
+ * 40 01 Number of objects
+ * 01
+ * 51 14 First PKI Object
+ * 41 02 Object ID
+ * 01 02
+ * 42 05 Buffer properties
+ * 00 1E 00 57 05
+ * 43 04 PKI Properties
+ * 06 10 01 00
+ * 26 01 ???
+ * 01
+ * 39 01
+ * 00
+ * 3A 07 ACA ???
+ * A0 00 00 00 79 03 00
*/
unsigned char object_id[] = "\x01\x00";
unsigned char buffer_properties[] = "\x00\x00\x00\x00\x00";
unsigned char pki_properties[] = "\x06\x10\x01\x01";
- static struct simpletlv_member pki_object[3] = {
+ unsigned char buffer_26[] = "\x01";
+ static struct simpletlv_member pki_object[] = {
{CAC_PROPERTIES_OBJECT_ID, 2, {/*.value = object_id*/},
SIMPLETLV_TYPE_LEAF},
{CAC_PROPERTIES_BUFFER_PROPERTIES, 5, {/*.value = buffer_properties*/},
SIMPLETLV_TYPE_LEAF},
{CAC_PROPERTIES_PKI_PROPERTIES, 4, {/*.value = pki_properties*/},
SIMPLETLV_TYPE_LEAF},
+ {0x26, 0x01, {/*.child = buffer_26*/}, SIMPLETLV_TYPE_LEAF},
};
unsigned char applet_information[] = "\x10\x02\x06\x02\x03";
unsigned char number_objects[] = "\x01";
+ unsigned char buffer_39[] = "\x00";
+ unsigned char aca_aid[] = "\xA0\x00\x00\x00\x79\x03\x00";
static struct simpletlv_member properties[] = {
{CAC_PROPERTIES_APPLET_INFORMATION, 5, {/*.value = applet_information*/},
SIMPLETLV_TYPE_LEAF},
{CAC_PROPERTIES_NUMBER_OBJECTS, 1, {/*.value = number_objects */},
SIMPLETLV_TYPE_LEAF},
- {CAC_PROPERTIES_PKI_OBJECT, 3, {/*.child = pki_object*/},
+ {CAC_PROPERTIES_PKI_OBJECT, 4, {/*.child = pki_object*/},
SIMPLETLV_TYPE_COMPOUND},
+ {0x39, 0x01, {/*.child = buffer_39*/}, SIMPLETLV_TYPE_LEAF},
+ {0x3A, 0x07, {/*.child = aca_aid*/}, SIMPLETLV_TYPE_LEAF},
};
size_t properties_len = sizeof(properties)/sizeof(struct simpletlv_member);
/* if this would be 1, the certificate would be compressed */
unsigned char certinfo[] = "\x00";
struct simpletlv_member buffer[] = {
- {CAC_PKI_TAG_CERTINFO, 1, {/*.value = certinfo*/}, SIMPLETLV_TYPE_LEAF},
- {CAC_PKI_TAG_CERTIFICATE, cert_len, {/*.value = cert*/}, SIMPLETLV_TYPE_LEAF},
+ {CAC_PKI_TAG_CERTINFO, 1, {/*.value = certinfo*/},
+ SIMPLETLV_TYPE_LEAF},
+ {CAC_PKI_TAG_CERTIFICATE, cert_len, {/*.value = cert*/},
+ SIMPLETLV_TYPE_LEAF},
+ {CAC_PKI_TAG_MSCUID, 0, {/*.value = NULL*/}, SIMPLETLV_TYPE_LEAF},
+ {CAC_PKI_TAG_ERROR_DETECTION_CODE, 0, {/*.value = NULL*/},
+ SIMPLETLV_TYPE_LEAF},
};
size_t buffer_len = sizeof(buffer)/sizeof(struct simpletlv_member);
@@ -865,6 +947,8 @@ cac_new_pki_applet_private(int i, const unsigned char *cert,
/* Tag+Len buffer */
buffer[0].value.value = certinfo;
buffer[1].value.value = (unsigned char *)cert;
+ buffer[2].value.value = NULL;
+ buffer[3].value.value = NULL;
/* Ex:
* 0A 00 Length of whole buffer
* 71 Tag: CertInfo
@@ -919,15 +1003,20 @@ cac_new_pki_applet_private(int i, const unsigned char *cert,
if (bits > 0)
pki_properties[1] = 0xff & (bits / 8 / 8);
pki_object[2].value.value = pki_properties;
+ pki_object[3].value.value = buffer_26;
/* Inject Applet Version */
properties[0].value.value = applet_information;
properties[1].value.value = number_objects;
properties[2].value.child = pki_object;
+ properties[3].value.value = buffer_39;
+ properties[4].value.value = aca_aid;
/* Clone the properties */
- applet_private->properties_len = properties_len;
- applet_private->properties = simpletlv_clone(properties, properties_len);
+ applet_private->properties_len = 3;
+ applet_private->long_properties_len = properties_len;
+ applet_private->properties = simpletlv_clone(properties,
+ applet_private->long_properties_len);
if (applet_private->properties == NULL) {
goto failure;
}
@@ -1326,36 +1415,38 @@ failure:
* 00
* 0E 00 4E 04
*
- * OID buffers:
- * :3000
+ * OID buffers (from NIST SP 800-73-4)
+ * :3000: Card Holder Unique Identifier
* Tag buffer:
* 0C 00
- * 30 19 SEIWG data
- * 34 10 ?? list of 0x30
- * 35 08 ?? 32 30 31 32 30 34 30 31
- * 3E FF 1A 06 ??
+ * 30 19 FASC
+ * 34 10 GUID
+ * 35 08 Expiration Date
+ * 3E FF 1A 06 Issuer Asymmetric Signature
* FE 00 Error detection code
* Value buffer:
* D4 F8 10 DA 08 26 6C 10 A2 04 E5 83 60 DA 01 0C
* 11 CE 66 62 84 38 10 93 E1 <-- SEIWG data
*
- * :6010
+ * :6010: Cardholder Fingerprints
* Tag buffer:
* 06 00
- * BC FF CF 04 ??
+ * BC FF CF 04 Fingerprint I & II
* FE 00 Error Detection Code
*
- * :6030
+ * :6030: Cardholder Facial Image
* Tag buffer:
* 06 00
- * BC FF A9 29 ??
+ * BC FF A9 29 Image for Visual Verification
* FE 00 Error Detection Code
*
- * :9000
+ * :9000: Security Object
* 08 00
- * BB FF 38 02 Some PKCS#7 signed block
- * BA 30 ???
+ * BB FF 38 02 Security Object
+ * BA 30 Mapping of DG to ContainerID
* FE 00 Error Detectionc Code
+ *
+ * we should do this as passthrough too
*/
@@ -1385,14 +1476,18 @@ cac_new_ccc_applet_private(int cert_count)
*/
static unsigned char object_id[] = "\xDB\x00";
static unsigned char buffer_properties[] = "\x00\x00\x00\x00\x00";
- static struct simpletlv_member tv_object[2] = {
+ static unsigned char buffer_26[] = "\x01";
+ static struct simpletlv_member tv_object[3] = {
{CAC_PROPERTIES_OBJECT_ID, 2, {/*.value = object_id*/},
SIMPLETLV_TYPE_LEAF},
{CAC_PROPERTIES_BUFFER_PROPERTIES, 5, {/*.value = buffer_properties*/},
SIMPLETLV_TYPE_LEAF},
+ {0x26, 0x01, {/*.value = buffer_26*/}, SIMPLETLV_TYPE_LEAF},
};
static unsigned char applet_information[] = "\x10\x02\x06\x02\x03";
static unsigned char number_objects[] = "\x01";
+ static unsigned char buffer_39[] = "\x00";
+ static unsigned char aca_aid[] = "\xA0\x00\x00\x00\x79\x03\x00";
static struct simpletlv_member properties[] = {
{CAC_PROPERTIES_APPLET_INFORMATION, 5, {/*.value = applet_information*/},
SIMPLETLV_TYPE_LEAF},
@@ -1400,6 +1495,8 @@ cac_new_ccc_applet_private(int cert_count)
SIMPLETLV_TYPE_LEAF},
{CAC_PROPERTIES_TV_OBJECT, 2, {/*.child = tv_object*/},
SIMPLETLV_TYPE_COMPOUND},
+ {0x39, 0x01, {/*.child = buffer_39*/}, SIMPLETLV_TYPE_LEAF},
+ {0x3A, 0x07, {/*.child = aca_aid*/}, SIMPLETLV_TYPE_LEAF},
};
size_t properties_len = sizeof(properties)/sizeof(struct simpletlv_member);
@@ -1445,6 +1542,8 @@ cac_new_ccc_applet_private(int cert_count)
*/
};
unsigned char pkcs15[] = "\x00";
+ /* NIST SP 800-73-4: The data model of the PIV Card Application shall
+ * be identified by data model number 0x10 */
unsigned char reg_data_model[] = "\x10";
unsigned char acr_table[] = "\x07\xA0\x00\x00\x00\x79\x03\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00";
@@ -1638,15 +1737,19 @@ cac_new_ccc_applet_private(int cert_count)
ushort2lebytes(&buffer_properties[1], applet_private->tag_buffer_len);
ushort2lebytes(&buffer_properties[3], applet_private->val_buffer_len);
tv_object[1].value.value = buffer_properties;
+ tv_object[2].value.value = buffer_26;
/* Inject Applet Version */
properties[0].value.value = applet_information;
properties[1].value.value = number_objects;
properties[2].value.child = tv_object;
+ properties[3].value.value = buffer_39;
+ properties[4].value.value = aca_aid;
/* Link the properties */
applet_private->properties = properties;
- applet_private->properties_len = properties_len;
+ applet_private->properties_len = 3;
+ applet_private->long_properties_len = properties_len;
return applet_private;
@@ -1701,14 +1804,87 @@ cac_new_aca_applet_private(int cert_count)
* 10 Applet family
* 02 06 02 02 Applet version
*/
+
+ /* 0x40 Long properties (?):
+ * 01 05 Applet Information
+ * 10 02 06 02 02
+ * 23 0C
+ * 20 11 00 00 00 00 00 00 00 00 00 58
+ * 2A 02
+ * 02 00
+ * 2B 05 RID ???
+ * A0 00 00 00 79
+ * 22 10
+ * 00 00 00 DA 01 B4 03 30 00 00 00 70 00 51 02 9D
+ * 2C 01
+ * 00
+ * 20 02
+ * 08 01
+ * 21 01
+ * 0F
+ * 32 04
+ * 03 03 03 03
+ * 30 01
+ * 08
+ * 31 04
+ * 06 08 00 00
+ * 24 01
+ * FF
+ * 25 02
+ * 01 00
+ * 26 01
+ * 01
+ */
+
static unsigned char applet_information[] = "\x10\x02\x06\x02\x02";
- static struct simpletlv_member properties[1] = {
+ static unsigned char buffer_23[] = "\x20\x11\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x58";
+ static unsigned char buffer_2A[] = "\x02\x00";
+ static unsigned char rid[] = "\xA0\x00\x00\x00\x79";
+ static unsigned char buffer_22[] = "\x00\x00\x00\xDA\x01\xB4\x03\x30\x00"
+ "\x00\x00\x70\x00\x51\x02\x9D";
+ static unsigned char buffer_2C[] = "\x00";
+ static unsigned char buffer_20[] = "\x08\x01";
+ static unsigned char buffer_21[] = "\x0F";
+ static unsigned char buffer_32[] = "\x03\x03\x03\x03";
+ static unsigned char buffer_30[] = "\x08";
+ static unsigned char buffer_31[] = "\x06\x08\x00\x00";
+ static unsigned char buffer_24[] = "\xFF";
+ static unsigned char buffer_25[] = "\x01\x00";
+ static unsigned char buffer_26[] = "\x01";
+ static struct simpletlv_member properties[] = {
{CAC_PROPERTIES_APPLET_INFORMATION, 5, {/*.value = applet_information*/},
SIMPLETLV_TYPE_LEAF},
+ {0x23, 0x0C, {/*.value = buffer_23*/}, SIMPLETLV_TYPE_LEAF},
+ {0x2A, 0x02, {/*.value = buffer_2A*/}, SIMPLETLV_TYPE_LEAF},
+ {0x2B, 0x05, {/*.value = rid*/}, SIMPLETLV_TYPE_LEAF},
+ {0x22, 0x10, {/*.value = buffer_22*/}, SIMPLETLV_TYPE_LEAF},
+ {0x2C, 0x01, {/*.value = buffer_2C*/}, SIMPLETLV_TYPE_LEAF},
+ {0x20, 0x02, {/*.value = buffer_20*/}, SIMPLETLV_TYPE_LEAF},
+ {0x21, 0x01, {/*.value = buffer_21*/}, SIMPLETLV_TYPE_LEAF},
+ {0x32, 0x04, {/*.value = buffer_32*/}, SIMPLETLV_TYPE_LEAF},
+ {0x30, 0x01, {/*.value = buffer_30*/}, SIMPLETLV_TYPE_LEAF},
+ {0x31, 0x04, {/*.value = buffer_31*/}, SIMPLETLV_TYPE_LEAF},
+ {0x24, 0x01, {/*.value = buffer_24*/}, SIMPLETLV_TYPE_LEAF},
+ {0x25, 0x02, {/*.value = buffer_25*/}, SIMPLETLV_TYPE_LEAF},
+ {0x26, 0x01, {/*.value = buffer_26*/}, SIMPLETLV_TYPE_LEAF},
};
/* Inject Applet Version into Applet information */
properties[0].value.value = applet_information;
+ properties[1].value.value = buffer_23;
+ properties[2].value.value = buffer_2A;
+ properties[3].value.value = rid;
+ properties[4].value.value = buffer_22;
+ properties[5].value.value = buffer_2C;
+ properties[6].value.value = buffer_20;
+ properties[7].value.value = buffer_21;
+ properties[8].value.value = buffer_32;
+ properties[9].value.value = buffer_30;
+ properties[10].value.value = buffer_31;
+ properties[11].value.value = buffer_24;
+ properties[12].value.value = buffer_25;
+ properties[13].value.value = buffer_26;
/* Create the private data structure */
applet_private = g_new0(VCardAppletPrivate, 1);
@@ -1725,6 +1901,7 @@ cac_new_aca_applet_private(int cert_count)
/* Link the properties */
applet_private->properties = properties;
applet_private->properties_len = 1;
+ applet_private->long_properties_len = 14;
aca_applet_data->pki_applets = cert_count;
@@ -1744,11 +1921,13 @@ cac_new_empty_applet_private(unsigned char objects[][2], unsigned int objects_le
unsigned char object_id[] = "\x00\x00";
unsigned char buffer_properties[] = "\x00\x00\x00\x00\x00";
+ static unsigned char buffer_26[] = "\x01";
static struct simpletlv_member tv_buffer[] = {
{CAC_PROPERTIES_OBJECT_ID, 2, {/*.value = object_id*/},
SIMPLETLV_TYPE_LEAF},
{CAC_PROPERTIES_BUFFER_PROPERTIES, 5, {/*.value = buffer_properties*/},
SIMPLETLV_TYPE_LEAF},
+ {0x26, 0x01, {/*.value = buffer_26*/}, SIMPLETLV_TYPE_LEAF},
};
unsigned char applet_information[] = "\x10\x02\x06\x02\x03";
unsigned char number_objects = 0;
@@ -1757,15 +1936,15 @@ cac_new_empty_applet_private(unsigned char objects[][2], unsigned int objects_le
SIMPLETLV_TYPE_LEAF},
{CAC_PROPERTIES_NUMBER_OBJECTS, 1, {/*.value = number_objects*/},
SIMPLETLV_TYPE_LEAF},
- {CAC_PROPERTIES_TV_OBJECT, 2, {.child = NULL},
+ {CAC_PROPERTIES_TV_OBJECT, 3, {.child = NULL},
SIMPLETLV_TYPE_COMPOUND},
- {CAC_PROPERTIES_TV_OBJECT, 2, {.child = NULL},
+ {CAC_PROPERTIES_TV_OBJECT, 3, {.child = NULL},
SIMPLETLV_TYPE_COMPOUND},
- {CAC_PROPERTIES_TV_OBJECT, 2, {.child = NULL},
+ {CAC_PROPERTIES_TV_OBJECT, 3, {.child = NULL},
SIMPLETLV_TYPE_COMPOUND},
- {CAC_PROPERTIES_TV_OBJECT, 2, {.child = NULL},
+ {CAC_PROPERTIES_TV_OBJECT, 3, {.child = NULL},
SIMPLETLV_TYPE_COMPOUND},
- {CAC_PROPERTIES_TV_OBJECT, 2, {.child = NULL},
+ {CAC_PROPERTIES_TV_OBJECT, 3, {.child = NULL},
SIMPLETLV_TYPE_COMPOUND},
};
unsigned properties_len = 2;
@@ -1786,9 +1965,10 @@ cac_new_empty_applet_private(unsigned char objects[][2], unsigned int objects_le
/* Inject Object ID */
tv_buffer[0].value.value = object_id;
tv_buffer[1].value.value = buffer_properties;
+ tv_buffer[2].value.value = buffer_26;
/* clone the object to the structure */
- properties[2+i].value.child = simpletlv_clone(tv_buffer, 2);
+ properties[2+i].value.child = simpletlv_clone(tv_buffer, 3);
if (properties[2+i].value.child == NULL)
goto failure;
@@ -1812,13 +1992,14 @@ cac_new_empty_applet_private(unsigned char objects[][2], unsigned int objects_le
/* Clone the properties */
applet_private->properties_len = properties_len;
+ applet_private->long_properties_len = properties_len; /*TODO*/
applet_private->properties = simpletlv_clone(properties, properties_len);
if (applet_private->properties == NULL)
goto failure;
/* clean up the allocated properties */
for (i = 0; i < number_objects; i++) {
- simpletlv_free(properties[2+i].value.child, 2);
+ simpletlv_free(properties[2+i].value.child, 3);
}
/* tag/value buffers */
@@ -1848,11 +2029,13 @@ cac_new_passthrough_applet_private(VCard *card, const char *label,
unsigned char object_id[] = "\x00\x00";
unsigned char buffer_properties[] = "\x00\x00\x00\x00\x00";
- static struct simpletlv_member tv_buffer[2] = {
+ static unsigned char buffer_26[] = "\x01";
+ static struct simpletlv_member tv_buffer[3] = {
{CAC_PROPERTIES_OBJECT_ID, 2, {/*.value = object_id*/},
SIMPLETLV_TYPE_LEAF},
{CAC_PROPERTIES_BUFFER_PROPERTIES, 5, {/*.value = buffer_properties*/},
SIMPLETLV_TYPE_LEAF},
+ {0x26, 0x01, {/*.value = buffer_26*/}, SIMPLETLV_TYPE_LEAF},
};
unsigned char applet_information[] = "\x10\x02\x06\x02\x03";
unsigned char number_objects[] = "\x01";
@@ -1861,7 +2044,7 @@ cac_new_passthrough_applet_private(VCard *card, const char *label,
SIMPLETLV_TYPE_LEAF},
{CAC_PROPERTIES_NUMBER_OBJECTS, 1, {/*.value = number_objects*/},
SIMPLETLV_TYPE_LEAF},
- {CAC_PROPERTIES_TV_OBJECT, 2, {/*.child = tv_buffer*/},
+ {CAC_PROPERTIES_TV_OBJECT, 3, {/*.child = tv_buffer*/},
SIMPLETLV_TYPE_COMPOUND},
};
@@ -1892,6 +2075,7 @@ cac_new_passthrough_applet_private(VCard *card, const char *label,
/* Inject Object ID */
tv_buffer[0].value.value = object_id;
tv_buffer[1].value.value = buffer_properties;
+ tv_buffer[2].value.value = buffer_26;
/* Inject Applet Version */
properties[0].value.value = applet_information;
@@ -1900,7 +2084,9 @@ cac_new_passthrough_applet_private(VCard *card, const char *label,
/* Clone the properties */
applet_private->properties_len = 3;
- applet_private->properties = simpletlv_clone(properties, 3);
+ applet_private->long_properties_len = 3; /*TODO*/
+ applet_private->properties = simpletlv_clone(properties,
+ applet_private->long_properties_len);
if (applet_private->properties == NULL)
goto failure;
diff --git a/src/cac.h b/src/cac.h
index ff8fa0e..db8af2f 100644
--- a/src/cac.h
+++ b/src/cac.h
@@ -1,5 +1,5 @@
/*
- * defines the entry point for the cac card. Only used by cac.c anc
+ * defines the entry point for the cac card. Only used by cac.c and
* vcard_emul_type.c
*
* This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
@@ -64,6 +64,10 @@
#define CAC_PROPERTIES_TV_OBJECT 0x50
#define CAC_PROPERTIES_PKI_OBJECT 0x51
+/* Buffer formats */
+#define CAC_FORMAT_SIMPLETLV 1
+#define CAC_FORMAT_EXTENDED 2
+
/*
* Initialize the cac card. This is the only public function in this file. All
diff --git a/tests/common.c b/tests/common.c
index ecd16c0..2f1e8ad 100644
--- a/tests/common.c
+++ b/tests/common.c
@@ -102,11 +102,11 @@ void get_properties_coid(VReader *reader, const unsigned char coid[2],
VReaderStatus status;
uint8_t pbRecvBuffer[APDUBufSize], *p, *p_end, *p2, *p2_end;
uint8_t get_properties[] = {
- /* Get properties */
+ /* Get properties [Le] */
0x80, 0x56, 0x01, 0x00, 0x00
};
uint8_t get_properties_tag[] = {
- /* Get properties [tag list] */
+ /* Get properties [tag list] [Le] */
0x80, 0x56, 0x02, 0x00, 0x02, 0x01, 0x01, 0x00
};
int verified_pki_properties = 0;
@@ -203,6 +203,11 @@ void get_properties_coid(VReader *reader, const unsigned char coid[2],
verified_pki_properties = 1;
break;
+ case 0x26:
+ g_assert_cmpint(vlen2, ==, 1);
+ g_assert_cmphex(p2[0], ==, 0x01);
+ break;
+
default:
g_debug("Unknown tag in object: 0x%02x", tag2);
g_assert_not_reached();
@@ -212,6 +217,16 @@ void get_properties_coid(VReader *reader, const unsigned char coid[2],
/* one more object processed */
num_objects++;
break;
+
+ case 0x39:
+ g_assert_cmpint(vlen, ==, 1);
+ g_assert_cmphex(p[0], ==, 0x00);
+ break;
+
+ case 0x3A:
+ g_assert_cmpint(vlen, ==, 7);
+ break;
+
default:
g_debug("Unknown tag in properties buffer: 0x%02x", tag);
g_assert_not_reached();
@@ -257,6 +272,32 @@ void get_properties_coid(VReader *reader, const unsigned char coid[2],
g_assert_cmpint(dwRecvLength, ==, 16); /* Two applet information buffers + status */
g_assert_cmpint(pbRecvBuffer[dwRecvLength-2], ==, VCARD7816_SW1_SUCCESS);
g_assert_cmpint(pbRecvBuffer[dwRecvLength-1], ==, 0x00);
+
+
+ /* Test the undocumented P1 = 0x40 */
+ dwRecvLength = APDUBufSize;
+ get_properties[2] = 0x40;
+ get_properties[4] = 0x00;
+ status = vreader_xfr_bytes(reader,
+ get_properties, sizeof(get_properties),
+ pbRecvBuffer, &dwRecvLength);
+ g_assert_cmpint(status, ==, VREADER_OK);
+ /* for too long Le, the cards return LE_ERROR with correct length to ask */
+ g_assert_cmpint(dwRecvLength, ==, 2);
+ g_assert_cmpint(pbRecvBuffer[0], ==, VCARD7816_SW1_LE_ERROR);
+ g_assert_cmpint(pbRecvBuffer[1], !=, 0x00);
+
+ /* Update the APDU to match Le field from response and resend */
+ get_properties[4] = pbRecvBuffer[1];
+ dwRecvLength = APDUBufSize;
+ status = vreader_xfr_bytes(reader,
+ get_properties, sizeof(get_properties),
+ pbRecvBuffer, &dwRecvLength);
+ g_assert_cmpint(status, ==, VREADER_OK);
+ g_assert_cmpint(dwRecvLength, >, 2);
+ g_assert_cmpint(pbRecvBuffer[dwRecvLength-2], ==, VCARD7816_SW1_SUCCESS);
+ g_assert_cmpint(pbRecvBuffer[dwRecvLength-1], ==, 0x00);
+
}
void get_properties(VReader *reader, int object_type)
diff --git a/tests/libcacard.c b/tests/libcacard.c
index b41a56c..b15cc70 100644
--- a/tests/libcacard.c
+++ b/tests/libcacard.c
@@ -388,6 +388,62 @@ static void get_acr(VReader *reader)
/* parse the response */
parse_acr(pbRecvBuffer, dwRecvLength);
+
+ /* Undocumented 0x40 returns ACR in different encoding */
+ get_acr[2] = 0x40;
+ dwRecvLength = APDUBufSize;
+ status = vreader_xfr_bytes(reader,
+ get_acr, sizeof(get_acr),
+ pbRecvBuffer, &dwRecvLength);
+ g_assert_cmpint(status, ==, VREADER_OK);
+ g_assert_cmpint(dwRecvLength, >, 2);
+ g_assert_cmphex(pbRecvBuffer[dwRecvLength-2], ==, VCARD7816_SW1_SUCCESS);
+ g_assert_cmphex(pbRecvBuffer[dwRecvLength-1], ==, 0x00);
+
+ /* parse the response */
+ //parse_acr(pbRecvBuffer, dwRecvLength);
+
+ /* Undocumented 0x50 returns Applet/Object ACR in different encoding */
+ get_acr[2] = 0x50;
+ dwRecvLength = APDUBufSize;
+ status = vreader_xfr_bytes(reader,
+ get_acr, sizeof(get_acr),
+ pbRecvBuffer, &dwRecvLength);
+ g_assert_cmpint(status, ==, VREADER_OK);
+ g_assert_cmpint(dwRecvLength, ==, 2);
+ g_assert_cmphex(pbRecvBuffer[dwRecvLength-2], ==, VCARD7816_SW1_RESPONSE_BYTES);
+ g_assert_cmphex(pbRecvBuffer[dwRecvLength-1], ==, 0x00);
+
+ /* parse the response */
+ //parse_acr(pbRecvBuffer, dwRecvLength);
+
+ /* Undocumented 0x60 returns AMP in different encoding */
+ get_acr[2] = 0x60;
+ dwRecvLength = APDUBufSize;
+ status = vreader_xfr_bytes(reader,
+ get_acr, sizeof(get_acr),
+ pbRecvBuffer, &dwRecvLength);
+ g_assert_cmpint(status, ==, VREADER_OK);
+ g_assert_cmpint(dwRecvLength, >, 2);
+ g_assert_cmphex(pbRecvBuffer[dwRecvLength-2], ==, VCARD7816_SW1_SUCCESS);
+ g_assert_cmphex(pbRecvBuffer[dwRecvLength-1], ==, 0x00);
+
+ /* parse the response */
+ //parse_acr(pbRecvBuffer, dwRecvLength);
+
+ /* Undocumented 0x61 returns Service Applet in different encoding */
+ get_acr[2] = 0x61;
+ dwRecvLength = APDUBufSize;
+ status = vreader_xfr_bytes(reader,
+ get_acr, sizeof(get_acr),
+ pbRecvBuffer, &dwRecvLength);
+ g_assert_cmpint(status, ==, VREADER_OK);
+ g_assert_cmpint(dwRecvLength, >, 2);
+ g_assert_cmphex(pbRecvBuffer[dwRecvLength-2], ==, VCARD7816_SW1_SUCCESS);
+ g_assert_cmphex(pbRecvBuffer[dwRecvLength-1], ==, 0x00);
+
+ /* parse the response */
+ //parse_acr(pbRecvBuffer, dwRecvLength);
}
static void do_login(VReader *reader)
--
2.17.1
More information about the Spice-devel
mailing list