[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