1 /*
2  * Copyright (c) 2012 Red Hat Inc.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  *     * Redistributions of source code must retain the above
9  *       copyright notice, this list of conditions and the
10  *       following disclaimer.
11  *     * Redistributions in binary form must reproduce the
12  *       above copyright notice, this list of conditions and
13  *       the following disclaimer in the documentation and/or
14  *       other materials provided with the distribution.
15  *     * The names of contributors to this software may not be
16  *       used to endorse or promote products derived from this
17  *       software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
25  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
26  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
27  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
29  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
30  * DAMAGE.
31  *
32  * Author: Stef Walter <stefw@gnome.org>
33  */
34 
35 #include "config.h"
36 #include "test.h"
37 #include "test-trust.h"
38 
39 #include <stdlib.h>
40 #include <stdio.h>
41 #include <string.h>
42 
43 #include <sys/stat.h>
44 #include <sys/types.h>
45 #include <fcntl.h>
46 #ifdef OS_UNIX
47 #include <unistd.h>
48 #endif
49 
50 #include "attrs.h"
51 #include "debug.h"
52 #include "parser.h"
53 #include "path.h"
54 #include "pkcs11x.h"
55 #include "message.h"
56 #include "token.h"
57 
58 static CK_OBJECT_CLASS certificate = CKO_CERTIFICATE;
59 static CK_OBJECT_CLASS data = CKO_DATA;
60 static CK_BBOOL falsev = CK_FALSE;
61 static CK_BBOOL truev = CK_TRUE;
62 
63 struct {
64 	p11_token *token;
65 	p11_index *index;
66 	p11_parser *parser;
67 	char *directory;
68 	char *unwritable;
69 } test;
70 
71 static void
setup(void * path)72 setup (void *path)
73 {
74 	test.token = p11_token_new (333, path, "Label", P11_TOKEN_FLAG_NONE);
75 	assert_ptr_not_null (test.token);
76 
77 	test.index = p11_token_index (test.token);
78 	assert_ptr_not_null (test.token);
79 
80 	test.parser = p11_token_parser (test.token);
81 	assert_ptr_not_null (test.parser);
82 }
83 
84 static void
setup_temp(void * unused)85 setup_temp (void *unused)
86 {
87 	test.directory = p11_test_directory ("test-module");
88 	setup (test.directory);
89 }
90 
91 static void
setup_writable(void * unused)92 setup_writable (void *unused)
93 {
94 	setup_temp (unused);
95 
96 	test.unwritable = p11_path_build (test.directory, "unwritable", NULL);
97 #ifdef OS_UNIX
98 	if (mkdir (test.unwritable, S_IRWXU) < 0)
99 #else
100 	if (mkdir (test.unwritable) < 0)
101 #endif
102 		assert_fail ("mkdir() failed", test.unwritable);
103 
104 	chmod (test.unwritable, 0);
105 }
106 
107 static void
teardown(void * path)108 teardown (void *path)
109 {
110 	p11_token_free (test.token);
111 }
112 
113 static void
teardown_temp(void * unused)114 teardown_temp (void *unused)
115 {
116 	p11_test_directory_delete (test.directory);
117 	teardown (test.directory);
118 	free (test.directory);
119 	memset (&test, 0, sizeof (test));
120 }
121 
122 static void
teardown_writable(void * unused)123 teardown_writable (void *unused)
124 {
125 	chmod (test.unwritable, 0644);
126 	free (test.unwritable);
127 
128 	teardown_temp (unused);
129 }
130 
131 static void
test_token_load(void * path)132 test_token_load (void *path)
133 {
134 	p11_index *index;
135 	int count;
136 
137 	count = p11_token_load (test.token);
138 	assert_num_eq (8, count);
139 
140 	/* A certificate and trust object for each parsed object */
141 	index = p11_token_index (test.token);
142 	assert (((count - 1) * 2) + 1 <= p11_index_size (index));
143 }
144 
145 static void
test_token_flags(void * path)146 test_token_flags (void *path)
147 {
148 	/*
149 	 * blocklist comes from the input/distrust.pem file. It is not in the blocklist
150 	 * directory, but is an OpenSSL trusted certificate file, and is marked
151 	 * in the blocklist style for OpenSSL.
152 	 */
153 
154 	CK_ATTRIBUTE blocklist[] = {
155 		{ CKA_CLASS, &certificate, sizeof (certificate) },
156 		{ CKA_LABEL, "Red Hat Is the CA", 17 },
157 		{ CKA_SERIAL_NUMBER, "\x02\x01\x01", 3 },
158 		{ CKA_TRUSTED, &falsev, sizeof (falsev) },
159 		{ CKA_X_DISTRUSTED, &truev, sizeof (truev) },
160 		{ CKA_INVALID },
161 	};
162 
163 	/*
164 	 * blocklist2 comes from the input/blocklist/self-server.der file. It is
165 	 * explicitly put on the blocklist, even though it contains no trust
166 	 * policy information.
167 	 */
168 
169 	const unsigned char self_server_subject[] = {
170 		0x30, 0x4b, 0x31, 0x13, 0x30, 0x11, 0x06, 0x0a, 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64,
171 		0x01, 0x19, 0x16, 0x03, 0x43, 0x4f, 0x4d, 0x31, 0x17, 0x30, 0x15, 0x06, 0x0a, 0x09, 0x92, 0x26,
172 		0x89, 0x93, 0xf2, 0x2c, 0x64, 0x01, 0x19, 0x16, 0x07, 0x45, 0x58, 0x41, 0x4d, 0x50, 0x4c, 0x45,
173 		0x31, 0x1b, 0x30, 0x19, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x12, 0x73, 0x65, 0x72, 0x76, 0x65,
174 		0x72, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d,
175 	};
176 
177 	CK_ATTRIBUTE blocklist2[] = {
178 		{ CKA_CLASS, &certificate, sizeof (certificate) },
179 		{ CKA_SUBJECT, (void *)self_server_subject, sizeof (self_server_subject) },
180 		{ CKA_TRUSTED, &falsev, sizeof (falsev) },
181 		{ CKA_X_DISTRUSTED, &truev, sizeof (truev) },
182 		{ CKA_INVALID },
183 	};
184 
185 	/*
186 	 * anchor comes from the input/anchors/cacert3.der file. It is
187 	 * explicitly marked as an anchor, even though it contains no trust
188 	 * policy information.
189 	 */
190 
191 	CK_ATTRIBUTE anchor[] = {
192 		{ CKA_CLASS, &certificate, sizeof (certificate) },
193 		{ CKA_SUBJECT, (void *)test_cacert3_ca_subject, sizeof (test_cacert3_ca_subject) },
194 		{ CKA_TRUSTED, &truev, sizeof (truev) },
195 		{ CKA_X_DISTRUSTED, &falsev, sizeof (falsev) },
196 		{ CKA_INVALID },
197 	};
198 
199 	const unsigned char cacert_root_subject[] = {
200 		0x30, 0x79, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x07, 0x52, 0x6f, 0x6f,
201 		0x74, 0x20, 0x43, 0x41, 0x31, 0x1e, 0x30, 0x1c, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x15, 0x68,
202 		0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x63, 0x61, 0x63, 0x65, 0x72, 0x74,
203 		0x2e, 0x6f, 0x72, 0x67, 0x31, 0x22, 0x30, 0x20, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x19, 0x43,
204 		0x41, 0x20, 0x43, 0x65, 0x72, 0x74, 0x20, 0x53, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x20, 0x41,
205 		0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x09, 0x2a, 0x86,
206 		0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x12, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74,
207 		0x40, 0x63, 0x61, 0x63, 0x65, 0x72, 0x74, 0x2e, 0x6f, 0x72, 0x67,
208 	};
209 
210 	/*
211 	 * notrust comes from the input/cacert-ca.der file. It contains no
212 	 * trust information, and is not explicitly marked as an anchor, so
213 	 * it's neither trusted or distrusted.
214 	 */
215 
216 	CK_ATTRIBUTE notrust[] = {
217 		{ CKA_CLASS, &certificate, sizeof (certificate) },
218 		{ CKA_SUBJECT, (void *)cacert_root_subject, sizeof (cacert_root_subject) },
219 		{ CKA_TRUSTED, &falsev, sizeof (falsev) },
220 		{ CKA_X_DISTRUSTED, &falsev, sizeof (falsev) },
221 		{ CKA_INVALID },
222 	};
223 
224 	CK_ATTRIBUTE *expected[] = {
225 		anchor,
226 		blocklist,
227 		blocklist2,
228 		notrust,
229 		NULL,
230 	};
231 
232 	CK_OBJECT_HANDLE handle;
233 	CK_ATTRIBUTE *object;
234 	int i;
235 
236 	if (p11_token_load (test.token) < 0)
237 		assert_not_reached ();
238 
239 	/* The other objects */
240 	for (i = 0; expected[i]; i++) {
241 		handle = p11_index_find (p11_token_index (test.token), expected[i], 2);
242 		assert (handle != 0);
243 
244 		object = p11_index_lookup (p11_token_index (test.token), handle);
245 		assert_ptr_not_null (object);
246 
247 		test_check_attrs (expected[i], object);
248 	}
249 }
250 
251 static void
test_token_path(void * path)252 test_token_path (void *path)
253 {
254 	assert_str_eq (path, p11_token_get_path (test.token));
255 }
256 
257 static void
test_token_label(void * path)258 test_token_label (void *path)
259 {
260 	assert_str_eq ("Label", p11_token_get_label (test.token));
261 }
262 
263 static void
test_token_slot(void * path)264 test_token_slot (void *path)
265 {
266 	assert_num_eq (333, p11_token_get_slot (test.token));
267 }
268 
269 static void
test_not_writable(void)270 test_not_writable (void)
271 {
272 	p11_token *token;
273 	char *path;
274 	int fd;
275 
276 	path = p11_path_build (test.unwritable, "test", NULL);
277 	fd = open (path, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
278 	free (path);
279 
280 	if (fd >= 0) {
281 		close (fd);
282 		assert_skip ("cannot perform non-writable test", NULL);
283 	}
284 
285 	token = p11_token_new (333, test.unwritable, "Label", P11_TOKEN_FLAG_NONE);
286 	assert (!p11_token_is_writable (token));
287 	p11_token_free (token);
288 
289 	token = p11_token_new (333, "", "Label", P11_TOKEN_FLAG_NONE);
290 	assert (!p11_token_is_writable (token));
291 	p11_token_free (token);
292 
293 	path = p11_path_build (test.unwritable, "non-existent", NULL);
294 	token = p11_token_new (333, path, "Label", P11_TOKEN_FLAG_NONE);
295 	free (path);
296 	assert (!p11_token_is_writable (token));
297 	p11_token_free (token);
298 }
299 
300 static void
test_writable_exists(void)301 test_writable_exists (void)
302 {
303 	/* A writable directory since we created it */
304 	assert (p11_token_is_writable (test.token));
305 }
306 
307 static void
test_writable_no_exist(void)308 test_writable_no_exist (void)
309 {
310 	char *directory;
311 	p11_token *token;
312 	char *path;
313 
314 	directory = p11_test_directory ("test-module");
315 
316 	path = p11_path_build (directory, "subdir", NULL);
317 	assert (path != NULL);
318 
319 	token = p11_token_new (333, path, "Label", P11_TOKEN_FLAG_NONE);
320 	free (path);
321 
322 	/* A writable directory since parent is writable */
323 	assert (p11_token_is_writable (token));
324 
325 	p11_token_free (token);
326 
327 	if (rmdir (directory) < 0)
328 		assert_not_reached ();
329 
330 	free (directory);
331 }
332 
333 static void
test_load_already(void)334 test_load_already (void)
335 {
336 	CK_ATTRIBUTE cert[] = {
337 		{ CKA_CLASS, &certificate, sizeof (certificate) },
338 		{ CKA_SUBJECT, (void *)test_cacert3_ca_subject, sizeof (test_cacert3_ca_subject) },
339 		{ CKA_VALUE, (void *)test_cacert3_ca_der, sizeof (test_cacert3_ca_der) },
340 		{ CKA_INVALID },
341 	};
342 
343 	CK_OBJECT_HANDLE handle;
344 	int ret;
345 
346 	p11_test_file_write (test.directory, "test.cer", test_cacert3_ca_der,
347 	                     sizeof (test_cacert3_ca_der));
348 
349 	ret = p11_token_load (test.token);
350 	assert_num_eq (ret, 1);
351 	handle = p11_index_find (test.index, cert, -1);
352 	assert (handle != 0);
353 
354 	/* Have to wait to make sure changes are detected */
355 	p11_sleep_ms (1100);
356 
357 	ret = p11_token_load (test.token);
358 	assert_num_eq (ret, 0);
359 	assert_num_eq (p11_index_find (test.index, cert, -1), handle);
360 }
361 
362 static void
test_load_unreadable(void)363 test_load_unreadable (void)
364 {
365 	CK_ATTRIBUTE cert[] = {
366 		{ CKA_CLASS, &certificate, sizeof (certificate) },
367 		{ CKA_SUBJECT, (void *)test_cacert3_ca_subject, sizeof (test_cacert3_ca_subject) },
368 		{ CKA_VALUE, (void *)test_cacert3_ca_der, sizeof (test_cacert3_ca_der) },
369 		{ CKA_INVALID },
370 	};
371 
372 	int ret;
373 
374 	p11_test_file_write (test.directory, "test.cer", test_cacert3_ca_der,
375 	                     sizeof (test_cacert3_ca_der));
376 
377 	ret = p11_token_load (test.token);
378 	assert_num_eq (ret, 1);
379 	assert (p11_index_find (test.index, cert, -1) != 0);
380 
381 	p11_test_file_write (test.directory, "test.cer", "", 0);
382 
383 	/* Have to wait to make sure changes are detected */
384 	p11_sleep_ms (1100);
385 
386 	ret = p11_token_load (test.token);
387 	assert_num_eq (ret, 0);
388 	assert (p11_index_find (test.index, cert, -1) == 0);
389 }
390 
391 static void
test_load_gone(void)392 test_load_gone (void)
393 {
394 	CK_ATTRIBUTE cert[] = {
395 		{ CKA_CLASS, &certificate, sizeof (certificate) },
396 		{ CKA_SUBJECT, (void *)test_cacert3_ca_subject, sizeof (test_cacert3_ca_subject) },
397 		{ CKA_VALUE, (void *)test_cacert3_ca_der, sizeof (test_cacert3_ca_der) },
398 		{ CKA_INVALID },
399 	};
400 
401 	int ret;
402 
403 	p11_test_file_write (test.directory, "test.cer", test_cacert3_ca_der,
404 	                     sizeof (test_cacert3_ca_der));
405 
406 	ret = p11_token_load (test.token);
407 	assert_num_eq (ret, 1);
408 	assert (p11_index_find (test.index, cert, -1) != 0);
409 
410 	p11_test_file_delete (test.directory, "test.cer");
411 
412 	/* Have to wait to make sure changes are detected */
413 	p11_sleep_ms (1100);
414 
415 	ret = p11_token_load (test.token);
416 	assert_num_eq (ret, 0);
417 	assert (p11_index_find (test.index, cert, -1) == 0);
418 }
419 
420 static void
test_load_found(void)421 test_load_found (void)
422 {
423 	CK_ATTRIBUTE cert[] = {
424 		{ CKA_CLASS, &certificate, sizeof (certificate) },
425 		{ CKA_SUBJECT, (void *)test_cacert3_ca_subject, sizeof (test_cacert3_ca_subject) },
426 		{ CKA_VALUE, (void *)test_cacert3_ca_der, sizeof (test_cacert3_ca_der) },
427 		{ CKA_INVALID },
428 	};
429 
430 	int ret;
431 
432 	ret = p11_token_load (test.token);
433 	assert_num_eq (ret, 0);
434 	assert (p11_index_find (test.index, cert, -1) == 0);
435 
436 	/* Have to wait to make sure changes are detected */
437 	p11_sleep_ms (1100);
438 
439 	p11_test_file_write (test.directory, "test.cer", test_cacert3_ca_der,
440 	                     sizeof (test_cacert3_ca_der));
441 
442 	ret = p11_token_load (test.token);
443 	assert_num_eq (ret, 1);
444 	assert (p11_index_find (test.index, cert, -1) != 0);
445 }
446 
447 static void
test_load_contrived(void)448 test_load_contrived (void)
449 {
450 	int ret;
451 	p11_index *index;
452 
453 	p11_test_file_write (test.directory, "contrived.der", test_contrived_der,
454 	                     sizeof (test_contrived_der));
455 
456 	ret = p11_token_load (test.token);
457 	assert_num_eq (ret, 1);
458 
459 	index = p11_token_index (test.token);
460 	ret = p11_index_size (index);
461 	assert_num_eq (ret, 3);
462 }
463 
464 static void
test_reload_changed(void)465 test_reload_changed (void)
466 {
467 	CK_ATTRIBUTE cacert3[] = {
468 		{ CKA_CLASS, &certificate, sizeof (certificate) },
469 		{ CKA_SUBJECT, (void *)test_cacert3_ca_subject, sizeof (test_cacert3_ca_subject) },
470 		{ CKA_VALUE, (void *)test_cacert3_ca_der, sizeof (test_cacert3_ca_der) },
471 		{ CKA_INVALID },
472 	};
473 
474 	CK_ATTRIBUTE verisign[] = {
475 		{ CKA_CLASS, &certificate, sizeof (certificate) },
476 		{ CKA_VALUE, (void *)verisign_v1_ca, sizeof (verisign_v1_ca) },
477 		{ CKA_INVALID },
478 	};
479 
480 	CK_ATTRIBUTE *attrs;
481 	CK_OBJECT_HANDLE handle;
482 	int ret;
483 
484 	/* Just one file */
485 	p11_test_file_write (test.directory, "test.cer", test_cacert3_ca_der,
486 	                     sizeof (test_cacert3_ca_der));
487 
488 	ret = p11_token_load (test.token);
489 	assert_num_eq (ret, 1);
490 	handle = p11_index_find (test.index, cacert3, -1);
491 	assert (handle != 0);
492 
493 	/* Replace the file with verisign */
494 	p11_test_file_write (test.directory, "test.cer", verisign_v1_ca,
495 	                     sizeof (verisign_v1_ca));
496 
497 	/* Add another file with cacert3, but not reloaded */
498 	p11_test_file_write (test.directory, "another.cer", test_cacert3_ca_der,
499 	                     sizeof (test_cacert3_ca_der));
500 
501 	attrs = p11_index_lookup (test.index, handle);
502 	assert_ptr_not_null (attrs);
503 	if (!p11_token_reload (test.token, attrs))
504 		assert_not_reached ();
505 
506 	assert (p11_index_find (test.index, cacert3, -1) == 0);
507 	assert (p11_index_find (test.index, verisign, -1) != 0);
508 }
509 
510 static void
test_reload_gone(void)511 test_reload_gone (void)
512 {
513 	CK_ATTRIBUTE cacert3[] = {
514 		{ CKA_CLASS, &certificate, sizeof (certificate) },
515 		{ CKA_SUBJECT, (void *)test_cacert3_ca_subject, sizeof (test_cacert3_ca_subject) },
516 		{ CKA_VALUE, (void *)test_cacert3_ca_der, sizeof (test_cacert3_ca_der) },
517 		{ CKA_INVALID },
518 	};
519 
520 	CK_ATTRIBUTE verisign[] = {
521 		{ CKA_CLASS, &certificate, sizeof (certificate) },
522 		{ CKA_VALUE, (void *)verisign_v1_ca, sizeof (verisign_v1_ca) },
523 		{ CKA_INVALID },
524 	};
525 
526 	CK_ATTRIBUTE *attrs;
527 	CK_OBJECT_HANDLE handle;
528 	int ret;
529 
530 	/* Just one file */
531 	p11_test_file_write (test.directory, "cacert3.cer", test_cacert3_ca_der,
532 	                     sizeof (test_cacert3_ca_der));
533 	p11_test_file_write (test.directory, "verisign.cer", verisign_v1_ca,
534 	                     sizeof (verisign_v1_ca));
535 
536 	ret = p11_token_load (test.token);
537 	assert_num_eq (ret, 2);
538 	handle = p11_index_find (test.index, cacert3, -1);
539 	assert (handle != 0);
540 	assert (p11_index_find (test.index, verisign, -1) != 0);
541 
542 	p11_test_file_delete (test.directory, "cacert3.cer");
543 	p11_test_file_delete (test.directory, "verisign.cer");
544 
545 	attrs = p11_index_lookup (test.index, handle);
546 	assert_ptr_not_null (attrs);
547 	if (p11_token_reload (test.token, attrs))
548 		assert_not_reached ();
549 
550 	assert (p11_index_find (test.index, cacert3, -1) == 0);
551 	assert (p11_index_find (test.index, verisign, -1) != 0);
552 }
553 
554 static void
test_reload_no_origin(void)555 test_reload_no_origin (void)
556 {
557 	CK_ATTRIBUTE cacert3[] = {
558 		{ CKA_CLASS, &certificate, sizeof (certificate) },
559 		{ CKA_SUBJECT, (void *)test_cacert3_ca_subject, sizeof (test_cacert3_ca_subject) },
560 		{ CKA_VALUE, (void *)test_cacert3_ca_der, sizeof (test_cacert3_ca_der) },
561 		{ CKA_INVALID },
562 	};
563 
564 	if (p11_token_reload (test.token, cacert3))
565 		assert_not_reached ();
566 }
567 
568 static void
test_write_new(void)569 test_write_new (void)
570 {
571 	CK_ATTRIBUTE original[] = {
572 		{ CKA_CLASS, &data, sizeof (data) },
573 		{ CKA_LABEL, "Yay!", 4 },
574 		{ CKA_VALUE, "eight", 5 },
575 		{ CKA_TOKEN, &truev, sizeof (truev) },
576 		{ CKA_INVALID }
577 	};
578 
579 	CK_ATTRIBUTE expected[] = {
580 		{ CKA_CLASS, &data, sizeof (data) },
581 		{ CKA_LABEL, "Yay!", 4 },
582 		{ CKA_VALUE, "eight", 5 },
583 		{ CKA_APPLICATION, "", 0 },
584 		{ CKA_OBJECT_ID, "", 0 },
585 		{ CKA_INVALID }
586 	};
587 
588 	CK_OBJECT_HANDLE handle;
589 	p11_array *parsed;
590 	char *path;
591 	CK_RV rv;
592 	int ret;
593 
594 	rv = p11_index_add (test.index, original, 4, &handle);
595 	assert_num_eq (rv, CKR_OK);
596 
597 	/* The expected file name */
598 	path = p11_path_build (test.directory, "Yay_.p11-kit", NULL);
599 	ret = p11_parse_file (test.parser, path, NULL, 0);
600 	assert_num_eq (ret, P11_PARSE_SUCCESS);
601 	free (path);
602 
603 	parsed = p11_parser_parsed (test.parser);
604 	assert_num_eq (parsed->num, 1);
605 
606 	test_check_attrs (expected, parsed->elem[0]);
607 }
608 
609 static void
test_write_no_label(void)610 test_write_no_label (void)
611 {
612 	CK_ATTRIBUTE original[] = {
613 		{ CKA_CLASS, &data, sizeof (data) },
614 		{ CKA_VALUE, "eight", 5 },
615 		{ CKA_TOKEN, &truev, sizeof (truev) },
616 		{ CKA_INVALID }
617 	};
618 
619 	CK_ATTRIBUTE expected[] = {
620 		{ CKA_CLASS, &data, sizeof (data) },
621 		{ CKA_LABEL, "", 0 },
622 		{ CKA_VALUE, "eight", 5 },
623 		{ CKA_APPLICATION, "", 0 },
624 		{ CKA_OBJECT_ID, "", 0 },
625 		{ CKA_INVALID }
626 	};
627 
628 	CK_OBJECT_HANDLE handle;
629 	p11_array *parsed;
630 	char *path;
631 	CK_RV rv;
632 	int ret;
633 
634 	rv = p11_index_add (test.index, original, 4, &handle);
635 	assert_num_eq (rv, CKR_OK);
636 
637 	/* The expected file name */
638 	path = p11_path_build (test.directory, "data.p11-kit", NULL);
639 	ret = p11_parse_file (test.parser, path, NULL, 0);
640 	assert_num_eq (ret, P11_PARSE_SUCCESS);
641 	free (path);
642 
643 	parsed = p11_parser_parsed (test.parser);
644 	assert_num_eq (parsed->num, 1);
645 
646 	test_check_attrs (expected, parsed->elem[0]);
647 }
648 
649 static void
test_modify_multiple(void)650 test_modify_multiple (void)
651 {
652 	const char *test_data =
653 		"# This file has been auto-generated and written by p11-kit.\n"
654 		"[p11-kit-object-v1]\n"
655 		"class: data\n"
656 		"label: \"first\"\n"
657 		"value: \"1\"\n"
658 		"\n"
659 		"[p11-kit-object-v1]\n"
660 		"class: data\n"
661 		"label: \"second\"\n"
662 		"value: \"2\"\n"
663 		"\n"
664 		"[p11-kit-object-v1]\n"
665 		"class: data\n"
666 		"label: \"third\"\n"
667 		"value: \"3\"\n";
668 
669 	CK_ATTRIBUTE first[] = {
670 		{ CKA_CLASS, &data, sizeof (data) },
671 		{ CKA_LABEL, "first", 5 },
672 		{ CKA_VALUE, "1", 1 },
673 		{ CKA_INVALID },
674 	};
675 
676 	CK_ATTRIBUTE second[] = {
677 		{ CKA_CLASS, &data, sizeof (data) },
678 		{ CKA_LABEL, "zwei", 4 },
679 		{ CKA_VALUE, "2", 2 },
680 		{ CKA_INVALID },
681 	};
682 
683 	CK_ATTRIBUTE third[] = {
684 		{ CKA_CLASS, &data, sizeof (data) },
685 		{ CKA_LABEL, "third", 5 },
686 		{ CKA_VALUE, "3", 1 },
687 		{ CKA_INVALID },
688 	};
689 
690 	CK_ATTRIBUTE match = { CKA_LABEL, "second", 6 };
691 
692 	CK_OBJECT_HANDLE handle;
693 	p11_array *parsed;
694 	char *path;
695 	int ret;
696 	CK_RV rv;
697 
698 	p11_test_file_write (test.directory, "Test.p11-kit", test_data, strlen (test_data));
699 
700 	/* Reload now that we have this new file */
701 	p11_token_load (test.token);
702 
703 	handle = p11_index_find (test.index, &match, 1);
704 
705 	rv = p11_index_update (test.index, handle, p11_attrs_dup (second));
706 	assert_num_eq (rv, CKR_OK);
707 
708 	/* Now read in the file and make sure it has all the objects */
709 	path = p11_path_build (test.directory, "Test.p11-kit", NULL);
710 	ret = p11_parse_file (test.parser, path, NULL, 0);
711 	assert_num_eq (ret, P11_PARSE_SUCCESS);
712 	free (path);
713 
714 	parsed = p11_parser_parsed (test.parser);
715 	assert_num_eq (parsed->num, 3);
716 
717 	/* The modified one will be first */
718 	test_check_attrs (second, parsed->elem[0]);
719 	test_check_attrs (first, parsed->elem[1]);
720 	test_check_attrs (third, parsed->elem[2]);
721 }
722 
723 static void
test_remove_one(void)724 test_remove_one (void)
725 {
726 	const char *test_data =
727 		"[p11-kit-object-v1]\n"
728 		"class: data\n"
729 		"label: \"first\"\n"
730 		"value: \"1\"\n"
731 		"\n";
732 
733 	CK_ATTRIBUTE match = { CKA_LABEL, "first", 5 };
734 
735 	CK_OBJECT_HANDLE handle;
736 	CK_RV rv;
737 
738 	p11_test_file_write (test.directory, "Test.p11-kit", test_data, strlen (test_data));
739 	test_check_directory (test.directory, ("Test.p11-kit", NULL));
740 
741 	/* Reload now that we have this new file */
742 	p11_token_load (test.token);
743 
744 	handle = p11_index_find (test.index, &match, 1);
745 	assert_num_cmp (handle, !=, 0);
746 
747 	rv = p11_index_remove (test.index, handle);
748 	assert_num_eq (rv, CKR_OK);
749 
750 	/* No other files in the test directory, all files gone */
751 	test_check_directory (test.directory, (NULL, NULL));
752 }
753 
754 static void
test_remove_multiple(void)755 test_remove_multiple (void)
756 {
757 	const char *test_data =
758 		"[p11-kit-object-v1]\n"
759 		"class: data\n"
760 		"label: \"first\"\n"
761 		"value: \"1\"\n"
762 		"\n"
763 		"[p11-kit-object-v1]\n"
764 		"class: data\n"
765 		"label: \"second\"\n"
766 		"value: \"2\"\n"
767 		"\n"
768 		"[p11-kit-object-v1]\n"
769 		"class: data\n"
770 		"label: \"third\"\n"
771 		"value: \"3\"\n";
772 
773 	CK_ATTRIBUTE first[] = {
774 		{ CKA_CLASS, &data, sizeof (data) },
775 		{ CKA_LABEL, "first", 5 },
776 		{ CKA_VALUE, "1", 1 },
777 		{ CKA_INVALID },
778 	};
779 
780 	CK_ATTRIBUTE third[] = {
781 		{ CKA_CLASS, &data, sizeof (data) },
782 		{ CKA_LABEL, "third", 5 },
783 		{ CKA_VALUE, "3", 1 },
784 		{ CKA_INVALID },
785 	};
786 
787 	CK_ATTRIBUTE match = { CKA_LABEL, "second", 6 };
788 
789 	CK_OBJECT_HANDLE handle;
790 	p11_array *parsed;
791 	char *path;
792 	int ret;
793 	CK_RV rv;
794 
795 	p11_test_file_write (test.directory, "Test.p11-kit", test_data, strlen (test_data));
796 
797 	/* Reload now that we have this new file */
798 	p11_token_load (test.token);
799 
800 	handle = p11_index_find (test.index, &match, 1);
801 	assert_num_cmp (handle, !=, 0);
802 
803 	rv = p11_index_remove (test.index, handle);
804 	assert_num_eq (rv, CKR_OK);
805 
806 	/* Now read in the file and make sure it has all the objects */
807 	path = p11_path_build (test.directory, "Test.p11-kit", NULL);
808 	ret = p11_parse_file (test.parser, path, NULL, 0);
809 	assert_num_eq (ret, P11_PARSE_SUCCESS);
810 	free (path);
811 
812 	parsed = p11_parser_parsed (test.parser);
813 	assert_num_eq (parsed->num, 2);
814 
815 	/* The modified one will be first */
816 	test_check_attrs (first, parsed->elem[0]);
817 	test_check_attrs (third, parsed->elem[1]);
818 }
819 
820 int
main(int argc,char * argv[])821 main (int argc,
822       char *argv[])
823 {
824 	p11_fixture (setup, teardown);
825 	p11_testx (test_token_load, SRCDIR "/trust/input", "/token/load");
826 	p11_testx (test_token_flags, SRCDIR "/trust/input", "/token/flags");
827 	p11_testx (test_token_path, "/wheee", "/token/path");
828 	p11_testx (test_token_label, "/wheee", "/token/label");
829 	p11_testx (test_token_slot, "/unneeded", "/token/slot");
830 
831 	p11_fixture (setup_writable, teardown_writable);
832 	p11_test (test_not_writable, "/token/not-writable");
833 	p11_test (test_writable_no_exist, "/token/writable-no-exist");
834 
835 	p11_fixture (setup_temp, teardown_temp);
836 	p11_test (test_writable_exists, "/token/writable-exists");
837 	p11_test (test_load_found, "/token/load-found");
838 	p11_test (test_load_already, "/token/load-already");
839 	p11_test (test_load_unreadable, "/token/load-unreadable");
840 	p11_test (test_load_gone, "/token/load-gone");
841 	p11_test (test_load_contrived, "/token/load-contrived");
842 	p11_test (test_reload_changed, "/token/reload-changed");
843 	p11_test (test_reload_gone, "/token/reload-gone");
844 	p11_test (test_reload_no_origin, "/token/reload-no-origin");
845 	p11_test (test_write_new, "/token/write-new");
846 	p11_test (test_write_no_label, "/token/write-no-label");
847 	p11_test (test_modify_multiple, "/token/modify-multiple");
848 	p11_test (test_remove_one, "/token/remove-one");
849 	p11_test (test_remove_multiple, "/token/remove-multiple");
850 
851 	return p11_test_run (argc, argv);
852 }
853