Compare commits

...

12 Commits

Author SHA1 Message Date
Emily
0dc3e4f7eb testSignedPackages.shim-signed: init
This signs the shim with the same vendor certificate that gets embedded
in the shim, which is not what you want for supporting Microsoft Secure
Boot keys. The Microsoft signature will require different handling in
future work, and is blocked on compliance anyway, but this is still
useful for having a uniform bootloader chain and MOK handling.
2026-08-14 09:12:30 +01:00
Emily
cbfabf3690 testSignedPackages.systemd-boot-signed: init 2026-08-14 09:12:30 +01:00
Emily
b679c44d3c testSignedPackages.fwupd-efi-signed: init 2026-08-14 09:12:30 +01:00
Emily
b200783799 testSignedPackages: init 2026-08-14 09:12:30 +01:00
Emily
e96622b122 mkSignedPackages: init 2026-08-14 09:12:30 +01:00
Emily
6c62ab4d6b authenticodeCheckHook: init 2026-08-14 09:12:30 +01:00
Emily
dbbb241a34 fwupd-efi: add description 2026-08-14 09:12:29 +01:00
Emily
412750b3c7 fwupd-efi: inherit metadata from fwupd 2026-08-14 09:12:29 +01:00
Emily
7ee25ddbc3 fwupd-efi: add boot security team to maintainers 2026-08-14 09:12:29 +01:00
Emily
088c7d64cb shim-unsigned: add boot security team to maintainers 2026-08-14 09:12:29 +01:00
Emily
f3b80ee197 autopen: init at 0.2.0 2026-08-14 09:12:29 +01:00
Emily
9acceb309f maintainers/team-list: add boot security team 2026-08-14 09:12:29 +01:00
21 changed files with 1301 additions and 4 deletions

View File

@@ -526,3 +526,7 @@ pkgs/by-name/wa/warp-terminal/ @emilytrau @imadnyc @4evy @johnrtitor
/nixos/lib/testing @NixOS/test-driver
/nixos/tests/nixos-test-driver @NixOS/test-driver
/nixos/modules/virtualisation/nspawn-container/run-nspawn @NixOS/test-driver
# Boot security
/pkgs/by-name/au/autopen @NixOS/boot-security
/pkgs/misc/signed-packages @NixOS/boot-security

View File

