* 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@xxxxxxxxxx> Reviewed-by: Robert Relyea <rrelyea@xxxxxxxxxx> --- 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@xxxxxxxxxx> + * + * 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@xxxxxxxxxx> + * + * 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@xxxxxxxxxx> + * + * 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@xxxxxxxxxx> + * Marc-André Lureau <marcandre.lureau@xxxxxxxxxx> + * + * 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 _______________________________________________ Spice-devel mailing list Spice-devel@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/spice-devel