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