@@ -91,6 +91,10 @@ with lib.maintainers;
shortName = "Blockchains";
};
boot-security = {
github = "boot-security";
};
budgie = {
members = [
bobby285271

View File

@@ -0,0 +1,21 @@
{
lib,
makeSetupHook,
pesign,
}:
makeSetupHook {
name = "authenticode-check-hook";
substitutions = {
pesigcheck = lib.getExe' pesign "pesigcheck";
};
__structuredAttrs = true;
meta = {
description = "Setup hook for verifying Authenticode signatures";
inherit (pesign.meta) platforms;
teams = [ lib.teams.boot-security ];
};
} ./setup-hook.bash

View File

@@ -0,0 +1,41 @@
isPE() {
local fd
local magic
exec {fd}< "$1"
LANG=C read -r -n 2 -u "$fd" magic
exec {fd}<&-
if [[ $magic == MZ ]]; then
# Lets just assume this isnt a DOS executable…
return 0
else
return 1
fi
}
authenticodeCheckHook() {
local excludeFlags=()
for pattern in "${authenticodeCheckExclude[@]}"; do
excludeFlags+=(
-a '!' '(' -name "$pattern" -o -wholename "$prefix/$pattern" ')'
)
done
local checked=
while read -rd '' file; do
if isPE "$file"; then
checked=1
"@pesigcheck@" \
--no-system-db=0 \
--certfile="$authenticodeCertificate" \
--in="$file"
fi
done < <(find -L -- "$prefix" -type f "${excludeFlags[@]}" -print0)
if [[ -z $checked ]]; then
nixErrorLog 'no PE files found'
exit 1
fi
}
fixupOutputHooks+=(authenticodeCheckHook)

View File

@@ -0,0 +1,170 @@
{
lib,
buildPackages,
autopen,
}:
let
inherit (lib)
concatMapStringsSep
escapeURL
extendMkDerivation
getLib
splitString
unsafeGetAttrPos
;
inherit (autopen.lib)
sign
;
inherit (autopen.lib.internal)
mkCliDerivationBuilder
;
inherit (autopen.lib.authenticode)
attachSignature
mkSignedAttrsForPe
;
mkSystemdSbsignDerivation = mkCliDerivationBuilder {
package = getLib buildPackages.systemd;
exe = "${getLib buildPackages.systemd}/lib/systemd/systemd-sbsign";
attrPrefix = "systemdSbsign";
};
escapeURLPath = path: concatMapStringsSep "/" escapeURL (splitString "/" path);
in
{
mkSignedAttrsForPe = extendMkDerivation {
constructDrv = mkSystemdSbsignDerivation;
extendDrvArgs =
finalAttrs:
{
pname,
version,
certificate,
peFile,
pos ? unsafeGetAttrPos "pname" args,
...
}@args:
{
name = "${pname}-${version}-${baseNameOf peFile}.signed-attrs.der";
systemdSbsignArgs = [
"sign"
finalAttrs.certificateArgs
{
prepareOfflineSigning = true;
output = placeholder "out";
}
peFile
];
# `systemd-sbsign(1)` expects a PEMencoded certificate, but
# autopen produces DER-encoded certificates. We explicitly
# use the default OpenSSL provider, which takes `file://`
# URLs and accepts both encodings.
certificateArgs = {
certificateSource = "provider:default";
certificate = "file://${escapeURLPath "${certificate}"}";
};
certificateNotBefore = certificate.certificateParams.notBefore;
preSystemdSbsign = ''
export SOURCE_DATE_EPOCH="$(date --date="$certificateNotBefore" +%s)"
'';
inherit pos;
};
};
attachSignature = extendMkDerivation {
constructDrv = mkSystemdSbsignDerivation;
extendDrvArgs =
finalAttrs:
{
pname,
version,
signature,
passthru ? { },
pos ? unsafeGetAttrPos "pname" args,
...
}@args:
let
signedAttrs = signature.message;
in
{
name = "${pname}-${version}-${baseNameOf signedAttrs.peFile}.signed";
systemdSbsignArgs = [
"sign"
signedAttrs.certificateArgs
{
signedData = signedAttrs;
signedDataSignature = signature;
output = placeholder "out";
}
signedAttrs.peFile
];
passthru = {
inherit (signedAttrs) certificate peFile;
inherit signedAttrs;
}
// passthru;
inherit pos;
};
};
mkSignedPe = extendMkDerivation {
constructDrv = attachSignature;
# Ensure that the signing key doesnt leak from the derivation.
excludeDrvArgNames = [ "signingKey" ];
extendDrvArgs =
finalAttrs:
{
pname,
version,
signingKey,
certificate,
peFile,
pos ? unsafeGetAttrPos "pname" args,
meta ? { },
...
}@args:
{
signature = sign {
inherit signingKey;
message = mkSignedAttrsForPe {
inherit
pname
version
certificate
peFile
pos
;
meta = meta // {
${if meta ? description then "description" else null} = "${meta.description} (to be signed)";
};
};
inherit pos;
meta = meta // {
${if meta ? description then "description" else null} = "${meta.description} (signature)";
};
};
inherit pos;
};
};
}

View File

@@ -0,0 +1,9 @@
{ callPackage }:
{
internal = callPackage ./internal.nix { };
signingKey = callPackage ./signing-key.nix { };
sign = callPackage ./sign.nix { };
x509 = callPackage ./x509.nix { };
authenticode = callPackage ./authenticode.nix { };
}

View File

