Support bookworm openssl in Key
This commit is contained in:
parent
988a3b0fe7
commit
c41ad54c37
4 changed files with 272 additions and 63 deletions
|
|
@ -1,4 +1,6 @@
|
|||
use async_trait::async_trait;
|
||||
#[cfg(test)]
|
||||
use mockall::mock;
|
||||
use std::error::Error;
|
||||
use std::ffi::OsStr;
|
||||
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)]
|
||||
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
|
||||
}
|
||||
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?;
|
||||
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)?;
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
#[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)]
|
||||
pub struct StdCommandRunner;
|
||||
|
||||
#[async_trait(?Send)]
|
||||
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);
|
||||
let mut child = Command::new(program)
|
||||
.args(args)
|
||||
|
|
@ -114,7 +143,7 @@ impl Drop for TempSetEnv<'_> {
|
|||
|
||||
#[async_trait(?Send)]
|
||||
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())
|
||||
.expect("User does not exist")
|
||||
.uid();
|
||||
|
|
|
|||
|
|
@ -92,63 +92,30 @@ impl<_C: CommandRunner, C: Borrow<_C>, P: AsRef<Path>, S: AsRef<str>, B: AsRef<s
|
|||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::Checkout;
|
||||
use super::{Checkout, Symbol};
|
||||
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]
|
||||
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());
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ impl<C: CommandRunner, P: AsRef<Path>> Symbol for Key<C, P> {
|
|||
return Ok(false);
|
||||
}
|
||||
|
||||
let stdout = self
|
||||
let mut stdout = self
|
||||
.command_runner
|
||||
.get_output(
|
||||
"openssl",
|
||||
|
|
@ -44,9 +44,12 @@ impl<C: CommandRunner, P: AsRef<Path>> Symbol for Key<C, P> {
|
|||
],
|
||||
)
|
||||
.await?;
|
||||
if stdout.starts_with("RSA ".as_ref()) {
|
||||
stdout = stdout.split_off(4);
|
||||
}
|
||||
Ok(
|
||||
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)]
|
||||
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…
Add table
Add a link
Reference in a new issue