diff options
68 files changed, 853 insertions, 567 deletions
@@ -52,6 +52,17 @@ CHANGES WITH 251: or ID field of /etc/os-release or another suitable identifier before deploying the image. + * sd-boot gained a new *experimental* setting "reboot-for-bitlocker" in + loader.conf that implements booting Microsoft Windows from the + sd-boot in a way that first reboots the system, to reset the TPM + PCRs. This improves compatibility with BitLocker's TPM use, as the + PCRs will only record the Windows boot process, and not sd-boot + itself, thus retaining the PCR measurements not involving + sd-boot. Note that this feature is experimental for now, and is + likely going to be generalized, renamed and removed in its current + form in a future release, without retaining compatibility with its + current implementation. + * The --make-machine-id-directory= switch to bootctl has been replaced by --make-entry-directory=, given that the entry directory is not necessarily named after the machine ID, but after some other suitable @@ -109,6 +120,19 @@ CHANGES WITH 251: 250. For newer kernels, non-x86 systems, or older x86 systems, there should be no visible changes. + * sd-boot will now measure the kernel command line into TPM PCR 12 + rather than PCR 8. This improves usefulness of the measurements on + sytems where sd-boot is chainloaded from Grub. Grub measures all + commands its executes into PCR 8, which makes it very hard to use + reasonably, hence separate ourselves from that and use PCR 12 + instead, which is already what certain Ubuntu editions use it for. To + retain compatibility with systems running older systemd systems a new + Meson option 'efi-tpm-pcr-compat' has been added (which defaults to + false). If enabled, the measurement is done twice: into the new-style + PCR 12 *and* the old-style PCR 8. It's strongly advised to migrate + all users to PCR 12 for this purpose in the long run, as we intend to + remove this compatibility feature again in two year's time. + CHANGES WITH 250: * Support for encrypted and authenticated credentials has been added. diff --git a/man/crypttab.xml b/man/crypttab.xml index ac5c6ef666..22411166a8 100644 --- a/man/crypttab.xml +++ b/man/crypttab.xml @@ -678,6 +678,14 @@ </varlistentry> <varlistentry> + <term><option>tpm2-pin=</option></term> + + <listitem><para>Takes a boolean argument, defaults to <literal>false</literal>. Controls whether + TPM2 volume unlocking is bound to a PIN in addition to PCRs. Similarly, this option is only useful + when TPM2 enrollment metadata is not available.</para></listitem> + </varlistentry> + + <varlistentry> <term><option>token-timeout=</option></term> <listitem><para>Specifies how long to wait at most for configured security devices (i.e. FIDO2, diff --git a/man/loader.conf.xml b/man/loader.conf.xml index caff44aa1e..e5453c7dcd 100644 --- a/man/loader.conf.xml +++ b/man/loader.conf.xml @@ -206,8 +206,11 @@ <varlistentry> <term>reboot-for-bitlocker</term> - <listitem><para>Work around BitLocker requiring a recovery key when the boot loader was - updated (enabled by default).</para> + <listitem><para>Caveat: This feature is experimental, and is likely to be changed (or removed in its + current form) in a future version of systemd.</para> + + <para>Work around BitLocker requiring a recovery key when the boot loader was + updated (disabled by default).</para> <para>Try to detect BitLocker encrypted drives along with an active TPM. If both are found and Windows Boot Manager is selected in the boot menu, set the <literal>BootNext</literal> diff --git a/man/systemd-cryptenroll.xml b/man/systemd-cryptenroll.xml index d5fdb54cdd..02f932edfb 100644 --- a/man/systemd-cryptenroll.xml +++ b/man/systemd-cryptenroll.xml @@ -214,6 +214,8 @@ <!-- See: https://github.com/rhboot/shim/blob/main/README.tpm --> <!-- See: https://www.gnu.org/software/grub/manual/grub/html_node/Measured-Boot.html --> <!-- See: https://sourceforge.net/p/linux-ima/wiki/Home/ --> + <!-- See: https://github.com/tianocore-docs/edk2-TrustedBootChain/blob/main/4_Other_Trusted_Boot_Chains.md --> + <!-- See: https://wiki.archlinux.org/title/Trusted_Platform_Module#Accessing_PCR_registers --> <tgroup cols='2' align='left' colsep='1' rowsep='1'> <colspec colname="pcr" /> @@ -267,14 +269,14 @@ <entry>Secure boot state; changes when UEFI SecureBoot mode is enabled/disabled, or firmware certificates (PK, KEK, db, dbx, …) changes. The shim project will measure most of its (non-MOK) certificates and SBAT data into this PCR.</entry> </row> + <!-- Grub measures all its commands and the kernel command line into PCR 8… --> + <!-- Grub measures all files it reads (including kernel image, initrd, …) into PCR 9… --> + <row> - <entry>8</entry> + <entry>12</entry> <entry><citerefentry><refentrytitle>sd-boot</refentrytitle><manvolnum>7</manvolnum></citerefentry> measures the kernel command line into this PCR.</entry> - <!-- Grub measures all its commands and the kernel command line into PCR 8 too… --> </row> - <!-- Grub measures all files it reads (including kernel image, initrd, …) into PCR 9… --> - <row> <entry>10</entry> <entry>The IMA project measures its runtime state into this PCR.</entry> @@ -300,6 +302,24 @@ </varlistentry> <varlistentry> + <term><option>--tpm2-with-pin=</option><replaceable>BOOL</replaceable></term> + + <listitem><para>When enrolling a TPM2 device, controls whether to require the user to enter a PIN + when unlocking the volume in addition to PCR binding, based on TPM2 policy authentication. Defaults + to <literal>no</literal>. Despite being called PIN, any character can be used, not just numbers. + </para> + + <para>Note that incorrect PIN entry when unlocking increments the + TPM dictionary attack lockout mechanism, and may lock out users for a prolonged time, depending on + its configuration. The lockout mechanism is a global property of the TPM, + <command>systemd-cryptenroll</command> does not control or configure the lockout mechanism. You may + use tpm2-tss tools to inspect or configure the dictionary attack lockout, with + <citerefentry><refentrytitle>tpm2_getcap</refentrytitle><manvolnum>1</manvolnum></citerefentry> and + <citerefentry><refentrytitle>tpm2_dictionarylockout</refentrytitle><manvolnum>1</manvolnum></citerefentry> + commands, respectively.</para></listitem> + </varlistentry> + + <varlistentry> <term><option>--wipe-slot=</option><arg rep="repeat">SLOT</arg></term> <listitem><para>Wipes one or more LUKS2 key slots. Takes a comma separated list of numeric slot diff --git a/meson_options.txt b/meson_options.txt index 5d635748d5..284109cadf 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -426,6 +426,8 @@ option('efi-libdir', type : 'string', description : 'path to the EFI lib directory') option('efi-includedir', type : 'string', value : '/usr/include/efi', description : 'path to the EFI header directory') +option('efi-tpm-pcr-compat', type : 'boolean', value : 'false', + description : 'Measure kernel command line also into TPM PCR 8 (in addition to 12)') option('sbat-distro', type : 'string', value : 'auto', description : 'SBAT distribution ID, e.g. fedora, or auto for autodetection') option('sbat-distro-generation', type : 'integer', value : 1, diff --git a/src/analyze/test-verify.c b/src/analyze/test-verify.c index f8c0bd9786..d37e54bca6 100644 --- a/src/analyze/test-verify.c +++ b/src/analyze/test-verify.c @@ -3,7 +3,7 @@ #include "analyze-verify-util.h" #include "tests.h" -static void test_verify_nonexistent(void) { +TEST(verify_nonexistent) { /* Negative cases */ assert_se(verify_executable(NULL, &(ExecCommand) {.flags = EXEC_COMMAND_IGNORE_FAILURE, .path = (char*) "/non/existent"}, NULL) == 0); assert_se(verify_executable(NULL, &(ExecCommand) {.path = (char*) "/non/existent"}, NULL) < 0); @@ -13,8 +13,4 @@ static void test_verify_nonexistent(void) { assert_se(verify_executable(NULL, &(ExecCommand) {.flags = EXEC_COMMAND_IGNORE_FAILURE, .path = (char*) "/bin/echo"}, NULL) == 0); } -int main(int argc, char *argv[]) { - test_setup_logging(LOG_DEBUG); - - test_verify_nonexistent(); -} +DEFINE_TEST_MAIN(LOG_DEBUG); diff --git a/src/basic/hmac.h b/src/basic/hmac.h index a5682c439f..e58c1838a3 100644 --- a/src/basic/hmac.h +++ b/src/basic/hmac.h @@ -4,7 +4,7 @@ #include <stdint.h> #include <stdlib.h> -#define SHA256_DIGEST_SIZE 32 +#include "sha256.h" /* Unoptimized implementation based on FIPS 198. 'res' has to be allocated by * the caller. Prefer external OpenSSL functions, and use this only when diff --git a/src/boot/efi/boot.c b/src/boot/efi/boot.c index f6706c68fc..82954ddac1 100644 --- a/src/boot/efi/boot.c +++ b/src/boot/efi/boot.c @@ -1549,7 +1549,7 @@ static void config_load_defaults(Config *config, EFI_FILE *root_dir) { .editor = TRUE, .auto_entries = TRUE, .auto_firmware = TRUE, - .reboot_for_bitlocker = TRUE, + .reboot_for_bitlocker = FALSE, .random_seed_mode = RANDOM_SEED_WITH_SYSTEM_TOKEN, .idx_default_efivar = IDX_INVALID, .console_mode = CONSOLE_MODE_KEEP, @@ -1983,6 +1983,9 @@ static EFI_STATUS boot_windows_bitlocker(void) { UINTN n_handles; EFI_STATUS err; + // FIXME: Experimental for now. Should be generalized, and become a per-entry option that can be + // enabled independently of BitLocker, and without a BootXXXX entry pre-existing. + /* BitLocker key cannot be sealed without a TPM present. */ if (!tpm_present()) return EFI_NOT_FOUND; diff --git a/src/boot/efi/cpio.c b/src/boot/efi/cpio.c index 2855c4119b..14957130be 100644 --- a/src/boot/efi/cpio.c +++ b/src/boot/efi/cpio.c @@ -311,7 +311,8 @@ EFI_STATUS pack_cpio( const CHAR8 *target_dir_prefix, UINT32 dir_mode, UINT32 access_mode, - UINTN tpm_pcr, + const UINT32 tpm_pcr[], + UINTN n_tpm_pcr, const CHAR16 *tpm_description, void **ret_buffer, UINTN *ret_buffer_size) { @@ -328,6 +329,7 @@ EFI_STATUS pack_cpio( assert(loaded_image); assert(target_dir_prefix); + assert(tpm_pcr || n_tpm_pcr == 0); assert(ret_buffer); assert(ret_buffer_size); @@ -449,13 +451,15 @@ EFI_STATUS pack_cpio( if (EFI_ERROR(err)) return log_error_status_stall(err, L"Failed to pack cpio trailer: %r"); - err = tpm_log_event( - tpm_pcr, - POINTER_TO_PHYSICAL_ADDRESS(buffer), - buffer_size, - tpm_description); - if (EFI_ERROR(err)) - log_error_stall(L"Unable to add initrd TPM measurement for PCR %u (%s), ignoring: %r", tpm_pcr, tpm_description, err); + for (UINTN i = 0; i < n_tpm_pcr; i++) { + err = tpm_log_event( + tpm_pcr[i], + POINTER_TO_PHYSICAL_ADDRESS(buffer), + buffer_size, + tpm_description); + if (EFI_ERROR(err)) + log_error_stall(L"Unable to add initrd TPM measurement for PCR %u (%s), ignoring: %r", tpm_pcr[i], tpm_description, err); + } *ret_buffer = TAKE_PTR(buffer); *ret_buffer_size = buffer_size; diff --git a/src/boot/efi/cpio.h b/src/boot/efi/cpio.h index a272d28929..5f6698fd12 100644 --- a/src/boot/efi/cpio.h +++ b/src/boot/efi/cpio.h @@ -10,8 +10,8 @@ EFI_STATUS pack_cpio( const CHAR8 *target_dir_prefix, UINT32 dir_mode, UINT32 access_mode, - UINTN tpm_pcr, + const UINT32 tpm_pcr[], + UINTN n_tpm_pcr, const CHAR16 *tpm_description, void **ret_buffer, UINTN *ret_buffer_size); - diff --git a/src/boot/efi/measure.c b/src/boot/efi/measure.c index 992acde527..da4fd18ea8 100644 --- a/src/boot/efi/measure.c +++ b/src/boot/efi/measure.c @@ -139,12 +139,16 @@ BOOLEAN tpm_present(void) { return tcg2_interface_check() || tcg1_interface_check(); } -EFI_STATUS tpm_log_event(UINT32 pcrindex, const EFI_PHYSICAL_ADDRESS buffer, UINTN buffer_size, const CHAR16 *description) { +EFI_STATUS tpm_log_event(UINT32 pcrindex, EFI_PHYSICAL_ADDRESS buffer, UINTN buffer_size, const CHAR16 *description) { EFI_TCG *tpm1; EFI_TCG2 *tpm2; assert(description); + /* PCR disabled */ + if (pcrindex == UINT32_MAX) + return EFI_SUCCESS; + tpm2 = tcg2_interface_check(); if (tpm2) return tpm2_measure_to_pcr_and_event_log(tpm2, pcrindex, buffer, buffer_size, description); @@ -162,11 +166,15 @@ EFI_STATUS tpm_log_load_options(const CHAR16 *load_options) { /* Measures a load options string into the TPM2, i.e. the kernel command line */ - err = tpm_log_event(TPM_PCR_INDEX_KERNEL_PARAMETERS, - POINTER_TO_PHYSICAL_ADDRESS(load_options), - StrSize(load_options), load_options); - if (EFI_ERROR(err)) - return log_error_status_stall(err, L"Unable to add load options (i.e. kernel command) line measurement: %r", err); + for (UINTN i = 0; i < 2; i++) { + UINT32 pcr = i == 0 ? TPM_PCR_INDEX_KERNEL_PARAMETERS : TPM_PCR_INDEX_KERNEL_PARAMETERS_COMPAT; + + err = tpm_log_event(pcr, + POINTER_TO_PHYSICAL_ADDRESS(load_options), + StrSize(load_options), load_options); + if (EFI_ERROR(err)) + return log_error_status_stall(err, L"Unable to add load options (i.e. kernel command) line measurement to PCR %u: %r", pcr, err); + } return EFI_SUCCESS; } diff --git a/src/boot/efi/measure.h b/src/boot/efi/measure.h index ffa4924562..7a817b22d8 100644 --- a/src/boot/efi/measure.h +++ b/src/boot/efi/measure.h @@ -3,10 +3,24 @@ #include <efi.h> +/* This TPM PCR is where we extend the kernel command line and any passed credentials here. */ +#define TPM_PCR_INDEX_KERNEL_PARAMETERS 12U + +/* We used to write the the kernel command line/credentials into PCR 8, in systemd <= 250. Let's provide for + * some compatibility. (Remove in 2023!) */ +#if EFI_TPM_PCR_COMPAT +#define TPM_PCR_INDEX_KERNEL_PARAMETERS_COMPAT 8U +#else +#define TPM_PCR_INDEX_KERNEL_PARAMETERS_COMPAT UINT32_MAX +#endif + +/* This TPM PCR is where most Linux infrastructure extends the initrd binary images into, and so do we. */ +#define TPM_PCR_INDEX_INITRD 4U + #if ENABLE_TPM BOOLEAN tpm_present(void); -EFI_STATUS tpm_log_event(UINT32 pcrindex, const EFI_PHYSICAL_ADDRESS buffer, UINTN buffer_size, const CHAR16 *description); +EFI_STATUS tpm_log_event(UINT32 pcrindex, EFI_PHYSICAL_ADDRESS buffer, UINTN buffer_size, const CHAR16 *description); EFI_STATUS tpm_log_load_options(const CHAR16 *cmdline); #else @@ -14,9 +28,11 @@ EFI_STATUS tpm_log_load_options(const CHAR16 *cmdline); static inline BOOLEAN tpm_present(void) { return FALSE; } -static inline EFI_STATUS tpm_log_event(UINT32 pcrindex, const EFI_PHYSICAL_ADDRESS buffer, UINTN buffer_size, const CHAR16 *description) { + +static inline EFI_STATUS tpm_log_event(UINT32 pcrindex, EFI_PHYSICAL_ADDRESS buffer, UINTN buffer_size, const CHAR16 *description) { return EFI_SUCCESS; } + static inline EFI_STATUS tpm_log_load_options(const CHAR16 *cmdline) { return EFI_SUCCESS; } diff --git a/src/boot/efi/meson.build b/src/boot/efi/meson.build index f6004e47ec..ffee98bbb8 100644 --- a/src/boot/efi/meson.build +++ b/src/boot/efi/meson.build @@ -104,6 +104,7 @@ conf.set_quoted('EFI_MACHINE_TYPE_NAME', efi_arch[0]) efi_conf = configuration_data() efi_conf.set_quoted('EFI_MACHINE_TYPE_NAME', efi_arch[0]) efi_conf.set10('ENABLE_TPM', get_option('tpm')) +efi_conf.set10('EFI_TPM_PCR_COMPAT', get_option('efi-tpm-pcr-compat')) foreach ctype : ['color-normal', 'color-entry', 'color-highlight', 'color-edit'] c = get_option('efi-' + ctype).split(',') diff --git a/src/boot/efi/stub.c b/src/boot/efi/stub.c index 22554a4860..73d06de7f1 100644 --- a/src/boot/efi/stub.c +++ b/src/boot/efi/stub.c @@ -234,7 +234,8 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) { (const CHAR8*) ".extra/credentials", /* dir_mode= */ 0500, /* access_mode= */ 0400, - /* tpm_pcr= */ TPM_PCR_INDEX_KERNEL_PARAMETERS, + /* tpm_pcr= */ (UINT32[]) { TPM_PCR_INDEX_KERNEL_PARAMETERS, TPM_PCR_INDEX_KERNEL_PARAMETERS_COMPAT }, + /* n_tpm_pcr= */ 2, L"Credentials initrd", &credential_initrd, &credential_initrd_size); @@ -245,7 +246,8 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) { (const CHAR8*) ".extra/global_credentials", /* dir_mode= */ 0500, /* access_mode= */ 0400, - /* tpm_pcr= */ TPM_PCR_INDEX_KERNEL_PARAMETERS, + /* tpm_pcr= */ (UINT32[]) { TPM_PCR_INDEX_KERNEL_PARAMETERS, TPM_PCR_INDEX_KERNEL_PARAMETERS_COMPAT }, + /* n_tpm_pcr= */ 2, L"Global credentials initrd", &global_credential_initrd, &global_credential_initrd_size); @@ -256,7 +258,8 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) { (const CHAR8*) ".extra/sysext", /* dir_mode= */ 0555, /* access_mode= */ 0444, - /* tpm_pcr= */ TPM_PCR_INDEX_INITRD, + /* tpm_pcr= */ (UINT32[]) { TPM_PCR_INDEX_INITRD }, + /* n_tpm_pcr= */ 1, L"System extension initrd", &sysext_initrd, &sysext_initrd_size); diff --git a/src/boot/efi/test-bcd.c b/src/boot/efi/test-bcd.c index 5d3d6c2c40..d04d1ee45a 100644 --- a/src/boot/efi/test-bcd.c +++ b/src/boot/efi/test-bcd.c @@ -39,8 +39,7 @@ static void test_get_bcd_title_one( } TEST(get_bcd_title) { - const char16_t win10[] = { 'W', 'i', 'n', 'd', 'o', 'w', 's', ' ', '1', '0', '\0' }; - test_get_bcd_title_one("test-bcd/win10.bcd.zst", win10, sizeof(win10)); + test_get_bcd_title_one("test-bcd/win10.bcd.zst", u"Windows 10", sizeof(u"Windows 10")); test_get_bcd_title_one("test-bcd/description-bad-type.bcd.zst", NULL, 0); test_get_bcd_title_one("test-bcd/description-empty.bcd.zst", NULL, 0); diff --git a/src/boot/efi/util.h b/src/boot/efi/util.h index 33b17d04fb..93dd2da566 100644 --- a/src/boot/efi/util.h +++ b/src/boot/efi/util.h @@ -6,13 +6,6 @@ #include "string-util-fundamental.h" -/* This TPM PCR is where most Linux infrastructure extends the kernel command line into, and so do we. We also extend - * any passed credentials here. */ -#define TPM_PCR_INDEX_KERNEL_PARAMETERS 8 - -/* This TPM PCR is where most Linux infrastructure extends the initrd binary images into, and so do we. */ -#define TPM_PCR_INDEX_INITRD 4 - #define offsetof(type, member) __builtin_offsetof(type, member) #define UINTN_MAX (~(UINTN)0) diff --git a/src/busctl/test-busctl-introspect.c b/src/busctl/test-busctl-introspect.c index 216a9a3c3b..d0800d2360 100644 --- a/src/busctl/test-busctl-introspect.c +++ b/src/busctl/test-busctl-introspect.c @@ -313,7 +313,7 @@ static int on_path(const char *path, void *userdata) { return 0; } -static void test_introspect_on_path(void) { +TEST(introspect_on_path) { static const XMLIntrospectOps ops = { .on_path = on_path, }; @@ -321,8 +321,6 @@ static void test_introspect_on_path(void) { _cleanup_set_free_ Set *paths = NULL; _cleanup_free_ char **l = NULL; - log_info("/* %s */", __func__); - assert_se(set_put_strdup(&paths, "/") > 0); log_debug("/* parse_xml_introspect(\"/\") */"); @@ -363,10 +361,4 @@ static void test_introspect_on_path(void) { assert_se(strv_equal(l, expected)); } -int main(int argc, char *argv[]) { - test_setup_logging(LOG_DEBUG); - - test_introspect_on_path(); - - return 0; -} +DEFINE_TEST_MAIN(LOG_DEBUG); diff --git a/src/cryptenroll/cryptenroll-tpm2.c b/src/cryptenroll/cryptenroll-tpm2.c index 801014af11..e8c64dd753 100644 --- a/src/cryptenroll/cryptenroll-tpm2.c +++ b/src/cryptenroll/cryptenroll-tpm2.c @@ -1,7 +1,9 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #include "alloc-util.h" +#include "ask-password-api.h" #include "cryptenroll-tpm2.h" +#include "env-util.h" #include "hexdecoct.h" #include "json.h" #include "memory-util.h" @@ -58,11 +60,78 @@ static int search_policy_hash( return -ENOENT; /* Not found */ } +static int get_pin(char **ret_pin_str, TPM2Flags *ret_flags) { + _cleanup_free_ char *pin_str = NULL; + int r; + TPM2Flags flags = 0; + + assert(ret_pin_str); + assert(ret_flags); + + r = getenv_steal_erase("NEWPIN", &pin_str); + if (r < 0) + return log_error_errno(r, "Failed to acquire PIN from environment: %m"); + if (r > 0) + flags |= TPM2_FLAGS_USE_PIN; + else { + for (size_t i = 5;; i--) { + _cleanup_strv_free_erase_ char **pin = NULL, **pin2 = NULL; + + if (i <= 0) + return log_error_errno( + SYNTHETIC_ERRNO(ENOKEY), "Too many attempts, giving up."); + + pin = strv_free_erase(pin); + r = ask_password_auto( + "Please enter TPM2 PIN:", + "drive-harddisk", + NULL, + "tpm2-pin", + "cryptenroll.tpm2-pin", + USEC_INFINITY, + 0, + &pin); + if (r < 0) + return log_error_errno(r, "Failed to ask for user pin: %m"); + assert(strv_length(pin) == 1); + + r = ask_password_auto( + "Please enter TPM2 PIN (repeat):", + "drive-harddisk", + NULL, + "tpm2-pin", + "cryptenroll.tpm2-pin", + USEC_INFINITY, + 0, + &pin2); + if (r < 0) + return log_error_errno(r, "Failed to ask for user pin: %m"); + assert(strv_length(pin) == 1); + + if (strv_equal(pin, pin2)) { + pin_str = strdup(*pin); + if (!pin_str) + return log_oom(); + flags |= TPM2_FLAGS_USE_PIN; + break; + } + + log_error("PINs didn't match, please try again!"); + } + } + + *ret_flags = flags; + *ret_pin_str = TAKE_PTR(pin_str); + + return 0; +} + int enroll_tpm2(struct crypt_device *cd, const void *volume_key, size_t volume_key_size, const char *device, - uint32_t pcr_mask) { + uint32_t pcr_mask, + bool use_pin) { _cleanup_(erase_and_freep) void *secret = NULL, *secret2 = NULL; _cleanup_(json_variant_unrefp) JsonVariant *v = NULL; @@ -71,7 +140,9 @@ int enroll_tpm2(struct crypt_device *cd, _cleanup_free_ void *blob = NULL, *hash = NULL; uint16_t pcr_bank, primary_alg; const char *node; + _cleanup_(erase_and_freep) char *pin_str = NULL; int r, keyslot; + TPM2Flags flags = 0; assert(cd); assert(volume_key); @@ -80,7 +151,13 @@ int enroll_tpm2(struct crypt_device *cd, assert_se(node = crypt_get_device_name(cd)); - r = tpm2_seal(device, pcr_mask, &secret, &secret_size, &blob, &blob_size, &hash, &hash_size, &pcr_bank, &primary_alg); + if (use_pin) { + r = get_pin(&pin_str, &flags); + if (r < 0) + return r; + } + + r = tpm2_seal(device, pcr_mask, pin_str, &secret, &secret_size, &blob, &blob_size, &hash, &hash_size, &pcr_bank, &primary_alg); if (r < 0) return r; @@ -97,7 +174,7 @@ int enroll_tpm2(struct crypt_device *cd, /* Quick verification that everything is in order, we are not in a hurry after all. */ log_debug("Unsealing for verification..."); - r = tpm2_unseal(device, pcr_mask, pcr_bank, primary_alg, blob, blob_size, hash, hash_size, &secret2, &secret2_size); + r = tpm2_unseal(device, pcr_mask, pcr_bank, primary_alg, blob, blob_size, hash, hash_size, pin_str, &secret2, &secret2_size); if (r < 0) return r; @@ -123,7 +200,7 @@ int enroll_tpm2(struct crypt_device *cd, if (keyslot < 0) return log_error_errno(keyslot, "Failed to add new TPM2 key to %s: %m", node); - r = tpm2_make_luks2_json(keyslot, pcr_mask, pcr_bank, primary_alg, blob, blob_size, hash, hash_size, &v); + r = tpm2_make_luks2_json(keyslot, pcr_mask, pcr_bank, primary_alg, blob, blob_size, hash, hash_size, flags, &v); if (r < 0) return log_error_errno(r, "Failed to prepare TPM2 JSON token object: %m"); diff --git a/src/cryptenroll/cryptenroll-tpm2.h b/src/cryptenroll/cryptenroll-tpm2.h index d5dd1b0003..742f49b8d5 100644 --- a/src/cryptenroll/cryptenroll-tpm2.h +++ b/src/cryptenroll/cryptenroll-tpm2.h @@ -7,9 +7,9 @@ #include "log.h" #if HAVE_TPM2 -int enroll_tpm2(struct crypt_device *cd, const void *volume_key, size_t volume_key_size, const char *device, uint32_t pcr_mask); +int enroll_tpm2(struct crypt_device *cd, const void *volume_key, size_t volume_key_size, const char *device, uint32_t pcr_mask, bool use_pin); #else -static inline int enroll_tpm2(struct crypt_device *cd, const void *volume_key, size_t volume_key_size, const char *device, uint32_t pcr_mask) { +static inline int enroll_tpm2(struct crypt_device *cd, const void *volume_key, size_t volume_key_size, const char *device, uint32_t pcr_mask, bool use_pin) { return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "TPM2 key enrollment not supported."); } diff --git a/src/cryptenroll/cryptenroll.c b/src/cryptenroll/cryptenroll.c index e13f5b7ac8..2fd6d9080e 100644 --- a/src/cryptenroll/cryptenroll.c +++ b/src/cryptenroll/cryptenroll.c @@ -32,6 +32,7 @@ static char *arg_pkcs11_token_uri = NULL; static char *arg_fido2_device = NULL; static char *arg_tpm2_device = NULL; static uint32_t arg_tpm2_pcr_mask = UINT32_MAX; +static bool arg_tpm2_pin = false; static char *arg_node = NULL; static int *arg_wipe_slots = NULL; static size_t arg_n_wipe_slots = 0; @@ -100,6 +101,8 @@ static int help(void) { " Enroll a TPM2 device\n" " --tpm2-pcrs=PCR1+PCR2+PCR3+…\n" " Specify TPM2 PCRs to seal against\n" + " --tpm2-with-pin=BOOL\n" + " Whether to require entering a PIN to unlock the volume\n" " --wipe-slot=SLOT1,SLOT2,…\n" " Wipe specified slots\n" "\nSee the %s for details.\n", @@ -121,6 +124,7 @@ static int parse_argv(int argc, char *argv[]) { ARG_FIDO2_DEVICE, ARG_TPM2_DEVICE, ARG_TPM2_PCRS, + ARG_TPM2_PIN, ARG_WIPE_SLOT, ARG_FIDO2_WITH_PIN, ARG_FIDO2_WITH_UP, @@ -139,6 +143,7 @@ static int parse_argv(int argc, char *argv[]) { { "fido2-with-user-verification", required_argument, NULL, ARG_FIDO2_WITH_UV }, { "tpm2-device", required_argument, NULL, ARG_TPM2_DEVICE }, { "tpm2-pcrs", required_argument, NULL, ARG_TPM2_PCRS }, + { "tpm2-with-pin", required_argument, NULL, ARG_TPM2_PIN }, { "wipe-slot", required_argument, NULL, ARG_WIPE_SLOT }, {} }; @@ -301,6 +306,14 @@ static int parse_argv(int argc, char *argv[]) { break; } + case ARG_TPM2_PIN: { + r = parse_boolean_argument("--tpm2-with-pin=", optarg, &arg_tpm2_pin); + if (r < 0) + return r; + + break; + } + case ARG_WIPE_SLOT: { const char *p = optarg; @@ -558,7 +571,7 @@ static int run(int argc, char *argv[]) { break; case ENROLL_TPM2: - slot = enroll_tpm2(cd, vk, vks, arg_tpm2_device, arg_tpm2_pcr_mask); + slot = enroll_tpm2(cd, vk, vks, arg_tpm2_device, arg_tpm2_pcr_mask, arg_tpm2_pin); break; case _ENROLL_TYPE_INVALID: diff --git a/src/cryptsetup/cryptsetup-tokens/cryptsetup-token-systemd-tpm2.c b/src/cryptsetup/cryptsetup-tokens/cryptsetup-token-systemd-tpm2.c index e2d28a5dda..23df974999 100644 --- a/src/cryptsetup/cryptsetup-tokens/cryptsetup-token-systemd-tpm2.c +++ b/src/cryptsetup/cryptsetup-tokens/cryptsetup-token-systemd-tpm2.c @@ -6,8 +6,10 @@ #include "cryptsetup-token.h" #include "cryptsetup-token-util.h" #include "hexdecoct.h" +#include "json.h" #include "luks2-tpm2.h" #include "memory-util.h" +#include "strv.h" #include "tpm2-util.h" #include "version.h" @@ -78,7 +80,8 @@ _public_ int cryptsetup_token_open( if (usrptr) params = *(systemd_tpm2_plugin_params *)usrptr; - r = parse_luks2_tpm2_data(json, params.search_pcr_mask, &pcr_mask, &pcr_bank, &primary_alg, &base64_blob, &hex_policy_hash); + TPM2Flags flags = 0; + r = parse_luks2_tpm2_data(json, params.search_pcr_mask, &pcr_mask, &pcr_bank, &primary_alg, &base64_blob, &hex_policy_hash, &flags); if (r < 0) return log_debug_open_error(cd, r); @@ -101,6 +104,7 @@ _public_ int cryptsetup_token_open( blob_size, policy_hash, policy_hash_size, + flags, &decrypted_key, &decrypted_key_size); if (r < 0) @@ -135,6 +139,7 @@ _public_ void cryptsetup_token_dump( const char *json /* validated 'systemd-tpm2' token if cryptsetup_token_validate is defined */) { int r; + TPM2Flags flags = 0; uint32_t pcr_mask; uint16_t pcr_bank, primary_alg; size_t decoded_blob_size; @@ -144,7 +149,7 @@ _public_ void cryptsetup_token_dump( assert(json); - r = parse_luks2_tpm2_data(json, UINT32_MAX, &pcr_mask, &pcr_bank, &primary_alg, &base64_blob, &hex_policy_hash); + r = parse_luks2_tpm2_data(json, UINT32_MAX, &pcr_mask, &pcr_bank, &primary_alg, &base64_blob, &hex_policy_hash, &flags); if (r < 0) return (void) crypt_log_debug_errno(cd, r, "Failed to parse " TOKEN_NAME " metadata: %m."); @@ -171,6 +176,7 @@ _public_ void cryptsetup_token_dump( crypt_log(cd, "\ttpm2-primary-alg: %s\n", strna(tpm2_primary_alg_to_string(primary_alg))); crypt_log(cd, "\ttpm2-blob: %s\n", blob_str); crypt_log(cd, "\ttpm2-policy-hash:" CRYPT_DUMP_LINE_SEP "%s\n", policy_hash_str); + crypt_log(cd, "\ttpm2-pin: %s\n", true_false(flags & TPM2_FLAGS_USE_PIN)); } /* @@ -268,5 +274,13 @@ _public_ int cryptsetup_token_validate( if (r < 0) return crypt_log_debug_errno(cd, r, "Invalid base64 data in 'tpm2-policy-hash' field: %m"); + w = json_variant_by_key(v, "tpm2-pin"); + if (w) { + if (!json_variant_is_boolean(w)) { + crypt_log_debug(cd, "TPM2 PIN policy is not a boolean."); + return 1; + } + } + return 0; } diff --git a/src/cryptsetup/cryptsetup-tokens/luks2-tpm2.c b/src/cryptsetup/cryptsetup-tokens/luks2-tpm2.c index 3d39dfa884..0d6e4bc0f8 100644 --- a/src/cryptsetup/cryptsetup-tokens/luks2-tpm2.c +++ b/src/cryptsetup/cryptsetup-tokens/luks2-tpm2.c @@ -1,11 +1,15 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #include "alloc-util.h" +#include "ask-password-api.h" +#include "env-util.h" #include "hexdecoct.h" #include "json.h" +#include "log.h" #include "luks2-tpm2.h" #include "parse-util.h" #include "random-util.h" +#include "strv.h" #include "tpm2-util.h" int acquire_luks2_key( @@ -17,10 +21,12 @@ int acquire_luks2_key( size_t key_data_size, const void *policy_hash, size_t policy_hash_size, + TPM2Flags flags, void **ret_decrypted_key, size_t *ret_decrypted_key_size) { _cleanup_free_ char *auto_device = NULL; + _cleanup_(erase_and_freep) char *pin_str = NULL; int r; assert(ret_decrypted_key); @@ -36,12 +42,22 @@ int acquire_luks2_key( device = auto_device; } + r = getenv_steal_erase("PIN", &pin_str); + if (r < 0) + return log_error_errno(r, "Failed to acquire PIN from environment: %m"); + if (!r) { + /* PIN entry is not supported by plugin, let it fallback, possibly to sd-cryptsetup's + * internal handling. */ + if (flags & TPM2_FLAGS_USE_PIN) + return -EOPNOTSUPP; + } + return tpm2_unseal( device, pcr_mask, pcr_bank, primary_alg, key_data, key_data_size, - policy_hash, policy_hash_size, + policy_hash, policy_hash_size, pin_str, ret_decrypted_key, ret_decrypted_key_size); } @@ -53,7 +69,8 @@ int parse_luks2_tpm2_data( uint16_t *ret_pcr_bank, uint16_t *ret_primary_alg, char **ret_base64_blob, - char **ret_hex_policy_hash) { + char **ret_hex_policy_hash, + TPM2Flags *ret_flags) { int r; JsonVariant *w, *e; @@ -61,6 +78,7 @@ int parse_luks2_tpm2_data( uint16_t pcr_bank = UINT16_MAX, primary_alg = TPM2_ALG_ECC; _cleanup_free_ char *base64_blob = NULL, *hex_policy_hash = NULL; _cleanup_(json_variant_unrefp) JsonVariant *v = NULL; + TPM2Flags flags = 0; assert(json); assert(ret_pcr_mask); @@ -138,11 +156,21 @@ int parse_luks2_tpm2_data( if (!hex_policy_hash) return -ENOMEM; + w = json_variant_by_key(v, "tpm2-pin"); + if (w) { + if (!json_variant_is_boolean(w)) + return -EINVAL; + + if (json_variant_boolean(w)) + flags |= TPM2_FLAGS_USE_PIN; + } + *ret_pcr_mask = pcr_mask; *ret_pcr_bank = pcr_bank; *ret_primary_alg = primary_alg; *ret_base64_blob = TAKE_PTR(base64_blob); *ret_hex_policy_hash = TAKE_PTR(hex_policy_hash); + *ret_flags = flags; return 0; } diff --git a/src/cryptsetup/cryptsetup-tokens/luks2-tpm2.h b/src/cryptsetup/cryptsetup-tokens/luks2-tpm2.h index 0c93ea82cc..34c93216ee 100644 --- a/src/cryptsetup/cryptsetup-tokens/luks2-tpm2.h +++ b/src/cryptsetup/cryptsetup-tokens/luks2-tpm2.h @@ -2,6 +2,8 @@ #pragma once +#include "tpm2-util.h" + struct crypt_device; int acquire_luks2_key( @@ -13,6 +15,7 @@ int acquire_luks2_key( size_t key_data_size, const void *policy_hash, size_t policy_hash_size, + TPM2Flags flags, void **ret_decrypted_key, size_t *ret_decrypted_key_size); @@ -23,4 +26,5 @@ int parse_luks2_tpm2_data( uint16_t *ret_pcr_bank, uint16_t *ret_primary_alg, char **ret_base64_blob, - char **ret_hex_policy_hash); + char **ret_hex_policy_hash, + TPM2Flags *ret_flags); diff --git a/src/cryptsetup/cryptsetup-tpm2.c b/src/cryptsetup/cryptsetup-tpm2.c index cb139518a7..b84d64def8 100644 --- a/src/cryptsetup/cryptsetup-tpm2.c +++ b/src/cryptsetup/cryptsetup-tpm2.c @@ -1,7 +1,9 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #include "alloc-util.h" +#include "ask-password-api.h" #include "cryptsetup-tpm2.h" +#include "env-util.h" #include "fileio.h" #include "hexdecoct.h" #include "json.h" @@ -9,6 +11,47 @@ #include "random-util.h" #include "tpm2-util.h" +static int get_pin(usec_t until, AskPasswordFlags ask_password_flags, bool headless, char **ret_pin_str) { + _cleanup_free_ char *pin_str = NULL; + _cleanup_strv_free_erase_ char **pin = NULL; + int r; + + assert(ret_pin_str); + + r = getenv_steal_erase("PIN", &pin_str); + if (r < 0) + return log_error_errno(r, "Failed to acquire PIN from environment: %m"); + if (!r) { + if (headless) + return log_error_errno( + SYNTHETIC_ERRNO(ENOPKG), + "PIN querying disabled via 'headless' option. " + "Use the '$PIN' environment variable."); + + pin = strv_free_erase(pin); + r = ask_password_auto( + "Please enter TPM2 PIN:", + "drive-harddisk", + NULL, + "tpm2-pin", + "cryptsetup.tpm2-pin", + until, + ask_password_flags, + &pin); + if (r < 0) + return log_error_errno(r, "Failed to ask for user pin: %m"); + assert(strv_length(pin) == 1); + + pin_str = strdup(pin[0]); + if (!pin_str) + return log_oom(); + } + + *ret_pin_str = TAKE_PTR(pin_str); + + return r; +} + int acquire_tpm2_key( const char *volume_name, const char *device, @@ -22,6 +65,10 @@ int acquire_tpm2_key( size_t key_data_size, const void *policy_hash, size_t policy_hash_size, + TPM2Flags flags, + usec_t until, + bool headless, + AskPasswordFlags ask_password_flags, void **ret_decrypted_key, size_t *ret_decrypted_key_size) { @@ -64,7 +111,51 @@ int acquire_tpm2_key( blob = loaded_blob; } - return tpm2_unseal(device, pcr_mask, pcr_bank, primary_alg, blob, blob_size, policy_hash, policy_hash_size, ret_decrypted_key, ret_decrypted_key_size); + if (!(flags & TPM2_FLAGS_USE_PIN)) + return tpm2_unseal( + device, + pcr_mask, + pcr_bank, + primary_alg, + blob, + blob_size, + policy_hash, + policy_hash_size, + NULL, + ret_decrypted_key, + ret_decrypted_key_size); + + for (int i = 5;; i--) { + _cleanup_(erase_and_freep) char *pin_str = NULL; + + if (i <= 0) + return -EACCES; + + r = get_pin(until, ask_password_flags, headless, &pin_str); + if (r < 0) + return r; + + r = tpm2_unseal( + device, + pcr_mask, + pcr_bank, + primary_alg, + blob, + blob_size, + policy_hash, + policy_hash_size, + pin_str, + ret_decrypted_key, + ret_decrypted_key_size); + /* We get this error in case there is an authentication policy mismatch. This should + * not happen, but this avoids confusing behavior, just in case. */ + if (IN_SET(r, -EPERM, -ENOLCK)) + return r; + if (r < 0) + continue; + + return r; + } } int find_tpm2_auto_data( @@ -79,11 +170,13 @@ int find_tpm2_auto_data( void **ret_policy_hash, size_t *ret_policy_hash_size, int *ret_keyslot, - int *ret_token) { + int *ret_token, + TPM2Flags *ret_flags) { _cleanup_free_ void *blob = NULL, *policy_hash = NULL; size_t blob_size = 0, policy_hash_size = 0; int r, keyslot = -1, token = -1; + TPM2Flags flags = 0; uint32_t pcr_mask = 0; uint16_t pcr_bank = UINT16_MAX; /* default: pick automatically */ uint16_t primary_alg = TPM2_ALG_ECC; /* ECC was the only supported algorithm in systemd < 250, use that as implied default, for compatibility */ @@ -196,6 +289,16 @@ int find_tpm2_auto_data( return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid base64 data in 'tpm2-policy-hash' field."); + w = json_variant_by_key(v, "tpm2-pin"); + if (w) { + if (!json_variant_is_boolean(w)) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "TPM2 PIN policy is not a boolean."); + + if (json_variant_boolean(w)) + flags |= TPM2_FLAGS_USE_PIN; + } + break; } @@ -215,6 +318,7 @@ int find_tpm2_auto_data( *ret_token = token; *ret_pcr_bank = pcr_bank; *ret_primary_alg = primary_alg; + *ret_flags = flags; return 0; } diff --git a/src/cryptsetup/cryptsetup-tpm2.h b/src/cryptsetup/cryptsetup-tpm2.h index bd04620462..ab16d0a18f 100644 --- a/src/cryptsetup/cryptsetup-tpm2.h +++ b/src/cryptsetup/cryptsetup-tpm2.h @@ -3,9 +3,11 @@ #include <sys/types.h> +#include "ask-password-api.h" #include "cryptsetup-util.h" #include "log.h" #include "time-util.h" +#include "tpm2-util.h" #if HAVE_TPM2 @@ -22,6 +24,10 @@ int acquire_tpm2_key( size_t key_data_size, const void *policy_hash, size_t policy_hash_size, + TPM2Flags flags, + usec_t until, + bool headless, + AskPasswordFlags ask_password_flags, void **ret_decrypted_key, size_t *ret_decrypted_key_size); @@ -37,7 +43,8 @@ int find_tpm2_auto_data( void **ret_policy_hash, size_t *ret_policy_hash_size, int *ret_keyslot, - int *ret_token); + int *ret_token, + TPM2Flags *ret_flags); #else @@ -54,6 +61,10 @@ static inline int acquire_tpm2_key( size_t key_data_size, const void *policy_hash, size_t policy_hash_size, + TPM2Flags flags, + usec_t until, + bool headless, + AskPasswordFlags ask_password_flags, void **ret_decrypted_key, size_t *ret_decrypted_key_size) { @@ -73,7 +84,8 @@ static inline int find_tpm2_auto_data( void **ret_policy_hash, size_t *ret_policy_hash_size, int *ret_keyslot, - int *ret_token) { + int *ret_token, + TPM2Flags *ret_flags) { return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "TPM2 support not available."); diff --git a/src/cryptsetup/cryptsetup.c b/src/cryptsetup/cryptsetup.c index 56a3eedacc..c2075f53fd 100644 --- a/src/cryptsetup/cryptsetup.c +++ b/src/cryptsetup/cryptsetup.c @@ -82,6 +82,7 @@ static char *arg_fido2_rp_id = NULL; static char *arg_tpm2_device = NULL; static bool arg_tpm2_device_auto = false; static uint32_t arg_tpm2_pcr_mask = UINT32_MAX; +static bool arg_tpm2_pin = false; static bool arg_headless = false; static usec_t arg_token_timeout_usec = 30*USEC_PER_SEC; @@ -387,6 +388,16 @@ static int parse_one_option(const char *option) { arg_tpm2_pcr_mask |= mask; } + } else if ((val = startswith(option, "tpm2-pin="))) { + + r = parse_boolean(val); + if (r < 0) { + log_error_errno(r, "Failed to parse %s, ignoring: %m", option); + return 0; + } + + arg_tpm2_pin = r; + } else if ((val = startswith(option, "try-empty-password="))) { r = parse_boolean(val); @@ -1301,9 +1312,15 @@ static int attach_luks_or_plain_or_bitlk_by_tpm2( key_file, arg_keyfile_size, arg_keyfile_offset, key_data, key_data_size, NULL, 0, /* we don't know the policy hash */ + arg_tpm2_pin, + until, + arg_headless, + arg_ask_password_flags, &decrypted_key, &decrypted_key_size); if (r >= 0) break; + if (IN_SET(r, -EACCES, -ENOLCK)) + return log_error_errno(SYNTHETIC_ERRNO(EAGAIN), "TPM2 PIN unlock failed, falling back to traditional unlocking."); if (ERRNO_IS_NOT_SUPPORTED(r)) /* TPM2 support not compiled in? */ return log_debug_errno(SYNTHETIC_ERRNO(EAGAIN), "TPM2 support not available, falling back to traditional unlocking."); if (r != -EAGAIN) /* EAGAIN means: no tpm2 chip found */ @@ -1335,6 +1352,7 @@ static int attach_luks_or_plain_or_bitlk_by_tpm2( for (;;) { uint32_t pcr_mask; uint16_t pcr_bank, primary_alg; + TPM2Flags tpm2_flags; r = find_tpm2_auto_data( cd, @@ -1346,7 +1364,8 @@ static int attach_luks_or_plain_or_bitlk_by_tpm2( &blob, &blob_size, &policy_hash, &policy_hash_size, &keyslot, - &token); + &token, + &tpm2_flags); if (r == -ENXIO) /* No further TPM2 tokens found in the LUKS2 header. */ return log_debug_errno(SYNTHETIC_ERRNO(EAGAIN), @@ -1369,7 +1388,13 @@ static int attach_luks_or_plain_or_bitlk_by_tpm2( NULL, 0, 0, /* no key file */ blob, blob_size, policy_hash, policy_hash_size, + tpm2_flags, + until, + arg_headless, + arg_ask_password_flags, &decrypted_key, &decrypted_key_size); + if (IN_SET(r, -EACCES, -ENOLCK)) + return log_error_errno(SYNTHETIC_ERRNO(EAGAIN), "TPM2 PIN unlock failed, falling back to traditional unlocking."); if (r != -EPERM) break; diff --git a/src/fundamental/sha256.h b/src/fundamental/sha256.h index abc4167628..e53197f2ef 100644 --- a/src/fundamental/sha256.h +++ b/src/fundamental/sha256.h @@ -8,6 +8,8 @@ #include "types-fundamental.h" +#define SHA256_DIGEST_SIZE 32 + struct sha256_ctx { uint32_t H[8]; diff --git a/src/journal/test-journal-config.c b/src/journal/test-journal-config.c index bd0de9600a..1a6c531f4e 100644 --- a/src/journal/test-journal-config.c +++ b/src/journal/test-journal-config.c @@ -3,6 +3,7 @@ #include <stdbool.h> #include "journald-server.h" +#include "tests.h" #define _COMPRESS_PARSE_CHECK(str, enab, thresh, varname) \ do { \ @@ -17,7 +18,7 @@ #define COMPRESS_PARSE_CHECK(str, enabled, threshold) \ _COMPRESS_PARSE_CHECK(str, enabled, threshold, conf##__COUNTER__) -static void test_config_compress(void) { +TEST(config_compress) { COMPRESS_PARSE_CHECK("yes", true, 111); COMPRESS_PARSE_CHECK("no", false, 111); COMPRESS_PARSE_CHECK("y", true, 111); @@ -46,8 +47,4 @@ static void test_config_compress(void) { COMPRESS_PARSE_CHECK("", true, UINT64_MAX); } -int main(int argc, char *argv[]) { - test_config_compress(); - - return 0; -} +DEFINE_TEST_MAIN(LOG_INFO); diff --git a/src/journal/test-journal-interleaving.c b/src/journal/test-journal-interleaving.c index 2d86e2a5a1..bbb83d0824 100644 --- a/src/journal/test-journal-interleaving.c +++ b/src/journal/test-journal-interleaving.c @@ -70,7 +70,7 @@ static void append_number(ManagedJournalFile *f, int n, uint64_t *seqnum) { free(p); } -static void test_check_number (sd_journal *j, int n) { +static void test_check_number(sd_journal *j, int n) { const void *d; _cleanup_free_ char *k; size_t l; @@ -84,7 +84,7 @@ static void test_check_number (sd_journal *j, int n) { assert_se(n == x); } -static void test_check_numbers_down (sd_journal *j, int count) { +static void test_check_numbers_down(sd_journal *j, int count) { int i; for (i = 1; i <= count; i++) { @@ -99,7 +99,7 @@ static void test_check_numbers_down (sd_journal *j, int count) { } -static void test_check_numbers_up (sd_journal *j, int count) { +static void test_check_numbers_up(sd_journal *j, int count) { for (int i = count; i >= 1; i--) { int r; test_check_number(j, i); @@ -145,7 +145,7 @@ static void mkdtemp_chdir_chattr(char *path) { (void) chattr_path(path, FS_NOCOW_FL, FS_NOCOW_FL, NULL); } -static void test_skip(void (*setup)(void)) { +static void test_skip_one(void (*setup)(void)) { char t[] = "/var/tmp/journal-skip-XXXXXX"; sd_journal *j; int r; @@ -201,8 +201,12 @@ static void test_skip(void (*setup)(void)) { puts("------------------------------------------------------------"); } -static void test_sequence_numbers(void) { +TEST(skip) { + test_skip_one(setup_sequential); + test_skip_one(setup_interleaved); +} +TEST(sequence_numbers) { _cleanup_(mmap_cache_unrefp) MMapCache *m = NULL; char t[] = "/var/tmp/journal-seq-XXXXXX"; ManagedJournalFile *one, *two; @@ -287,19 +291,14 @@ static void test_sequence_numbers(void) { } } -int main(int argc, char *argv[]) { - test_setup_logging(LOG_DEBUG); - +static int intro(void) { /* managed_journal_file_open requires a valid machine id */ if (access("/etc/machine-id", F_OK) != 0) return log_tests_skipped("/etc/machine-id not found"); - arg_keep = argc > 1; - - test_skip(setup_sequential); - test_skip(setup_interleaved); + arg_keep = saved_argc > 1; - test_sequence_numbers(); - - return 0; + return EXIT_SUCCESS; } + +DEFINE_TEST_MAIN_WITH_INTRO(LOG_DEBUG, intro); diff --git a/src/journal/test-journal-syslog.c b/src/journal/test-journal-syslog.c index 33f412956b..84cfcefc3a 100644 --- a/src/journal/test-journal-syslog.c +++ b/src/journal/test-journal-syslog.c @@ -5,8 +5,9 @@ #include "macro.h" #include "string-util.h" #include "syslog-util.h" +#include "tests.h" -static void test_syslog_parse_identifier(const char *str, +static void test_syslog_parse_identifier_one(const char *str, const char *ident, const char *pid, const char *rest, int ret) { const char *buf = str; _cleanup_free_ char *ident2 = NULL, *pid2 = NULL; @@ -20,40 +21,50 @@ static void test_syslog_parse_identifier(const char *str, assert_se(streq(buf, rest)); } -static void test_syslog_parse_priority(const char *str, int priority, int ret) { - const char *buf = str; +static void test_syslog_parse_priority_one(const char *str, bool with_facility, int priority, int ret) { int priority2 = 0, ret2; - ret2 = syslog_parse_priority(&buf, &priority2, false); + ret2 = syslog_parse_priority(&str, &priority2, with_facility); assert_se(ret == ret2); if (ret2 == 1) assert_se(priority == priority2); } -int main(void) { - test_syslog_parse_identifier("pidu[111]: xxx", "pidu", "111", "xxx", 11); - test_syslog_parse_identifier("pidu: xxx", "pidu", NULL, "xxx", 6); - test_syslog_parse_identifier("pidu: xxx", "pidu", NULL, " xxx", 6); - test_syslog_parse_identifier("pidu xxx", NULL, NULL, "pidu xxx", 0); - test_syslog_parse_identifier(" pidu xxx", NULL, NULL, " pidu xxx", 0); - test_syslog_parse_identifier("", NULL, NULL, "", 0); - test_syslog_parse_identifier(" ", NULL, NULL, " ", 0); - test_syslog_parse_identifier(":", "", NULL, "", 1); - test_syslog_parse_identifier(": ", "", NULL, " ", 2); - test_syslog_parse_identifier(" :", "", NULL, "", 2); - test_syslog_parse_identifier(" pidu:", "pidu", NULL, "", 8); - test_syslog_parse_identifier("pidu:", "pidu", NULL, "", 5); - test_syslog_parse_identifier("pidu: ", "pidu", NULL, "", 6); - test_syslog_parse_identifier("pidu : ", NULL, NULL, "pidu : ", 0); - - test_syslog_parse_priority("<>", 0, 0); - test_syslog_parse_priority("<>aaa", 0, 0); - test_syslog_parse_priority("<aaaa>", 0, 0); - test_syslog_parse_priority("<aaaa>aaa", 0, 0); - test_syslog_parse_priority(" <aaaa>", 0, 0); - test_syslog_parse_priority(" <aaaa>aaa", 0, 0); - /* TODO: add test cases of valid priorities */ - - return 0; +TEST(syslog_parse_identifier) { + test_syslog_parse_identifier_one("pidu[111]: xxx", "pidu", "111", "xxx", 11); + test_syslog_parse_identifier_one("pidu: xxx", "pidu", NULL, "xxx", 6); + test_syslog_parse_identifier_one("pidu: xxx", "pidu", NULL, " xxx", 6); + test_syslog_parse_identifier_one("pidu xxx", NULL, NULL, "pidu xxx", 0); + test_syslog_parse_identifier_one(" pidu xxx", NULL, NULL, " pidu xxx", 0); + test_syslog_parse_identifier_one("", NULL, NULL, "", 0); + test_syslog_parse_identifier_one(" ", NULL, NULL, " ", 0); + test_syslog_parse_identifier_one(":", "", NULL, "", 1); + test_syslog_parse_identifier_one(": ", "", NULL, " ", 2); + test_syslog_parse_identifier_one(" :", "", NULL, "", 2); + test_syslog_parse_identifier_one(" pidu:", "pidu", NULL, "", 8); + test_syslog_parse_identifier_one("pidu:", "pidu", NULL, "", 5); + test_syslog_parse_identifier_one("pidu: ", "pidu", NULL, "", 6); + test_syslog_parse_identifier_one("pidu : ", NULL, NULL, "pidu : ", 0); +} + +TEST(syslog_parse_priority) { + test_syslog_parse_priority_one("", false, 0, 0); + test_syslog_parse_priority_one("<>", false, 0, 0); + test_syslog_parse_priority_one("<>aaa", false, 0, 0); + test_syslog_parse_priority_one("<aaaa>", false, 0, 0); + test_syslog_parse_priority_one("<aaaa>aaa", false, 0, 0); + test_syslog_parse_priority_one(" <aaaa>", false, 0, 0); + test_syslog_parse_priority_one(" <aaaa>aaa", false, 0, 0); + test_syslog_parse_priority_one(" <aaaa>aaa", false, 0, 0); + test_syslog_parse_priority_one(" <1>", false, 0, 0); + test_syslog_parse_priority_one("<1>", false, 1, 1); + test_syslog_parse_priority_one("<7>", false, 7, 1); + test_syslog_parse_priority_one("<8>", false, 0, 0); + test_syslog_parse_priority_one("<9>", true, 9, 1); + test_syslog_parse_priority_one("<22>", true, 22, 1); + test_syslog_parse_priority_one("<111>", false, 0, 0); + test_syslog_parse_priority_one("<111>", true, 111, 1); } + +DEFINE_TEST_MAIN(LOG_INFO); diff --git a/src/journal/test-journal.c b/src/journal/test-journal.c index bfc1cf2960..07c476559c 100644 --- a/src/journal/test-journal.c +++ b/src/journal/test-journal.c @@ -23,7 +23,7 @@ static void mkdtemp_chdir_chattr(char *path) { (void) chattr_path(path, FS_NOCOW_FL, FS_NOCOW_FL, NULL); } -static void test_non_empty(void) { +TEST(non_empty) { _cleanup_(mmap_cache_unrefp) MMapCache *m = NULL; dual_timestamp ts; ManagedJournalFile *f; @@ -34,8 +34,6 @@ static void test_non_empty(void) { sd_id128_t fake_boot_id; char t[] = "/var/tmp/journal-XXXXXX"; - test_setup_logging(LOG_DEBUG); - m = mmap_cache_new(); assert_se(m != NULL); @@ -120,13 +118,11 @@ static void test_non_empty(void) { puts("------------------------------------------------------------"); } -static void test_empty(void) { +TEST(empty) { _cleanup_(mmap_cache_unrefp) MMapCache *m = NULL; ManagedJournalFile *f1, *f2, *f3, *f4; char t[] = "/var/tmp/journal-XXXXXX"; - test_setup_logging(LOG_DEBUG); - m = mmap_cache_new(); assert_se(m != NULL); @@ -177,8 +173,6 @@ static bool check_compressed(uint64_t compress_threshold, uint64_t data_size) { assert_se(data_size <= sizeof(data)); - test_setup_logging(LOG_DEBUG); - m = mmap_cache_new(); assert_se(m != NULL); @@ -228,7 +222,7 @@ static bool check_compressed(uint64_t compress_threshold, uint64_t data_size) { return is_compressed; } -static void test_min_compress_size(void) { +TEST(min_compress_size) { /* Note that XZ will actually fail to compress anything under 80 bytes, so you have to choose the limits * carefully */ @@ -249,20 +243,14 @@ static void test_min_compress_size(void) { } #endif -int main(int argc, char *argv[]) { - arg_keep = argc > 1; - - test_setup_logging(LOG_INFO); +static int intro(void) { + arg_keep = saved_argc > 1; /* managed_journal_file_open requires a valid machine id */ if (access("/etc/machine-id", F_OK) != 0) return log_tests_skipped("/etc/machine-id not found"); - test_non_empty(); - test_empty(); -#if HAVE_COMPRESSION - test_min_compress_size(); -#endif - - return 0; + return EXIT_SUCCESS; } + +DEFINE_TEST_MAIN_WITH_INTRO(LOG_DEBUG, intro); diff --git a/src/libsystemd-network/test-dhcp6-client.c b/src/libsystemd-network/test-dhcp6-client.c index f53e093d77..dfd9042c29 100644 --- a/src/libsystemd-network/test-dhcp6-client.c +++ b/src/libsystemd-network/test-dhcp6-client.c @@ -78,12 +78,10 @@ static int test_ifindex = 42; static unsigned test_client_sent_message_count = 0; static sd_dhcp6_client *client_ref = NULL; -static void test_client_basic(void) { +TEST(client_basic) { _cleanup_(sd_dhcp6_client_unrefp) sd_dhcp6_client *client = NULL; int v; - log_debug("/* %s */", __func__); - assert_se(sd_dhcp6_client_new(&client) >= 0); assert_se(client); @@ -144,13 +142,11 @@ static void test_client_basic(void) { assert_se(sd_dhcp6_client_detach_event(client) >= 0); } -static void test_parse_domain(void) { +TEST(parse_domain) { _cleanup_free_ char *domain = NULL; _cleanup_strv_free_ char **list = NULL; uint8_t *data; - log_debug("/* %s */", __func__); - data = (uint8_t []) { 7, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 3, 'c', 'o', 'm', 0 }; assert_se(dhcp6_option_parse_domainname(data, 13, &domain) >= 0); assert_se(domain); @@ -182,7 +178,7 @@ static void test_parse_domain(void) { assert_se(dhcp6_option_parse_domainname_list(data, 2, &list) < 0); } -static void test_option(void) { +TEST(option) { uint8_t packet[] = { 'F', 'O', 'O', 'H', 'O', 'G', 'E', 0x00, SD_DHCP6_OPTION_ORO, 0x00, 0x07, @@ -204,8 +200,6 @@ static void test_option(void) { uint16_t optcode; uint8_t *out; - log_debug("/* %s */", __func__); - assert_se(sizeof(packet) == sizeof(result)); offset = 0; @@ -258,7 +252,7 @@ static void test_option(void) { assert_se(memcmp(packet, result, sizeof(packet)) == 0); } -static void test_option_status(void) { +TEST(option_status) { uint8_t option1[] = { /* IA NA */ 0x00, 0x03, 0x00, 0x12, 0x1a, 0x1d, 0x1a, 0x1d, @@ -330,8 +324,6 @@ static void test_option_status(void) { be32_t iaid; int r; - log_debug("/* %s */", __func__); - memcpy(&iaid, option1 + 4, sizeof(iaid)); option = (DHCP6Option*) option1; @@ -384,7 +376,7 @@ static void test_option_status(void) { ia = dhcp6_ia_free(ia); } -static void test_client_parse_message_issue_22099(void) { +TEST(client_parse_message_issue_22099) { static const uint8_t msg[] = { /* Message type */ DHCP6_MESSAGE_REPLY, @@ -444,8 +436,6 @@ static void test_client_parse_message_issue_22099(void) { _cleanup_(sd_dhcp6_client_unrefp) sd_dhcp6_client *client = NULL; _cleanup_(sd_dhcp6_lease_unrefp) sd_dhcp6_lease *lease = NULL; - log_debug("/* %s */", __func__); - assert_se(sd_dhcp6_client_new(&client) >= 0); assert_se(sd_dhcp6_client_set_iaid(client, 0xcc59117b) >= 0); assert_se(sd_dhcp6_client_set_duid(client, 2, duid, sizeof(duid)) >= 0); @@ -970,12 +960,10 @@ int dhcp6_network_bind_udp_socket(int ifindex, struct in6_addr *a) { return TAKE_FD(test_fd[0]); } -static void test_dhcp6_client(void) { +TEST(dhcp6_client) { _cleanup_(sd_dhcp6_client_unrefp) sd_dhcp6_client *client = NULL; _cleanup_(sd_event_unrefp) sd_event *e = NULL; - log_debug("/* %s */", __func__); - assert_se(sd_event_new(&e) >= 0); assert_se(sd_event_add_time_relative(e, NULL, clock_boottime_or_monotonic(), 2 * USEC_PER_SEC, 0, @@ -1006,15 +994,4 @@ static void test_dhcp6_client(void) { test_fd[1] = safe_close(test_fd[1]); } -int main(int argc, char *argv[]) { - test_setup_logging(LOG_DEBUG); - - test_client_basic(); - test_parse_domain(); - test_option(); - test_option_status(); - test_client_parse_message_issue_22099(); - test_dhcp6_client(); - - return 0; -} +DEFINE_TEST_MAIN(LOG_DEBUG); diff --git a/src/libsystemd-network/test-ndisc-ra.c b/src/libsystemd-network/test-ndisc-ra.c index 83186a97bb..cbf065d4fb 100644 --- a/src/libsystemd-network/test-ndisc-ra.c +++ b/src/libsystemd-network/test-ndisc-ra.c @@ -100,11 +100,9 @@ static const struct in6_addr test_rdnss = { { { 0x20, 0x01, 0x0d, 0xb8, static const char *test_dnssl[] = { "lab.intra", NULL }; -static void test_radv_prefix(void) { +TEST(radv_prefix) { sd_radv_prefix *p; - printf("* %s\n", __func__); - assert_se(sd_radv_prefix_new(&p) >= 0); assert_se(sd_radv_prefix_set_onlink(NULL, true) < 0); @@ -142,11 +140,9 @@ static void test_radv_prefix(void) { assert_se(!p); } -static void test_radv(void) { +TEST(radv) { sd_radv *ra; - printf("* %s\n", __func__); - assert_se(sd_radv_new(&ra) >= 0); assert_se(ra); @@ -284,13 +280,11 @@ static int radv_recv(sd_event_source *s, int fd, uint32_t revents, void *userdat return 0; } -static void test_ra(void) { +TEST(ra) { sd_event *e; sd_radv *ra; unsigned i; - printf("* %s\n", __func__); - assert_se(socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC | SOCK_NONBLOCK, 0, test_fd) >= 0); assert_se(sd_event_new(&e) >= 0); @@ -349,14 +343,4 @@ static void test_ra(void) { sd_event_unref(e); } -int main(int argc, char *argv[]) { - - test_setup_logging(LOG_DEBUG); - - test_radv_prefix(); - test_radv(); - test_ra(); - - printf("* done\n"); - return 0; -} +DEFINE_TEST_MAIN(LOG_DEBUG); diff --git a/src/libsystemd-network/test-ndisc-rs.c b/src/libsystemd-network/test-ndisc-rs.c index 10915e1d4c..2c27d12b09 100644 --- a/src/libsystemd-network/test-ndisc-rs.c +++ b/src/libsystemd-network/test-ndisc-rs.c @@ -257,13 +257,10 @@ static void test_callback(sd_ndisc *nd, sd_ndisc_event_t event, sd_ndisc_router sd_event_exit(e, 0); } -static void test_rs(void) { +TEST(rs) { sd_event *e; sd_ndisc *nd; - if (verbose) - printf("* %s\n", __func__); - send_ra_function = send_ra; assert_se(sd_event_new(&e) >= 0); @@ -347,13 +344,10 @@ static int test_timeout_value(uint8_t flags) { return 0; } -static void test_timeout(void) { +TEST(timeout) { sd_event *e; sd_ndisc *nd; - if (verbose) - printf("* %s\n", __func__); - send_ra_function = test_timeout_value; assert_se(sd_event_new(&e) >= 0); @@ -381,12 +375,4 @@ static void test_timeout(void) { sd_event_unref(e); } -int main(int argc, char *argv[]) { - - test_setup_logging(LOG_DEBUG); - - test_rs(); - test_timeout(); - - return 0; -} +DEFINE_TEST_MAIN(LOG_DEBUG); diff --git a/src/libsystemd-network/test-sd-dhcp-lease.c b/src/libsystemd-network/test-sd-dhcp-lease.c index 9f13226889..3eea1b0d9b 100644 --- a/src/libsystemd-network/test-sd-dhcp-lease.c +++ b/src/libsystemd-network/test-sd-dhcp-lease.c @@ -6,13 +6,14 @@ #include "macro.h" #include "string-util.h" #include "strv.h" +#include "tests.h" /* According to RFC1035 section 4.1.4, a domain name in a message can be either: * - a sequence of labels ending in a zero octet * - a pointer * - a sequence of labels ending with a pointer */ -static void test_dhcp_lease_parse_search_domains_basic(void) { +TEST(dhcp_lease_parse_search_domains_basic) { int r; _cleanup_strv_free_ char **domains = NULL; static const uint8_t optionbuf[] = { @@ -26,7 +27,7 @@ static void test_dhcp_lease_parse_search_domains_basic(void) { assert_se(streq(domains[1], "ABCD.EFG")); } -static void test_dhcp_lease_parse_search_domains_ptr(void) { +TEST(dhcp_lease_parse_search_domains_ptr) { int r; _cleanup_strv_free_ char **domains = NULL; static const uint8_t optionbuf[] = { @@ -39,7 +40,7 @@ static void test_dhcp_lease_parse_search_domains_ptr(void) { assert_se(streq(domains[1], "FOO")); } -static void test_dhcp_lease_parse_search_domains_labels_and_ptr(void) { +TEST(dhcp_lease_parse_search_domains_labels_and_ptr) { int r; _cleanup_strv_free_ char **domains = NULL; static const uint8_t optionbuf[] = { @@ -55,7 +56,7 @@ static void test_dhcp_lease_parse_search_domains_labels_and_ptr(void) { /* Tests for exceptions. */ -static void test_dhcp_lease_parse_search_domains_no_data(void) { +TEST(dhcp_lease_parse_search_domains_no_data) { _cleanup_strv_free_ char **domains = NULL; static const uint8_t optionbuf[3] = {0, 0, 0}; @@ -63,7 +64,7 @@ static void test_dhcp_lease_parse_search_domains_no_data(void) { assert_se(dhcp_lease_parse_search_domains(optionbuf, 0, &domains) == -ENODATA); } -static void test_dhcp_lease_parse_search_domains_loops(void) { +TEST(dhcp_lease_parse_search_domains_loops) { _cleanup_strv_free_ char **domains = NULL; static const uint8_t optionbuf[] = { 0x03, 'F', 'O', 'O', 0x00, 0x03, 'B', 'A', 'R', 0xC0, 0x06, @@ -72,7 +73,7 @@ static void test_dhcp_lease_parse_search_domains_loops(void) { assert_se(dhcp_lease_parse_search_domains(optionbuf, sizeof(optionbuf), &domains) == -EBADMSG); } -static void test_dhcp_lease_parse_search_domains_wrong_len(void) { +TEST(dhcp_lease_parse_search_domains_wrong_len) { _cleanup_strv_free_ char **domains = NULL; static const uint8_t optionbuf[] = { 0x03, 'F', 'O', 'O', 0x03, 'B', 'A', 'R', 0x00, @@ -82,12 +83,4 @@ static void test_dhcp_lease_parse_search_domains_wrong_len(void) { assert_se(dhcp_lease_parse_search_domains(optionbuf, sizeof(optionbuf) - 5, &domains) == -EBADMSG); } -int main(int argc, char *argv[]) { - test_dhcp_lease_parse_search_domains_basic(); - test_dhcp_lease_parse_search_domains_ptr(); - test_dhcp_lease_parse_search_domains_labels_and_ptr(); - test_dhcp_lease_parse_search_domains_no_data(); - test_dhcp_lease_parse_search_domains_loops(); - test_dhcp_lease_parse_search_domains_wrong_len(); - return 0; -} +DEFINE_TEST_MAIN(LOG_INFO); diff --git a/src/libsystemd/sd-bus/test-bus-address.c b/src/libsystemd/sd-bus/test-bus-address.c index 59421094c5..00d3c15a8f 100644 --- a/src/libsystemd/sd-bus/test-bus-address.c +++ b/src/libsystemd/sd-bus/test-bus-address.c @@ -22,13 +22,13 @@ static void test_one_address(sd_bus *b, } } -static void test_bus_set_address_system_remote(char **args) { +TEST(bus_set_address_system_remote) { _cleanup_(sd_bus_unrefp) sd_bus *b = NULL; assert_se(sd_bus_new(&b) >= 0); - if (!strv_isempty(args)) { + if (!strv_isempty(saved_argv + 1)) { char **a; - STRV_FOREACH(a, args) + STRV_FOREACH(a, saved_argv + 1) test_one_address(b, *a, 0, NULL); return; }; @@ -61,10 +61,4 @@ static void test_bus_set_address_system_remote(char **args) { -EINVAL, NULL); } -int main(int argc, char *argv[]) { - test_setup_logging(LOG_INFO); - - test_bus_set_address_system_remote(argv + 1); - - return 0; -} +DEFINE_TEST_MAIN(LOG_INFO); diff --git a/src/libsystemd/sd-bus/test-bus-error.c b/src/libsystemd/sd-bus/test-bus-error.c index 84728e4e84..952455255d 100644 --- a/src/libsystemd/sd-bus/test-bus-error.c +++ b/src/libsystemd/sd-bus/test-bus-error.c @@ -8,8 +8,9 @@ #include "errno-list.h" #include "errno-util.h" #include "string-util.h" +#include "tests.h" -static void test_error(void) { +TEST(error) { _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL, second = SD_BUS_ERROR_NULL; const sd_bus_error const_error = SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_FILE_EXISTS, "const error"); const sd_bus_error temporarily_const_error = { @@ -126,7 +127,7 @@ static void test_error(void) { extern const sd_bus_error_map __start_SYSTEMD_BUS_ERROR_MAP[]; extern const sd_bus_error_map __stop_SYSTEMD_BUS_ERROR_MAP[]; -static void dump_mapping_table(void) { +static int dump_mapping_table(void) { const sd_bus_error_map *m; printf("----- errno mappings ------\n"); @@ -142,9 +143,11 @@ static void dump_mapping_table(void) { m++; } printf("---------------------------\n"); + + return EXIT_SUCCESS; } -static void test_errno_mapping_standard(void) { +TEST(errno_mapping_standard) { assert_se(sd_bus_error_set(NULL, "System.Error.EUCLEAN", NULL) == -EUCLEAN); assert_se(sd_bus_error_set(NULL, "System.Error.EBUSY", NULL) == -EBUSY); assert_se(sd_bus_error_set(NULL, "System.Error.EINVAL", NULL) == -EINVAL); @@ -186,7 +189,7 @@ static const sd_bus_error_map test_errors_bad2[] = { SD_BUS_ERROR_MAP_END }; -static void test_errno_mapping_custom(void) { +TEST(errno_mapping_custom) { assert_se(sd_bus_error_set(NULL, "org.freedesktop.custom-dbus-error", NULL) == -5); assert_se(sd_bus_error_set(NULL, "org.freedesktop.custom-dbus-error-2", NULL) == -52); assert_se(sd_bus_error_set(NULL, "org.freedesktop.custom-dbus-error-x", NULL) == -EIO); @@ -214,7 +217,7 @@ static void test_errno_mapping_custom(void) { assert_se(sd_bus_error_add_map(test_errors_bad2) == -EINVAL); } -static void test_sd_bus_error_set_errnof(void) { +TEST(sd_bus_error_set_errnof) { _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_free_ char *str = NULL; @@ -288,13 +291,4 @@ static void test_sd_bus_error_set_errnof(void) { assert_se(error._need_free == 1); } -int main(int argc, char *argv[]) { - dump_mapping_table(); - - test_error(); - test_errno_mapping_standard(); - test_errno_mapping_custom(); - test_sd_bus_error_set_errnof(); - - return 0; -} +DEFINE_TEST_MAIN_WITH_INTRO(LOG_INFO, dump_mapping_table); diff --git a/src/libsystemd/sd-bus/test-bus-gvariant.c b/src/libsystemd/sd-bus/test-bus-gvariant.c index edd8301d45..47b1752360 100644 --- a/src/libsystemd/sd-bus/test-bus-gvariant.c +++ b/src/libsystemd/sd-bus/test-bus-gvariant.c @@ -15,9 +15,7 @@ #include "tests.h" #include "util.h" -static void test_bus_gvariant_is_fixed_size(void) { - log_info("/* %s */", __func__); - +TEST(bus_gvariant_is_fixed_size) { assert_se(bus_gvariant_is_fixed_size("") > 0); assert_se(bus_gvariant_is_fixed_size("()") == -EINVAL); assert_se(bus_gvariant_is_fixed_size("y") > 0); @@ -42,9 +40,7 @@ static void test_bus_gvariant_is_fixed_size(void) { assert_se(bus_gvariant_is_fixed_size("((u)yyy(b(iiivi)))") == 0); } -static void test_bus_gvariant_get_size(void) { - log_info("/* %s */", __func__); - +TEST(bus_gvariant_get_size) { assert_se(bus_gvariant_get_size("") == 0); assert_se(bus_gvariant_get_size("()") == -EINVAL); assert_se(bus_gvariant_get_size("y") == 1); @@ -76,9 +72,7 @@ static void test_bus_gvariant_get_size(void) { assert_se(bus_gvariant_get_size("((t)(t))") == 16); } -static void test_bus_gvariant_get_alignment(void) { - log_info("/* %s */", __func__); - +TEST(bus_gvariant_get_alignment) { assert_se(bus_gvariant_get_alignment("") == 1); assert_se(bus_gvariant_get_alignment("()") == -EINVAL); assert_se(bus_gvariant_get_alignment("y") == 1); @@ -119,7 +113,7 @@ static void test_bus_gvariant_get_alignment(void) { assert_se(bus_gvariant_get_alignment("((t)(t))") == 8); } -static int test_marshal(void) { +TEST_RET(marshal) { _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *n = NULL; _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; _cleanup_free_ void *blob = NULL; @@ -209,12 +203,4 @@ static int test_marshal(void) { return EXIT_SUCCESS; } -int main(int argc, char *argv[]) { - test_setup_logging(LOG_DEBUG); - - test_bus_gvariant_is_fixed_size(); - test_bus_gvariant_get_size(); - test_bus_gvariant_get_alignment(); - - return test_marshal(); -} +DEFINE_TEST_MAIN(LOG_DEBUG); diff --git a/src/libsystemd/sd-bus/test-bus-introspect.c b/src/libsystemd/sd-bus/test-bus-introspect.c index fb247c4d14..3c026aedb9 100644 --- a/src/libsystemd/sd-bus/test-bus-introspect.c +++ b/src/libsystemd/sd-bus/test-bus-introspect.c @@ -6,7 +6,7 @@ #include "test-vtable-data.h" -static void test_manual_introspection(const sd_bus_vtable vtable[]) { +static void test_manual_introspection_one(const sd_bus_vtable vtable[]) { struct introspect intro = {}; _cleanup_free_ char *s = NULL; @@ -23,13 +23,11 @@ static void test_manual_introspection(const sd_bus_vtable vtable[]) { fputs("\n", stdout); } -int main(int argc, char *argv[]) { - test_setup_logging(LOG_DEBUG); - - test_manual_introspection(test_vtable_1); - test_manual_introspection(test_vtable_2); - test_manual_introspection(test_vtable_deprecated); - test_manual_introspection((const sd_bus_vtable *) vtable_format_221); - - return 0; +TEST(manual_introspection) { + test_manual_introspection_one(test_vtable_1); + test_manual_introspection_one(test_vtable_2); + test_manual_introspection_one(test_vtable_deprecated); + test_manual_introspection_one((const sd_bus_vtable *) vtable_format_221); } + +DEFINE_TEST_MAIN(LOG_DEBUG); diff --git a/src/libsystemd/sd-device/test-device-util.c b/src/libsystemd/sd-device/test-device-util.c index 93fc105d98..bc8ab66716 100644 --- a/src/libsystemd/sd-device/test-device-util.c +++ b/src/libsystemd/sd-device/test-device-util.c @@ -3,11 +3,9 @@ #include "device-util.h" #include "tests.h" -static void test_log_device_full(void) { +TEST(log_device_full) { int r; - log_info("/* %s */", __func__); - for (int level = LOG_ERR; level <= LOG_DEBUG; level++) { log_device_full(NULL, level, "test level=%d: %m", level); @@ -22,9 +20,4 @@ static void test_log_device_full(void) { } } -int main(int argc, char **argv) { - test_setup_logging(LOG_INFO); - - test_log_device_full(); - return 0; -} +DEFINE_TEST_MAIN(LOG_INFO); diff --git a/src/libsystemd/sd-device/test-sd-device.c b/src/libsystemd/sd-device/test-sd-device.c index aaa16f740d..2d2157ba70 100644 --- a/src/libsystemd/sd-device/test-sd-device.c +++ b/src/libsystemd/sd-device/test-sd-device.c @@ -60,24 +60,20 @@ static void test_sd_device_one(sd_device *d) { log_info("syspath:%s subsystem:%s initialized:%s", syspath, strna(subsystem), yes_no(i)); } -static void test_sd_device_enumerator_devices(void) { +TEST(sd_device_enumerator_devices) { _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL; sd_device *d; - log_info("/* %s */", __func__); - assert_se(sd_device_enumerator_new(&e) >= 0); assert_se(sd_device_enumerator_allow_uninitialized(e) >= 0); FOREACH_DEVICE(e, d) test_sd_device_one(d); } -static void test_sd_device_enumerator_subsystems(void) { +TEST(sd_device_enumerator_subsystems) { _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL; sd_device *d; - log_info("/* %s */", __func__); - assert_se(sd_device_enumerator_new(&e) >= 0); assert_se(sd_device_enumerator_allow_uninitialized(e) >= 0); FOREACH_SUBSYSTEM(e, d) @@ -113,7 +109,7 @@ static unsigned test_sd_device_enumerator_filter_subsystem_one(const char *subsy return n_new_dev; } -static void test_sd_device_enumerator_filter_subsystem(void) { +TEST(sd_device_enumerator_filter_subsystem) { _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL; _cleanup_(hashmap_freep) Hashmap *subsystems; unsigned n_new_dev = 0; @@ -121,8 +117,6 @@ static void test_sd_device_enumerator_filter_subsystem(void) { Hashmap *h; char *s; - log_info("/* %s */", __func__); - assert_se(subsystems = hashmap_new(&string_hash_ops)); assert_se(sd_device_enumerator_new(&e) >= 0); @@ -164,7 +158,7 @@ static void test_sd_device_enumerator_filter_subsystem(void) { assert_se(n_new_dev <= 10); } -static void test_sd_device_new_from_nulstr(void) { +TEST(sd_device_new_from_nulstr) { const char *devlinks = "/dev/disk/by-partuuid/1290d63a-42cc-4c71-b87c-xxxxxxxxxxxx\0" "/dev/disk/by-path/pci-0000:00:0f.0-scsi-0:0:0:0-part3\0" @@ -179,8 +173,6 @@ static void test_sd_device_new_from_nulstr(void) { const uint8_t *nulstr; size_t len; - log_info("/* %s */", __func__); - assert_se(sd_device_new_from_syspath(&device, "/sys/class/net/lo") >= 0); /* Yeah, of course, setting devlink to the loopback interface is nonsense. But this is just a @@ -205,14 +197,4 @@ static void test_sd_device_new_from_nulstr(void) { } } -int main(int argc, char **argv) { - test_setup_logging(LOG_INFO); - - test_sd_device_enumerator_devices(); - test_sd_device_enumerator_subsystems(); - test_sd_device_enumerator_filter_subsystem(); - - test_sd_device_new_from_nulstr(); - - return 0; -} +DEFINE_TEST_MAIN(LOG_INFO); diff --git a/src/libsystemd/sd-event/test-event.c b/src/libsystemd/sd-event/test-event.c index 0ac23c1118..f902c4e3ff 100644 --- a/src/libsystemd/sd-event/test-event.c +++ b/src/libsystemd/sd-event/test-event.c @@ -195,7 +195,7 @@ static int post_handler(sd_event_source *s, void *userdata) { return 2; } -static void test_basic(bool with_pidfd) { +static void test_basic_one(bool with_pidfd) { sd_event *e = NULL; sd_event_source *w = NULL, *x = NULL, *y = NULL, *z = NULL, *q = NULL, *t = NULL; static const char ch = 'x'; @@ -302,12 +302,15 @@ static void test_basic(bool with_pidfd) { assert_se(unsetenv("SYSTEMD_PIDFD") >= 0); } -static void test_sd_event_now(void) { +TEST(basic) { + test_basic_one(true); /* test with pidfd */ + test_basic_one(false); /* test without pidfd */ +} + +TEST(sd_event_now) { _cleanup_(sd_event_unrefp) sd_event *e = NULL; uint64_t event_now; - log_info("/* %s */", __func__); - assert_se(sd_event_new(&e) >= 0); assert_se(sd_event_now(e, CLOCK_MONOTONIC, &event_now) > 0); assert_se(sd_event_now(e, CLOCK_REALTIME, &event_now) > 0); @@ -341,12 +344,10 @@ static int rtqueue_handler(sd_event_source *s, const struct signalfd_siginfo *si return 0; } -static void test_rtqueue(void) { +TEST(rtqueue) { sd_event_source *u = NULL, *v = NULL, *s = NULL; sd_event *e = NULL; - log_info("/* %s */", __func__); - assert_se(sd_event_default(&e) >= 0); assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGRTMIN+2, SIGRTMIN+3, SIGUSR2, -1) >= 0); @@ -476,7 +477,7 @@ static int delete_self_handler(sd_event_source *s, const struct inotify_event *e return 1; } -static void test_inotify(unsigned n_create_events) { +static void test_inotify_one(unsigned n_create_events) { _cleanup_(rm_rf_physical_and_freep) char *p = NULL; sd_event_source *a = NULL, *b = NULL, *c = NULL, *d = NULL; struct inotify_context context = { @@ -529,6 +530,11 @@ static void test_inotify(unsigned n_create_events) { sd_event_unref(e); } +TEST(inotify) { + test_inotify_one(100); /* should work without overflow */ + test_inotify_one(33000); /* should trigger a q overflow */ +} + static int pidfd_handler(sd_event_source *s, const siginfo_t *si, void *userdata) { assert_se(s); assert_se(si); @@ -548,14 +554,12 @@ static int pidfd_handler(sd_event_source *s, const siginfo_t *si, void *userdata return 0; } -static void test_pidfd(void) { +TEST(pidfd) { sd_event_source *s = NULL, *t = NULL; sd_event *e = NULL; int pidfd; pid_t pid, pid2; - log_info("/* %s */", __func__); - assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD, -1) >= 0); pid = fork(); @@ -628,15 +632,13 @@ static int ratelimit_expired(sd_event_source *s, void *userdata) { return ++expired; } -static void test_ratelimit(void) { +TEST(ratelimit) { _cleanup_close_pair_ int p[2] = {-1, -1}; _cleanup_(sd_event_unrefp) sd_event *e = NULL; _cleanup_(sd_event_source_unrefp) sd_event_source *s = NULL; uint64_t interval; unsigned count, burst; - log_info("/* %s */", __func__); - assert_se(sd_event_default(&e) >= 0); assert_se(pipe2(p, O_CLOEXEC|O_NONBLOCK) >= 0); @@ -706,7 +708,7 @@ static void test_ratelimit(void) { assert_se(expired == 0); } -static void test_simple_timeout(void) { +TEST(simple_timeout) { _cleanup_(sd_event_unrefp) sd_event *e = NULL; usec_t f, t, some_time; @@ -741,7 +743,7 @@ static int inotify_self_destroy_handler(sd_event_source *s, const struct inotify return 1; } -static void test_inotify_self_destroy(void) { +TEST(inotify_self_destroy) { _cleanup_(sd_event_source_unrefp) sd_event_source *s = NULL; _cleanup_(sd_event_unrefp) sd_event *e = NULL; char path[] = "/tmp/inotifyXXXXXX"; @@ -759,25 +761,4 @@ static void test_inotify_self_destroy(void) { assert_se(sd_event_loop(e) >= 0); } -int main(int argc, char *argv[]) { - test_setup_logging(LOG_DEBUG); - - test_simple_timeout(); - - test_basic(true); /* test with pidfd */ - test_basic(false); /* test without pidfd */ - - test_sd_event_now(); - test_rtqueue(); - - test_inotify(100); /* should work without overflow */ - test_inotify(33000); /* should trigger a q overflow */ - - test_pidfd(); - - test_ratelimit(); - - test_inotify_self_destroy(); - - return 0; -} +DEFINE_TEST_MAIN(LOG_DEBUG); diff --git a/src/libsystemd/sd-journal/test-audit-type.c b/src/libsystemd/sd-journal/test-audit-type.c index 5adbf0d5b6..1d5003bd9b 100644 --- a/src/libsystemd/sd-journal/test-audit-type.c +++ b/src/libsystemd/sd-journal/test-audit-type.c @@ -4,6 +4,7 @@ #include <linux/audit.h> #include "audit-type.h" +#include "tests.h" static void print_audit_label(int i) { const char *name; @@ -13,14 +14,11 @@ static void print_audit_label(int i) { printf("%i → %s → %s\n", i, audit_type_to_string(i), name); } -static void test_audit_type(void) { +TEST(audit_type) { int i; for (i = 0; i <= AUDIT_KERNEL; i++) print_audit_label(i); } -int main(int argc, char **argv) { - test_audit_type(); - return 0; -} +DEFINE_TEST_MAIN(LOG_INFO); diff --git a/src/libsystemd/sd-journal/test-journal-send.c b/src/libsystemd/sd-journal/test-journal-send.c index 533b8d91e6..8f9d9c4a30 100644 --- a/src/libsystemd/sd-journal/test-journal-send.c +++ b/src/libsystemd/sd-journal/test-journal-send.c @@ -10,8 +10,9 @@ #include "journal-send.h" #include "macro.h" #include "memory-util.h" +#include "tests.h" -static void test_journal_print(void) { +TEST(journal_print) { assert_se(sd_journal_print(LOG_INFO, "XXX") == 0); assert_se(sd_journal_print(LOG_INFO, "%s", "YYY") == 0); assert_se(sd_journal_print(LOG_INFO, "X%4094sY", "ZZZ") == 0); @@ -19,7 +20,7 @@ static void test_journal_print(void) { assert_se(sd_journal_print(LOG_INFO, "X%*sY", LONG_LINE_MAX - 8 - 2, "ZZZ") == -ENOBUFS); } -static void test_journal_send(void) { +TEST(journal_send) { _cleanup_free_ char *huge = NULL; #define HUGE_SIZE (4096*1024) @@ -98,13 +99,13 @@ static void test_journal_send(void) { closelog(); } -int main(int argc, char *argv[]) { - test_journal_print(); - test_journal_send(); - +static int outro(void) { /* Sleep a bit to make it easy for journald to collect metadata. */ sleep(1); close_journal_fd(); - return 0; + + return EXIT_SUCCESS; } + +DEFINE_TEST_MAIN_FULL(LOG_INFO, NULL, outro); diff --git a/src/libsystemd/sd-login/test-login.c b/src/libsystemd/sd-login/test-login.c index 3fc394d5ee..f7cef6e304 100644 --- a/src/libsystemd/sd-login/test-login.c +++ b/src/libsystemd/sd-login/test-login.c @@ -11,6 +11,7 @@ #include "log.h" #include "string-util.h" #include "strv.h" +#include "tests.h" #include "time-util.h" #include "user-util.h" @@ -35,7 +36,7 @@ static const char *e(int r) { return r == 0 ? "OK" : errno_to_name(r); } -static void test_login(void) { +TEST(login) { _cleanup_close_pair_ int pair[2] = { -1, -1 }; _cleanup_free_ char *pp = NULL, *qq = NULL, *display_session = NULL, *cgroup = NULL, @@ -259,10 +260,13 @@ static void test_login(void) { } } -static void test_monitor(void) { +TEST(monitor) { sd_login_monitor *m = NULL; int r; + if (!streq_ptr(saved_argv[1], "-m")) + return; + assert_se(sd_login_monitor_new("session", &m) == 0); for (unsigned n = 0; n < 5; n++) { @@ -290,16 +294,9 @@ static void test_monitor(void) { sd_login_monitor_unref(m); } -int main(int argc, char* argv[]) { - log_parse_environment(); - log_open(); - +static int intro(void) { log_info("/* Information printed is from the live system */"); - - test_login(); - - if (streq_ptr(argv[1], "-m")) - test_monitor(); - - return 0; + return EXIT_SUCCESS; } + +DEFINE_TEST_MAIN_WITH_INTRO(LOG_INFO, intro); diff --git a/src/locale/test-keymap-util.c b/src/locale/test-keymap-util.c index f726e8e524..668f94ec80 100644 --- a/src/locale/test-keymap-util.c +++ b/src/locale/test-keymap-util.c @@ -6,11 +6,9 @@ #include "string-util.h" #include "tests.h" -static void test_find_language_fallback(void) { +TEST(find_language_fallback) { _cleanup_free_ char *ans = NULL, *ans2 = NULL; - log_info("/*** %s ***/", __func__); - assert_se(find_language_fallback("foobar", &ans) == 0); assert_se(ans == NULL); @@ -24,12 +22,10 @@ static void test_find_language_fallback(void) { assert_se(streq(ans2, "szl:pl")); } -static void test_find_converted_keymap(void) { +TEST(find_converted_keymap) { _cleanup_free_ char *ans = NULL, *ans2 = NULL; int r; - log_info("/*** %s ***/", __func__); - assert_se(find_converted_keymap("pl", "foobar", &ans) == 0); assert_se(ans == NULL); @@ -46,12 +42,10 @@ static void test_find_converted_keymap(void) { assert_se(streq(ans2, "pl-dvorak")); } -static void test_find_legacy_keymap(void) { +TEST(find_legacy_keymap) { Context c = {}; _cleanup_free_ char *ans = NULL, *ans2 = NULL; - log_info("/*** %s ***/", __func__); - c.x11_layout = (char*) "foobar"; assert_se(find_legacy_keymap(&c, &ans) == 0); assert_se(ans == NULL); @@ -65,11 +59,9 @@ static void test_find_legacy_keymap(void) { assert_se(streq(ans, "pl2")); } -static void test_vconsole_convert_to_x11(void) { +TEST(vconsole_convert_to_x11) { _cleanup_(context_clear) Context c = {}; - log_info("/*** %s ***/", __func__); - log_info("/* test emptying first (:) */"); assert_se(free_and_strdup(&c.x11_layout, "foo") >= 0); assert_se(free_and_strdup(&c.x11_variant, "bar") >= 0); @@ -119,12 +111,10 @@ static void test_vconsole_convert_to_x11(void) { assert_se(c.x11_variant == NULL); } -static void test_x11_convert_to_vconsole(void) { +TEST(x11_convert_to_vconsole) { _cleanup_(context_clear) Context c = {}; int r; - log_info("/*** %s ***/", __func__); - log_info("/* test emptying first (:) */"); assert_se(free_and_strdup(&c.vc_keymap, "foobar") >= 0); assert_se(x11_convert_to_vconsole(&c) == 1); @@ -189,20 +179,13 @@ static void test_x11_convert_to_vconsole(void) { assert_se(streq(c.vc_keymap, "ru")); } -int main(int argc, char **argv) { +static int intro(void) { _cleanup_free_ char *map = NULL; - test_setup_logging(LOG_DEBUG); - - test_find_language_fallback(); - test_find_converted_keymap(); - assert_se(get_testdata_dir("test-keymap-util/kbd-model-map", &map) >= 0); assert_se(setenv("SYSTEMD_KBD_MODEL_MAP", map, 1) == 0); - test_find_legacy_keymap(); - test_vconsole_convert_to_x11(); - test_x11_convert_to_vconsole(); - - return 0; + return EXIT_SUCCESS; } + +DEFINE_TEST_MAIN_WITH_INTRO(LOG_DEBUG, intro); diff --git a/src/login/test-login-shared.c b/src/login/test-login-shared.c index d3de9c4958..17cd479dc9 100644 --- a/src/login/test-login-shared.c +++ b/src/login/test-login-shared.c @@ -2,8 +2,9 @@ #include "login-util.h" #include "macro.h" +#include "tests.h" -static void test_session_id_valid(void) { +TEST(session_id_valid) { assert_se(session_id_valid("c1")); assert_se(session_id_valid("1234")); @@ -12,11 +13,4 @@ static void test_session_id_valid(void) { assert_se(!session_id_valid("\tid")); } -int main(int argc, char* argv[]) { - log_parse_environment(); - log_open(); - - test_session_id_valid(); - - return 0; -} +DEFINE_TEST_MAIN(LOG_INFO); diff --git a/src/network/test-networkd-address.c b/src/network/test-networkd-address.c index 46e8369abb..e0d85b2b79 100644 --- a/src/network/test-networkd-address.c +++ b/src/network/test-networkd-address.c @@ -11,11 +11,9 @@ static void test_FORMAT_LIFETIME_one(usec_t lifetime, const char *expected) { assert_se(streq(t, expected)); } -static void test_FORMAT_LIFETIME(void) { +TEST(FORMAT_LIFETIME) { usec_t now_usec; - log_info("/* %s */", __func__); - now_usec = now(clock_boottime_or_monotonic()); test_FORMAT_LIFETIME_one(now_usec, "for 0"); @@ -24,10 +22,4 @@ static void test_FORMAT_LIFETIME(void) { test_FORMAT_LIFETIME_one(USEC_INFINITY, "forever"); } -int main(int argc, char *argv[]) { - test_setup_logging(LOG_DEBUG); - - test_FORMAT_LIFETIME(); - - return 0; -} +DEFINE_TEST_MAIN(LOG_DEBUG); diff --git a/src/network/test-networkd-conf.c b/src/network/test-networkd-conf.c index 5f1328e39c..2e4ca0cb5f 100644 --- a/src/network/test-networkd-conf.c +++ b/src/network/test-networkd-conf.c @@ -9,6 +9,7 @@ #include "networkd-manager.h" #include "networkd-network.h" #include "strv.h" +#include "tests.h" static void test_config_parse_duid_type_one(const char *rvalue, int ret, DUIDType expected, usec_t expected_time) { DUID actual = {}; @@ -22,7 +23,7 @@ static void test_config_parse_duid_type_one(const char *rvalue, int ret, DUIDTyp assert_se(expected_time == actual.llt_time); } -static void test_config_parse_duid_type(void) { +TEST(config_parse_duid_type) { test_config_parse_duid_type_one("", 0, 0, 0); test_config_parse_duid_type_one("link-layer-time", 0, DUID_TYPE_LLT, 0); test_config_parse_duid_type_one("link-layer-time:2000-01-01 00:00:00 UTC", 0, DUID_TYPE_LLT, (usec_t) 946684800000000); @@ -86,7 +87,7 @@ static void test_config_parse_ether_addrs_one(const char *rvalue, const struct e #define BYTES_1_128 {0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,0xa,0xb,0xc,0xd,0xe,0xf,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,0x80} -static void test_config_parse_duid_rawdata(void) { +TEST(config_parse_duid_rawdata) { test_config_parse_duid_rawdata_one("", 0, &(DUID){}); test_config_parse_duid_rawdata_one("00:11:22:33:44:55:66:77", 0, &(DUID){0, 8, {0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77}}); @@ -102,7 +103,7 @@ static void test_config_parse_duid_rawdata(void) { test_config_parse_duid_rawdata_one(&BYTES_0_128[2], 0, &(DUID){0, 128, BYTES_1_128}); } -static void test_config_parse_ether_addr(void) { +TEST(config_parse_ether_addr) { const struct ether_addr t[] = { { .ether_addr_octet = { 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff } }, { .ether_addr_octet = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab } }, @@ -192,7 +193,7 @@ static void test_config_parse_address_one(const char *rvalue, int family, unsign } } -static void test_config_parse_address(void) { +TEST(config_parse_address) { test_config_parse_address_one("", AF_INET, 0, NULL, 0); test_config_parse_address_one("/", AF_INET, 0, NULL, 0); test_config_parse_address_one("/8", AF_INET, 0, NULL, 0); @@ -219,7 +220,7 @@ static void test_config_parse_address(void) { test_config_parse_address_one("::1/-1", AF_INET6, 0, NULL, 0); } -static void test_config_parse_match_ifnames(void) { +TEST(config_parse_match_ifnames) { _cleanup_strv_free_ char **names = NULL; assert_se(config_parse_match_ifnames("network", "filename", 1, "section", 1, "Name", 0, "!hoge hogehoge foo", &names, NULL) == 0); @@ -229,7 +230,7 @@ static void test_config_parse_match_ifnames(void) { assert_se(strv_equal(names, STRV_MAKE("!hoge", "!hogehoge", "!foo", "!baz", "aaa", "bbb", "ccc"))); } -static void test_config_parse_match_strv(void) { +TEST(config_parse_match_strv) { _cleanup_strv_free_ char **names = NULL; assert_se(config_parse_match_strv("network", "filename", 1, "section", 1, "Name", 0, "!hoge hogehoge foo", &names, NULL) == 0); @@ -247,16 +248,4 @@ static void test_config_parse_match_strv(void) { "KEY3=val with \\quotation\\"))); } -int main(int argc, char **argv) { - log_parse_environment(); - log_open(); - - test_config_parse_duid_type(); - test_config_parse_duid_rawdata(); - test_config_parse_ether_addr(); - test_config_parse_address(); - test_config_parse_match_ifnames(); - test_config_parse_match_strv(); - - return 0; -} +DEFINE_TEST_MAIN(LOG_INFO); diff --git a/src/partition/repart.c b/src/partition/repart.c index 91645202fc..8345b6f582 100644 --- a/src/partition/repart.c +++ b/src/partition/repart.c @@ -2656,7 +2656,7 @@ static int partition_encrypt( uint16_t pcr_bank, primary_alg; int keyslot; - r = tpm2_seal(arg_tpm2_device, arg_tpm2_pcr_mask, &secret, &secret_size, &blob, &blob_size, &hash, &hash_size, &pcr_bank, &primary_alg); + r = tpm2_seal(arg_tpm2_device, arg_tpm2_pcr_mask, NULL, &secret, &secret_size, &blob, &blob_size, &hash, &hash_size, &pcr_bank, &primary_alg); if (r < 0) return log_error_errno(r, "Failed to seal to TPM2: %m"); @@ -2678,7 +2678,7 @@ static int partition_encrypt( if (keyslot < 0) return log_error_errno(keyslot, "Failed to add new TPM2 key to %s: %m", node); - r = tpm2_make_luks2_json(keyslot, arg_tpm2_pcr_mask, pcr_bank, primary_alg, blob, blob_size, hash, hash_size, &v); + r = tpm2_make_luks2_json(keyslot, arg_tpm2_pcr_mask, pcr_bank, primary_alg, blob, blob_size, hash, hash_size, 0, &v); if (r < 0) return log_error_errno(r, "Failed to prepare TPM2 JSON token object: %m"); diff --git a/src/resolve/test-dnssec.c b/src/resolve/test-dnssec.c index 3263095360..d325b533ea 100644 --- a/src/resolve/test-dnssec.c +++ b/src/resolve/test-dnssec.c @@ -9,13 +9,13 @@ #endif #include "alloc-util.h" +#include "hexdecoct.h" #include "resolved-dns-dnssec.h" #include "resolved-dns-rr.h" #include "string-util.h" -#include "hexdecoct.h" - -static void test_dnssec_verify_dns_key(void) { +#include "tests.h" +TEST(dnssec_verify_dns_key) { static const uint8_t ds1_fprint[] = { 0x46, 0x8B, 0xC8, 0xDD, 0xC7, 0xE8, 0x27, 0x03, 0x40, 0xBB, 0x8A, 0x1F, 0x3B, 0x2E, 0x45, 0x9D, 0x80, 0x67, 0x14, 0x01, @@ -88,7 +88,7 @@ static void test_dnssec_verify_dns_key(void) { assert_se(dnssec_verify_dnskey_by_ds(dnskey, ds2, false) > 0); } -static void test_dnssec_verify_rfc8080_ed25519_example1(void) { +TEST(dnssec_verify_rfc8080_ed25519_example1) { static const uint8_t dnskey_blob[] = { 0x97, 0x4d, 0x96, 0xa2, 0x2d, 0x22, 0x4b, 0xc0, 0x1a, 0xdb, 0x91, 0x50, 0x91, 0x47, 0x7d, 0x44, 0xcc, 0xd9, 0x1c, 0x9a, 0x41, 0xa1, 0x14, 0x30, 0x01, 0x01, 0x17, 0xd5, 0x2c, 0x59, @@ -180,7 +180,7 @@ static void test_dnssec_verify_rfc8080_ed25519_example1(void) { #endif } -static void test_dnssec_verify_rfc8080_ed25519_example2(void) { +TEST(dnssec_verify_rfc8080_ed25519_example2) { static const uint8_t dnskey_blob[] = { 0xcc, 0xf9, 0xd9, 0xfd, 0x0c, 0x04, 0x7b, 0xb4, 0xbc, 0x0b, 0x94, 0x8f, 0xcf, 0x63, 0x9f, 0x4b, 0x94, 0x51, 0xe3, 0x40, 0x13, 0x93, 0x6f, 0xeb, 0x62, 0x71, 0x3d, 0xc4, 0x72, 0x4, @@ -272,7 +272,7 @@ static void test_dnssec_verify_rfc8080_ed25519_example2(void) { #endif } -static void test_dnssec_verify_rfc6605_example1(void) { +TEST(dnssec_verify_rfc6605_example1) { static const uint8_t signature_blob[] = { 0xab, 0x1e, 0xb0, 0x2d, 0x8a, 0xa6, 0x87, 0xe9, 0x7d, 0xa0, 0x22, 0x93, 0x37, 0xaa, 0x88, 0x73, 0xe6, 0xf0, 0xeb, 0x26, 0xbe, 0x28, 0x9f, 0x28, 0x33, 0x3d, 0x18, 0x3f, 0x5d, 0x3b, 0x7a, 0x95, @@ -359,7 +359,7 @@ static void test_dnssec_verify_rfc6605_example1(void) { assert_se(result == DNSSEC_VALIDATED); } -static void test_dnssec_verify_rfc6605_example2(void) { +TEST(dnssec_verify_rfc6605_example2) { static const uint8_t signature_blob[] = { 0xfc, 0xbe, 0x61, 0x0c, 0xa2, 0x2f, 0x18, 0x3c, 0x88, 0xd5, 0xf7, 0x00, 0x45, 0x7d, 0xf3, 0xeb, 0x9a, 0xab, 0x98, 0xfb, 0x15, 0xcf, 0xbd, 0xd0, 0x0f, 0x53, 0x2b, 0xe4, 0x21, 0x2a, 0x3a, 0x22, @@ -454,8 +454,7 @@ static void test_dnssec_verify_rfc6605_example2(void) { assert_se(result == DNSSEC_VALIDATED); } -static void test_dnssec_verify_rrset(void) { - +TEST(dnssec_verify_rrset) { static const uint8_t signature_blob[] = { 0x7f, 0x79, 0xdd, 0x5e, 0x89, 0x79, 0x18, 0xd0, 0x34, 0x86, 0x8c, 0x72, 0x77, 0x75, 0x48, 0x4d, 0xc3, 0x7d, 0x38, 0x04, 0xab, 0xcd, 0x9e, 0x4c, 0x82, 0xb0, 0x92, 0xca, 0xe9, 0x66, 0xe9, 0x6e, @@ -533,8 +532,7 @@ static void test_dnssec_verify_rrset(void) { assert_se(result == DNSSEC_VALIDATED); } -static void test_dnssec_verify_rrset2(void) { - +TEST(dnssec_verify_rrset2) { static const uint8_t signature_blob[] = { 0x48, 0x45, 0xc8, 0x8b, 0xc0, 0x14, 0x92, 0xf5, 0x15, 0xc6, 0x84, 0x9d, 0x2f, 0xe3, 0x32, 0x11, 0x7d, 0xf1, 0xe6, 0x87, 0xb9, 0x42, 0xd3, 0x8b, 0x9e, 0xaf, 0x92, 0x31, 0x0a, 0x53, 0xad, 0x8b, @@ -625,8 +623,7 @@ static void test_dnssec_verify_rrset2(void) { assert_se(result == DNSSEC_VALIDATED); } -static void test_dnssec_verify_rrset3(void) { - +TEST(dnssec_verify_rrset3) { static const uint8_t signature_blob[] = { 0x41, 0x09, 0x08, 0x67, 0x51, 0x6d, 0x02, 0xf2, 0x17, 0x1e, 0x61, 0x03, 0xc6, 0x80, 0x7a, 0x82, 0x8f, 0x6c, 0x8c, 0x4c, 0x68, 0x6f, 0x1c, 0xaa, 0x4a, 0xe0, 0x9b, 0x72, 0xdf, 0x7f, 0x15, 0xfa, @@ -755,7 +752,7 @@ static void test_dnssec_verify_rrset3(void) { assert_se(result == DNSSEC_VALIDATED); } -static void test_dnssec_nsec3_hash(void) { +TEST(dnssec_nsec3_hash) { static const uint8_t salt[] = { 0xB0, 0x1D, 0xFA, 0xCE }; static const uint8_t next_hashed_name[] = { 0x84, 0x10, 0x26, 0x53, 0xc9, 0xfa, 0x4d, 0x85, 0x6c, 0x97, 0x82, 0xe2, 0x8f, 0xdf, 0x2d, 0x5e, 0x87, 0x69, 0xc4, 0x52 }; _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL; @@ -787,16 +784,4 @@ static void test_dnssec_nsec3_hash(void) { assert_se(strcasecmp(b, "PJ8S08RR45VIQDAQGE7EN3VHKNROTBMM") == 0); } -int main(int argc, char *argv[]) { - test_dnssec_verify_dns_key(); - test_dnssec_verify_rfc8080_ed25519_example1(); - test_dnssec_verify_rfc8080_ed25519_example2(); - test_dnssec_verify_rfc6605_example1(); - test_dnssec_verify_rfc6605_example2(); - test_dnssec_verify_rrset(); - test_dnssec_verify_rrset2(); - test_dnssec_verify_rrset3(); - test_dnssec_nsec3_hash(); - - return 0; -} +DEFINE_TEST_MAIN(LOG_INFO); diff --git a/src/resolve/test-resolved-etc-hosts.c b/src/resolve/test-resolved-etc-hosts.c index cc55a980ad..e5a20a2b14 100644 --- a/src/resolve/test-resolved-etc-hosts.c +++ b/src/resolve/test-resolved-etc-hosts.c @@ -14,11 +14,9 @@ #include "tests.h" #include "tmpfile-util.h" -static void test_parse_etc_hosts_system(void) { +TEST(parse_etc_hosts_system) { _cleanup_fclose_ FILE *f = NULL; - log_info("/* %s */", __func__); - f = fopen("/etc/hosts", "re"); if (!f) { assert_se(errno == ENOENT); @@ -37,12 +35,10 @@ static void test_parse_etc_hosts_system(void) { ((_addr)->family == AF_INET6 && \ !memcmp(&(_addr)->address.in6, &(struct in6_addr) { .s6_addr = __VA_ARGS__}, 16) ) -static void test_parse_etc_hosts(void) { +TEST(parse_etc_hosts) { _cleanup_(unlink_tempfilep) char t[] = "/tmp/test-resolved-etc-hosts.XXXXXX"; - log_info("/* %s */", __func__); - int fd; _cleanup_fclose_ FILE *f; const char *s; @@ -128,7 +124,7 @@ static void test_parse_etc_hosts(void) { assert_se(!set_contains(hosts.no_address, "foobar.foo.foo")); } -static void test_parse_file(const char *fname) { +static void test_parse_file_one(const char *fname) { _cleanup_(etc_hosts_free) EtcHosts hosts = {}; _cleanup_fclose_ FILE *f; @@ -138,14 +134,9 @@ static void test_parse_file(const char *fname) { assert_se(etc_hosts_parse(&hosts, f) == 0); } -int main(int argc, char **argv) { - test_setup_logging(LOG_DEBUG); - - if (argc == 1) { - test_parse_etc_hosts_system(); - test_parse_etc_hosts(); - } else - test_parse_file(argv[1]); - - return 0; +TEST(parse_file) { + for (int i = 1; i < saved_argc; i++) + test_parse_file_one(saved_argv[i]); } + +DEFINE_TEST_MAIN(LOG_DEBUG); diff --git a/src/resolve/test-resolved-packet.c b/src/resolve/test-resolved-packet.c index cd93b1c23d..dd8c969b14 100644 --- a/src/resolve/test-resolved-packet.c +++ b/src/resolve/test-resolved-packet.c @@ -4,7 +4,7 @@ #include "resolved-dns-packet.h" #include "tests.h" -static void test_dns_packet_new(void) { +TEST(dns_packet_new) { size_t i; _cleanup_(dns_packet_unrefp) DnsPacket *p2 = NULL; @@ -23,10 +23,4 @@ static void test_dns_packet_new(void) { assert_se(dns_packet_new(&p2, DNS_PROTOCOL_DNS, DNS_PACKET_SIZE_MAX + 1, DNS_PACKET_SIZE_MAX) == -EFBIG); } -int main(int argc, char **argv) { - test_setup_logging(LOG_DEBUG); - - test_dns_packet_new(); - - return 0; -} +DEFINE_TEST_MAIN(LOG_DEBUG); diff --git a/src/shared/creds-util.c b/src/shared/creds-util.c index 4d0681bc10..c4dcc396ac 100644 --- a/src/shared/creds-util.c +++ b/src/shared/creds-util.c @@ -534,6 +534,7 @@ int encrypt_credential_and_warn( r = tpm2_seal(tpm2_device, tpm2_pcr_mask, + NULL, &tpm2_key, &tpm2_key_size, &tpm2_blob, @@ -803,6 +804,7 @@ int decrypt_credential_and_warn( le32toh(t->blob_size), t->policy_hash_and_blob + le32toh(t->blob_size), le32toh(t->policy_hash_size), + NULL, &tpm2_key, &tpm2_key_size); if (r < 0) diff --git a/src/shared/tpm2-util.c b/src/shared/tpm2-util.c index 70a2929432..44fe899acd 100644 --- a/src/shared/tpm2-util.c +++ b/src/shared/tpm2-util.c @@ -14,6 +14,7 @@ #include "hexdecoct.h" #include "memory-util.h" #include "random-util.h" +#include "sha256.h" #include "time-util.h" static void *libtss2_esys_dl = NULL; @@ -30,10 +31,12 @@ TSS2_RC (*sym_Esys_GetRandom)(ESYS_CONTEXT *esysContext, ESYS_TR shandle1, ESYS_ TSS2_RC (*sym_Esys_Initialize)(ESYS_CONTEXT **esys_context, TSS2_TCTI_CONTEXT *tcti, TSS2_ABI_VERSION *abiVersion) = NULL; TSS2_RC (*sym_Esys_Load)(ESYS_CONTEXT *esysContext, ESYS_TR parentHandle, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3, const TPM2B_PRIVATE *inPrivate, const TPM2B_PUBLIC *inPublic, ESYS_TR *objectHandle) = NULL; TSS2_RC (*sym_Esys_PCR_Read)(ESYS_CONTEXT *esysContext, ESYS_TR shandle1,ESYS_TR shandle2, ESYS_TR shandle3, const TPML_PCR_SELECTION *pcrSelectionIn, UINT32 *pcrUpdateCounter, TPML_PCR_SELECTION **pcrSelectionOut, TPML_DIGEST **pcrValues); +TSS2_RC (*sym_Esys_PolicyAuthValue)(ESYS_CONTEXT *esysContext, ESYS_TR policySession, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3) = NULL; TSS2_RC (*sym_Esys_PolicyGetDigest)(ESYS_CONTEXT *esysContext, ESYS_TR policySession, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3, TPM2B_DIGEST **policyDigest) = NULL; TSS2_RC (*sym_Esys_PolicyPCR)(ESYS_CONTEXT *esysContext, ESYS_TR policySession, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3, const TPM2B_DIGEST *pcrDigest, const TPML_PCR_SELECTION *pcrs) = NULL; TSS2_RC (*sym_Esys_StartAuthSession)(ESYS_CONTEXT *esysContext, ESYS_TR tpmKey, ESYS_TR bind, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3, const TPM2B_NONCE *nonceCaller, TPM2_SE sessionType, const TPMT_SYM_DEF *symmetric, TPMI_ALG_HASH authHash, ESYS_TR *sessionHandle) = NULL; TSS2_RC (*sym_Esys_Startup)(ESYS_CONTEXT *esysContext, TPM2_SU startupType) = NULL; +TSS2_RC (*sym_Esys_TR_SetAuth)(ESYS_CONTEXT *esysContext, ESYS_TR handle, TPM2B_AUTH const *authValue) = NULL; TSS2_RC (*sym_Esys_Unseal)(ESYS_CONTEXT *esysContext, ESYS_TR itemHandle, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3, TPM2B_SENSITIVE_DATA **outData) = NULL; const char* (*sym_Tss2_RC_Decode)(TSS2_RC rc) = NULL; @@ -58,10 +61,12 @@ int dlopen_tpm2(void) { DLSYM_ARG(Esys_Initialize), DLSYM_ARG(Esys_Load), DLSYM_ARG(Esys_PCR_Read), + DLSYM_ARG(Esys_PolicyAuthValue), DLSYM_ARG(Esys_PolicyGetDigest), DLSYM_ARG(Esys_PolicyPCR), DLSYM_ARG(Esys_StartAuthSession), DLSYM_ARG(Esys_Startup), + DLSYM_ARG(Esys_TR_SetAuth), DLSYM_ARG(Esys_Unseal)); if (r < 0) return r; @@ -594,6 +599,7 @@ static int tpm2_make_pcr_session( ESYS_CONTEXT *c, uint32_t pcr_mask, uint16_t pcr_bank, /* If UINT16_MAX, pick best bank automatically, otherwise specify bank explicitly. */ + bool use_pin, ESYS_TR *ret_session, TPM2B_DIGEST **ret_policy_digest, TPMI_ALG_HASH *ret_pcr_bank) { @@ -669,6 +675,21 @@ static int tpm2_make_pcr_session( goto finish; } + if (use_pin) { + rc = sym_Esys_PolicyAuthValue( + c, + session, + ESYS_TR_NONE, + ESYS_TR_NONE, + ESYS_TR_NONE); + if (rc != TSS2_RC_SUCCESS) { + r = log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), + "Failed to add authValue policy to TPM: %s", + sym_Tss2_RC_Decode(rc)); + goto finish; + } + } + if (DEBUG_LOGGING || ret_policy_digest) { log_debug("Acquiring policy digest."); @@ -717,9 +738,22 @@ finish: return r; } +static void hash_pin(const char *pin, size_t len, uint8_t ret_digest[static SHA256_DIGEST_SIZE]) { + struct sha256_ctx hash; + + assert(pin); + + sha256_init_ctx(&hash); + sha256_process_bytes(pin, len, &hash); + sha256_finish_ctx(&hash, ret_digest); + + explicit_bzero_safe(&hash, sizeof(hash)); +} + int tpm2_seal( const char *device, uint32_t pcr_mask, + const char *pin, void **ret_secret, size_t *ret_secret_size, void **ret_blob, @@ -782,7 +816,8 @@ int tpm2_seal( if (r < 0) return r; - r = tpm2_make_pcr_session(c.esys_context, pcr_mask, UINT16_MAX, NULL, &policy_digest, &pcr_bank); + r = tpm2_make_pcr_session(c.esys_context, pcr_mask, UINT16_MAX, !!pin, NULL, &policy_digest, + &pcr_bank); if (r < 0) goto finish; @@ -813,6 +848,10 @@ int tpm2_seal( .size = sizeof(hmac_sensitive.sensitive), .sensitive.data.size = 32, }; + if (pin) { + hash_pin(pin, strlen(pin), hmac_sensitive.sensitive.userAuth.buffer); + hmac_sensitive.sensitive.userAuth.size = SHA256_DIGEST_SIZE; + } assert(sizeof(hmac_sensitive.sensitive.data.buffer) >= hmac_sensitive.sensitive.data.size); (void) tpm2_credit_random(c.esys_context); @@ -910,6 +949,7 @@ int tpm2_seal( r = 0; finish: + explicit_bzero_safe(&hmac_sensitive, sizeof(hmac_sensitive)); primary = flush_context_verbose(c.esys_context, primary); return r; } @@ -923,6 +963,7 @@ int tpm2_unseal( size_t blob_size, const void *known_policy_hash, size_t known_policy_hash_size, + const char *pin, void **ret_secret, size_t *ret_secret_size) { @@ -978,7 +1019,7 @@ int tpm2_unseal( if (r < 0) return r; - r = tpm2_make_pcr_session(c.esys_context, pcr_mask, pcr_bank, &session, &policy_digest, NULL); + r = tpm2_make_pcr_session(c.esys_context, pcr_mask, pcr_bank, !!pin, &session, &policy_digest, NULL); if (r < 0) goto finish; @@ -1005,11 +1046,38 @@ int tpm2_unseal( &public, &hmac_key); if (rc != TSS2_RC_SUCCESS) { - r = log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), - "Failed to load HMAC key in TPM: %s", sym_Tss2_RC_Decode(rc)); + /* If we're in dictionary attack lockout mode, we should see a lockout error here, which we + * need to translate for the caller. */ + if (rc == TPM2_RC_LOCKOUT) + r = log_error_errno( + SYNTHETIC_ERRNO(ENOLCK), + "TPM2 device is in dictionary attack lockout mode."); + else + r = log_error_errno( + SYNTHETIC_ERRNO(ENOTRECOVERABLE), + "Failed to load HMAC key in TPM: %s", + sym_Tss2_RC_Decode(rc)); goto finish; } + if (pin) { + TPM2B_AUTH auth = { + .size = SHA256_DIGEST_SIZE + }; + + hash_pin(pin, strlen(pin), auth.buffer); + + rc = sym_Esys_TR_SetAuth(c.esys_context, hmac_key, &auth); + explicit_bzero_safe(&auth, sizeof(auth)); + if (rc != TSS2_RC_SUCCESS) { + r = log_error_errno( + SYNTHETIC_ERRNO(ENOTRECOVERABLE), + "Failed to load PIN in TPM: %s", + sym_Tss2_RC_Decode(rc)); + goto finish; + } + } + log_debug("Unsealing HMAC key."); rc = sym_Esys_Unseal( @@ -1223,6 +1291,7 @@ int tpm2_make_luks2_json( size_t blob_size, const void *policy_hash, size_t policy_hash_size, + TPM2Flags flags, JsonVariant **ret) { _cleanup_(json_variant_unrefp) JsonVariant *v = NULL, *a = NULL; @@ -1263,7 +1332,9 @@ int tpm2_make_luks2_json( JSON_BUILD_PAIR("tpm2-pcrs", JSON_BUILD_VARIANT(a)), JSON_BUILD_PAIR_CONDITION(!!tpm2_pcr_bank_to_string(pcr_bank), "tpm2-pcr-bank", JSON_BUILD_STRING(tpm2_pcr_bank_to_string(pcr_bank))), JSON_BUILD_PAIR_CONDITION(!!tpm2_primary_alg_to_string(primary_alg), "tpm2-primary-alg", JSON_BUILD_STRING(tpm2_primary_alg_to_string(primary_alg))), - JSON_BUILD_PAIR("tpm2-policy-hash", JSON_BUILD_HEX(policy_hash, policy_hash_size)))); + JSON_BUILD_PAIR("tpm2-policy-hash", JSON_BUILD_HEX(policy_hash, policy_hash_size)), + JSON_BUILD_PAIR("tpm2-pin", JSON_BUILD_BOOLEAN(flags & TPM2_FLAGS_USE_PIN))) + ); if (r < 0) return r; diff --git a/src/shared/tpm2-util.h b/src/shared/tpm2-util.h index cb57a847e2..5a9bcf8c24 100644 --- a/src/shared/tpm2-util.h +++ b/src/shared/tpm2-util.h @@ -1,9 +1,15 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once +#include <stdbool.h> + #include "json.h" #include "macro.h" +typedef enum TPM2Flags { + TPM2_FLAGS_USE_PIN = 1 << 0, +} TPM2Flags; + #if HAVE_TPM2 #include <tss2/tss2_esys.h> @@ -20,10 +26,12 @@ extern TSS2_RC (*sym_Esys_GetRandom)(ESYS_CONTEXT *esysContext, ESYS_TR shandle1 extern TSS2_RC (*sym_Esys_Initialize)(ESYS_CONTEXT **esys_context, TSS2_TCTI_CONTEXT *tcti, TSS2_ABI_VERSION *abiVersion); extern TSS2_RC (*sym_Esys_Load)(ESYS_CONTEXT *esysContext, ESYS_TR parentHandle, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3, const TPM2B_PRIVATE *inPrivate, const TPM2B_PUBLIC *inPublic, ESYS_TR *objectHandle); extern TSS2_RC (*sym_Esys_PCR_Read)(ESYS_CONTEXT *esysContext, ESYS_TR shandle1,ESYS_TR shandle2, ESYS_TR shandle3, const TPML_PCR_SELECTION *pcrSelectionIn, UINT32 *pcrUpdateCounter, TPML_PCR_SELECTION **pcrSelectionOut, TPML_DIGEST **pcrValues); +extern TSS2_RC (*sym_Esys_PolicyAuthValue)(ESYS_CONTEXT *esysContext, ESYS_TR policySession, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3); extern TSS2_RC (*sym_Esys_PolicyGetDigest)(ESYS_CONTEXT *esysContext, ESYS_TR policySession, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3, TPM2B_DIGEST **policyDigest); extern TSS2_RC (*sym_Esys_PolicyPCR)(ESYS_CONTEXT *esysContext, ESYS_TR policySession, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3, const TPM2B_DIGEST *pcrDigest, const TPML_PCR_SELECTION *pcrs); extern TSS2_RC (*sym_Esys_StartAuthSession)(ESYS_CONTEXT *esysContext, ESYS_TR tpmKey, ESYS_TR bind, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3, const TPM2B_NONCE *nonceCaller, TPM2_SE sessionType, const TPMT_SYM_DEF *symmetric, TPMI_ALG_HASH authHash, ESYS_TR *sessionHandle); extern TSS2_RC (*sym_Esys_Startup)(ESYS_CONTEXT *esysContext, TPM2_SU startupType); +extern TSS2_RC (*sym_Esys_TR_SetAuth)(ESYS_CONTEXT *esysContext, ESYS_TR handle, TPM2B_AUTH const *authValue); extern TSS2_RC (*sym_Esys_Unseal)(ESYS_CONTEXT *esysContext, ESYS_TR itemHandle, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3, TPM2B_SENSITIVE_DATA **outData); extern const char* (*sym_Tss2_RC_Decode)(TSS2_RC rc); @@ -35,8 +43,8 @@ extern TSS2_RC (*sym_Tss2_MU_TPM2B_PUBLIC_Unmarshal)(uint8_t const buffer[], siz int dlopen_tpm2(void); -int tpm2_seal(const char *device, uint32_t pcr_mask, void **ret_secret, size_t *ret_secret_size, void **ret_blob, size_t *ret_blob_size, void **ret_pcr_hash, size_t *ret_pcr_hash_size, uint16_t *ret_pcr_bank, uint16_t *ret_primary_alg); -int tpm2_unseal(const char *device, uint32_t pcr_mask, uint16_t pcr_bank, uint16_t primary_alg, const void *blob, size_t blob_size, const void *pcr_hash, size_t pcr_hash_size, void **ret_secret, size_t *ret_secret_size); +int tpm2_seal(const char *device, uint32_t pcr_mask, const char *pin, void **ret_secret, size_t *ret_secret_size, void **ret_blob, size_t *ret_blob_size, void **ret_pcr_hash, size_t *ret_pcr_hash_size, uint16_t *ret_pcr_bank, uint16_t *ret_primary_alg); +int tpm2_unseal(const char *device, uint32_t pcr_mask, uint16_t pcr_bank, uint16_t primary_alg, const void *blob, size_t blob_size, const void *pcr_hash, size_t pcr_hash_size, const char *pin, void **ret_secret, size_t *ret_secret_size); #endif @@ -45,7 +53,7 @@ int tpm2_find_device_auto(int log_level, char **ret); int tpm2_parse_pcrs(const char *s, uint32_t *ret); -int tpm2_make_luks2_json(int keyslot, uint32_t pcr_mask, uint16_t pcr_bank, uint16_t primary_alg, const void *blob, size_t blob_size, const void *policy_hash, size_t policy_hash_size, JsonVariant **ret); +int tpm2_make_luks2_json(int keyslot, uint32_t pcr_mask, uint16_t pcr_bank, uint16_t primary_alg, const void *blob, size_t blob_size, const void *policy_hash, size_t policy_hash_size, TPM2Flags flags, JsonVariant **ret); #define TPM2_PCRS_MAX 24 diff --git a/src/shutdown/test-umount.c b/src/shutdown/test-umount.c index 676c6dd862..56fcff05b1 100644 --- a/src/shutdown/test-umount.c +++ b/src/shutdown/test-umount.c @@ -9,7 +9,7 @@ #include "umount.h" #include "util.h" -static void test_mount_points_list(const char *fname) { +static void test_mount_points_list_one(const char *fname) { _cleanup_(mount_points_list_free) LIST_HEAD(MountPoint, mp_list_head); _cleanup_free_ char *testdata_fname = NULL; MountPoint *m; @@ -33,7 +33,14 @@ static void test_mount_points_list(const char *fname) { major(m->devnum), minor(m->devnum)); } -static void test_swap_list(const char *fname) { +TEST(mount_points_list) { + test_mount_points_list_one(NULL); + test_mount_points_list_one("/test-umount/empty.mountinfo"); + test_mount_points_list_one("/test-umount/garbled.mountinfo"); + test_mount_points_list_one("/test-umount/rhbug-1554943.mountinfo"); +} + +static void test_swap_list_one(const char *fname) { _cleanup_(mount_points_list_free) LIST_HEAD(MountPoint, mp_list_head); _cleanup_free_ char *testdata_fname = NULL; MountPoint *m; @@ -61,14 +68,9 @@ static void test_swap_list(const char *fname) { major(m->devnum), minor(m->devnum)); } -int main(int argc, char **argv) { - test_setup_logging(LOG_DEBUG); - - test_mount_points_list(NULL); - test_mount_points_list("/test-umount/empty.mountinfo"); - test_mount_points_list("/test-umount/garbled.mountinfo"); - test_mount_points_list("/test-umount/rhbug-1554943.mountinfo"); - - test_swap_list(NULL); - test_swap_list("/test-umount/example.swaps"); +TEST(swap_list) { + test_swap_list_one(NULL); + test_swap_list_one("/test-umount/example.swaps"); } + +DEFINE_TEST_MAIN(LOG_DEBUG); diff --git a/src/timesync/test-timesync.c b/src/timesync/test-timesync.c index 31e91e7b7b..7993e4c12b 100644 --- a/src/timesync/test-timesync.c +++ b/src/timesync/test-timesync.c @@ -7,7 +7,7 @@ #include "timesyncd-conf.h" #include "tests.h" -static void test_manager_parse_string(void) { +TEST(manager_parse_string) { /* Make sure that NTP_SERVERS is configured to something * that we can actually parse successfully. */ @@ -25,10 +25,4 @@ static void test_manager_parse_string(void) { assert_se(manager_parse_server_string(m, SERVER_LINK, "time1.foobar.com time2.foobar.com axrfav.,avf..ra 12345..123") == 0); } -int main(int argc, char **argv) { - test_setup_logging(LOG_DEBUG); - - test_manager_parse_string(); - - return 0; -} +DEFINE_TEST_MAIN(LOG_DEBUG); diff --git a/src/udev/fido_id/test-fido-id-desc.c b/src/udev/fido_id/test-fido-id-desc.c index 6836bca28d..36c777a09e 100644 --- a/src/udev/fido_id/test-fido-id-desc.c +++ b/src/udev/fido_id/test-fido-id-desc.c @@ -5,8 +5,9 @@ #include "fido_id_desc.h" #include "macro.h" +#include "tests.h" -static void test_is_fido_security_token_desc__fido(void) { +TEST(is_fido_security_token_desc__fido) { static const uint8_t FIDO_HID_DESC_1[] = { 0x06, 0xd0, 0xf1, 0x09, 0x01, 0xa1, 0x01, 0x09, 0x20, 0x15, 0x00, 0x26, 0xff, 0x00, 0x75, 0x08, 0x95, 0x40, 0x81, 0x02, 0x09, 0x21, 0x15, 0x00, 0x26, 0xff, 0x00, 0x75, 0x08, 0x95, @@ -27,7 +28,7 @@ static void test_is_fido_security_token_desc__fido(void) { assert_se(is_fido_security_token_desc(FIDO_HID_DESC_2, sizeof(FIDO_HID_DESC_2)) > 0); } -static void test_is_fido_security_token_desc__non_fido(void) { +TEST(is_fido_security_token_desc__non_fido) { /* Wrong usage page */ static const uint8_t NON_FIDO_HID_DESC_1[] = { 0x06, 0xd0, 0xf0, 0x09, 0x01, 0xa1, 0x01, 0x09, 0x20, 0x15, 0x00, 0x26, 0xff, 0x00, 0x75, @@ -54,7 +55,7 @@ static void test_is_fido_security_token_desc__non_fido(void) { assert_se(is_fido_security_token_desc(NON_FIDO_HID_DESC_3, sizeof(NON_FIDO_HID_DESC_3)) == 0); } -static void test_is_fido_security_token_desc__invalid(void) { +TEST(is_fido_security_token_desc__invalid) { /* Size coded on 1 byte, but no byte given */ static const uint8_t INVALID_HID_DESC_1[] = { 0x01 }; assert_se(is_fido_security_token_desc(INVALID_HID_DESC_1, sizeof(INVALID_HID_DESC_1)) < 0); @@ -76,10 +77,4 @@ static void test_is_fido_security_token_desc__invalid(void) { assert_se(is_fido_security_token_desc(INVALID_HID_DESC_5, sizeof(INVALID_HID_DESC_5)) < 0); } -int main(int argc, char *argv[]) { - test_is_fido_security_token_desc__fido(); - test_is_fido_security_token_desc__non_fido(); - test_is_fido_security_token_desc__invalid(); - - return EXIT_SUCCESS; -} +DEFINE_TEST_MAIN(LOG_INFO); diff --git a/src/udev/test-udev-builtin.c b/src/udev/test-udev-builtin.c index 21a8ea3fa6..2ce7f196fd 100644 --- a/src/udev/test-udev-builtin.c +++ b/src/udev/test-udev-builtin.c @@ -3,9 +3,7 @@ #include "tests.h" #include "udev-builtin.h" -static void test_udev_builtin_cmd_to_ptr(void) { - log_info("/* %s */", __func__); - +TEST(udev_builtin_cmd_to_ptr) { /* Those could have been static asserts, but ({}) is not allowed there. */ #if HAVE_BLKID assert_se(UDEV_BUILTIN_CMD_TO_PTR(UDEV_BUILTIN_BLKID)); @@ -19,8 +17,4 @@ static void test_udev_builtin_cmd_to_ptr(void) { assert_se(PTR_TO_UDEV_BUILTIN_CMD((void*) 10000) == _UDEV_BUILTIN_INVALID); } -int main(int argc, char *argv[]) { - test_setup_logging(LOG_DEBUG); - - test_udev_builtin_cmd_to_ptr(); -} +DEFINE_TEST_MAIN(LOG_DEBUG); diff --git a/src/udev/test-udev-netlink.c b/src/udev/test-udev-netlink.c index c1213b7ca8..1fddb5efb1 100644 --- a/src/udev/test-udev-netlink.c +++ b/src/udev/test-udev-netlink.c @@ -132,12 +132,10 @@ static void test_link_info_one(sd_netlink *rtnl, int ifindex) { } } -static void test_link_info_get(void) { +TEST(link_info_get) { _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL; - log_debug("/* %s */", __func__); - assert_se(sd_netlink_open(&rtnl) >= 0); assert_se(sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0) >= 0); @@ -156,10 +154,4 @@ static void test_link_info_get(void) { } } -int main(int argc, char *argv[]) { - test_setup_logging(LOG_DEBUG); - - test_link_info_get(); - - return 0; -} +DEFINE_TEST_MAIN(LOG_DEBUG); diff --git a/src/udev/test-udev-node.c b/src/udev/test-udev-node.c index 010c19acf5..b5eaa0de58 100644 --- a/src/udev/test-udev-node.c +++ b/src/udev/test-udev-node.c @@ -13,7 +13,7 @@ static void test_udev_node_escape_path_one(const char *path, const char *expecte assert_se(streq(buf, expected)); } -static void test_udev_node_escape_path(void) { +TEST(udev_node_escape_path) { char a[NAME_MAX+1], b[NAME_MAX+1]; test_udev_node_escape_path_one("/disk/by-id/nvme-eui.1922908022470001001b448b44ccb9d6", "\\x2fdisk\\x2fby-id\\x2fnvme-eui.1922908022470001001b448b44ccb9d6"); @@ -47,10 +47,4 @@ static void test_udev_node_escape_path(void) { test_udev_node_escape_path_one(a, b); } -int main(int argc, char *argv[]) { - test_setup_logging(LOG_INFO); - - test_udev_node_escape_path(); - - return 0; -} +DEFINE_TEST_MAIN(LOG_INFO); diff --git a/src/xdg-autostart-generator/test-xdg-autostart.c b/src/xdg-autostart-generator/test-xdg-autostart.c index c7a816bc25..841a5606f6 100644 --- a/src/xdg-autostart-generator/test-xdg-autostart.c +++ b/src/xdg-autostart-generator/test-xdg-autostart.c @@ -9,7 +9,7 @@ #include "tmpfile-util.h" #include "xdg-autostart-service.h" -static void test_translate_name(void) { +TEST(translate_name) { _cleanup_free_ char *t; assert_se(t = xdg_autostart_service_translate_name("a-b.blub.desktop")); @@ -24,7 +24,7 @@ static void test_xdg_format_exec_start_one(const char *exec, const char *expecte assert_se(streq(out, expected)); } -static void test_xdg_format_exec_start(void) { +TEST(xdg_format_exec_start) { test_xdg_format_exec_start_one("/bin/sleep 100", "/bin/sleep \"100\""); /* All standardised % identifiers are stripped. */ @@ -50,7 +50,7 @@ static const char* const xdg_desktop_file[] = { "Hidden=\t true\n"), }; -static void test_xdg_desktop_parse(unsigned i, const char *s) { +static void test_xdg_desktop_parse_one(unsigned i, const char *s) { _cleanup_(unlink_tempfilep) char name[] = "/tmp/test-xdg-autostart-parser.XXXXXX"; _cleanup_fclose_ FILE *f = NULL; _cleanup_(xdg_autostart_service_freep) XdgAutostartService *service = NULL; @@ -80,14 +80,9 @@ static void test_xdg_desktop_parse(unsigned i, const char *s) { } } -int main(int argc, char *argv[]) { - test_setup_logging(LOG_DEBUG); - - test_translate_name(); - test_xdg_format_exec_start(); - +TEST(xdg_desktop_parse) { for (size_t i = 0; i < ELEMENTSOF(xdg_desktop_file); i++) - test_xdg_desktop_parse(i, xdg_desktop_file[i]); - - return 0; + test_xdg_desktop_parse_one(i, xdg_desktop_file[i]); } + +DEFINE_TEST_MAIN(LOG_DEBUG); diff --git a/test/TEST-70-TPM2/Makefile b/test/TEST-70-TPM2/Makefile new file mode 100644 index 0000000000..9f65d4ca4f --- /dev/null +++ b/test/TEST-70-TPM2/Makefile @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later + +all setup run clean clean-again: + @TEST_BASE_DIR=../ ./test.sh --$@ + +.PHONY: all setup run clean clean-again diff --git a/test/TEST-70-TPM2/test.sh b/test/TEST-70-TPM2/test.sh new file mode 100755 index 0000000000..d716614bcf --- /dev/null +++ b/test/TEST-70-TPM2/test.sh @@ -0,0 +1,40 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: LGPL-2.1-or-later +set -e + +TEST_DESCRIPTION="cryptenroll/cryptsetup with TPM2 devices" +IMAGE_NAME="tpm2" +TEST_NO_NSPAWN=1 +TEST_REQUIRE_INSTALL_TESTS=0 + +# shellcheck source=test/test-functions +. "${TEST_BASE_DIR:?}/test-functions" + +command -v swtpm >/dev/null 2>&1 || exit 0 +command -v tpm2_pcrextend >/dev/null 2>&1 || exit 0 + +test_append_files() { + ( + local workspace="${1:?}" + + instmods tpm tpm_tis tpm_ibmvtpm + install_dmevent + generate_module_dependencies + inst_binary tpm2_pcrextend + ) +} + +machine="$(uname -m)" +tpmdevice="tpm-tis" +if [ "$machine" = "ppc64le" ]; then + # tpm-spapr support was introduced in qemu 5.0.0. Skip test for old qemu versions. + qemu_min_version "5.0.0" || exit 0 + tpmdevice="tpm-spapr" +fi + +tpmstate=$(mktemp -d) +swtpm socket --tpm2 --tpmstate dir="$tpmstate" --ctrl type=unixio,path="$tpmstate/sock" & +trap 'kill %%; rm -rf $tpmstate' SIGINT EXIT +QEMU_OPTIONS="-chardev socket,id=chrtpm,path=$tpmstate/sock -tpmdev emulator,id=tpm0,chardev=chrtpm -device $tpmdevice,tpmdev=tpm0" + +do_test "$@" diff --git a/test/test-functions b/test/test-functions index e815ce1c58..6619a7a44b 100644 --- a/test/test-functions +++ b/test/test-functions @@ -1213,7 +1213,7 @@ install_missing_libraries() { local lib path # A number of dependencies is now optional via dlopen, so the install # script will not pick them up, since it looks at linkage. - for lib in libcryptsetup libidn libidn2 pwquality libqrencode tss2-esys tss2-rc tss2-mu libfido2 libbpf libelf libdw; do + for lib in libcryptsetup libidn libidn2 pwquality libqrencode tss2-esys tss2-rc tss2-mu tss2-tcti-device libfido2 libbpf libelf libdw; do ddebug "Searching for $lib via pkg-config" if pkg-config --exists "$lib"; then path="$(pkg-config --variable=libdir "$lib")" diff --git a/test/units/testsuite-70.service b/test/units/testsuite-70.service new file mode 100644 index 0000000000..c13c2d51a3 --- /dev/null +++ b/test/units/testsuite-70.service @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +[Unit] +Description=TEST-70-TPM2 + +[Service] +Type=oneshot +ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh diff --git a/test/units/testsuite-70.sh b/test/units/testsuite-70.sh new file mode 100755 index 0000000000..f395ef4e5e --- /dev/null +++ b/test/units/testsuite-70.sh @@ -0,0 +1,48 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: LGPL-2.1-or-later +set -ex + +export SYSTEMD_LOG_LEVEL=debug + + +# Prepare fresh disk image +img="/var/tmp/test.img" +dd if=/dev/zero of=$img bs=1024k count=20 status=none +echo -n passphrase >/tmp/passphrase +cryptsetup luksFormat -q --use-urandom $img /tmp/passphrase + +# Enroll unlock with default PCR policy +env PASSWORD=passphrase systemd-cryptenroll --tpm2-device=auto $img +/usr/lib/systemd/systemd-cryptsetup attach test-volume $img - tpm2-device=auto,headless=1 +/usr/lib/systemd/systemd-cryptsetup detach test-volume + +# Check with wrong PCR +tpm2_pcrextend 7:sha256=0000000000000000000000000000000000000000000000000000000000000000 +/usr/lib/systemd/systemd-cryptsetup attach test-volume $img - tpm2-device=auto,headless=1 && { echo 'unexpected success'; exit 1; } + +# Enroll unlock with PCR+PIN policy +systemd-cryptenroll --wipe-slot=tpm2 $img +env PASSWORD=passphrase NEWPIN=123456 systemd-cryptenroll --tpm2-device=auto --tpm2-with-pin=true $img +env PIN=123456 /usr/lib/systemd/systemd-cryptsetup attach test-volume $img - tpm2-device=auto,headless=1 +/usr/lib/systemd/systemd-cryptsetup detach test-volume + +# Check failure with wrong PIN +env PIN=123457 /usr/lib/systemd/systemd-cryptsetup attach test-volume $img - tpm2-device=auto,headless=1 && { echo 'unexpected success'; exit 1; } + +# Check failure with wrong PCR (and correct PIN) +tpm2_pcrextend 7:sha256=0000000000000000000000000000000000000000000000000000000000000000 +env PIN=123456 /usr/lib/systemd/systemd-cryptsetup attach test-volume $img - tpm2-device=auto,headless=1 && { echo 'unexpected success'; exit 1; } + +# Enroll unlock with PCR 0+7 +systemd-cryptenroll --wipe-slot=tpm2 $img +env PASSWORD=passphrase systemd-cryptenroll --tpm2-device=auto --tpm2-pcrs=0+7 $img +/usr/lib/systemd/systemd-cryptsetup attach test-volume $img - tpm2-device=auto,headless=1 +/usr/lib/systemd/systemd-cryptsetup detach test-volume + +# Check with wrong PCR 0 +tpm2_pcrextend 0:sha256=0000000000000000000000000000000000000000000000000000000000000000 +/usr/lib/systemd/systemd-cryptsetup attach test-volume $img - tpm2-device=auto,headless=1 && exit 1 + +echo OK >/testok + +exit 0 |