]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/test/test-tpm2.c
tree-wide: insert space after for and switch
[thirdparty/systemd.git] / src / test / test-tpm2.c
index bbf2790a475bf77d08fcb620a79642c15f06c77b..19881c6e91f447bbd8dbef3de8316bb389a49836 100644 (file)
@@ -2,8 +2,9 @@
 
 #include "hexdecoct.h"
 #include "macro.h"
-#include "tpm2-util.h"
 #include "tests.h"
+#include "tpm2-util.h"
+#include "virt.h"
 
 TEST(tpm2_pcr_index_from_string) {
         assert_se(tpm2_pcr_index_from_string("platform-code") == 0);
@@ -73,7 +74,7 @@ TEST(tpm2_util_pbkdf2_hmac_sha256) {
         };
 
         uint8_t res[SHA256_DIGEST_SIZE];
-        for(size_t i = 0; i < sizeof(test_vectors)/sizeof(test_vectors[0]); i++) {
+        for (size_t i = 0; i < sizeof(test_vectors)/sizeof(test_vectors[0]); i++) {
 
                 int rc = tpm2_util_pbkdf2_hmac_sha256(
                                 test_vectors[i].pass,
@@ -859,18 +860,18 @@ static void check_name(const TPM2B_NAME *name, const char *expect) {
         assert_se(memcmp(name->name, e, e_len) == 0);
 }
 
-TEST(calculate_name) {
+TEST(calculate_pubkey_name) {
         TPM2B_PUBLIC public;
         TPM2B_NAME name;
 
         /* RSA */
         tpm2b_public_rsa_init(&public, "9ec7341c52093ac40a1965a5df10432513c539adcf905e30577ab6ebc88ffe53cd08cef12ed9bec6125432f4fada3629b8b96d31b8f507aa35029188fe396da823fcb236027f7fbb01b0da3d87be7f999390449ced604bdf7e26c48657cc0671000f1147da195c3861c96642e54427cb7a11572e07567ec3fd6316978abc4bd92b27bb0a0e4958e599804eeb41d682b3b7fc1f960209f80a4fb8a1b64abfd96bf5d554e73cdd6ad1c8becb4fcf5e8f0c3e621d210e5e2f308f6520ad9a966779231b99f06c5989e5a23a9415c8808ab89ce81117632e2f8461cd4428bded40979236aeadafe8de3f51660a45e1dbc87694e6a36360201cca3ff9e7263e712727");
-        assert_se(tpm2_calculate_name(&public.publicArea, &name) >= 0);
+        assert_se(tpm2_calculate_pubkey_name(&public.publicArea, &name) >= 0);
         check_name(&name, "000be78f74a470dd92e979ca067cdb2293a35f075e8560b436bd2ccea5da21486a07");
 
         /* ECC */
         tpm2b_public_ecc_init(&public, TPM2_ECC_NIST_P256, "238e02ee4fd5598add6b502429f1815418515e4b0d6551c8e816b38cb15451d1", "70c2d491769775ec43ccd5a571c429233e9d30cf0f486c2e01acd6cb32ba93b6");
-        assert_se(tpm2_calculate_name(&public.publicArea, &name) >= 0);
+        assert_se(tpm2_calculate_pubkey_name(&public.publicArea, &name) >= 0);
         check_name(&name, "000b302787187ba19c82011c987bd2dcdbb652b3a543ccc5cb0b49c33d4caae604a6");
 }
 
@@ -961,9 +962,58 @@ TEST(calculate_policy_pcr) {
         assert_se(digest_check(&d, "7481fd1b116078eb3ac2456e4ad542c9b46b9b8eb891335771ca8e7c8f8e4415"));
 }
 
+static void check_srk_rsa_template(TPMT_PUBLIC *template) {
+        assert_se(template->type == TPM2_ALG_RSA);
+        assert_se(template->nameAlg == TPM2_ALG_SHA256);
+        assert_se(template->objectAttributes == 0x30472);
+        assert_se(template->parameters.rsaDetail.symmetric.algorithm == TPM2_ALG_AES);
+        assert_se(template->parameters.rsaDetail.symmetric.keyBits.sym == 128);
+        assert_se(template->parameters.rsaDetail.symmetric.mode.sym == TPM2_ALG_CFB);
+        assert_se(template->parameters.rsaDetail.scheme.scheme == TPM2_ALG_NULL);
+        assert_se(template->parameters.rsaDetail.keyBits == 2048);
+}
+
+static void check_srk_ecc_template(TPMT_PUBLIC *template) {
+        assert_se(template->type == TPM2_ALG_ECC);
+        assert_se(template->nameAlg == TPM2_ALG_SHA256);
+        assert_se(template->objectAttributes == 0x30472);
+        assert_se(template->parameters.eccDetail.symmetric.algorithm == TPM2_ALG_AES);
+        assert_se(template->parameters.eccDetail.symmetric.keyBits.sym == 128);
+        assert_se(template->parameters.eccDetail.symmetric.mode.sym == TPM2_ALG_CFB);
+        assert_se(template->parameters.eccDetail.scheme.scheme == TPM2_ALG_NULL);
+        assert_se(template->parameters.eccDetail.kdf.scheme == TPM2_ALG_NULL);
+        assert_se(template->parameters.eccDetail.curveID == TPM2_ECC_NIST_P256);
+}
+
+TEST(tpm2_get_srk_template) {
+        TPMT_PUBLIC template;
+
+        assert_se(tpm2_get_srk_template(TPM2_ALG_RSA, &template) >= 0);
+        check_srk_rsa_template(&template);
+
+        assert_se(tpm2_get_srk_template(TPM2_ALG_ECC, &template) >= 0);
+        check_srk_ecc_template(&template);
+}
+
+static void check_best_srk_template(Tpm2Context *c) {
+        TEST_LOG_FUNC();
+
+        TPMT_PUBLIC template;
+        assert_se(tpm2_get_best_srk_template(c, &template) >= 0);
+
+        assert_se(IN_SET(template.type, TPM2_ALG_ECC, TPM2_ALG_RSA));
+
+        if (template.type == TPM2_ALG_RSA)
+                check_srk_rsa_template(&template);
+        else
+                check_srk_ecc_template(&template);
+}
+
 static void check_test_parms(Tpm2Context *c) {
         assert(c);
 
+        TEST_LOG_FUNC();
+
         TPMU_PUBLIC_PARMS parms = {
                 .symDetail.sym = {
                         .algorithm = TPM2_ALG_AES,
@@ -986,6 +1036,8 @@ static void check_test_parms(Tpm2Context *c) {
 static void check_supports_alg(Tpm2Context *c) {
         assert(c);
 
+        TEST_LOG_FUNC();
+
         /* Test invalid algs */
         assert_se(!tpm2_supports_alg(c, TPM2_ALG_ERROR));
         assert_se(!tpm2_supports_alg(c, TPM2_ALG_LAST + 1));
@@ -999,6 +1051,8 @@ static void check_supports_alg(Tpm2Context *c) {
 static void check_supports_command(Tpm2Context *c) {
         assert(c);
 
+        TEST_LOG_FUNC();
+
         /* Test invalid commands. TPM specification Part 2 ("Structures") section "TPM_CC (Command Codes)"
          * states bits 31:30 and 28:16 are reserved and must be 0. */
         assert_se(!tpm2_supports_command(c, UINT32_C(0x80000000)));
@@ -1016,6 +1070,116 @@ static void check_supports_command(Tpm2Context *c) {
         assert_se(tpm2_supports_command(c, TPM2_CC_Unseal));
 }
 
+static void check_get_or_create_srk(Tpm2Context *c) {
+        TEST_LOG_FUNC();
+
+        _cleanup_free_ TPM2B_PUBLIC *public = NULL;
+        _cleanup_free_ TPM2B_NAME *name = NULL, *qname = NULL;
+        _cleanup_(tpm2_handle_freep) Tpm2Handle *handle = NULL;
+        assert_se(tpm2_get_or_create_srk(c, NULL, &public, &name, &qname, &handle) >= 0);
+        assert_se(public && name && qname && handle);
+
+        _cleanup_free_ TPM2B_PUBLIC *public2 = NULL;
+        _cleanup_free_ TPM2B_NAME *name2 = NULL, *qname2 = NULL;
+        _cleanup_(tpm2_handle_freep) Tpm2Handle *handle2 = NULL;
+        assert_se(tpm2_get_srk(c, NULL, &public2, &name2, &qname2, &handle2) >= 0);
+        assert_se(public2 && name2 && qname2 && handle2);
+
+        assert_se(memcmp_nn(public, sizeof(*public), public2, sizeof(*public2)) == 0);
+        assert_se(memcmp_nn(name->name, name->size, name2->name, name2->size) == 0);
+        assert_se(memcmp_nn(qname->name, qname->size, qname2->name, qname2->size) == 0);
+}
+
+#if HAVE_OPENSSL && OPENSSL_VERSION_MAJOR >= 3
+static void calculate_seal_and_unseal(
+                Tpm2Context *c,
+                TPM2_HANDLE parent_index,
+                const TPM2B_PUBLIC *parent_public) {
+
+        _cleanup_free_ char *secret_string = NULL;
+        assert_se(asprintf(&secret_string, "The classified documents are in room %x", parent_index) > 0);
+        size_t secret_size = strlen(secret_string) + 1;
+
+        _cleanup_free_ void *blob = NULL;
+        size_t blob_size = 0;
+        _cleanup_free_ void *serialized_parent = NULL;
+        size_t serialized_parent_size;
+        assert_se(tpm2_calculate_seal(
+                        parent_index,
+                        parent_public,
+                        /* attributes= */ NULL,
+                        secret_string, secret_size,
+                        /* policy= */ NULL,
+                        /* pin= */ NULL,
+                        /* ret_secret= */ NULL, /* ret_secret_size= */ 0,
+                        &blob, &blob_size,
+                        &serialized_parent, &serialized_parent_size) >= 0);
+
+        _cleanup_free_ void *unsealed_secret = NULL;
+        size_t unsealed_secret_size;
+        assert_se(tpm2_unseal(
+                        c,
+                        /* hash_pcr_mask= */ 0,
+                        /* pcr_bank= */ 0,
+                        /* pubkey= */ NULL, /* pubkey_size= */ 0,
+                        /* pubkey_pcr_mask= */ 0,
+                        /* signature= */ NULL,
+                        /* pin= */ NULL,
+                        /* pcrlock_policy= */ NULL,
+                        /* primary_alg= */ 0,
+                        blob, blob_size,
+                        /* known_policy_hash= */ NULL, /* known_policy_hash_size= */ 0,
+                        serialized_parent, serialized_parent_size,
+                        &unsealed_secret, &unsealed_secret_size) >= 0);
+
+        assert_se(memcmp_nn(secret_string, secret_size, unsealed_secret, unsealed_secret_size) == 0);
+
+        char unsealed_string[unsealed_secret_size];
+        assert_se(snprintf(unsealed_string, unsealed_secret_size, "%s", (char*) unsealed_secret) == (int) unsealed_secret_size - 1);
+        log_debug("Unsealed secret is: %s", unsealed_string);
+}
+
+static int check_calculate_seal(Tpm2Context *c) {
+        assert(c);
+        int r;
+
+        if (detect_virtualization() == VIRTUALIZATION_NONE && !slow_tests_enabled()) {
+                log_notice("Skipping slow calculate seal TPM2 tests. Physical system detected, and slow tests disabled.");
+                return 0;
+        }
+
+        TEST_LOG_FUNC();
+
+        _cleanup_free_ TPM2B_PUBLIC *srk_public = NULL;
+        assert_se(tpm2_get_srk(c, NULL, &srk_public, NULL, NULL, NULL) >= 0);
+        calculate_seal_and_unseal(c, TPM2_SRK_HANDLE, srk_public);
+
+        TPMI_ALG_ASYM test_algs[] = { TPM2_ALG_RSA, TPM2_ALG_ECC, };
+        for (unsigned i = 0; i < ELEMENTSOF(test_algs); i++) {
+                TPMI_ALG_ASYM alg = test_algs[i];
+
+                TPM2B_PUBLIC template = { .size = sizeof(TPMT_PUBLIC), };
+                assert_se(tpm2_get_srk_template(alg, &template.publicArea) >= 0);
+
+                _cleanup_free_ TPM2B_PUBLIC *public = NULL;
+                _cleanup_(tpm2_handle_freep) Tpm2Handle *handle = NULL;
+                assert_se(tpm2_create_primary(c, NULL, &template, NULL, &public, &handle) >= 0);
+
+                /* Once our minimum libtss2-esys version is 2.4.0 or later, this can assume
+                 * tpm2_index_from_handle() should always work. */
+                TPM2_HANDLE index;
+                r = tpm2_index_from_handle(c, handle, &index);
+                if (r == -EOPNOTSUPP)
+                        return log_tests_skipped("libtss2-esys version too old to support tpm2_index_from_handle()");
+                assert_se(r >= 0);
+
+                calculate_seal_and_unseal(c, index, public);
+        }
+
+        return 0;
+}
+#endif /* HAVE_OPENSSL && OPENSSL_VERSION_MAJOR >= 3 */
+
 static void check_seal_unseal_for_handle(Tpm2Context *c, TPM2_HANDLE handle) {
         TPM2B_DIGEST policy = TPM2B_DIGEST_MAKE(NULL, TPM2_SHA256_DIGEST_SIZE);
 
@@ -1043,6 +1207,7 @@ static void check_seal_unseal_for_handle(Tpm2Context *c, TPM2_HANDLE handle) {
                         /* pubkey_pcr_mask= */ 0,
                         /* signature= */ NULL,
                         /* pin= */ NULL,
+                        /* pcrlock_policy= */ NULL,
                         /* primary_alg= */ 0,
                         blob, blob_size,
                         /* policy_hash= */ NULL, /* policy_hash_size= */ 0,
@@ -1057,6 +1222,13 @@ static void check_seal_unseal(Tpm2Context *c) {
 
         assert(c);
 
+        if (detect_virtualization() == VIRTUALIZATION_NONE && !slow_tests_enabled()) {
+                log_notice("Skipping slow seal/unseal TPM2 tests. Physical system detected, and slow tests disabled.");
+                return;
+        }
+
+        TEST_LOG_FUNC();
+
         check_seal_unseal_for_handle(c, 0);
         check_seal_unseal_for_handle(c, TPM2_SRK_HANDLE);
 
@@ -1089,6 +1261,7 @@ static void check_seal_unseal(Tpm2Context *c) {
 
 TEST_RET(tests_which_require_tpm) {
         _cleanup_(tpm2_context_unrefp) Tpm2Context *c = NULL;
+        int r = 0;
 
         if (tpm2_context_new(NULL, &c) < 0)
                 return log_tests_skipped("Could not find TPM");
@@ -1096,9 +1269,15 @@ TEST_RET(tests_which_require_tpm) {
         check_test_parms(c);
         check_supports_alg(c);
         check_supports_command(c);
+        check_best_srk_template(c);
+        check_get_or_create_srk(c);
         check_seal_unseal(c);
 
-        return 0;
+#if HAVE_OPENSSL && OPENSSL_VERSION_MAJOR >= 3 /* calculating sealed object requires openssl >= 3 */
+        r = check_calculate_seal(c);
+#endif
+
+        return r;
 }
 
 #endif /* HAVE_TPM2 */