mirror of
https://github.com/NixOS/nixpkgs.git
synced 2025-11-10 09:43:30 +01:00
396 lines
13 KiB
Nix
396 lines
13 KiB
Nix
{
|
|
lib,
|
|
pkgs,
|
|
config,
|
|
...
|
|
}:
|
|
let
|
|
cfg = config.security.tpm2;
|
|
|
|
# This snippet is taken from tpm2-tss/dist/tpm-udev.rules, but modified to allow custom user/groups
|
|
# The idea is that the tssUser is allowed to access the TPM and kernel TPM resource manager, while
|
|
# the tssGroup is only allowed to access the kernel resource manager
|
|
# Therefore, if either of the two are null, the respective part isn't generated
|
|
udevRules = tssUser: tssGroup: ''
|
|
${lib.optionalString (
|
|
tssUser != null
|
|
) ''KERNEL=="tpm[0-9]*", TAG+="systemd", MODE="0660", OWNER="${tssUser}"''}
|
|
${
|
|
lib.optionalString (
|
|
tssUser != null || tssGroup != null
|
|
) ''KERNEL=="tpmrm[0-9]*", TAG+="systemd", MODE="0660"''
|
|
+ lib.optionalString (tssUser != null) '', OWNER="${tssUser}"''
|
|
+ lib.optionalString (tssGroup != null) '', GROUP="${tssGroup}"''
|
|
}
|
|
'';
|
|
|
|
fapiConfig = (
|
|
pkgs.writeText "fapi-config.json" (
|
|
builtins.toJSON (
|
|
{
|
|
profile_name = cfg.fapi.profileName;
|
|
profile_dir = cfg.fapi.profileDir;
|
|
user_dir = cfg.fapi.userDir;
|
|
system_dir = cfg.fapi.systemDir;
|
|
tcti = cfg.fapi.tcti;
|
|
system_pcrs = cfg.fapi.systemPcrs;
|
|
log_dir = cfg.fapi.logDir;
|
|
firmware_log_file = cfg.fapi.firmwareLogFile;
|
|
ima_log_file = cfg.fapi.imaLogFile;
|
|
}
|
|
// lib.optionalAttrs (cfg.fapi.ekCertLess != null) {
|
|
ek_cert_less = lib.boolToYesNo cfg.fapi.ekCertLess;
|
|
}
|
|
// lib.optionalAttrs (cfg.fapi.ekFingerprint != null) { ek_fingerprint = cfg.fapi.ekFingerprint; }
|
|
)
|
|
)
|
|
);
|
|
in
|
|
{
|
|
options.security.tpm2 = {
|
|
enable = lib.mkEnableOption "Trusted Platform Module 2 support";
|
|
|
|
tssUser = lib.mkOption {
|
|
description = ''
|
|
Name of the tpm device-owner and service user, set if applyUdevRules is
|
|
set.
|
|
'';
|
|
type = lib.types.nullOr lib.types.str;
|
|
default = if cfg.abrmd.enable then "tss" else "root";
|
|
defaultText = lib.literalExpression ''if config.security.tpm2.abrmd.enable then "tss" else "root"'';
|
|
};
|
|
|
|
tssGroup = lib.mkOption {
|
|
description = ''
|
|
Group of the tpm kernel resource manager (tpmrm) device-group, set if
|
|
applyUdevRules is set.
|
|
'';
|
|
type = lib.types.nullOr lib.types.str;
|
|
default = "tss";
|
|
};
|
|
|
|
applyUdevRules = lib.mkOption {
|
|
description = ''
|
|
Whether to make the /dev/tpm[0-9] devices accessible by the tssUser, or
|
|
the /dev/tpmrm[0-9] by tssGroup respectively
|
|
'';
|
|
type = lib.types.bool;
|
|
default = true;
|
|
};
|
|
|
|
abrmd = {
|
|
enable = lib.mkEnableOption ''
|
|
Trusted Platform 2 userspace resource manager daemon
|
|
'';
|
|
|
|
package = lib.mkPackageOption pkgs "tpm2-abrmd" { };
|
|
};
|
|
|
|
pkcs11 = {
|
|
enable = lib.mkEnableOption ''
|
|
TPM2 PKCS#11 tool and shared library in system path
|
|
(`/run/current-system/sw/lib/libtpm2_pkcs11.so`)
|
|
'';
|
|
|
|
package = lib.mkOption {
|
|
description = "tpm2-pkcs11 package to use";
|
|
type = lib.types.package;
|
|
default = if cfg.abrmd.enable then pkgs.tpm2-pkcs11.abrmd else pkgs.tpm2-pkcs11;
|
|
defaultText = lib.literalExpression "if config.security.tpm2.abrmd.enable then pkgs.tpm2-pkcs11.abrmd else pkgs.tpm2-pkcs11";
|
|
};
|
|
};
|
|
|
|
tctiEnvironment = {
|
|
enable = lib.mkOption {
|
|
description = ''
|
|
Set common TCTI environment variables to the specified value.
|
|
The variables are
|
|
- `TPM2TOOLS_TCTI`
|
|
- `TPM2_PKCS11_TCTI`
|
|
'';
|
|
type = lib.types.bool;
|
|
default = false;
|
|
};
|
|
|
|
interface = lib.mkOption {
|
|
description = ''
|
|
The name of the TPM command transmission interface (TCTI) library to
|
|
use.
|
|
'';
|
|
type = lib.types.enum [
|
|
"tabrmd"
|
|
"device"
|
|
];
|
|
default = "device";
|
|
};
|
|
|
|
deviceConf = lib.mkOption {
|
|
description = ''
|
|
Configuration part of the device TCTI, e.g. the path to the TPM device.
|
|
Applies if interface is set to "device".
|
|
The format is specified in the
|
|
[
|
|
tpm2-tools repository](https://github.com/tpm2-software/tpm2-tools/blob/master/man/common/tcti.md#tcti-options).
|
|
'';
|
|
type = lib.types.str;
|
|
default = "/dev/tpmrm0";
|
|
};
|
|
|
|
tabrmdConf = lib.mkOption {
|
|
description = ''
|
|
Configuration part of the tabrmd TCTI, like the D-Bus bus name.
|
|
Applies if interface is set to "tabrmd".
|
|
The format is specified in the
|
|
[
|
|
tpm2-tools repository](https://github.com/tpm2-software/tpm2-tools/blob/master/man/common/tcti.md#tcti-options).
|
|
'';
|
|
type = lib.types.str;
|
|
default = "bus_name=com.intel.tss2.Tabrmd";
|
|
};
|
|
};
|
|
|
|
fapi = {
|
|
profileName = lib.mkOption {
|
|
description = ''
|
|
Name of the default cryptographic profile chosen from the profile_dir directory.
|
|
'';
|
|
type = lib.types.str;
|
|
default = "P_ECCP256SHA256";
|
|
};
|
|
|
|
profileDir = lib.mkOption {
|
|
description = ''
|
|
Directory that contains all cryptographic profiles known to FAPI.
|
|
'';
|
|
type = lib.types.str;
|
|
default = "${pkgs.tpm2-tss}/etc/tpm2-tss/fapi-profiles/";
|
|
defaultText = lib.literalExpression "\${pkgs.tpm2-tss}/etc/fapi-profiles/";
|
|
};
|
|
|
|
userDir = lib.mkOption {
|
|
description = ''
|
|
The directory where user objects are stored.
|
|
'';
|
|
type = lib.types.str;
|
|
default = "~/.local/share/tpm2-tss/user/keystore/";
|
|
};
|
|
|
|
systemDir = lib.mkOption {
|
|
description = ''
|
|
The directory where system objects, policies, and imported objects are stored.
|
|
'';
|
|
type = lib.types.str;
|
|
default = "/var/lib/tpm2-tss/keystore";
|
|
};
|
|
|
|
tcti = lib.mkOption {
|
|
description = ''
|
|
The TCTI which will be used.
|
|
|
|
An empty string indicates no TCTI is specified by the FAPI config.
|
|
|
|
If not specified in the FAPI config it can be specified by environment
|
|
variable (TPM2TOOLS_TCTI, TPM2_PKCS11_TCTI, etc) or a TCTI will be chosen
|
|
by the FAPI library by searching for tabrmd, device, and mssim TCTIs in
|
|
that order.
|
|
'';
|
|
type = lib.types.str;
|
|
default = "";
|
|
example = "device:/dev/tpmrm0";
|
|
};
|
|
|
|
systemPcrs = lib.mkOption {
|
|
description = ''
|
|
The PCR registers which are used by the system.
|
|
'';
|
|
type = lib.types.listOf lib.types.int;
|
|
default = [ ];
|
|
};
|
|
|
|
logDir = lib.mkOption {
|
|
description = ''
|
|
The directory for the event log.
|
|
'';
|
|
type = lib.types.str;
|
|
default = "/var/log/tpm2-tss/eventlog/";
|
|
};
|
|
|
|
ekCertLess = lib.mkOption {
|
|
description = ''
|
|
A switch to disable Endorsement Key (EK) certificate verification.
|
|
|
|
A value of null indicates that the generated fapi config file does not
|
|
contain a ek_cert_less key. The effect of not having that key at all is
|
|
the same as setting its value to false.
|
|
|
|
A value of false means that the tss2 cli will not work if there is no
|
|
EK Cert installed, or if the installed EK Cert can't be validated.
|
|
|
|
A value of true means that the tss2 cli will work even if there's no EK
|
|
cert installed.
|
|
'';
|
|
type = lib.types.nullOr lib.types.bool;
|
|
default = null;
|
|
};
|
|
|
|
ekFingerprint = lib.mkOption {
|
|
description = ''
|
|
The fingerprint of the endorsement key.
|
|
|
|
A value of null means that you have chosen not to specify the expected
|
|
fingerprint of the EK. You can still have an endorsement key, it just
|
|
won't get checked to see if it's fingerprint matches a particular value
|
|
before being used.
|
|
'';
|
|
type = lib.types.nullOr lib.types.str;
|
|
default = null;
|
|
};
|
|
|
|
firmwareLogFile = lib.mkOption {
|
|
description = ''
|
|
The binary bios measurements.
|
|
'';
|
|
type = lib.types.str;
|
|
default = "/sys/kernel/security/tpm0/binary_bios_measurements";
|
|
};
|
|
|
|
imaLogFile = lib.mkOption {
|
|
description = ''
|
|
The binary IMA measurements (Integrity Measurement Architecture).
|
|
'';
|
|
type = lib.types.str;
|
|
default = "/sys/kernel/security/ima/binary_runtime_measurements";
|
|
};
|
|
};
|
|
};
|
|
|
|
config = lib.mkIf cfg.enable (
|
|
lib.mkMerge [
|
|
{
|
|
# PKCS11 tools and library
|
|
environment.systemPackages = lib.mkIf cfg.pkcs11.enable [
|
|
(lib.getBin cfg.pkcs11.package)
|
|
(lib.getLib cfg.pkcs11.package)
|
|
];
|
|
|
|
services.udev.extraRules = lib.mkIf cfg.applyUdevRules (udevRules cfg.tssUser cfg.tssGroup);
|
|
|
|
# Create the tss user and group only if the default value is used
|
|
users.users.${cfg.tssUser} = lib.mkIf (cfg.tssUser == "tss") {
|
|
isSystemUser = true;
|
|
group = "tss";
|
|
};
|
|
users.groups.${cfg.tssGroup} = lib.mkIf (cfg.tssGroup == "tss") { };
|
|
|
|
environment.variables = lib.mkIf cfg.tctiEnvironment.enable (
|
|
lib.attrsets.genAttrs
|
|
[
|
|
"TPM2TOOLS_TCTI"
|
|
"TPM2_PKCS11_TCTI"
|
|
]
|
|
(
|
|
_:
|
|
''${cfg.tctiEnvironment.interface}:${
|
|
if cfg.tctiEnvironment.interface == "tabrmd" then
|
|
cfg.tctiEnvironment.tabrmdConf
|
|
else
|
|
cfg.tctiEnvironment.deviceConf
|
|
}''
|
|
)
|
|
);
|
|
}
|
|
|
|
{
|
|
# This script has the hash of the udev rules in it,
|
|
# and also writes that hash to
|
|
# /var/lib/tpm2-udev-trigger/hash.txt at the end.
|
|
# On each run, it checks to see if the hash embedded in the script
|
|
# matches the hash on disk. If they are different, that
|
|
# indicates that the udev rules created by this module
|
|
# have changed. In that case, a udev change is triggered
|
|
# for tpm and tpmrm devices so that the new rules are
|
|
# applied at the end of a nixos-rebuild switch or activate
|
|
systemd.services."tpm2-udev-trigger" =
|
|
let
|
|
udevHash =
|
|
if cfg.applyUdevRules then (builtins.hashString "md5" (udevRules cfg.tssUser cfg.tssGroup)) else "";
|
|
in
|
|
{
|
|
description = "Trigger udev change for TPM devices";
|
|
wants = [ "systemd-udevd.service" ];
|
|
after = [
|
|
"tpm2.target"
|
|
"systemd-udevd.service"
|
|
];
|
|
wantedBy = [ "multi-user.target" ];
|
|
serviceConfig = {
|
|
Type = "oneshot";
|
|
RemainAfterExit = true;
|
|
ExecStart = pkgs.writeShellScript "tpm2-udev-trigger.sh" ''
|
|
stateDir=/var/lib/tpm2-udev-trigger
|
|
mkdir -p $stateDir
|
|
newHash=${udevHash}
|
|
hashFile=$stateDir/hash.txt
|
|
|
|
# if file exists, read old hash
|
|
if [ -f $hashFile ]; then
|
|
oldHash="$(< $hashFile)"
|
|
else
|
|
oldHash=""
|
|
fi
|
|
|
|
if [ "$oldHash" != "$newHash" ]; then
|
|
echo "TPM udev rules changed, triggering udev"
|
|
${config.systemd.package}/bin/udevadm trigger --subsystem-match=tpm --action=change
|
|
${config.systemd.package}/bin/udevadm trigger --subsystem-match=tpmrm --action=change
|
|
echo "$newHash" > $hashFile
|
|
else
|
|
echo "TPM udev rules unchanged, not triggering udev"
|
|
fi
|
|
'';
|
|
};
|
|
};
|
|
}
|
|
|
|
(lib.mkIf cfg.abrmd.enable {
|
|
systemd.services."tpm2-abrmd" = {
|
|
wants = [
|
|
"tpm2-udev-trigger.service"
|
|
"dev-tpm0.device"
|
|
];
|
|
after = [
|
|
"tpm2-udev-trigger.service"
|
|
"dev-tpm0.device"
|
|
];
|
|
wantedBy = [ "multi-user.target" ];
|
|
serviceConfig = {
|
|
Type = "dbus";
|
|
Restart = "always";
|
|
RestartSec = 30;
|
|
BusName = "com.intel.tss2.Tabrmd";
|
|
ExecStart = "${cfg.abrmd.package}/bin/tpm2-abrmd";
|
|
User = "tss";
|
|
Group = "tss";
|
|
};
|
|
};
|
|
|
|
services.dbus.packages = lib.singleton cfg.abrmd.package;
|
|
})
|
|
|
|
{
|
|
environment.etc."tpm2-tss/fapi-config.json".source = fapiConfig;
|
|
systemd.tmpfiles.rules = [
|
|
"d ${cfg.fapi.logDir} 2750 ${cfg.tssUser} ${cfg.tssGroup} -"
|
|
"d ${cfg.fapi.systemDir} 2750 root ${cfg.tssGroup} -"
|
|
];
|
|
}
|
|
]
|
|
);
|
|
|
|
meta.doc = ./tpm2.md;
|
|
meta.maintainers = with lib.maintainers; [
|
|
lschuermann
|
|
scottstephens
|
|
];
|
|
}
|