- Actually run tcsd as tss/tss
- Install a udev rule to set /dev/tpm* permissions
- Remove systemd-udev-settle dependency, use dev-tpm0.device instead
- Use systemd-tmpfiles to set up the state directory
- Add documentation URI to tcsd.service
This module cannot be easily tested with a NixOS test due to the TPM
dependency. Technically, one could be emulated using swtpm[1], but this
is not packaged in Nixpkgs. If you computer has a real TPM you can do a
passthrough in Qemu, but this requires running the VM as root and of
course it's not determinstic:
    $ nix build -f nixos vm --arg configuration '
      {
        virtualisation.qemu.options = [
          "-tpmdev passthrough,id=tpm0,path=/dev/tpm0,cancel-path=/sys/class/tpm/tpm0/cancel"
          "-device tpm-tis,tpmdev=tpm0"
        ];
        users.users.root.hashedPassword = "";
        services.tcsd.enable = true;
      }'
After starting the VM, log in as root, you can check the service has
started with `systemctl status tcsd`.
[1]: https://github.com/stefanberger/swtpm
		
	
			
		
			
				
	
	
		
			161 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			Nix
		
	
	
	
	
	
			
		
		
	
	
			161 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			Nix
		
	
	
	
	
	
# tcsd daemon.
 | 
						|
 | 
						|
{ config, pkgs, lib, ... }:
 | 
						|
 | 
						|
with lib;
 | 
						|
let
 | 
						|
 | 
						|
  cfg = config.services.tcsd;
 | 
						|
 | 
						|
  tcsdConf = pkgs.writeText "tcsd.conf" ''
 | 
						|
    port = 30003
 | 
						|
    num_threads = 10
 | 
						|
    system_ps_file = ${cfg.stateDir}/system.data
 | 
						|
    # This is the log of each individual measurement done by the system.
 | 
						|
    # By re-calculating the PCR registers based on this information, even
 | 
						|
    # finer details about the measured environment can be inferred than
 | 
						|
    # what is available directly from the PCR registers.
 | 
						|
    firmware_log_file = /sys/kernel/security/tpm0/binary_bios_measurements
 | 
						|
    kernel_log_file = /sys/kernel/security/ima/binary_runtime_measurements
 | 
						|
    firmware_pcrs = ${cfg.firmwarePCRs}
 | 
						|
    kernel_pcrs = ${cfg.kernelPCRs}
 | 
						|
    platform_cred = ${cfg.platformCred}
 | 
						|
    conformance_cred = ${cfg.conformanceCred}
 | 
						|
    endorsement_cred = ${cfg.endorsementCred}
 | 
						|
    #remote_ops = create_key,random
 | 
						|
    #host_platform_class = server_12
 | 
						|
    #all_platform_classes = pc_11,pc_12,mobile_12
 | 
						|
  '';
 | 
						|
 | 
						|
