1{ lib, pkgs, config, ... }:
2let
3 cfg = config.security.tpm2;
4
5 # This snippet is taken from tpm2-tss/dist/tpm-udev.rules, but modified to allow custom user/groups
6 # The idea is that the tssUser is allowed to access the TPM and kernel TPM resource manager, while
7 # the tssGroup is only allowed to access the kernel resource manager
8 # Therefore, if either of the two are null, the respective part isn't generated
9 udevRules = tssUser: tssGroup: ''
10 ${lib.optionalString (tssUser != null) ''KERNEL=="tpm[0-9]*", MODE="0660", OWNER="${tssUser}"''}
11 ${lib.optionalString (tssUser != null || tssGroup != null)
12 ''KERNEL=="tpmrm[0-9]*", MODE="0660"''
13 + lib.optionalString (tssUser != null) '', OWNER="${tssUser}"''
14 + lib.optionalString (tssGroup != null) '', GROUP="${tssGroup}"''
15 }
16 '';
17
18in {
19 options.security.tpm2 = {
20 enable = lib.mkEnableOption "Trusted Platform Module 2 support";
21
22 tssUser = lib.mkOption {
23 description = ''
24 Name of the tpm device-owner and service user, set if applyUdevRules is
25 set.
26 '';
27 type = lib.types.nullOr lib.types.str;
28 default = if cfg.abrmd.enable then "tss" else "root";
29 defaultText = lib.literalExpression ''if config.security.tpm2.abrmd.enable then "tss" else "root"'';
30 };
31
32 tssGroup = lib.mkOption {
33 description = ''
34 Group of the tpm kernel resource manager (tpmrm) device-group, set if
35 applyUdevRules is set.
36 '';
37 type = lib.types.nullOr lib.types.str;
38 default = "tss";
39 };
40
41 applyUdevRules = lib.mkOption {
42 description = ''
43 Whether to make the /dev/tpm[0-9] devices accessible by the tssUser, or
44 the /dev/tpmrm[0-9] by tssGroup respectively
45 '';
46 type = lib.types.bool;
47 default = true;
48 };
49
50 abrmd = {
51 enable = lib.mkEnableOption ''
52 Trusted Platform 2 userspace resource manager daemon
53 '';
54
55 package = lib.mkOption {
56 description = "tpm2-abrmd package to use";
57 type = lib.types.package;
58 default = pkgs.tpm2-abrmd;
59 defaultText = lib.literalExpression "pkgs.tpm2-abrmd";
60 };
61 };
62
63 pkcs11 = {
64 enable = lib.mkEnableOption ''
65 TPM2 PKCS#11 tool and shared library in system path
66 (`/run/current-system/sw/lib/libtpm2_pkcs11.so`)
67 '';
68
69 package = lib.mkOption {
70 description = "tpm2-pkcs11 package to use";
71 type = lib.types.package;
72 default = pkgs.tpm2-pkcs11;
73 defaultText = lib.literalExpression "pkgs.tpm2-pkcs11";
74 };
75 };
76
77 tctiEnvironment = {
78 enable = lib.mkOption {
79 description = ''
80 Set common TCTI environment variables to the specified value.
81 The variables are
82 - `TPM2TOOLS_TCTI`
83 - `TPM2_PKCS11_TCTI`
84 '';
85 type = lib.types.bool;
86 default = false;
87 };
88
89 interface = lib.mkOption {
90 description = ''
91 The name of the TPM command transmission interface (TCTI) library to
92 use.
93 '';
94 type = lib.types.enum [ "tabrmd" "device" ];
95 default = "device";
96 };
97
98 deviceConf = lib.mkOption {
99 description = ''
100 Configuration part of the device TCTI, e.g. the path to the TPM device.
101 Applies if interface is set to "device".
102 The format is specified in the
103 [
104 tpm2-tools repository](https://github.com/tpm2-software/tpm2-tools/blob/master/man/common/tcti.md#tcti-options).
105 '';
106 type = lib.types.str;
107 default = "/dev/tpmrm0";
108 };
109
110 tabrmdConf = lib.mkOption {
111 description = ''
112 Configuration part of the tabrmd TCTI, like the D-Bus bus name.
113 Applies if interface is set to "tabrmd".
114 The format is specified in the
115 [
116 tpm2-tools repository](https://github.com/tpm2-software/tpm2-tools/blob/master/man/common/tcti.md#tcti-options).
117 '';
118 type = lib.types.str;
119 default = "bus_name=com.intel.tss2.Tabrmd";
120 };
121 };
122 };
123
124 config = lib.mkIf cfg.enable (lib.mkMerge [
125 {
126 # PKCS11 tools and library
127 environment.systemPackages = lib.mkIf cfg.pkcs11.enable [
128 (lib.getBin cfg.pkcs11.package)
129 (lib.getLib cfg.pkcs11.package)
130 ];
131
132 services.udev.extraRules = lib.mkIf cfg.applyUdevRules
133 (udevRules cfg.tssUser cfg.tssGroup);
134
135 # Create the tss user and group only if the default value is used
136 users.users.${cfg.tssUser} = lib.mkIf (cfg.tssUser == "tss") {
137 isSystemUser = true;
138 group = "tss";
139 };
140 users.groups.${cfg.tssGroup} = lib.mkIf (cfg.tssGroup == "tss") {};
141
142 environment.variables = lib.mkIf cfg.tctiEnvironment.enable (
143 lib.attrsets.genAttrs [
144 "TPM2TOOLS_TCTI"
145 "TPM2_PKCS11_TCTI"
146 ] (_: ''${cfg.tctiEnvironment.interface}:${
147 if cfg.tctiEnvironment.interface == "tabrmd" then
148 cfg.tctiEnvironment.tabrmdConf
149 else
150 cfg.tctiEnvironment.deviceConf
151 }'')
152 );
153 }
154
155 (lib.mkIf cfg.abrmd.enable {
156 systemd.services."tpm2-abrmd" = {
157 wantedBy = [ "multi-user.target" ];
158 serviceConfig = {
159 Type = "dbus";
160 Restart = "always";
161 RestartSec = 30;
162 BusName = "com.intel.tss2.Tabrmd";
163 ExecStart = "${cfg.abrmd.package}/bin/tpm2-abrmd";
164 User = "tss";
165 Group = "tss";
166 };
167 };
168
169 services.dbus.packages = lib.singleton cfg.abrmd.package;
170 })
171 ]);
172
173 meta.maintainers = with lib.maintainers; [ lschuermann ];
174}