Branch data Line data Source code
1 : : /*
2 : : * Test mirroring of CAC smart card
3 : : *
4 : : * Copyright 2018 - 2022 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 : : /* select the second PKI */
260 : 6 : select_applet(reader, TEST_PKI_2);
261 : :
262 : : /* get properties to figure out the key length */
263 : 6 : get_properties(reader, TEST_PKI_2);
264 : :
265 : 6 : do_sign(reader, 0);
266 : :
267 : : /* test also multipart signatures */
268 : 6 : do_sign(reader, 1);
269 : :
270 : 6 : vreader_free(reader); /* get by id ref */
271 : : }
272 : :
273 : 2 : static void test_decipher(void)
274 : : {
275 : 2 : VReader *reader = vreader_get_reader_by_id(0);
276 : :
277 : : /* Skip the HW tests without physical card */
278 [ - + ]: 2 : if (vreader_card_is_present(reader) != VREADER_OK) {
279 : 0 : vreader_free(reader);
280 : 0 : g_test_skip("No physical card found");
281 : 0 : return;
282 : : }
283 : :
284 : : /* select the ACA */
285 : 2 : select_applet(reader, TEST_ACA);
286 : :
287 : 2 : do_login(reader);
288 : :
289 : : /* select the PKI */
290 : 2 : select_applet(reader, TEST_PKI);
291 : :
292 : : /* get properties to figure out the key length */
293 : 2 : get_properties(reader, TEST_PKI);
294 : :
295 : 2 : do_decipher(reader, TEST_PKI);
296 : :
297 : : /* select the second PKI */
298 : 2 : select_applet(reader, TEST_PKI_2);
299 : :
300 : : /* get properties to figure out the key length */
301 : 2 : get_properties(reader, TEST_PKI_2);
302 : :
303 : 2 : do_decipher(reader, TEST_PKI_2);
304 : :
305 : 2 : vreader_free(reader); /* get by id ref */
306 : : }
307 : :
308 : : /* Try to pass bad formatted PKCS#1.5 data and make sure the libcacard does not
309 : : * crash while handling them
310 : : */
311 : 2 : static void test_sign_bad_data_x509(void)
312 : : {
313 : 2 : VReader *reader = vreader_get_reader_by_id(0);
314 : : VReaderStatus status;
315 : 2 : int dwRecvLength = APDUBufSize;
316 : : uint8_t pbRecvBuffer[APDUBufSize];
317 : 2 : uint8_t sign[] = {
318 : : /* SIGN [p1,p2=0 ] [Lc ] [2048b keys: 256 bytes of non PKCS#1.5 data] */
319 : : 0x80, 0x42, 0x00, 0x00, 0x00, 0x01, 0x00,
320 : : 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
321 : : /* ^--- the second byte of data should be 0x01 for signatures */
322 : : 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
323 : : 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
324 : : 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
325 : : 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
326 : : 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
327 : : 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
328 : : 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
329 : : 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
330 : : 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
331 : : 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
332 : : 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
333 : : 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
334 : : 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
335 : : 0xff, 0xff, 0x00, 0x64, 0x61, 0x74, 0x61, 0x20, 0x74, 0x6f, 0x20, 0x73, 0x69, 0x67, 0x6e, 0x20,
336 : : 0x28, 0x6d, 0x61, 0x78, 0x20, 0x31, 0x30, 0x30, 0x20, 0x62, 0x79, 0x74, 0x65, 0x73, 0x29, 0x0a,
337 : : 0x00 /* <-- [Le] */
338 : : };
339 : : int sign_len = sizeof(sign);
340 : : int key_bits;
341 : :
342 [ - + ]: 2 : g_assert_nonnull(reader);
343 : :
344 : : /* Skip the HW tests without physical card */
345 [ - + ]: 2 : if (vreader_card_is_present(reader) != VREADER_OK) {
346 : 0 : vreader_free(reader);
347 : 0 : g_test_skip("No physical card found");
348 : 0 : return;
349 : : }
350 : :
351 : : /* get properties to figure out the key length */
352 : 2 : select_applet(reader, TEST_PKI);
353 : 2 : get_properties(reader, TEST_PKI);
354 : :
355 : : /* run the actual test */
356 : :
357 : 2 : key_bits = getBits();
358 : : /* Adjust the buffers to match the key lengths, if already retrieved */
359 [ + - ]: 2 : if (key_bits && key_bits < 2048) {
360 : 2 : int payload_len = key_bits/8; /* RSA signature has the same length as the key */
361 : 2 : sign[4] = payload_len; /* less than 2048b will fit the length into one byte */
362 : 2 : sign[5] = 0x00; /* PKCS#1.5 padding first byte */
363 : : /*sign[6] = 0x01; <- this should be 0x01 for PKCS#1.5 signatures */
364 : 2 : memmove(&sign[6], &sign[sign_len - payload_len], payload_len - 1);
365 : 2 : sign_len = 5 /* [APDU header] */ + payload_len + 1 /* [Le] */;
366 : 2 : sign[sign_len-1] = 0x00; /* [Le] */
367 : : }
368 : :
369 : 2 : dwRecvLength = APDUBufSize;
370 : 2 : status = vreader_xfr_bytes(reader,
371 : : sign, sign_len,
372 : : pbRecvBuffer, &dwRecvLength);
373 [ - + ]: 2 : g_assert_cmpint(status, ==, VREADER_OK);
374 : : /* We expect one of the following results:
375 : : * * VCARD7816_STATUS_ERROR_DATA_INVALID: Invalid data
376 : : * * VCARD7816_STATUS_SUCCESS: Properly signed data
377 : : *
378 : : * we should not crash as with 2.5.3
379 : : */
380 [ + - ]: 2 : if (pbRecvBuffer[dwRecvLength-2] == VCARD7816_SW1_SUCCESS) {
381 : : g_assert_cmphex(pbRecvBuffer[dwRecvLength-2], ==, VCARD7816_SW1_SUCCESS);
382 [ - + ]: 2 : g_assert_cmphex(pbRecvBuffer[dwRecvLength-1], ==, 0x00);
383 : : } else {
384 [ # # ]: 0 : g_assert_cmphex(pbRecvBuffer[dwRecvLength-2], ==, VCARD7816_SW1_COMMAND_ERROR);
385 [ # # ]: 0 : g_assert_cmphex(pbRecvBuffer[dwRecvLength-1], ==, 0x84);
386 : : }
387 : :
388 : : /* no need to fetch the actual response */
389 : 2 : vreader_free(reader); /* get by id ref */
390 : : }
391 : :
392 : : /* This is a regression test for issues with PKCS#11 tokens
393 : : * invalidating object handles after logout (such as softhsm).
394 : : * See: https://bugzilla.mozilla.org/show_bug.cgi?id=1576642
395 : : */
396 : 2 : static void test_sign_logout_sign(void)
397 : : {
398 : 2 : VReader *reader = vreader_get_reader_by_id(0);
399 : :
400 [ - + ]: 2 : g_assert_nonnull(reader);
401 : :
402 : 2 : test_login();
403 : 2 : test_sign();
404 : :
405 : : /* This implicitly logs out the user */
406 : 2 : test_login();
407 : 2 : test_sign();
408 : :
409 : 2 : vreader_free(reader); /* get by id ref */
410 : 2 : }
411 : :
412 : 2 : static void libcacard_finalize(void)
413 : : {
414 : 2 : VReader *reader = vreader_get_reader_by_id(0);
415 : :
416 : : /* This actually still generates events */
417 [ + - ]: 2 : if (reader) /*if /remove didn't run */
418 : 2 : vreader_remove_reader(reader);
419 : :
420 : : /* This probably supposed to be a event that terminates the loop */
421 : 2 : vevent_queue_vevent(vevent_new(VEVENT_LAST, reader, NULL));
422 : :
423 : : /* join */
424 : 2 : g_thread_join(thread);
425 : :
426 : : /* Clean up */
427 : 2 : vreader_free(reader);
428 : :
429 : 2 : vcard_emul_finalize();
430 : 2 : }
431 : :
432 : 2 : int main(int argc, char *argv[])
433 : : {
434 : : int ret;
435 : :
436 : 2 : g_test_init(&argc, &argv, NULL);
437 : :
438 : 2 : loop = g_main_loop_new(NULL, TRUE);
439 : :
440 : 2 : libcacard_init();
441 : :
442 : 2 : g_test_add_func("/hw-tests/list", test_list);
443 : 2 : g_test_add_func("/hw-tests/passthrough-applet", test_passthrough_applets);
444 : 2 : g_test_add_func("/hw-tests/check-login-count", check_login_count);
445 : 2 : g_test_add_func("/hw-tests/msft-applet", test_msft_applet);
446 : 2 : g_test_add_func("/hw-tests/gp-applet", test_gp_applet);
447 : 2 : g_test_add_func("/hw-tests/login", test_login);
448 : 2 : g_test_add_func("/hw-tests/sign", test_sign);
449 : 2 : g_test_add_func("/hw-tests/sign-bad-data", test_sign_bad_data_x509);
450 : 2 : g_test_add_func("/hw-tests/decipher", test_decipher);
451 : 2 : g_test_add_func("/hw-tests/empty-applets", test_empty_applets);
452 : 2 : g_test_add_func("/hw-tests/get-response", test_get_response);
453 : 2 : g_test_add_func("/hw-tests/sign-logout-sign", test_sign_logout_sign);
454 : :
455 : 2 : ret = g_test_run();
456 : :
457 : 2 : libcacard_finalize();
458 : :
459 : : return ret;
460 : : }
461 : :
462 : : /* vim: set ts=4 sw=4 tw=0 noet expandtab: */
|