[Spice-devel] [PATCH libcacard v2 22/35] tests: Create separate hardware tests

Jakub Jelen jjelen at redhat.com
Thu Aug 2 09:43:54 UTC 2018


 * These tests are supposed to run against existing CAC card
   connected to local computer, which should be presenting
   certificates with 1024 b keys.

 * These tests are skipped in case there is no card available.

 * This also extends the existing testsuite with tests for
   various empty applets

 * The NSS DB needs to be created under tests/hwdb/ and local
   pkcs#11 module needs to be added to the database

Signed-off-by: Jakub Jelen <jjelen at redhat.com>
Reviewed-by: Robert Relyea <rrelyea at redhat.com>
---
 Makefile.am        |  15 ++
 docs/libcacard.txt |   1 +
 tests/common.c     | 525 +++++++++++++++++++++++++++++++++++++++++++++
 tests/common.h     |  42 ++++
 tests/hwtests.c    | 287 +++++++++++++++++++++++++
 tests/libcacard.c  | 422 ++----------------------------------
 6 files changed, 884 insertions(+), 408 deletions(-)
 create mode 100644 tests/common.c
 create mode 100644 tests/common.h
 create mode 100644 tests/hwtests.c

diff --git a/Makefile.am b/Makefile.am
index 1be09c6..174ab25 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -75,8 +75,13 @@ include $(srcdir)/build-aux/glib-tap.mk
 test_programs =					\
 	tests/libcacard				\
 	tests/simpletlv				\
+	tests/hwtests				\
 	$(NULL)
 
+tests_libcacard_SOURCES =			\
+	tests/common.c				\
+	tests/libcacard.c			\
+	$(NULL)
 tests_libcacard_LDADD =				\
 	libcacard.la				\
 	src/common.lo				\
@@ -89,6 +94,16 @@ tests_simpletlv_LDADD =				\
 	src/simpletlv.lo			\
 	$(NULL)
 
+tests_hwtests_SOURCES =				\
+	tests/common.c				\
+	tests/hwtests.c				\
+	$(NULL)
+tests_hwtests_LDADD =				\
+	libcacard.la				\
+	src/common.lo				\
+	src/simpletlv.lo			\
+	$(NULL)
+
 @CODE_COVERAGE_RULES@
 
 AM_CPPFLAGS =					\
diff --git a/docs/libcacard.txt b/docs/libcacard.txt
index f421054..405eed9 100644
--- a/docs/libcacard.txt
+++ b/docs/libcacard.txt
@@ -500,4 +500,5 @@ src/simpletlv.c - Simple TLV encoding functions
 src/simpletlv.h - header file for Simple TLV encoding helpers
 tests/libcacard.c - Test for the whole smart card emulation
 tests/simpletlv.c - Unit tests for SimpleTLV encoding and decoding functions
+tests/hwtests.c - Tests intended to be ran against real card if available
 
