qemu/tests/unit/test-crypto-secret.c
<<
>>
Prefs
   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#ifdef CONFIG_KEYUTILS
  28#include "crypto/secret_keyring.h"
  29#include <keyutils.h>
  30#endif
  31
  32static 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
  52static 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
  86static 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
 100static 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#ifdef CONFIG_KEYUTILS
 132
 133#define DESCRIPTION "qemu_test_secret"
 134#define PAYLOAD "Test Payload"
 135
 136
 137static 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
 165static 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
 190static 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
 216static 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
 242static 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 responce 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 */
 272
 273static 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
 294static 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
 309static 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
 330static 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
 351static 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
 370static 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
 390static 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
 423static 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
 455static 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
 481static 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
 507static 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
 532static 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
 558int 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#ifdef CONFIG_KEYUTILS
 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 */
 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