From 1a51803bd6892b42d2652e8886362568c1e051cd Mon Sep 17 00:00:00 2001 From: Bernd Schoolmann Date: Fri, 10 Jan 2025 17:12:46 +0100 Subject: [PATCH] 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()); } }