You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
282 lines
5.6 KiB
282 lines
5.6 KiB
use crate::command_runner::CommandRunner;
|
|
use crate::symbols::Symbol;
|
|
use async_trait::async_trait;
|
|
use nonzero_ext::nonzero;
|
|
use std::error::Error;
|
|
use std::num::NonZeroU32;
|
|
use std::path::Path;
|
|
|
|
#[derive(Debug)]
|
|
pub struct Key<C, P> {
|
|
file_path: P,
|
|
command_runner: C,
|
|
bits: NonZeroU32,
|
|
}
|
|
|
|
impl<C, P> Key<C, P> {
|
|
pub const fn new(command_runner: C, file_path: P) -> Self {
|
|
Self {
|
|
file_path,
|
|
command_runner,
|
|
bits: nonzero!(4096u32), // FIXME: Policy
|
|
}
|
|
}
|
|
}
|
|
|
|
#[async_trait(?Send)]
|
|
impl<C: CommandRunner, P: AsRef<Path>> Symbol for Key<C, P> {
|
|
async fn target_reached(&self) -> Result<bool, Box<dyn Error>> {
|
|
if !self.file_path.as_ref().exists() {
|
|
return Ok(false);
|
|
}
|
|
|
|
let mut stdout = self
|
|
.command_runner
|
|
.get_output(
|
|
"openssl",
|
|
args![
|
|
"rsa",
|
|
"-in",
|
|
self.file_path.as_ref(),
|
|
"-noout",
|
|
"-check",
|
|
"-text",
|
|
],
|
|
)
|
|
.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!("Private-Key: ({} bit, 2 primes)\n", self.bits).as_ref()),
|
|
)
|
|
}
|
|
|
|
async fn execute(&self) -> Result<(), Box<dyn Error>> {
|
|
self
|
|
.command_runner
|
|
.run_successfully(
|
|
"openssl",
|
|
args![
|
|
"genrsa",
|
|
"-out",
|
|
self.file_path.as_ref(),
|
|
self.bits.to_string(),
|
|
],
|
|
)
|
|
.await
|
|
}
|
|
}
|
|
|
|
#[cfg(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);
|
|
});
|
|
}
|
|
}
|