[Spice-devel] [PATCH libcacard 39/45] tests: Negative test cases to increase coverage

Jakub Jelen jjelen at redhat.com
Tue Jul 31 14:50:33 UTC 2018


 * mostly negative test cases that were missed during initial implementation
   * passthrough and empty applets
   * multi-part signatures
   * check login count
   * invalid GET PROPERTIES APDU queries
   * invalid SELECT APDU queries
   * invalid instructions
   * invalid READ BUFFER APDU queries
   * invalid GET ACR APDU queries
 * properly clean up the memory when the test is finished

Signed-off-by: Jakub Jelen <jjelen at redhat.com>
Reviewed-by: Robert Relyea <rrelyea at redhat.com>
---
 tests/common.c    | 108 ++++++++++-
 tests/common.h    |   5 +-
 tests/hwtests.c   |  44 ++++-
 tests/libcacard.c | 468 +++++++++++++++++++++++++++++++++++++++++++++-
 4 files changed, 605 insertions(+), 20 deletions(-)

diff --git a/tests/common.c b/tests/common.c
index a70ec89..ee10af8 100644
--- a/tests/common.c
+++ b/tests/common.c
@@ -351,8 +351,6 @@ void read_buffer(VReader *reader, uint8_t type, int object_type)
     g_assert_cmphex(pbRecvBuffer[dwRecvLength-1], ==, 0x00);
 
     dwLength = (pbRecvBuffer[0] & 0xff) | ((pbRecvBuffer[1] << 8) & 0xff);
-    if (object_type != TEST_EMPTY_BUFFER)
-        g_assert_cmpint(dwLength, !=, 0);
     if (dwLength == 0)
         return;
 
@@ -424,6 +422,13 @@ void select_applet(VReader *reader, int type)
         /* Select first PKI Applet */
         0xa0, 0x00, 0x00, 0x00, 0x79, 0x01, 0x00
     };
+    uint8_t selfile_passthrough[] = {
+        /* Select Person Instance (passthrough) */
+        0xa0, 0x00, 0x00, 0x00, 0x79, 0x02, 0x00
+    };
+    uint8_t selfile_empty[] = {
+        0xA0, 0x00, 0x00, 0x00, 0x79, 0x02, 0xF0
+    };
     uint8_t *aid = NULL;
     size_t aid_len = 0;
 
@@ -443,6 +448,16 @@ void select_applet(VReader *reader, int type)
         aid_len = sizeof(selfile_aca);
         break;
 
+    case TEST_PASSTHROUGH:
+        aid = selfile_passthrough;
+        aid_len = sizeof(selfile_passthrough);
+        break;
+
+    case TEST_EMPTY:
+        aid = selfile_empty;
+        aid_len = sizeof(selfile_empty);
+        break;
+
     default:
         g_assert_not_reached();
     }
@@ -451,7 +466,7 @@ void select_applet(VReader *reader, int type)
     select_aid(reader, aid, aid_len);
 }
 
-void do_sign(VReader *reader)
+void do_sign(VReader *reader, int parts)
 {
     VReaderStatus status;
     int dwRecvLength = APDUBufSize;
@@ -492,6 +507,37 @@ void do_sign(VReader *reader)
         sign_len = 5 + key_bits/8;
     }
 
+    /* The driver supports signatures while data are passed in more separate APDUs */
+    if (parts) {
+        int split = 0x47;
+        /* we have not sent the whole buffer */
+        sign[2] = 0x80;
+        sign[4] = split;
+        sign[5] = 0x00;
+        sign[6] = 0x01;
+        sign[7] = 0xFF;
+        sign[8] = 0xFF;
+        sign_len = 5 + split;
+
+        status = vreader_xfr_bytes(reader,
+                                   sign, sign_len,
+                                   pbRecvBuffer, &dwRecvLength);
+        g_assert_cmpint(status, ==, VREADER_OK);
+        g_assert_cmpint(dwRecvLength, ==, 2);
+        g_assert_cmphex(pbRecvBuffer[dwRecvLength-2], ==, VCARD7816_SW1_SUCCESS);
+        g_assert_cmphex(pbRecvBuffer[dwRecvLength-1], ==, 0x00);
+
+        /* the next message will send the rest of the buffer */
+        sign[2] = 0x00;
+        if (key_bits)
+            sign[4] = key_bits/8 - split;
+        else
+            sign[4] = 256 - split;
+        memmove(&sign[5], &sign[5+2+split], sign[4]);
+        sign_len = 5 + sign[4];
+    }
+
+    dwRecvLength = APDUBufSize;
     status = vreader_xfr_bytes(reader,
                                sign, sign_len,
                                pbRecvBuffer, &dwRecvLength);
