Branch data Line data Source code
1 : : /*
2 : : * Test mirroring of CAC smart card
3 : : *
4 : : * Copyright 2018 Red Hat, Inc.
5 : : *
6 : : * Author: Jakub Jelen <jjelen@redhat.com>
7 : : *
8 : : * This code is licensed under the GNU LGPL, version 2.1 or later.
9 : : * See the COPYING file in the top-level directory.
10 : : */
11 : :
12 : : #include <glib.h>
13 : : #include <string.h>
14 : : #include "libcacard.h"
15 : : #include "simpletlv.h"
16 : : #include "common.h"
17 : :
18 : : #define ARGS "db=\"sql:%s\" use_hw=removable"
19 : : #define LOGIN_PIN "77777777"
20 : :
21 : : static GMainLoop *loop;
22 : : static GThread *thread;
23 : : static guint nreaders;
24 : : static GMutex mutex;
25 : : static GCond cond;
26 : :
27 : : static gpointer
28 : 2 : events_thread(G_GNUC_UNUSED gpointer arg)
29 : : {
30 : : unsigned int reader_id;
31 : : VEvent *event;
32 : :
33 : : while (1) {
34 : 12 : event = vevent_wait_next_vevent();
35 [ + - + + ]: 12 : if (event == NULL || event->type == VEVENT_LAST) {
36 : 2 : vevent_delete(event);
37 : : break;
38 : : }
39 : 10 : reader_id = vreader_get_id(event->reader);
40 [ + + ]: 10 : if (reader_id == VSCARD_UNDEFINED_READER_ID) {
41 : 4 : g_mutex_lock(&mutex);
42 : 4 : vreader_set_id(event->reader, nreaders++);
43 : 4 : g_cond_signal(&cond);
44 : 4 : g_mutex_unlock(&mutex);
45 : 4 : reader_id = vreader_get_id(event->reader);
46 : : }
47 [ - + ]: 10 : switch (event->type) {
48 : : case VEVENT_READER_INSERT:
49 : : case VEVENT_READER_REMOVE:
50 : : case VEVENT_CARD_INSERT:
51 : : case VEVENT_CARD_REMOVE:
52 : : break;
53 : 0 : case VEVENT_LAST:
54 : : default:
55 : 0 : g_warn_if_reached();
56 : 0 : break;
57 : : }
58 : 10 : vevent_delete(event);
59 : : }
60 : :
61 : 2 : return NULL;
62 : : }
63 : :
64 : 2 : static void libcacard_init(void)
65 : : {
66 : : VCardEmulOptions *command_line_options = NULL;
67 : 2 : gchar *dbdir = g_test_build_filename(G_TEST_BUILT, "hwdb", NULL);
68 : 2 : gchar *args = g_strdup_printf(ARGS, dbdir);
69 : : VCardEmulError ret;
70 : :
71 : 2 : thread = g_thread_new("test/events", events_thread, NULL);
72 : :
73 : 2 : command_line_options = vcard_emul_options(args);
74 : 2 : ret = vcard_emul_init(command_line_options);
75 [ - + ]: 2 : g_assert_cmpint(ret, ==, VCARD_EMUL_OK);
76 : :
77 : : /* We test with real hardware */
78 : 2 : setHWTests(1);
79 : :
80 : : /* Do not assume any specific reader name here */
81 : :
82 : 2 : g_mutex_lock(&mutex);
83 [ - + ]: 2 : while (nreaders < 2)
84 : 0 : g_cond_wait(&cond, &mutex);
85 : 2 : g_mutex_unlock(&mutex);
86 : :
87 : 2 : g_free(args);
88 : 2 : g_free(dbdir);
89 : 2 : }
90 : :
91 : 2 : static void test_list(void)
92 : : {
93 : 2 : VReaderList *list = vreader_get_reader_list();
94 : : VReaderListEntry *reader_entry;
95 : : int cards = 0;
96 : :
97 [ + + ]: 6 : for (reader_entry = vreader_list_get_first(list); reader_entry;
98 : 4 : reader_entry = vreader_list_get_next(reader_entry)) {
99 : 4 : VReader *r = vreader_list_get_reader(reader_entry);
100 : : vreader_id_t id;
101 : 4 : id = vreader_get_id(r);
102 : 4 : g_debug("%s: VReader name = %s, card = %d, %u", __func__, vreader_get_name(r), vreader_card_is_present(r), id);
103 [ - + ]: 4 : g_assert_cmpint(id, !=, VSCARD_UNDEFINED_READER_ID);
104 [ + + ]: 4 : if (vreader_card_is_present(r) == VREADER_OK) {
105 : 2 : cards++;
106 : : }
107 : 4 : vreader_free(r);
108 : : }
109 : 2 : vreader_list_delete(list);
110 : :
111 [ - + ]: 2 : if (cards == 0) {
112 : 0 : g_test_skip("No physical card found");
113 : 0 : return;
114 : : }
115 : :
116 [ - + ]: 2 : g_assert_cmpint(cards, ==, 1);
117 : : }
118 : :
119 : 16 : static void do_login(VReader *reader)
120 : : {
121 : : VReaderStatus status;
122 : 16 : int dwRecvLength = APDUBufSize;
123 : : uint8_t pbRecvBuffer[APDUBufSize];
124 : 16 : uint8_t login[] = {
125 : : /* VERIFY [p1,p2=0 ] [Lc] [pin 77777777 ] */
126 : : 0x00, 0x20, 0x00, 0x00, 0x08,
127 : : //0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37
128 : : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
129 : : };
130 : 16 : uint8_t login_check[] = {
131 : : /* VERIFY [p1,p2=0 ] [Lc] */
132 : : 0x00, 0x20, 0x00, 0x00, 0x00
133 : : };
134 : : int login_len, pin_len;
135 : :
136 [ - + - + ]: 16 : g_assert_nonnull(reader);
137 : :
138 : : /* Set the pin from constant */
139 : : pin_len = strlen(LOGIN_PIN);
140 : 16 : login[4] = pin_len;
141 : 16 : memcpy(&login[5], LOGIN_PIN, pin_len);
142 : : login_len = 5 + pin_len;
143 : :
144 : 16 : status = vreader_xfr_bytes(reader,
145 : : login, login_len,
146 : : pbRecvBuffer, &dwRecvLength);
147 [ - + ]: 16 : g_assert_cmpint(status, ==, VREADER_OK);
148 [ - + ]: 16 : g_assert_cmphex(pbRecvBuffer[0], ==, VCARD7816_SW1_SUCCESS);
149 [ - + ]: 16 : g_assert_cmphex(pbRecvBuffer[1], ==, 0x00);
150 : :
151 : : /* Check the login status now */
152 : 16 : status = vreader_xfr_bytes(reader,
153 : : login_check, sizeof(login_check),
154 : : pbRecvBuffer, &dwRecvLength);
155 [ - + ]: 16 : g_assert_cmpint(status, ==, VREADER_OK);
156 [ - + ]: 16 : g_assert_cmphex(pbRecvBuffer[0], ==, VCARD7816_SW1_SUCCESS);
157 [ - + ]: 16 : g_assert_cmphex(pbRecvBuffer[1], ==, 0x00);
158 : 16 : }
159 : :
160 : 2 : static void test_passthrough_applets(void)
161 : : {
162 : 2 : uint8_t applet_person[] = {
163 : : /*Read Buffer OFFSET TYPE LENGTH */
164 : : 0xA0, 0x00, 0x00, 0x00, 0x79, 0x02, 0x00
165 : : };
166 : 2 : uint8_t applet_personnel[] = {
167 : : /*Read Buffer OFFSET TYPE LENGTH */
168 : : 0xA0, 0x00, 0x00, 0x00, 0x79, 0x02, 0x01
169 : : };
170 : 2 : uint8_t person_coid[2] = {0x02, 0x00};
171 : 2 : uint8_t personnel_coid[2] = {0x02, 0x01};
172 : :
173 : 2 : VReader *reader = vreader_get_reader_by_id(0);
174 : :
175 : : /* Skip the HW tests without physical card */
176 [ - + ]: 2 : if (vreader_card_is_present(reader) != VREADER_OK) {
177 : 0 : vreader_free(reader);
178 : 0 : g_test_skip("No physical card found");
179 : 0 : return;
180 : : }
181 : :
182 : : /* select the Person Instance applet A0000000790200 */
183 : 2 : select_aid(reader, applet_person, sizeof(applet_person));
184 : :
185 : : /* get properties */
186 : 2 : get_properties_coid(reader, person_coid, TEST_GENERIC);
187 : :
188 : : /* These objects requires a PIN to read the value buffer */
189 : 2 : do_login(reader);
190 : :
191 : : /* get the TAG buffer length */
192 : 2 : read_buffer(reader, CAC_FILE_TAG, TEST_GENERIC);
193 : :
194 : : /* get the VALUE buffer length */
195 : 2 : read_buffer(reader, CAC_FILE_VALUE, TEST_GENERIC);
196 : :
197 : :
198 : : /* select the Personnel applet A0000000790201 */
199 : 2 : select_aid(reader, applet_personnel, sizeof(applet_personnel));
200 : :
201 : : /* get properties */
202 : 2 : get_properties_coid(reader, personnel_coid, TEST_GENERIC);
203 : :
204 : : /* get the TAG buffer */
205 : 2 : read_buffer(reader, CAC_FILE_TAG, TEST_GENERIC);
206 : :
207 : : /* get the VALUE buffer */
208 : 2 : read_buffer(reader, CAC_FILE_VALUE, TEST_GENERIC);
209 : :
210 : 2 : vreader_free(reader); /* get by id ref */
211 : : }
212 : :
213 : 6 : static void test_login(void)
214 : : {
215 : 6 : VReader *reader = vreader_get_reader_by_id(0);
216 : :
217 : : /* Skip the HW tests without physical card */
218 [ - + ]: 6 : if (vreader_card_is_present(reader) != VREADER_OK) {
219 : 0 : vreader_free(reader);
220 : 0 : g_test_skip("No physical card found");
221 : 0 : return;
222 : : }
223 : :
224 : : /* select the ACA */
225 : 6 : select_applet(reader, TEST_ACA);
226 : :
227 : 6 : do_login(reader);
228 : :
229 : 6 : vreader_free(reader); /* get by id ref */
230 : : }
231 : :
232 : 6 : static void test_sign(void)
233 : : {
234 : 6 : VReader *reader = vreader_get_reader_by_id(0);
235 : :
236 : : /* Skip the HW tests without physical card */
237 [ - + ]: 6 : if (vreader_card_is_present(reader) != VREADER_OK) {
238 : 0 : vreader_free(reader);
239 : 0 : g_test_skip("No physical card found");
240 : 0 : return;
241 : : }
242 : :
243 : : /* select the ACA */
244 : 6 : select_applet(reader, TEST_ACA);
245 : :
246 : 6 : do_login(reader);
247 : :
248 : : /* select the PKI */
249 : 6 : select_applet(reader, TEST_PKI);
250 : :
251 : : /* get properties to figure out the key length */
252 : 6 : get_properties(reader, TEST_PKI);
253 : :
254 : 6 : do_sign(reader, 0);
255 : :
256 : : /* test also multipart signatures */
257 : 6 : do_sign(reader, 1);
258 : :
259 : 6 : vreader_free(reader); /* get by id ref */
260 : : }
261 : :
262 : 2 : static void test_decipher(void)
263 : : {
264 : 2 : VReader *reader = vreader_get_reader_by_id(0);
265 : :
266 : : /* Skip the HW tests without physical card */
267 [ - + ]: 2 : if (vreader_card_is_present(reader) != VREADER_OK) {
268 : 0 : vreader_free(reader);
269 : 0 : g_test_skip("No physical card found");
270 : 0 : return;
271 : : }
272 : :
273 : : /* select the ACA */
274 : 2 : select_applet(reader, TEST_ACA);
275 : :
276 : 2 : do_login(reader);
277 : :
278 : : /* select the PKI */
279 : 2 : select_applet(reader, TEST_PKI);
280 : :
281 : : /* get properties to figure out the key length */
282 : 2 : get_properties(reader, TEST_PKI);
283 : :
284 : 2 : do_decipher(reader);
285 : :
286 : 2 : vreader_free(reader); /* get by id ref */
287 : : }
288 : :
289 : : /* Try to pass bad formatted PKCS#1.5 data and make sure the libcacard does not
290 : : * crash while handling them
291 : : */
292 : 2 : static void test_sign_bad_data_x509(void)
293 : : {
294 : 2 : VReader *reader = vreader_get_reader_by_id(0);
295 : : VReaderStatus status;
296 : 2 : int dwRecvLength = APDUBufSize;
297 : : uint8_t pbRecvBuffer[APDUBufSize];
298 : 2 : uint8_t sign[] = {
299 : : /* SIGN [p1,p2=0 ] [Lc ] [2048b keys: 256 bytes of non PKCS#1.5 data] */
300 : : 0x80, 0x42, 0x00, 0x00, 0x00, 0x01, 0x00,
301 : : 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
302 : : /* ^--- the second byte of data should be 0x01 for signatures */
303 : : 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
304 : : 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
305 : : 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
306 : : 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
307 : : 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
308 : : 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
309 : : 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
310 : : 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
311 : : 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
312 : : 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
313 : : 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
314 : : 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
315 : : 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
316 : : 0xff, 0xff, 0x00, 0x64, 0x61, 0x74, 0x61, 0x20, 0x74, 0x6f, 0x20, 0x73, 0x69, 0x67, 0x6e, 0x20,
317 : : 0x28, 0x6d, 0x61, 0x78, 0x20, 0x31, 0x30, 0x30, 0x20, 0x62, 0x79, 0x74, 0x65, 0x73, 0x29, 0x0a,
318 : : 0x00 /* <-- [Le] */
319 : : };
320 : : int sign_len = sizeof(sign);
321 : 2 : int key_bits = getBits();
322 : :
323 [ - + - + ]: 2 : g_assert_nonnull(reader);
324 : :
325 : : /* Skip the HW tests without physical card */
326 [ - + ]: 2 : if (vreader_card_is_present(reader) != VREADER_OK) {
327 : 0 : vreader_free(reader);
328 : 0 : g_test_skip("No physical card found");
329 : 0 : return;
330 : : }
331 : :
332 : : /* run the actual test */
333 : :
334 : 2 : key_bits = getBits();
335 : : /* Adjust the buffers to match the key lengths, if already retrieved */
336 [ + - ]: 2 : if (key_bits && key_bits < 2048) {
337 : 2 : int payload_len = key_bits/8; /* RSA signature has the same length as the key */
338 : 2 : sign[4] = payload_len; /* less than 2048b will fit the length into one byte */
339 : 2 : sign[5] = 0x00; /* PKCS#1.5 padding first byte */
340 : : /*sign[6] = 0x01; <- this should be 0x01 for PKCS#1.5 signatures */
341 : 2 : memmove(&sign[6], &sign[sign_len - payload_len], payload_len - 1);
342 : 2 : sign_len = 5 /* [APDU header] */ + payload_len + 1 /* [Le] */;
343 : 2 : sign[sign_len-1] = 0x00; /* [Le] */
344 : : }
345 : :
346 : 2 : dwRecvLength = APDUBufSize;
347 : 2 : status = vreader_xfr_bytes(reader,
348 : : sign, sign_len,
349 : : pbRecvBuffer, &dwRecvLength);
350 [ - + ]: 2 : g_assert_cmpint(status, ==, VREADER_OK);
351 : : /* We expect one of the following results:
352 : : * * VCARD7816_STATUS_ERROR_DATA_INVALID: Invalid data
353 : : * * VCARD7816_STATUS_SUCCESS: Properly signed data
354 : : *
355 : : * we should not crash as with 2.5.3
356 : : */
357 [ + + ]: 2 : if (pbRecvBuffer[dwRecvLength-2] == VCARD7816_SW1_SUCCESS) {
358 : : g_assert_cmphex(pbRecvBuffer[dwRecvLength-2], ==, VCARD7816_SW1_SUCCESS);
359 [ - + ]: 1 : g_assert_cmphex(pbRecvBuffer[dwRecvLength-1], ==, 0x00);
360 : : } else {
361 [ - + ]: 1 : g_assert_cmphex(pbRecvBuffer[dwRecvLength-2], ==, VCARD7816_SW1_COMMAND_ERROR);
362 [ - + ]: 1 : g_assert_cmphex(pbRecvBuffer[dwRecvLength-1], ==, 0x84);
363 : : }
364 : :
365 : : /* no need to fetch the actual response */
366 : 2 : vreader_free(reader); /* get by id ref */
367 : : }
368 : :
369 : : /* This is a regression test for issues with PKCS#11 tokens
370 : : * invalidating object handles after logout (such as softhsm).
371 : : * See: https://bugzilla.mozilla.org/show_bug.cgi?id=1576642
372 : : */
373 : 2 : static void test_sign_logout_sign(void)
374 : : {
375 : 2 : VReader *reader = vreader_get_reader_by_id(0);
376 : :
377 [ - + - + ]: 2 : g_assert_nonnull(reader);
378 : :
379 : 2 : test_login();
380 : 2 : test_sign();
381 : :
382 : : /* This implicitly logs out the user */
383 : 2 : test_login();
384 : 2 : test_sign();
385 : :
386 : 2 : vreader_free(reader); /* get by id ref */
387 : 2 : }
388 : :
389 : 2 : static void libcacard_finalize(void)
390 : : {
391 : 2 : VReader *reader = vreader_get_reader_by_id(0);
392 : :
393 : : /* This actually still generates events */
394 [ + - ]: 2 : if (reader) /*if /remove didn't run */
395 : 2 : vreader_remove_reader(reader);
396 : :
397 : : /* This probably supposed to be a event that terminates the loop */
398 : 2 : vevent_queue_vevent(vevent_new(VEVENT_LAST, reader, NULL));
399 : :
400 : : /* join */
401 : 2 : g_thread_join(thread);
402 : :
403 : : /* Clean up */
404 : 2 : vreader_free(reader);
405 : :
406 : 2 : vcard_emul_finalize();
407 : 2 : }
408 : :
409 : 2 : int main(int argc, char *argv[])
410 : : {
411 : : int ret;
412 : :
413 : 2 : g_test_init(&argc, &argv, NULL);
414 : :
415 : 2 : loop = g_main_loop_new(NULL, TRUE);
416 : :
417 : 2 : libcacard_init();
418 : :
419 : 2 : g_test_add_func("/hw-tests/list", test_list);
420 : 2 : g_test_add_func("/hw-tests/passthrough-applet", test_passthrough_applets);
421 : 2 : g_test_add_func("/hw-tests/check-login-count", check_login_count);
422 : 2 : g_test_add_func("/hw-tests/msft-applet", check_login_count);
423 : 2 : g_test_add_func("/hw-tests/gp-applet", test_gp_applet);
424 : 2 : g_test_add_func("/hw-tests/login", test_login);
425 : 2 : g_test_add_func("/hw-tests/sign", test_sign);
426 : 2 : g_test_add_func("/hw-tests/sign-bad-data", test_sign_bad_data_x509);
427 : 2 : g_test_add_func("/hw-tests/decipher", test_decipher);
428 : 2 : g_test_add_func("/hw-tests/empty-applets", test_empty_applets);
429 : 2 : g_test_add_func("/hw-tests/get-response", test_get_response);
430 : 2 : g_test_add_func("/hw-tests/sign-logout-sign", test_sign_logout_sign);
431 : :
432 : 2 : ret = g_test_run();
433 : :
434 : 2 : libcacard_finalize();
435 : :
436 : : return ret;
437 : : }
438 : :
439 : : /* vim: set ts=4 sw=4 tw=0 noet expandtab: */
|