From 58eb783654920f1fc85de32bcd6357f16053c705 Mon Sep 17 00:00:00 2001 From: Scott Stephens Date: Fri, 13 Feb 2026 22:04:55 -0500 Subject: [PATCH 1/3] nixos/tpm2: move tpm2 tests to own directory --- nixos/tests/all-tests.nix | 2 +- nixos/tests/tpm2/default.nix | 4 ++++ nixos/tests/{tpm2.nix => tpm2/tpm2-abrmd.nix} | 4 ++++ 3 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 nixos/tests/tpm2/default.nix rename nixos/tests/{tpm2.nix => tpm2/tpm2-abrmd.nix} (94%) diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix index 0ad508dd87ec..9cf7fa3fe834 100644 --- a/nixos/tests/all-tests.nix +++ b/nixos/tests/all-tests.nix @@ -1633,7 +1633,7 @@ in tomcat = runTest ./tomcat.nix; tor = runTest ./tor.nix; tpm-ek = handleTest ./tpm-ek { }; - tpm2 = runTest ./tpm2.nix; + tpm2 = import ./tpm2 { inherit runTest; }; traccar = runTest ./traccar.nix; # tracee requires bpf tracee = handleTestOn [ "x86_64-linux" ] ./tracee.nix { }; diff --git a/nixos/tests/tpm2/default.nix b/nixos/tests/tpm2/default.nix new file mode 100644 index 000000000000..724afad301e3 --- /dev/null +++ b/nixos/tests/tpm2/default.nix @@ -0,0 +1,4 @@ +{ runTest }: +{ + abrmd = runTest ./tpm2-abrmd.nix; +} diff --git a/nixos/tests/tpm2.nix b/nixos/tests/tpm2/tpm2-abrmd.nix similarity index 94% rename from nixos/tests/tpm2.nix rename to nixos/tests/tpm2/tpm2-abrmd.nix index e38020f6e5ba..f0d28d932756 100644 --- a/nixos/tests/tpm2.nix +++ b/nixos/tests/tpm2/tpm2-abrmd.nix @@ -39,6 +39,10 @@ machine.start() machine.wait_for_unit("multi-user.target") + with subtest("/dev/tpmrm0 has correct ownership"): + machine.succeed('[ `stat -c "%U" /dev/tpmrm0` = "tss" ]') + machine.succeed('[ `stat -c "%G" /dev/tpmrm0` = "tss" ]') + with subtest("tabrmd service started properly"): machine.succeed('[ `systemctl show tpm2-abrmd.service --property=Result` = "Result=success" ]') machine.succeed('[ `journalctl -b -u tpm2-abrmd.service | grep -c "Starting"` = "1" ]') From b1fb31f3d22b53d284f616fd819b3317509d9b81 Mon Sep 17 00:00:00 2001 From: Scott Stephens Date: Fri, 13 Feb 2026 22:05:45 -0500 Subject: [PATCH 2/3] nixos/tpm2: add test for #489756 --- nixos/tests/tpm2/default.nix | 1 + nixos/tests/tpm2/tpm2-tpmrm.nix | 72 +++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+) create mode 100644 nixos/tests/tpm2/tpm2-tpmrm.nix diff --git a/nixos/tests/tpm2/default.nix b/nixos/tests/tpm2/default.nix index 724afad301e3..caa0697ec3e2 100644 --- a/nixos/tests/tpm2/default.nix +++ b/nixos/tests/tpm2/default.nix @@ -1,4 +1,5 @@ { runTest }: { abrmd = runTest ./tpm2-abrmd.nix; + tpmrm = runTest ./tpm2-tpmrm.nix; } diff --git a/nixos/tests/tpm2/tpm2-tpmrm.nix b/nixos/tests/tpm2/tpm2-tpmrm.nix new file mode 100644 index 000000000000..3f777c7c2ba3 --- /dev/null +++ b/nixos/tests/tpm2/tpm2-tpmrm.nix @@ -0,0 +1,72 @@ +{ lib, pkgs, ... }: +{ + name = "tpm2-tpmrm"; + + nodes.machine = + { config, pkgs, ... }: + { + virtualisation = { + mountHostNixStore = true; + useEFIBoot = true; + tpm.enable = true; + }; + + users.users = { + tss-user = { + isNormalUser = true; + extraGroups = [ "tss" ]; + }; + }; + + security.sudo.wheelNeedsPassword = false; + + security.tpm2 = { + enable = true; + pkcs11.enable = true; + tctiEnvironment.enable = true; + fapi.ekCertLess = true; + }; + + environment.systemPackages = [ + pkgs.tpm2-tools + pkgs.openssl + ]; + }; + + testScript = '' + machine.start() + machine.wait_for_unit("multi-user.target") + + with subtest("/dev/tpmrm0 has correct ownership"): + machine.succeed('[ `stat -c "%U" /dev/tpmrm0` = "root" ]') + machine.succeed('[ `stat -c "%G" /dev/tpmrm0` = "tss" ]') + + with subtest("tpm2 cli works"): + machine.succeed('tpm2 createprimary --hierarchy=o --key-algorithm=aes256 --attributes="fixedtpm|fixedparent|sensitivedataorigin|userwithauth|restricted|decrypt" --key-context=owner_root_key.ctx') + machine.succeed('tpm2 create --parent-context=owner_root_key.ctx --key-algorithm=ecc256:ecdsa-sha256:null --attributes="fixedtpm|fixedparent|sensitivedataorigin|userwithauth|restricted|sign" --key-context=ecc_sign_key.ctx --creation-ticket=ecc_sign_key-creation_ticket.bin -f pem --output=ecc_sign_key_public.pem') + machine.succeed('echo "A very important message." > message.txt') + machine.succeed('tpm2 sign --key-context=ecc_sign_key.ctx --hash-algorithm=sha256 -f plain --signature message_signature.bin message.txt') + machine.succeed('openssl dgst -verify ecc_sign_key_public.pem -signature message_signature.bin message.txt') + machine.succeed('echo "evil addition!" >> message.txt') + machine.fail('openssl dgst -verify ecc_sign_key_public.pem -signature message_signature.bin message.txt') + + def format_command(command, user): + return f"runuser -u {user} -- bash -c '{command}'" + def succeedu(command,user): + return machine.succeed(format_command(command,user)) + def failu(command,user): + return machine.fail(format_command(command,user)) + + with subtest("tss2 cli works"): + machine.succeed('tss2 provision') + succeedu('tss2 createkey --path=HS/SRK/sign --type=sign --authValue=""',"tss-user") + succeedu('tss2 gettpmblobs --path=HS/SRK/sign --tpm2bPublic=$HOME/sign_key_public.bin',"tss-user") + succeedu('tpm2 print -t TPM2B_PUBLIC -f pem $HOME/sign_key_public.bin > $HOME/sign_key_public.pem',"tss-user") + succeedu('echo "A very important message." > $HOME/message.txt',"tss-user") + succeedu('tpm2 hash --hash-algorithm=sha256 --output=$HOME/message_hash.bin $HOME/message.txt',"tss-user") + succeedu('tss2 sign --keyPath=HS/SRK/sign --digest=$HOME/message_hash.bin --signature=$HOME/message_signature.bin',"tss-user") + succeedu('openssl dgst -verify $HOME/sign_key_public.pem -signature $HOME/message_signature.bin $HOME/message.txt',"tss-user") + succeedu('echo "evil addition!" >> $HOME/message.txt',"tss-user") + failu('openssl dgst -verify $HOME/sign_key_public.pem -signature $HOME/message_signature.bin $HOME/message.txt',"tss-user") + ''; +} From c43291044e6a111ecfe159dc7da4085f44ddd160 Mon Sep 17 00:00:00 2001 From: Scott Stephens Date: Fri, 13 Feb 2026 22:21:57 -0500 Subject: [PATCH 3/3] nixos/tpm2: create tss user and group if either is required We only want to create users and groups in the module if they are the module defaults; if a user is specifying something else, we can presume that they are creating that themselves and don't want to conflict. The previous implementation caused problems when the module was configured to use the /dev/tpmrm0 kernel resource manager. In this configuration, /dev/tpmrm0 would be owned by root, but in the group tss, which caused there to be no tss user created. This in turn caused the tss group to be a "normal" group, not a system group, and udev does not assign devices to normal groups. Unfortunately, there is no isSystemGroup option corresponding to the isSystemUser option. To avoid messing with the user system, we add the tss user if we need the group. resolves #489756 --- nixos/modules/security/tpm2.nix | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nixos/modules/security/tpm2.nix b/nixos/modules/security/tpm2.nix index 44abf5a06410..cf1535e25ac3 100644 --- a/nixos/modules/security/tpm2.nix +++ b/nixos/modules/security/tpm2.nix @@ -276,11 +276,11 @@ in services.udev.extraRules = lib.mkIf cfg.applyUdevRules (udevRules cfg.tssUser cfg.tssGroup); # Create the tss user and group only if the default value is used - users.users.${cfg.tssUser} = lib.mkIf (cfg.tssUser == "tss") { + users.users.tss = lib.mkIf (cfg.tssUser == "tss" || cfg.tssGroup == "tss") { isSystemUser = true; group = "tss"; }; - users.groups.${cfg.tssGroup} = lib.mkIf (cfg.tssGroup == "tss") { }; + users.groups.tss = lib.mkIf (cfg.tssUser == "tss" || cfg.tssGroup == "tss") { }; environment.variables = lib.mkIf cfg.tctiEnvironment.enable ( lib.attrsets.genAttrs