[Spice-devel] [PATCH libcacard v2 05/35] Card Manager Applet
Jakub Jelen
jjelen at redhat.com
Thu Aug 2 09:43:37 UTC 2018
* The card manager applet from Global Platform is common in
Java Cards.
* This commit fixes its location and implement appropriate
responses to APDUs in separate independent file which can
be used in other cards in future.
* The responses to SELECT APDU are still handled in
the generic ISO 7816 code, but the responses are improved.
* This affects also the existing testsuite, which needs
adjustments, since the SELECT APDU retunrs different data.
* This loads the GP applet separately from CAC applet
Signed-off-by: Jakub Jelen <jjelen at redhat.com>
Reviewed-by: Robert Relyea <rrelyea at redhat.com>
---
Makefile.am | 2 +
docs/libcacard.txt | 1 +
src/cac.c | 41 +++--------------
src/card_7816.c | 59 +++++++++++++++++++++---
src/gp.c | 102 ++++++++++++++++++++++++++++++++++++++++++
src/gp.h | 30 +++++++++++++
src/vcard_emul_type.c | 11 ++++-
tests/libcacard.c | 10 ++---
8 files changed, 207 insertions(+), 49 deletions(-)
create mode 100644 src/gp.c
create mode 100644 src/gp.h
diff --git a/Makefile.am b/Makefile.am
index 2074947..8cf4c4d 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -5,6 +5,8 @@ lib_LTLIBRARIES = libcacard.la
libcacard_la_SOURCES = \
src/cac.c \
+ src/gp.c \
+ src/gp.h \
src/capcsc.h \
src/card_7816.c \
src/common.c \
diff --git a/docs/libcacard.txt b/docs/libcacard.txt
index f6cd46c..964882d 100644
--- a/docs/libcacard.txt
+++ b/docs/libcacard.txt
@@ -479,6 +479,7 @@ src/vreadert.h - comon virtual reader types.
src/vcard_emul_type.c - manage the card type emulators.
src/vcard_emul_type.h - definitions for card type emulators.
src/cac.c - card type emulator for CAC cards
+src/gp.c - basic Global Platform card manager emulation
src/vcard_emul.h - virtual card emulator service definitions.
src/vcard_emul_nss.c - virtual card emulator implementation for nss.
src/vscclient.c - socket connection to guest qemu usb driver.
diff --git a/src/cac.c b/src/cac.c
index 126e109..ec88cc3 100644
--- a/src/cac.c
+++ b/src/cac.c
@@ -248,6 +248,9 @@ cac_common_process_apdu(VCard *card, VCardAPDU *apdu, VCardResponse **response)
ret = VCARD_NEXT;
break;
}
+
+ assert(applet_private);
+
/* handle file id setting */
if (apdu->a_Lc != 2) {
*response = vcard_make_response(
@@ -457,32 +460,6 @@ cac_applet_pki_process_apdu(VCard *card, VCardAPDU *apdu,
return ret;
}
-static VCardStatus
-cac_applet_id_process_apdu(VCard *card, VCardAPDU *apdu,
- VCardResponse **response)
-{
- VCardStatus ret = VCARD_FAIL;
-
- switch (apdu->a_ins) {
- case CAC_UPDATE_BUFFER:
- *response = vcard_make_response(
- VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED);
- ret = VCARD_DONE;
- break;
- case CAC_READ_BUFFER:
- /* new CAC call, go ahead and use the old version for now */
- /* TODO: implement */
- *response = vcard_make_response(
- VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED);
- ret = VCARD_DONE;
- break;
- default:
- ret = cac_common_process_apdu(card, apdu, response);
- break;
- }
- return ret;
-}
-
/*
* utilities for creating and destroying the private applet data
*/
@@ -1014,8 +991,6 @@ failure:
}
-static unsigned char cac_id_aid[] = {
- 0xa0, 0x00, 0x00, 0x00, 0x79, 0x03, 0x00 };
/*
* Initialize the cac card. This is the only public function in this file. All
* the rest are connected through function pointers.
@@ -1052,14 +1027,8 @@ cac_card_init(VReader *reader, VCard *card,
}
vcard_add_applet(card, applet);
- /* create a default blank container applet */
- applet = vcard_new_applet(cac_applet_id_process_apdu,
- NULL, cac_id_aid,
- sizeof(cac_id_aid));
- if (applet == NULL) {
- goto failure;
- }
- vcard_add_applet(card, applet);
+ /* GP applet is created from vcard_emul_type() */
+
return VCARD_DONE;
failure:
diff --git a/src/card_7816.c b/src/card_7816.c
index 371150f..58bdda8 100644
--- a/src/card_7816.c
+++ b/src/card_7816.c
@@ -13,6 +13,18 @@
#include "vcard_emul.h"
#include "card_7816.h"
+
+/* Global Platform Card Manager applet AID */
+static unsigned char gp_aid[] = {
+ 0xa0, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00 };
+/* Global Platfrom Card Manager response on select applet */
+static unsigned char gp_response[] = {
+ 0x6F, 0x19, 0x84, 0x08, 0xA0, 0x00, 0x00, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0xA5, 0x0D, 0x9F, 0x6E,
+ 0x06, 0x12, 0x91, 0x51, 0x81, 0x01, 0x00, 0x9F,
+ 0x65, 0x01, 0xFF};
+
+
/*
* set the status bytes based on the status word
*/
@@ -95,6 +107,7 @@ vcard_response_new(VCard *card, unsigned char *buf,
{
VCardResponse *new_response;
+ g_debug("%s: Sending response (len = %d, Le = %d)", __func__, len, Le);
if (len > Le) {
return vcard_init_buffer_response(card, buf, len);
}
@@ -115,6 +128,7 @@ vcard_response_new_bytes(VCard *card, unsigned char *buf, int len, int Le,
{
VCardResponse *new_response;
+ g_debug("%s: Sending response (len = %d, Le = %d)", __func__, len, Le);
if (len > Le) {
return vcard_init_buffer_response(card, buf, len);
}
@@ -615,6 +629,7 @@ vcard7816_vm_process_apdu(VCard *card, VCardAPDU *apdu,
break;
case VCARD7816_INS_SELECT_FILE:
+ /* GSC-IS: 5.3.3.2 Select Applet APDU: P1 = 0x04 */
if (apdu->a_p1 != 0x04) {
*response = vcard_make_response(
VCARD7816_STATUS_ERROR_FUNCTION_NOT_SUPPORTED);
@@ -622,16 +637,48 @@ vcard7816_vm_process_apdu(VCard *card, VCardAPDU *apdu,
}
/* side effect, deselect the current applet if no applet has been found
- * */
+ */
current_applet = vcard_find_applet(card, apdu->a_body, apdu->a_Lc);
vcard_select_applet(card, apdu->a_channel, current_applet);
if (current_applet) {
- unsigned char *aid;
- int aid_len;
- aid = vcard_applet_get_aid(current_applet, &aid_len);
- *response = vcard_response_new(card, aid, aid_len, apdu->a_Le,
- VCARD7816_STATUS_SUCCESS);
+ VCardApplet *gp_applet = vcard_find_applet(card,
+ gp_aid, sizeof(gp_aid));
+ if (current_applet == gp_applet) {
+ /* if the new applet is Global Platform Card Manager, we need to
+ * return a response (from Card Specification v2.3.1):
+ *
+ * 6F 19 : FCI Template
+ * 84 08 : Application / file AID
+ * A0 00 00 00 03 00 00 00
+ * A5 0D : Proprietary data
+ * 9F 6E 06 : Application Producution Life Cycle
+ * 12 91 51 81 01 00
+ * 9F 65 01 : Maximum Length of data field in comand message
+ * FF
+ */
+ *response = vcard_response_new(card, gp_response,
+ sizeof(gp_response), apdu->a_Le, VCARD7816_STATUS_SUCCESS);
+ } else {
+ static unsigned char fci_template[] = {
+ 0x6F, 0x0B, 0x84, 0x07, 0xA0, 0x00, 0x00, 0x00,
+ 0x79, 0x03, 0x00, 0xA5, 0x00};
+ /* with GSC-IS 2 applets, we do not need to return anything
+ * for select applet, but cards generally do, at least this
+ * FCI template stub:
+ *
+ * 6F 0B : FCI Template
+ * 84 07 : Application / file AID
+ * A0 00 00 00 79 03 00
+ * A5 00 : Porprietary data
+ */
+ /* Insert the correct AID in the structure */
+ g_assert_cmpint(apdu->a_Lc, ==, 7);
+ memcpy(&fci_template[4], apdu->a_body, apdu->a_Lc);
+ *response = vcard_response_new(card, fci_template,
+ sizeof(fci_template), apdu->a_Le, VCARD7816_STATUS_SUCCESS);
+ }
} else {
+ /* the real CAC returns (SW1=0x6A, SW2=0x82) */
*response = vcard_make_response(
VCARD7816_STATUS_ERROR_FILE_NOT_FOUND);
}
diff --git a/src/gp.c b/src/gp.c
new file mode 100644
index 0000000..a4233cc
--- /dev/null
+++ b/src/gp.c
@@ -0,0 +1,102 @@
+/*
+ * defines the entry point for the Global Plarform Applet emulation. Only used
+ * by vcard_emul_type.c
+ *
+ * Copyright 2018 Red Hat, Inc.
+ *
+ * Author: Jakub Jelen <jjelen at redhat.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "glib-compat.h"
+
+#include <string.h>
+#include <stdio.h>
+#include <stdbool.h>
+
+#include "gp.h"
+#include "vcard.h"
+#include "vcard_emul.h"
+#include "card_7816.h"
+
+static unsigned char gp_container_aid[] = {
+ 0xa0, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00 };
+
+/* Data returned for Get Data Instruction */
+static unsigned char gp_get_data[] = {
+ 0x9F, 0x7F, 0x2A, 0x40, 0x70, 0x50, 0x72, 0x12,
+ 0x91, 0x51, 0x81, 0x01, 0x00, 0x70, 0x70, 0x00,
+ 0x00, 0x58, 0xBD, 0x36, 0x0E, 0x40, 0x82, 0x70,
+ 0x90, 0x12, 0x93, 0x70, 0x90, 0x04, 0x44, 0x72,
+ 0x00, 0x00, 0x01, 0x00, 0x40, 0x04, 0x45, 0x84,
+ 0x00, 0x00, 0x2C, 0x19, 0xB5
+};
+
+static VCardStatus
+gp_applet_container_process_apdu(VCard *card, VCardAPDU *apdu,
+ VCardResponse **response)
+{
+ VCardStatus ret = VCARD_FAIL;
+ unsigned int tag;
+
+ switch (apdu->a_ins) {
+ case GP_GET_DATA:
+ /* GET DATA isntruction for tags:
+ * 00 66 (not found):
+ * 9F 7F (len = 2D):
+ * 9F 7F 2A 40 70 50 72 12 91 51 81 01 00 70 70 00
+ * 00 58 BD 36 0E 40 82 70 90 12 93 70 90 04 44 72
+ * 00 00 01 00 40 04 45 84 00 00 2C 19 B5
+ */
+ tag = (apdu->a_p1 & 0xff) << 8 | (apdu->a_p2 & 0xff);
+ if (tag == 0x9f7f) {
+ *response = vcard_response_new(card, gp_get_data,
+ sizeof(gp_get_data), apdu->a_Le, VCARD7816_STATUS_SUCCESS);
+ ret = VCARD_DONE;
+ break;
+ }
+ *response = vcard_make_response(VCARD7816_STATUS_ERROR_DATA_NOT_FOUND);
+ ret = VCARD_DONE;
+ break;
+
+ default:
+ /* Let the ISO 7816 code to handle other APDUs */
+ ret = VCARD_NEXT;
+ break;
+ }
+ return ret;
+}
+
+
+/*
+ * Initialize the cac card. This is the only public function in this file. All
+ * the rest are connected through function pointers.
+ */
+VCardStatus
+gp_card_init(VReader *reader, VCard *card,
+ const char *params,
+ unsigned char * const *cert,
+ int cert_len[],
+ VCardKey *key[] /* adopt the keys*/,
+ int cert_count)
+{
+ VCardApplet *applet;
+
+ /* create Card Manager container */
+ applet = vcard_new_applet(gp_applet_container_process_apdu,
+ NULL, gp_container_aid,
+ sizeof(gp_container_aid));
+ if (applet == NULL) {
+ goto failure;
+ }
+ vcard_add_applet(card, applet);
+
+ return VCARD_DONE;
+
+failure:
+ return VCARD_FAIL;
+}
+
+/* vim: set ts=4 sw=4 tw=0 noet expandtab: */
diff --git a/src/gp.h b/src/gp.h
new file mode 100644
index 0000000..7f68e47
--- /dev/null
+++ b/src/gp.h
@@ -0,0 +1,30 @@
+/*
+ * defines the entry point for the Global Plarform Applet emulation. Only used
+ * by vcard_emul_type.c
+ *
+ * Copyright 2018 Red Hat, Inc.
+ *
+ * Author: Jakub Jelen <jjelen at redhat.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING file in the top-level directory.
+ */
+#ifndef GP_H
+#define GP_H 1
+
+#include "vcard.h"
+#include "vreader.h"
+
+#define GP_GET_DATA 0xCA
+
+/*
+ * Initialize the Global Platform Applet. This is the only public function in
+ * this file. All the rest are connected through function pointers.
+ */
+VCardStatus
+gp_card_init(VReader *reader, VCard *card, const char *params,
+ unsigned char * const *cert, int cert_len[],
+ VCardKey *key[] /* adopt the keys*/, int cert_count);
+
+
+#endif
diff --git a/src/vcard_emul_type.c b/src/vcard_emul_type.c
index 44cc305..d818fe7 100644
--- a/src/vcard_emul_type.c
+++ b/src/vcard_emul_type.c
@@ -13,6 +13,7 @@
#include "vcardt.h"
#include "vcard_emul_type.h"
#include "cac.h"
+#include "gp.h"
#include "glib-compat.h"
VCardStatus vcard_init(VReader *vreader, VCard *vcard,
@@ -20,12 +21,18 @@ VCardStatus vcard_init(VReader *vreader, VCard *vcard,
unsigned char *const *cert, int cert_len[],
VCardKey *key[], int cert_count)
{
+ int rv;
+
switch (type) {
case VCARD_EMUL_NONE:
break;
case VCARD_EMUL_CAC:
- return cac_card_init(vreader, vcard, params,
- cert, cert_len, key, cert_count);
+ rv = cac_card_init(vreader, vcard, params,
+ cert, cert_len, key, cert_count);
+ if (rv == VCARD_DONE)
+ rv = gp_card_init(vreader, vcard, params,
+ cert, cert_len, key, cert_count);
+ return rv;
/* add new ones here */
case VCARD_EMUL_PASSTHRU:
default:
diff --git a/tests/libcacard.c b/tests/libcacard.c
index 9dfe974..ccb3188 100644
--- a/tests/libcacard.c
+++ b/tests/libcacard.c
@@ -151,7 +151,7 @@ static void test_cac(void)
0x00, 0xa4, 0x04, 0x00, 0x07, 0xa0, 0x00, 0x00, 0x00, 0x79, 0x01, 0x00
};
uint8_t getresp[] = {
- 0x00, 0xc0, 0x00, 0x00, 0x07
+ 0x00, 0xc0, 0x00, 0x00, 0x0d
};
g_assert_nonnull(reader);
@@ -160,16 +160,16 @@ static void test_cac(void)
pbRecvBuffer, &dwRecvLength);
g_assert_cmpint(status, ==, VREADER_OK);
g_assert_cmphex(pbRecvBuffer[0], ==, VCARD7816_SW1_RESPONSE_BYTES);
- g_assert_cmphex(pbRecvBuffer[1], ==, 0x7);
+ g_assert_cmphex(pbRecvBuffer[1], ==, 0x0d);
dwRecvLength = APDUBufSize;
status = vreader_xfr_bytes(reader,
getresp, sizeof(getresp),
pbRecvBuffer, &dwRecvLength);
g_assert_cmpint(status, ==, VREADER_OK);
- g_assert_cmpint(dwRecvLength, ==, 9);
- g_assert_cmphex(pbRecvBuffer[7], ==, VCARD7816_SW1_SUCCESS);
- g_assert_cmphex(pbRecvBuffer[8], ==, 0x0);
+ g_assert_cmpint(dwRecvLength, ==, 15);
+ g_assert_cmphex(pbRecvBuffer[dwRecvLength-2], ==, VCARD7816_SW1_SUCCESS);
+ g_assert_cmphex(pbRecvBuffer[dwRecvLength-1], ==, 0x0);
/* The old way of reading certificate does not work anymore */
--
2.17.1
More information about the Spice-devel
mailing list