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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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