/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "hexdecoct.h"
+#include "macro.h"
#include "tpm2-util.h"
#include "tests.h"
check_parse_pcr_argument_to_mask("debug+24", -EINVAL);
}
-static void tpm2b_public_rsa_init(TPM2B_PUBLIC *public, const char *rsa_n) {
- TPMT_PUBLIC tpmt = {
- .type = TPM2_ALG_RSA,
- .nameAlg = TPM2_ALG_SHA256,
- .objectAttributes = TPMA_OBJECT_RESTRICTED|TPMA_OBJECT_DECRYPT|TPMA_OBJECT_FIXEDTPM|TPMA_OBJECT_FIXEDPARENT|TPMA_OBJECT_SENSITIVEDATAORIGIN|TPMA_OBJECT_USERWITHAUTH,
- .parameters.rsaDetail = {
- .symmetric = {
- .algorithm = TPM2_ALG_AES,
- .keyBits.aes = 128,
- .mode.aes = TPM2_ALG_CFB,
- },
- .scheme.scheme = TPM2_ALG_NULL,
- .keyBits = 2048,
+static const TPMT_PUBLIC test_rsa_template = {
+ .type = TPM2_ALG_RSA,
+ .nameAlg = TPM2_ALG_SHA256,
+ .objectAttributes = TPMA_OBJECT_RESTRICTED|TPMA_OBJECT_DECRYPT|TPMA_OBJECT_FIXEDTPM|TPMA_OBJECT_FIXEDPARENT|TPMA_OBJECT_SENSITIVEDATAORIGIN|TPMA_OBJECT_USERWITHAUTH,
+ .parameters.rsaDetail = {
+ .symmetric = {
+ .algorithm = TPM2_ALG_AES,
+ .keyBits.aes = 128,
+ .mode.aes = TPM2_ALG_CFB,
},
- };
+ .scheme.scheme = TPM2_ALG_NULL,
+ .keyBits = 2048,
+ },
+};
+
+static const TPMT_PUBLIC test_ecc_template = {
+ .type = TPM2_ALG_ECC,
+ .nameAlg = TPM2_ALG_SHA256,
+ .objectAttributes = TPMA_OBJECT_RESTRICTED|TPMA_OBJECT_DECRYPT|TPMA_OBJECT_FIXEDTPM|TPMA_OBJECT_FIXEDPARENT|TPMA_OBJECT_SENSITIVEDATAORIGIN|TPMA_OBJECT_USERWITHAUTH,
+ .parameters.eccDetail = {
+ .symmetric = {
+ .algorithm = TPM2_ALG_AES,
+ .keyBits.aes = 128,
+ .mode.aes = TPM2_ALG_CFB,
+ },
+ .scheme.scheme = TPM2_ALG_NULL,
+ .curveID = TPM2_ECC_NIST_P256,
+ .kdf.scheme = TPM2_ALG_NULL,
+ },
+};
+
+static const TPMT_PUBLIC *test_templates[] = {
+ &test_rsa_template,
+ &test_ecc_template,
+};
+
+static void tpm2b_public_rsa_init(TPM2B_PUBLIC *public, const char *rsa_n) {
+ TPMT_PUBLIC tpmt = test_rsa_template;
DEFINE_HEX_PTR(key, rsa_n);
tpmt.unique.rsa = TPM2B_PUBLIC_KEY_RSA_MAKE(key, key_len);
}
static void tpm2b_public_ecc_init(TPM2B_PUBLIC *public, TPMI_ECC_CURVE curve, const char *x, const char *y) {
- TPMT_PUBLIC tpmt = {
- .type = TPM2_ALG_ECC,
- .nameAlg = TPM2_ALG_SHA256,
- .objectAttributes = TPMA_OBJECT_RESTRICTED|TPMA_OBJECT_DECRYPT|TPMA_OBJECT_FIXEDTPM|TPMA_OBJECT_FIXEDPARENT|TPMA_OBJECT_SENSITIVEDATAORIGIN|TPMA_OBJECT_USERWITHAUTH,
- .parameters.eccDetail = {
- .symmetric = {
- .algorithm = TPM2_ALG_AES,
- .keyBits.aes = 128,
- .mode.aes = TPM2_ALG_CFB,
- },
- .scheme.scheme = TPM2_ALG_NULL,
- .curveID = curve,
- .kdf.scheme = TPM2_ALG_NULL,
- },
- };
+ TPMT_PUBLIC tpmt = test_ecc_template;
+ tpmt.parameters.eccDetail.curveID = curve;
DEFINE_HEX_PTR(buf_x, x);
tpmt.unique.ecc.x = TPM2B_ECC_PARAMETER_MAKE(buf_x, buf_x_len);
assert_se(digest_check(&d, "7481fd1b116078eb3ac2456e4ad542c9b46b9b8eb891335771ca8e7c8f8e4415"));
}
-TEST(tpm_required_tests) {
- int r;
-
- _cleanup_(tpm2_context_unrefp) Tpm2Context *c = NULL;
- r = tpm2_context_new(NULL, &c);
- if (r < 0) {
- log_tests_skipped("Could not find TPM");
- return;
- }
+static void check_test_parms(Tpm2Context *c) {
+ assert(c);
TPMU_PUBLIC_PARMS parms = {
.symDetail.sym = {
/* Test with valid parms */
assert_se(tpm2_test_parms(c, TPM2_ALG_SYMCIPHER, &parms));
+}
+
+static void check_supports_alg(Tpm2Context *c) {
+ assert(c);
/* Test invalid algs */
assert_se(!tpm2_supports_alg(c, TPM2_ALG_ERROR));
assert_se(tpm2_supports_alg(c, TPM2_ALG_RSA));
assert_se(tpm2_supports_alg(c, TPM2_ALG_AES));
assert_se(tpm2_supports_alg(c, TPM2_ALG_CFB));
+}
+
+static void check_supports_command(Tpm2Context *c) {
+ assert(c);
/* 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, TPM2_CC_Unseal));
}
+static void check_seal_unseal_for_handle(Tpm2Context *c, TPM2_HANDLE handle) {
+ TPM2B_DIGEST policy = TPM2B_DIGEST_MAKE(NULL, TPM2_SHA256_DIGEST_SIZE);
+
+ assert(c);
+
+ log_debug("Check seal/unseal for handle 0x%" PRIx32, handle);
+
+ _cleanup_free_ void *secret = NULL, *blob = NULL, *srk = NULL, *unsealed_secret = NULL;
+ size_t secret_size, blob_size, srk_size, unsealed_secret_size;
+ assert_se(tpm2_seal(
+ c,
+ handle,
+ &policy,
+ /* pin= */ NULL,
+ &secret, &secret_size,
+ &blob, &blob_size,
+ /* ret_primary_alg= */ NULL,
+ &srk, &srk_size) >= 0);
+
+ 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,
+ /* primary_alg= */ 0,
+ blob, blob_size,
+ /* policy_hash= */ NULL, /* policy_hash_size= */ 0,
+ srk, srk_size,
+ &unsealed_secret, &unsealed_secret_size) >= 0);
+
+ assert_se(memcmp_nn(secret, secret_size, unsealed_secret, unsealed_secret_size) == 0);
+}
+
+static void check_seal_unseal(Tpm2Context *c) {
+ int r;
+
+ assert(c);
+
+ check_seal_unseal_for_handle(c, 0);
+ check_seal_unseal_for_handle(c, TPM2_SRK_HANDLE);
+
+ FOREACH_ARRAY(template, test_templates, ELEMENTSOF(test_templates)) {
+ TPM2B_PUBLIC public = {
+ .publicArea = **template,
+ .size = sizeof(**template),
+ };
+ _cleanup_(tpm2_handle_freep) Tpm2Handle *transient_handle = NULL;
+ assert_se(tpm2_create_primary(
+ c,
+ /* session= */ NULL,
+ &public,
+ /* sensitive= */ NULL,
+ /* ret_public= */ NULL,
+ &transient_handle) >= 0);
+
+ TPMI_DH_PERSISTENT transient_handle_index;
+ r = tpm2_index_from_handle(c, transient_handle, &transient_handle_index);
+ if (r == -EOPNOTSUPP) {
+ /* libesys too old */
+ log_tests_skipped("libesys too old for tpm2_index_from_handle");
+ return;
+ }
+ assert_se(r >= 0);
+
+ check_seal_unseal_for_handle(c, transient_handle_index);
+ }
+}
+
+TEST_RET(tests_which_require_tpm) {
+ _cleanup_(tpm2_context_unrefp) Tpm2Context *c = NULL;
+
+ if (tpm2_context_new(NULL, &c) < 0)
+ return log_tests_skipped("Could not find TPM");
+
+ check_test_parms(c);
+ check_supports_alg(c);
+ check_supports_command(c);
+ check_seal_unseal(c);
+
+ return 0;
+}
+
#endif /* HAVE_TPM2 */
DEFINE_TEST_MAIN(LOG_DEBUG);
SD_TPM2SETUP="/usr/lib/systemd/systemd-tpm2-setup"
export SYSTEMD_LOG_LEVEL=debug
+trap cleanup ERR
+cleanup() {
+ # Evict the TPM primary key that we persisted
+ if [[ -n $persistent ]]; then
+ tpm2_evictcontrol -c "$persistent"
+ fi
+}
+persistent=""
+
cryptsetup_has_token_plugin_support() {
local plugin_path
rm -f /tmp/pcr.dat
fi
+# Use default (0) seal key handle
+systemd-cryptenroll --wipe-slot=tpm2 "$img"
+PASSWORD=passphrase systemd-cryptenroll --tpm2-device=auto --tpm2-seal-key-handle=0 "$img"
+systemd-cryptsetup attach test-volume "$img" - tpm2-device=auto,headless=1
+systemd-cryptsetup detach test-volume
+
+systemd-cryptenroll --wipe-slot=tpm2 "$img"
+PASSWORD=passphrase systemd-cryptenroll --tpm2-device=auto --tpm2-seal-key-handle=0x0 "$img"
+systemd-cryptsetup attach test-volume "$img" - tpm2-device=auto,headless=1
+systemd-cryptsetup detach test-volume
+
+# Use SRK seal key handle
+systemd-cryptenroll --wipe-slot=tpm2 "$img"
+PASSWORD=passphrase systemd-cryptenroll --tpm2-device=auto --tpm2-seal-key-handle=81000001 "$img"
+systemd-cryptsetup attach test-volume "$img" - tpm2-device=auto,headless=1
+systemd-cryptsetup detach test-volume
+
+systemd-cryptenroll --wipe-slot=tpm2 "$img"
+PASSWORD=passphrase systemd-cryptenroll --tpm2-device=auto --tpm2-seal-key-handle=0x81000001 "$img"
+systemd-cryptsetup attach test-volume "$img" - tpm2-device=auto,headless=1
+systemd-cryptsetup detach test-volume
+
+# Test invalid ranges: pcr, nv, session, permanent
+systemd-cryptenroll --wipe-slot=tpm2 "$img"
+(! PASSWORD=passphrase systemd-cryptenroll --tpm2-device=auto --tpm2-seal-key-handle=7 "$img") # PCR
+(! PASSWORD=passphrase systemd-cryptenroll --tpm2-device=auto --tpm2-seal-key-handle=0x01000001 "$img") # NV index
+(! PASSWORD=passphrase systemd-cryptenroll --tpm2-device=auto --tpm2-seal-key-handle=0x02000001 "$img") # HMAC/loaded session
+(! PASSWORD=passphrase systemd-cryptenroll --tpm2-device=auto --tpm2-seal-key-handle=0x03000001 "$img") # Policy/saved session
+(! PASSWORD=passphrase systemd-cryptenroll --tpm2-device=auto --tpm2-seal-key-handle=0x40000001 "$img") # Permanent
+
+# Use non-SRK persistent seal key handle (by creating/persisting new key)
+primary=/tmp/primary.ctx
+tpm2_createprimary -c "$primary"
+persistent_line=$(tpm2_evictcontrol -c "$primary" | grep persistent-handle)
+persistent="0x${persistent_line##*0x}"
+tpm2_flushcontext -t
+
+systemd-cryptenroll --wipe-slot=tpm2 "$img"
+PASSWORD=passphrase systemd-cryptenroll --tpm2-device=auto --tpm2-seal-key-handle="${persistent#0x}" "$img"
+systemd-cryptsetup attach test-volume "$img" - tpm2-device=auto,headless=1
+systemd-cryptsetup detach test-volume
+
+systemd-cryptenroll --wipe-slot=tpm2 "$img"
+PASSWORD=passphrase systemd-cryptenroll --tpm2-device=auto --tpm2-seal-key-handle="$persistent" "$img"
+systemd-cryptsetup attach test-volume "$img" - tpm2-device=auto,headless=1
+systemd-cryptsetup detach test-volume
+
+tpm2_evictcontrol -c "$persistent"
+persistent=""
+rm -f "$primary"
+
rm -f "${img:?}"
if [[ -x "$SD_MEASURE" ]]; then
"$SD_TPM2SETUP" --early=no
fi
+cleanup
+
touch /testok