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 (lib.mdDoc "Trusted Platform Module 2 support");
21
22 tssUser = lib.mkOption {
23 description = lib.mdDoc ''
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 = lib.mdDoc ''
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 = lib.mdDoc ''
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 (lib.mdDoc ''
52 Trusted Platform 2 userspace resource manager daemon
53 '');
54
55 package = lib.mkOption {
56 description = lib.mdDoc "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 (lib.mdDoc ''
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 = lib.mdDoc "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 = lib.mdDoc ''
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 = lib.mdDoc ''
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 = lib.mdDoc ''
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 = lib.mdDoc ''
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}