Skip to content

Commit 1625a3b

Browse files
committed
jetson-orin: stabilize UEFI secure-boot flashing
Make the UEFI secure-boot flashing flow stable and ensure the certificate inputs are part of the remote build closure so cross-built flash scripts do not fail on remote builders. Signed-off-by: vadik likholetov <vadikas@gmail.com>
1 parent cd63df2 commit 1625a3b

File tree

10 files changed

+211
-15
lines changed

10 files changed

+211
-15
lines changed

docs/src/content/docs/ghaf/overview/arch/secureboot.mdx

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,3 +43,27 @@ efi-readvar -v PK
4343
efi-readvar -v KEK
4444
efi-readvar -v db
4545
```
46+
47+
## Jetson Orin signed flashing workflow
48+
49+
Jetson Orin targets produce two independent build artifacts in CI:
50+
51+
1. The flash script (`nix build .#nvidia-jetson-orin-agx-debug-from-x86_64-flash-script`) which orchestrates NVIDIA's flashing tools.
52+
2. The filesystem image (`nix build .#nvidia-jetson-orin-agx-debug-from-x86_64`) that contains the ESP and root partitions.
53+
54+
After the filesystem image is signed, pass its Nix store path directly to the flash helper:
55+
56+
```sh
57+
SIGNED_SD_IMAGE=$(nix path-info .#nvidia-jetson-orin-agx-debug-from-x86_64)
58+
./result/bin/flash-ghaf-host -s "$SIGNED_SD_IMAGE"
59+
```
60+
61+
The `-s/--signed-sd-image` flag extracts `BOOTAA64.EFI` and the kernel from the signed image, wires them into the flashing workdir, and launches NVIDIA's flashing script without requiring any additional staging directories or host key material.
62+
63+
The argument to `-s/--signed-sd-image` must be the signed image output directory (for example, the value returned by `nix path-info`), not the `*.img.zst` file itself. The directory is expected to contain `esp.offset`, `esp.size`, `root.offset`, and `root.size`, plus either `sd-image/*.img.zst` or `*.img.zst` at the top level. Passing the image file directly will fail with `Signed image directory not found: ...`.
64+
65+
Running `./result/bin/flash-ghaf-host` without `-s` clears signed-image overrides and flashes the standard unsigned image bundled with the build output.
66+
67+
For ad-hoc debugging you can also point `-s` to a copy of the signed build outside the Nix store (for example, `cp -a $(nix path-info …) /tmp/orin-signed` and then pass `/tmp/orin-signed`), which is useful when the original store path is unavailable on the flashing host.
68+
69+
For CI jobs that still need a deterministic artifact directory (for example when reusing the same signed files across multiple runs), use the extractor helper provided by `jetpack-nixos` and point `ghaf.hardware.nvidia.orin.flashScriptOverrides.signedArtifactsPath` at the staged directory.

flake.lock

Lines changed: 6 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

flake.nix

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@
133133
# Nvidia Orin support for NixOS
134134
jetpack-nixos = {
135135
#url = "github:anduril/jetpack-nixos";
136-
url = "github:tiiuae/jetpack-nixos/march-rebase";
136+
url = "github:vadika/jetpack-nixos/refactor/flash-signed-sd-image";
137137
inputs.nixpkgs.follows = "nixpkgs";
138138
};
139139

modules/reference/hardware/jetpack/nvidia-jetson-orin/default.nix

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
imports = [
77
./partition-template.nix
88
./jetson-orin.nix
9+
./secureboot.nix
910
./pci-passthrough-common.nix
1011
./virtualization
1112
./optee/optee.nix

modules/reference/hardware/jetpack/nvidia-jetson-orin/jetson-orin.nix

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,20 @@ in
273273
default = "";
274274
};
275275

276+
flashScriptOverrides.signedArtifactsPath = mkOption {
277+
description = ''
278+
Absolute path on the host that contains pre-signed Jetson Orin boot
279+
artifacts.
280+
281+
The flash script expects at least `BOOTAA64.EFI` and `Image` to be
282+
present in this directory. Optional files such as `initrd` or device
283+
trees can be staged as well. The directory can also be provided at
284+
runtime through the `SIGNED_ARTIFACTS_DIR` environment variable.
285+
'';
286+
type = types.nullOr types.str;
287+
default = null;
288+
};
289+
276290
somType = mkOption {
277291
description = "SoM config Type (NX|AGX32|AGX64|Nano)";
278292
type = types.str;
@@ -300,6 +314,7 @@ in
300314
};
301315

