Skip to content

Commit fff8f5e

Browse files
committed
Add IsoReader to cdrw module & use it to implement IsoSecretReader.
1 parent 1189870 commit fff8f5e

File tree

5 files changed

+313
-33
lines changed

5 files changed

+313
-33
lines changed

Cargo.lock

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

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,4 @@ x509-cert = "0.2.5"
3737
yubihsm = { git = "https://github.com/oxidecomputer/yubihsm.rs", branch = "session-close", features = ["usb", "untested"] }
3838
zeroize = "1.8.1"
3939
zeroize_derive = "1.4.2"
40+
glob = "0.3.1"

src/cdrw.rs

Lines changed: 146 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,12 @@
33
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
44

55
use anyhow::{anyhow, Context, Result};
6-
use log::warn;
7-
use std::{fs, path::Path, process::Command};
6+
use log::{debug, warn};
7+
use std::{
8+
fs,
9+
path::{Path, PathBuf},
10+
process::Command,
11+
};
812
use tempfile::{tempdir, TempDir};
913

1014
pub struct IsoWriter {
@@ -58,3 +62,143 @@ impl IsoWriter {
5862
Ok(())
5963
}
6064
}
65+
66+
pub struct IsoReader {
67+
iso_file: PathBuf,
68+
}
69+
70+
impl IsoReader {
71+
pub fn new<P: AsRef<Path>>(iso: P) -> Self {
72+
Self {
73+
iso_file: PathBuf::from(iso.as_ref()),
74+
}
75+
}
76+
77+
pub fn read<P: AsRef<Path>>(&self, path: P) -> Result<Vec<u8>> {
78+
let loop_dev = loopback_setup(&self.iso_file)?;
79+
80+
let tmpdir = tempdir()?;
81+
mount(&loop_dev, &tmpdir)?;
82+
83+
let src = tmpdir.path().join(&path);
84+
let data = fs::read(src)?;
85+
86+
unmount(&tmpdir)?;
87+
88+
loopback_teardown(&loop_dev)?;
89+
90+
Ok(data)
91+
}
92+
}
93+
94+
// create loopback device for iso file and get the device path from
95+
// losetup stdout
96+
fn loopback_setup<P: AsRef<Path>>(iso_file: P) -> Result<String> {
97+
let mut cmd = Command::new("losetup");
98+
let output = cmd
99+
.arg("-f")
100+
.output()
101+
.with_context(|| "unable to execute \"losetup\"")?;
102+
103+
debug!("executing command: \"{:#?}\"", cmd);
104+
105+
if !output.status.success() {
106+
warn!("command failed with status: {}", output.status);
107+
warn!("stderr: \"{}\"", String::from_utf8_lossy(&output.stderr));
108+
return Err(anyhow!("Failed to get next available loopback device"));
109+
}
110+
111+
let loop_dev = String::from(String::from_utf8(output.stdout)?.trim());
112+
debug!("got loopback device: {}", loop_dev);
113+
114+
let mut cmd = Command::new("losetup");
115+
let output = cmd
116+
.arg(&loop_dev)
117+
.arg(iso_file.as_ref())
118+
.output()
119+
.with_context(|| "failed to execute \"losetup\"")?;
120+
121+
debug!("executing command: \"{:#?}\"", cmd);
122+
if output.status.success() {
123+
Ok(loop_dev)
124+
} else {
125+
warn!("command failed with status: {}", output.status);
126+
warn!("stderr: \"{}\"", String::from_utf8_lossy(&output.stderr));
127+
Err(anyhow!(
128+
"Failed to create loopback device {} for ISO file {}",
129+
loop_dev,
130+
iso_file.as_ref().display()
131+
))
132+
}
133+
}
134+
135+
fn loopback_teardown<P: AsRef<Path>>(loop_dev: P) -> Result<()> {
136+
// tear down the loopback device
137+
let mut cmd = Command::new("losetup");
138+
let output = cmd
139+
.arg("-d")
140+
.arg(loop_dev.as_ref())
141+
.output()
142+
.context("failed to execute \"losetup\"")?;
143+
144+
if output.status.success() {
145+
Ok(())
146+
} else {
147+
warn!("command failed with status: {}", output.status);
148+
warn!("stderr: \"{}\"", String::from_utf8_lossy(&output.stderr));
149+
Err(anyhow!(
150+
"Failed to delete loopback device {}",
151+
loop_dev.as_ref().display()
152+
))
153+
}
154+
}
155+
156+
// TODO: sys_mount crate
157+
fn mount<P: AsRef<Path>, Q: AsRef<Path>>(
158+
device: P,
159+
mount_point: Q,
160+
) -> Result<()> {
161+
let mut cmd = Command::new("mount");
162+
let output = cmd
163+
.arg(device.as_ref())
164+
.arg(mount_point.as_ref())
165+
.output()
166+
.with_context(|| {
167+
format!(
168+
"failed to mount \"{}\" at \"{}\"",
169+
device.as_ref().display(),
170+
mount_point.as_ref().display()
171+
)
172+
})?;
173+
174+
if output.status.success() {
175+
Ok(())
176+
} else {
177+
warn!("command failed with status: {}", output.status);
178+
warn!("stderr: \"{}\"", String::from_utf8_lossy(&output.stderr));
179+
Err(anyhow!(
180+
"Failed to mount device {} at {}",
181+
device.as_ref().display(),
182+
mount_point.as_ref().display()
183+
))
184+
}
185+
}
186+
187+
fn unmount<P: AsRef<Path>>(mount_point: P) -> Result<()> {
188+
// unmount now that we've got the data we need
189+
let mut cmd = Command::new("umount");
190+
let output = cmd.arg(mount_point.as_ref()).output().with_context(|| {
191+
format!("failed to unmount \"{}\"", mount_point.as_ref().display())
192+
})?;
193+
194+
if output.status.success() {
195+
Ok(())
196+
} else {
197+
warn!("command failed with status: {}", output.status);
198+
warn!("stderr: \"{}\"", String::from_utf8_lossy(&output.stderr));
199+
Err(anyhow!(
200+
"Failed to unmount at {}",
201+
mount_point.as_ref().display()
202+
))
203+
}
204+
}