@@ -0,0 +1,148 @@
{
lib,
stdenvNoCC,
autopen,
}:
let
inherit (lib)
concatMap
concatMapStringsSep
extendMkDerivation
isAttrs
isDerivation
match
splitStringBy
substring
toLower
toUpper
;
inherit (lib.generators)
mkValueStringDefault
;
inherit (lib.cli)
toCommandLine
;
inherit (autopen.lib.internal)
mkCliDerivationBuilder
;
splitCamelCase = splitStringBy (_prev: curr: match "[A-Z]" curr != null) true;
toKebabCase = camelCase: concatMapStringsSep "-" toLower (splitCamelCase camelCase);
optionFormat = optionName: {
option = "--${toKebabCase optionName}";
sep = "=";
explicitBool = false;
};
in
{
mkCliDerivationBuilder =
{
package,
exe,
attrPrefix,
}:
extendMkDerivation {
constructDrv = stdenvNoCC.mkDerivation;
extendDrvArgs =
finalAttrs:
{
nativeBuildInputs ? [ ],
...
}@args:
{
nativeBuildInputs = [ package ] ++ nativeBuildInputs;
buildCommand = ''
runHook "pre$hookName"
echoCmd "$exeName flags" "''${exeFlags[@]}"
"$exe" "''${exeFlags[@]}"
runHook "post$hookName"
'';
inherit exe;
exeName = baseNameOf exe;
exeFlags = concatMap (
component:
if isAttrs component && !isDerivation component then
toCommandLine optionFormat component
else
[ (mkValueStringDefault { } component) ]
) args."${attrPrefix}Args";
hookName = toUpper (substring 0 1 attrPrefix) + substring 1 (-1) attrPrefix;
strictDeps = true;
__structuredAttrs = true;
};
};
mkAutopenDerivation = mkCliDerivationBuilder {
package = autopen;
exe = "autopen";
attrPrefix = "autopen";
};
/**
Hide a derivations internals.
This is used to abstract away implementation details so that
secret capabilities used at build time dont trivially leak out of
a derivation to consumers of its outputs.
Note that pulling `drv.drvPath` pulls in the transitive build
dependency closure of `drv`, including built outputs, so this is
not foolproof. Hiding `drvPath` wouldnt solve this, as any
derivation that uses the output of `drv` would itself have a
`drvPath` that behaves the same way. Therefore, this should
unfortunately be considered a besteffort approach under current
Nix semantics.
# Inputs
`drv`
: The derivation to hide the internals of.
# Type
```
hideDerivation :: Derivation -> Derivation
```
*/
hideDerivation =
drv:
assert isDerivation drv && drv.outputs == [ "out" ];
let
hiddenDrv = {
inherit (drv)
type
name
system
outPath
drvPath
outputs
outputName
strictDeps
__structuredAttrs
passthru
meta
;
out = hiddenDrv;
all = [ hiddenDrv ];
}
// drv.passthru;
in
hiddenDrv;
}

View File

@@ -0,0 +1,76 @@
{
lib,
autopen,
}:
let
inherit (lib)
unsafeGetAttrPos
;
inherit (autopen.lib.internal)
hideDerivation
mkAutopenDerivation
;
in
/**
Sign a message with a signing key.
# Inputs
`signingKey`
: The signing key to use.
`message`
: The path to the message to sign.
`pos` (optional)
: The position for the signature derivation.
`meta` (optional)
: The metadata for the signature derivation.
# Type
```
sign ::
{
signingKey :: SigningKey,
message :: StorePath,
pos :: { file :: String, line :: Int } | Null,
meta :: AttrSet,
} -> Derivation
```
*/
{
signingKey,
message,
pos ? unsafeGetAttrPos "message" args,
meta ? { },
}@args:
hideDerivation (mkAutopenDerivation {
name = "${message.name}.sig";
inherit signingKey message;
autopenArgs = [
"sign"
{
inherit signingKey;
output = placeholder "out";
}
message
];
# Keys shouldnt propagate to outputs.
allowedRequisites = [ "out" ];
passthru = {
# TODO: This is technically a little strange in terms of the
# cryptographic semantics, but its convenient.
inherit message;
};
inherit pos meta;
})

