xref: /qemu/tests/unit/test-crypto-secret.c (revision 8b7b9c5c)
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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