src/main.rs

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,9 @@ use oks::{
2525
ENV_NEW_PASSWORD, ENV_PASSWORD, KEYSPEC_EXT,
2626
},
2727
hsm::Hsm,
28-
secret_reader::{self, PasswordReader, SecretInput, StdioPasswordReader},
28+
secret_reader::{
29+
self, PasswordReader, SecretInputArg, StdioPasswordReader,
30+
},
2931
secret_writer::{self, SecretOutputArg},
3032
util,
3133
};
@@ -72,8 +74,8 @@ struct Args {
7274
#[derive(Subcommand, Debug, PartialEq)]
7375
enum Command {
7476
Ca {
75-
#[clap(long, env)]
76-
auth_method: SecretInput,
77+
#[clap(flatten)]
78+
auth_method: SecretInputArg,
7779

7880
#[command(subcommand)]
7981
command: CaCommand,
@@ -156,8 +158,8 @@ enum CaCommand {
156158
enum HsmCommand {
157159
/// Generate keys in YubiHSM from specification.
158160
Generate {
159-
#[clap(long, env)]
160-
auth_method: SecretInput,
161+
#[clap(flatten)]
162+
auth_method: SecretInputArg,
161163

162164
#[clap(long, env, default_value = "input")]
163165
key_spec: PathBuf,
@@ -182,17 +184,17 @@ enum HsmCommand {
182184
#[clap(long, env, default_value = "input")]
183185
backups: PathBuf,
184186

185-
#[clap(long, env)]
186-
share_method: SecretInput,
187+
#[clap(flatten)]
188+
share_method: SecretInputArg,
187189

188190
#[clap(long, env, default_value = "input/verifier.json")]
189191
verifier: PathBuf,
190192
},
191193

192194
/// Get serial number from YubiHSM and dump to console.
193195
SerialNumber {
194-
#[clap(long, env)]
195-
auth_method: SecretInput,
196+
#[clap(flatten)]
197+
auth_method: SecretInputArg,
196198
},
197199
}
198200

@@ -237,13 +239,14 @@ fn get_auth_id(auth_id: Option<Id>, command: &HsmCommand) -> Id {
237239
/// the user with a password prompt.
238240
fn get_passwd(
239241
auth_id: Option<Id>,
240-
auth_method: &SecretInput,
242+
auth_method: &SecretInputArg,
241243
command: &HsmCommand,
242244
) -> Result<Zeroizing<String>> {
243245
let passwd = match env::var(ENV_PASSWORD).ok() {
244246
Some(s) => Zeroizing::new(s),
245247
None => {
246-
let passwd_reader = secret_reader::get_passwd_reader(*auth_method);
248+
let mut passwd_reader =
249+
secret_reader::get_passwd_reader(auth_method)?;
247250

248251
if auth_id.is_some() {
249252
// if auth_id was set by the caller but not the password we
@@ -289,7 +292,7 @@ fn get_new_passwd(hsm: Option<&mut Hsm>) -> Result<Zeroizing<String>> {
289292
}
290293
// last option: challenge the caller
291294
None => {
292-
let passwd_reader = StdioPasswordReader::default();
295+
let mut passwd_reader = StdioPasswordReader::default();
293296
loop {
294297
let password = passwd_reader.read(PASSWD_NEW)?;
295298
let password2 = passwd_reader.read(PASSWD_NEW_2)?;
@@ -682,7 +685,8 @@ fn main() -> Result<()> {
682685
} => {
683686
// The CA modules pulls the password out of the environment. If
684687
// ENV_PASSWORD isn't set the caller will be challenged.
685-
let passwd_reader = secret_reader::get_passwd_reader(auth_method);
688+
let mut passwd_reader =
689+
secret_reader::get_passwd_reader(&auth_method)?;
686690
let password = passwd_reader.read(PASSWD_PROMPT)?;
687691
std::env::set_var(ENV_PASSWORD, password.deref());
688692

@@ -826,9 +830,9 @@ fn main() -> Result<()> {
826830
let verifier = fs::read_to_string(verifier)?;
827831
let verifier: Verifier = serde_json::from_str(&verifier)?;
828832
let share_itr = secret_reader::get_share_reader(
829-
*share_method,
833+
share_method,
830834
verifier,
831-
);
835+
)?;
832836

833837
let mut shares: Zeroizing<Vec<Share>> =
834838
Zeroizing::new(Vec::new());

0 commit comments

Comments
 (0)