diff --git a/tests/common.c b/tests/common.c
new file mode 100644
index 0000000..21a3099
--- /dev/null
+++ b/tests/common.c
@@ -0,0 +1,525 @@
+/*
+ * Shared test functions for libCACard
+ *
+ * Copyright 2018 Red Hat, Inc.
+ *
+ * Author: Jakub Jelen <jjelen at redhat.com>
+ *
+ * This code is licensed under the GNU LGPL, version 2.1 or later.
+ * See the COPYING file in the top-level directory.
+ */
+#include <glib.h>
+#include <string.h>
+
+#include "common.h"
+#include "simpletlv.h"
+
+int key_bits = 0;
+int hw_tests = 0;
+
+
+void select_aid(VReader *reader, unsigned char *aid, unsigned int aid_len)
+{
+    VReaderStatus status;
+    int dwRecvLength = APDUBufSize;
+    uint8_t pbRecvBuffer[APDUBufSize];
+    uint8_t selfile[] = {
+        0x00, 0xa4, 0x04, 0x00, 0x07, 0xa0, 0x00, 0x00, 0x00, 0x79, 0x01, 0x00
+    };
+    size_t selfile_len = sizeof(selfile);
+
+    g_assert_cmpint(aid_len, ==, 7);
+    memcpy(&selfile[5], aid, aid_len);
+
+    g_debug("%s: Add applet with AID 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x",
+        __func__, aid[0], aid[1], aid[2], aid[3], aid[4], aid[5], aid[6]);
+    g_assert_nonnull(reader);
+    status = vreader_xfr_bytes(reader,
+                               selfile, selfile_len,
+                               pbRecvBuffer, &dwRecvLength);
+    g_assert_cmpint(status, ==, VREADER_OK);
+    g_assert_cmphex(pbRecvBuffer[dwRecvLength-2], ==, VCARD7816_SW1_RESPONSE_BYTES);
+    g_assert_cmphex(pbRecvBuffer[dwRecvLength-1], >, 0);
+}
+
+void get_properties_coid(VReader *reader, const unsigned char coid[2],
+                         int object_type)
+{
+    int dwRecvLength = APDUBufSize;
+    VReaderStatus status;
+    uint8_t pbRecvBuffer[APDUBufSize], *p, *p_end, *p2, *p2_end;
+    uint8_t get_properties[] = {
+        /* Get properties */
+        0x80, 0x56, 0x01, 0x00, 0x00
+    };
+    uint8_t get_properties_tag[] = {
+        /* Get properties             [tag list] */
+        0x80, 0x56, 0x02, 0x00, 0x02, 0x01, 0x01, 0x00
+    };
+    int verified_pki_properties = 0;
+    int num_objects = 0, num_objects_expected = -1;
+    int have_applet_information = 0;
+
+    status = vreader_xfr_bytes(reader,
+                               get_properties, sizeof(get_properties),
+                               pbRecvBuffer, &dwRecvLength);
+    g_assert_cmpint(status, ==, VREADER_OK);
+    g_assert_cmpint(dwRecvLength, ==, 2);
+    /* for too long Le, the cards return LE_ERROR with correct length to ask */
+    g_assert_cmpint(pbRecvBuffer[dwRecvLength-2], ==, VCARD7816_SW1_LE_ERROR);
+    g_assert_cmpint(pbRecvBuffer[dwRecvLength-1], >, 0);
+
+    /* Update the APDU to match Le field from response and resend */
+    get_properties[4] = pbRecvBuffer[1];
+    dwRecvLength = APDUBufSize;
+    status = vreader_xfr_bytes(reader,
+                               get_properties, sizeof(get_properties),
+                               pbRecvBuffer, &dwRecvLength);
+    g_assert_cmpint(status, ==, VREADER_OK);
+    g_assert_cmpint(dwRecvLength, >, 2);
+    g_assert_cmpint(pbRecvBuffer[dwRecvLength-2], ==, VCARD7816_SW1_SUCCESS);
+    g_assert_cmpint(pbRecvBuffer[dwRecvLength-1], ==, 0x00);
+
+    /* try to parse the response, if it makes sense */
+    p = pbRecvBuffer;
+    p_end = p + dwRecvLength - 2;
+    while (p < p_end) {
+        uint8_t tag;
+        size_t vlen;
+        if (simpletlv_read_tag(&p, p_end - p, &tag, &vlen) < 0) {
+            g_debug("The generated SimpleTLV can not be parsed");
+            g_assert_not_reached();
+        }
+        g_debug("Tag: 0x%02x, Len: %lu", tag, vlen);
+        g_assert_cmpint(vlen, <=, p_end - p);
+
+        switch (tag) {
+        case 0x01: /* Applet Information */
+            g_assert_cmpint(vlen, ==, 5);
+            g_assert_cmphex(*p, ==, 0x10); /* Applet family */
+            have_applet_information = 1;
+            break;
+
+        case 0x40: /* Number of objects */
+            g_assert_cmpint(vlen, ==, 1);
+            if (num_objects_expected != -1) {
+                g_debug("Received multiple number-of-objects tags");
+                g_assert_not_reached();
+            }
+            num_objects_expected = *p;
+            break;
+
+        case 0x50: /* TV Object */
+        case 0x51: /* PKI Object */
+            /* recursive SimpleTLV structure */
+            p2 = p;
+            p2_end = p + vlen;
+            while (p2 < p2_end) {
+                uint8_t tag2;
+                size_t vlen2;
+                if (simpletlv_read_tag(&p2, p2_end - p2, &tag2, &vlen2) < 0) {
+                    g_debug("The generated SimpleTLV can not be parsed");
+                    g_assert_not_reached();
+                }
+                g_assert_cmpint(vlen2, <=, p2_end - p2);
+                g_debug("    Tag: 0x%02x, Len: %lu", tag2, vlen2);
+
+                switch (tag2) {
+                case 0x41: /* Object ID */
+                    g_assert_cmpmem(p2, vlen2, coid, 2);
+                    break;
+
+                case 0x42: /* Buffer properties */
+                    g_assert_cmpint(vlen2, ==, 5);
+                    if (object_type != TEST_EMPTY_BUFFER)
+                        g_assert_cmpint(p2[0], ==, 0x00);
+                    break;
+
+                case 0x43: /* PKI properties */
+                    g_assert_cmphex(p2[0], ==, 0x06);
+                    if (hw_tests) {
+                        /* Assuming CAC card with 1024 b RSA keys */
+                        key_bits = 1024;
+                    } else {
+                        /* Assuming 2048 b RSA keys */
+                        key_bits = 2048;
+                    }
+                    g_assert_cmphex(p2[1], ==, (key_bits / 8 / 8));
+                    g_assert_cmphex(p2[2], ==, 0x01);
+                    g_assert_cmphex(p2[3], ==, 0x01);
+                    verified_pki_properties = 1;
+                    break;
+
+                default:
+                    g_debug("Unknown tag in object: 0x%02x", tag2);
+                    g_assert_not_reached();
+                }
+                p2 += vlen2;
+            }
+            /* one more object processed */
+            num_objects++;
+            break;
+        default:
+            g_debug("Unknown tag in properties buffer: 0x%02x", tag);
+            g_assert_not_reached();
+        }
+        p += vlen;
+    }
+
+    if (num_objects_expected != -1) {
+        g_assert_cmpint(num_objects, ==, num_objects_expected);
+    }
+
+    if (object_type == TEST_EMPTY_BUFFER) {
+        g_assert_cmpint(num_objects_expected, ==, 1);
+    }
+
+    if (object_type == TEST_EMPTY) {
+        g_assert_cmpint(num_objects_expected, ==, 0);
+    }
+
+    if (object_type == TEST_PKI) {
+        g_assert_cmpint(verified_pki_properties, ==, 1);
+    }
+
+    g_assert_cmpint(have_applet_information, ==, 1);
+
+    /* Try to list only some properties */
+    dwRecvLength = APDUBufSize;
+    status = vreader_xfr_bytes(reader,
+                               get_properties_tag, sizeof(get_properties_tag),
+                               pbRecvBuffer, &dwRecvLength);
+    g_assert_cmpint(status, ==, VREADER_OK);
+    g_assert_cmpint(dwRecvLength, ==, 2);
+    g_assert_cmpint(pbRecvBuffer[0], ==, VCARD7816_SW1_LE_ERROR);
+    g_assert_cmpint(pbRecvBuffer[1], ==, 0x0e); /* Two applet information buffers */
+
+    /* Update the APDU to match Le field from response and resend */
+    get_properties_tag[7] = pbRecvBuffer[1];
+    dwRecvLength = APDUBufSize;
+    status = vreader_xfr_bytes(reader,
+                               get_properties_tag, sizeof(get_properties_tag),
+                               pbRecvBuffer, &dwRecvLength);
+    g_assert_cmpint(status, ==, VREADER_OK);
+    g_assert_cmpint(dwRecvLength, ==, 16); /* Two applet information buffers + status */
+    g_assert_cmpint(pbRecvBuffer[dwRecvLength-2], ==, VCARD7816_SW1_SUCCESS);
+    g_assert_cmpint(pbRecvBuffer[dwRecvLength-1], ==, 0x00);
+}
+
+void get_properties(VReader *reader, int object_type)
+{
+    unsigned char coid[2];
+    switch (object_type) {
+    case TEST_PKI:
+        // XXX only the first PKI for now
+        coid[0] = 0x01;
+        coid[1] = 0x00;
+        get_properties_coid(reader, coid, object_type);
+        break;
+
+    case TEST_CCC:
+        coid[0] = 0xDB;
+        coid[1] = 0x00;
+        get_properties_coid(reader, coid, object_type);
+        break;
+
+    case TEST_ACA:
+        coid[0] = 0x03;
+        coid[1] = 0x00;
+        get_properties_coid(reader, coid, object_type);
+        break;
+
+    default:
+        g_debug("Got unknown object type");
+        g_assert_not_reached();
+    }
+}
+
+void read_buffer(VReader *reader, uint8_t type, int object_type)
+{
+    int dwRecvLength = APDUBufSize, dwLength, dwReadLength, offset;
+    VReaderStatus status;
+    uint8_t pbRecvBuffer[APDUBufSize];
+    uint8_t *data;
+    uint8_t read_buffer[] = {
+        /*Read Buffer  OFFSET         TYPE LENGTH a_Le */
+        0x80, 0x52, 0x00, 0x00, 0x02, 0x01, 0x02, 0x02
+    };
+    int card_urls = 0;
+
+    dwRecvLength = 4;
+    read_buffer[5] = type;
+    status = vreader_xfr_bytes(reader,
+                               read_buffer, sizeof(read_buffer),
+                               pbRecvBuffer, &dwRecvLength);
+    g_assert_cmpint(status, ==, VREADER_OK);
+    g_assert_cmpint(dwRecvLength, ==, 4);
+    g_assert_cmphex(pbRecvBuffer[dwRecvLength-2], ==, VCARD7816_SW1_SUCCESS);
+    g_assert_cmphex(pbRecvBuffer[dwRecvLength-1], ==, 0x00);
+
+    dwLength = (pbRecvBuffer[0] & 0xff) | ((pbRecvBuffer[1] << 8) & 0xff);
+    if (dwLength == 0)
+        return;
+
+    data = g_malloc(dwLength);
+    offset = 0x02;
+    do {
+        dwReadLength = MIN(255, dwLength);
+        dwRecvLength = dwReadLength+2;
+        read_buffer[2] = (unsigned char) ((offset >> 8) & 0xff);
+        read_buffer[3] = (unsigned char) (offset & 0xff);
+        read_buffer[6] = (unsigned char) (dwReadLength);
+        read_buffer[7] = (unsigned char) (dwReadLength);
+        status = vreader_xfr_bytes(reader,
+                                   read_buffer, sizeof(read_buffer),
+                                   pbRecvBuffer, &dwRecvLength);
+        g_assert_cmpint(status, ==, VREADER_OK);
+        g_assert_cmpint(dwRecvLength, ==, dwReadLength + 2);
+        g_assert_cmphex(pbRecvBuffer[dwRecvLength-2], ==, VCARD7816_SW1_SUCCESS);
+        g_assert_cmphex(pbRecvBuffer[dwRecvLength-1], ==, 0x00);
+
+        memcpy(data + offset - 2, pbRecvBuffer, dwReadLength - 2);
+        offset += dwLength;
+        dwLength -= dwReadLength;
+    } while (dwLength != 0);
+
+    /* Try to parse the TAG buffer, if it makes sense */
+    if (type == CAC_FILE_TAG) {
+        uint8_t *p = data;
+        uint8_t *p_end = p + offset - 2;
+        while (p < p_end) {
+            uint8_t tag;
+            size_t vlen;
+            if (simpletlv_read_tag(&p, p_end - p, &tag, &vlen) < 0) {
+                g_debug("The generated SimpleTLV can not be parsed");
+                g_assert_not_reached();
+            }
+            g_debug("Tag: 0x%02x, Len: %lu", tag, vlen);
+
+            switch (tag) {
+            case 0xF3: /* CardURL from CCC */
+                if (object_type == TEST_CCC) {
+                    card_urls++;
+                } else {
+                    g_debug("CardURLs found outside of CCC buffer");
+                    g_assert_not_reached();
+                }
+                break;
+            default:
+                break;
+            }
+        }
+        if (object_type == TEST_CCC)
+            g_assert_cmpint(card_urls, ==, 11 + 3);
+    }
+    g_free(data);
+}
+
+void select_applet(VReader *reader, int type)
+{
+    uint8_t selfile_ccc[] = {
+        /* Select CCC Applet */
+        0xa0, 0x00, 0x00, 0x01, 0x16, 0xDB, 0x00
+    };
+    uint8_t selfile_aca[] = {
+        /* Select ACA Applet */
+        0xa0, 0x00, 0x00, 0x00, 0x79, 0x03, 0x00
+    };
+    uint8_t selfile_pki[] = {
+        /* Select first PKI Applet */
+        0xa0, 0x00, 0x00, 0x00, 0x79, 0x01, 0x00
+    };
+    uint8_t *aid = NULL;
+    size_t aid_len = 0;
+
+    switch (type) {
+    case TEST_PKI:
+        aid = selfile_pki;
+        aid_len = sizeof(selfile_pki);
+        break;
+
+    case TEST_CCC:
+        aid = selfile_ccc;
+        aid_len = sizeof(selfile_ccc);
+        break;
+
+    case TEST_ACA:
+        aid = selfile_aca;
+        aid_len = sizeof(selfile_aca);
+        break;
+
+    default:
+        g_assert_not_reached();
+    }
+    g_assert_nonnull(aid);
+
+    select_aid(reader, aid, aid_len);
+}
+
+void do_sign(VReader *reader)
+{
+    VReaderStatus status;
+    int dwRecvLength = APDUBufSize;
+    uint8_t pbRecvBuffer[APDUBufSize];
+    uint8_t sign[] = {
+        /* VERIFY   [p1,p2=0 ]  [Lc            ] [2048b keys: 256 bytes of PKCS#1.5 padded data] */
+        0x80, 0x42, 0x00, 0x00, 0x00, 0x01, 0x00,
+0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+0xff, 0xff, 0x00, 0x64, 0x61, 0x74, 0x61, 0x20, 0x74, 0x6f, 0x20, 0x73, 0x69, 0x67, 0x6e, 0x20,
+0x28, 0x6d, 0x61, 0x78, 0x20, 0x31, 0x30, 0x30, 0x20, 0x62, 0x79, 0x74, 0x65, 0x73, 0x29, 0x0a
+    };
+    int sign_len = sizeof(sign);
+    uint8_t getresp[] = {
+        /* Get Response (max we can get) */
+        0x00, 0xc0, 0x00, 0x00, 0x00
+    };
+    g_assert_nonnull(reader);
+
+    /* Adjust the buffers to match the key lengths, if already retrieved */
+    if (key_bits && key_bits < 2048) {
+        sign[4] = key_bits/8; /* less than 2048b will fit the length into one byte */
+        sign[5] = 0x00;
+        sign[6] = 0x01;
+        memcpy(&sign[7], &sign[sign_len-key_bits/8+2], key_bits/8-2);
+        sign_len = 5 + key_bits/8;
+    }
+
+    status = vreader_xfr_bytes(reader,
+                               sign, sign_len,
+                               pbRecvBuffer, &dwRecvLength);
+    g_assert_cmpint(status, ==, VREADER_OK);
+    g_assert_cmphex(pbRecvBuffer[dwRecvLength-2], ==, VCARD7816_SW1_RESPONSE_BYTES);
+    g_assert_cmphex(pbRecvBuffer[dwRecvLength-1], ==, (unsigned char) (key_bits/8));
+
+
+    /* fetch the actual response */
+    dwRecvLength = APDUBufSize;
+    status = vreader_xfr_bytes(reader,
+                               getresp, sizeof(getresp),
+                               pbRecvBuffer, &dwRecvLength);
+    g_assert_cmpint(status, ==, VREADER_OK);
+    g_assert_cmpint(dwRecvLength, ==, key_bits/8+2);
+    g_assert_cmphex(pbRecvBuffer[dwRecvLength-2], ==, VCARD7816_SW1_SUCCESS);
+    g_assert_cmphex(pbRecvBuffer[dwRecvLength-1], ==, 0x00);
+
+}
+
+void test_empty_applets(void)
+{
+    uint8_t applet_02fb[] = {
+        0xA0, 0x00, 0x00, 0x00, 0x79, 0x02, 0xFB
+    };
+    uint8_t applet_1201[] = {
+        0xA0, 0x00, 0x00, 0x00, 0x79, 0x12, 0x01
+    };
+    uint8_t applet_1202[] = {
+        0xA0, 0x00, 0x00, 0x00, 0x79, 0x12, 0x02
+    };
+    uint8_t applet_02f0[] = {
+        0xA0, 0x00, 0x00, 0x00, 0x79, 0x02, 0xF0
+    };
+    uint8_t applet_02f1[] = {
+        0xA0, 0x00, 0x00, 0x00, 0x79, 0x02, 0xF1
+    };
+    uint8_t applet_02f2[] = {
+        0xA0, 0x00, 0x00, 0x00, 0x79, 0x02, 0xF2
+    };
+    uint8_t coid[2] = {0x02, 0xFB};
+
+    VReader *reader = vreader_get_reader_by_id(0);
+
+
+    /* select the empty applet A00000007902FB, which should be empty buffer */
+    select_aid(reader, applet_02fb, sizeof(applet_02fb));
+
+    /* get properties */
+    get_properties_coid(reader, coid, TEST_EMPTY_BUFFER);
+
+    /* get the TAG buffer length */
+    read_buffer(reader, CAC_FILE_TAG, TEST_EMPTY_BUFFER);
+
+    /* get the VALUE buffer length */
+    read_buffer(reader, CAC_FILE_VALUE, TEST_EMPTY_BUFFER);
+
+
+    /* select the empty applet A0000000791201, which should be empty buffer */
+    select_aid(reader, applet_1201, sizeof(applet_1201));
+    coid[0] = 0x12;
+    coid[1] = 0x01;
+
+    /* get properties */
+    get_properties_coid(reader, coid, TEST_EMPTY_BUFFER);
+
+    /* get the TAG buffer length */
+    read_buffer(reader, CAC_FILE_TAG, TEST_EMPTY_BUFFER);
+
+    /* get the VALUE buffer length */
+    read_buffer(reader, CAC_FILE_VALUE, TEST_EMPTY_BUFFER);
+
+
+    /* select the empty applet A0000000791202, which should be empty buffer */
+    select_aid(reader, applet_1202, sizeof(applet_1202));
+    coid[0] = 0x12;
+    coid[1] = 0x02;
+
+    /* get properties */
+    get_properties_coid(reader, coid, TEST_EMPTY_BUFFER);
+
+    /* get the TAG buffer length */
+    read_buffer(reader, CAC_FILE_TAG, TEST_EMPTY_BUFFER);
+
+    /* get the VALUE buffer length */
+    read_buffer(reader, CAC_FILE_VALUE, TEST_EMPTY_BUFFER);
+
+
+    /* select the empty applet A00000007902F0, which should be empty */
+    select_aid(reader, applet_02f0, sizeof(applet_02f0));
+
+    /* get properties */
+    get_properties_coid(reader, NULL, TEST_EMPTY);
+
+
+    /* select the empty applet A00000007902F1, which should be empty */
+    select_aid(reader, applet_02f1, sizeof(applet_02f1));
+
+    /* get properties */
+    get_properties_coid(reader, NULL, TEST_EMPTY);
+
+
+    /* select the empty applet A00000007902F2, which should be empty */
+    select_aid(reader, applet_02f2, sizeof(applet_02f2));
+
+    /* get properties */
+    get_properties_coid(reader, NULL, TEST_EMPTY);
+
+
+    vreader_free(reader); /* get by id ref */
+}
+
+int
+isHWTests(void)
+{
+    return hw_tests;
+}
+
+void
+setHWTests(int new_value)
+{
+    hw_tests = new_value;
+}
+
+
+/* vim: set ts=4 sw=4 tw=0 noet expandtab: */
diff --git a/tests/common.h b/tests/common.h
new file mode 100644
index 0000000..4ba2619
--- /dev/null
+++ b/tests/common.h
@@ -0,0 +1,42 @@
+/*
+ * Shared test functions for libCACard
+ *
+ * Copyright 2018 Red Hat, Inc.
+ *
+ * Author: Jakub Jelen <jjelen at redhat.com>
+ *
+ * This code is licensed under the GNU LGPL, version 2.1 or later.
+ * See the COPYING file in the top-level directory.
+ */
+#ifndef _TESTS_COMMON
+#define _TESTS_COMMON
+
+#include "libcacard.h"
+
+#define APDUBufSize 270
+
+enum {
+    TEST_PKI = 1,
+    TEST_CCC = 2,
+    TEST_ACA = 3,
+    TEST_GENERIC = 4,
+    TEST_EMPTY_BUFFER = 5,
+    TEST_EMPTY = 6,
+};
+
+void select_aid(VReader *reader, unsigned char *aid, unsigned int aid_len);
+void select_applet(VReader *reader, int type);
+
+void get_properties_coid(VReader *reader, const unsigned char coid[2], int object_type);
+void get_properties(VReader *reader, int object_type);
+
+void read_buffer(VReader *reader, uint8_t type, int object_type);
+
+void do_sign(VReader *reader);
+
+void test_empty_applets(void);
+
+int isHWTests(void);
+void setHWTests(int);
+
+#endif /* _TESTS_COMMON */
diff --git a/tests/hwtests.c b/tests/hwtests.c
new file mode 100644
index 0000000..fe64927
--- /dev/null
+++ b/tests/hwtests.c
@@ -0,0 +1,287 @@
+/*
+ * Test mirroring of CAC smart card
+ *
+ * Copyright 2018 Red Hat, Inc.
+ *
+ * Author: Jakub Jelen <jjelen at redhat.com>
+ *
+ * This code is licensed under the GNU LGPL, version 2.1 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include <glib.h>
+#include <string.h>
+#include "libcacard.h"
+#include "simpletlv.h"
+#include "common.h"
+
+#define ARGS "db=\"sql:%s\" use_hw=yes"
+#define LOGIN_PIN "77777777"
+
+static GMainLoop *loop;
+static GThread *thread;
+static guint nreaders;
+static GMutex mutex;
+static GCond cond;
+
+static gpointer
+events_thread(gpointer arg)
+{
+    unsigned int reader_id;
+    VEvent *event;
+
+    while (1) {
+        event = vevent_wait_next_vevent();
+        if (event == NULL || event->type == VEVENT_LAST) {
+            vevent_delete(event);
+            break;
+        }
+        reader_id = vreader_get_id(event->reader);
+        if (reader_id == VSCARD_UNDEFINED_READER_ID) {
+            g_mutex_lock(&mutex);
+            vreader_set_id(event->reader, nreaders++);
+            g_cond_signal(&cond);
+            g_mutex_unlock(&mutex);
+            reader_id = vreader_get_id(event->reader);
+        }
+        switch (event->type) {
+        case VEVENT_READER_INSERT:
+        case VEVENT_READER_REMOVE:
+        case VEVENT_CARD_INSERT:
+        case VEVENT_CARD_REMOVE:
+            break;
+        case VEVENT_LAST:
+        default:
+            g_warn_if_reached();
+            break;
+        }
+        vevent_delete(event);
+    }
+
+    return NULL;
+}
+
+static void libcacard_init(void)
+{
+    VCardEmulOptions *command_line_options = NULL;
+    gchar *dbdir = g_test_build_filename(G_TEST_DIST, "hwdb", NULL);
+    gchar *args = g_strdup_printf(ARGS, dbdir);
+    VCardEmulError ret;
+
+    thread = g_thread_new("test/events", events_thread, NULL);
+
+    command_line_options = vcard_emul_options(args);
+    ret = vcard_emul_init(command_line_options);
+    g_assert_cmpint(ret, ==, VCARD_EMUL_OK);
+
+    /* We test with real hardware */
+    setHWTests(1);
+
+    /* Do not assume any specific reader name here */
+
+    g_mutex_lock(&mutex);
+    while (nreaders == 0)
+        g_cond_wait(&cond, &mutex);
+    g_mutex_unlock(&mutex);
+
+    g_free(args);
+    g_free(dbdir);
+}
+
+static void test_list(void)
+{
+    VReaderList *list = vreader_get_reader_list();
+    VReaderListEntry *reader_entry;
+    int cards = 0;
+
+    for (reader_entry = vreader_list_get_first(list); reader_entry;
+         reader_entry = vreader_list_get_next(reader_entry)) {
+        VReader *r = vreader_list_get_reader(reader_entry);
+        vreader_id_t id;
+        id = vreader_get_id(r);
+        g_debug("%s: VReader name = %s, card = %d", __func__, vreader_get_name(r), vreader_card_is_present(r));
+        g_assert_cmpint(id, !=, VSCARD_UNDEFINED_READER_ID);
+        if (vreader_card_is_present(r) == VREADER_OK) {
+            cards++;
+        }
+    }
+    if (cards == 0) {
+        vreader_list_delete(list);
+        g_test_skip("No physical card found");
+        return;
+    }
+
+    g_assert_cmpint(cards, ==, 1);
+    vreader_list_delete(list);
+}
+
+static void do_login(VReader *reader)
+{
+    VReaderStatus status;
+    int dwRecvLength = APDUBufSize;
+    uint8_t pbRecvBuffer[APDUBufSize];
+    uint8_t login[] = {
+        /* VERIFY   [p1,p2=0 ]  [Lc]  [pin 77777777 ] */
+        0x00, 0x20, 0x00, 0x00, 0x08,
+        0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37
+    };
+    g_assert_nonnull(reader);
+    status = vreader_xfr_bytes(reader,
+                               login, sizeof(login),
+                               pbRecvBuffer, &dwRecvLength);
+    g_assert_cmpint(status, ==, VREADER_OK);
+    g_assert_cmphex(pbRecvBuffer[0], ==, VCARD7816_SW1_SUCCESS);
+    g_assert_cmphex(pbRecvBuffer[1], ==, 0x00);
+}
+
+static void test_passthrough_applets(void)
+{
+    uint8_t applet_person[] = {
+        /*Read Buffer  OFFSET         TYPE LENGTH */
+        0xA0, 0x00, 0x00, 0x00, 0x79, 0x02, 0x00
+    };
+    uint8_t applet_personnel[] = {
+        /*Read Buffer  OFFSET         TYPE LENGTH */
+        0xA0, 0x00, 0x00, 0x00, 0x79, 0x02, 0x01
+    };
+    uint8_t person_coid[2] = {0x02, 0x00};
+    uint8_t personnel_coid[2] = {0x02, 0x01};
+
+    VReader *reader = vreader_get_reader_by_id(0);
+
+    /* Skip the HW tests without physical card */
+    if (vreader_card_is_present(reader) != VREADER_OK) {
+        g_test_skip("No physical card found");
+        return;
+    }
+
+    /* select the Person Instance applet A0000000790200 */
+    select_aid(reader, applet_person, sizeof(applet_person));
+
+    /* get properties */
+    get_properties_coid(reader, person_coid, TEST_GENERIC);
+
+    /* These objects requires a PIN to read the value buffer */
+    do_login(reader);
+
+    /* get the TAG buffer length */
+    read_buffer(reader, CAC_FILE_TAG, TEST_GENERIC);
+
+    /* get the VALUE buffer length */
+    read_buffer(reader, CAC_FILE_VALUE, TEST_GENERIC);
+
+
+    /* select the Personnel applet A0000000790201 */
+    select_aid(reader, applet_personnel, sizeof(applet_personnel));
+
+    /* get properties */
+    get_properties_coid(reader, personnel_coid, TEST_GENERIC);
+
+    /* get the TAG buffer */
+    read_buffer(reader, CAC_FILE_TAG, TEST_GENERIC);
+
+    /* get the VALUE buffer */
+    read_buffer(reader, CAC_FILE_VALUE, TEST_GENERIC);
+
+    vreader_free(reader); /* get by id ref */
+}
+
+static void test_login(void)
+{
+    VReader *reader = vreader_get_reader_by_id(0);
+
+    /* Skip the HW tests without physical card */
+    if (vreader_card_is_present(reader) != VREADER_OK) {
+        g_test_skip("No physical card found");
+        return;
+    }
+
+    /* select the ACA */
+    select_applet(reader, TEST_ACA);
+
+    do_login(reader);
+
+    vreader_free(reader); /* get by id ref */
+}
+
+static void test_sign(void)
+{
+    VReader *reader = vreader_get_reader_by_id(0);
+
+    /* Skip the HW tests without physical card */
+    if (vreader_card_is_present(reader) != VREADER_OK) {
+        g_test_skip("No physical card found");
+        return;
+    }
+
+    /* select the ACA */
+    select_applet(reader, TEST_ACA);
+
+    do_login(reader);
+
+    /* select the PKI */
+    select_applet(reader, TEST_PKI);
+
+    /* get properties to figure out the key length */
+    get_properties(reader, TEST_PKI);
+
+    do_sign(reader);
+
+    vreader_free(reader); /* get by id ref */
+}
+
+static void test_empty_applets_hw(void) {
+
+    VReader *reader = vreader_get_reader_by_id(0);
+
+    /* Skip the HW tests without physical card */
+    if (vreader_card_is_present(reader) != VREADER_OK) {
+        vreader_free(reader);
+        g_test_skip("No physical card found");
+        return;
+    }
+
+    vreader_free(reader); /* get by id ref */
+
+    test_empty_applets();
+}
+
+static void libcacard_finalize(void)
+{
+    VReader *reader = vreader_get_reader_by_id(0);
+
+    /* This probably supposed to be a event that terminates the loop */
+    vevent_queue_vevent(vevent_new(VEVENT_LAST, reader, NULL));
+
+    /* join */
+    g_thread_join(thread);
+
+    /* Clean up */
+    vreader_free(reader);
+    vreader_free(reader);
+}
+
+int main(int argc, char *argv[])
+{
+    int ret;
+
+    g_test_init(&argc, &argv, NULL);
+
+    loop = g_main_loop_new(NULL, TRUE);
+
+    libcacard_init();
+
+    g_test_add_func("/hw-tests/list", test_list);
+    g_test_add_func("/hw-tests/passthrough-applet", test_passthrough_applets);
+    g_test_add_func("/hw-tests/login", test_login);
+    g_test_add_func("/hw-tests/sign", test_sign);
+    g_test_add_func("/hw-tests/empty-applets", test_empty_applets_hw);
+
+    ret = g_test_run();
+
+    libcacard_finalize();
+
+    return ret;
+}
+
+/* vim: set ts=4 sw=4 tw=0 noet expandtab: */
diff --git a/tests/libcacard.c b/tests/libcacard.c
index b1c5604..2aea3f0 100644
--- a/tests/libcacard.c
+++ b/tests/libcacard.c
@@ -1,7 +1,20 @@
+/*
+ * Test general functionality of software emulated smart card
+ *
+ * Copyright 2018 Red Hat, Inc.
+ *
+ * Authors:
+ *  Jakub Jelen <jjelen at redhat.com>
+ *  Marc-André Lureau <marcandre.lureau at redhat.com>
+ *
+ * This code is licensed under the GNU LGPL, version 2.1 or later.
+ * See the COPYING file in the top-level directory.
+ */
 #include <glib.h>
 #include <string.h>
 #include "libcacard.h"
 #include "simpletlv.h"