View File

@@ -0,0 +1,242 @@
{
lib,
autopen,
}:
let
inherit (lib)
hashString
unsafeGetAttrPos
;
inherit (autopen.lib.internal)
hideDerivation
mkAutopenDerivation
;
/**
Produce a fake derivation object with a given `outPath`.
This differs from `lib.toDerivation` in that it does not depend on
`storePaths`.
# Inputs
`outPath`
: The output path for the derivation.
`attrs`
: Any additional attributes to include in the derivation.
# Type
```
fakeDerivation :: String -> AttrSet -> Derivation
```
*/
fakeDerivation =
outPath: attrs:
let
drv = {
type = "derivation";
outputs = [ "out" ];
out = drv;
all = [ drv ];
outputName = "out";
inherit outPath;
}
// attrs;
in
drv;
in
{
/**
Import a signing key from an existing path.
::: {.warning}
The contents of the path will be copied into the store; **this is
insecure to use with software keys**.
Outside of testing, you should use remote keys that do not
contain private key material, likely through
`autopen.lib.signingKey.remote`.
:::
# Inputs
`name`
: The name to use for the signing key derivation.
`path`
: The path containing the signing key.
`pos` (optional)
: The position for the signing key derivation.
`meta` (optional)
: The metadata for the signing key derivation.
# Type
```
import ::
{
name :: String,
path :: Path | Derivation,
pos :: { file :: String, line :: Int } | Null,
meta :: AttrSet,
} -> SigningKey
```
*/
import =
{
name,
path,
pos ? unsafeGetAttrPos "name" args,
meta ? { },
}@args:
let
signingKey = fakeDerivation "${path}" {
inherit name verificationKey;
meta = meta // {
${if pos != null then "position" else null} = "${pos.file}:${toString pos.line}";
};
};
verificationKey = hideDerivation (mkAutopenDerivation {
name = "${name}-verification-key";
autopenArgs = [
"signing-key"
"get-verification-key"
{
inherit signingKey;
output = placeholder "out";
}
];
inherit pos;
meta = meta // {
${if meta ? description then "description" else null} = "${meta.description} (verification key)";
};
});
in
signingKey;
/**
Create a remote signing key.
These are stubs that reference signing keys accessible through
a remote server (see `autopen signing-key remote` and
`autopen serve`).
# Inputs
`name`
: The name to use for the signing key derivation.
`socketPath` (optional, default: `"/run/autopen/socket"`)
: The path to the autopen servers Unix socket inside the Nix
build environment.
`verificationKey`
: The path to the verification key file corresponding to the
signing key.
`pos` (optional)
: The position for the signing key derivation.
`meta` (optional)
: The metadata for the signing key derivation.
# Type
```
remote ::
{
name :: String,
socketPath :: String,
verificationKey :: VerificationKey,
pos :: { file :: String, line :: Int } | Null,
meta :: AttrSet,
} -> SigningKey
```
*/
remote =
{
name,
socketPath ? "/run/autopen/socket",
verificationKey,
pos ? unsafeGetAttrPos "name" args,
meta ? { },
}@args:
let
verificationKey = fakeDerivation "${args.verificationKey}" {
name = "${name}-verification-key";
meta = meta // {
${if meta ? description then "description" else null} = "${meta.description} (verification key)";
${if pos != null then "position" else null} = "${pos.file}:${toString pos.line}";
};
};
# We need a store path to use as a file reference for the
# remote key.
#
# Ideally, this would be an unforgeable capability
# passed down from the builders autopen configuration. The
# best we can do with Nix as it exists is to create a store
# path that is stable and unique for a given remote key
# configuration.
#
# The fundamental property this ensures is that derivations
# that dont include this store path in their buildtime
# closure cannot use the corresponding key. This preserves the
# fundamental guarantees of the Nix model, and lets us expose
# signing capabilities inside the build sandbox without letting
# arbitrary packages with compromised upstreams sign anything.
#
# We cant stop derivations that shouldnt have
# access to this from reconstructing it independently for a
# given key configuration, but this and the `drvPath` hole can
# be detected by CI. In any case, this is more a matter of
# defenceindepth; the capability model of autopen is not
# intended as a strong protection against a compromise of
# Nixpkgs itself.
#
# We use an empty directory here, as files can could be subject
# to a hardlinking attack via store optimization.
fileRefPath = builtins.path {
path = ./.;
name = "${name}-key-handle-${hashString "sha256" "${verificationKey}"}";
filter = _: _: false;
};
in
mkAutopenDerivation {
name = "${name}-signing-key";
autopenArgs = [
"signing-key"
"remote"
"create"
{
inherit socketPath fileRefPath verificationKey;
output = placeholder "out";
}
];
allowedRequisites = [
"out"
fileRefPath
];
passthru = {
inherit socketPath fileRefPath verificationKey;
};
inherit pos meta;
};
}