@@ -629,6 +675,16 @@ void test_get_response(void)
     /* select CCC */
     select_applet(reader, TEST_CCC);
 
+    /* read buffer without response buffer. Ignore the response. */
+    dwRecvLength = 2;
+    status = vreader_xfr_bytes(reader,
+                               read_buffer, sizeof(read_buffer),
+                               pbRecvBuffer, &dwRecvLength);
+    g_assert_cmpint(status, ==, VREADER_OK);
+    g_assert_cmpint(dwRecvLength, ==, 2);
+    g_assert_cmpint(pbRecvBuffer[0], ==, VCARD7816_SW1_RESPONSE_BYTES);
+    g_assert_cmpint(pbRecvBuffer[1], ==, 0x02);
+
     /* read buffer without response buffer */
     dwRecvLength = 2;
     status = vreader_xfr_bytes(reader,
@@ -674,10 +730,54 @@ void test_get_response(void)
     g_assert_cmphex(pbRecvBuffer[dwRecvLength-2], ==, VCARD7816_SW1_SUCCESS);
     g_assert_cmphex(pbRecvBuffer[dwRecvLength-1], ==, 0x00);
 
-    g_assert_cmpint(dwLength, ==, 0x34);
+    /* If we ask again, when there is no pending response */
+    dwRecvLength = dwLength + 2;
+    getresp[4] = dwLength;
+    status = vreader_xfr_bytes(reader,
+                               getresp, sizeof(getresp),
+                               pbRecvBuffer, &dwRecvLength);
+    g_assert_cmpint(status, ==, VREADER_OK);
+    g_assert_cmpint(dwRecvLength, ==, 2);
+    g_assert_cmphex(pbRecvBuffer[dwRecvLength-2], ==, VCARD7816_SW1_P1_P2_ERROR);
+    g_assert_cmphex(pbRecvBuffer[dwRecvLength-1], ==, 0x88);
+
     vreader_free(reader); /* get by id ref */
 }
 
+void check_login_count(void)
+{
+    VReader *reader = vreader_get_reader_by_id(0);
+    VReaderStatus status;
+    int dwRecvLength = APDUBufSize;
+    uint8_t pbRecvBuffer[APDUBufSize];
+    uint8_t login[] = {
+        /* VERIFY   [p1,p2=0 ]  [Lc] */
+        0x00, 0x20, 0x00, 0x00, 0x00
+    };
+    g_assert_nonnull(reader);
+
+    /* Get login count */
+    status = vreader_xfr_bytes(reader,
+                               login, sizeof(login),
+                               pbRecvBuffer, &dwRecvLength);
+    g_assert_cmpint(status, ==, VREADER_OK);
+    /* NSS does not know how to do this yet */
+    g_assert_cmphex(pbRecvBuffer[0], ==, VCARD7816_SW1_P1_P2_ERROR);
+    g_assert_cmphex(pbRecvBuffer[1], ==, 0x88);
+
+    /* P1 = 0x01 is invalid */
+    login[2] = 0x01;
+    status = vreader_xfr_bytes(reader,
+                               login, sizeof(login),
+                               pbRecvBuffer, &dwRecvLength);
+    g_assert_cmpint(status, ==, VREADER_OK);
+    g_assert_cmphex(pbRecvBuffer[0], ==, VCARD7816_SW1_P1_P2_ERROR);
+    g_assert_cmphex(pbRecvBuffer[1], ==, 0x00);
+
+    vreader_free(reader);
+}
+
+
 int
 isHWTests(void)
 {
diff --git a/tests/common.h b/tests/common.h
index c02ea6b..611bc3f 100644
--- a/tests/common.h
+++ b/tests/common.h
@@ -22,6 +22,7 @@ enum {
     TEST_GENERIC = 4,
     TEST_EMPTY_BUFFER = 5,
     TEST_EMPTY = 6,
+    TEST_PASSTHROUGH = 7,
 };
 
 void select_coid_good(VReader *reader, unsigned char *coid);
@@ -37,12 +38,14 @@ 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 do_sign(VReader *reader, int parts);
 
 void test_empty_applets(void);
 
 void test_get_response(void);
 
+void check_login_count(void);
+
 int isHWTests(void);
 void setHWTests(int);
 
diff --git a/tests/hwtests.c b/tests/hwtests.c
index 1e35a9b..e357ea2 100644
--- a/tests/hwtests.c
+++ b/tests/hwtests.c
@@ -32,7 +32,8 @@ events_thread(gpointer arg)
 
     while (1) {
         event = vevent_wait_next_vevent();
-        if (event == NULL) {
+        if (event == NULL || event->type == VEVENT_LAST) {
+            vevent_delete(event);
             break;
         }
         reader_id = vreader_get_id(event->reader);
@@ -106,6 +107,7 @@ static void test_list(void)
         vreader_free(r);
     }
     if (cards == 0) {
+        vreader_list_delete(list);
         g_test_skip("No physical card found");
         return;
     }
@@ -122,11 +124,21 @@ static void do_login(VReader *reader)
     uint8_t login[] = {
         /* VERIFY   [p1,p2=0 ]  [Lc]  [pin 77777777 ] */
         0x00, 0x20, 0x00, 0x00, 0x08,
-        0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37
+        //0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
     };
+    int login_len, pin_len;
+
     g_assert_nonnull(reader);
+
+    /* Set the pin from constant */
+    pin_len = strlen(LOGIN_PIN);
+    login[4] = pin_len;
+    memcpy(&login[5], LOGIN_PIN, pin_len);
+    login_len = 5 + pin_len;
+
     status = vreader_xfr_bytes(reader,
-                               login, sizeof(login),
+                               login, login_len,
                                pbRecvBuffer, &dwRecvLength);
     g_assert_cmpint(status, ==, VREADER_OK);
     g_assert_cmphex(pbRecvBuffer[0], ==, VCARD7816_SW1_SUCCESS);
@@ -227,7 +239,10 @@ static void test_sign(void)
     /* get properties to figure out the key length */
     get_properties(reader, TEST_PKI);
 
-    do_sign(reader);
+    do_sign(reader, 0);
+
+    /* test also multipart signatures */
+    do_sign(reader, 1);
 
     vreader_free(reader); /* get by id ref */
 }
@@ -345,6 +360,21 @@ static void test_sign_bad_data_x509(void)
     vreader_free(reader); /* get by id ref */
 }
 
