2022-11-21 19:29:16 -05:00
|
|
|
use std::fs;
|
|
|
|
use std::path::{Path, PathBuf};
|
|
|
|
|
|
|
|
use anyhow::Result;
|
|
|
|
use clap::{Parser, Subcommand};
|
|
|
|
|
2022-11-23 09:26:26 -05:00
|
|
|
use crate::{crypto, install};
|
2022-11-21 19:29:16 -05:00
|
|
|
|
|
|
|
#[derive(Parser)]
|
|
|
|
pub struct Cli {
|
|
|
|
#[clap(subcommand)]
|
|
|
|
pub commands: Commands,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Subcommand)]
|
|
|
|
pub enum Commands {
|
|
|
|
/// Generate key pair
|
|
|
|
Generate,
|
|
|
|
/// Sign
|
|
|
|
Sign { file: PathBuf, private_key: PathBuf },
|
|
|
|
/// Sign
|
|
|
|
Verify { file: PathBuf, public_key: PathBuf },
|
2022-11-23 09:26:26 -05:00
|
|
|
Install {
|
|
|
|
public_key: PathBuf,
|
|
|
|
bootspec: PathBuf,
|
|
|
|
},
|
2022-11-21 19:29:16 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Cli {
|
|
|
|
pub fn call(self) -> Result<()> {
|
|
|
|
self.commands.call()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Commands {
|
|
|
|
pub fn call(self) -> Result<()> {
|
|
|
|
match self {
|
|
|
|
Commands::Generate => generate(),
|
|
|
|
Commands::Sign { file, private_key } => sign(&file, &private_key),
|
|
|
|
Commands::Verify { file, public_key } => verify(&file, &public_key),
|
2022-11-23 09:26:26 -05:00
|
|
|
Commands::Install {
|
|
|
|
public_key,
|
|
|
|
bootspec,
|
|
|
|
} => install(&public_key, &bootspec),
|
2022-11-21 19:29:16 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn generate() -> Result<()> {
|
|
|
|
let key_pair = crypto::generate_key();
|
|
|
|
|
|
|
|
fs::write("public_key.pem", key_pair.pk.to_pem())?;
|
|
|
|
fs::write("private_key.pem", key_pair.sk.to_pem())?;
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn sign(file: &Path, private_key: &Path) -> Result<()> {
|
|
|
|
let message = fs::read(file)?;
|
|
|
|
let private_key = fs::read_to_string(private_key)?;
|
|
|
|
|
|
|
|
let signature = crypto::sign(&message, &private_key)?;
|
|
|
|
|
|
|
|
let file_path = with_extension(file, ".sig");
|
|
|
|
fs::write(file_path, signature.as_slice())?;
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn verify(file: &Path, public_key: &Path) -> Result<()> {
|
|
|
|
let message = fs::read(file)?;
|
|
|
|
|
|
|
|
let signature_path = with_extension(file, ".sig");
|
|
|
|
let signature = fs::read(signature_path)?;
|
|
|
|
|
|
|
|
let public_key = fs::read_to_string(public_key)?;
|
|
|
|
|
|
|
|
crypto::verify(&message, &signature, &public_key)?;
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn with_extension(path: &Path, extension: &str) -> PathBuf {
|
|
|
|
let mut file_path = path.to_path_buf().into_os_string();
|
|
|
|
file_path.push(extension);
|
|
|
|
PathBuf::from(file_path)
|
|
|
|
}
|
2022-11-23 09:26:26 -05:00
|
|
|
|
|
|
|
fn install(public_key: &Path, bootspec: &Path) -> Result<()> {
|
|
|
|
let lanzaboote_bin = std::env::var("LANZABOOTE")?;
|
|
|
|
install::install(public_key, bootspec, Path::new(&lanzaboote_bin))
|
|
|
|
}
|