1 /*
2 * QEMU Crypto secret handling
3 *
4 * Copyright (c) 2015 Red Hat, Inc.
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18 *
19 */
20
21 #include "qemu/osdep.h"
22
23 #include "crypto/init.h"
24 #include "crypto/secret.h"
25 #include "qapi/error.h"
26 #include "qemu/module.h"
27 #if defined(CONFIG_KEYUTILS) && defined(CONFIG_SECRET_KEYRING)
28 #include "crypto/secret_keyring.h"
29 #include <keyutils.h>
30 #endif
31
test_secret_direct(void)32 static void test_secret_direct(void)
33 {
34 Object *sec = object_new_with_props(
35 TYPE_QCRYPTO_SECRET,
36 object_get_objects_root(),
37 "sec0",
38 &error_abort,
39 "data", "123456",
40 NULL);
41
42 char *pw = qcrypto_secret_lookup_as_utf8("sec0",
43 &error_abort);
44
45 g_assert_cmpstr(pw, ==, "123456");
46
47 object_unparent(sec);
48 g_free(pw);
49 }
50
51
test_secret_indirect_good(void)52 static void test_secret_indirect_good(void)
53 {
54 Object *sec;
55 char *fname = NULL;
56 int fd = g_file_open_tmp("qemu-test-crypto-secret-XXXXXX",
57 &fname,
58 NULL);
59
60 g_assert(fd >= 0);
61 g_assert_nonnull(fname);
62
63 g_assert(write(fd, "123456", 6) == 6);
64
65 sec = object_new_with_props(
66 TYPE_QCRYPTO_SECRET,
67 object_get_objects_root(),
68 "sec0",
69 &error_abort,
70 "file", fname,
71 NULL);
72
73 char *pw = qcrypto_secret_lookup_as_utf8("sec0",
74 &error_abort);
75
76 g_assert_cmpstr(pw, ==, "123456");
77
78 object_unparent(sec);
79 g_free(pw);
80 close(fd);
81 unlink(fname);
82 g_free(fname);
83 }
84
85
test_secret_indirect_badfile(void)86 static void test_secret_indirect_badfile(void)
87 {
88 Object *sec = object_new_with_props(
89 TYPE_QCRYPTO_SECRET,
90 object_get_objects_root(),
91 "sec0",
92 NULL,
93 "file", "does-not-exist",
94 NULL);
95
96 g_assert(sec == NULL);
97 }
98
99
test_secret_indirect_emptyfile(void)100 static void test_secret_indirect_emptyfile(void)
101 {
102 Object *sec;
103 char *fname = NULL;
104 int fd = g_file_open_tmp("qemu-test-crypto-secretXXXXXX",
105 &fname,
106 NULL);
107
108 g_assert(fd >= 0);
109 g_assert_nonnull(fname);
110
111 sec = object_new_with_props(
112 TYPE_QCRYPTO_SECRET,
113 object_get_objects_root(),
114 "sec0",
115 &error_abort,
116 "file", fname,
117 NULL);
118
119 char *pw = qcrypto_secret_lookup_as_utf8("sec0",
120 &error_abort);
121
122 g_assert_cmpstr(pw, ==, "");
123
124 object_unparent(sec);
125 g_free(pw);
126 close(fd);
127 unlink(fname);
128 g_free(fname);
129 }
130
131 #if defined(CONFIG_KEYUTILS) && defined(CONFIG_SECRET_KEYRING)
132
133 #define DESCRIPTION "qemu_test_secret"
134 #define PAYLOAD "Test Payload"
135
136
test_secret_keyring_good(void)137 static void test_secret_keyring_good(void)
138 {
139 char key_str[16];
140 Object *sec;
141 int32_t key = add_key("user", DESCRIPTION, PAYLOAD,
142 strlen(PAYLOAD), KEY_SPEC_PROCESS_KEYRING);
143
144 g_assert(key >= 0);
145
146 snprintf(key_str, sizeof(key_str), "0x%08x", key);
147 sec = object_new_with_props(
148 TYPE_QCRYPTO_SECRET_KEYRING,
149 object_get_objects_root(),
150 "sec0",
151 &error_abort,
152 "serial", key_str,
153 NULL);
154
155 assert(0 <= keyctl_unlink(key, KEY_SPEC_PROCESS_KEYRING));
156 char *pw = qcrypto_secret_lookup_as_utf8("sec0",
157 &error_abort);
158 g_assert_cmpstr(pw, ==, PAYLOAD);
159
160 object_unparent(sec);
161 g_free(pw);
162 }
163
164
test_secret_keyring_revoked_key(void)165 static void test_secret_keyring_revoked_key(void)
166 {
167 char key_str[16];
168 Object *sec;
169 int32_t key = add_key("user", DESCRIPTION, PAYLOAD,
170 strlen(PAYLOAD), KEY_SPEC_PROCESS_KEYRING);
171 g_assert(key >= 0);
172 g_assert_false(keyctl_revoke(key));
173
174 snprintf(key_str, sizeof(key_str), "0x%08x", key);
175 sec = object_new_with_props(
176 TYPE_QCRYPTO_SECRET_KEYRING,
177 object_get_objects_root(),
178 "sec0",
179 NULL,
180 "serial", key_str,
181 NULL);
182
183 g_assert(errno == EKEYREVOKED);
184 g_assert(sec == NULL);
185
186 keyctl_unlink(key, KEY_SPEC_PROCESS_KEYRING);
187 }
188
189
test_secret_keyring_expired_key(void)190 static void test_secret_keyring_expired_key(void)
191 {
192 char key_str[16];
193 Object *sec;
194 int32_t key = add_key("user", DESCRIPTION, PAYLOAD,
195 strlen(PAYLOAD), KEY_SPEC_PROCESS_KEYRING);
196 g_assert(key >= 0);
197 g_assert_false(keyctl_set_timeout(key, 1));
198 sleep(1);
199
200 snprintf(key_str, sizeof(key_str), "0x%08x", key);
201 sec = object_new_with_props(
202 TYPE_QCRYPTO_SECRET_KEYRING,
203 object_get_objects_root(),
204 "sec0",
205 NULL,
206 "serial", key_str,
207 NULL);
208
209 g_assert(errno == EKEYEXPIRED);
210 g_assert(sec == NULL);
211
212 keyctl_unlink(key, KEY_SPEC_PROCESS_KEYRING);
213 }
214
215
test_secret_keyring_bad_serial_key(void)216 static void test_secret_keyring_bad_serial_key(void)
217 {
218 Object *sec;
219
220 sec = object_new_with_props(
221 TYPE_QCRYPTO_SECRET_KEYRING,
222 object_get_objects_root(),
223 "sec0",
224 NULL,
225 "serial", "1",
226 NULL);
227
228 g_assert(errno == ENOKEY);
229 g_assert(sec == NULL);
230 }
231
232 /*
233 * TODO
234 * test_secret_keyring_bad_key_access_right() is not working yet.
235 * We don't know yet if this due a bug in the Linux kernel or
236 * whether it's normal syscall behavior.
237 * We've requested information from kernel maintainers.
238 * See: <https://www.spinics.net/lists/keyrings/index.html>
239 * Thread: 'security/keys: remove possessor verify after key permission check'
240 */
241
test_secret_keyring_bad_key_access_right(void)242 static void test_secret_keyring_bad_key_access_right(void)
243 {
244 char key_str[16];
245 Object *sec;
246
247 g_test_skip("TODO: Need response from Linux kernel maintainers");
248 return;
249
250 int32_t key = add_key("user", DESCRIPTION, PAYLOAD,
251 strlen(PAYLOAD), KEY_SPEC_PROCESS_KEYRING);
252 g_assert(key >= 0);
253 g_assert_false(keyctl_setperm(key, KEY_POS_ALL & (~KEY_POS_READ)));
254
255 snprintf(key_str, sizeof(key_str), "0x%08x", key);
256
257 sec = object_new_with_props(
258 TYPE_QCRYPTO_SECRET_KEYRING,
259 object_get_objects_root(),
260 "sec0",
261 NULL,
262 "serial", key_str,
263 NULL);
264
265 g_assert(errno == EACCES);
266 g_assert(sec == NULL);
267
268 keyctl_unlink(key, KEY_SPEC_PROCESS_KEYRING);
269 }
270
271 #endif /* CONFIG_KEYUTILS && CONFIG_SECRET_KEYRING */
272
test_secret_noconv_base64_good(void)273 static void test_secret_noconv_base64_good(void)
274 {
275 Object *sec = object_new_with_props(
276 TYPE_QCRYPTO_SECRET,
277 object_get_objects_root(),
278 "sec0",
279 &error_abort,
280 "data", "MTIzNDU2",
281 "format", "base64",
282 NULL);
283
284 char *pw = qcrypto_secret_lookup_as_base64("sec0",
285 &error_abort);
286
287 g_assert_cmpstr(pw, ==, "MTIzNDU2");
288
289 object_unparent(sec);
290 g_free(pw);
291 }
292
293
test_secret_noconv_base64_bad(void)294 static void test_secret_noconv_base64_bad(void)
295 {
296 Object *sec = object_new_with_props(
297 TYPE_QCRYPTO_SECRET,
298 object_get_objects_root(),
299 "sec0",
300 NULL,
301 "data", "MTI$NDU2",
302 "format", "base64",
303 NULL);
304
305 g_assert(sec == NULL);
306 }
307
308
test_secret_noconv_utf8(void)309 static void test_secret_noconv_utf8(void)
310 {
311 Object *sec = object_new_with_props(
312 TYPE_QCRYPTO_SECRET,
313 object_get_objects_root(),
314 "sec0",
315 &error_abort,
316 "data", "123456",
317 "format", "raw",
318 NULL);
319
320 char *pw = qcrypto_secret_lookup_as_utf8("sec0",
321 &error_abort);
322
323 g_assert_cmpstr(pw, ==, "123456");
324
325 object_unparent(sec);
326 g_free(pw);
327 }
328
329
test_secret_conv_base64_utf8valid(void)330 static void test_secret_conv_base64_utf8valid(void)
331 {
332 Object *sec = object_new_with_props(
333 TYPE_QCRYPTO_SECRET,
334 object_get_objects_root(),
335 "sec0",
336 &error_abort,
337 "data", "MTIzNDU2",
338 "format", "base64",
339 NULL);
340
341 char *pw = qcrypto_secret_lookup_as_utf8("sec0",
342 &error_abort);
343
344 g_assert_cmpstr(pw, ==, "123456");
345
346 object_unparent(sec);
347 g_free(pw);
348 }
349
350
test_secret_conv_base64_utf8invalid(void)351 static void test_secret_conv_base64_utf8invalid(void)
352 {
353 Object *sec = object_new_with_props(
354 TYPE_QCRYPTO_SECRET,
355 object_get_objects_root(),
356 "sec0",
357 &error_abort,
358 "data", "f0VMRgIBAQAAAA==",
359 "format", "base64",
360 NULL);
361
362 char *pw = qcrypto_secret_lookup_as_utf8("sec0",
363 NULL);
364 g_assert(pw == NULL);
365
366 object_unparent(sec);
367 }
368
369
test_secret_conv_utf8_base64(void)370 static void test_secret_conv_utf8_base64(void)
371 {
372 Object *sec = object_new_with_props(
373 TYPE_QCRYPTO_SECRET,
374 object_get_objects_root(),
375 "sec0",
376 &error_abort,
377 "data", "123456",
378 NULL);
379
380 char *pw = qcrypto_secret_lookup_as_base64("sec0",
381 &error_abort);
382
383 g_assert_cmpstr(pw, ==, "MTIzNDU2");
384
385 object_unparent(sec);
386 g_free(pw);
387 }
388
389
test_secret_crypt_raw(void)390 static void test_secret_crypt_raw(void)
391 {
392 Object *master = object_new_with_props(
393 TYPE_QCRYPTO_SECRET,
394 object_get_objects_root(),
395 "master",
396 &error_abort,
397 "data", "9miloPQCzGy+TL6aonfzVcptibCmCIhKzrnlfwiWivk=",
398 "format", "base64",
399 NULL);
400 Object *sec = object_new_with_props(
401 TYPE_QCRYPTO_SECRET,
402 object_get_objects_root(),
403 "sec0",
404 &error_abort,
405 "data",
406 "\xCC\xBF\xF7\x09\x46\x19\x0B\x52\x2A\x3A\xB4\x6B\xCD\x7A\xB0\xB0",
407 "format", "raw",
408 "keyid", "master",
409 "iv", "0I7Gw/TKuA+Old2W2apQ3g==",
410 NULL);
411
412 char *pw = qcrypto_secret_lookup_as_utf8("sec0",
413 &error_abort);
414
415 g_assert_cmpstr(pw, ==, "123456");
416
417 object_unparent(sec);
418 object_unparent(master);
419 g_free(pw);
420 }
421
422
test_secret_crypt_base64(void)423 static void test_secret_crypt_base64(void)
424 {
425 Object *master = object_new_with_props(
426 TYPE_QCRYPTO_SECRET,
427 object_get_objects_root(),
428 "master",
429 &error_abort,
430 "data", "9miloPQCzGy+TL6aonfzVcptibCmCIhKzrnlfwiWivk=",
431 "format", "base64",
432 NULL);
433 Object *sec = object_new_with_props(
434 TYPE_QCRYPTO_SECRET,
435 object_get_objects_root(),
436 "sec0",
437 &error_abort,
438 "data", "zL/3CUYZC1IqOrRrzXqwsA==",
439 "format", "base64",
440 "keyid", "master",
441 "iv", "0I7Gw/TKuA+Old2W2apQ3g==",
442 NULL);
443
444 char *pw = qcrypto_secret_lookup_as_utf8("sec0",
445 &error_abort);
446
447 g_assert_cmpstr(pw, ==, "123456");
448
449 object_unparent(sec);
450 object_unparent(master);
451 g_free(pw);
452 }
453
454
test_secret_crypt_short_key(void)455 static void test_secret_crypt_short_key(void)
456 {
457 Object *master = object_new_with_props(
458 TYPE_QCRYPTO_SECRET,
459 object_get_objects_root(),
460 "master",
461 &error_abort,
462 "data", "9miloPQCzGy+TL6aonfzVc",
463 "format", "base64",
464 NULL);
465 Object *sec = object_new_with_props(
466 TYPE_QCRYPTO_SECRET,
467 object_get_objects_root(),
468 "sec0",
469 NULL,
470 "data", "zL/3CUYZC1IqOrRrzXqwsA==",
471 "format", "raw",
472 "keyid", "master",
473 "iv", "0I7Gw/TKuA+Old2W2apQ3g==",
474 NULL);
475
476 g_assert(sec == NULL);
477 object_unparent(master);
478 }
479
480
test_secret_crypt_short_iv(void)481 static void test_secret_crypt_short_iv(void)
482 {
483 Object *master = object_new_with_props(
484 TYPE_QCRYPTO_SECRET,
485 object_get_objects_root(),
486 "master",
487 &error_abort,
488 "data", "9miloPQCzGy+TL6aonfzVcptibCmCIhKzrnlfwiWivk=",
489 "format", "base64",
490 NULL);
491 Object *sec = object_new_with_props(
492 TYPE_QCRYPTO_SECRET,
493 object_get_objects_root(),
494 "sec0",
495 NULL,
496 "data", "zL/3CUYZC1IqOrRrzXqwsA==",
497 "format", "raw",
498 "keyid", "master",
499 "iv", "0I7Gw/TKuA+Old2W2a",
500 NULL);
501
502 g_assert(sec == NULL);
503 object_unparent(master);
504 }
505
506
test_secret_crypt_missing_iv(void)507 static void test_secret_crypt_missing_iv(void)
508 {
509 Object *master = object_new_with_props(
510 TYPE_QCRYPTO_SECRET,
511 object_get_objects_root(),
512 "master",
513 &error_abort,
514 "data", "9miloPQCzGy+TL6aonfzVcptibCmCIhKzrnlfwiWivk=",
515 "format", "base64",
516 NULL);
517 Object *sec = object_new_with_props(
518 TYPE_QCRYPTO_SECRET,
519 object_get_objects_root(),
520 "sec0",
521 NULL,
522 "data", "zL/3CUYZC1IqOrRrzXqwsA==",
523 "format", "raw",
524 "keyid", "master",
525 NULL);
526
527 g_assert(sec == NULL);
528 object_unparent(master);
529 }
530
531
test_secret_crypt_bad_iv(void)532 static void test_secret_crypt_bad_iv(void)
533 {
534 Object *master = object_new_with_props(
535 TYPE_QCRYPTO_SECRET,
536 object_get_objects_root(),
537 "master",
538 &error_abort,
539 "data", "9miloPQCzGy+TL6aonfzVcptibCmCIhKzrnlfwiWivk=",
540 "format", "base64",
541 NULL);
542 Object *sec = object_new_with_props(
543 TYPE_QCRYPTO_SECRET,
544 object_get_objects_root(),
545 "sec0",
546 NULL,
547 "data", "zL/3CUYZC1IqOrRrzXqwsA==",
548 "format", "raw",
549 "keyid", "master",
550 "iv", "0I7Gw/TK$$uA+Old2W2a",
551 NULL);
552
553 g_assert(sec == NULL);
554 object_unparent(master);
555 }
556
557
main(int argc,char ** argv)558 int main(int argc, char **argv)
559 {
560 module_call_init(MODULE_INIT_QOM);
561 g_test_init(&argc, &argv, NULL);
562
563 g_assert(qcrypto_init(NULL) == 0);
564
565 g_test_add_func("/crypto/secret/direct",
566 test_secret_direct);
567 g_test_add_func("/crypto/secret/indirect/good",
568 test_secret_indirect_good);
569 g_test_add_func("/crypto/secret/indirect/badfile",
570 test_secret_indirect_badfile);
571 g_test_add_func("/crypto/secret/indirect/emptyfile",
572 test_secret_indirect_emptyfile);
573
574 #if defined(CONFIG_KEYUTILS) && defined(CONFIG_SECRET_KEYRING)
575 g_test_add_func("/crypto/secret/keyring/good",
576 test_secret_keyring_good);
577 g_test_add_func("/crypto/secret/keyring/revoked_key",
578 test_secret_keyring_revoked_key);
579 g_test_add_func("/crypto/secret/keyring/expired_key",
580 test_secret_keyring_expired_key);
581 g_test_add_func("/crypto/secret/keyring/bad_serial_key",
582 test_secret_keyring_bad_serial_key);
583 g_test_add_func("/crypto/secret/keyring/bad_key_access_right",
584 test_secret_keyring_bad_key_access_right);
585 #endif /* CONFIG_KEYUTILS && CONFIG_SECRET_KEYRING */
586
587 g_test_add_func("/crypto/secret/noconv/base64/good",
588 test_secret_noconv_base64_good);
589 g_test_add_func("/crypto/secret/noconv/base64/bad",
590 test_secret_noconv_base64_bad);
591 g_test_add_func("/crypto/secret/noconv/utf8",
592 test_secret_noconv_utf8);
593 g_test_add_func("/crypto/secret/conv/base64/utf8valid",
594 test_secret_conv_base64_utf8valid);
595 g_test_add_func("/crypto/secret/conv/base64/utf8invalid",
596 test_secret_conv_base64_utf8invalid);
597 g_test_add_func("/crypto/secret/conv/utf8/base64",
598 test_secret_conv_utf8_base64);
599
600 g_test_add_func("/crypto/secret/crypt/raw",
601 test_secret_crypt_raw);
602 g_test_add_func("/crypto/secret/crypt/base64",
603 test_secret_crypt_base64);
604 g_test_add_func("/crypto/secret/crypt/shortkey",
605 test_secret_crypt_short_key);
606 g_test_add_func("/crypto/secret/crypt/shortiv",
607 test_secret_crypt_short_iv);
608 g_test_add_func("/crypto/secret/crypt/missingiv",
609 test_secret_crypt_missing_iv);
610 g_test_add_func("/crypto/secret/crypt/badiv",
611 test_secret_crypt_bad_iv);
612
613 return g_test_run();
614 }
615