Skip to content

Commit 1de5f0f

Browse files
author
Gareth Widlansky
committed
add support for key autoenroll to sdboot
Signed-off-by: Gareth Widlansky <gareth.widlansky@proton.me> add autoenroll to sdboot Signed-off-by: Gareth Widlansky <gareth.widlansky@proton.me> asdf Signed-off-by: Gareth Widlansky <gareth.widlansky@proton.me>
1 parent f687add commit 1de5f0f

File tree

2 files changed

+73
-4
lines changed

2 files changed

+73
-4
lines changed

crates/lib/src/bootc_composefs/boot.rs

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,12 +61,12 @@
6161
//! 1. **Primary**: New/upgraded deployment (default boot target)
6262
//! 2. **Secondary**: Currently booted deployment (rollback option)
6363
64-
use std::ffi::OsStr;
6564
use std::fs::create_dir_all;
6665
use std::io::Write;
6766
use std::path::Path;
67+
use std::{ffi::OsStr, os::unix::ffi::OsStrExt};
6868

69-
use anyhow::{anyhow, Context, Result};
69+
use anyhow::{anyhow, bail, Context, Result};
7070
use bootc_blockdev::find_parent_devices;
7171
use bootc_kernel_cmdline::utf8::{Cmdline, Parameter};
7272
use bootc_mount::inspect_filesystem_of_dir;
@@ -78,6 +78,7 @@ use cap_std_ext::{
7878
};
7979
use clap::ValueEnum;
8080
use composefs::fs::read_file;
81+
use composefs::generic_tree::{Directory, Inode, LeafContent};
8182
use composefs::tree::RegularFile;
8283
use composefs_boot::BootOps;
8384
use composefs_boot::{
@@ -1142,6 +1143,42 @@ pub(crate) fn setup_composefs_uki_boot(
11421143
Ok(())
11431144
}
11441145

1146+
pub struct AuthFile {
1147+
pub filename: Utf8PathBuf,
1148+
pub file: RegularFile<Sha512HashValue>,
1149+
}
1150+
1151+
fn get_autoenroll_keys(root: &Directory<RegularFile<Sha512HashValue>>) -> Result<Vec<AuthFile>> {
1152+
let mut entries = vec![];
1153+
match root.get_directory("/usr/lib/bootc/keys".as_ref()) {
1154+
Ok(keys_dir) => {
1155+
for (filename, inode) in keys_dir.entries() {
1156+
if !filename.as_bytes().ends_with(b".auth") {
1157+
continue;
1158+
}
1159+
1160+
let Inode::Leaf(leaf) = inode else {
1161+
bail!("/usr/lib/bootc/keys/{filename:?} is a directory");
1162+
};
1163+
1164+
let LeafContent::Regular(file) = &leaf.content else {
1165+
bail!("/usr/lib/bootc/keys/{filename:?} is not a regular file");
1166+
};
1167+
let path = match Utf8PathBuf::from_os_string(filename.into()) {
1168+
Ok(p) => p,
1169+
Err(_) => bail!("couldn't get pathbuf: /usr/lib/bootc/keys/{filename:?}"),
1170+
};
1171+
entries.push(AuthFile {
1172+
filename: path,
1173+
file: file.clone(),
1174+
});
1175+
}
1176+
}
1177+
Err(other) => Err(other)?,
1178+
};
1179+
Ok(entries)
1180+
}
1181+
11451182
#[context("Setting up composefs boot")]
11461183
pub(crate) fn setup_composefs_boot(
11471184
root_setup: &RootSetup,
@@ -1160,6 +1197,8 @@ pub(crate) fn setup_composefs_boot(
11601197

11611198
let postfetch = PostFetchState::new(state, &mounted_fs)?;
11621199

1200+
let keys = get_autoenroll_keys(&fs.root)?;
1201+
11631202
let boot_uuid = root_setup
11641203
.get_boot_uuid()?
11651204
.or(root_setup.rootfs_uuid.as_deref())
@@ -1181,6 +1220,8 @@ pub(crate) fn setup_composefs_boot(
11811220
&root_setup.physical_root_path,
11821221
&state.config_opts,
11831222
None,
1223+
keys,
1224+
&repo,
11841225
)?;
11851226
}
11861227

crates/lib/src/bootloader.rs

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,19 @@
1+
use std::fs::create_dir_all;
12
use std::process::Command;
23

34
use anyhow::{anyhow, bail, Context, Result};
45
use bootc_utils::CommandRunExt;
56
use camino::Utf8Path;
7+
use cap_std_ext::cap_std::ambient_authority;
68
use cap_std_ext::cap_std::fs::Dir;
9+
use cap_std_ext::dirext::CapStdExtDirExt;
10+
use composefs::fs::read_file;
711
use fn_error_context::context;
812

913
use bootc_blockdev::{Partition, PartitionTable};
1014
use bootc_mount as mount;
1115

12-
use crate::bootc_composefs::boot::mount_esp;
16+
use crate::bootc_composefs::boot::{mount_esp, AuthFile};
1317
use crate::{discoverable_partition_specification, utils};
1418

1519
/// The name of the mountpoint for efi (as a subdirectory of /boot, or at the toplevel)
@@ -74,6 +78,8 @@ pub(crate) fn install_systemd_boot(
7478
_rootfs: &Utf8Path,
7579
_configopts: &crate::install::InstallConfigOpts,
7680
_deployment_path: Option<&str>,
81+
autoenroll: Vec<AuthFile>,
82+
repo: &crate::store::ComposefsRepository,
7783
) -> Result<()> {
7884
let esp_part = device
7985
.find_partition_of_type(discoverable_partition_specification::ESP)
@@ -87,7 +93,29 @@ pub(crate) fn install_systemd_boot(
8793
Command::new("bootctl")
8894
.args(["install", "--esp-path", esp_path.as_str()])
8995
.log_debug()
90-
.run_inherited_with_cmd_context()
96+
.run_inherited_with_cmd_context()?;
97+
98+
if autoenroll.len() < 1 {
99+
return Ok(());
100+
}
101+
102+
println!("Autoenrolling keys");
103+
let path = esp_path.join("loader/keys/auto");
104+
create_dir_all(&path)?;
105+
106+
let keys_dir = Dir::open_ambient_dir(&path, ambient_authority())
107+
.with_context(|| format!("Opening {path}"))?;
108+
for a in autoenroll.iter() {
109+
let p = path.join(a.filename.clone());
110+
keys_dir
111+
.atomic_write(
112+
&a.filename,
113+
read_file(&a.file, &repo).context("reading file")?,
114+
)
115+
.with_context(|| format!("Writing secure boot key: {p}"))?;
116+
println!("Wrote secure boot key: {p}");
117+
}
118+
Ok(())
91119
}
92120

93121
#[context("Installing bootloader using zipl")]

0 commit comments

Comments
 (0)