[Spice-devel] [PATCH spice-server 2/8] test-smartcard: Add test for Smartcard device
Frediano Ziglio
fziglio at redhat.com
Mon Oct 7 10:39:00 UTC 2019
Create Smardcard device.
Connect to it and test some messages are parsed and processed
as expected.
Signed-off-by: Frediano Ziglio <fziglio at redhat.com>
---
server/tests/.gitignore | 1 +
server/tests/Makefile.am | 4 +
server/tests/meson.build | 4 +
server/tests/test-smartcard.c | 211 ++++++++++++++++++++++++++++++++++
4 files changed, 220 insertions(+)
create mode 100644 server/tests/test-smartcard.c
diff --git a/server/tests/.gitignore b/server/tests/.gitignore
index 36e978d4..56cc7eb9 100644
--- a/server/tests/.gitignore
+++ b/server/tests/.gitignore
@@ -29,5 +29,6 @@ test-leaks
test-sasl
test-record
test-websocket
+test-smartcard
/test-*.log
/test-*.trs
diff --git a/server/tests/Makefile.am b/server/tests/Makefile.am
index 98250851..dd285c24 100644
--- a/server/tests/Makefile.am
+++ b/server/tests/Makefile.am
@@ -68,6 +68,10 @@ check_PROGRAMS = \
test-record \
$(NULL)
+if HAVE_SMARTCARD
+check_PROGRAMS += test-smartcard
+endif
+
if !OS_WIN32
check_PROGRAMS += \
test-stream \
diff --git a/server/tests/meson.build b/server/tests/meson.build
index 33472f14..95ade60f 100644
--- a/server/tests/meson.build
+++ b/server/tests/meson.build
@@ -65,6 +65,10 @@ if spice_server_has_sasl
tests += [['test-sasl', true]]
endif
+if spice_server_has_smartcard == true
+ tests += [['test-smartcard', true]]
+endif
+
if host_machine.system() != 'windows'
tests += [
['test-stream', true],
diff --git a/server/tests/test-smartcard.c b/server/tests/test-smartcard.c
new file mode 100644
index 00000000..47e541d3
--- /dev/null
+++ b/server/tests/test-smartcard.c
@@ -0,0 +1,211 @@
+/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ Copyright (C) 2019 Red Hat, Inc.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+/**
+ * Test Smartcard device and channel
+ */
+
+#include <config.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <unistd.h>
+
+#include <spice/protocol.h>
+#include <spice/stream-device.h>
+
+#include "test-display-base.h"
+#include "test-glib-compat.h"
+#include "reds.h"
+#include "vmc-emu.h"
+#include "red-client.h"
+#include "net-utils.h"
+
+static SpiceCoreInterface *core;
+static Test *test;
+static VmcEmu *vmc;
+typedef int TestFixture;
+
+static void test_smartcard_setup(TestFixture *fixture, gconstpointer user_data)
+{
+ g_assert_null(core);
+ g_assert_null(test);
+ g_assert_null(vmc);
+ core = basic_event_loop_init();
+ g_assert_nonnull(core);
+ test = test_new(core);
+ g_assert_nonnull(test);
+ vmc = vmc_emu_new("smartcard", NULL);
+ g_assert_nonnull(vmc);
+}
+
+static void test_smartcard_teardown(TestFixture *fixture, gconstpointer user_data)
+{
+ g_assert_nonnull(core);
+ g_assert_nonnull(test);
+ g_assert_nonnull(vmc);
+
+ vmc_emu_destroy(vmc);
+ vmc = NULL;
+ test_destroy(test);
+ test = NULL;
+ basic_event_loop_destroy();
+ core = NULL;
+}
+
+static RedStream *create_dummy_stream(SpiceServer *server, int *p_socket)
+{
+ int sv[2];
+ g_assert_cmpint(socketpair(AF_LOCAL, SOCK_STREAM, 0, sv), ==, 0);
+ if (p_socket) {
+ *p_socket = sv[1];
+ }
+ red_socket_set_non_blocking(sv[0], true);
+ red_socket_set_non_blocking(sv[1], true);
+
+ RedStream * stream = red_stream_new(server, sv[0]);
+ g_assert_nonnull(stream);
+
+ return stream;
+}
+
+static void send_ack_sync(int socket, uint32_t generation)
+{
+ struct {
+ uint16_t dummy;
+ uint16_t type;
+ uint32_t len;
+ uint32_t generation;
+ } msg;
+ SPICE_VERIFY(sizeof(msg) == 12);
+ msg.type = GUINT16_TO_LE(SPICE_MSGC_ACK_SYNC);
+ msg.len = GUINT32_TO_LE(sizeof(generation));
+ msg.generation = GUINT32_TO_LE(generation);
+
+ g_assert_cmpint(socket_write(socket, &msg.type, 10), ==, 10);
+}
+
+static void send_data(int socket, uint32_t type)
+{
+ struct {
+ uint16_t dummy;
+ uint16_t type;
+ uint32_t len;
+ VSCMsgHeader vheader;
+ char data[6];
+ } msg;
+ SPICE_VERIFY(sizeof(msg) == 8+12+8);
+ msg.type = GUINT16_TO_LE(SPICE_MSGC_SMARTCARD_DATA);
+ msg.len = GUINT32_TO_LE(sizeof(VSCMsgHeader)+6);
+ msg.vheader.type = GUINT32_TO_LE(type);
+ msg.vheader.reader_id = 0;
+ msg.vheader.length = GUINT32_TO_LE(6);
+ strcpy(msg.data, "hello");
+
+ g_assert_cmpint(socket_write(socket, &msg.type, sizeof(msg)-4), ==, sizeof(msg)-4);
+}
+
+static void check_data(void *opaque)
+{
+ static const char expected_buf[] =
+ // forwarded ReaderAdd message, note that payload is stripped
+ "\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00"
+ // forwarded APDU message
+ "\x00\x00\x00\x07\x00\x00\x00\x00\x00\x00\x00\x06\x68\x65\x6c\x6c\x6f\x00";
+ const size_t expected_buf_len = sizeof(expected_buf) - 1;
+ g_assert_cmpint(vmc->write_pos, ==, expected_buf_len);
+ g_assert_true(memcmp(vmc->write_buf, expected_buf, expected_buf_len) == 0);
+ basic_event_loop_quit();
+}
+
+static void test_smartcard(TestFixture *fixture, gconstpointer user_data)
+{
+ SpiceServer *const server = test->server;
+ uint8_t *p = vmc->message;
+
+ spice_server_add_interface(server, &vmc->instance.base);
+
+ // add VSC_Init message
+ memcpy(p, "\x00\x00\x00\x01\x0a\x0b\x0c\x0d\x00\x00\x00\x00", 12);
+ p += 12;
+ vmc_emu_add_read_till(vmc, p);
+
+ // find Smartcard channel to connect to
+ RedChannel *channel = reds_find_channel(server, SPICE_CHANNEL_SMARTCARD, 0);
+ g_assert_nonnull(channel);
+
+ // create dummy RedClient and MainChannelClient
+ RedChannelCapabilities caps;
+ memset(&caps, 0, sizeof(caps));
+ uint32_t common_caps = 1 << SPICE_COMMON_CAP_MINI_HEADER;
+ caps.num_common_caps = 1;
+ caps.common_caps = spice_memdup(&common_caps, sizeof(common_caps));
+
+ RedClient *client = red_client_new(server, FALSE);
+ g_assert_nonnull(client);
+
+ MainChannel *main_channel = main_channel_new(server);
+ g_assert_nonnull(main_channel);
+
+ MainChannelClient *mcc;
+ mcc = main_channel_link(main_channel, client, create_dummy_stream(server, NULL),
+ 0, FALSE, &caps);
+ g_assert_nonnull(mcc);
+ red_client_set_main(client, mcc);
+
+ // create our testing RedChannelClient
+ int client_socket;
+ red_channel_connect(channel, client, create_dummy_stream(server, &client_socket),
+ FALSE, &caps);
+ red_channel_capabilities_reset(&caps);
+
+ spice_server_char_device_wakeup(&vmc->instance);
+
+ send_ack_sync(client_socket, 1);
+ send_data(client_socket, VSC_ReaderAdd);
+ send_data(client_socket, VSC_APDU);
+
+ SpiceTimer *watch_timer;
+ watch_timer = core->timer_add(check_data, core);
+ core->timer_start(watch_timer, 100);
+
+ // start all test
+ basic_event_loop_mainloop();
+
+ core->timer_remove(watch_timer);
+
+ // cleanup
+ red_client_destroy(client);
+ g_object_unref(main_channel);
+ g_object_unref(channel);
+}
+
+static void test_add(const char *name, void (*func)(TestFixture *, gconstpointer),
+ gconstpointer arg)
+{
+ g_test_add(name, TestFixture, arg, test_smartcard_setup, func, test_smartcard_teardown);
+}
+
+int main(int argc, char *argv[])
+{
+ g_test_init(&argc, &argv, NULL);
+
+ test_add("/server/smartcard", test_smartcard, NULL);
+
+ return g_test_run();
+}
--
2.21.0
More information about the Spice-devel
mailing list