125 lines
4.4 KiB
Rust
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(())
|
|
}
|