in
 | 
						|
{
 | 
						|
 | 
						|
  ###### interface
 | 
						|
 | 
						|
  options = {
 | 
						|
 | 
						|
    services.tcsd = {
 | 
						|
 | 
						|
      enable = mkOption {
 | 
						|
        default = false;
 | 
						|
        type = types.bool;
 | 
						|
        description = ''
 | 
						|
          Whether to enable tcsd, a Trusted Computing management service
 | 
						|
          that provides TCG Software Stack (TSS).  The tcsd daemon is
 | 
						|
          the only portal to the Trusted Platform Module (TPM), a hardware
 | 
						|
          chip on the motherboard.
 | 
						|
        '';
 | 
						|
      };
 | 
						|
 | 
						|
      user = mkOption {
 | 
						|
        default = "tss";
 | 
						|
        type = types.str;
 | 
						|
        description = "User account under which tcsd runs.";
 | 
						|
      };
 | 
						|
 | 
						|
      group = mkOption {
 | 
						|
        default = "tss";
 | 
						|
        type = types.str;
 | 
						|
        description = "Group account under which tcsd runs.";
 | 
						|
      };
 | 
						|
 | 
						|
      stateDir = mkOption {
 | 
						|
        default = "/var/lib/tpm";
 | 
						|
        type = types.path;
 | 
						|
        description = ''
 | 
						|
          The location of the system persistent storage file.
 | 
						|
          The system persistent storage file holds keys and data across
 | 
						|
          restarts of the TCSD and system reboots.
 | 
						|
        '';
 | 
						|
      };
 | 
						|
 | 
						|
      firmwarePCRs = mkOption {
 | 
						|
        default = "0,1,2,3,4,5,6,7";
 | 
						|
        type = types.str;
 | 
						|
        description = "PCR indices used in the TPM for firmware measurements.";
 | 
						|
      };
 | 
						|
 | 
						|
      kernelPCRs = mkOption {
 | 
						|
        default = "8,9,10,11,12";
 | 
						|
        type = types.str;
 | 
						|
        description = "PCR indices used in the TPM for kernel measurements.";
 | 
						|
      };
 | 
						|
 | 
						|
      platformCred = mkOption {
 | 
						|
        default = "${cfg.stateDir}/platform.cert";
 | 
						|
        type = types.path;
 | 
						|
        description = ''
 | 
						|
          Path to the platform credential for your TPM. Your TPM
 | 
						|
          manufacturer may have provided you with a set of credentials
 | 
						|
          (certificates) that should be used when creating identities
 | 
						|
          using your TPM. When a user of your TPM makes an identity,
 | 
						|
          this credential will be encrypted as part of that process.
 | 
						|
          See the 1.1b TPM Main specification section 9.3 for information
 | 
						|
          on this process. '';
 | 
						|
      };
 | 
						|
 | 
						|
      conformanceCred = mkOption {
 | 
						|
        default = "${cfg.stateDir}/conformance.cert";
 | 
						|
        type = types.path;
 | 
						|
        description = ''
 | 
						|
          Path to the conformance credential for your TPM.
 | 
						|
          See also the platformCred option'';
 | 
						|
      };
 | 
						|
 | 
						|
      endorsementCred = mkOption {
 | 
						|
        default = "${cfg.stateDir}/endorsement.cert";
 | 
						|
        type = types.path;
 | 
						|
        description = ''
 | 
						|
          Path to the endorsement credential for your TPM.
 | 
						|
          See also the platformCred option'';
 | 
						|
      };
 | 
						|
    };
 | 
						|
 | 
						|
  };
 | 
						|
 | 
						|
  ###### implementation
 | 
						|
 | 
						|
  config = mkIf cfg.enable {
 | 
						|
 | 
						|
    environment.systemPackages = [ pkgs.trousers ];
 | 
						|
 | 
						|
    services.udev.extraRules = ''
 | 
						|
      # Give tcsd ownership of all TPM devices
 | 
						|
      KERNEL=="tpm[0-9]*", MODE="0660", OWNER="${cfg.user}", GROUP="${cfg.group}"
 | 
						|
      # Tag TPM devices to create a .device unit for tcsd to depend on
 | 
						|
      ACTION=="add", KERNEL=="tpm[0-9]*", TAG+="systemd"
 | 
						|
    '';
 | 
						|
 | 
						|
    systemd.tmpfiles.rules = [
 | 
						|
      # Initialise the state directory
 | 
						|
      "d ${cfg.stateDir} 0770 ${cfg.user} ${cfg.group} - -"
 | 
						|
    ];
 | 
						|
 | 
						|
    systemd.services.tcsd = {
 | 
						|
      description = "Manager for Trusted Computing resources";
 | 
						|
      documentation = [ "man:tcsd(8)" ];
 | 
						|
 | 
						|
      requires = [ "dev-tpm0.device" ];
 | 
						|
      after = [ "dev-tpm0.device" ];
 | 
						|
      wantedBy = [ "multi-user.target" ];
 | 
						|
 | 
						|
      serviceConfig = {
 | 
						|
        User = cfg.user;
 | 
						|
        Group = cfg.group;
 | 
						|
        ExecStart = "${pkgs.trousers}/sbin/tcsd -f -c ${tcsdConf}";
 | 
						|
      };
 | 
						|
    };
 | 
						|
 | 
						|
    users.users = optionalAttrs (cfg.user == "tss") {
 | 
						|
      tss = {
 | 
						|
        group = "tss";
 | 
						|
        uid = config.ids.uids.tss;
 | 
						|
      };
 | 
						|
    };
 | 
						|
 | 
						|
    users.groups = optionalAttrs (cfg.group == "tss") {
 | 
						|
      tss.gid = config.ids.gids.tss;
 | 
						|
    };
 | 
						|
  };
 | 
						|
}
 |