diff --git a/flake.nix b/flake.nix index 4861f8e..4f716cb 100644 --- a/flake.nix +++ b/flake.nix @@ -64,6 +64,10 @@ ]; }; + lanzatool = naersk-stable.buildPackage { + src = ./lanzatool; + }; + osrel = pkgs.writeText "lanzaboote-osrel" '' NAME=Lanzaboote VERSION="${lanzaboote.version}" @@ -82,7 +86,7 @@ ''; in { packages.x86_64-linux = { - inherit qemuUefi uefi-run lanzaboote lanzaboote-uki; + inherit qemuUefi uefi-run lanzaboote lanzaboote-uki lanzatool; default = lanzaboote-uki; }; @@ -91,6 +95,7 @@ qemuUefi uefi-run rust-nightly + lanzatool ]; }; }; diff --git a/lanzatool/Cargo.lock b/lanzatool/Cargo.lock new file mode 100644 index 0000000..2736bea --- /dev/null +++ b/lanzatool/Cargo.lock @@ -0,0 +1,255 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "anyhow" +version = "1.0.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "216261ddc8289130e551ddcd5ce8a064710c0d064a4d2895c67151c92b5443f6" + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "clap" +version = "4.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2148adefda54e14492fb9bddcc600b4344c5d1a3123bd666dcb939c6f0e0e57e" +dependencies = [ + "atty", + "bitflags", + "clap_derive", + "clap_lex", + "once_cell", + "strsim", + "termcolor", +] + +[[package]] +name = "clap_derive" +version = "4.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0177313f9f02afc995627906bbd8967e2be069f5261954222dac78290c2b9014" +dependencies = [ + "heck", + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d4198f73e42b4936b35b5bb248d81d2b595ecb170da0bac7655c54eedfa8da8" +dependencies = [ + "os_str_bytes", +] + +[[package]] +name = "ct-codecs" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3b7eb4404b8195a9abb6356f4ac07d8ba267045c8d6d220ac4dc992e6cc75df" + +[[package]] +name = "ed25519-compact" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f2d21333b679bbbac680b3eb45c86937e42f69277028f4e97b599b80b86c253" +dependencies = [ + "ct-codecs", + "getrandom", +] + +[[package]] +name = "getrandom" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "heck" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "lanzasign" +version = "0.1.0" +dependencies = [ + "anyhow", + "clap", + "ed25519-compact", +] + +[[package]] +name = "libc" +version = "0.2.137" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7fcc620a3bff7cdd7a365be3376c97191aeaccc2a603e600951e452615bf89" + +[[package]] +name = "once_cell" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860" + +[[package]] +name = "os_str_bytes" +version = "6.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b7820b9daea5457c9f21c69448905d723fbd21136ccf521748f23fd49e723ee" + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro2" +version = "1.0.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "syn" +version = "1.0.103" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a864042229133ada95abf3b54fdc62ef5ccabe9515b64717bcb9a1919e59445d" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "termcolor" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "unicode-ident" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/lanzatool/Cargo.toml b/lanzatool/Cargo.toml new file mode 100644 index 0000000..339de02 --- /dev/null +++ b/lanzatool/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "lanztool" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +anyhow = "1.0.66" +clap = { version = "4.0.26", features = ["derive"] } +ed25519-compact = "2.0.2" diff --git a/lanzatool/src/cli.rs b/lanzatool/src/cli.rs new file mode 100644 index 0000000..6576b7c --- /dev/null +++ b/lanzatool/src/cli.rs @@ -0,0 +1,79 @@ +use std::fs; +use std::path::{Path, PathBuf}; + +use anyhow::Result; +use clap::{Parser, Subcommand}; + +use crate::crypto; + +#[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 }, +} + +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), + } + } +} + +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) +} diff --git a/lanzatool/src/crypto.rs b/lanzatool/src/crypto.rs new file mode 100644 index 0000000..6433c1f --- /dev/null +++ b/lanzatool/src/crypto.rs @@ -0,0 +1,22 @@ +use anyhow::Result; +use ed25519_compact::{KeyPair, Noise, PublicKey, SecretKey, Seed, Signature}; + +pub fn generate_key() -> KeyPair { + KeyPair::from_seed(Seed::default()) +} + +pub fn sign(message: &[u8], private_key: &str) -> Result { + let private_key = SecretKey::from_pem(private_key)?; + let signature = private_key.sign(message, Some(Noise::generate())); + + Ok(signature) +} + +pub fn verify(message: &[u8], signature: &[u8], public_key: &str) -> Result<()> { + let signature = Signature::from_slice(signature)?; + let public_key = PublicKey::from_pem(public_key)?; + + public_key.verify(message, &signature)?; + + Ok(()) +} diff --git a/lanzatool/src/main.rs b/lanzatool/src/main.rs new file mode 100644 index 0000000..e09cbcc --- /dev/null +++ b/lanzatool/src/main.rs @@ -0,0 +1,18 @@ +mod cli; +mod crypto; + +use std::process; + +use anyhow::Result; +use clap::Parser; + +use cli::Cli; + +fn main() -> Result<()> { + let cli = Cli::parse(); + if let Err(e) = cli.call() { + eprintln!("{}", e); + process::exit(1) + }; + Ok(()) +}