+#include "common.h"
 
 #define ARGS "db=\"sql:%s\" use_hw=no soft=(,Test,CAC,,cert1,cert2,cert3)"
 
@@ -11,13 +24,6 @@ static guint nreaders;
 static GMutex mutex;
 static GCond cond;
 
-enum {
-    TEST_PKI = 1,
-    TEST_CCC = 2,
-    TEST_ACA = 3,
-    TEST_GENERIC = 4
-};
-
 static gpointer
 events_thread(gpointer arg)
 {
@@ -130,8 +136,6 @@ static void test_card_remove_insert(void)
     vreader_free(reader); /* get by id ref */
 }
 
-#define APDUBufSize 270
-
 static void test_xfer(void)
 {
     VReader *reader = vreader_get_reader_by_id(0);
@@ -151,185 +155,6 @@ static void test_xfer(void)
     vreader_free(reader); /* get by id ref */
 }
 
-static void get_properties_coid(VReader *reader, const unsigned char coid[2],
-                                int object_type)
-{
-    int dwRecvLength = APDUBufSize;
-    VReaderStatus status;
-    uint8_t pbRecvBuffer[APDUBufSize], *p, *p_end, *p2, *p2_end;
-    uint8_t get_properties[] = {
-        /* Get properties */
-        0x80, 0x56, 0x01, 0x00, 0x00
-    };
-    uint8_t get_properties_tag[] = {
-        /* Get properties             [tag list] */
-        0x80, 0x56, 0x02, 0x00, 0x02, 0x01, 0x01, 0x00
-    };
-    int verified_pki_properties = 0;
-    int num_objects = 0, num_objects_expected = -1;
-    int have_applet_information = 0;
-
-    status = vreader_xfr_bytes(reader,
-                               get_properties, sizeof(get_properties),
-                               pbRecvBuffer, &dwRecvLength);
-    g_assert_cmpint(status, ==, VREADER_OK);
-    /* for too long Le, the cards return LE_ERROR with correct length to ask */
-    g_assert_cmpint(dwRecvLength, ==, 2);
-    g_assert_cmpint(pbRecvBuffer[dwRecvLength-2], ==, VCARD7816_SW1_LE_ERROR);
-    g_assert_cmpint(pbRecvBuffer[dwRecvLength-1], >, 0);
-
-    /* Update the APDU to match Le field from response and resend */
-    get_properties[4] = pbRecvBuffer[1];
-    dwRecvLength = APDUBufSize;
-    status = vreader_xfr_bytes(reader,
-                               get_properties, sizeof(get_properties),
-                               pbRecvBuffer, &dwRecvLength);
-    g_assert_cmpint(status, ==, VREADER_OK);
-    g_assert_cmpint(dwRecvLength, >, 2);
-    g_assert_cmpint(pbRecvBuffer[dwRecvLength-2], ==, VCARD7816_SW1_SUCCESS);
-    g_assert_cmpint(pbRecvBuffer[dwRecvLength-1], ==, 0x00);
-
-    /* try to parse the response, if it makes sense */
-    p = pbRecvBuffer;
-    p_end = p + dwRecvLength - 2;
-    while (p < p_end) {
-        uint8_t tag;
-        size_t vlen;
-        if (simpletlv_read_tag(&p, p_end - p, &tag, &vlen) < 0) {
-            g_debug("The generated SimpleTLV can not be parsed");
-            g_assert_not_reached();
-        }
-        g_debug("Tag: 0x%02x, Len: %lu", tag, vlen);
-        g_assert_cmpint(vlen, <=, p_end - p);
-
-        switch (tag) {
-        case 0x01: /* Applet Information */
-            g_assert_cmpint(vlen, ==, 5);
-            g_assert_cmphex(*p, ==, 0x10); /* Applet family */
-            have_applet_information = 1;
-            break;
-
-        case 0x40: /* Number of objects */
-            g_assert_cmpint(vlen, ==, 1);
-            if (num_objects_expected != -1) {
-                g_debug("Received multiple number-of-objects tags");
-                g_assert_not_reached();
-            }
-            num_objects_expected = *p;
-            break;
-
-        case 0x50: /* TV Object */
-        case 0x51: /* PKI Object */
-            /* recursive SimpleTLV structure */
-            p2 = p;
-            p2_end = p + vlen;
-            while (p2 < p2_end) {
-                uint8_t tag2;
-                size_t vlen2;
-                if (simpletlv_read_tag(&p2, p2_end - p2, &tag2, &vlen2) < 0) {
-                    g_debug("The generated SimpleTLV can not be parsed");
-                    g_assert_not_reached();
-                }
-                g_assert_cmpint(vlen2, <=, p2_end - p2);
-                g_debug("    Tag: 0x%02x, Len: %lu", tag2, vlen2);
-
-                switch (tag2) {
-                case 0x41: /* Object ID */
-                    g_assert_cmpmem(p2, vlen2, coid, 2);
-                    break;
-
-                case 0x42: /* Buffer properties */
-                    g_assert_cmpint(vlen2, ==, 5);
-                    if (object_type != TEST_GENERIC)
-                        g_assert_cmpint(p2[0], ==, 0x00);
-                    break;
-
-                case 0x43: /* PKI properties */
-                    /* For now, expecting 2048 b RSA keys */
-                    g_assert_cmphex(p2[0], ==, 0x06);
-                    g_assert_cmphex(p2[1], ==, (2048 / 8 / 8));
-                    g_assert_cmphex(p2[2], ==, 0x01);
-                    g_assert_cmphex(p2[3], ==, 0x01);
-                    verified_pki_properties = 1;
-                    break;
-
-                default:
-                    g_debug("Unknown tag in object: 0x%02x", tag2);
-                    g_assert_not_reached();
-                }
-                p2 += vlen2;
-            }
-            /* one more object processed */
-            num_objects++;
-            break;
-        default:
-            g_debug("Unknown tag in properties buffer: 0x%02x", tag);
-            g_assert_not_reached();
-        }
-        p += vlen;
-    }
-
-    if (num_objects_expected != -1) {
-        g_assert_cmpint(num_objects, ==, num_objects_expected);
-    }
-
-    if (object_type == TEST_PKI) {
-        g_assert_cmpint(verified_pki_properties, ==, 1);
-    }
-
-    g_assert_cmpint(have_applet_information, ==, 1);
-
-    /* Try to list only some properties */
-    dwRecvLength = APDUBufSize;
-    status = vreader_xfr_bytes(reader,
-                               get_properties_tag, sizeof(get_properties_tag),
-                               pbRecvBuffer, &dwRecvLength);
-    g_assert_cmpint(status, ==, VREADER_OK);
-    g_assert_cmpint(dwRecvLength, ==, 2);
-    g_assert_cmpint(pbRecvBuffer[0], ==, VCARD7816_SW1_LE_ERROR);
-    g_assert_cmpint(pbRecvBuffer[1], ==, 0x0e); /* Two applet information buffers */
-
-    /* Update the APDU to match Le field from response and resend */
-    get_properties_tag[7] = pbRecvBuffer[1];
-    dwRecvLength = APDUBufSize;
-    status = vreader_xfr_bytes(reader,
-                               get_properties_tag, sizeof(get_properties_tag),
-                               pbRecvBuffer, &dwRecvLength);
-    g_assert_cmpint(status, ==, VREADER_OK);
-    g_assert_cmpint(dwRecvLength, ==, 16); /* Two applet information buffers + status */
-    g_assert_cmpint(pbRecvBuffer[dwRecvLength-2], ==, VCARD7816_SW1_SUCCESS);
-    g_assert_cmpint(pbRecvBuffer[dwRecvLength-1], ==, 0x00);
-}
-
-static void get_properties(VReader *reader, int object_type)
-{
-    unsigned char coid[2];
-    switch (object_type) {
-    case TEST_PKI:
-        // XXX only the first PKI for now
-        coid[0] = 0x01;
-        coid[1] = 0x00;
-        get_properties_coid(reader, coid, object_type);
-        break;
-
-    case TEST_CCC:
-        coid[0] = 0xDB;
-        coid[1] = 0x00;
-        get_properties_coid(reader, coid, object_type);
-        break;
-
-    case TEST_ACA:
-        coid[0] = 0x03;
-        coid[1] = 0x00;
-        get_properties_coid(reader, coid, object_type);
-        break;
-
-    default:
-        g_debug("Got unknown object type");
-        g_assert_not_reached();
-    }
-}
-
 static void parse_acr(uint8_t *buf, int buflen)
 {
     uint8_t *p, *p_end;
@@ -565,151 +390,6 @@ static void get_acr(VReader *reader)
     parse_acr(pbRecvBuffer, dwRecvLength);
 }
 