+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;
@@ -358,6 +388,7 @@ int main(int argc, char *argv[])
     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/check-login-count", check_login_count);
     g_test_add_func("/hw-tests/sign", test_sign);
     g_test_add_func("/hw-tests/sign-bad-data", test_sign_bad_data_x509);
     g_test_add_func("/hw-tests/empty-applets", test_empty_applets_hw);
@@ -365,10 +396,7 @@ int main(int argc, char *argv[])
 
     ret = g_test_run();
 
-    g_main_loop_unref(loop);
-
-    /* FIXME: no wait to queue a NULL event */
-    /* g_thread_join(thread); */
+    libcacard_finalize();
 
     return ret;
 }
diff --git a/tests/libcacard.c b/tests/libcacard.c
index cd08a54..eb3ad49 100644
--- a/tests/libcacard.c
+++ b/tests/libcacard.c
@@ -4,8 +4,8 @@
  * Copyright 2018 Red Hat, Inc.
  *
  * Authors:
- *  Jakub Jelen <jjelen at redhat.com>
  *  Marc-André Lureau <marcandre.lureau at redhat.com>
+ *  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.
@@ -32,7 +32,8 @@ events_thread(gpointer arg)
 
     while (1) {
         event = vevent_wait_next_vevent();
-        if (event == NULL) {
+        if (event == NULL || event->type == VEVENT_LAST) {
+            vevent_delete(event);
             break;
         }
         reader_id = vreader_get_id(event->reader);
@@ -103,6 +104,7 @@ static void test_list(void)
         if (vreader_card_is_present(r) == VREADER_OK) {
             cards++;
         }
+        vreader_free(r);
     }
     g_assert_cmpint(cards, ==, 1);
     vreader_list_delete(list);
@@ -540,7 +542,10 @@ static void test_sign(void)
     /* select the PKI */
     select_applet(reader, TEST_PKI);
 
-    do_sign(reader);
+    do_sign(reader, 0);
+
+    /* test also multipart signatures */
+    do_sign(reader, 1);
 
     vreader_free(reader); /* get by id ref */
 }
@@ -555,7 +560,7 @@ static void test_remove(void)
     status = vreader_remove_reader(reader);
     g_assert_cmpint(status, ==, VREADER_OK);
     vreader_free(reader); /* get by id ref */
