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