-static void read_buffer(VReader *reader, uint8_t type, int object_type)
-{
-    int dwRecvLength = APDUBufSize, dwLength, dwReadLength, offset;
-    VReaderStatus status;
-    uint8_t pbRecvBuffer[APDUBufSize];
-    uint8_t *data;
-    uint8_t read_buffer[] = {
-        /*Read Buffer  OFFSET         TYPE LENGTH a_Le */
-        0x80, 0x52, 0x00, 0x00, 0x02, 0x01, 0x02, 0x02
-    };
-    int card_urls = 0;
-
-    dwRecvLength = 4;
-    read_buffer[5] = type;
-    status = vreader_xfr_bytes(reader,
-                               read_buffer, sizeof(read_buffer),
-                               pbRecvBuffer, &dwRecvLength);
-    g_assert_cmpint(status, ==, VREADER_OK);
-    g_assert_cmpint(dwRecvLength, ==, 4);
-    g_assert_cmphex(pbRecvBuffer[dwRecvLength-2], ==, VCARD7816_SW1_SUCCESS);
-    g_assert_cmphex(pbRecvBuffer[dwRecvLength-1], ==, 0x00);
-
-    dwLength = (pbRecvBuffer[0] & 0xff) | ((pbRecvBuffer[1] << 8) & 0xff);
-    if (dwLength == 0)
-        return;
-
-    data = g_malloc(dwLength);
-    offset = 0x02;
-    do {
-        dwReadLength = MIN(255, dwLength);
-        dwRecvLength = dwReadLength+2;
-        read_buffer[2] = (unsigned char) ((offset >> 8) & 0xff);
-        read_buffer[3] = (unsigned char) (offset & 0xff);
-        read_buffer[6] = (unsigned char) (dwReadLength);
-        read_buffer[7] = (unsigned char) (dwReadLength);
-        status = vreader_xfr_bytes(reader,
-                                   read_buffer, sizeof(read_buffer),
-                                   pbRecvBuffer, &dwRecvLength);
-        g_assert_cmpint(status, ==, VREADER_OK);
-        g_assert_cmpint(dwRecvLength, ==, dwReadLength + 2);
-        g_assert_cmphex(pbRecvBuffer[dwRecvLength-2], ==, VCARD7816_SW1_SUCCESS);
-        g_assert_cmphex(pbRecvBuffer[dwRecvLength-1], ==, 0x00);
-
-        memcpy(data + offset - 2, pbRecvBuffer, dwReadLength);
-        offset += dwLength;
-        dwLength -= dwReadLength;
-    } while (dwLength != 0);
-
-    /* Try to parse the TAG buffer, if it makes sense */
-    if (type == CAC_FILE_TAG) {
-        uint8_t *p = data;
-        uint8_t *p_end = p + offset - 2;
-        while (p < p_end) {
-            uint8_t tag;
-            size_t vlen;
-            if (simpletlv_read_tag(&p, p_end - p, &tag, &vlen) < 0) {
-                g_debug("The generated SimpleTLV can not be parsed");
-                g_assert_not_reached();
-            }
-            g_debug("Tag: 0x%02x, Len: %lu", tag, vlen);
-
-            switch (tag) {
-            case 0xF3: /* CardURL from CCC */
-                if (object_type == TEST_CCC) {
-                    card_urls++;
-                } else {
-                    g_debug("CardURLs found outside of CCC buffer");
-                    g_assert_not_reached();
-                }
-                break;
-            default:
-                break;
-            }
-        }
-        if (object_type == TEST_CCC)
-            g_assert_cmpint(card_urls, ==, 11 + 3);
-    }
-    g_free(data);
-}
-
-static void select_aid(VReader *reader, unsigned char *aid, unsigned int aid_len)
-{
-    VReaderStatus status;
-    int dwRecvLength = APDUBufSize;
-    uint8_t pbRecvBuffer[APDUBufSize];
-    uint8_t selfile[] = {
-        0x00, 0xa4, 0x04, 0x00, 0x07, 0xa0, 0x00, 0x00, 0x00, 0x79, 0x01, 0x00
-    };
-    size_t selfile_len = sizeof(selfile);
-
-    g_assert_cmpint(aid_len, ==, 7);
-    memcpy(&selfile[5], aid, aid_len);
-
-    g_debug("%s: Add applet with AID 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x",
-        __func__, aid[0], aid[1], aid[2], aid[3], aid[4], aid[5], aid[6]);
-    g_assert_nonnull(reader);
-    status = vreader_xfr_bytes(reader,
-                               selfile, selfile_len,
-                               pbRecvBuffer, &dwRecvLength);
-    g_assert_cmpint(status, ==, VREADER_OK);
-    g_assert_cmphex(pbRecvBuffer[dwRecvLength-2], ==, VCARD7816_SW1_RESPONSE_BYTES);
-    g_assert_cmphex(pbRecvBuffer[dwRecvLength-1], >, 0);
-}
-
-static void select_applet(VReader *reader, int type)
-{
-    uint8_t selfile_ccc[] = {
-        /* Select CCC Applet */
-        0xa0, 0x00, 0x00, 0x01, 0x16, 0xDB, 0x00
-    };
-    uint8_t selfile_aca[] = {
-        /* Select ACA Applet */
-        0xa0, 0x00, 0x00, 0x00, 0x79, 0x03, 0x00
-    };
-    uint8_t selfile_pki[] = {
-        /* Select first PKI Applet */
-        0xa0, 0x00, 0x00, 0x00, 0x79, 0x01, 0x00
-    };
-    uint8_t *aid = NULL;
-    size_t aid_len = 0;
-
-    switch (type) {
-    case TEST_PKI:
-        aid = selfile_pki;
-        aid_len = sizeof(selfile_pki);
-        break;
-
-    case TEST_CCC:
-        aid = selfile_ccc;
-        aid_len = sizeof(selfile_ccc);
-        break;
-
-    case TEST_ACA:
-        aid = selfile_aca;
-        aid_len = sizeof(selfile_aca);
-        break;
-
-    default:
-        g_assert_not_reached();
-    }
-    g_assert_nonnull(aid);
-
-    select_aid(reader, aid, aid_len);
-}
-
 static void do_login(VReader *reader)
 {
     VReaderStatus status;
@@ -728,56 +408,6 @@ static void do_login(VReader *reader)
     g_assert_cmphex(pbRecvBuffer[1], ==, 0x00);
 }
 
