diff --git a/cdn-proto/src/connection/auth/broker.rs b/cdn-proto/src/connection/auth/broker.rs index b6daffc..c75839c 100644 --- a/cdn-proto/src/connection/auth/broker.rs +++ b/cdn-proto/src/connection/auth/broker.rs @@ -16,7 +16,7 @@ use tracing::error; use crate::{ bail, connection::protocols::Connection, - crypto::signature::SignatureScheme, + crypto::signature::{Namespace, SignatureScheme}, def::{PublicKey, RunDef, Scheme}, discovery::{BrokerIdentifier, DiscoveryClient}, error::{Error, Result}, @@ -169,9 +169,13 @@ impl BrokerAuth { ) .as_secs(); - // Sign the timestamp from above + // Sign the timestamp from above (with a namespace) let signature = bail!( - Scheme::::sign(&keypair.private_key, ×tamp.to_le_bytes()), + Scheme::::sign( + &keypair.private_key, + Namespace::BrokerBrokerAuth.as_str(), + ×tamp.to_le_bytes() + ), Crypto, "failed to sign message" ); @@ -261,6 +265,7 @@ impl BrokerAuth { // Verify the signature if !Scheme::::verify( &public_key, + Namespace::BrokerBrokerAuth.as_str(), &auth_message.timestamp.to_le_bytes(), &auth_message.signature, ) { diff --git a/cdn-proto/src/connection/auth/marshal.rs b/cdn-proto/src/connection/auth/marshal.rs index c316ba5..418ea3c 100644 --- a/cdn-proto/src/connection/auth/marshal.rs +++ b/cdn-proto/src/connection/auth/marshal.rs @@ -16,6 +16,7 @@ use tracing::error; use crate::{ bail, connection::protocols::Connection, + crypto::signature::Namespace, def::{PublicKey, RunDef, Scheme}, discovery::DiscoveryClient, error::{Error, Result}, @@ -64,6 +65,7 @@ impl MarshalAuth { // Verify the signature if !Scheme::::verify( &public_key, + Namespace::UserMarshalAuth.as_str(), &auth_message.timestamp.to_le_bytes(), &auth_message.signature, ) { diff --git a/cdn-proto/src/connection/auth/user.rs b/cdn-proto/src/connection/auth/user.rs index 248f4df..3f7bb7b 100644 --- a/cdn-proto/src/connection/auth/user.rs +++ b/cdn-proto/src/connection/auth/user.rs @@ -12,7 +12,6 @@ use std::{ time::{SystemTime, UNIX_EPOCH}, }; -use crate::connection::protocols::Connection; use crate::crypto::signature::Serializable; use crate::{ bail, @@ -21,6 +20,7 @@ use crate::{ error::{Error, Result}, message::{AuthenticateWithKey, AuthenticateWithPermit, Message, Topic}, }; +use crate::{connection::protocols::Connection, crypto::signature::Namespace}; /// This is the `UserAuth` struct that we define methods to for authentication purposes. pub struct UserAuth(PhantomData); @@ -48,7 +48,11 @@ impl UserAuth { // Sign the timestamp from above let signature = bail!( - Scheme::::sign(&keypair.private_key, ×tamp.to_le_bytes()), + Scheme::::sign( + &keypair.private_key, + Namespace::UserMarshalAuth.as_str(), + ×tamp.to_le_bytes() + ), Crypto, "failed to sign message" ); diff --git a/cdn-proto/src/crypto/signature.rs b/cdn-proto/src/crypto/signature.rs index 650067c..90db49e 100644 --- a/cdn-proto/src/crypto/signature.rs +++ b/cdn-proto/src/crypto/signature.rs @@ -15,6 +15,22 @@ use jf_signature::{ use super::rng::DeterministicRng; +/// The auth namespaces for the signature scheme +pub enum Namespace { + UserMarshalAuth, + BrokerBrokerAuth, +} + +impl Namespace { + /// Get the namespace as a string + pub fn as_str(&self) -> &'static str { + match self { + Namespace::UserMarshalAuth => "espresso-cdn-user-marshal-auth", + Namespace::BrokerBrokerAuth => "espresso-cdn-broker-broker-auth", + } + } +} + /// This trait defines a generic signature scheme, wherein we can sign and verify messages /// with the associated public and private keys. pub trait SignatureScheme: Send + Sync + 'static { @@ -27,14 +43,23 @@ pub trait SignatureScheme: Send + Sync + 'static { /// /// # Errors /// If signing fails - fn sign(private_key: &Self::PrivateKey, message: &[u8]) -> Result>; + fn sign( + private_key: &Self::PrivateKey, + namespace: &'static str, + message: &[u8], + ) -> Result>; /// Verify a message with the public key, the message itself, and the signature. /// /// # Returns /// - false if verification failed /// - true if verification succeeded - fn verify(public_key: &Self::PublicKey, message: &[u8], signature: &[u8]) -> bool; + fn verify( + public_key: &Self::PublicKey, + namespace: &'static str, + message: &[u8], + signature: &[u8], + ) -> bool; } /// Allows for us to be generic over a serializable [signature | public key]. @@ -96,10 +121,22 @@ impl SignatureScheme for BLS { /// # Errors /// - If serialization fails /// - If signing fails - fn sign(private_key: &Self::PrivateKey, message: &[u8]) -> Result> { + fn sign( + private_key: &Self::PrivateKey, + namespace: &'static str, + message: &[u8], + ) -> Result> { + // Add the namespace to the message + let mut namespaced_message = namespace.as_bytes().to_vec(); + namespaced_message.extend_from_slice(message); + // Sign the message - let serialized_signature = - ::sign(&(), private_key, message, &mut DeterministicRng(0))?; + let serialized_signature = ::sign( + &(), + private_key, + namespaced_message, + &mut DeterministicRng(0), + )?; // Serialize the signature let mut buf = vec![]; @@ -115,7 +152,16 @@ impl SignatureScheme for BLS { /// # Errors /// - If signature deserialization fails /// - If signing fails - fn verify(public_key: &Self::PublicKey, message: &[u8], signature: &[u8]) -> bool { + fn verify( + public_key: &Self::PublicKey, + namespace: &'static str, + message: &[u8], + signature: &[u8], + ) -> bool { + // Add the namespace to the message + let mut namespaced_message = namespace.as_bytes().to_vec(); + namespaced_message.extend_from_slice(message); + // Deserialize the signature let Ok(signature) = ::Signature::deserialize_uncompressed(signature) @@ -124,6 +170,50 @@ impl SignatureScheme for BLS { }; // Verify the signature - ::verify(&(), public_key, message, &signature).is_ok() + ::verify(&(), public_key, namespaced_message, &signature).is_ok() + } +} + +#[cfg(test)] +mod test { + use rand::{rngs::StdRng, SeedableRng}; + + use super::*; + + #[test] + fn signature_namespace_parity() { + // Generate a keypair + let keypair = + BLS::key_gen(&(), &mut StdRng::seed_from_u64(0)).expect("failed to generate key"); + + // Sign a message with the namespace `UserMarshalAuth` + let signature = ::sign( + &keypair.0, + crate::crypto::signature::Namespace::UserMarshalAuth.as_str(), + b"hello world", + ) + .expect("failed to sign message"); + + // Verify the signature with the namespace `UserMarshalAuth` + assert!( + ::verify( + &keypair.1, + crate::crypto::signature::Namespace::UserMarshalAuth.as_str(), + b"hello world", + &signature, + ), + "failed to verify signature" + ); + + // Make sure it fails with the wrong namespace + assert!( + !::verify( + &keypair.1, + crate::crypto::signature::Namespace::BrokerBrokerAuth.as_str(), + b"hello world", + &signature, + ), + "verified signature with wrong namespace" + ); } } diff --git a/cdn-proto/src/discovery/redis.rs b/cdn-proto/src/discovery/redis.rs index c5e7344..a644905 100644 --- a/cdn-proto/src/discovery/redis.rs +++ b/cdn-proto/src/discovery/redis.rs @@ -142,7 +142,7 @@ impl DiscoveryClient for Redis { // Get the number of connections the broker has let num_connections: u64 = bail!( redis::cmd("GET") - .arg(&format!("{broker}/num_connections")) + .arg(format!("{broker}/num_connections")) .query_async(&mut self.underlying_connection) .await, Connection, @@ -152,7 +152,7 @@ impl DiscoveryClient for Redis { // Get the number of permits the broker has let num_permits: u64 = bail!( redis::cmd("SCARD") - .arg(&format!("{broker}/permits")) + .arg(format!("{broker}/permits")) .query_async(&mut self.underlying_connection) .await, Connection,