Browse Source

Support bookworm openssl in Key

master
Adrian Heine 1 year ago
parent
commit
c41ad54c37
  1. 1
      Cargo.toml
  2. 43
      src/command_runner.rs
  3. 73
      src/symbols/git/checkout.rs
  4. 218
      src/symbols/tls/key.rs

1
Cargo.toml

@ -19,3 +19,4 @@ nonzero_ext = "0.3.0"
[dev-dependencies] [dev-dependencies]
tempfile = "3" tempfile = "3"
mockall = "0.11.4"

43
src/command_runner.rs

@ -1,4 +1,6 @@
use async_trait::async_trait; use async_trait::async_trait;
#[cfg(test)]
use mockall::mock;
use std::error::Error; use std::error::Error;
use std::ffi::OsStr; use std::ffi::OsStr;
use std::io::Result as IoResult; use std::io::Result as IoResult;
@ -33,30 +35,57 @@ pub fn get_output(output: Output) -> Result<Vec<u8>, Box<dyn Error>> {
#[async_trait(?Send)] #[async_trait(?Send)]
pub trait CommandRunner { pub trait CommandRunner {
async fn run(&self, program: &str, args: &[&OsStr], stdin: &[u8]) -> IoResult<Output>;
async fn run<'a>(&self, program: &str, args: &'a [&'a OsStr], input: &[u8]) -> IoResult<Output>;
async fn run_with_args(&self, program: &str, args: &[&OsStr]) -> IoResult<Output> {
async fn run_with_args<'a>(&self, program: &str, args: &'a [&'a OsStr]) -> IoResult<Output> {
self.run(program, args, b"").await self.run(program, args, b"").await
} }
async fn get_output(&self, program: &str, args: &[&OsStr]) -> Result<Vec<u8>, Box<dyn Error>> {
async fn get_output<'a>(
&self,
program: &str,
args: &'a [&'a OsStr],
) -> Result<Vec<u8>, Box<dyn Error>> {
let output = self.run_with_args(program, args).await?; let output = self.run_with_args(program, args).await?;
get_output(output) get_output(output)
} }
async fn run_successfully(&self, program: &str, args: &[&OsStr]) -> Result<(), Box<dyn Error>> {
async fn run_successfully<'a>(
&self,
program: &str,
args: &'a [&'a OsStr],
) -> Result<(), Box<dyn Error>> {
is_success(self.run(program, args, b"").await)?; is_success(self.run(program, args, b"").await)?;
Ok(()) Ok(())
} }
async fn get_stderr(&self, program: &str, args: &[&OsStr]) -> Result<Vec<u8>, Box<dyn Error>> {
async fn get_stderr<'a>(
&self,
program: &str,
args: &'a [&'a OsStr],
) -> Result<Vec<u8>, Box<dyn Error>> {
Ok(is_success(self.run_with_args(program, args).await)?.stderr) Ok(is_success(self.run_with_args(program, args).await)?.stderr)
} }
} }
#[cfg(test)]
mock! {
pub CommandRunner {
}
#[async_trait(?Send)]
impl CommandRunner for CommandRunner {
async fn run<'a>(&self, program: &str, args: &'a [&'a OsStr], input: &[u8]) -> IoResult<Output>;
async fn run_with_args<'a>(&self, program: &str, args: &'a [&'a OsStr]) -> IoResult<Output>;
async fn get_output<'a>(&self, program: &str, args: &'a [&'a OsStr]) -> Result<Vec<u8>, Box<dyn Error>>;
async fn run_successfully<'a>(&self, program: &str, args: &'a [&'a OsStr]) -> Result<(), Box<dyn Error>>;
async fn get_stderr<'a>(&self, program: &str, args: &'a [&'a OsStr]) -> Result<Vec<u8>, Box<dyn Error>>;
}
}
#[derive(Debug)] #[derive(Debug)]
pub struct StdCommandRunner; pub struct StdCommandRunner;
#[async_trait(?Send)] #[async_trait(?Send)]
impl CommandRunner for StdCommandRunner { impl CommandRunner for StdCommandRunner {
async fn run(&self, program: &str, args: &[&OsStr], input: &[u8]) -> IoResult<Output> {
async fn run<'a>(&self, program: &str, args: &'a [&'a OsStr], input: &[u8]) -> IoResult<Output> {
//println!("{} {:?}", program, args); //println!("{} {:?}", program, args);
let mut child = Command::new(program) let mut child = Command::new(program)
.args(args) .args(args)
@ -114,7 +143,7 @@ impl Drop for TempSetEnv<'_> {
#[async_trait(?Send)] #[async_trait(?Send)]
impl<U: AsRef<str>> CommandRunner for SetuidCommandRunner<U> { impl<U: AsRef<str>> CommandRunner for SetuidCommandRunner<U> {
async fn run(&self, program: &str, args: &[&OsStr], input: &[u8]) -> IoResult<Output> {
async fn run<'a>(&self, program: &str, args: &'a [&'a OsStr], input: &[u8]) -> IoResult<Output> {
let uid = get_user_by_name(self.user_name.as_ref()) let uid = get_user_by_name(self.user_name.as_ref())
.expect("User does not exist") .expect("User does not exist")
.uid(); .uid();

73
src/symbols/git/checkout.rs

@ -92,63 +92,30 @@ impl<_C: CommandRunner, C: Borrow<_C>, P: AsRef<Path>, S: AsRef<str>, B: AsRef<s
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::Checkout;
use super::{Checkout, Symbol};
use crate::async_utils::run; use crate::async_utils::run;
use crate::async_utils::sleep;
use crate::command_runner::CommandRunner;
use crate::symbols::Symbol;
use async_trait::async_trait;
use std::cell::RefCell;
use std::ffi::{OsStr, OsString};
use std::io::Result as IoResult;
use std::os::unix::process::ExitStatusExt;
use std::process::{ExitStatus, Output};
use std::time::{Duration, Instant};
struct DummyCommandRunner {
pub args: RefCell<Vec<Vec<OsString>>>,
}
#[async_trait(?Send)]
impl CommandRunner for DummyCommandRunner {
async fn run(&self, program: &str, args: &[&OsStr], stdin: &[u8]) -> IoResult<Output> {
assert_eq!(program, "git");
assert_eq!(stdin, b"");
sleep(Duration::from_millis(50)).await;
self
.args
.borrow_mut()
.push(args.iter().map(|a| a.to_os_string()).collect());
Ok(Output {
status: ExitStatus::from_raw(0),
stdout: vec![],
stderr: vec![],
})
}
}
use crate::command_runner::MockCommandRunner;
use mockall::Sequence;
#[test] #[test]
fn test() { fn test() {
let c = DummyCommandRunner {
args: RefCell::new(vec![]),
};
let checkout: Checkout<DummyCommandRunner, _, _, _, _> =
Checkout::new(".", "source", "branch", &c);
let start = Instant::now();
let mut seq = Sequence::new();
let mut c = MockCommandRunner::new();
c.expect_get_output()
.times(1)
.withf(|cmd, args| cmd == "git" && args == ["-C", ".", "rev-list", "-1", "HEAD"])
.returning(|_, _| Ok("".into()));
c.expect_get_output()
.times(1)
.in_sequence(&mut seq)
.withf(|cmd, args| cmd == "git" && args == ["-C", ".", "fetch", "source", "branch"])
.returning(|_, _| Ok("".into()));
c.expect_get_output()
.times(1)
.in_sequence(&mut seq)
.withf(|cmd, args| cmd == "git" && args == ["-C", ".", "rev-list", "-1", "FETCH_HEAD"])
.returning(|_, _| Ok("".into()));
let checkout = Checkout::new(".", "source", "branch", c);
assert!(run(checkout.target_reached()).unwrap()); assert!(run(checkout.target_reached()).unwrap());
let end = Instant::now();
let mut args = c.args.into_inner();
let first_two_args = &mut args[0..2];
first_two_args.sort_unstable();
assert_eq!(
first_two_args,
[
["-C", ".", "fetch", "source", "branch"],
["-C", ".", "rev-list", "-1", "HEAD"],
]
);
assert_eq!(args[2], ["-C", ".", "rev-list", "-1", "FETCH_HEAD"]);
assert!((end - start).as_millis() >= 100);
assert!((end - start).as_millis() < 150);
} }
} }

218
src/symbols/tls/key.rs

@ -30,7 +30,7 @@ impl<C: CommandRunner, P: AsRef<Path>> Symbol for Key<C, P> {
return Ok(false); return Ok(false);
} }
let stdout = self
let mut stdout = self
.command_runner .command_runner
.get_output( .get_output(
"openssl", "openssl",
@ -44,9 +44,12 @@ impl<C: CommandRunner, P: AsRef<Path>> Symbol for Key<C, P> {
], ],
) )
.await?; .await?;
if stdout.starts_with("RSA ".as_ref()) {
stdout = stdout.split_off(4);
}
Ok( Ok(
stdout.ends_with(b"RSA key ok\n") stdout.ends_with(b"RSA key ok\n")
&& stdout.starts_with(format!("RSA Private-Key: ({} bit, 2 primes)\n", self.bits).as_ref()),
&& stdout.starts_with(format!("Private-Key: ({} bit, 2 primes)\n", self.bits).as_ref()),
) )
} }
@ -67,4 +70,213 @@ impl<C: CommandRunner, P: AsRef<Path>> Symbol for Key<C, P> {
} }
#[cfg(test)] #[cfg(test)]
mod test {}
mod test {
use super::{Key, Symbol};
use crate::async_utils::run;
use crate::command_runner::MockCommandRunner;
#[test]
fn test_bookworm_success() {
let mut command_runner = MockCommandRunner::new();
command_runner
.expect_get_output()
.times(1)
.returning(|_, _| {
Ok(
"Private-Key: (4096 bit, 2 primes)
modulus:
00:...
publicExponent: 65537 (0x10001)
privateExponent:
57:...
prime1:
00:...
prime2:
00:...
exponent1:
2b:...
exponent2:
0e:...
coefficient:
43:...
RSA key ok
"
.into(),
)
});
let symbol = Key::new(command_runner, "/"); // FIXME: Has to be an existing file
run(async {
assert_eq!(symbol.target_reached().await.unwrap(), true);
});
}
#[test]
fn test_bookworm_short_key() {
let mut command_runner = MockCommandRunner::new();
command_runner
.expect_get_output()
.times(1)
.returning(|_, _| {
Ok(
"Private-Key: (2048 bit, 2 primes)
modulus:
00:...
publicExponent: 65537 (0x10001)
privateExponent:
57:...
prime1:
00:...
prime2:
00:...
exponent1:
2b:...
exponent2:
0e:...
coefficient:
43:...
RSA key ok
"
.into(),
)
});
let symbol = Key::new(command_runner, "/"); // FIXME: Has to be an existing file
run(async {
assert_eq!(symbol.target_reached().await.unwrap(), false);
});
}
#[test]
fn test_bookworm_broken_key() {
let mut command_runner = MockCommandRunner::new();
command_runner.expect_get_output()
.times(1)
.returning(|_, _| Ok("Private-Key: (4096 bit, 2 primes)
modulus:
00:...
publicExponent: 65537 (0x10001)
privateExponent:
57:...
prime1:
00:...
prime2:
00:...
exponent1:
2b:...
exponent2:
0e:...
coefficient:
43:...
RSA key not ok
40C782E5E77F0000:error:0200007E:rsa routines:rsa_validate_keypair_multiprime:iqmp not inverse of q:../crypto/rsa/rsa_chk.c:196:
".into()));
let symbol = Key::new(command_runner, "/"); // FIXME: Has to be an existing file
run(async {
assert_eq!(symbol.target_reached().await.unwrap(), false);
});
}
#[test]
fn test_bullseye_success() {
let mut command_runner = MockCommandRunner::new();
command_runner
.expect_get_output()
.times(1)
.returning(|_, _| {
Ok(
"RSA Private-Key: (4096 bit, 2 primes)
modulus:
00:...
publicExponent: 65537 (0x10001)
privateExponent:
57:...
prime1:
00:...
prime2:
00:...
exponent1:
2b:...
exponent2:
0e:...
coefficient:
43:...
RSA key ok
"
.into(),
)
});
let symbol = Key::new(command_runner, "/"); // FIXME: Has to be an existing file
run(async {
assert_eq!(symbol.target_reached().await.unwrap(), true);
});
}
#[test]
fn test_bullseye_short_key() {
let mut command_runner = MockCommandRunner::new();
command_runner
.expect_get_output()
.times(1)
.returning(|_, _| {
Ok(
"RSA Private-Key: (2048 bit, 2 primes)
modulus:
00:...
publicExponent: 65537 (0x10001)
privateExponent:
57:...
prime1:
00:...
prime2:
00:...
exponent1:
2b:...
exponent2:
0e:...
coefficient:
43:...
RSA key ok
"
.into(),
)
});
let symbol = Key::new(command_runner, "/"); // FIXME: Has to be an existing file
run(async {
assert_eq!(symbol.target_reached().await.unwrap(), false);
});
}
#[test]
fn test_bullseye_broken_key() {
let mut command_runner = MockCommandRunner::new();
command_runner
.expect_get_output()
.times(1)
.returning(|_, _| {
Ok(
"RSA Private-Key: (4096 bit, 2 primes)
modulus:
00:...
publicExponent: 65537 (0x10001)
privateExponent:
57:...
prime1:
00:...
prime2:
00:...
exponent1:
2b:...
exponent2:
0e:...
coefficient:
43:...
RSA key error: iqmp not inverse of q
"
.into(),
)
});
let symbol = Key::new(command_runner, "/"); // FIXME: Has to be an existing file
run(async {
assert_eq!(symbol.target_reached().await.unwrap(), false);
});
}
}
Loading…
Cancel
Save