View File

@@ -0,0 +1,138 @@
{
lib,
autopen,
}:
let
inherit (lib)
extendMkDerivation
unsafeGetAttrPos
;
inherit (autopen.lib)
sign
;
inherit (autopen.lib.internal)
mkAutopenDerivation
;
inherit (autopen.lib.x509)
attachSignature
mkTbsCertificateForSelfSigning
;
in
{
mkTbsCertificateForSelfSigning = extendMkDerivation {
constructDrv = mkAutopenDerivation;
extendDrvArgs =
finalAttrs:
{
name,
passthru ? { },
pos ? unsafeGetAttrPos "name" args,
...
}@args:
{
name = "${name}.tbs-certificate.der";
autopenArgs = [
"x509"
"create-tbs-certificate"
finalAttrs.certificateParams
{ output = placeholder "out"; }
];
passthru = {
inherit (finalAttrs.certificateParams) verificationKey;
}
// passthru;
inherit pos;
};
};
attachSignature = extendMkDerivation {
constructDrv = mkAutopenDerivation;
extendDrvArgs =
finalAttrs:
{
name,
signature,
passthru ? { },
pos ? unsafeGetAttrPos "name" args,
...
}@args:
let
tbsCertificate = signature.message;
in
{
name = "${name}.cer";
autopenArgs = [
"x509"
"create-certificate"
tbsCertificate.certificateParams
{
inherit signature;
output = placeholder "out";
}
];
passthru = {
inherit (tbsCertificate) verificationKey certificateParams;
inherit tbsCertificate signature;
}
// passthru;
inherit pos;
};
};
mkSelfSignedCertificate = extendMkDerivation {
constructDrv = attachSignature;
# Ensure that the signing key doesnt leak from the derivation.
excludeDrvArgNames = [ "signingKey" ];
extendDrvArgs =
finalAttrs:
{
name,
signingKey,
certificateParams,
pos ? unsafeGetAttrPos "name" args,
meta ? { },
...
}@args:
{
signature = sign {
inherit signingKey;
message = mkTbsCertificateForSelfSigning {
inherit name;
certificateParams = certificateParams // {
inherit (signingKey) verificationKey;
};
inherit pos;
meta = meta // {
${if meta ? description then "description" else null} = "${meta.description} (to be signed)";
};
};
inherit pos;
meta = meta // {
${if meta ? description then "description" else null} = "${meta.description} (signature)";
};
};
inherit pos meta;
};
};
}

View File

