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