302316
config = mkIf cfg.enable {
317+
ghaf.hardware.nvidia.orin.secureboot.enable = lib.mkDefault true;
303318
hardware.nvidia-jetpack.firmware.eksFile = "${firmwareEkbImage}/eks_t234.img";
304319
hardware.nvidia-jetpack.kernel.version = "${cfg.kernelVersion}";
305320
nixpkgs.hostPlatform.system = "aarch64-linux";

modules/reference/hardware/jetpack/nvidia-jetson-orin/partition-template.nix

Lines changed: 70 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -147,14 +147,79 @@ let
147147
mkdir -pv "$WORKDIR/bootloader"
148148
rm -fv "$WORKDIR/bootloader/esp.img"
149149
150+
${lib.optionalString (cfg.flashScriptOverrides.signedArtifactsPath != null) ''
151+
if [ -z "''${SIGNED_ARTIFACTS_DIR:-}" ]; then
152+
SIGNED_ARTIFACTS_DIR=${lib.escapeShellArg cfg.flashScriptOverrides.signedArtifactsPath}
153+
fi
154+
''}
155+
156+
if [ -n "''${SIGNED_ARTIFACTS_DIR:-}" ]; then
157+
echo "Using signed artifacts from $SIGNED_ARTIFACTS_DIR"
158+
159+
for artifact in BOOTAA64.EFI Image; do
160+
if [ ! -f "$SIGNED_ARTIFACTS_DIR/$artifact" ]; then
161+
echo "ERROR: Missing $artifact in $SIGNED_ARTIFACTS_DIR" >&2
162+
exit 1
163+
fi
164+
done
165+
166+
export BOOTAA64_EFI="$SIGNED_ARTIFACTS_DIR/BOOTAA64.EFI"
167+
export KERNEL_IMAGE="$SIGNED_ARTIFACTS_DIR/Image"
168+
169+
if [ -f "$SIGNED_ARTIFACTS_DIR/initrd" ]; then
170+
export INITRD_IMAGE="$SIGNED_ARTIFACTS_DIR/initrd"
171+
fi
172+
173+
if [ -f "$SIGNED_ARTIFACTS_DIR/dtb" ]; then
174+
export DTB_IMAGE="$SIGNED_ARTIFACTS_DIR/dtb"
175+
fi
176+
fi
177+
178+
if [ -n "''${BOOTAA64_EFI:-}" ]; then
179+
if [ ! -f "$BOOTAA64_EFI" ]; then
180+
echo "ERROR: BOOTAA64_EFI not found: $BOOTAA64_EFI" >&2
181+
exit 1
182+
fi
183+
echo "Using external BOOTAA64.EFI: $BOOTAA64_EFI"
184+
cp -f "$BOOTAA64_EFI" "$WORKDIR/bootloader/BOOTAA64.efi"
185+
fi
186+
187+
if [ -n "''${KERNEL_IMAGE:-}" ]; then
188+
if [ ! -f "$KERNEL_IMAGE" ]; then
189+
echo "ERROR: KERNEL_IMAGE not found: $KERNEL_IMAGE" >&2
190+
exit 1
191+
fi
192+
echo "Using external kernel Image: $KERNEL_IMAGE"
193+
mkdir -pv "$WORKDIR/kernel"
194+
cp -f "$KERNEL_IMAGE" "$WORKDIR/kernel/Image"
195+
fi
196+
150197
${lib.optionalString (!cfg.flashScriptOverrides.onlyQSPI) ''
198+
image_source_root=${lib.escapeShellArg (toString images)}
199+
200+
if [ -n "''${SIGNED_SD_IMAGE_DIR:-}" ]; then
201+
if [ ! -d "$SIGNED_SD_IMAGE_DIR" ]; then
202+
echo "ERROR: SIGNED_SD_IMAGE_DIR not found: $SIGNED_SD_IMAGE_DIR" >&2
203+
exit 1
204+
fi
205+
image_source_root="$SIGNED_SD_IMAGE_DIR"
206+
fi
207+
151208
# Read partition offsets and sizes from sdImage metadata
152-
ESP_OFFSET=$(cat "${images}/esp.offset")
153-
ESP_SIZE=$(cat "${images}/esp.size")
154-
ROOT_OFFSET=$(cat "${images}/root.offset")
155-
ROOT_SIZE=$(cat "${images}/root.size")
209+
ESP_OFFSET=$(cat "$image_source_root/esp.offset")
210+
ESP_SIZE=$(cat "$image_source_root/esp.size")
211+
ROOT_OFFSET=$(cat "$image_source_root/root.offset")
212+
ROOT_SIZE=$(cat "$image_source_root/root.size")
213+
214+
img=$(find "$image_source_root" -maxdepth 1 -name '*.img.zst' -print -quit)
215+
if [ -z "$img" ]; then
216+
img=$(find "$image_source_root/sd-image" -maxdepth 1 -name '*.img.zst' -print -quit 2>/dev/null || true)
217+
fi
218+
if [ -z "$img" ]; then
219+
echo "ERROR: No .img.zst found in $image_source_root/sd-image or $image_source_root" >&2
220+
exit 1
221+
fi
156222
157-
img="${images}/sd-image/${config.image.fileName}"
158223
echo "Source image: $img"
159224
echo "ESP: offset=$ESP_OFFSET sectors, size=$ESP_SIZE sectors"
160225
echo "Root: offset=$ROOT_OFFSET sectors, size=$ROOT_SIZE sectors"
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
# SPDX-FileCopyrightText: 2022-2026 TII (SSRC) and the Ghaf contributors
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
{
5+
config,
6+
lib,
7+
pkgs,
8+
...
9+
}:
10+
let
11+
cfg = config.ghaf.hardware.nvidia.orin.secureboot;
12+
13+
eslFromCert =
14+
name: cert:
15+
pkgs.runCommand name
16+
{
17+
nativeBuildInputs = [ pkgs.buildPackages.efitools ];
18+
certPath = cert;
19+
}
20+
''
21+
if [ ! -s "$certPath" ]; then
22+
echo "Missing or empty UEFI secure boot certificate: $certPath" >&2
23+
exit 1
24+
fi
25+
26+
${pkgs.buildPackages.efitools}/bin/cert-to-efi-sig-list "$certPath" "$out"
27+
28+
if [ "$(wc -c < "$out")" -le 44 ]; then
29+
echo "Generated ESL ${name} from $certPath is empty" >&2
30+
exit 1
31+
fi
32+
'';
33+
34+
keysDir = cfg.keysSource;
35+
36+
requiredCertFiles = [
37+
(keysDir + "/PK.crt")
38+
(keysDir + "/KEK.crt")
39+
(keysDir + "/db.crt")
40+
];
41+
42+
pkEsl = eslFromCert "PK.esl" (keysDir + "/PK.crt");
43+
kekEsl = eslFromCert "KEK.esl" (keysDir + "/KEK.crt");
44+
dbEsl = eslFromCert "db.esl" (keysDir + "/db.crt");
45+
in
46+
{
47+
options.ghaf.hardware.nvidia.orin.secureboot = {
48+
enable = lib.mkEnableOption "UEFI Secure Boot key enrollment for Jetson Orin";
49+
50+
keysSource = lib.mkOption {
51+
type = lib.types.path;
52+
default = ../../../../secureboot/keys;
53+
description = "Directory containing PK.crt, KEK.crt and db.crt used to generate ESLs.";
54+
};
55+
};
56+
57+
config = lib.mkIf cfg.enable {
58+
assertions = map (certFile: {
59+
assertion = builtins.pathExists certFile;
60+
message = "Missing UEFI secure boot certificate `${toString certFile}`. Set `ghaf.hardware.nvidia.orin.secureboot.keysSource` to a directory containing `PK.crt`, `KEK.crt`, and `db.crt`.";
61+
}) requiredCertFiles;
62+
63+
hardware.nvidia-jetpack.firmware.uefi.secureBoot = {
64+
enrollDefaultKeys = true;
65+
defaultPkEslFile = pkEsl;
66+
defaultKekEslFile = kekEsl;
67+
defaultDbEslFile = dbEsl;
68+
};
69+
};
70+
}

modules/secureboot/keys/PK.crt

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
-----BEGIN CERTIFICATE-----
2+
MIIDNjCCAh6gAwIBAgIUCVyaeK6BQFa6zWAXk9L3nVY85SgwDQYJKoZIhvcNAQEL
3+
BQAwMzELMAkGA1UEBhMCRkkxDTALBgNVBAoMBEdoYWYxFTATBgNVBAMMDEdoYWYg
4+
VUVGSSBQSzAeFw0yNjAyMTYxMDI4MTZaFw0zNjAyMTQxMDI4MTZaMDMxCzAJBgNV
5+
BAYTAkZJMQ0wCwYDVQQKDARHaGFmMRUwEwYDVQQDDAxHaGFmIFVFRkkgUEswggEi
6+
MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDC9o1um1Mc/5/beeDITHdUTiPV
7+
BhAf8hTVEonNBqhrvn6iyZJzrKreYjsan4/7KON25Im+5iNpb3HpuNrOjQr0i6G8
8+
tzNUq0p/FMRJrHObMbI5m6DtgqL0YgtuSdaPFADyvVPc49hbReGJXmmbwpScVDXJ
9+
A6j1uDAymftLLSv7k582fbTvuO57Vq1781A+TrUuCtmmQUH+taFpQmqvPcq/pjoL
10+
8epVy4qhlhPcoobx/0GPyWjyGgOHq79qTkUiF7WOd3BnlWKMXTwuJ6dmZJ7Lg6YL
11+
wOTWdjBvWNaZEfl1K3RTIb6Jd4dqBJyrRWJGXAWlk1YEG0lPa8ioIFf1LjhlAgMB
12+
AAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQW
13+
BBTYB3z9cFazEXgEAqbh5aNfsYJWqDANBgkqhkiG9w0BAQsFAAOCAQEAwi8N1fBU
14+
O90XVTqYY/JE6fYFY3monLNYzCOZf9aOF9g6o2HAESdUvRmygqfUGoyEBJyRVvnK
15+
RYJJzCr6CX4lMFl091K8sqa5gXjm+Jub9y7OwxEpu1/QVS2iI5qJM2gjenVMBruv
16+
sC5WBPnVg1jyYXBMxtKa/uQ/fny022Pcaxqxlw7PWkljLZVAT0IJ/PRh2+Soelwt
17+
xPv9cm+n2kbxv69IZayS6iQWAWcXWToupEkrWGx8s8uNQHQXofAq0PNQEhc88kjP
18+
mnAAO0BkEvjRrvGFQC1y3LG6iLD6EKa1afXnbk4NdH2lzavA+XVxoyihFmk8QN/P
19+
Rx3srFWDfvhStA==
20+
-----END CERTIFICATE-----

modules/secureboot/keys/README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
1-
Generated from `tiiuae/ghaf-infra-pki` `yubi-uefi` artifacts at commit `e1a50f184b8ca7bba34f61f296b38ec870aaf21d`.
1+
Generated from `tiiuae/ghaf-infra-pki` `yubi-uefi` artifacts at commit `56d288c3a65945420086c48449f7eb0331eb1b37`.
22

33
Imported files:
44
- `PK.auth` sha256 `a7dd8d62169ce4a259296cd1e9c619f76310ae5fe56811311cb89437b1335215`
55
- `KEK.auth` sha256 `6fad4e13e9d71794225dbe9137038d6e153f23a5714cf39b71395c5bee08d713`
66
- `db.auth` sha256 `f1bb5578afff87b0c45fe27184cb27b77a65b8ac9cee0ac8e713719cab36509f`
7+
- `PK.crt` sha256 `0708ef65cd8b7b03782d047971a65e32f3f3f848594a4ed5e425f80c20305a43`
78
- `KEK.crt` sha256 `0cdf80e3b8c67a137909b62b0897681c7f37fe94dd8788ad5aa8d0e16966b849`
89
- `db.crt` sha256 `bc2adf26326de4097d9985351be416197423db4c829152e94d21e13afc579c00`
910

1011
Certificate fingerprints:
12+
- `PK.crt` sha256 `68:FB:46:A5:2B:03:9A:7D:37:B9:7B:C3:94:13:CD:57:F8:A5:05:FF:2F:84:D2:F8:4A:73:C0:58:98:BC:59:2F`
1113
- `KEK.crt` sha256 `E3:C7:43:B3:06:9A:2B:4B:4B:5F:88:99:BB:C7:CE:9F:84:DF:94:06:E1:28:CD:DA:06:7A:FD:81:EF:34:24:15`
1214
- `db.crt` sha256 `B4:CB:12:37:1F:EF:29:A3:F4:2A:48:80:1C:24:E6:51:49:C5:81:06:0C:F9:42:18:9A:FA:A2:45:FD:6B:C9:3F`

targets/nvidia-jetson-orin/flake-module.nix

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -179,8 +179,7 @@ in
179179
builtins.listToAttrs (map (t: lib.nameValuePair t.name t.package) crossTargets)
180180
// builtins.listToAttrs (
181181
map (
182-
t:
183-
lib.nameValuePair "${t.name}-flash-script" t.hostConfiguration.pkgs.nvidia-jetpack.legacyFlashScript
182+
t: lib.nameValuePair "${t.name}-flash-script" t.hostConfiguration.pkgs.nvidia-jetpack.flashScript
184183
) crossTargets
185184
)
186185
// builtins.listToAttrs (

0 commit comments

Comments
 (0)