@@ -0,0 +1,62 @@
{
lib,
callPackage,
stdenv,
rustPlatform,
fetchFromGitHub,
capnproto,
autopen,
}:
rustPlatform.buildRustPackage (finalAttrs: {
pname = "autopen";
version = "0.2.0";
src = fetchFromGitHub {
owner = "emilazy";
repo = "autopen";
tag = "v${finalAttrs.version}";
hash = "sha256-7/uAwpNNQByKAjrpr6R40dkVWg5t15bqLD4KJNT53wI=";
};
cargoHash = "sha256-baV0suVBCgV/gFnAD5uo6fpfQg/CYreyFgsiEGTmH3A=";
nativeBuildInputs = [
capnproto
];
useNextest = true;
cargoTestFlags = [ "--max-fail=all" ];
strictDeps = true;
__structuredAttrs = true;
passthru = {
lib = callPackage ./lib { };
mkTest = callPackage ./tests { };
testSigningKey = autopen.lib.signingKey.import {
name = "autopen-test-rsa3072-pkcs1-sha256";
path = ./tests/test-rsa3072-pkcs1-sha256-signing-key.bin;
};
tests = {
softwareKey = autopen.mkTest {
signingKey = autopen.testSigningKey;
};
};
};
meta = {
description = "Cryptographic signing tool with an objectcapability interface";
homepage = "https://github.com/emilazy/autopen";
license = lib.licenses.blueOak100;
sourceProvenance = [ lib.sourceTypes.fromSource ];
teams = [ lib.teams.boot-security ];
mainProgram = "autopen";
platforms = lib.platforms.unix;
};
})

View File

@@ -0,0 +1,83 @@
{
lib,
stdenvNoCC,
writeText,
autopen,
testSignedPackages,
linkFarm,
runCommand,
openssl_4_0,
}:
{
signingKey,
}:
let
message = writeText "autopen-test-message" ''
squeamish ossifrage
'';
signature = autopen.lib.sign {
inherit signingKey message;
};
signedPackages = testSignedPackages.override {
uefiSigningKey = signingKey;
};
in
linkFarm "autopen-test" (
{
inherit signingKey;
inherit (signingKey) verificationKey;
inherit message signature;
signature-check =
runCommand "autopen-test-signature-check"
{
nativeBuildInputs = [
autopen
];
inherit (signingKey) verificationKey;
inherit signature message;
strictDeps = true;
__structuredAttrs = true;
}
''
autopen verify \
--verification-key="$verificationKey" \
--signature="$signature" \
-- "$message"
touch -- "$out"
'';
certificate-check =
runCommand "autopen-test-certificate-check"
{
nativeBuildInputs = [
# Versions prior to 4.0 suffer from
# <https://github.com/openssl/openssl/issues/15124>…
openssl_4_0
];
inherit (signedPackages) uefiCertificate;
strictDeps = true;
__structuredAttrs = true;
}
''
exec &> >(tee -- "$out")
openssl asn1parse -in "$uefiCertificate" -inform DER -i
openssl x509 -in "$uefiCertificate" -noout -text
openssl verify \
-verbose \
-CAfile "$uefiCertificate" \
-attime "$(date --date=1970-01-01T23:59:59Z +%s)" \
-check_ss_sig \
-x509_strict \
-- "$uefiCertificate"
'';
}
// lib.optionalAttrs stdenvNoCC.hostPlatform.isLinux (
lib.filterAttrs (_: lib.isDerivation) signedPackages
)
)

View File

@@ -8,6 +8,7 @@
gnu-efi,
python3,
python3Packages,
fwupd,
}:
stdenv.mkDerivation (finalAttrs: {
@@ -52,9 +53,13 @@ stdenv.mkDerivation (finalAttrs: {
];
meta = {
homepage = "https://fwupd.org/";
maintainers = [ ];
license = lib.licenses.lgpl21Plus;
platforms = lib.platforms.linux;
description = "EFI Application used by uefi-capsule plugin in fwupd";
inherit (fwupd.meta)
homepage
maintainers
license
platforms
;
teams = [ lib.teams.boot-security ];
};
})

View File

@@ -74,5 +74,6 @@ stdenv.mkDerivation (finalAttrs: {
maintainers = with lib.maintainers; [
baloo
];
teams = [ lib.teams.boot-security ];
};
})