-static void do_sign(VReader *reader)
-{
-    VReaderStatus status;
-    int dwRecvLength = APDUBufSize;
-    uint8_t pbRecvBuffer[APDUBufSize];
-    uint8_t sign[] = {
-        /* VERIFY   [p1,p2=0 ]  [Lc            ]  [ 256 bytes of PKCS#1.5 padded data ... ] */
-        0x80, 0x42, 0x00, 0x00, 0x00, 0x01, 0x00,
-0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-0xff, 0xff, 0x00, 0x64, 0x61, 0x74, 0x61, 0x20, 0x74, 0x6f, 0x20, 0x73, 0x69, 0x67, 0x6e, 0x20,
-0x28, 0x6d, 0x61, 0x78, 0x20, 0x31, 0x30, 0x30, 0x20, 0x62, 0x79, 0x74, 0x65, 0x73, 0x29, 0x0a
-    };
-    uint8_t getresp[] = {
-        /* Get Response (max we can get) */
-        0x00, 0xc0, 0x00, 0x00, 0x00
-    };
-    g_assert_nonnull(reader);
-    status = vreader_xfr_bytes(reader,
-                               sign, sizeof(sign),
-                               pbRecvBuffer, &dwRecvLength);
-    g_assert_cmpint(status, ==, VREADER_OK);
-    g_assert_cmphex(pbRecvBuffer[dwRecvLength-2], ==, VCARD7816_SW1_RESPONSE_BYTES);
-    g_assert_cmphex(pbRecvBuffer[dwRecvLength-1], ==, 0x00);
-
-
-    /* fetch the actual response */
-    dwRecvLength = APDUBufSize;
-    status = vreader_xfr_bytes(reader,
-                               getresp, sizeof(getresp),
-                               pbRecvBuffer, &dwRecvLength);
-    g_assert_cmpint(status, ==, VREADER_OK);
-    g_assert_cmpint(dwRecvLength, ==, 258);
-    g_assert_cmphex(pbRecvBuffer[dwRecvLength-2], ==, VCARD7816_SW1_SUCCESS);
-    g_assert_cmphex(pbRecvBuffer[dwRecvLength-1], ==, 0x00);
-
-}
-
 static void test_cac_pki(void)
 {
     VReader *reader = vreader_get_reader_by_id(0);
@@ -923,30 +553,6 @@ static void test_get_response(void)
     vreader_free(reader); /* get by id ref */
 }
 
