diff --git a/Cargo.lock b/Cargo.lock index 8c3ff1b..9edc54e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1459,6 +1459,22 @@ version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" +[[package]] +name = "verifier" +version = "0.1.0" +dependencies = [ + "anyhow", + "attest-data", + "const-oid", + "ed25519-dalek", + "env_logger", + "log", + "p384", + "pem-rfc7468", + "sha3", + "x509-cert", +] + [[package]] name = "verifier-cli" version = "0.1.0" @@ -1475,6 +1491,7 @@ dependencies = [ "pem-rfc7468", "sha3", "tempfile", + "verifier", "x509-cert", ] diff --git a/verifier-cli/Cargo.toml b/verifier-cli/Cargo.toml index f3bf4c3..fc3e014 100644 --- a/verifier-cli/Cargo.toml +++ b/verifier-cli/Cargo.toml @@ -18,4 +18,5 @@ p384 = { workspace = true, default-features = true } pem-rfc7468 = { workspace = true, features = ["alloc", "std"] } sha3.workspace = true tempfile.workspace = true +verifier.path = "../verifier" x509-cert = { workspace = true, default-features = true } diff --git a/verifier-cli/src/main.rs b/verifier-cli/src/main.rs index 48510ed..d2bc581 100644 --- a/verifier-cli/src/main.rs +++ b/verifier-cli/src/main.rs @@ -2,16 +2,12 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at https://mozilla.org/MPL/2.0/. -mod pki_path; - use anyhow::{anyhow, Context, Result}; use attest_data::{Attestation, Nonce}; use clap::{Parser, Subcommand, ValueEnum}; -use ed25519_dalek::{Signature, Verifier, VerifyingKey}; use env_logger::Builder; use log::{debug, error, info, warn, LevelFilter}; use pem_rfc7468::{LineEnding, PemLabel}; -use pki_path::PkiPathSignatureVerifier; use sha3::{Digest, Sha3_256}; use std::{ fmt::{self, Debug, Formatter}, @@ -21,6 +17,7 @@ use std::{ process::{Command, Output}, }; use tempfile::NamedTempFile; +use verifier::PkiPathSignatureVerifier; use x509_cert::{ der::{Decode, DecodePem}, Certificate, PkiPath, @@ -479,33 +476,16 @@ fn main() -> Result<()> { log, nonce, } => { - // To verify an attestation we need to extract and construct a few - // things before we can verify the attestation: - // - signature: the attestation produced by the RoT when - // `alias_priv` is used to sign `message` let attestation = fs::read(attestation)?; let (attestation, _): (Attestation, _) = hubpack::deserialize(&attestation).map_err(|e| { anyhow!("Failed to deserialize Attestation: {}", e) })?; - let signature = match attestation { - Attestation::Ed25519(s) => Signature::from_bytes(&s.0), - }; - // - log_data: the hubpack encoded measurement log `hubpack(log)` let log = fs::read(log)?; - // - nonce: nonce provided to RoT when the attestation provided - // was collected - let nonce = fs::read(nonce)?; - // - message: the data that's signed by the RoT to produce an - // attestation `sha3_256(log_data | nonce)` - let mut message = Sha3_256::new(); - message.update(log); - message.update(nonce); - let message = message.finalize(); + let nonce: Nonce = fs::read(nonce)?.try_into()?; - // - verifier: public key / `alias_pub` from pair used to sign the attestation let alias = fs::read(alias_cert)?; let alias = match pem_rfc7468::decode_vec(&alias) { Ok((l, v)) => { @@ -521,16 +501,10 @@ fn main() -> Result<()> { alias } }; + let alias = Certificate::from_der(&alias)?; - let alias = alias - .tbs_certificate - .subject_public_key_info - .subject_public_key - .as_bytes() - .ok_or_else(|| anyhow!("Invalid / unaligned public key"))?; - - let verifying_key = VerifyingKey::from_bytes(alias.try_into()?)?; - verifying_key.verify(message.as_slice(), &signature)?; + + verifier::verify_attestation(&alias, &attestation, &log, &nonce)?; } AttestCommand::VerifyCertChain { cert_chain, diff --git a/verifier/Cargo.toml b/verifier/Cargo.toml new file mode 100644 index 0000000..4d047bb --- /dev/null +++ b/verifier/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "verifier" +version = "0.1.0" +edition = "2021" +description = "a library crate implementing the attestation verifier" +license = "MPL-2.0" + +[dependencies] +anyhow = { workspace = true, features = ["std"] } +attest-data = { path = "../attest-data", features = ["std"] } +const-oid = { workspace = true, features = ["db"] } +ed25519-dalek = { workspace = true, features = ["std"] } +env_logger.workspace = true +log.workspace = true +p384 = { workspace = true, default-features = true } +pem-rfc7468 = { workspace = true, features = ["alloc", "std"] } +sha3.workspace = true +x509-cert = { workspace = true, default-features = true } diff --git a/verifier-cli/src/pki_path.rs b/verifier/src/lib.rs similarity index 86% rename from verifier-cli/src/pki_path.rs rename to verifier/src/lib.rs index 6bb59f5..ef5ba20 100644 --- a/verifier-cli/src/pki_path.rs +++ b/verifier/src/lib.rs @@ -3,7 +3,9 @@ // file, You can obtain one at https://mozilla.org/MPL/2.0/. use anyhow::{anyhow, Result}; +use attest_data::{Attestation, Nonce}; use const_oid::db::{rfc5912::ID_EC_PUBLIC_KEY, rfc8410::ID_ED_25519}; +use sha3::{Digest, Sha3_256}; use x509_cert::{der::Encode, Certificate, PkiPath}; /// Unit-like struct with a single non-member associated function. This @@ -225,3 +227,38 @@ impl PkiPathSignatureVerifier { } } } + +pub fn verify_attestation( + alias: &Certificate, + attestation: &Attestation, + log: &[u8], + nonce: &Nonce, +) -> Result<()> { + use ed25519_dalek::{Signature, Verifier, VerifyingKey}; + + // To verify an attestation we need to extract and construct a few + // things before we can verify the attestation: + // - signature: the attestation produced by the RoT when + // `alias_priv` is used to sign `message` + let signature = match attestation { + Attestation::Ed25519(s) => Signature::from_bytes(&s.0), + }; + + // - message: the data that's signed by the RoT to produce an + // attestation `sha3_256(log | nonce)` + let mut message = Sha3_256::new(); + message.update(log); + message.update(nonce); + let message = message.finalize(); + + let alias = alias + .tbs_certificate + .subject_public_key_info + .subject_public_key + .as_bytes() + .ok_or_else(|| anyhow!("Invalid / unaligned public key"))?; + + let verifying_key = VerifyingKey::from_bytes(alias.try_into()?)?; + verifying_key.verify(message.as_slice(), &signature)?; + todo!("verify_attestation"); +}