View File

@@ -0,0 +1,57 @@
{
stdenvNoCC,
lndir,
authenticodeCheckHook,
fwupd-efi,
autopen,
uefiSigningKey,
uefiCertificate,
}:
stdenvNoCC.mkDerivation (finalAttrs: {
pname = "${finalAttrs.unsigned.pname}-signed";
inherit (finalAttrs.unsigned) version;
dontUnpack = true;
dontBuild = true;
nativeBuildInputs = [
lndir
authenticodeCheckHook
];
authenticodeCertificate = uefiCertificate;
unsigned = fwupd-efi;
pePath = "libexec/fwupd/efi/fwupd${stdenvNoCC.hostPlatform.efiArch}.efi";
signedPe = autopen.lib.authenticode.mkSignedPe {
inherit (finalAttrs.unsigned) pname version;
signingKey = uefiSigningKey;
certificate = uefiCertificate;
peFile = "${finalAttrs.unsigned}/${finalAttrs.pePath}";
};
installPhase = ''
runHook preInstall
mkdir -p -- "$out/lib/pkgconfig"
substitute \
"$unsigned/lib/pkgconfig/fwupd-efi.pc" \
"$out/lib/pkgconfig/fwupd-efi.pc" \
--replace-fail "$unsigned" "$out"
lndir "$unsigned" "$out"
ln -sf -- "$signedPe" "$out/$pePath"
runHook postInstall
'';
strictDeps = true;
__structuredAttrs = true;
meta = fwupd-efi.meta // {
description = "${fwupd-efi.meta.description} (signed)";
};
})

View File

@@ -0,0 +1,67 @@
{
lib,
stdenvNoCC,
lndir,
authenticodeCheckHook,
shim-unsigned,
autopen,
uefiSigningKey,
uefiCertificate,
}:
stdenvNoCC.mkDerivation (finalAttrs: {
pname = "${finalAttrs.unsigned.pname}-signed";
inherit (finalAttrs.unsigned) version;
dontUnpack = true;
dontBuild = true;
nativeBuildInputs = [
lndir
authenticodeCheckHook
];
authenticodeCertificate = uefiCertificate;
unsigned = shim-unsigned.override {
vendorCertFile = uefiCertificate;
defaultLoader = "\\\\systemd-boot${stdenvNoCC.hostPlatform.efiArch}.efi";
};
signedPes =
lib.genAttrs
[
finalAttrs.unsigned.target
finalAttrs.unsigned.mokManagerTarget
finalAttrs.unsigned.fallbackTarget
]
(
peName:
autopen.lib.authenticode.mkSignedPe {
inherit (finalAttrs.unsigned) pname version;
signingKey = uefiSigningKey;
certificate = uefiCertificate;
peFile = "${finalAttrs.unsigned}/share/shim/${peName}";
}
);
installPhase = ''
runHook preInstall
mkdir -- "$out"
lndir "$unsigned" "$out"
for peName in "''${!signedPes[@]}"; do
ln -sf -- "''${signedPes[$peName]}" "$out/share/shim/$peName"
done
runHook postInstall
'';
strictDeps = true;
__structuredAttrs = true;
meta = shim-unsigned.meta // {
description = "${shim-unsigned.meta.description} (signed)";
};
})

View File

