* 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@xxxxxxxxxx> Reviewed-by: Robert Relyea <rrelyea@xxxxxxxxxx> --- 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@xxxxxxxxxx> + * + * 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@xxxxxxxxxx> + * + * 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 _______________________________________________ Spice-devel mailing list Spice-devel@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/spice-devel