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.mkPackageOption pkgs "tpm2-abrmd" { };
62 };
63
64 pkcs11 = {
65 enable = lib.mkEnableOption ''
66 TPM2 PKCS#11 tool and shared library in system path
67 (`/run/current-system/sw/lib/libtpm2_pkcs11.so`)
68 '';
69
70 package = lib.mkOption {
71 description = "tpm2-pkcs11 package to use";
72 type = lib.types.package;
73 default = if cfg.abrmd.enable then pkgs.tpm2-pkcs11.abrmd else pkgs.tpm2-pkcs11;
74 defaultText = lib.literalExpression "if config.security.tpm2.abrmd.enable then pkgs.tpm2-pkcs11.abrmd else 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 - `TPM2TOOLS_TCTI`
84 - `TPM2_PKCS11_TCTI`
85 '';
86 type = lib.types.bool;
87 default = false;
88 };
89
90 interface = lib.mkOption {
91 description = ''
92 The name of the TPM command transmission interface (TCTI) library to
93 use.
94 '';
95 type = lib.types.enum [
96 "tabrmd"
97 "device"
98 ];
99 default = "device";
100 };
101
102 deviceConf = lib.mkOption {
103 description = ''
104 Configuration part of the device TCTI, e.g. the path to the TPM device.
105 Applies if interface is set to "device".
106 The format is specified in the
107 [
108 tpm2-tools repository](https://github.com/tpm2-software/tpm2-tools/blob/master/man/common/tcti.md#tcti-options).
109 '';
110 type = lib.types.str;
111 default = "/dev/tpmrm0";
112 };
113
114 tabrmdConf = lib.mkOption {
115 description = ''
116 Configuration part of the tabrmd TCTI, like the D-Bus bus name.
117 Applies if interface is set to "tabrmd".
118 The format is specified in the
119 [
120 tpm2-tools repository](https://github.com/tpm2-software/tpm2-tools/blob/master/man/common/tcti.md#tcti-options).
121 '';
122 type = lib.types.str;
123 default = "bus_name=com.intel.tss2.Tabrmd";
124 };
125 };
126 };
127
128 config = lib.mkIf cfg.enable (
129 lib.mkMerge [
130 {
131 # PKCS11 tools and library
132 environment.systemPackages = lib.mkIf cfg.pkcs11.enable [
133 (lib.getBin cfg.pkcs11.package)
134 (lib.getLib cfg.pkcs11.package)
135 ];
136
137 services.udev.extraRules = lib.mkIf cfg.applyUdevRules (udevRules cfg.tssUser cfg.tssGroup);
138
139 # Create the tss user and group only if the default value is used
140 users.users.${cfg.tssUser} = lib.mkIf (cfg.tssUser == "tss") {
141 isSystemUser = true;
142 group = "tss";
143 };
144 users.groups.${cfg.tssGroup} = lib.mkIf (cfg.tssGroup == "tss") { };
145
146 environment.variables = lib.mkIf cfg.tctiEnvironment.enable (
147 lib.attrsets.genAttrs
148 [
149 "TPM2TOOLS_TCTI"
150 "TPM2_PKCS11_TCTI"
151 ]
152 (
153 _:
154 ''${cfg.tctiEnvironment.interface}:${
155 if cfg.tctiEnvironment.interface == "tabrmd" then
156 cfg.tctiEnvironment.tabrmdConf
157 else
158 cfg.tctiEnvironment.deviceConf
159 }''
160 )
161 );
162 }
163
164 (lib.mkIf cfg.abrmd.enable {
165 systemd.services."tpm2-abrmd" = {
166 wantedBy = [ "multi-user.target" ];
167 serviceConfig = {
168 Type = "dbus";
169 Restart = "always";
170 RestartSec = 30;
171 BusName = "com.intel.tss2.Tabrmd";
172 ExecStart = "${cfg.abrmd.package}/bin/tpm2-abrmd";
173 User = "tss";
174 Group = "tss";
175 };
176 };
177
178 services.dbus.packages = lib.singleton cfg.abrmd.package;
179 })
180 ]
181 );
182
183 meta.maintainers = with lib.maintainers; [ lschuermann ];
184}