From b6417cf8d4416c829cbd139553f29eb64a914265 Mon Sep 17 00:00:00 2001 From: Bernd Schoolmann Date: Fri, 10 Jan 2025 12:41:16 +0100 Subject: [PATCH 1/3] Add signing module --- Cargo.lock | 116 +++++++++++------ crates/bitwarden-crypto/Cargo.toml | 4 + crates/bitwarden-crypto/src/error.rs | 9 ++ crates/bitwarden-crypto/src/lib.rs | 1 + .../bitwarden-crypto/src/signing/ed25519.rs | 119 ++++++++++++++++++ crates/bitwarden-crypto/src/signing/mod.rs | 108 ++++++++++++++++ .../bitwarden-crypto/src/signing/signature.rs | 43 +++++++ 7 files changed, 364 insertions(+), 36 deletions(-) create mode 100644 crates/bitwarden-crypto/src/signing/ed25519.rs create mode 100644 crates/bitwarden-crypto/src/signing/mod.rs create mode 100644 crates/bitwarden-crypto/src/signing/signature.rs diff --git a/Cargo.lock b/Cargo.lock index 7f03988d..d95080a8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -168,6 +168,21 @@ dependencies = [ "zeroize", ] +[[package]] +name = "arrayref" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" + +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" +dependencies = [ + "zeroize", +] + [[package]] name = "askama" version = "0.12.1" @@ -424,14 +439,17 @@ dependencies = [ "aes", "argon2", "base64", + "blake3", "cbc", "criterion", + "ed25519-dalek", "generic-array", "hkdf", "hmac", "num-bigint", "num-traits", "pbkdf2", + "pkcs8", "rand", "rand_chacha", "rayon", @@ -441,6 +459,7 @@ dependencies = [ "serde_json", "sha1", "sha2", + "signature", "subtle", "thiserror 1.0.69", "tsify-next", @@ -676,6 +695,20 @@ dependencies = [ "digest", ] +[[package]] +name = "blake3" +version = "1.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8ee0c1824c4dea5b5f81736aff91bae041d2c07ee1192bec91054e10e3e601e" +dependencies = [ + "arrayref", + "arrayvec", + "cc", + "cfg-if", + "constant_time_eq", + "zeroize", +] + [[package]] name = "block-buffer" version = "0.10.4" @@ -789,9 +822,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.3" +version = "1.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27f657647bcff5394bf56c7317665bbf790a137a50eaaa5c6bfbb9e27a518f2d" +checksum = "9157bbaa6b165880c27a4293a474c91cdcf265cc68cc829bf10be0964a391caf" dependencies = [ "shlex", ] @@ -1000,6 +1033,12 @@ version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" +[[package]] +name = "constant_time_eq" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" + [[package]] name = "core-foundation" version = "0.9.4" @@ -1084,9 +1123,9 @@ dependencies = [ [[package]] name = "crossbeam-deque" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" dependencies = [ "crossbeam-epoch", "crossbeam-utils", @@ -1103,9 +1142,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.20" +version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "crossterm" @@ -1216,6 +1255,7 @@ dependencies = [ "fiat-crypto", "rustc_version", "subtle", + "zeroize", ] [[package]] @@ -1414,8 +1454,12 @@ checksum = "4a3daa8e81a3963a60642bcc1f90a670680bd4a77535faa384e9d1c79d620871" dependencies = [ "curve25519-dalek", "ed25519", + "rand_core", + "serde", "sha2", + "signature", "subtle", + "zeroize", ] [[package]] @@ -1877,9 +1921,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hyper" -version = "1.5.1" +version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97818827ef4f364230e16705d4706e2897df2bb60617d6ca15d598025a3c481f" +checksum = "256fb8d4bd6413123cc9d91832d78325c48ff41677595be797d90f42969beae0" dependencies = [ "bytes", "futures-channel", @@ -1898,9 +1942,9 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.27.3" +version = "0.27.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08afdbb5c31130e3034af566421053ab03787c640246a446327f550d11bcb333" +checksum = "f6884a48c6826ec44f524c7456b163cebe9e55a18d7b5e307cb4f100371cc767" dependencies = [ "futures-util", "http", @@ -2898,7 +2942,7 @@ dependencies = [ "rustc-hash", "rustls", "socket2", - "thiserror 2.0.6", + "thiserror 2.0.8", "tokio", "tracing", ] @@ -2917,7 +2961,7 @@ dependencies = [ "rustls", "rustls-pki-types", "slab", - "thiserror 2.0.6", + "thiserror 2.0.8", "tinyvec", "tracing", "web-time", @@ -2925,9 +2969,9 @@ dependencies = [ [[package]] name = "quinn-udp" -version = "0.5.8" +version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52cd4b1eff68bf27940dd39811292c49e007f4d0b4c357358dc9b0197be6b527" +checksum = "1c40286217b4ba3a71d644d752e6a0b71f13f1b6a2c5311acfcbe0c2418ed904" dependencies = [ "cfg_aliases", "libc", @@ -2998,9 +3042,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.7" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" +checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834" dependencies = [ "bitflags 2.6.0", ] @@ -3159,9 +3203,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.19" +version = "0.23.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "934b404430bb06b3fae2cba809eb45a1ab1aecd64491213d7c3301b88393f8d1" +checksum = "5065c3f250cbd332cd894be57c40fa52387247659b14a2d6041d121547903b1b" dependencies = [ "once_cell", "ring", @@ -3195,9 +3239,9 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.10.0" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16f1201b3c9a7ee8039bcadc17b7e605e2945b27eee7631788c1bd2b0643674b" +checksum = "d2bf47e6ff922db3825eb750c4e2ff784c6ff8fb9e13046ef6a1d1c5401b0b37" dependencies = [ "web-time", ] @@ -3379,9 +3423,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.12.1" +version = "2.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa39c7303dc58b5543c94d22c1766b0d31f2ee58306363ea622b10bbc075eaa2" +checksum = "1863fd3768cd83c56a7f60faa4dc0d403f1b6df0a38c3c25f44b7894e45370d5" dependencies = [ "core-foundation-sys", "libc", @@ -3389,18 +3433,18 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.23" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" +checksum = "3cb6eb87a131f756572d7fb904f6e7b68633f09cca868c5df1c4b8d1a694bbba" dependencies = [ "serde", ] [[package]] name = "serde" -version = "1.0.215" +version = "1.0.216" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" +checksum = "0b9781016e935a97e8beecf0c933758c97a5520d32930e460142b4cd80c6338e" dependencies = [ "serde_derive", ] @@ -3418,9 +3462,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.215" +version = "1.0.216" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" +checksum = "46f859dbbf73865c6627ed570e78961cd3ac92407a2d117204c49232485da55e" dependencies = [ "proc-macro2", "quote", @@ -3864,11 +3908,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.6" +version = "2.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fec2a1820ebd077e2b90c4df007bebf344cd394098a13c563957d0afc83ea47" +checksum = "08f5383f3e0071702bf93ab5ee99b52d26936be9dedd9413067cbdcddcb6141a" dependencies = [ - "thiserror-impl 2.0.6", + "thiserror-impl 2.0.8", ] [[package]] @@ -3884,9 +3928,9 @@ dependencies = [ [[package]] name = "thiserror-impl" -version = "2.0.6" +version = "2.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d65750cab40f4ff1929fb1ba509e9914eb756131cef4210da8d5d700d26f6312" +checksum = "f2f357fcec90b3caef6623a099691be676d033b40a058ac95d2a6ade6fa0c943" dependencies = [ "proc-macro2", "quote", @@ -4168,9 +4212,9 @@ checksum = "7e51b68083f157f853b6379db119d1c1be0e6e4dec98101079dec41f6f5cf6df" [[package]] name = "unicode-bidi" -version = "0.3.17" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ab17db44d7388991a428b2ee655ce0c212e862eff1768a455c58f9aad6e7893" +checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" [[package]] name = "unicode-ident" @@ -4619,7 +4663,7 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys 0.48.0", + "windows-sys 0.59.0", ] [[package]] diff --git a/crates/bitwarden-crypto/Cargo.toml b/crates/bitwarden-crypto/Cargo.toml index 7bf32615..5b65786a 100644 --- a/crates/bitwarden-crypto/Cargo.toml +++ b/crates/bitwarden-crypto/Cargo.toml @@ -27,13 +27,16 @@ argon2 = { version = ">=0.5.0, <0.6", features = [ "zeroize", ], default-features = false } base64 = ">=0.22.1, <0.23" +blake3 = { version = "1.5.5", features = ["zeroize"] } cbc = { version = ">=0.1.2, <0.2", features = ["alloc", "zeroize"] } +ed25519-dalek = { version = "2.1.1", features = ["alloc", "digest", "pem", "pkcs8", "rand_core", "signature"] } generic-array = { version = ">=0.14.7, <1.0", features = ["zeroize"] } hkdf = ">=0.12.3, <0.13" hmac = ">=0.12.1, <0.13" num-bigint = ">=0.4, <0.5" num-traits = ">=0.2.15, <0.3" pbkdf2 = { version = ">=0.12.1, <0.13", default-features = false } +pkcs8 = "0.10.2" rand = ">=0.8.5, <0.9" rayon = ">=1.8.1, <2.0" rsa = ">=0.9.2, <0.10" @@ -41,6 +44,7 @@ schemars = { workspace = true } serde = { workspace = true } sha1 = ">=0.10.5, <0.11" sha2 = ">=0.10.6, <0.11" +signature = "2.2.0" subtle = ">=2.5.0, <3.0" thiserror = { workspace = true } tsify-next = { workspace = true, optional = true } diff --git a/crates/bitwarden-crypto/src/error.rs b/crates/bitwarden-crypto/src/error.rs index 2f9a58b8..c202f585 100644 --- a/crates/bitwarden-crypto/src/error.rs +++ b/crates/bitwarden-crypto/src/error.rs @@ -41,6 +41,15 @@ pub enum CryptoError { #[error("Number is zero")] ZeroNumber, + + #[error("Invalid signature algorithm")] + InvalidSignatureAlgorithm, + #[error("Signature Parse Error")] + SignatureParseError, + #[error("Invalid hash algorithm")] + InvalidHashAlgorithm, + #[error("Hash Parse Error")] + HashParseError, } #[derive(Debug, Error)] diff --git a/crates/bitwarden-crypto/src/lib.rs b/crates/bitwarden-crypto/src/lib.rs index 40f7a63c..51c77aec 100644 --- a/crates/bitwarden-crypto/src/lib.rs +++ b/crates/bitwarden-crypto/src/lib.rs @@ -75,6 +75,7 @@ pub use fingerprint::fingerprint; mod keys; pub use keys::*; mod rsa; +mod signing; pub use crate::rsa::RsaKeyPair; mod util; pub use util::{generate_random_alphanumeric, generate_random_bytes, pbkdf2}; diff --git a/crates/bitwarden-crypto/src/signing/ed25519.rs b/crates/bitwarden-crypto/src/signing/ed25519.rs new file mode 100644 index 00000000..98a4b167 --- /dev/null +++ b/crates/bitwarden-crypto/src/signing/ed25519.rs @@ -0,0 +1,119 @@ +use ::signature::SignerMut; +use base64::{engine::general_purpose::STANDARD, Engine}; +use ed25519_dalek::{ed25519, SigningKey, VerifyingKey}; +use pkcs8::{der::Decode, DecodePrivateKey, EncodePrivateKey, PrivateKeyInfo}; + +use super::{signature, SignerImpl, VerifierImpl}; +use crate::{error::Result, CryptoError, EncString, KeyDecryptable, SymmetricCryptoKey}; + +pub(crate) struct Ed25519Verifier { + inner: VerifyingKey, +} + +impl VerifierImpl for Ed25519Verifier { + fn verify(&self, data: &[u8], signature: &signature::Signature) -> bool { + let signature_bytes: [u8; 64] = signature.data.clone().try_into().unwrap(); + let signature = ed25519_dalek::Signature::from_bytes(&signature_bytes); + self.inner.verify_strict(data, &signature).is_ok() + } +} + +pub(crate) struct Ed25519Signer { + inner: SigningKey, +} + +impl SignerImpl for Ed25519Signer { + fn sign(&mut self, data: &[u8]) -> signature::Signature { + let res = self.inner.sign(data); + signature::Signature::new(super::SignatureAlgorithm::Ed25519, res.to_bytes().to_vec()) + } + + fn verifier(&self) -> Ed25519Verifier { + Ed25519Verifier { + inner: self.inner.verifying_key(), + } + } + + fn generate(rng: &mut R) -> Self { + Self { + inner: SigningKey::generate(rng), + } + } +} + +// impl Ed25519KeyPair { +// fn verifier(&self) -> VerifyingKey { +// let spki = STANDARD.decode(&self.verifier).unwrap(); +// let decoded_public_key: VerifyingKey = +// pkcs8::DecodePublicKey::from_public_key_der(spki.as_slice()).unwrap(); +// decoded_public_key +// } + +// fn signer(&self, key: &SymmetricCryptoKey) -> Result { +// let pkcs8_private_key: Vec = self.signer.decrypt_with_key(key).unwrap(); +// let pkcs8_private_key = pkcs8_private_key.as_slice(); +// let signing_key = SigningKey::from_pkcs8_der(pkcs8_private_key).unwrap(); +// Ok(signing_key) +// } +// } + +// pub(crate) fn make_key_pair(encapsulating_key: &SymmetricCryptoKey) -> Result { +// let mut rng = rand::thread_rng(); +// let signing_key: SigningKey = SigningKey::generate(&mut rng); +// let verifying_key: VerifyingKey = signing_key.verifying_key(); +// let pkcs8_private_key = &signing_key.to_pkcs8_der().unwrap(); +// let private_key_info = PrivateKeyInfo::from_der(pkcs8_private_key.as_bytes()).unwrap(); +// private_key_info.algorithm.oid == ed25519::pkcs8::ALGORITHM_OID; +// let pkcs8_private_key = pkcs8_private_key.as_bytes(); +// let spki = pkcs8::EncodePublicKey::to_public_key_der(&verifying_key).unwrap(); +// let public_key_b64 = STANDARD.encode(spki.as_bytes()); + +// let protected = EncString::encrypt_aes256_hmac( +// pkcs8_private_key.as_ref(), +// encapsulating_key +// .mac_key +// .as_ref() +// .ok_or(CryptoError::InvalidMac)?, +// &encapsulating_key.key, +// )?; + +// Ok(Ed25519KeyPair { +// verifier: public_key_b64, +// signer: protected, +// }) +// } + +// impl Verifier for VerifyingKey { +// fn verify(&self, data: &[u8], signature: &signature::Signature) -> bool { +// let signature_bytes: [u8; 64] = signature.data.clone().try_into().unwrap(); +// let signature = ed25519_dalek::Signature::from_bytes(&signature_bytes); +// self.verify_strict(data, &signature).is_ok() +// } +// } + +// impl Signer for SigningKey { +// fn sign(&mut self, data: &[u8]) -> signature::Signature { +// let res = self.sign(self, data); +// signature::Signature::new(super::SignatureAlgorithm::Ed25519, res.data) +// } +// fn verifier(&self) -> impl Verifier; +// } + +// #[cfg(test)] +// mod tests { +// use crate::{ +// signing::ed25519::{make_key_pair, sign_ed25519, verify_ed25519}, +// SymmetricCryptoKey, +// }; + +// #[test] +// fn test_make_key_pair_and_sign() { +// let key = SymmetricCryptoKey::generate(rand::thread_rng()); +// let key_pair = make_key_pair(&key).unwrap(); +// let verifier = key_pair.verifier(); +// let mut signer = key_pair.signer(&key).unwrap(); +// let data = b"hello world"; +// let signature = sign_ed25519(&mut signer, data).unwrap(); +// assert!(verify_ed25519(&verifier, data, &signature)); +// } +// } diff --git a/crates/bitwarden-crypto/src/signing/mod.rs b/crates/bitwarden-crypto/src/signing/mod.rs new file mode 100644 index 00000000..dfc630a0 --- /dev/null +++ b/crates/bitwarden-crypto/src/signing/mod.rs @@ -0,0 +1,108 @@ +mod ed25519; +pub mod signature; + +#[derive(Debug, Clone, PartialEq)] +pub enum SignatureAlgorithm { + Ed25519, +} + +enum SignatureImpl { + Ed25519(ed25519::Ed25519Signer), +} + +enum VerifyImpl { + Ed25519(ed25519::Ed25519Verifier), +} + +struct Signer { + impl_: SignatureImpl, +} + +struct Verifier { + impl_: VerifyImpl, +} + +impl Signer { + pub(crate) fn generate( + rng: &mut R, + algorithm: &SignatureAlgorithm, + ) -> Self { + match algorithm { + SignatureAlgorithm::Ed25519 => { + let signing_key = ed25519::Ed25519Signer::generate(rng); + Signer { + impl_: SignatureImpl::Ed25519(signing_key), + } + } + } + } + + pub(crate) fn sign(&mut self, data: &[u8]) -> signature::Signature { + match &mut self.impl_ { + SignatureImpl::Ed25519(signer) => signer.sign(data), + } + } + + pub(crate) fn verifier(&self) -> Verifier { + match &self.impl_ { + SignatureImpl::Ed25519(signer) => Verifier { + impl_: VerifyImpl::Ed25519(signer.verifier()), + }, + } + } +} + +impl Verifier { + pub(crate) fn verify(&self, data: &[u8], signature: &signature::Signature) -> bool { + match &self.impl_ { + VerifyImpl::Ed25519(verifier) => { + if !signature.algorithm().eq(&SignatureAlgorithm::Ed25519) { + return false; + } + verifier.verify(data, signature) + } + } + } +} + +impl SignatureAlgorithm { + pub fn from_str(algorithm: &str) -> Option { + match algorithm { + "ed25519" => Some(Self::Ed25519), + _ => None, + } + } + + pub fn to_string(&self) -> String { + match self { + Self::Ed25519 => "ed25519".to_string(), + } + } +} + +trait VerifierImpl { + fn verify(&self, data: &[u8], signature: &signature::Signature) -> bool; +} + +trait SignerImpl { + fn sign(&mut self, data: &[u8]) -> signature::Signature; + fn verifier(&self) -> V; + fn generate(rng: &mut R) -> Self; +} + +#[cfg(test)] +mod tests { + use rand::rngs::OsRng; + + use super::*; + + #[test] + fn test_sign_verify() { + let mut rng = OsRng; + let mut signer = Signer::generate(&mut rng, &SignatureAlgorithm::Ed25519); + let verifier = signer.verifier(); + let data = b"hello world"; + let signature = signer.sign(data); + assert!(verifier.verify(data, &signature)); + } +} diff --git a/crates/bitwarden-crypto/src/signing/signature.rs b/crates/bitwarden-crypto/src/signing/signature.rs new file mode 100644 index 00000000..6856dde4 --- /dev/null +++ b/crates/bitwarden-crypto/src/signing/signature.rs @@ -0,0 +1,43 @@ +use base64::{prelude::BASE64_STANDARD, Engine}; + +use super::SignatureAlgorithm; +use crate::CryptoError; + +#[derive(Debug, PartialEq, Clone)] +pub(crate) struct Signature { + algorithm: SignatureAlgorithm, + pub(crate) data: Vec, +} + +impl Signature { + pub fn new(algorithm: SignatureAlgorithm, data: Vec) -> Self { + Self { algorithm, data } + } + + pub fn to_string(&self) -> String { + format!( + "{}:{}", + self.algorithm.to_string(), + BASE64_STANDARD.encode(&self.data) + ) + } + + pub fn from_string(s: &str) -> Result { + let parts: Vec<&str> = s.split(':').collect(); + if parts.len() != 2 { + return Err(CryptoError::SignatureParseError); + } + + let algorithm = + SignatureAlgorithm::from_str(parts[0]).ok_or(CryptoError::InvalidSignatureAlgorithm)?; + let data = BASE64_STANDARD + .decode(parts[1]) + .map_err(|_| CryptoError::SignatureParseError)?; + + Ok(Self { algorithm, data }) + } + + pub fn algorithm(&self) -> &SignatureAlgorithm { + &self.algorithm + } +} From a3c131eaeed2308532d66710215faf09d965cfc8 Mon Sep 17 00:00:00 2001 From: Bernd Schoolmann Date: Fri, 10 Jan 2025 16:30:31 +0100 Subject: [PATCH 2/3] Continue draft for signing & trust support --- crates/bitwarden-crypto/Cargo.toml | 10 +- crates/bitwarden-crypto/src/keys/key_hash.rs | 81 +++++++++++++ crates/bitwarden-crypto/src/keys/mod.rs | 2 + .../bitwarden-crypto/src/keys/signing_key.rs | 77 +++++++++++++ crates/bitwarden-crypto/src/lib.rs | 3 +- crates/bitwarden-crypto/src/sign.rs | 75 ++++++++++++ .../bitwarden-crypto/src/signing/ed25519.rs | 108 +++++------------- crates/bitwarden-crypto/src/signing/mod.rs | 49 +++++++- crates/bitwarden-wasm-internal/npm/VERSION | 1 + 9 files changed, 323 insertions(+), 83 deletions(-) create mode 100644 crates/bitwarden-crypto/src/keys/key_hash.rs create mode 100644 crates/bitwarden-crypto/src/keys/signing_key.rs create mode 100644 crates/bitwarden-crypto/src/sign.rs create mode 100644 crates/bitwarden-wasm-internal/npm/VERSION diff --git a/crates/bitwarden-crypto/Cargo.toml b/crates/bitwarden-crypto/Cargo.toml index 5b65786a..a73ba583 100644 --- a/crates/bitwarden-crypto/Cargo.toml +++ b/crates/bitwarden-crypto/Cargo.toml @@ -29,7 +29,14 @@ argon2 = { version = ">=0.5.0, <0.6", features = [ base64 = ">=0.22.1, <0.23" blake3 = { version = "1.5.5", features = ["zeroize"] } cbc = { version = ">=0.1.2, <0.2", features = ["alloc", "zeroize"] } -ed25519-dalek = { version = "2.1.1", features = ["alloc", "digest", "pem", "pkcs8", "rand_core", "signature"] } +ed25519-dalek = { version = "2.1.1", features = [ + "alloc", + "digest", + "pem", + "pkcs8", + "rand_core", + "signature", +] } generic-array = { version = ">=0.14.7, <1.0", features = ["zeroize"] } hkdf = ">=0.12.3, <0.13" hmac = ">=0.12.1, <0.13" @@ -42,6 +49,7 @@ rayon = ">=1.8.1, <2.0" rsa = ">=0.9.2, <0.10" schemars = { workspace = true } serde = { workspace = true } +serde_json.workspace = true sha1 = ">=0.10.5, <0.11" sha2 = ">=0.10.6, <0.11" signature = "2.2.0" diff --git a/crates/bitwarden-crypto/src/keys/key_hash.rs b/crates/bitwarden-crypto/src/keys/key_hash.rs new file mode 100644 index 00000000..9b07fed8 --- /dev/null +++ b/crates/bitwarden-crypto/src/keys/key_hash.rs @@ -0,0 +1,81 @@ +use base64::{engine::general_purpose::STANDARD, Engine}; +use serde::{Deserialize, Serialize}; + +use crate::CryptoError; + +#[derive(PartialEq, Serialize, Deserialize)] +pub(crate) enum KeyHashAlgorithm { + Blake3, +} + +impl KeyHashAlgorithm { + pub(crate) fn from_str(s: &str) -> Option { + match s { + "blake3" => Some(Self::Blake3), + _ => None, + } + } + + pub(crate) fn to_string(&self) -> String { + match self { + Self::Blake3 => "blake3".to_string(), + } + } +} + +#[derive(PartialEq, Serialize, Deserialize)] +pub(crate) struct KeyHash { + pub(crate) hash: Vec, + pub(crate) algorithm: KeyHashAlgorithm, +} + +impl KeyHash { + pub(crate) fn from_str(s: &str) -> Result { + let parts: Vec<&str> = s.split(':').collect(); + if parts.len() != 2 { + return Err(CryptoError::HashParseError); + } + + let algorithm = + KeyHashAlgorithm::from_str(parts[0]).ok_or(CryptoError::InvalidHashAlgorithm)?; + let hash = STANDARD + .decode(parts[1]) + .map_err(|_| CryptoError::HashParseError)?; + + Ok(Self { algorithm, hash }) + } + + pub(crate) fn to_string(&self) -> String { + format!( + "{}:{}", + self.algorithm.to_string(), + STANDARD.encode(&self.hash) + ) + } + + /// only for debugging + pub(crate) fn default() -> Self { + Self { + hash: vec![0; 32], + algorithm: KeyHashAlgorithm::Blake3, + } + } +} + +pub(crate) trait KeyHashable { + fn hash(&self) -> KeyHash; +} + +impl KeyHashable for T { + fn hash(&self) -> KeyHash { + let hash: [u8; 32] = blake3::hash(&self.hash_data()).into(); + KeyHash { + hash: hash.to_vec(), + algorithm: KeyHashAlgorithm::Blake3, + } + } +} + +pub(crate) trait KeyHashData { + fn hash_data(&self) -> Vec; +} diff --git a/crates/bitwarden-crypto/src/keys/mod.rs b/crates/bitwarden-crypto/src/keys/mod.rs index ac173296..5d9c42fa 100644 --- a/crates/bitwarden-crypto/src/keys/mod.rs +++ b/crates/bitwarden-crypto/src/keys/mod.rs @@ -21,4 +21,6 @@ mod device_key; pub use device_key::{DeviceKey, TrustDeviceResponse}; mod pin_key; pub use pin_key::PinKey; +pub(crate) mod key_hash; +pub(crate) mod signing_key; mod utils; diff --git a/crates/bitwarden-crypto/src/keys/signing_key.rs b/crates/bitwarden-crypto/src/keys/signing_key.rs new file mode 100644 index 00000000..7f7bdadb --- /dev/null +++ b/crates/bitwarden-crypto/src/keys/signing_key.rs @@ -0,0 +1,77 @@ +use std::pin::Pin; + +use super::key_encryptable::CryptoKey; +use crate::{ + error::Result, + signing::{SignatureAlgorithm, Signer, Verifier}, +}; + +pub trait Verifiable { + fn verifier(&self) -> VerifyingCryptoKey; +} + +pub struct VerifyingCryptoKey { + verifier: Verifier, +} + +impl VerifyingCryptoKey { + pub fn from_spki_der(der: &[u8]) -> Result { + Ok(Self { + verifier: Verifier::from_spki_der(der)?, + }) + } + + pub fn to_spki_der(&self) -> Vec { + self.verifier.to_spki_der() + } +} + +#[derive(Clone)] +pub struct SigningCryptoKey { + pub(crate) signing_key: Pin>, +} + +const _: () = { + fn assert_zeroize_on_drop() {} + fn assert_all() { + assert_zeroize_on_drop::(); + } +}; + +impl zeroize::ZeroizeOnDrop for SigningCryptoKey {} + +impl SigningCryptoKey { + pub fn generate(rng: &mut R) -> Self { + let algorithm = SignatureAlgorithm::Ed25519; + Self { + signing_key: Box::pin(Signer::generate(rng, &algorithm)), + } + } + + pub fn from_der(der: &[u8]) -> Result { + Ok(Self { + signing_key: Box::pin(Signer::from_pkcs8_der(der)?), + }) + } + + pub fn to_der(&self) -> Result> { + Ok(self.signing_key.to_pkcs8_der()) + } +} + +impl Verifiable for SigningCryptoKey { + fn verifier(&self) -> VerifyingCryptoKey { + VerifyingCryptoKey { + verifier: self.signing_key.verifier(), + } + } +} + +impl CryptoKey for SigningCryptoKey {} + +// We manually implement these to make sure we don't print any sensitive data +impl std::fmt::Debug for SigningCryptoKey { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("SigningCryptoKey").finish() + } +} diff --git a/crates/bitwarden-crypto/src/lib.rs b/crates/bitwarden-crypto/src/lib.rs index 51c77aec..96482092 100644 --- a/crates/bitwarden-crypto/src/lib.rs +++ b/crates/bitwarden-crypto/src/lib.rs @@ -75,7 +75,8 @@ pub use fingerprint::fingerprint; mod keys; pub use keys::*; mod rsa; -mod signing; +mod sign; +pub(crate) mod signing; pub use crate::rsa::RsaKeyPair; mod util; pub use util::{generate_random_alphanumeric, generate_random_bytes, pbkdf2}; diff --git a/crates/bitwarden-crypto/src/sign.rs b/crates/bitwarden-crypto/src/sign.rs new file mode 100644 index 00000000..51bded22 --- /dev/null +++ b/crates/bitwarden-crypto/src/sign.rs @@ -0,0 +1,75 @@ +use serde::{Deserialize, Serialize}; + +use crate::{ + key_hash::{self, KeyHash}, + signing, + signing_key::{SigningCryptoKey, VerifyingCryptoKey}, + CryptoError, +}; + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +pub enum TrustIdentity { + User(String), + Organization(String), +} + +#[derive(Serialize, Deserialize, PartialEq)] +struct IdentityTrustMessage { + identity: TrustIdentity, + verifying_key_fingerprint: KeyHash, +} + +pub enum SignatureContext { + IdentityTrust(TrustIdentity), +} + +pub struct Signature { + context: SignatureContext, + data: Vec, + signature_data: signing::signature::Signature, + signing_key_hash: KeyHash, +} + +/// Generate a trust signature, that shows that the current user trusts the identity of the peer +/// with the given identity key. +/// # Arguments +/// * `own_signing_key` - The signing key of the current user +/// * `peer_verifying_key` - The verifying key of the peer +/// * `peer_identity` - The identity of the peer +pub fn trust_identity_key( + own_signing_key: &mut SigningCryptoKey, + peer_verifying_key: &VerifyingCryptoKey, + peer_identity: TrustIdentity, +) -> Result { + let message = IdentityTrustMessage { + identity: peer_identity.clone(), + verifying_key_fingerprint: key_hash::KeyHash::default(), + }; + + let message_bytes = serde_json::to_vec(&message).map_err(|_| CryptoError::InvalidKey)?; + + Ok(Signature { + context: SignatureContext::IdentityTrust(peer_identity), + data: message_bytes.clone(), + signature_data: own_signing_key.signing_key.sign(&message_bytes), + signing_key_hash: key_hash::KeyHash::default(), + }) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::{signing::Signer, signing_key::Verifiable}; + + #[test] + fn test_trust_identity_key() { + let mut own_signing_key = SigningCryptoKey::generate(&mut rand::thread_rng()); + let peer_signing_key = SigningCryptoKey::generate(&mut rand::thread_rng()); + let peer_verifying_key = peer_signing_key.verifier(); + let peer_identity = TrustIdentity::User("test_user_id".to_string()); + + let signature = + trust_identity_key(&mut own_signing_key, &peer_verifying_key, peer_identity) + .expect("Failed to generate trust signature"); + } +} diff --git a/crates/bitwarden-crypto/src/signing/ed25519.rs b/crates/bitwarden-crypto/src/signing/ed25519.rs index 98a4b167..bbb132b3 100644 --- a/crates/bitwarden-crypto/src/signing/ed25519.rs +++ b/crates/bitwarden-crypto/src/signing/ed25519.rs @@ -1,11 +1,11 @@ use ::signature::SignerMut; -use base64::{engine::general_purpose::STANDARD, Engine}; -use ed25519_dalek::{ed25519, SigningKey, VerifyingKey}; -use pkcs8::{der::Decode, DecodePrivateKey, EncodePrivateKey, PrivateKeyInfo}; +use ed25519_dalek::{SigningKey, VerifyingKey}; +use pkcs8::{DecodePrivateKey, EncodePrivateKey}; use super::{signature, SignerImpl, VerifierImpl}; -use crate::{error::Result, CryptoError, EncString, KeyDecryptable, SymmetricCryptoKey}; +use crate::{error::Result, CryptoError}; +#[derive(Clone)] pub(crate) struct Ed25519Verifier { inner: VerifyingKey, } @@ -18,6 +18,22 @@ impl VerifierImpl for Ed25519Verifier { } } +impl Ed25519Verifier { + pub(crate) fn from_der(data: &[u8]) -> Result { + let key_bytes: [u8; 32] = data.try_into().map_err(|_| CryptoError::InvalidKey)?; + let verifying_key = + VerifyingKey::from_bytes(&key_bytes).map_err(|_| CryptoError::InvalidKey)?; + Ok(Self { + inner: verifying_key, + }) + } + + pub(crate) fn to_der(&self) -> Vec { + self.inner.to_bytes().to_vec() + } +} + +#[derive(Clone)] pub(crate) struct Ed25519Signer { inner: SigningKey, } @@ -41,79 +57,13 @@ impl SignerImpl for Ed25519Signer { } } -// impl Ed25519KeyPair { -// fn verifier(&self) -> VerifyingKey { -// let spki = STANDARD.decode(&self.verifier).unwrap(); -// let decoded_public_key: VerifyingKey = -// pkcs8::DecodePublicKey::from_public_key_der(spki.as_slice()).unwrap(); -// decoded_public_key -// } - -// fn signer(&self, key: &SymmetricCryptoKey) -> Result { -// let pkcs8_private_key: Vec = self.signer.decrypt_with_key(key).unwrap(); -// let pkcs8_private_key = pkcs8_private_key.as_slice(); -// let signing_key = SigningKey::from_pkcs8_der(pkcs8_private_key).unwrap(); -// Ok(signing_key) -// } -// } - -// pub(crate) fn make_key_pair(encapsulating_key: &SymmetricCryptoKey) -> Result { -// let mut rng = rand::thread_rng(); -// let signing_key: SigningKey = SigningKey::generate(&mut rng); -// let verifying_key: VerifyingKey = signing_key.verifying_key(); -// let pkcs8_private_key = &signing_key.to_pkcs8_der().unwrap(); -// let private_key_info = PrivateKeyInfo::from_der(pkcs8_private_key.as_bytes()).unwrap(); -// private_key_info.algorithm.oid == ed25519::pkcs8::ALGORITHM_OID; -// let pkcs8_private_key = pkcs8_private_key.as_bytes(); -// let spki = pkcs8::EncodePublicKey::to_public_key_der(&verifying_key).unwrap(); -// let public_key_b64 = STANDARD.encode(spki.as_bytes()); - -// let protected = EncString::encrypt_aes256_hmac( -// pkcs8_private_key.as_ref(), -// encapsulating_key -// .mac_key -// .as_ref() -// .ok_or(CryptoError::InvalidMac)?, -// &encapsulating_key.key, -// )?; - -// Ok(Ed25519KeyPair { -// verifier: public_key_b64, -// signer: protected, -// }) -// } - -// impl Verifier for VerifyingKey { -// fn verify(&self, data: &[u8], signature: &signature::Signature) -> bool { -// let signature_bytes: [u8; 64] = signature.data.clone().try_into().unwrap(); -// let signature = ed25519_dalek::Signature::from_bytes(&signature_bytes); -// self.verify_strict(data, &signature).is_ok() -// } -// } - -// impl Signer for SigningKey { -// fn sign(&mut self, data: &[u8]) -> signature::Signature { -// let res = self.sign(self, data); -// signature::Signature::new(super::SignatureAlgorithm::Ed25519, res.data) -// } -// fn verifier(&self) -> impl Verifier; -// } - -// #[cfg(test)] -// mod tests { -// use crate::{ -// signing::ed25519::{make_key_pair, sign_ed25519, verify_ed25519}, -// SymmetricCryptoKey, -// }; +impl Ed25519Signer { + pub(crate) fn from_der(data: &[u8]) -> Result { + let signing_key = SigningKey::from_pkcs8_der(data).map_err(|_| CryptoError::InvalidKey)?; + Ok(Self { inner: signing_key }) + } -// #[test] -// fn test_make_key_pair_and_sign() { -// let key = SymmetricCryptoKey::generate(rand::thread_rng()); -// let key_pair = make_key_pair(&key).unwrap(); -// let verifier = key_pair.verifier(); -// let mut signer = key_pair.signer(&key).unwrap(); -// let data = b"hello world"; -// let signature = sign_ed25519(&mut signer, data).unwrap(); -// assert!(verify_ed25519(&verifier, data, &signature)); -// } -// } + pub(crate) fn to_der(&self) -> Vec { + self.inner.to_pkcs8_der().unwrap().as_bytes().to_vec() + } +} diff --git a/crates/bitwarden-crypto/src/signing/mod.rs b/crates/bitwarden-crypto/src/signing/mod.rs index dfc630a0..42b89b39 100644 --- a/crates/bitwarden-crypto/src/signing/mod.rs +++ b/crates/bitwarden-crypto/src/signing/mod.rs @@ -1,3 +1,8 @@ +use pkcs8::{der::Decode, PrivateKeyInfo, SubjectPublicKeyInfoRef}; +use zeroize::ZeroizeOnDrop; + +use crate::{key_hash::KeyHash, signing_key::SigningCryptoKey, CryptoError}; + mod ed25519; pub mod signature; @@ -6,19 +11,25 @@ pub enum SignatureAlgorithm { Ed25519, } +#[derive(Clone)] enum SignatureImpl { Ed25519(ed25519::Ed25519Signer), } +#[derive(Clone)] enum VerifyImpl { Ed25519(ed25519::Ed25519Verifier), } -struct Signer { +#[derive(Clone)] +pub(crate) struct Signer { impl_: SignatureImpl, } -struct Verifier { +impl ZeroizeOnDrop for Signer {} + +#[derive(Clone)] +pub(crate) struct Verifier { impl_: VerifyImpl, } @@ -50,6 +61,23 @@ impl Signer { }, } } + + pub(crate) fn from_pkcs8_der(data: &[u8]) -> Result { + let private_key_info = + PrivateKeyInfo::from_der(data).map_err(|_| CryptoError::KeyDecrypt)?; + match private_key_info.algorithm.oid { + ed25519_dalek::ed25519::pkcs8::ALGORITHM_OID => Ok(Signer { + impl_: SignatureImpl::Ed25519(ed25519::Ed25519Signer::from_der(data)?), + }), + _ => Err(CryptoError::InvalidKey), + } + } + + pub(crate) fn to_pkcs8_der(&self) -> Vec { + match &self.impl_ { + SignatureImpl::Ed25519(signer) => signer.to_der(), + } + } } impl Verifier { @@ -63,6 +91,23 @@ impl Verifier { } } } + + pub(crate) fn from_spki_der(data: &[u8]) -> Result { + let public_key_info = + SubjectPublicKeyInfoRef::from_der(data).map_err(|_| CryptoError::InvalidKey)?; + match public_key_info.algorithm.oid { + ed25519_dalek::ed25519::pkcs8::ALGORITHM_OID => Ok(Verifier { + impl_: VerifyImpl::Ed25519(ed25519::Ed25519Verifier::from_der(data)?), + }), + _ => Err(CryptoError::InvalidKey), + } + } + + pub(crate) fn to_spki_der(&self) -> Vec { + match &self.impl_ { + VerifyImpl::Ed25519(verifier) => verifier.to_der(), + } + } } impl SignatureAlgorithm { diff --git a/crates/bitwarden-wasm-internal/npm/VERSION b/crates/bitwarden-wasm-internal/npm/VERSION new file mode 100644 index 00000000..42d90fed --- /dev/null +++ b/crates/bitwarden-wasm-internal/npm/VERSION @@ -0,0 +1 @@ +611ae0b6bad34196111acf7570feba9cbf861bc1 From 1a51803bd6892b42d2652e8886362568c1e051cd Mon Sep 17 00:00:00 2001 From: Bernd Schoolmann Date: Fri, 10 Jan 2025 17:12:46 +0100 Subject: [PATCH 3/3] Add verification and add keyhashes --- crates/bitwarden-crypto/src/error.rs | 2 + .../bitwarden-crypto/src/keys/signing_key.rs | 16 +++++- .../src/keys/symmetric_crypto_key.rs | 8 ++- crates/bitwarden-crypto/src/sign.rs | 56 ++++++++++++++++--- 4 files changed, 72 insertions(+), 10 deletions(-) diff --git a/crates/bitwarden-crypto/src/error.rs b/crates/bitwarden-crypto/src/error.rs index c202f585..5913808e 100644 --- a/crates/bitwarden-crypto/src/error.rs +++ b/crates/bitwarden-crypto/src/error.rs @@ -50,6 +50,8 @@ pub enum CryptoError { InvalidHashAlgorithm, #[error("Hash Parse Error")] HashParseError, + #[error("Invalid signature")] + InvalidSignature, } #[derive(Debug, Error)] diff --git a/crates/bitwarden-crypto/src/keys/signing_key.rs b/crates/bitwarden-crypto/src/keys/signing_key.rs index 7f7bdadb..b3f324c8 100644 --- a/crates/bitwarden-crypto/src/keys/signing_key.rs +++ b/crates/bitwarden-crypto/src/keys/signing_key.rs @@ -1,6 +1,6 @@ use std::pin::Pin; -use super::key_encryptable::CryptoKey; +use super::{key_encryptable::CryptoKey, key_hash::KeyHashData}; use crate::{ error::Result, signing::{SignatureAlgorithm, Signer, Verifier}, @@ -11,7 +11,7 @@ pub trait Verifiable { } pub struct VerifyingCryptoKey { - verifier: Verifier, + pub(crate) verifier: Verifier, } impl VerifyingCryptoKey { @@ -31,6 +31,18 @@ pub struct SigningCryptoKey { pub(crate) signing_key: Pin>, } +impl KeyHashData for SigningCryptoKey { + fn hash_data(&self) -> Vec { + self.verifier().to_spki_der() + } +} + +impl KeyHashData for VerifyingCryptoKey { + fn hash_data(&self) -> Vec { + self.to_spki_der() + } +} + const _: () = { fn assert_zeroize_on_drop() {} fn assert_all() { diff --git a/crates/bitwarden-crypto/src/keys/symmetric_crypto_key.rs b/crates/bitwarden-crypto/src/keys/symmetric_crypto_key.rs index 971564b0..3f0c5cfa 100644 --- a/crates/bitwarden-crypto/src/keys/symmetric_crypto_key.rs +++ b/crates/bitwarden-crypto/src/keys/symmetric_crypto_key.rs @@ -6,7 +6,7 @@ use generic_array::GenericArray; use rand::Rng; use zeroize::Zeroize; -use super::key_encryptable::CryptoKey; +use super::{key_encryptable::CryptoKey, key_hash::KeyHashData}; use crate::CryptoError; /// A symmetric encryption key. Used to encrypt and decrypt [`EncString`](crate::EncString) @@ -135,6 +135,12 @@ impl std::fmt::Debug for SymmetricCryptoKey { } } +impl KeyHashData for SymmetricCryptoKey { + fn hash_data(&self) -> Vec { + self.to_vec() + } +} + #[cfg(test)] pub fn derive_symmetric_key(name: &str) -> SymmetricCryptoKey { use zeroize::Zeroizing; diff --git a/crates/bitwarden-crypto/src/sign.rs b/crates/bitwarden-crypto/src/sign.rs index 51bded22..e49cceea 100644 --- a/crates/bitwarden-crypto/src/sign.rs +++ b/crates/bitwarden-crypto/src/sign.rs @@ -1,9 +1,10 @@ use serde::{Deserialize, Serialize}; +use self::key_hash::KeyHashable; use crate::{ key_hash::{self, KeyHash}, signing, - signing_key::{SigningCryptoKey, VerifyingCryptoKey}, + signing_key::{SigningCryptoKey, Verifiable, VerifyingCryptoKey}, CryptoError, }; @@ -43,7 +44,7 @@ pub fn trust_identity_key( ) -> Result { let message = IdentityTrustMessage { identity: peer_identity.clone(), - verifying_key_fingerprint: key_hash::KeyHash::default(), + verifying_key_fingerprint: peer_verifying_key.hash(), }; let message_bytes = serde_json::to_vec(&message).map_err(|_| CryptoError::InvalidKey)?; @@ -52,14 +53,45 @@ pub fn trust_identity_key( context: SignatureContext::IdentityTrust(peer_identity), data: message_bytes.clone(), signature_data: own_signing_key.signing_key.sign(&message_bytes), - signing_key_hash: key_hash::KeyHash::default(), + signing_key_hash: own_signing_key.hash(), }) } +pub fn verify_identity_trust( + own_signing_key: &mut SigningCryptoKey, + peer_verifying_key: &VerifyingCryptoKey, + peer_identity: TrustIdentity, + signature: &Signature, +) -> Result<(), CryptoError> { + if let SignatureContext::IdentityTrust(message_peer_identity) = &signature.context { + if !message_peer_identity.eq(&peer_identity) { + return Err(CryptoError::InvalidSignature); + } + } else { + return Err(CryptoError::InvalidSignature); + } + + let message = IdentityTrustMessage { + identity: peer_identity.clone(), + verifying_key_fingerprint: peer_verifying_key.hash(), + }; + + let message_bytes = serde_json::to_vec(&message).map_err(|_| CryptoError::InvalidKey)?; + if !own_signing_key + .verifier() + .verifier + .verify(&message_bytes, &signature.signature_data) + { + return Err(CryptoError::InvalidSignature); + } + + Ok(()) +} + #[cfg(test)] mod tests { use super::*; - use crate::{signing::Signer, signing_key::Verifiable}; + use crate::signing_key::Verifiable; #[test] fn test_trust_identity_key() { @@ -68,8 +100,18 @@ mod tests { let peer_verifying_key = peer_signing_key.verifier(); let peer_identity = TrustIdentity::User("test_user_id".to_string()); - let signature = - trust_identity_key(&mut own_signing_key, &peer_verifying_key, peer_identity) - .expect("Failed to generate trust signature"); + let signature = trust_identity_key( + &mut own_signing_key, + &peer_verifying_key, + peer_identity.clone(), + ) + .expect("Failed to generate trust signature"); + let verified = verify_identity_trust( + &mut own_signing_key, + &peer_verifying_key, + peer_identity, + &signature, + ); + assert!(verified.is_ok()); } }