-static void test_other_applets(void)
-{
-    uint8_t applet_02fb[] = {
-        /*Read Buffer  OFFSET         TYPE LENGTH */
-        0xA0, 0x00, 0x00, 0x00, 0x79, 0x02, 0xFB
-    };
-    uint8_t coid[2] = {0x02, 0xFB};
-    VReader *reader = vreader_get_reader_by_id(0);
-
-    /* select the empty applet A00000007902FB, which should be empty*/
-    select_aid(reader, applet_02fb, sizeof(applet_02fb));
-
-    /* get properties */
-    get_properties_coid(reader, coid, TEST_GENERIC);
-
-    /* get the TAG buffer length */
-    read_buffer(reader, CAC_FILE_TAG, TEST_GENERIC);
-
-    /* get the VALUE buffer length */
-    read_buffer(reader, CAC_FILE_VALUE, TEST_GENERIC);
-
-    vreader_free(reader); /* get by id ref */
-}
-
 static void libcacard_finalize(void)
 {
     VReader *reader = vreader_get_reader_by_id(0);
@@ -981,7 +587,7 @@ int main(int argc, char *argv[])
     g_test_add_func("/libcacard/get-response", test_get_response);
     g_test_add_func("/libcacard/login", test_login);
     g_test_add_func("/libcacard/sign", test_sign);
-    g_test_add_func("/libcacard/other-applets", test_other_applets);
+    g_test_add_func("/libcacard/empty-applets", test_empty_applets);
     g_test_add_func("/libcacard/remove", test_remove);
 
     ret = g_test_run();
-- 
2.17.1



More information about the Spice-devel mailing list