rpki/src/bin/cir_ta_only_fixture.rs

125 lines
4.4 KiB
Rust

use std::path::PathBuf;
use rpki::cir::{
CIR_VERSION_V1, CanonicalInputRepresentation, CirHashAlgorithm, CirObject, CirTal, encode_cir,
write_bytes_to_static_pool,
};
use sha2::Digest;
const USAGE: &str = "Usage: cir_ta_only_fixture --tal-path <path> --ta-path <path> --tal-uri <url> --validation-time <rfc3339> --cir-out <path> --static-root <path>";
fn parse_args(
argv: &[String],
) -> Result<
(
PathBuf,
PathBuf,
String,
time::OffsetDateTime,
PathBuf,
PathBuf,
),
String,
> {
let mut tal_path = None;
let mut ta_path = None;
let mut tal_uri = None;
let mut validation_time = None;
let mut cir_out = None;
let mut static_root = None;
let mut i = 1usize;
while i < argv.len() {
match argv[i].as_str() {
"--tal-path" => {
i += 1;
tal_path = Some(PathBuf::from(
argv.get(i).ok_or("--tal-path requires a value")?,
));
}
"--ta-path" => {
i += 1;
ta_path = Some(PathBuf::from(
argv.get(i).ok_or("--ta-path requires a value")?,
));
}
"--tal-uri" => {
i += 1;
tal_uri = Some(argv.get(i).ok_or("--tal-uri requires a value")?.clone());
}
"--validation-time" => {
i += 1;
let raw = argv.get(i).ok_or("--validation-time requires a value")?;
validation_time = Some(
time::OffsetDateTime::parse(
raw,
&time::format_description::well_known::Rfc3339,
)
.map_err(|e| format!("invalid validation time: {e}"))?,
);
}
"--cir-out" => {
i += 1;
cir_out = Some(PathBuf::from(
argv.get(i).ok_or("--cir-out requires a value")?,
));
}
"--static-root" => {
i += 1;
static_root = Some(PathBuf::from(
argv.get(i).ok_or("--static-root requires a value")?,
));
}
"-h" | "--help" => return Err(USAGE.to_string()),
other => return Err(format!("unknown argument: {other}\n\n{USAGE}")),
}
i += 1;
}
Ok((
tal_path.ok_or_else(|| format!("--tal-path is required\n\n{USAGE}"))?,
ta_path.ok_or_else(|| format!("--ta-path is required\n\n{USAGE}"))?,
tal_uri.ok_or_else(|| format!("--tal-uri is required\n\n{USAGE}"))?,
validation_time.ok_or_else(|| format!("--validation-time is required\n\n{USAGE}"))?,
cir_out.ok_or_else(|| format!("--cir-out is required\n\n{USAGE}"))?,
static_root.ok_or_else(|| format!("--static-root is required\n\n{USAGE}"))?,
))
}
fn main() -> Result<(), String> {
let argv: Vec<String> = std::env::args().collect();
let (tal_path, ta_path, tal_uri, validation_time, cir_out, static_root) = parse_args(&argv)?;
let tal_bytes = std::fs::read(&tal_path).map_err(|e| format!("read tal failed: {e}"))?;
let ta_bytes = std::fs::read(&ta_path).map_err(|e| format!("read ta failed: {e}"))?;
let tal = rpki::data_model::tal::Tal::decode_bytes(&tal_bytes)
.map_err(|e| format!("decode tal failed: {e}"))?;
let ta_rsync_uri = tal
.ta_uris
.iter()
.find(|uri| uri.scheme() == "rsync")
.ok_or("tal must contain an rsync URI")?
.as_str()
.to_string();
let sha = sha2::Sha256::digest(&ta_bytes);
let hash_hex = hex::encode(sha);
write_bytes_to_static_pool(&static_root, validation_time.date(), &hash_hex, &ta_bytes)
.map_err(|e| format!("write static pool failed: {e}"))?;
let cir = CanonicalInputRepresentation {
version: CIR_VERSION_V1,
hash_alg: CirHashAlgorithm::Sha256,
validation_time,
objects: vec![CirObject {
rsync_uri: ta_rsync_uri,
sha256: sha.to_vec(),
}],
tals: vec![CirTal { tal_uri, tal_bytes }],
};
let der = encode_cir(&cir).map_err(|e| format!("encode cir failed: {e}"))?;
if let Some(parent) = cir_out.parent() {
std::fs::create_dir_all(parent).map_err(|e| format!("create cir parent failed: {e}"))?;
}
std::fs::write(&cir_out, der).map_err(|e| format!("write cir failed: {e}"))?;
Ok(())
}