* 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@xxxxxxxxxx> Reviewed-by: Robert Relyea <rrelyea@xxxxxxxxxx> --- src/cac.c | 361 +++++++++++++++++++++++++++++++++++++++++++++++++----- src/cac.h | 15 +++ 2 files changed, 345 insertions(+), 31 deletions(-) diff --git a/src/cac.c b/src/cac.c index 06a5d1b..126e109 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) @@ -676,6 +671,312 @@ 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[] = { + {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}, + }; + size_t properties_len = sizeof(properties)/sizeof(struct simpletlv_member); + + 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[] = { + {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}, + }; + size_t buffer_len = sizeof(buffer)/sizeof(struct simpletlv_member); + 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, buffer_len, + &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, buffer_len, + &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 = properties_len; + + 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 */ @@ -713,8 +1014,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 }; /* @@ -744,10 +1043,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 _______________________________________________ Spice-devel mailing list Spice-devel@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/spice-devel