[PATCH libcacard 09/45] Adjust PKI Applet to CAC 2

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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




[Index of Archives]     [Linux Virtualization]     [Linux Virtualization]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [IETF Annouce]     [Security]     [Bugtraq]     [Linux OMAP]     [Linux MIPS]     [ECOS]     [Asterisk Internet PBX]     [Linux API]     [Monitors]