From 1a5d1358b7b36f28a6f1dc939315d08a9c6fda1a Mon Sep 17 00:00:00 2001 From: Jared Baur Date: Tue, 13 Jun 2023 11:26:55 -0700 Subject: [PATCH 1/5] optee-client: init at 4.6.0 OP-TEE client provides libraries, headers, and a userspace supplicant for interacting with OP-TEE OS, a trusted execution environment for ARM. --- pkgs/by-name/op/optee-client/package.nix | 72 ++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 pkgs/by-name/op/optee-client/package.nix diff --git a/pkgs/by-name/op/optee-client/package.nix b/pkgs/by-name/op/optee-client/package.nix new file mode 100644 index 000000000000..dbe59890d452 --- /dev/null +++ b/pkgs/by-name/op/optee-client/package.nix @@ -0,0 +1,72 @@ +{ + fetchFromGitHub, + isNixOS ? true, + lib, + libuuid, + pkg-config, + stdenv, + which, +}: + +stdenv.mkDerivation (finalAttrs: { + pname = "optee-client"; + version = "4.6.0"; + + src = fetchFromGitHub { + owner = "OP-TEE"; + repo = "optee_client"; + rev = finalAttrs.version; + hash = "sha256-hHEIn0WU4XfqwZbOdg9kwSDxDcvK7Tvxtelamfc3IRM="; + }; + + outputs = [ + "out" + "lib" + "dev" + ]; + + strictDeps = true; + + enableParallelBuilding = true; + + nativeBuildInputs = [ + which + pkg-config + ]; + buildInputs = [ libuuid ]; + + makeFlags = + [ + "CROSS_COMPILE=${stdenv.cc.targetPrefix}" + "DESTDIR=$(out)" + "SBINDIR=/bin" + "INCLUDEDIR=/include" + "LIBDIR=/lib" + ] + ++ + # If we are building for NixOS, change default optee config to use paths + # that will work well with NixOS. + lib.optionals isNixOS [ + "CFG_TEE_CLIENT_LOAD_PATH=/run/current-system/sw/lib" + "CFG_TEE_PLUGIN_LOAD_PATH=/run/current-system/sw/lib/tee-supplicant/plugins" + "CFG_TEE_FS_PARENT_PATH=/var/lib/tee" + ]; + + preFixup = '' + mkdir -p "$lib" "$dev" + mv "$out/lib" "$lib" + mv "$out/include" "$dev" + ''; + + meta = { + description = "Normal world client for OPTEE OS"; + homepage = "https://github.com/OP-TEE/optee_client"; + changelog = "https://github.com/OP-TEE/optee_client/releases/tag/${finalAttrs.version}"; + license = lib.licenses.bsd2; + maintainers = [ lib.maintainers.jmbaur ]; + platforms = [ + "aarch64-linux" + "armv7l-linux" + ]; + }; +}) From 309fe7f571393c1a0cb352e76ca3815316999e15 Mon Sep 17 00:00:00 2001 From: Jared Baur Date: Tue, 13 Jun 2023 11:30:45 -0700 Subject: [PATCH 2/5] optee-os: init at 4.6.0 This change adds two builds of OP-TEE OS (qemu armv7 & qemu aarch64) as well as a function that can be used for building OP-TEE OS for any board. This follows the pattern similar to buildUBoot and buildArmTrustedFirmware. --- pkgs/misc/optee-os/default.nix | 127 ++++++++++++++++++++++++++++++++ pkgs/top-level/all-packages.nix | 6 ++ 2 files changed, 133 insertions(+) create mode 100644 pkgs/misc/optee-os/default.nix diff --git a/pkgs/misc/optee-os/default.nix b/pkgs/misc/optee-os/default.nix new file mode 100644 index 000000000000..6b6d5ae692af --- /dev/null +++ b/pkgs/misc/optee-os/default.nix @@ -0,0 +1,127 @@ +{ + dtc, + fetchFromGitHub, + lib, + pkgsBuildBuild, + stdenv, +}: + +let + defaultVersion = "4.6.0"; + + defaultSrc = fetchFromGitHub { + owner = "OP-TEE"; + repo = "optee_os"; + rev = defaultVersion; + hash = "sha256-4z706DNfZE+CAPOa362CNSFhAN1KaNyKcI9C7+MRccs="; + }; + + buildOptee = lib.makeOverridable ( + { + version ? null, + src ? null, + platform, + extraMakeFlags ? [ ], + extraMeta ? { }, + ... + }@args: + + let + inherit (stdenv.hostPlatform) is32bit is64bit; + + taTarget = + { + "arm" = "ta_arm32"; + "arm64" = "ta_arm64"; + } + .${stdenv.hostPlatform.linuxArch}; + in + stdenv.mkDerivation ( + { + pname = "optee-os-${platform}"; + + version = if src == null then defaultVersion else version; + + src = if src == null then defaultSrc else src; + + postPatch = '' + patchShebangs $(find -type d -name scripts -printf '%p ') + ''; + + outputs = [ + "out" + "devkit" + ]; + + strictDeps = true; + + enableParallelBuilding = true; + + depsBuildBuild = [ pkgsBuildBuild.stdenv.cc ]; + + nativeBuildInputs = [ + dtc + (pkgsBuildBuild.python3.withPackages ( + p: with p; [ + pyelftools + cryptography + ] + )) + ]; + + makeFlags = + [ + "O=out" + "PLATFORM=${platform}" + "CFG_USER_TA_TARGETS=${taTarget}" + ] + ++ (lib.optionals (is32bit) [ + "CFG_ARM32_core=y" + "CROSS_COMPILE32=${stdenv.cc.targetPrefix}" + ]) + ++ (lib.optionals (is64bit) [ + "CFG_ARM64_core=y" + "CROSS_COMPILE64=${stdenv.cc.targetPrefix}" + ]) + ++ extraMakeFlags; + + installPhase = '' + runHook preInstall + + mkdir -p $out + cp out/core/{tee.elf,tee-pageable_v2.bin,tee.bin,tee-header_v2.bin,tee-pager_v2.bin,tee-raw.bin} $out + cp -r out/export-${taTarget} $devkit + + runHook postInstall + ''; + + meta = + with lib; + { + description = "A Trusted Execution Environment for ARM"; + homepage = "https://github.com/OP-TEE/optee_os"; + changelog = "https://github.com/OP-TEE/optee_os/blob/${defaultVersion}/CHANGELOG.md"; + license = licenses.bsd2; + maintainers = [ maintainers.jmbaur ]; + } + // extraMeta; + } + // removeAttrs args [ "extraMeta" ] + ) + ); +in +{ + inherit buildOptee; + + opteeQemuArm = buildOptee { + platform = "vexpress"; + extraMakeFlags = [ "PLATFORM_FLAVOR=qemu_virt" ]; + extraMeta.platforms = [ "armv7l-linux" ]; + }; + + opteeQemuAarch64 = buildOptee { + platform = "vexpress"; + extraMakeFlags = [ "PLATFORM_FLAVOR=qemu_armv8a" ]; + extraMeta.platforms = [ "aarch64-linux" ]; + }; +} diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix index 80a1ad392d14..81b03808bf68 100644 --- a/pkgs/top-level/all-packages.nix +++ b/pkgs/top-level/all-packages.nix @@ -7441,6 +7441,12 @@ with pkgs; libiberty_static = libiberty.override { staticBuild = true; }; }; + inherit (callPackage ../misc/optee-os { }) + buildOptee + opteeQemuArm + opteeQemuAarch64 + ; + patchelf = callPackage ../development/tools/misc/patchelf { }; patchelfUnstable = lowPrio (callPackage ../development/tools/misc/patchelf/unstable.nix { }); From 9a0134309c49ea2ca315df9c6cedaaa317698c9c Mon Sep 17 00:00:00 2001 From: Jared Baur Date: Tue, 13 Jun 2023 11:36:13 -0700 Subject: [PATCH 3/5] arm-trusted-firmware: make buildArmTrustedFirmware result overridable This allows for overriding function arguments to buildArmTrustedFirmware. --- pkgs/misc/arm-trusted-firmware/default.nix | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pkgs/misc/arm-trusted-firmware/default.nix b/pkgs/misc/arm-trusted-firmware/default.nix index 743e429c0051..b76b601046ba 100644 --- a/pkgs/misc/arm-trusted-firmware/default.nix +++ b/pkgs/misc/arm-trusted-firmware/default.nix @@ -18,7 +18,7 @@ }: let - buildArmTrustedFirmware = + buildArmTrustedFirmware = lib.makeOverridable ( { filesToInstall, installDir ? "$out", @@ -109,7 +109,8 @@ let // extraMeta; } // builtins.removeAttrs args [ "extraMeta" ] - ); + ) + ); in { From 516e9fae60f7d212aa52602279f74d5fd4d75d13 Mon Sep 17 00:00:00 2001 From: Jared Baur Date: Tue, 13 Jun 2023 11:37:30 -0700 Subject: [PATCH 4/5] arm-trusted-firmware: add openssl to nativeBuildInputs This allows for the `fiptool` make target for arm-trusted-firmware to be built. --- pkgs/misc/arm-trusted-firmware/default.nix | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/pkgs/misc/arm-trusted-firmware/default.nix b/pkgs/misc/arm-trusted-firmware/default.nix index b76b601046ba..54553365a779 100644 --- a/pkgs/misc/arm-trusted-firmware/default.nix +++ b/pkgs/misc/arm-trusted-firmware/default.nix @@ -59,8 +59,11 @@ let depsBuildBuild = [ buildPackages.stdenv.cc ]; - # For Cortex-M0 firmware in RK3399 - nativeBuildInputs = [ pkgsCross.arm-embedded.stdenv.cc ]; + nativeBuildInputs = [ + pkgsCross.arm-embedded.stdenv.cc # For Cortex-M0 firmware in RK3399 + openssl # For fiptool + ]; + # Make the new toolchain guessing (from 2.11+) happy # https://github.com/ARM-software/arm-trusted-firmware/blob/4ec2948fe3f65dba2f19e691e702f7de2949179c/make_helpers/toolchains/rk3399-m0.mk#L21-L22 rk3399-m0-oc = "${pkgsCross.arm-embedded.stdenv.cc.targetPrefix}objcopy"; From b8937303cef45a9552be9eb3518038bb06c41128 Mon Sep 17 00:00:00 2001 From: Jared Baur Date: Tue, 13 Jun 2023 11:38:28 -0700 Subject: [PATCH 5/5] nixos/tee-supplicant: add tee-supplicant module The tee-supplicant is a program that interacts with OP-TEE OS and allows loading trusted applications at runtime (among other things). There is an `optee` test included that uses the pkcs11 trusted application (in upstream OP-TEE OS), loads it during system startup via tee-supplicant, and uses `pkcs11-tool` to list available token slots. --- .../manual/release-notes/rl-2505.section.md | 2 + nixos/modules/module-list.nix | 1 + .../services/misc/tee-supplicant/default.nix | 95 +++++++++++++++++++ nixos/tests/all-tests.nix | 1 + nixos/tests/optee.nix | 72 ++++++++++++++ 5 files changed, 171 insertions(+) create mode 100644 nixos/modules/services/misc/tee-supplicant/default.nix create mode 100644 nixos/tests/optee.nix diff --git a/nixos/doc/manual/release-notes/rl-2505.section.md b/nixos/doc/manual/release-notes/rl-2505.section.md index 44e8e6b84364..694c8caadb2c 100644 --- a/nixos/doc/manual/release-notes/rl-2505.section.md +++ b/nixos/doc/manual/release-notes/rl-2505.section.md @@ -222,6 +222,8 @@ Alongside many enhancements to NixOS modules and general system improvements, th - [Limine](https://github.com/limine-bootloader/limine) a modern, advanced, portable, multiprotocol bootloader and boot manager. Available as [boot.loader.limine](#opt-boot.loader.limine.enable). +- [tee-supplicant](https://github.com/OP-TEE/optee_client), a userspace supplicant for OP-TEE OS. Available as [services.tee-supplicant](#opt-services.tee-supplicant.enable). + - [Orthanc](https://orthanc.uclouvain.be/) a lightweight, RESTful DICOM server for healthcare and medical research. Available as [services.orthanc](#opt-services.orthanc.enable). - [Docling Serve](https://github.com/docling-project/docling-serve) running [Docling](https://github.com/docling-project/docling) as an API service. Available as [services.docling-serve](#opt-services.docling-serve.enable). diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index a297dfc96d5d..6d4c9672f822 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -930,6 +930,7 @@ ./services/misc/taskchampion-sync-server.nix ./services/misc/taskserver ./services/misc/tautulli.nix + ./services/misc/tee-supplicant ./services/misc/tiddlywiki.nix ./services/misc/tp-auto-kbbl.nix ./services/misc/transfer-sh.nix diff --git a/nixos/modules/services/misc/tee-supplicant/default.nix b/nixos/modules/services/misc/tee-supplicant/default.nix new file mode 100644 index 000000000000..185253e2c44d --- /dev/null +++ b/nixos/modules/services/misc/tee-supplicant/default.nix @@ -0,0 +1,95 @@ +{ + config, + pkgs, + lib, + ... +}: +let + inherit (lib) + getExe' + mkEnableOption + mkIf + mkOption + mkPackageOption + types + ; + + cfg = config.services.tee-supplicant; + + taDir = "optee_armtz"; + + trustedApplications = pkgs.linkFarm "runtime-trusted-applications" ( + map ( + ta: + let + # This is safe since we are using it as the path value, so the context + # will still ensure that this nix store path exists on the running + # system. + taFile = builtins.baseNameOf (builtins.unsafeDiscardStringContext ta); + in + { + name = "lib/${taDir}/${taFile}"; + path = ta; + } + ) cfg.trustedApplications + ); +in +{ + options.services.tee-supplicant = { + enable = mkEnableOption "OP-TEE userspace supplicant"; + + package = mkPackageOption pkgs "optee-client" { }; + + trustedApplications = mkOption { + type = types.listOf types.path; + default = [ ]; + description = '' + A list of full paths to trusted applications that will be loaded at + runtime by tee-supplicant. + ''; + }; + + pluginPath = mkOption { + type = types.path; + default = "/run/current-system/sw/lib/tee-supplicant/plugins"; + description = '' + The directory where plugins will be loaded from on startup. + ''; + }; + + reeFsParentPath = mkOption { + type = types.path; + default = "/var/lib/tee"; + description = '' + The directory where the secure filesystem will be stored in the rich + execution environment (REE FS). + ''; + }; + }; + + config = mkIf cfg.enable { + environment = mkIf (cfg.trustedApplications != [ ]) { + systemPackages = [ trustedApplications ]; + pathsToLink = [ "/lib/${taDir}" ]; + }; + + systemd.services.tee-supplicant = { + description = "Userspace supplicant for OPTEE-OS"; + + serviceConfig = { + ExecStart = toString [ + (getExe' cfg.package "tee-supplicant") + "--ta-dir ${taDir}" + "--fs-parent-path ${cfg.reeFsParentPath}" + "--plugin-path ${cfg.pluginPath}" + ]; + Restart = "always"; + }; + + after = [ "modprobe@optee.service" ]; + wants = [ "modprobe@optee.service" ]; + + wantedBy = [ "multi-user.target" ]; + }; + }; +} diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix index 11d6afa5478e..441dbec25a0c 100644 --- a/nixos/tests/all-tests.nix +++ b/nixos/tests/all-tests.nix @@ -1064,6 +1064,7 @@ in openvscode-server = runTest ./openvscode-server.nix; open-webui = runTest ./open-webui.nix; openvswitch = runTest ./openvswitch.nix; + optee = handleTestOn [ "aarch64-linux" ] ./optee.nix { }; orangefs = runTest ./orangefs.nix; os-prober = handleTestOn [ "x86_64-linux" ] ./os-prober.nix { }; osquery = handleTestOn [ "x86_64-linux" ] ./osquery.nix { }; diff --git a/nixos/tests/optee.nix b/nixos/tests/optee.nix new file mode 100644 index 000000000000..ac049b30378c --- /dev/null +++ b/nixos/tests/optee.nix @@ -0,0 +1,72 @@ +import ./make-test-python.nix ( + { pkgs, lib, ... }: + { + name = "optee"; + + meta = with pkgs.lib.maintainers; { + maintainers = [ jmbaur ]; + }; + + nodes.machine = + { config, pkgs, ... }: + let + inherit (pkgs) armTrustedFirmwareQemu opteeQemuAarch64 ubootQemuAarch64; + + # Default environment for qemu-arm64 uboot does not work well with + # large nixos kernel/initrds. + uboot = ubootQemuAarch64.overrideAttrs (old: { + postPatch = + (old.postPatch or "") + + '' + substituteInPlace board/emulation/qemu-arm/qemu-arm.env \ + --replace-fail "ramdisk_addr_r=0x44000000" "ramdisk_addr_r=0x46000000" + ''; + }); + + bios = armTrustedFirmwareQemu.override { + extraMakeFlags = [ + "SPD=opteed" + "BL32=${opteeQemuAarch64}/tee-header_v2.bin" + "BL32_EXTRA1=${opteeQemuAarch64}/tee-pager_v2.bin" + "BL32_EXTRA2=${opteeQemuAarch64}/tee-pageable_v2.bin" + "BL33=${uboot}/u-boot.bin" + "all" + "fip" + ]; + filesToInstall = [ + "build/qemu/release/bl1.bin" + "build/qemu/release/fip.bin" + ]; + postInstall = '' + dd if=$out/bl1.bin of=$out/bios.bin bs=4096 conv=notrunc + dd if=$out/fip.bin of=$out/bios.bin seek=64 bs=4096 conv=notrunc + ''; + }; + in + { + virtualisation = { + inherit bios; + cores = 2; + qemu.options = [ + "-machine virt,secure=on,accel=tcg,gic-version=2" + "-cpu cortex-a57" + ]; + }; + + # VM boots up via qfw + boot.loader.grub.enable = false; + + services.tee-supplicant = { + enable = true; + # pkcs11 trusted application + trustedApplications = [ "${opteeQemuAarch64.devkit}/ta/fd02c9da-306c-48c7-a49c-bbd827ae86ee.ta" ]; + }; + }; + testScript = '' + machine.wait_for_unit("tee-supplicant.service") + out = machine.succeed("${pkgs.opensc}/bin/pkcs11-tool --module ${lib.getLib pkgs.optee-client}/lib/libckteec.so --list-token-slots") + if out.find("OP-TEE PKCS11 TA") < 0: + raise Exception("optee pkcs11 token not found") + ''; + } +)