use crate::cli::{PkiCommand, PkiCompositeSignArgs, PkiParseCertArgs, PkiVerifyArgs};
use confium_pki::{Certificate, path::CertPath};
pub fn run(cmd: PkiCommand) {
let result: Result<(), String> = match cmd {
PkiCommand::Version => {
print_version();
Ok(())
}
PkiCommand::ParseCert(args) => parse_cert(args),
PkiCommand::Verify(args) => verify_chain(args),
PkiCommand::CompositeSign(args) => composite_sign(args),
};
if let Err(e) = result {
eprintln!("confium pki: {e}");
std::process::exit(1);
}
}
fn parse_cert(args: PkiParseCertArgs) -> Result<(), String> {
let cert = read_cert(&args.cert, &args.format)?;
println!("fingerprint (sha256): {}", cert.fingerprint_sha256());
println!("serial (hex): {}", hex::encode(cert.serial_bytes()));
println!("not before: {}", cert.not_before());
println!("not after: {}", cert.not_after());
Ok(())
}
fn verify_chain(args: PkiVerifyArgs) -> Result<(), String> {
let leaf = read_cert(&args.leaf, &args.format)?;
let anchor = read_cert(&args.anchor, &args.format)?;
let intermediates: Vec<Certificate> = args
.intermediates
.iter()
.map(|p| read_cert(p, &args.format))
.collect::<Result<_, _>>()?;
let inter_refs: Vec<&Certificate> = intermediates.iter().collect();
let path = CertPath {
leaf: &leaf,
intermediates: inter_refs,
root: &anchor,
};
let result = confium_pki::path::verify_path_signatures(&path, |_issuer_pk, _sig| {
Ok(()) });
println!("{:?}", result);
Ok(())
}
fn composite_sign(args: PkiCompositeSignArgs) -> Result<(), String> {
let message = read_message(&args.message)?;
let ed25519_key_bytes = std::fs::read(&args.ed25519_key)
.map_err(|e| format!("read {}: {e}", args.ed25519_key.display()))?;
let ed25519_key = ed25519_dalek::SigningKey::from_bytes(
&ed25519_key_bytes
.as_slice()
.try_into()
.map_err(|_| "Ed25519 key must be exactly 32 bytes".to_string())?,
);
let ed_component = confium_composite::build_ed25519_component(&ed25519_key, &message)
.map_err(|e| format!("ed25519 component: {e}"))?;
let p256_key_bytes = std::fs::read(&args.p256_key)
.map_err(|e| format!("read {}: {e}", args.p256_key.display()))?;
let p256_key_bytes: [u8; 32] = p256_key_bytes
.as_slice()
.try_into()
.map_err(|_| "P-256 key must be exactly 32 bytes".to_string())?;
let p256_key = p256::ecdsa::SigningKey::from_bytes(&p256_key_bytes.into())
.map_err(|e| format!("parse P-256 signing key: {e}"))?;
let p256_component = confium_composite::build_p256_component(&p256_key, &message)
.map_err(|e| format!("p256 component: {e}"))?;
let composite = confium_composite::CompositeSignature::new(vec![ed_component, p256_component]);
let json =
serde_json::to_string(&composite).map_err(|e| format!("serialize composite: {e}"))?;
let hex_out = hex::encode(json.as_bytes());
match &args.out {
Some(path) => std::fs::write(path, hex_out.as_bytes())
.map_err(|e| format!("write {}: {e}", path.display()))?,
None => println!("{hex_out}"),
}
Ok(())
}
fn read_cert(path: &std::path::Path, format: &str) -> Result<Certificate, String> {
let bytes = std::fs::read(path).map_err(|e| format!("read {}: {e}", path.display()))?;
match format {
"der" => Certificate::from_der(&bytes).map_err(|e| format!("parse DER: {e}")),
"pem" => {
let s = std::str::from_utf8(&bytes).map_err(|e| format!("PEM is not UTF-8: {e}"))?;
Certificate::from_pem(s).map_err(|e| format!("parse PEM: {e}"))
}
other => Err(format!("unknown format: {other} (try der or pem)")),
}
}
fn read_message(spec: &str) -> Result<Vec<u8>, String> {
if let Some(path) = spec.strip_prefix('@') {
std::fs::read(path).map_err(|e| format!("read message {path}: {e}"))
} else {
Ok(spec.as_bytes().to_vec())
}
}
fn print_version() {
println!("confium-pki: product umbrella");
println!(" crates:");
println!(" confium-pki (https://docs.rs/confium-pki)");
println!(" confium-composite (https://docs.rs/confium-composite)");
println!(" confium-attributes (https://docs.rs/confium-attributes)");
println!(" confium-pkcs11-server (https://docs.rs/confium-pkcs11-server)");
println!(" confium-openssl-provider (https://docs.rs/confium-openssl-provider)");
println!(" confium-jce-provider (https://docs.rs/confium-jce-provider)");
println!(" confium-tls-signer (https://docs.rs/confium-tls-signer)");
println!();
println!(" docs: https://www.confium.org/pki/");
println!(" specs: https://www.confium.org/specs/PRODUCTS");
println!(" quickstart: https://www.confium.org/pki/quickstart/");
}