[Spice-devel] [PATCH libcacard 09/45] Adjust PKI Applet to CAC 2
Marc-André Lureau
marcandre.lureau at gmail.com
Tue Jul 31 22:16:41 UTC 2018
Hi Jakub,
On Tue, Jul 31, 2018 at 4:50 PM, Jakub Jelen <jjelen at redhat.com> wrote:
> * This involves creation of properties structures in the applet,
> that are used to discover pki buffers in the applet and its
> properties.
> * This also removes the old way of accessing certificates using
> GET CERTIFICATE APDU
>
> Signed-off-by: Jakub Jelen <jjelen at redhat.com>
> Reviewed-by: Robert Relyea <rrelyea at redhat.com>
> ---
Starting from this patch, make check fails.
It eventually get fixed by later patch "tests: GP Card Manager and
responses on SELECT APDU"
but then tests/hwtest keeps failing.
> src/cac.c | 467 +++++++++++++++++++++++++++++++++++++++++++++++-------
> src/cac.h | 30 +++-
> 2 files changed, 430 insertions(+), 67 deletions(-)
>
> diff --git a/src/cac.c b/src/cac.c
> index 8adb7f3..4fa84e3 100644
> --- a/src/cac.c
> +++ b/src/cac.c
> @@ -17,13 +17,11 @@
> #include "vcard.h"
> #include "vcard_emul.h"
> #include "card_7816.h"
> +#include "simpletlv.h"
> +#include "common.h"
>
> /* private data for PKI applets */
> typedef struct CACPKIAppletDataStruct {
> - unsigned char *cert;
> - int cert_len;
> - unsigned char *cert_buffer;
> - int cert_buffer_len;
> unsigned char *sign_buffer;
> int sign_buffer_len;
> VCardKey *key;
> @@ -33,12 +31,146 @@ typedef struct CACPKIAppletDataStruct {
> * CAC applet private data
> */
> struct VCardAppletPrivateStruct {
> + /* common attributes */
> + unsigned char *tag_buffer;
> + int tag_buffer_len;
> + unsigned char *val_buffer;
> + int val_buffer_len;
> + struct simpletlv_member *properties;
> + unsigned int properties_len;
> + /* applet-specific */
> union {
> CACPKIAppletData pki_data;
> void *reserved;
> } u;
> };
>
> +/*
> + * Encode SimpleTLV structures to file expected to be returned by the card.
> + * This means, data in SimpleTLV prefixed with 2B encoding the length of
> + * the whole buffer.
> + */
> +static int
> +cac_create_file(struct simpletlv_member *tlv, size_t tlv_len,
> + unsigned char **out, int type)
> +{
> + int len, length;
> + unsigned char *buffer = NULL, *start;
> +
> + len = simpletlv_get_length(tlv, tlv_len, type);
> + if (len < 0)
> + goto failure;
> +
> + buffer = g_malloc(2 /*2B length*/ + len);
> +
> + start = buffer + 2;
> + if (type == SIMPLETLV_TL)
> + length = simpletlv_encode_tl(tlv, tlv_len, &start, len, NULL);
> + else if (type == SIMPLETLV_VALUE)
> + length = simpletlv_encode_val(tlv, tlv_len, &start, len, NULL);
> + else
> + goto failure;
> +
> + if (length <= 0)
> + goto failure;
> +
> + ushort2lebytes(buffer, length);
> +
> + *out = buffer;
> + return len + 2;
> +
> +failure:
> + *out = NULL;
> + g_free(buffer);
> + return 0;
> +}
> +
> +static inline int
> +cac_create_tl_file(struct simpletlv_member *tlv, size_t tlv_len,
> + unsigned char **out)
> +{
> + return cac_create_file(tlv, tlv_len, out, SIMPLETLV_TL);
> +}
> +
> +static inline int
> +cac_create_val_file(struct simpletlv_member *tlv, size_t tlv_len,
> + unsigned char **out)
> +{
> + return cac_create_file(tlv, tlv_len, out, SIMPLETLV_VALUE);
> +}
> +
> +/*
> + * This function returns properties of an applet encoded as SimpleTLV.
> + * If the tags argument is provided, only the tags in the passed list
> + * with respective values are returned.
> + * Otherwise, all the tags are returned.
> + */
> +static VCardResponse *
> +get_properties(VCard *card,
> + struct simpletlv_member *properties, unsigned int properties_len,
> + unsigned char *tags, unsigned int tags_len,
> + unsigned int a_Le)
> +{
> + VCardResponse *r = NULL;
> + struct simpletlv_member *cp = NULL;
> + unsigned int cp_len = 0;
> + unsigned char *properties_buffer = NULL;
> + unsigned int properties_buffer_len = 0;
> +
> + if (tags_len > 0 && tags) {
> + unsigned int i, j, k = 0;
> +
> + cp = g_malloc_n(tags_len, sizeof(struct simpletlv_member));
> +
> + /* show only matching */
> + for (j = 0; j < tags_len; j++) {
> + int match = 0;
> + for (i = 0; i < properties_len; i++) {
> + if (properties[i].tag == tags[j]) {
> + memcpy(&cp[k], &properties[i],
> + sizeof(struct simpletlv_member));
> + match++;
> + k++;
> + break; // XXX do not allow more tags of the same ID
> + }
> + }
> + /* if this tag was not found, return */
> + if (!match) {
> + r = vcard_make_response(VCARD7816_STATUS_ERROR_DATA_NOT_FOUND);
> + goto cleanup;
> + }
> + }
> + cp_len = tags_len;
> + } else {
> + cp = properties;
> + cp_len = properties_len;
> + }
> +
> + /* Encode the SimpleTLV structure */
> + properties_buffer_len = simpletlv_encode(cp, cp_len,
> + &properties_buffer, 0, NULL);
> + if (properties_buffer_len <= 0) {
> + g_debug("%s: Failed to encode properties buffer", __func__);
> + goto cleanup;
> + }
> +
> + if (a_Le > properties_buffer_len) {
> + r = vcard_response_new_status_bytes(
> + VCARD7816_SW1_LE_ERROR, properties_buffer_len);
> + goto cleanup;
> + }
> + r = vcard_response_new(card, properties_buffer, properties_buffer_len,
> + a_Le, VCARD7816_STATUS_SUCCESS);
> +
> +cleanup:
> + g_free(properties_buffer);
> + if (tags_len > 0 && tags)
> + g_free(cp);
> + if (r == NULL)
> + r = vcard_make_response(VCARD7816_STATUS_ERROR_GENERAL);
> + return r;
> +}
> +
> /*
> * handle all the APDU's that are common to all CAC applets
> */
> @@ -46,9 +178,61 @@ static VCardStatus
> cac_common_process_apdu(VCard *card, VCardAPDU *apdu, VCardResponse **response)
> {
> int ef;
> + VCardAppletPrivate *applet_private;
> VCardStatus ret = VCARD_FAIL;
>
> + applet_private = vcard_get_current_applet_private(card, apdu->a_channel);
> +
> switch (apdu->a_ins) {
> + case CAC_GET_PROPERTIES:
> + /* 5.3.3.4: Get Properties APDU */
> + assert(applet_private);
> +
> + if (apdu->a_p2 != 0x00) {
> + /* P2 needs to be 0x00 */
> + *response = vcard_make_response(
> + VCARD7816_STATUS_ERROR_P1_P2_INCORRECT);
> + ret = VCARD_DONE;
> + break;
> + }
> + switch (apdu->a_p1) {
> + case 0x00:
> + /* Get a GSC-IS v2.0 compatible properties response message. */
> + /* If P1 = 0x00 cannot be supported by the smart card, SW1 = 0x6A and SW2 = 86. */
> + *response = vcard_make_response(
> + VCARD7816_STATUS_ERROR_P1_P2_INCORRECT);
> + break;
> + case 0x01:
> + /* Get all the properties. */
> + if (apdu->a_Lc != 0) {
> + *response = vcard_make_response(
> + VCARD7816_STATUS_ERROR_DATA_INVALID);
> + ret = VCARD_DONE;
> + break;
> + }
> + *response = get_properties(card, applet_private->properties,
> + applet_private->properties_len, NULL, 0, apdu->a_Le);
> + break;
> + case 0x02:
> + /* Get the properties of the tags provided in list of tags in
> + * the command data field. */
> + if (apdu->a_Lc == 0) {
> + *response = vcard_make_response(
> + VCARD7816_STATUS_ERROR_DATA_INVALID);
> + ret = VCARD_DONE;
> + break;
> + }
> + *response = get_properties(card, applet_private->properties,
> + applet_private->properties_len, apdu->a_body, apdu->a_Lc, apdu->a_Le);
> + break;
> + default:
> + /* unknown params returns (SW1=0x6A, SW2=0x86) */
> + *response = vcard_make_response(
> + VCARD7816_STATUS_ERROR_P1_P2_INCORRECT);
> + break;
> + }
> + ret = VCARD_DONE;
> + break;
> case VCARD7816_INS_SELECT_FILE:
> if (apdu->a_p1 != 0x02) {
> /* let the 7816 code handle applet switches */
> @@ -78,12 +262,6 @@ cac_common_process_apdu(VCard *card, VCardAPDU *apdu, VCardResponse **response)
> /* let the 7816 code handle these */
> ret = VCARD_NEXT;
> break;
> - case CAC_GET_PROPERTIES:
> - case CAC_GET_ACR:
> - /* skip these for now, this will probably be needed */
> - *response = vcard_make_response(VCARD7816_STATUS_ERROR_P1_P2_INCORRECT);
> - ret = VCARD_DONE;
> - break;
> default:
> *response = vcard_make_response(
> VCARD7816_STATUS_ERROR_COMMAND_NOT_SUPPORTED);
> @@ -93,6 +271,87 @@ cac_common_process_apdu(VCard *card, VCardAPDU *apdu, VCardResponse **response)
> return ret;
> }
>
> +/*
> + * Handle READ BUFFER APDU and other common APDUs for CAC applets
> + */
> +static VCardStatus
> +cac_common_process_apdu_read(VCard *card, VCardAPDU *apdu,
> + VCardResponse **response)
> +{
> + VCardAppletPrivate *applet_private;
> + VCardStatus ret = VCARD_FAIL;
> + int size, offset;
> +
> + applet_private = vcard_get_current_applet_private(card, apdu->a_channel);
> +
> + switch (apdu->a_ins) {
> + case CAC_READ_BUFFER:
> + /* Body contains exactly two bytes */
> + if (!apdu->a_body || apdu->a_Lc != 2) {
> + *response = vcard_make_response(
> + VCARD7816_STATUS_ERROR_DATA_INVALID);
> + ret = VCARD_DONE;
> + break;
> + }
> +
> + /* Second byte defines how many bytes should be read */
> + size = apdu->a_body[1];
> +
> + /* P1 | P2 defines offset to read from */
> + offset = (apdu->a_p1 << 8) | apdu->a_p2;
> + g_debug("%s: Reqested offset: %d bytes", __func__, offset);
> +
> + /* First byte selects TAG+LEN or VALUE buffer */
> + switch (apdu->a_body[0]) {
> + case CAC_FILE_VALUE:
> + size = MIN(size, applet_private->val_buffer_len - offset);
> + if (size < 0) { /* Overrun returns (SW1=0x6A, SW2=0x86) */
> + *response = vcard_make_response(
> + VCARD7816_STATUS_ERROR_P1_P2_INCORRECT);
> + break;
> + }
> + *response = vcard_response_new_bytes(
> + card, applet_private->val_buffer + offset, size,
> + apdu->a_Le, VCARD7816_SW1_SUCCESS, 0);
> + break;
> + case CAC_FILE_TAG:
> + g_debug("%s: Reqested: %d bytes", __func__, size);
> + size = MIN(size, applet_private->tag_buffer_len - offset);
> + if (size < 0) { /* Overrun returns (SW1=0x6A, SW2=0x86) */
> + *response = vcard_make_response(
> + VCARD7816_STATUS_ERROR_P1_P2_INCORRECT);
> + break;
> + }
> + g_debug("%s: Returning: %d bytes (have %d)", __func__, size,
> + applet_private->tag_buffer_len);
> + *response = vcard_response_new_bytes(
> + card, applet_private->tag_buffer + offset, size,
> + apdu->a_Le, VCARD7816_SW1_SUCCESS, 0);
> + break;
> + default:
> + *response = vcard_make_response(
> + VCARD7816_STATUS_ERROR_DATA_INVALID);
> + break;
> + }
> + if (*response == NULL) {
> + *response = vcard_make_response(
> + VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE);
> + }
> + ret = VCARD_DONE;
> + break;
> + 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;
> +}
> +
> +
> /*
> * reset the inter call state between applet selects
> */
> @@ -105,10 +364,8 @@ cac_applet_pki_reset(VCard *card, int channel)
> assert(applet_private);
> pki_applet = &(applet_private->u.pki_data);
>
> - pki_applet->cert_buffer = NULL;
> g_free(pki_applet->sign_buffer);
> pki_applet->sign_buffer = NULL;
> - pki_applet->cert_buffer_len = 0;
> pki_applet->sign_buffer_len = 0;
> return VCARD_DONE;
> }
> @@ -119,7 +376,7 @@ cac_applet_pki_process_apdu(VCard *card, VCardAPDU *apdu,
> {
> CACPKIAppletData *pki_applet;
> VCardAppletPrivate *applet_private;
> - int size, next;
> + int size;
> unsigned char *sign_buffer;
> bool retain_sign_buffer = FALSE;
> vcard_7816_status_t status;
> @@ -135,37 +392,6 @@ cac_applet_pki_process_apdu(VCard *card, VCardAPDU *apdu,
> VCARD7816_STATUS_ERROR_CONDITION_NOT_SATISFIED);
> ret = VCARD_DONE;
> break;
> - case CAC_GET_CERTIFICATE:
> - if ((apdu->a_p2 != 0) || (apdu->a_p1 != 0)) {
> - *response = vcard_make_response(
> - VCARD7816_STATUS_ERROR_P1_P2_INCORRECT);
> - break;
> - }
> - assert(pki_applet->cert != NULL);
> - size = apdu->a_Le;
> - if (pki_applet->cert_buffer == NULL) {
> - pki_applet->cert_buffer = pki_applet->cert;
> - pki_applet->cert_buffer_len = pki_applet->cert_len;
> - }
> - size = MIN(size, pki_applet->cert_buffer_len);
> - next = MIN(255, pki_applet->cert_buffer_len - size);
> - *response = vcard_response_new_bytes(
> - card, pki_applet->cert_buffer, size,
> - apdu->a_Le, next ?
> - VCARD7816_SW1_WARNING_CHANGE :
> - VCARD7816_SW1_SUCCESS,
> - next);
> - pki_applet->cert_buffer += size;
> - pki_applet->cert_buffer_len -= size;
> - if ((*response == NULL) || (next == 0)) {
> - pki_applet->cert_buffer = NULL;
> - }
> - if (*response == NULL) {
> - *response = vcard_make_response(
> - VCARD7816_STATUS_EXC_ERROR_MEMORY_FAILURE);
> - }
> - ret = VCARD_DONE;
> - break;
> case CAC_SIGN_DECRYPT:
> if (apdu->a_p2 != 0) {
> *response = vcard_make_response(
> @@ -215,21 +441,13 @@ cac_applet_pki_process_apdu(VCard *card, VCardAPDU *apdu,
> }
> 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);
> + ret = cac_common_process_apdu_read(card, apdu, response);
> break;
> }
> return ret;
> }
>
> -
> static VCardStatus
> cac_applet_id_process_apdu(VCard *card, VCardAPDU *apdu,
> VCardResponse **response)
> @@ -293,8 +511,11 @@ cac_delete_pki_applet_private(VCardAppletPrivate *applet_private)
> return;
> }
> pki_applet_data = &(applet_private->u.pki_data);
> - g_free(pki_applet_data->cert);
> g_free(pki_applet_data->sign_buffer);
> + g_free(applet_private->tag_buffer);
> + g_free(applet_private->val_buffer);
> + /* this one is cloned so needs to be freed */
> + simpletlv_free(applet_private->properties, applet_private->properties_len);
> if (pki_applet_data->key != NULL) {
> vcard_emul_delete_key(pki_applet_data->key);
> }
> @@ -302,25 +523,149 @@ cac_delete_pki_applet_private(VCardAppletPrivate *applet_private)
> }
>
> static VCardAppletPrivate *
> -cac_new_pki_applet_private(const unsigned char *cert,
> +cac_new_pki_applet_private(int i, const unsigned char *cert,
> int cert_len, VCardKey *key)
> {
> CACPKIAppletData *pki_applet_data;
> VCardAppletPrivate *applet_private;
>
> + /* PKI applet Properies 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
> + * 51 Tag: First PKI object
> + * 11 Length
> + * 41 Tag: ObjectID
> + * 02 Length
> + * 01 01
> + * 42 Buffer properties
> + * 05 Length
> + * 00 Type of tag supported
> + * 1E 00 T-Buffer length (LSB, MSB)
> + * 54 05 V-Buffer length (LSB, MSB)
> + * 43 Tag: PKI properties
> + * 04 Length
> + * 06 Algorithm ID Table 5-6 in GSC-IS 2.1
> + * 10 Key length bytes /8
> + * 01 Private key initialized
> + * 01 Public key initialized
> + */
> + unsigned char object_id[] = "\x01\x00";
> + unsigned char buffer_properties[] = "\x00\x00\x00\x00\x00";
> + unsigned char pki_properties[] = "\x06\x10\x01\x01";
> + static struct simpletlv_member pki_object[3] = {
> + {CAC_PROPERTIES_OBJECT_ID, 2, {/*.value = object_id*/},
> + SIMPLETLV_TYPE_LEAF},
> + {CAC_PROPERTIES_BUFFER_PROPERTIES, 5, {/*.value = buffer_properties*/},
> + SIMPLETLV_TYPE_LEAF},
> + {CAC_PROPERTIES_PKI_PROPERTIES, 4, {/*.value = pki_properties*/},
> + SIMPLETLV_TYPE_LEAF},
> + };
> + unsigned char applet_information[] = "\x10\x02\x06\x02\x03";
> + 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_PKI_OBJECT, 3, {/*.child = pki_object*/},
> + SIMPLETLV_TYPE_COMPOUND},
> + };
> + /* if this would be 1, the certificate would be compressed */
> + unsigned char certinfo[] = "\x00";
> + struct simpletlv_member buffer[] = {
> + {CAC_PKI_TAG_CERTINFO, 1, {/*.value = certinfo*/}, SIMPLETLV_TYPE_LEAF},
> + {CAC_PKI_TAG_CERTIFICATE, cert_len, {/*.value = cert*/}, SIMPLETLV_TYPE_LEAF},
> + };
> +
> applet_private = g_new0(VCardAppletPrivate, 1);
> pki_applet_data = &(applet_private->u.pki_data);
> - pki_applet_data->cert = (unsigned char *)g_malloc(cert_len+1);
> /*
> * if we want to support compression, then we simply change the 0 to a 1
> - * and compress the cert data with libz
> + * in certinfo and compress the cert data with libz
> + */
> +
> + /* 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 ] [...]
> + * */
> +
> + /* Tag+Len buffer */
> + buffer[0].value.value = certinfo;
> + buffer[1].value.value = (unsigned char *)cert;
> + /* Ex:
> + * 0A 00 Length of whole buffer
> + * 71 Tag: CertInfo
> + * 01 Length: 1B
> + * 70 Tag: Certificate
> + * FF B2 03 Length: (\x03 << 8) || \xB2
> + * 72 Tag: MSCUID
> + * 26 Length
> + */
> + applet_private->tag_buffer_len = cac_create_tl_file(buffer, 4,
> + &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:
> + * DA 03 Length of complete buffer
> + * 01 Value of CertInfo
> + * 78 [..] 6C Cert Value
> + * 7B 63 37 35 62 62 61 64 61 2D 35 32 39 38 2D 31
> + * 37 35 62 2D 39 32 64 63 2D 39 38 35 30 36 62 65
> + * 30 30 30 30 30 7D MSCUID Value
> */
> - pki_applet_data->cert[0] = 0; /* not compressed */
> - memcpy(&pki_applet_data->cert[1], cert, cert_len);
> - pki_applet_data->cert_len = cert_len+1;
> + applet_private->val_buffer_len = cac_create_val_file(buffer, 4,
> + &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 */
> + object_id[1] = i;
> + pki_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);
> + pki_object[1].value.value = buffer_properties;
> +
> + /* PKI properties needs adjustments based on the key sizes */
> + // TODO XXX assuming 1024 b keys!
> + // pki_properties[1] = key_bits >> 3;
> + pki_object[2].value.value = pki_properties;
> +
> + /* Inject Applet Version */
> + properties[0].value.value = applet_information;
> + properties[1].value.value = number_objects;
> + properties[2].value.child = pki_object;
> +
> + /* Clone the properties */
> + applet_private->properties_len = 4;
> + applet_private->properties = simpletlv_clone(properties, 4);
> + if (applet_private->properties == NULL)
> + goto failure;
>
> pki_applet_data->key = key;
> return applet_private;
> +
> +failure:
> + if (applet_private)
> + cac_delete_pki_applet_private(applet_private);
> + return NULL;
> }
>
>
> @@ -338,7 +683,7 @@ cac_new_pki_applet(int i, const unsigned char *cert,
>
> pki_aid[pki_aid_len-1] = i;
>
> - applet_private = cac_new_pki_applet_private(cert, cert_len, key);
> + applet_private = cac_new_pki_applet_private(i, cert, cert_len, key);
> if (applet_private == NULL) {
> goto failure;
> }
> diff --git a/src/cac.h b/src/cac.h
> index af7f4cd..7c5e9a3 100644
> --- a/src/cac.h
> +++ b/src/cac.h
> @@ -11,12 +11,30 @@
> #include "vcard.h"
> #include "vreader.h"
>
> -#define CAC_GET_PROPERTIES 0x56
> -#define CAC_GET_ACR 0x4c
> -#define CAC_READ_BUFFER 0x52
> -#define CAC_UPDATE_BUFFER 0x58
> -#define CAC_SIGN_DECRYPT 0x42
> -#define CAC_GET_CERTIFICATE 0x36
> +#define CAC_GET_PROPERTIES 0x56
> +#define CAC_GET_ACR 0x4c
> +#define CAC_READ_BUFFER 0x52 /* CACv2 */
> +#define CAC_UPDATE_BUFFER 0x58
> +#define CAC_SIGN_DECRYPT 0x42
> +#define CAC_GET_CERTIFICATE 0x36 /* CACv1 */
> +
> +/* read file TAGs for CACv2 */
> +#define CAC_FILE_TAG 0x01
> +#define CAC_FILE_VALUE 0x02
> +
> +/* PKI applet tags */
> +#define CAC_PKI_TAG_CERTIFICATE 0x70
> +#define CAC_PKI_TAG_CERTINFO 0x71
> +
> +/* Applet properties tags */
> +#define CAC_PROPERTIES_APPLET_INFORMATION 0x01
> +#define CAC_PROPERTIES_NUMBER_OBJECTS 0x40
> +#define CAC_PROPERTIES_OBJECT_ID 0x41
> +#define CAC_PROPERTIES_BUFFER_PROPERTIES 0x42
> +#define CAC_PROPERTIES_PKI_PROPERTIES 0x43
> +#define CAC_PROPERTIES_TV_OBJECT 0x50
> +#define CAC_PROPERTIES_PKI_OBJECT 0x51
> +
>
> /*
> * Initialize the cac card. This is the only public function in this file. All
> --
> 2.17.1
>
> _______________________________________________
> Spice-devel mailing list
> Spice-devel at lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/spice-devel
--
Marc-André Lureau
More information about the Spice-devel
mailing list