{ lib, pkgs, config, ... }: let cfg = config.security.tpm2; # This snippet is taken from tpm2-tss/dist/tpm-udev.rules, but modified to allow custom user/groups # The idea is that the tssUser is allowed to access the TPM and kernel TPM resource manager, while # the tssGroup is only allowed to access the kernel resource manager # Therefore, if either of the two are null, the respective part isn't generated udevRules = tssUser: tssGroup: '' ${lib.optionalString (tssUser != null) ''KERNEL=="tpm[0-9]*", MODE="0660", OWNER="${tssUser}"''} ${ lib.optionalString (tssUser != null || tssGroup != null) ''KERNEL=="tpmrm[0-9]*", MODE="0660"'' + lib.optionalString (tssUser != null) '', OWNER="${tssUser}"'' + lib.optionalString (tssGroup != null) '', GROUP="${tssGroup}"'' } ''; in { options.security.tpm2 = { enable = lib.mkEnableOption "Trusted Platform Module 2 support"; tssUser = lib.mkOption { description = '' Name of the tpm device-owner and service user, set if applyUdevRules is set. ''; type = lib.types.nullOr lib.types.str; default = if cfg.abrmd.enable then "tss" else "root"; defaultText = lib.literalExpression ''if config.security.tpm2.abrmd.enable then "tss" else "root"''; }; tssGroup = lib.mkOption { description = '' Group of the tpm kernel resource manager (tpmrm) device-group, set if applyUdevRules is set. ''; type = lib.types.nullOr lib.types.str; default = "tss"; }; applyUdevRules = lib.mkOption { description = '' Whether to make the /dev/tpm[0-9] devices accessible by the tssUser, or the /dev/tpmrm[0-9] by tssGroup respectively ''; type = lib.types.bool; default = true; }; abrmd = { enable = lib.mkEnableOption '' Trusted Platform 2 userspace resource manager daemon ''; package = lib.mkOption { description = "tpm2-abrmd package to use"; type = lib.types.package; default = pkgs.tpm2-abrmd; defaultText = lib.literalExpression "pkgs.tpm2-abrmd"; }; }; pkcs11 = { enable = lib.mkEnableOption '' TPM2 PKCS#11 tool and shared library in system path (`/run/current-system/sw/lib/libtpm2_pkcs11.so`) ''; package = lib.mkOption { description = "tpm2-pkcs11 package to use"; type = lib.types.package; default = pkgs.tpm2-pkcs11; defaultText = lib.literalExpression "pkgs.tpm2-pkcs11"; }; }; tctiEnvironment = { enable = lib.mkOption { description = '' Set common TCTI environment variables to the specified value. The variables are - `TPM2TOOLS_TCTI` - `TPM2_PKCS11_TCTI` ''; type = lib.types.bool; default = false; }; interface = lib.mkOption { description = '' The name of the TPM command transmission interface (TCTI) library to use. ''; type = lib.types.enum [ "tabrmd" "device" ]; default = "device"; }; deviceConf = lib.mkOption { description = '' Configuration part of the device TCTI, e.g. the path to the TPM device. Applies if interface is set to "device". The format is specified in the [ tpm2-tools repository](https://github.com/tpm2-software/tpm2-tools/blob/master/man/common/tcti.md#tcti-options). ''; type = lib.types.str; default = "/dev/tpmrm0"; }; tabrmdConf = lib.mkOption { description = '' Configuration part of the tabrmd TCTI, like the D-Bus bus name. Applies if interface is set to "tabrmd". The format is specified in the [ tpm2-tools repository](https://github.com/tpm2-software/tpm2-tools/blob/master/man/common/tcti.md#tcti-options). ''; type = lib.types.str; default = "bus_name=com.intel.tss2.Tabrmd"; }; }; }; config = lib.mkIf cfg.enable ( lib.mkMerge [ { # PKCS11 tools and library environment.systemPackages = lib.mkIf cfg.pkcs11.enable [ (lib.getBin cfg.pkcs11.package) (lib.getLib cfg.pkcs11.package) ]; 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") { isSystemUser = true; group = "tss"; }; users.groups.${cfg.tssGroup} = lib.mkIf (cfg.tssGroup == "tss") { }; environment.variables = lib.mkIf cfg.tctiEnvironment.enable ( lib.attrsets.genAttrs [ "TPM2TOOLS_TCTI" "TPM2_PKCS11_TCTI" ] ( _: ''${cfg.tctiEnvironment.interface}:${ if cfg.tctiEnvironment.interface == "tabrmd" then cfg.tctiEnvironment.tabrmdConf else cfg.tctiEnvironment.deviceConf }'' ) ); } (lib.mkIf cfg.abrmd.enable { systemd.services."tpm2-abrmd" = { wantedBy = [ "multi-user.target" ]; serviceConfig = { Type = "dbus"; Restart = "always"; RestartSec = 30; BusName = "com.intel.tss2.Tabrmd"; ExecStart = "${cfg.abrmd.package}/bin/tpm2-abrmd"; User = "tss"; Group = "tss"; }; }; services.dbus.packages = lib.singleton cfg.abrmd.package; }) ] ); meta.maintainers = with lib.maintainers; [ lschuermann ]; }