@@ -0,0 +1,67 @@
{
lib,
stdenvNoCC,
autopen,
lndir,
authenticodeCheckHook,
systemd,
uefiSigningKey,
uefiCertificate,
}:
stdenvNoCC.mkDerivation (finalAttrs: {
pname = "systemd-boot-signed";
inherit (finalAttrs.unsigned) version;
dontUnpack = true;
dontBuild = true;
nativeBuildInputs = [
lndir
authenticodeCheckHook
];
authenticodeCertificate = uefiCertificate;
authenticodeCheckExclude = [
# UKIs and addons are signed as a whole, not per stub.
"lib/systemd/boot/efi/*.stub"
];
unsigned = systemd;
pePath = "lib/systemd/boot/efi/systemd-boot${stdenvNoCC.hostPlatform.efiArch}.efi";
signedPe = autopen.lib.authenticode.mkSignedPe {
inherit (finalAttrs.unsigned) pname version;
signingKey = uefiSigningKey;
certificate = uefiCertificate;
peFile = "${finalAttrs.unsigned}/${finalAttrs.pePath}";
};
installPhase = ''
runHook preInstall
mkdir -p $out/lib/systemd/boot/efi
lndir {"$unsigned","$out"}/lib/systemd/boot/efi
ln -sf "$signedPe" "$out/$pePath"
runHook postInstall
'';
strictDeps = true;
__structuredAttrs = true;
meta = {
description = "A simple UEFI boot manager (signed)";
inherit (systemd.meta)
homepage
license
platforms
badPlatforms
identifiers
;
teams = systemd.meta.teams ++ [ lib.teams.boot-security ];
};
})

View File

@@ -0,0 +1,62 @@
let
autoCalledPackages = import ../../top-level/by-name-overlay.nix ./by-name;
in
{
lib,
newScope,
}:
{
uefiSigningKey,
uefiCertificate,
}:
let
inherit (lib)
extends
functionArgs
isFunction
makeScope
setFunctionArgs
;
in
makeScope newScope (
self:
let
# This allows packages in this scope to take `uefiSigningKey` as an
# argument without leaking it outside of the scope.
withSigningKey =
fn:
let
f = if isFunction fn then fn else import fn;
fArgs = functionArgs f;
in
if fArgs ? uefiSigningKey then
setFunctionArgs (args: f (args // { inherit uefiSigningKey; })) (
removeAttrs fArgs [ "uefiSigningKey" ]
)
else
f;
private =
extends autoCalledPackages
(_self: {
inherit uefiCertificate;
})
(
private
// self
// {
callPackage =
assert self.uefiCertificate.verificationKey == uefiSigningKey.verificationKey;
fn: self.callPackage (withSigningKey fn);
}
);
in
removeAttrs private [
"_internalCallByNamePackageFile"
"callPackage"
]
)

View File

@@ -0,0 +1,35 @@
{
lib,
mkSignedPackages,
autopen,
uefiSigningKey ? autopen.testSigningKey,
}:
mkSignedPackages {
inherit uefiSigningKey;
uefiCertificate = autopen.lib.x509.mkSelfSignedCertificate {
name = "insecure-test-uefi-certificate";
signingKey = uefiSigningKey;
certificateParams = {
purpose = "code-signing";
commonName = "INSECURE TEST CERTIFICATE, DO NOT TRUST";
notBefore = "1970-01-01T00:00:00Z";
lifetimeDays = 1;
};
passthru = {
signingKey = uefiSigningKey;
};
meta = {
description = "Insecure test UEFI Secure Boot certificate";
license = lib.licenses.free;
inherit (autopen.meta) platforms;
teams = [ lib.teams.boot-security ];
};
};
}

View File

@@ -752,6 +752,11 @@ with pkgs;
mkShell = callPackage ../build-support/mkshell { };
mkShellNoCC = mkShell.override { stdenv = stdenvNoCC; };
mkSignedPackages = callPackage ../misc/signed-packages { };
testSignedPackages = recurseIntoAttrs (
callPackage ../misc/signed-packages/test-signed-packages.nix { }
);
nixBufferBuilders = import ../applications/editors/emacs/build-support/buffer.nix {
inherit lib writeText;
inherit (emacs.pkgs) inherit-local;