-    vreader_free(reader);
+    //vreader_free(reader);
 
     reader = vreader_get_reader_by_id(0);
     g_assert_null(reader);
@@ -613,6 +618,10 @@ static void test_gp_applet(void)
         /* Get Response (max we can get) */
         0x00, 0xc0, 0x00, 0x00, 0x00
     };
+    uint8_t getdata[] = {
+        /* Get Response (max we can get) */
+        0x00, 0xca, 0x9f, 0x7f, 0x00
+    };
     VReader *reader = vreader_get_reader_by_id(0);
 
     /* select GP and wait for the response bytes */
@@ -632,8 +641,447 @@ static void test_gp_applet(void)
      * in select_aid()
      */
 
+    /* ask the applet for some data */
+    dwRecvLength = APDUBufSize;
+    status = vreader_xfr_bytes(reader,
+                               getdata, sizeof(getdata),
+                               pbRecvBuffer, &dwRecvLength);
+    g_assert_cmpint(status, ==, VREADER_OK);
+    g_assert_cmpint(dwRecvLength, ==, 0x2F);
+    g_assert_cmpint(pbRecvBuffer[dwRecvLength-2], ==, VCARD7816_SW1_SUCCESS);
+    g_assert_cmpint(pbRecvBuffer[dwRecvLength-1], ==, 0x00);
+
+    vreader_free(reader); /* get by id ref */
+}
+
+static void test_invalid_properties(void)
+{
+    VReader *reader = vreader_get_reader_by_id(0);
+    VReaderStatus status;
+    int dwRecvLength = APDUBufSize;
+    uint8_t pbRecvBuffer[APDUBufSize];
+    uint8_t get_properties[] = {
+        /* Get properties       [Le]  [RFU] */
+        0x80, 0x56, 0x01, 0x00, 0x00, 0x00, 0x00
+    };
+    size_t get_properties_len = 5;
+
+    g_assert_nonnull(reader);
+
+    select_applet(reader, TEST_CCC);
+
+    /* P1 = 0x00 is not supported */
+    get_properties[2] = 0x00;
+    dwRecvLength = APDUBufSize;
+    status = vreader_xfr_bytes(reader,
+                               get_properties, get_properties_len,
+                               pbRecvBuffer, &dwRecvLength);
+    g_assert_cmpint(status, ==, VREADER_OK);
+    g_assert_cmpint(dwRecvLength, ==, 2);
+    g_assert_cmpint(pbRecvBuffer[0], ==, VCARD7816_SW1_P1_P2_ERROR);
+    g_assert_cmpint(pbRecvBuffer[1], ==, 0x86);
+    get_properties[2] = 0x01;
+
+    /* P1 = 0x01 fails with additional data provided */
+    get_properties[2] = 0x01;
+    get_properties[4] = 0x02;
+    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[0], ==, VCARD7816_SW1_COMMAND_ERROR);
+    g_assert_cmpint(pbRecvBuffer[1], ==, 0x84);
+    get_properties[2] = 0x01;
+
+    /* P2 needs to be zero */
+    get_properties[3] = 0x01;
+    get_properties[4] = 0x00;
+    dwRecvLength = APDUBufSize;
+    status = vreader_xfr_bytes(reader,
+                               get_properties, get_properties_len,
+                               pbRecvBuffer, &dwRecvLength);
+    g_assert_cmpint(status, ==, VREADER_OK);
+    g_assert_cmpint(dwRecvLength, ==, 2);
+    g_assert_cmpint(pbRecvBuffer[0], ==, VCARD7816_SW1_P1_P2_ERROR);
+    g_assert_cmpint(pbRecvBuffer[1], ==, 0x86);
+    get_properties[3] = 0x00;
+
+    /* P1 = 0x02 requires some data (empty is invalid) */
+    get_properties[2] = 0x02;
+    dwRecvLength = APDUBufSize;
+    status = vreader_xfr_bytes(reader,
+                               get_properties, get_properties_len,
+                               pbRecvBuffer, &dwRecvLength);
+    g_assert_cmpint(status, ==, VREADER_OK);
+    g_assert_cmpint(dwRecvLength, ==, 2);
+    g_assert_cmpint(pbRecvBuffer[0], ==, VCARD7816_SW1_COMMAND_ERROR);
+    g_assert_cmpint(pbRecvBuffer[1], ==, 0x84);
+
+    /* P1 = 0x02 with invalid data fails */
+    get_properties[4] = 0x02;
+    get_properties[6] = 0xFF;
+    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[0], ==, VCARD7816_SW1_P1_P2_ERROR);
+    g_assert_cmpint(pbRecvBuffer[1], ==, 0x88);
+
+    /* P1 = 0x88 is invalid */
+    get_properties[2] = 0x88;
+    dwRecvLength = APDUBufSize;
+    status = vreader_xfr_bytes(reader,
+                               get_properties, get_properties_len,
+                               pbRecvBuffer, &dwRecvLength);
+    g_assert_cmpint(status, ==, VREADER_OK);
+    g_assert_cmpint(dwRecvLength, ==, 2);
+    g_assert_cmpint(pbRecvBuffer[0], ==, VCARD7816_SW1_P1_P2_ERROR);
+    g_assert_cmpint(pbRecvBuffer[1], ==, 0x86);
+
+    vreader_free(reader); /* get by id ref */
+}
+
+static void test_invalid_select(void)
+{
+    VReader *reader = vreader_get_reader_by_id(0);
+    VReaderStatus status;
+    int dwRecvLength = APDUBufSize;
+    uint8_t pbRecvBuffer[APDUBufSize];
+    uint8_t selfile[] = {
+        0x00, 0xa4, 0x02, 0x00, 0x07, 0xa0, 0x00, 0x00, 0x00, 0x79, 0x01, 0x00
+    };
+
+    g_assert_nonnull(reader);
+
+    select_applet(reader, TEST_CCC);
+
+    /* CAC applets handle only the P1 = 0x02: Empty OID is not valid */
+    selfile[4] = 0x00;
+    dwRecvLength = APDUBufSize;
+    status = vreader_xfr_bytes(reader,
+                               selfile, 5,
+                               pbRecvBuffer, &dwRecvLength);
+    g_assert_cmpint(status, ==, VREADER_OK);
+    g_assert_cmpint(dwRecvLength, ==, 2);
+    g_assert_cmpint(pbRecvBuffer[0], ==, VCARD7816_SW1_COMMAND_ERROR);
+    g_assert_cmpint(pbRecvBuffer[1], ==, 0x84);
+
+    /* CAC applets handle only the P1 = 0x02: 7B OID is not valid */
+    selfile[4] = 0x07;
+    dwRecvLength = APDUBufSize;
+    status = vreader_xfr_bytes(reader,
+                               selfile, sizeof(selfile),
+                               pbRecvBuffer, &dwRecvLength);
+    g_assert_cmpint(status, ==, VREADER_OK);
+    g_assert_cmpint(dwRecvLength, ==, 2);
+    g_assert_cmpint(pbRecvBuffer[0], ==, VCARD7816_SW1_COMMAND_ERROR);
+    g_assert_cmpint(pbRecvBuffer[1], ==, 0x84);
+
+    /* TODO check the iso7816 code handling the remaining SELECT APDUs */
+
+    vreader_free(reader); /* get by id ref */
+}
+
+static void test_invalid_instruction(void)
+{
+    VReader *reader = vreader_get_reader_by_id(0);
+    VReaderStatus status;
+    int dwRecvLength = APDUBufSize;
+    uint8_t pbRecvBuffer[APDUBufSize];
+    uint8_t apdu[] = {
+        0x00, 0xff, 0x00, 0x00, 0x00
+    };
+
+    g_assert_nonnull(reader);
+
+    /* Card Capability Container */
+    select_applet(reader, TEST_CCC);
+
+    /* 0xFF is invalid instruction everywhere, but fails in apdu_ins_to_string() */
+    /*dwRecvLength = APDUBufSize;
+    status = vreader_xfr_bytes(reader,
+                               apdu, sizeof(apdu),
+                               pbRecvBuffer, &dwRecvLength);
+    g_assert_cmpint(status, ==, VREADER_OK);
+    g_assert_cmpint(dwRecvLength, ==, 2);
+    g_assert_cmpint(pbRecvBuffer[0], ==, VCARD7816_SW1_INS_ERROR);
+    g_assert_cmpint(pbRecvBuffer[1], ==, 0x00);*/
+
+    /* CCC Applet does not know GET ACR instruction */
+    apdu[1] = 0x4c;
+    dwRecvLength = APDUBufSize;
+    status = vreader_xfr_bytes(reader,
+                               apdu, sizeof(apdu),
+                               pbRecvBuffer, &dwRecvLength);
+    g_assert_cmpint(status, ==, VREADER_OK);
+    g_assert_cmpint(dwRecvLength, ==, 2);
+    g_assert_cmpint(pbRecvBuffer[0], ==, VCARD7816_SW1_INS_ERROR);
+    g_assert_cmpint(pbRecvBuffer[1], ==, 0x00);
+
+    /* TODO check the iso7816 code handling the remaining SELECT APDUs */
+
+
+    /* PKI Applet */
+    select_applet(reader, TEST_PKI);
+
+    /* Update Buffer is not supported */
+    apdu[1] = 0x58;
+    dwRecvLength = APDUBufSize;
+    status = vreader_xfr_bytes(reader,
+                               apdu, sizeof(apdu),
+                               pbRecvBuffer, &dwRecvLength);
+    g_assert_cmpint(status, ==, VREADER_OK);
+    g_assert_cmpint(dwRecvLength, ==, 2);
+    g_assert_cmpint(pbRecvBuffer[0], ==, VCARD7816_SW1_COMMAND_ERROR);
+    g_assert_cmpint(pbRecvBuffer[1], ==, 0x85);
+
+    vreader_free(reader); /* get by id ref */
+}
+
+static void test_invalid_read_buffer_applet(VReader *reader, int object_type)
+{
+
+    VReaderStatus status;
+    int dwRecvLength = APDUBufSize;
+    uint8_t pbRecvBuffer[APDUBufSize];
+    uint8_t apdu[] = {
+        0x00, 0x52, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00
+    };
+    int apdu_len;
+
+    select_applet(reader, object_type);
+
+    /* Empty body is not accepted */
+    apdu[4] = 0x00;
+    apdu_len = 5;
+    dwRecvLength = APDUBufSize;
+    status = vreader_xfr_bytes(reader,
+                               apdu, apdu_len,
+                               pbRecvBuffer, &dwRecvLength);
+    g_assert_cmpint(status, ==, VREADER_OK);
+    g_assert_cmpint(dwRecvLength, ==, 2);
+    g_assert_cmpint(pbRecvBuffer[0], ==, VCARD7816_SW1_COMMAND_ERROR);
+    g_assert_cmpint(pbRecvBuffer[1], ==, 0x84);
+
+    /* 4B is too much */
+    apdu[4] = 0x04;
+    apdu_len = 9;
+    dwRecvLength = APDUBufSize;
+    status = vreader_xfr_bytes(reader,
+                               apdu, apdu_len,
+                               pbRecvBuffer, &dwRecvLength);
+    g_assert_cmpint(status, ==, VREADER_OK);
+    g_assert_cmpint(dwRecvLength, ==, 2);
+    g_assert_cmpint(pbRecvBuffer[0], ==, VCARD7816_SW1_COMMAND_ERROR);
+    g_assert_cmpint(pbRecvBuffer[1], ==, 0x84);
+
+    /* The first byte is invalid (nor tag, nor value) */
+    apdu[4] = 0x02;
+    apdu[5] = 0x06;
+    apdu_len = 7;
+    dwRecvLength = APDUBufSize;
+    status = vreader_xfr_bytes(reader,
+                               apdu, apdu_len,
+                               pbRecvBuffer, &dwRecvLength);
+    g_assert_cmpint(status, ==, VREADER_OK);
+    g_assert_cmpint(dwRecvLength, ==, 2);
+    g_assert_cmpint(pbRecvBuffer[0], ==, VCARD7816_SW1_COMMAND_ERROR);
+    g_assert_cmpint(pbRecvBuffer[1], ==, 0x84);
+
+    /* Read tag: P1 and P2 defines offset -- overunning the buffer should fail */
+    apdu[2] = 0x08;
+    apdu[3] = 0x08; /* <- Large enough */
+    apdu[5] = 0x01;
+    dwRecvLength = APDUBufSize;
+    status = vreader_xfr_bytes(reader,
+                               apdu, apdu_len,
+                               pbRecvBuffer, &dwRecvLength);
+    g_assert_cmpint(status, ==, VREADER_OK);
+    g_assert_cmpint(dwRecvLength, ==, 2);
+    g_assert_cmpint(pbRecvBuffer[0], ==, VCARD7816_SW1_P1_P2_ERROR);
+    g_assert_cmpint(pbRecvBuffer[1], ==, 0x86);
+
+    /* Read value: P1 and P2 defines offset -- overunning the buffer should fail */
+    apdu[5] = 0x02;
+    dwRecvLength = APDUBufSize;
+    status = vreader_xfr_bytes(reader,
+                               apdu, apdu_len,
+                               pbRecvBuffer, &dwRecvLength);
+    g_assert_cmpint(status, ==, VREADER_OK);
+    g_assert_cmpint(dwRecvLength, ==, 2);
+    g_assert_cmpint(pbRecvBuffer[0], ==, VCARD7816_SW1_P1_P2_ERROR);
+    g_assert_cmpint(pbRecvBuffer[1], ==, 0x86);
+}
+
+static void test_invalid_read_buffer(void)
+{
+    VReader *reader = vreader_get_reader_by_id(0);
+
+    g_assert_nonnull(reader);
+
+    test_invalid_read_buffer_applet(reader, TEST_CCC);
+    test_invalid_read_buffer_applet(reader, TEST_PKI);
+    test_invalid_read_buffer_applet(reader, TEST_PASSTHROUGH);
+    test_invalid_read_buffer_applet(reader, TEST_EMPTY);
+
     vreader_free(reader); /* get by id ref */
 }
