[Spice-devel] [PATCH libcacard 10/45] CCC Applet implementation
Jakub Jelen
jjelen at redhat.com
Tue Jul 31 14:50:04 UTC 2018
* The Card Capability Container (CCC) is mandatory applet of CAC 2
and is used to discover other applets, card capabilities and
properties
Signed-off-by: Jakub Jelen <jjelen at redhat.com>
Reviewed-by: Robert Relyea <rrelyea at redhat.com>
---
src/cac.c | 359 +++++++++++++++++++++++++++++++++++++++++++++++++-----
src/cac.h | 15 +++
2 files changed, 343 insertions(+), 31 deletions(-)
diff --git a/src/cac.c b/src/cac.c
index 4fa84e3..86ccc99 100644
--- a/src/cac.c
+++ b/src/cac.c
@@ -20,6 +20,10 @@
#include "simpletlv.h"
#include "common.h"
+static unsigned char cac_ccc_aid[] = {
+ 0xa0, 0x00, 0x00, 0x01, 0x16, 0xDB, 0x00 };
+
+
/* private data for PKI applets */
typedef struct CACPKIAppletDataStruct {
unsigned char *sign_buffer;
@@ -27,6 +31,10 @@ typedef struct CACPKIAppletDataStruct {
VCardKey *key;
} CACPKIAppletData;
+/* private data for CCC container */
+typedef struct CACCCCAppletDataStruct {
+} CACCCCAppletData;
+
/*
* CAC applet private data
*/
@@ -41,6 +49,7 @@ struct VCardAppletPrivateStruct {
/* applet-specific */
union {
CACPKIAppletData pki_data;
+ CACCCCAppletData ccc_data;
void *reserved;
} u;
};
@@ -474,31 +483,6 @@ cac_applet_id_process_apdu(VCard *card, VCardAPDU *apdu,
return ret;
}
-
-/*
- * TODO: if we ever want to support general CAC middleware, we will need to
- * implement the various containers.
- */
-static VCardStatus
-cac_applet_container_process_apdu(VCard *card, VCardAPDU *apdu,
- VCardResponse **response)
-{
- VCardStatus ret = VCARD_FAIL;
-
- switch (apdu->a_ins) {
- case CAC_READ_BUFFER:
- case CAC_UPDATE_BUFFER:
- *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
*/
@@ -522,6 +506,17 @@ cac_delete_pki_applet_private(VCardAppletPrivate *applet_private)
g_free(applet_private);
}
+static void
+cac_delete_ccc_applet_private(VCardAppletPrivate *applet_private)
+{
+ if (applet_private == NULL) {
+ return;
+ }
+ g_free(applet_private->tag_buffer);
+ g_free(applet_private->val_buffer);
+ g_free(applet_private);
+}
+
static VCardAppletPrivate *
cac_new_pki_applet_private(int i, const unsigned char *cert,
int cert_len, VCardKey *key)
@@ -669,6 +664,310 @@ failure:
}
+static VCardAppletPrivate *
+cac_new_ccc_applet_private(int cert_count)
+{
+ VCardAppletPrivate *applet_private;
+
+ /* CCC applet Properties ex.:
+ * 01 Tag: Applet Information
+ * 05 Length
+ * 10 Applet family
+ * 02 06 02 03 Applet version
+ * 40 Tag: Number of objects managed by this instance
+ * 01 Length
+ * 01 One
+ * 50 Tag: First TV-Buffer Object
+ * 0B Length
+ * 41 Tag: ObjectID
+ * 02 Length
+ * DB 00
+ * 42 Tag: Buffer Properties
+ * 05 Length
+ * 00 Type of Tag Supported
+ * F6 00 T-Buffer length (LSB, MSB)
+ * 04 02 V-Buffer length (LSB, MSB)
+ */
+ static unsigned char object_id[] = "\xDB\x00";
+ static unsigned char buffer_properties[] = "\x00\x00\x00\x00\x00";
+ static struct simpletlv_member tv_object[2] = {
+ {CAC_PROPERTIES_OBJECT_ID, 2, {/*.value = object_id*/},
+ SIMPLETLV_TYPE_LEAF},
+ {CAC_PROPERTIES_BUFFER_PROPERTIES, 5, {/*.value = buffer_properties*/},
+ SIMPLETLV_TYPE_LEAF},
+ };
+ static unsigned char applet_information[] = "\x10\x02\x06\x02\x03";
+ static unsigned char number_objects[] = "\x01";
+ static struct simpletlv_member properties[4] = {
+ {CAC_PROPERTIES_APPLET_INFORMATION, 5, {/*.value = applet_information*/},
+ SIMPLETLV_TYPE_LEAF},
+ {CAC_PROPERTIES_NUMBER_OBJECTS, 1, {/*.value = number_objects */},
+ SIMPLETLV_TYPE_LEAF},
+ {CAC_PROPERTIES_TV_OBJECT, 2, {/*.child = tv_object*/},
+ SIMPLETLV_TYPE_COMPOUND},
+ };
+
+ unsigned char card_identifier[] = "\xA0\x00\x00\x00\x79\x03\x02\x40\x70\x50"
+ "\x72\x36\x0E\x00\x00\x58\xBD\x00\x2C\x19\xB5";
+ unsigned char cc_version[] = "\x21";
+ unsigned char cg_version[] = "\x21";
+ unsigned char pki_cardurl[] =
+ "\xA0\x00\x00\x00\x79\x04\x01\x00\x01\x00\x00\x00\x00\x00\x00\x00";
+ unsigned char cardurl[14][16] = {
+ "\xA0\x00\x00\x01\x16\x01\x30\x00\x30\x00\x00\x00\x00\x00\x00\x00", /* ACA */
+ "\xA0\x00\x00\x00\x79\x01\x02\xFB\x02\xFB\x00\x00\x00\x00\x00\x00", /* ??? */
+ "\xA0\x00\x00\x00\x79\x01\x02\xFE\x02\xFE\x00\x00\x00\x00\x00\x00", /* PKI Certificate */
+ "\xA0\x00\x00\x00\x79\x01\x02\xFD\x02\xFD\x00\x00\x00\x00\x00\x00", /* PKI Credential */
+ "\xA0\x00\x00\x00\x79\x01\x02\x00\x02\x00\x00\x00\x00\x00\x00\x00", /* Person Instance */
+ "\xA0\x00\x00\x00\x79\x01\x02\x01\x02\x01\x00\x00\x00\x00\x00\x00", /* Personel */
+ "\xA0\x00\x00\x00\x79\x04\x01\x00\x01\x00\x00\x00\x00\x00\x00\x00", /* PKI */
+ "\xA0\x00\x00\x00\x79\x04\x01\x01\x01\x01\x00\x00\x00\x00\x00\x00", /* PKI */
+ "\xA0\x00\x00\x00\x79\x04\x01\x02\x01\x02\x00\x00\x00\x00\x00\x00", /* PKI */
+ "\xA0\x00\x00\x01\x16\x01\x60\x10\x30\x00\x00\x00\x00\x00\x00\x00", /* ?? AID=ACA ?? */
+ "\xA0\x00\x00\x01\x16\x01\x60\x30\x30\x00\x00\x00\x00\x00\x00\x00", /* ?? AID=ACA ?? */
+ "\xA0\x00\x00\x01\x16\x01\x90\x00\x30\x00\x00\x00\x00\x00\x00\x00", /* ?? AID=ACA ?? */
+ "\xA0\x00\x00\x00\x79\x01\x12\x01\x12\x01\x00\x00\x00\x00\x00\x00", /* ?? */
+ "\xA0\x00\x00\x00\x79\x01\x12\x02\x12\x02\x00\x00\x00\x00\x00\x00", /* ?? */
+ /*
+ * [ Empty for VM cards! ]
+ * [ RID 5B ][T ][ OID ][ AID ] [ P][AccessKeyInfo ][ K]
+ * CardApplicationType-^ ^ ^- Pin ID ^
+ * AccessProfile is empty --------------' |
+ * Key Crypto Algorithm ---------------------------------------'
+ *
+ * AID -- the "address" of the container
+ * Object ID = object type
+ *
+ * 7.3 The Applications CardURL
+ */
+ };
+ unsigned char pkcs15[] = "\x00";
+ 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";
+ static struct simpletlv_member buffer[26] = {
+ {CAC_CCC_CARD_IDENTIFIER, 0x15, {/*.value = card_identifier*/},
+ SIMPLETLV_TYPE_LEAF},
+ {CAC_CCC_CAPABILITY_CONTAINER_VERSION, 1, {/*.value = cc_version*/},
+ SIMPLETLV_TYPE_LEAF},
+ {CAC_CCC_CAPABILITY_GRAMMAR_VERSION, 1, {/*.value = cg_version*/},
+ SIMPLETLV_TYPE_LEAF},
+ {CAC_CCC_APPLICATION_CARDURL, 16, {/*.value = cardurl[0]*/},
+ SIMPLETLV_TYPE_LEAF},
+ {CAC_CCC_APPLICATION_CARDURL, 16, {/*.value = cardurl[1]*/},
+ SIMPLETLV_TYPE_NONE},
+ {CAC_CCC_APPLICATION_CARDURL, 16, {/*.value = cardurl[2]*/},
+ SIMPLETLV_TYPE_NONE},
+ {CAC_CCC_APPLICATION_CARDURL, 16, {/*.value = cardurl[3]*/},
+ SIMPLETLV_TYPE_NONE},
+ {CAC_CCC_APPLICATION_CARDURL, 16, {/*.value = cardurl[4]*/},
+ SIMPLETLV_TYPE_NONE},
+ {CAC_CCC_APPLICATION_CARDURL, 16, {/*.value = cardurl[5]*/},
+ SIMPLETLV_TYPE_NONE},
+ {CAC_CCC_APPLICATION_CARDURL, 16, {/*.value = cardurl[6]*/},
+ SIMPLETLV_TYPE_NONE},
+ {CAC_CCC_APPLICATION_CARDURL, 16, {/*.value = cardurl[7]*/},
+ SIMPLETLV_TYPE_NONE},
+ {CAC_CCC_APPLICATION_CARDURL, 16, {/*.value = cardurl[8]*/},
+ SIMPLETLV_TYPE_NONE},
+ {CAC_CCC_APPLICATION_CARDURL, 16, {/*.value = cardurl[9]*/},
+ SIMPLETLV_TYPE_NONE},
+ {CAC_CCC_APPLICATION_CARDURL, 16, {/*.value = cardurl[10]*/},
+ SIMPLETLV_TYPE_NONE},
+ {CAC_CCC_APPLICATION_CARDURL, 16, {/*.value = cardurl[11]*/},
+ SIMPLETLV_TYPE_NONE},
+ {CAC_CCC_APPLICATION_CARDURL, 16, {/*.value = cardurl[12]*/},
+ SIMPLETLV_TYPE_NONE},
+ {CAC_CCC_APPLICATION_CARDURL, 16, {/*.value = cardurl[13]*/},
+ SIMPLETLV_TYPE_NONE},
+ {CAC_CCC_PKCS15, 1, {/*.value = pkcs15 */},
+ SIMPLETLV_TYPE_LEAF},
+ {CAC_CCC_REGISTERED_DATA_MODEL_NUMBER, 1, {/*.value = reg_data_model */},
+ SIMPLETLV_TYPE_LEAF},
+ {CAC_CCC_ACCESS_CONTROL_RULE_TABLE, 17, {/*.value = acr_table */},
+ SIMPLETLV_TYPE_LEAF},
+ {CAC_CCC_CARD_APDUS, 0, {}, SIMPLETLV_TYPE_LEAF},
+ {CAC_CCC_REDIRECTION_TAG, 0, {}, SIMPLETLV_TYPE_LEAF},
+ {CAC_CCC_CAPABILITY_TUPLES, 0, {}, SIMPLETLV_TYPE_LEAF},
+ {CAC_CCC_STATUS_TUPLES, 0, {}, SIMPLETLV_TYPE_LEAF},
+ {CAC_CCC_NEXT_CCC, 0, {}, SIMPLETLV_TYPE_LEAF},
+ {CAC_CCC_ERROR_DETECTION_CODE, 0, {}, SIMPLETLV_TYPE_LEAF},
+ };
+ int i;
+
+ applet_private = g_new0(VCardAppletPrivate, 1);
+
+ /* prepare the buffers to when READ_BUFFER will be called.
+ * Assuming VM card with (LSB first if > 255)
+ * separate Tag+Length, Value buffers as described in 8.4:
+ * 2 B 1 B 1-3 B 1 B 1-3 B
+ * [ T-Len ] [ Tag1 ] [ Len1 ] [ Tag2] [ Len2 ] [...]
+ *
+ * 2 B Len1 B Len2 B
+ * [ V-Len ] [ Value 1 ] [ Value 2 ] [...]
+ * */
+
+ buffer[0].value.value = card_identifier;
+ buffer[1].value.value = cc_version;
+ buffer[2].value.value = cg_version;
+ buffer[3].value.value = cardurl[0]; /* ACA */
+
+ if (cert_count > 13) {
+ // XXX too many objects for now
+ g_debug("Too many PKI objects");
+ return NULL;
+ }
+ /* Generate card URLs for PKI applets */
+ for (i = 0; i < cert_count; i++) {
+ memcpy(cardurl[i+1], pki_cardurl, 16);
+ cardurl[i+1][8] = i; /* adjust OID and AID */
+ cardurl[i+1][10] = i;
+ buffer[i+4].value.value = cardurl[i+1];
+ buffer[i+4].type = SIMPLETLV_TYPE_LEAF;
+ }
+ /* Skip unknown CardURLs for now */
+
+ buffer[17].value.value = pkcs15;
+ buffer[18].value.value = reg_data_model;
+ buffer[19].value.value = acr_table;
+ /* CCC Tag+Len buffer */
+ /* Ex:
+ * 34 00 Length of complete buffer
+ * F0 15 Card Identifier
+ * F1 01 Capability Container version number
+ * F2 01 Capability Grammar version number
+ * F3 10 Applications CardURL
+ * F3 10 Applications CardURL
+ * F3 10 Applications CardURL
+ * F3 10 Applications CardURL
+ * F3 10 Applications CardURL
+ * F3 10 Applications CardURL
+ * F3 10 Applications CardURL
+ * F3 10 Applications CardURL
+ * F3 10 Applications CardURL
+ * F3 10 Applications CardURL
+ * F3 10 Applications CardURL
+ * F3 10 Applications CardURL
+ * F3 10 Applications CardURL
+ * F3 10 Applications CardURL
+ * F4 01 PKCS#15
+ * F5 01 Registered Data Model number
+ * F6 11 Access Control Rule Table
+ * F7 00 CARD APDUs
+ * FA 00 Redirection Tag
+ * FB 00 Capability Tuples (CTs)
+ * FC 00 Status Tuples (STs)
+ * FD 00 Next CCC
+ * FE 00 Error Detection Code
+ */
+ applet_private->tag_buffer_len = cac_create_tl_file(buffer, 33,
+ &applet_private->tag_buffer);
+ if (applet_private->tag_buffer_len == 0)
+ goto failure;
+ g_debug("%s: applet_private->tag_buffer = %s", __func__,
+ hex_dump(applet_private->tag_buffer, applet_private->tag_buffer_len, NULL, 0));
+
+ /* Value buffer */
+ /* Ex:
+ * 0A 01 Length of complete buffer
+ * A0 00 00 00 79 03 02 40 70 50 72 36 0E 00 00 58 BD 00 2C 19 B5
+ * [ GSC-RID ] [] [] [ Card ID ]
+ * Manufacturer ID-' '- Card Type = javaCard
+ * Card Identifier
+ * 21 CC version
+ * 21 Capability Grammar version
+ * A0 00 00 00 79 01 02 FB 02 FB 00 00 00 00 00 00
+ * A0 00 00 00 79 01 02 FE 02 FE 00 00 00 00 00 00
+ * A0 00 00 00 79 01 02 FD 02 FD 00 00 00 00 00 00
+ * A0 00 00 00 79 01 02 00 02 00 00 00 00 00 00 00
+ * A0 00 00 00 79 01 02 01 02 01 00 00 00 00 00 00
+ * A0 00 00 00 79 04 01 00 01 00 00 00 00 00 00 00
+ * A0 00 00 00 79 04 01 01 01 01 00 00 00 00 00 00
+ * A0 00 00 00 79 04 01 02 01 02 00 00 00 00 00 00
+ * A0 00 00 01 16 01 30 00 30 00 00 00 00 00 00 00
+ * A0 00 00 01 16 01 60 10 30 00 00 00 00 00 00 00
+ * A0 00 00 01 16 01 60 30 30 00 00 00 00 00 00 00
+ * A0 00 00 01 16 01 90 00 30 00 00 00 00 00 00 00
+ * A0 00 00 00 79 01 12 01 12 01 00 00 00 00 00 00
+ * A0 00 00 00 79 01 12 02 12 02 00 00 00 00 00 00
+ * [ RID ] [] [OID] [AID] [ unused in VM? ]
+ * Appl. Type -'
+ * 0x01 generic
+ * 0x02 ski
+ * 0x04 pki
+ * CardURLs
+ * 00 PKCS#15
+ * 10 Reg. data model number
+ * 07 A0 00 00 00 79 03 00 00 00 00 00 00 00 00 00 00
+ * [] [ ACA AID ] [ ???? ]
+ * Access Control Rule table
+ */
+ applet_private->val_buffer_len = cac_create_val_file(buffer, 33,
+ &applet_private->val_buffer);
+ if (applet_private->val_buffer_len == 0)
+ goto failure;
+ g_debug("%s: applet_private->val_buffer = %s", __func__,
+ hex_dump(applet_private->val_buffer, applet_private->val_buffer_len, NULL, 0));
+
+ /* Inject Object ID */
+ tv_object[0].value.value = object_id;
+
+ /* Inject T-Buffer and V-Buffer lengths in the properties buffer */
+ 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;
+
+ /* Inject Applet Version */
+ properties[0].value.value = applet_information;
+ properties[1].value.value = number_objects;
+ properties[2].value.child = tv_object;
+
+ /* Link the properties */
+ applet_private->properties = properties;
+ applet_private->properties_len = 4;
+
+ return applet_private;
+
+failure:
+ if (applet_private) {
+ cac_delete_ccc_applet_private(applet_private);
+ }
+ return NULL;
+}
+
+
+/*
+ * create a new CCC applet
+ */
+static VCardApplet *
+cac_new_ccc_applet(int cert_count)
+{
+ VCardAppletPrivate *applet_private;
+ VCardApplet *applet;
+
+ applet_private = cac_new_ccc_applet_private(cert_count);
+ if (applet_private == NULL) {
+ goto failure;
+ }
+ applet = vcard_new_applet(cac_common_process_apdu_read, NULL,
+ cac_ccc_aid, sizeof(cac_ccc_aid));
+ if (applet == NULL) {
+ goto failure;
+ }
+ vcard_set_applet_private(applet, applet_private,
+ cac_delete_ccc_applet_private);
+ applet_private = NULL;
+
+ return applet;
+
+failure:
+ if (applet_private != NULL) {
+ cac_delete_ccc_applet_private(applet_private);
+ }
+ return NULL;
+}
+
+
/*
* create a new cac applet which links to a given cert
*/
@@ -706,8 +1005,6 @@ failure:
}
-static unsigned char cac_default_container_aid[] = {
- 0xa0, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00 };
static unsigned char cac_id_aid[] = {
0xa0, 0x00, 0x00, 0x00, 0x79, 0x03, 0x00 };
/*
@@ -737,10 +1034,10 @@ cac_card_init(VReader *reader, VCard *card,
vcard_add_applet(card, applet);
}
- /* create a default blank container applet */
- applet = vcard_new_applet(cac_applet_container_process_apdu,
- NULL, cac_default_container_aid,
- sizeof(cac_default_container_aid));
+ /* create a CCC container, which is need for CAC recognition,
+ * which should be default
+ */
+ applet = cac_new_ccc_applet(cert_count);
if (applet == NULL) {
goto failure;
}
diff --git a/src/cac.h b/src/cac.h
index 7c5e9a3..58e302d 100644
--- a/src/cac.h
+++ b/src/cac.h
@@ -26,6 +26,21 @@
#define CAC_PKI_TAG_CERTIFICATE 0x70
#define CAC_PKI_TAG_CERTINFO 0x71
+/* CCC applet tags */
+#define CAC_CCC_CARD_IDENTIFIER 0xF0
+#define CAC_CCC_CAPABILITY_CONTAINER_VERSION 0xF1
+#define CAC_CCC_CAPABILITY_GRAMMAR_VERSION 0xF2
+#define CAC_CCC_APPLICATION_CARDURL 0xF3
+#define CAC_CCC_PKCS15 0xF4
+#define CAC_CCC_REGISTERED_DATA_MODEL_NUMBER 0xF5
+#define CAC_CCC_ACCESS_CONTROL_RULE_TABLE 0xF6
+#define CAC_CCC_CARD_APDUS 0xF7
+#define CAC_CCC_REDIRECTION_TAG 0xFA
+#define CAC_CCC_CAPABILITY_TUPLES 0xFB
+#define CAC_CCC_STATUS_TUPLES 0xFC
+#define CAC_CCC_NEXT_CCC 0xFD
+#define CAC_CCC_ERROR_DETECTION_CODE 0xFE
+
/* Applet properties tags */
#define CAC_PROPERTIES_APPLET_INFORMATION 0x01
#define CAC_PROPERTIES_NUMBER_OBJECTS 0x40
--
2.17.1
More information about the Spice-devel
mailing list