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