+
+static void test_invalid_acr(void)
+{
+    VReader *reader = vreader_get_reader_by_id(0);
+    VReaderStatus status;
+    int dwRecvLength = APDUBufSize;
+    uint8_t pbRecvBuffer[APDUBufSize];
+    uint8_t apdu[] = {
+        0x00, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x00
+    };
+    size_t apdu_len = 5;
+
+    g_assert_nonnull(reader);
+
+    select_applet(reader, TEST_ACA);
+
+    /* P2 needs to be zero */
+    apdu[3] = 0xff;
+    dwRecvLength = APDUBufSize;
+    status = vreader_xfr_bytes(reader,
+                               apdu, apdu_len,
+                               pbRecvBuffer, &dwRecvLength);
+    g_assert_cmpint(status, ==, VREADER_OK);
+    g_assert_cmpint(dwRecvLength, ==, 2);
+    g_assert_cmpint(pbRecvBuffer[0], ==, VCARD7816_SW1_P1_P2_ERROR);
+    g_assert_cmpint(pbRecvBuffer[1], ==, 0x86);
+    apdu[3] = 0x00;
+
+    /* For P1 = 0x00 we can not send any data */
+    apdu[4] = 0x02;
+    dwRecvLength = APDUBufSize;
+    status = vreader_xfr_bytes(reader,
+                               apdu, sizeof(apdu),
+                               pbRecvBuffer, &dwRecvLength);
+    g_assert_cmpint(status, ==, VREADER_OK);
+    g_assert_cmpint(dwRecvLength, ==, 2);
+    g_assert_cmpint(pbRecvBuffer[0], ==, VCARD7816_SW1_COMMAND_ERROR);
+    g_assert_cmpint(pbRecvBuffer[1], ==, 0x84);
+
+    /* For P1 = 0x01 we need to send exactly one byte */
+    apdu[2] = 0x01;
+    dwRecvLength = APDUBufSize;
+    status = vreader_xfr_bytes(reader,
+                               apdu, sizeof(apdu),
+                               pbRecvBuffer, &dwRecvLength);
+    g_assert_cmpint(status, ==, VREADER_OK);
+    g_assert_cmpint(dwRecvLength, ==, 2);
+    g_assert_cmpint(pbRecvBuffer[0], ==, VCARD7816_SW1_COMMAND_ERROR);
+    g_assert_cmpint(pbRecvBuffer[1], ==, 0x84);
+
+    /* For P1 = 0x10 we can not send any data */
+    apdu[2] = 0x10;
+    apdu[4] = 0x02;
+    dwRecvLength = APDUBufSize;
+    status = vreader_xfr_bytes(reader,
+                               apdu, sizeof(apdu),
+                               pbRecvBuffer, &dwRecvLength);
+    g_assert_cmpint(status, ==, VREADER_OK);
+    g_assert_cmpint(dwRecvLength, ==, 2);
+    g_assert_cmpint(pbRecvBuffer[0], ==, VCARD7816_SW1_COMMAND_ERROR);
+    g_assert_cmpint(pbRecvBuffer[1], ==, 0x84);
+
+    /* For P1 = 0x11 we need to send exactly 7B (2 are not enough) */
+    apdu[2] = 0x11;
+    dwRecvLength = APDUBufSize;
+    status = vreader_xfr_bytes(reader,
+                               apdu, sizeof(apdu),
+                               pbRecvBuffer, &dwRecvLength);
+    g_assert_cmpint(status, ==, VREADER_OK);
+    g_assert_cmpint(dwRecvLength, ==, 2);
+    g_assert_cmpint(pbRecvBuffer[0], ==, VCARD7816_SW1_COMMAND_ERROR);
+    g_assert_cmpint(pbRecvBuffer[1], ==, 0x84);
+
+    /* For P1 = 0x12 we need to send exactly 2B (1 is not enough) */
+    apdu[2] = 0x12;
+    apdu[4] = 0x01;
+    dwRecvLength = APDUBufSize;
+    status = vreader_xfr_bytes(reader,
+                               apdu, 6,
+                               pbRecvBuffer, &dwRecvLength);
+    g_assert_cmpint(status, ==, VREADER_OK);
+    g_assert_cmpint(dwRecvLength, ==, 2);
+    g_assert_cmpint(pbRecvBuffer[0], ==, VCARD7816_SW1_COMMAND_ERROR);
+    g_assert_cmpint(pbRecvBuffer[1], ==, 0x84);
+
+    /* For P1 = 0x20 we can not send any data */
+    apdu[2] = 0x20;
+    dwRecvLength = APDUBufSize;
+    status = vreader_xfr_bytes(reader,
+                               apdu, 6,
+                               pbRecvBuffer, &dwRecvLength);
+    g_assert_cmpint(status, ==, VREADER_OK);
+    g_assert_cmpint(dwRecvLength, ==, 2);
+    g_assert_cmpint(pbRecvBuffer[0], ==, VCARD7816_SW1_COMMAND_ERROR);
+    g_assert_cmpint(pbRecvBuffer[1], ==, 0x84);
+
+    /* For P1 = 0x21 we can not send any data */
+    apdu[2] = 0x21;
+    dwRecvLength = APDUBufSize;
+    status = vreader_xfr_bytes(reader,
+                               apdu, 6,
+                               pbRecvBuffer, &dwRecvLength);
+    g_assert_cmpint(status, ==, VREADER_OK);
+    g_assert_cmpint(dwRecvLength, ==, 2);
+    g_assert_cmpint(pbRecvBuffer[0], ==, VCARD7816_SW1_COMMAND_ERROR);
+    g_assert_cmpint(pbRecvBuffer[1], ==, 0x84);
+
+
+    vreader_free(reader); /* get by id ref */
+}
+
+static void test_passthrough_applet(void)
+{
+    uint8_t person_coid[2] = {0x02, 0x00};
+
+    VReader *reader = vreader_get_reader_by_id(0);
+
+    /* select the passthrough applet */
+    select_applet(reader, TEST_PASSTHROUGH);
+
+    /* 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_EMPTY_BUFFER);
+
+    /* get the VALUE buffer length */
+    read_buffer(reader, CAC_FILE_VALUE, TEST_EMPTY_BUFFER);
+
+    /* the buffers are empty without physical card */
+
+    vreader_free(reader); /* get by id ref */
+}
+
+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;
@@ -652,19 +1100,25 @@ int main(int argc, char *argv[])
     g_test_add_func("/libcacard/cac-ccc", test_cac_ccc);
     g_test_add_func("/libcacard/cac-aca", test_cac_aca);
     g_test_add_func("/libcacard/get-response", test_get_response);
