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 acess 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 = ''"tss" when using the userspace resource manager,'' +
30 ''"root" otherwise'';
31 };
32
33 tssGroup = lib.mkOption {
34 description = ''
35 Group of the tpm kernel resource manager (tpmrm) device-group, set if
36 applyUdevRules is set.
37 '';
38 type = lib.types.nullOr lib.types.str;
39 default = "tss";
40 };
41
42 applyUdevRules = lib.mkOption {
43 description = ''
44 Whether to make the /dev/tpm[0-9] devices accessible by the tssUser, or
45 the /dev/tpmrm[0-9] by tssGroup respectively
46 '';
47 type = lib.types.bool;
48 default = true;
49 };
50
51 abrmd = {
52 enable = lib.mkEnableOption ''
53 Trusted Platform 2 userspace resource manager daemon
54 '';
55
56 package = lib.mkOption {
57 description = "tpm2-abrmd package to use";
58 type = lib.types.package;
59 default = pkgs.tpm2-abrmd;
60 defaultText = "pkgs.tpm2-abrmd";
61 };
62 };
63
64 pkcs11 = {
65 enable = lib.mkEnableOption ''
66 TPM2 PKCS#11 tool and shared library in system path
67 (<literal>/run/current-system/sw/lib/libtpm2_pkcs11.so</literal>)
68 '';
69
70 package = lib.mkOption {
71 description = "tpm2-pkcs11 package to use";
72 type = lib.types.package;
73 default = pkgs.tpm2-pkcs11;
74 defaultText = "pkgs.tpm2-pkcs11";
75 };
76 };
77
78 tctiEnvironment = {
79 enable = lib.mkOption {
80 description = ''
81 Set common TCTI environment variables to the specified value.
82 The variables are
83 <itemizedlist>
84 <listitem>
85 <para>
86 <literal>TPM2TOOLS_TCTI</literal>
87 </para>
88 </listitem>
89 <listitem>
90 <para>
91 <literal>TPM2_PKCS11_TCTI</literal>
92 </para>
93 </listitem>
94 </itemizedlist>
95 '';
96 type = lib.types.bool;
97 default = false;
98 };
99
100 interface = lib.mkOption {
101 description = ''
102 The name of the TPM command transmission interface (TCTI) library to
103 use.
104 '';
105 type = lib.types.enum [ "tabrmd" "device" ];
106 default = "device";
107 };
108
109 deviceConf = lib.mkOption {
110 description = ''
111 Configuration part of the device TCTI, e.g. the path to the TPM device.
112 Applies if interface is set to "device".
113 The format is specified in the
114 <link xlink:href="https://github.com/tpm2-software/tpm2-tools/blob/master/man/common/tcti.md#tcti-options">
115 tpm2-tools repository</link>.
116 '';
117 type = lib.types.str;
118 default = "/dev/tpmrm0";
119 };
120
121 tabrmdConf = lib.mkOption {
122 description = ''
123 Configuration part of the tabrmd TCTI, like the D-Bus bus name.
124 Applies if interface is set to "tabrmd".
125 The format is specified in the
126 <link xlink:href="https://github.com/tpm2-software/tpm2-tools/blob/master/man/common/tcti.md#tcti-options">
127 tpm2-tools repository</link>.
128 '';
129 type = lib.types.str;
130 default = "bus_name=com.intel.tss2.Tabrmd";
131 };
132 };
133 };
134
135 config = lib.mkIf cfg.enable (lib.mkMerge [
136 {
137 # PKCS11 tools and library
138 environment.systemPackages = lib.mkIf cfg.pkcs11.enable [
139 (lib.getBin cfg.pkcs11.package)
140 (lib.getLib cfg.pkcs11.package)
141 ];
142
143 services.udev.extraRules = lib.mkIf cfg.applyUdevRules
144 (udevRules cfg.tssUser cfg.tssGroup);
145
146 # Create the tss user and group only if the default value is used
147 users.users.${cfg.tssUser} = lib.mkIf (cfg.tssUser == "tss") {
148 isSystemUser = true;
149 };
150 users.groups.${cfg.tssGroup} = lib.mkIf (cfg.tssGroup == "tss") {};
151
152 environment.variables = lib.mkIf cfg.tctiEnvironment.enable (
153 lib.attrsets.genAttrs [
154 "TPM2TOOLS_TCTI"
155 "TPM2_PKCS11_TCTI"
156 ] (_: ''${cfg.tctiEnvironment.interface}:${
157 if cfg.tctiEnvironment.interface == "tabrmd" then
158 cfg.tctiEnvironment.tabrmdConf
159 else
160 cfg.tctiEnvironment.deviceConf
161 }'')
162 );
163 }
164
165 (lib.mkIf cfg.abrmd.enable {
166 systemd.services."tpm2-abrmd" = {
167 wantedBy = [ "multi-user.target" ];
168 serviceConfig = {
169 Type = "dbus";
170 Restart = "always";
171 RestartSec = 30;
172 BusName = "com.intel.tss2.Tabrmd";
173 ExecStart = "${cfg.abrmd.package}/bin/tpm2-abrmd";
174 User = "tss";
175 Group = "nogroup";
176 };
177 };
178
179 services.dbus.packages = lib.singleton cfg.abrmd.package;
180 })
181 ]);
182
183 meta.maintainers = with lib.maintainers; [ lschuermann ];
184}