+    g_test_add_func("/libcacard/check-login-count", check_login_count);
     g_test_add_func("/libcacard/login", test_login);
     g_test_add_func("/libcacard/sign", test_sign);
     g_test_add_func("/libcacard/empty-applets", test_empty_applets);
     g_test_add_func("/libcacard/gp-applet", test_gp_applet);
+    g_test_add_func("/libcacard/invalid-properties-apdu", test_invalid_properties);
+    g_test_add_func("/libcacard/invalid-select-apdu", test_invalid_select);
+    g_test_add_func("/libcacard/invalid-instruction", test_invalid_instruction);
+    g_test_add_func("/libcacard/invalid-read-buffer", test_invalid_read_buffer);
+    g_test_add_func("/libcacard/invalid-acr", test_invalid_acr);
+    /* Even without the card, the passthrough applets are present */
+    g_test_add_func("/libcacard/passthrough-applet", test_passthrough_applet);
     g_test_add_func("/libcacard/remove", test_remove);
 
     ret = g_test_run();
 
     g_main_loop_unref(loop);
 
-    /* FIXME: no wait to queue a NULL event */
-    /* g_thread_join(thread); */
-
+    libcacard_finalize();
     return ret;
 }
 
-- 
2.17.1



More information about the Spice-devel mailing list