From c26d4f24fc367779e30a2ab9cdaf028b73cc536d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bogdan-=C8=98tefan=20Neac=C5=9Fu?= Date: Fri, 13 Dec 2024 10:38:25 +0200 Subject: [PATCH] Add conversion unit tests for auth msg (#5251) * Add conversion unit tests for auth msg * Fix remaining bad mac conversions --- common/authenticator-requests/src/lib.rs | 1 + common/authenticator-requests/src/util.rs | 71 ++ .../src/v2/registration.rs | 14 +- .../authenticator-requests/src/v2/request.rs | 2 +- .../authenticator-requests/src/v2/response.rs | 8 +- .../src/v3/conversion.rs | 576 +++++++++++++- .../src/v3/registration.rs | 14 +- .../authenticator-requests/src/v3/request.rs | 2 +- .../authenticator-requests/src/v3/response.rs | 10 +- common/authenticator-requests/src/v3/topup.rs | 2 +- .../src/v4/conversion.rs | 701 +++++++++++++++--- .../src/v4/registration.rs | 14 +- .../authenticator-requests/src/v4/request.rs | 4 +- .../authenticator-requests/src/v4/response.rs | 12 +- common/authenticator-requests/src/v4/topup.rs | 2 +- .../src/lib.rs | 2 +- .../authenticator/src/mixnet_listener.rs | 14 +- 17 files changed, 1304 insertions(+), 145 deletions(-) create mode 100644 common/authenticator-requests/src/util.rs diff --git a/common/authenticator-requests/src/lib.rs b/common/authenticator-requests/src/lib.rs index 27164417e8..ed987a9a50 100644 --- a/common/authenticator-requests/src/lib.rs +++ b/common/authenticator-requests/src/lib.rs @@ -8,6 +8,7 @@ pub mod v3; pub mod v4; mod error; +mod util; pub use error::Error; pub use v4 as latest; diff --git a/common/authenticator-requests/src/util.rs b/common/authenticator-requests/src/util.rs new file mode 100644 index 0000000000..cb1269f10c --- /dev/null +++ b/common/authenticator-requests/src/util.rs @@ -0,0 +1,71 @@ +// Copyright 2024 - Nym Technologies SA +// SPDX-License-Identifier: Apache-2.0 + +#[cfg(test)] +pub(crate) mod tests { + pub(crate) const CREDENTIAL_BYTES: [u8; 1245] = [ + 0, 0, 4, 133, 96, 179, 223, 185, 136, 23, 213, 166, 59, 203, 66, 69, 209, 181, 227, 254, + 16, 102, 98, 237, 59, 119, 170, 111, 31, 194, 51, 59, 120, 17, 115, 229, 79, 91, 11, 139, + 154, 2, 212, 23, 68, 70, 167, 3, 240, 54, 224, 171, 221, 1, 69, 48, 60, 118, 119, 249, 123, + 35, 172, 227, 131, 96, 232, 209, 187, 123, 4, 197, 102, 90, 96, 45, 125, 135, 140, 99, 1, + 151, 17, 131, 143, 157, 97, 107, 139, 232, 212, 87, 14, 115, 253, 255, 166, 167, 186, 43, + 90, 96, 173, 105, 120, 40, 10, 163, 250, 224, 214, 200, 178, 4, 160, 16, 130, 59, 76, 193, + 39, 240, 3, 101, 141, 209, 183, 226, 186, 207, 56, 210, 187, 7, 164, 240, 164, 205, 37, 81, + 184, 214, 193, 195, 90, 205, 238, 225, 195, 104, 12, 123, 203, 57, 233, 243, 215, 145, 195, + 196, 57, 38, 125, 172, 18, 47, 63, 165, 110, 219, 180, 40, 58, 116, 92, 254, 160, 98, 48, + 92, 254, 232, 107, 184, 80, 234, 60, 160, 235, 249, 76, 41, 38, 165, 28, 40, 136, 74, 48, + 166, 50, 245, 23, 201, 140, 101, 79, 93, 235, 128, 186, 146, 126, 180, 134, 43, 13, 186, + 19, 195, 48, 168, 201, 29, 216, 95, 176, 198, 132, 188, 64, 39, 212, 150, 32, 52, 53, 38, + 228, 199, 122, 226, 217, 75, 40, 191, 151, 48, 164, 242, 177, 79, 14, 122, 105, 151, 85, + 88, 199, 162, 17, 96, 103, 83, 178, 128, 9, 24, 30, 74, 108, 241, 85, 240, 166, 97, 241, + 85, 199, 11, 198, 226, 234, 70, 107, 145, 28, 208, 114, 51, 12, 234, 108, 101, 202, 112, + 48, 185, 22, 159, 67, 109, 49, 27, 149, 90, 109, 32, 226, 112, 7, 201, 208, 209, 104, 31, + 97, 134, 204, 145, 27, 181, 206, 181, 106, 32, 110, 136, 115, 249, 201, 111, 5, 245, 203, + 71, 121, 169, 126, 151, 178, 236, 59, 221, 195, 48, 135, 115, 6, 50, 227, 74, 97, 107, 107, + 213, 90, 2, 203, 154, 138, 47, 128, 52, 134, 128, 224, 51, 65, 240, 90, 8, 55, 175, 180, + 178, 204, 206, 168, 110, 51, 57, 189, 169, 48, 169, 136, 121, 99, 51, 170, 178, 214, 74, 1, + 96, 151, 167, 25, 173, 180, 171, 155, 10, 55, 142, 234, 190, 113, 90, 79, 80, 244, 71, 166, + 30, 235, 113, 150, 133, 1, 218, 17, 109, 111, 223, 24, 216, 177, 41, 2, 204, 65, 221, 212, + 207, 236, 144, 6, 65, 224, 55, 42, 1, 1, 161, 134, 118, 127, 111, 220, 110, 127, 240, 71, + 223, 129, 12, 93, 20, 220, 60, 56, 71, 146, 184, 95, 132, 69, 28, 56, 53, 192, 213, 22, + 119, 230, 152, 225, 182, 188, 163, 219, 37, 175, 247, 73, 14, 247, 38, 72, 243, 1, 48, 131, + 59, 8, 13, 96, 143, 185, 127, 241, 161, 217, 24, 149, 193, 40, 16, 30, 202, 151, 28, 119, + 240, 153, 101, 156, 61, 193, 72, 245, 199, 181, 12, 231, 65, 166, 67, 142, 121, 207, 202, + 58, 197, 113, 188, 248, 42, 124, 105, 48, 161, 241, 55, 209, 36, 194, 27, 63, 233, 144, + 189, 85, 117, 234, 9, 139, 46, 31, 206, 114, 95, 131, 29, 240, 13, 81, 142, 140, 133, 33, + 30, 41, 141, 37, 80, 217, 95, 221, 76, 115, 86, 201, 165, 51, 252, 9, 28, 209, 1, 48, 150, + 74, 248, 212, 187, 222, 66, 210, 3, 200, 19, 217, 171, 184, 42, 148, 53, 150, 57, 50, 6, + 227, 227, 62, 49, 42, 148, 148, 157, 82, 191, 58, 24, 34, 56, 98, 120, 89, 105, 176, 85, + 15, 253, 241, 41, 153, 195, 136, 1, 48, 142, 126, 213, 101, 223, 79, 133, 230, 105, 38, + 161, 149, 2, 21, 136, 150, 42, 72, 218, 85, 146, 63, 223, 58, 108, 186, 183, 248, 62, 20, + 47, 34, 113, 160, 177, 204, 181, 16, 24, 212, 224, 35, 84, 51, 168, 56, 136, 11, 1, 48, + 135, 242, 62, 149, 230, 178, 32, 224, 119, 26, 234, 163, 237, 224, 114, 95, 112, 140, 170, + 150, 96, 125, 136, 221, 180, 78, 18, 11, 12, 184, 2, 198, 217, 119, 43, 69, 4, 172, 109, + 55, 183, 40, 131, 172, 161, 88, 183, 101, 1, 48, 173, 216, 22, 73, 42, 255, 211, 93, 249, + 87, 159, 115, 61, 91, 55, 130, 17, 216, 60, 34, 122, 55, 8, 244, 244, 153, 151, 57, 5, 144, + 178, 55, 249, 64, 211, 168, 34, 148, 56, 89, 92, 203, 70, 124, 219, 152, 253, 165, 0, 32, + 203, 116, 63, 7, 240, 222, 82, 86, 11, 149, 167, 72, 224, 55, 190, 66, 201, 65, 168, 184, + 96, 47, 194, 241, 168, 124, 7, 74, 214, 250, 37, 76, 32, 218, 69, 122, 103, 215, 145, 169, + 24, 212, 229, 168, 106, 10, 144, 31, 13, 25, 178, 242, 250, 106, 159, 40, 48, 163, 165, 61, + 130, 57, 146, 4, 73, 32, 254, 233, 125, 135, 212, 29, 111, 4, 177, 114, 15, 210, 170, 82, + 108, 110, 62, 166, 81, 209, 106, 176, 156, 14, 133, 242, 60, 127, 120, 242, 28, 97, 0, 1, + 32, 103, 93, 109, 89, 240, 91, 1, 84, 150, 50, 206, 157, 203, 49, 220, 120, 234, 175, 234, + 150, 126, 225, 94, 163, 164, 199, 138, 114, 62, 99, 106, 112, 1, 32, 171, 40, 220, 82, 241, + 203, 76, 146, 111, 139, 182, 179, 237, 182, 115, 75, 128, 201, 107, 43, 214, 0, 135, 217, + 160, 68, 150, 232, 144, 114, 237, 98, 32, 30, 134, 232, 59, 93, 163, 253, 244, 13, 202, 52, + 147, 168, 83, 121, 123, 95, 21, 210, 209, 225, 223, 143, 49, 10, 205, 238, 1, 22, 83, 81, + 70, 1, 32, 26, 76, 6, 234, 160, 50, 139, 102, 161, 232, 155, 106, 130, 171, 226, 210, 233, + 178, 85, 247, 71, 123, 55, 53, 46, 67, 148, 137, 156, 207, 208, 107, 1, 32, 102, 31, 4, 98, + 110, 156, 144, 61, 229, 140, 198, 84, 196, 238, 128, 35, 131, 182, 137, 125, 241, 95, 69, + 131, 170, 27, 2, 144, 75, 72, 242, 102, 3, 32, 121, 80, 45, 173, 56, 65, 218, 27, 40, 251, + 197, 32, 169, 104, 123, 110, 90, 78, 153, 166, 38, 9, 129, 228, 99, 8, 1, 116, 142, 233, + 162, 69, 32, 216, 169, 159, 116, 95, 12, 63, 176, 195, 6, 183, 123, 135, 75, 61, 112, 106, + 83, 235, 176, 41, 27, 248, 48, 71, 165, 170, 12, 92, 103, 103, 81, 32, 58, 74, 75, 145, + 192, 94, 153, 69, 80, 128, 241, 3, 16, 117, 192, 86, 161, 103, 44, 174, 211, 196, 182, 124, + 55, 11, 107, 142, 49, 88, 6, 41, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0, 37, 139, 240, 0, 0, + 0, 0, 0, 0, 0, 1, + ]; + pub(crate) const RECIPIENT: &str = "CytBseW6yFXUMzz4SGAKdNLGR7q3sJLLYxyBGvutNEQV.4QXYyEVc5fUDjmmi8PrHN9tdUFV4PCvSJE1278cHyvoe@4sBbL1ngf1vtNqykydQKTFh26sQCw888GpUqvPvyNB4f"; +} diff --git a/common/authenticator-requests/src/v2/registration.rs b/common/authenticator-requests/src/v2/registration.rs index b7bf2d8430..f3aa22d749 100644 --- a/common/authenticator-requests/src/v2/registration.rs +++ b/common/authenticator-requests/src/v2/registration.rs @@ -29,7 +29,7 @@ pub type Taken = Option; pub const BANDWIDTH_CAP_PER_DAY: u64 = 1024 * 1024 * 1024; // 1 GB -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] pub struct InitMessage { /// Base64 encoded x25519 public key pub pub_key: PeerPublicKey, @@ -41,7 +41,7 @@ impl InitMessage { } } -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] pub struct FinalMessage { /// Gateway client data pub gateway_client: GatewayClient, @@ -50,28 +50,28 @@ pub struct FinalMessage { pub credential: Option, } -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] pub struct RegistrationData { pub nonce: u64, pub gateway_data: GatewayClient, pub wg_port: u16, } -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] pub struct RegistredData { pub pub_key: PeerPublicKey, pub private_ip: IpAddr, pub wg_port: u16, } -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] pub struct RemainingBandwidthData { pub available_bandwidth: i64, } /// Client that wants to register sends its PublicKey bytes mac digest encrypted with a DH shared secret. /// Gateway/Nym node can then verify pub_key payload using the same process -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] pub struct GatewayClient { /// Base64 encoded x25519 public key pub pub_key: PeerPublicKey, @@ -147,7 +147,7 @@ impl GatewayClient { // TODO: change the inner type into generic array of size HmacSha256::OutputSize // TODO2: rely on our internal crypto/hmac -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq)] pub struct ClientMac(Vec); impl fmt::Display for ClientMac { diff --git a/common/authenticator-requests/src/v2/request.rs b/common/authenticator-requests/src/v2/request.rs index 6943085af7..abd1e5ebff 100644 --- a/common/authenticator-requests/src/v2/request.rs +++ b/common/authenticator-requests/src/v2/request.rs @@ -87,7 +87,7 @@ impl AuthenticatorRequest { } } -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub enum AuthenticatorRequestData { Initial(InitMessage), Final(Box), diff --git a/common/authenticator-requests/src/v2/response.rs b/common/authenticator-requests/src/v2/response.rs index ab05dfcd35..1b389de43f 100644 --- a/common/authenticator-requests/src/v2/response.rs +++ b/common/authenticator-requests/src/v2/response.rs @@ -100,28 +100,28 @@ impl AuthenticatorResponse { } } -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub enum AuthenticatorResponseData { PendingRegistration(PendingRegistrationResponse), Registered(RegisteredResponse), RemainingBandwidth(RemainingBandwidthResponse), } -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub struct PendingRegistrationResponse { pub request_id: u64, pub reply_to: Recipient, pub reply: RegistrationData, } -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub struct RegisteredResponse { pub request_id: u64, pub reply_to: Recipient, pub reply: RegistredData, } -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub struct RemainingBandwidthResponse { pub request_id: u64, pub reply_to: Recipient, diff --git a/common/authenticator-requests/src/v3/conversion.rs b/common/authenticator-requests/src/v3/conversion.rs index fe0699ab8b..1a55576a0d 100644 --- a/common/authenticator-requests/src/v3/conversion.rs +++ b/common/authenticator-requests/src/v3/conversion.rs @@ -19,6 +19,24 @@ impl From for v3::request::AuthenticatorReque } } +impl TryFrom for v2::request::AuthenticatorRequest { + type Error = crate::Error; + + fn try_from( + authenticator_request: v3::request::AuthenticatorRequest, + ) -> Result { + Ok(Self { + protocol: Protocol { + version: 2, + service_provider_type: ServiceProviderType::Authenticator, + }, + data: authenticator_request.data.try_into()?, + reply_to: authenticator_request.reply_to, + request_id: authenticator_request.request_id, + }) + } +} + impl From for v3::request::AuthenticatorRequestData { fn from(authenticator_request_data: v2::request::AuthenticatorRequestData) -> Self { match authenticator_request_data { @@ -35,6 +53,29 @@ impl From for v3::request::AuthenticatorR } } +impl TryFrom for v2::request::AuthenticatorRequestData { + type Error = crate::Error; + + fn try_from( + authenticator_request_data: v3::request::AuthenticatorRequestData, + ) -> Result { + match authenticator_request_data { + v3::request::AuthenticatorRequestData::Initial(init_msg) => Ok( + v2::request::AuthenticatorRequestData::Initial(init_msg.into()), + ), + v3::request::AuthenticatorRequestData::Final(gw_client) => Ok( + v2::request::AuthenticatorRequestData::Final(gw_client.into()), + ), + v3::request::AuthenticatorRequestData::QueryBandwidth(pub_key) => Ok( + v2::request::AuthenticatorRequestData::QueryBandwidth(pub_key), + ), + v3::request::AuthenticatorRequestData::TopUpBandwidth(_) => Err( + Self::Error::Conversion("no top up bandwidth variant in v2".to_string()), + ), + } + } +} + impl From for v3::registration::InitMessage { fn from(init_msg: v2::registration::InitMessage) -> Self { Self { @@ -43,6 +84,14 @@ impl From for v3::registration::InitMessage { } } +impl From for v2::registration::InitMessage { + fn from(init_msg: v3::registration::InitMessage) -> Self { + Self { + pub_key: init_msg.pub_key, + } + } +} + impl From> for Box { fn from(gw_client: Box) -> Self { Box::new(v3::registration::FinalMessage { @@ -52,6 +101,15 @@ impl From> for Box> for Box { + fn from(gw_client: Box) -> Self { + Box::new(v2::registration::FinalMessage { + gateway_client: gw_client.gateway_client.into(), + credential: gw_client.credential, + }) + } +} + impl From for v3::registration::GatewayClient { fn from(gw_client: v2::registration::GatewayClient) -> Self { Self { @@ -93,7 +151,10 @@ impl TryFrom for v2::response::Authenticato Ok(Self { data: authenticator_response.data.try_into()?, reply_to: authenticator_response.reply_to, - protocol: authenticator_response.protocol, + protocol: Protocol { + version: 2, + service_provider_type: authenticator_response.protocol.service_provider_type, + }, }) } } @@ -101,7 +162,10 @@ impl TryFrom for v2::response::Authenticato impl From for v3::response::AuthenticatorResponse { fn from(value: v2::response::AuthenticatorResponse) -> Self { Self { - protocol: value.protocol, + protocol: Protocol { + version: 3, + service_provider_type: value.protocol.service_provider_type, + }, data: value.data.into(), reply_to: value.reply_to, } @@ -270,3 +334,511 @@ impl From for v3::registration::Remain } } } + +#[cfg(test)] +mod tests { + use std::{net::IpAddr, str::FromStr}; + + use nym_credentials_interface::CredentialSpendingData; + use nym_crypto::asymmetric::encryption::PrivateKey; + use nym_sphinx::addressing::Recipient; + use nym_wireguard_types::PeerPublicKey; + use x25519_dalek::PublicKey; + + use super::*; + use crate::util::tests::{CREDENTIAL_BYTES, RECIPIENT}; + + #[test] + fn upgrade_initial_req() { + let pub_key = PeerPublicKey::new(PublicKey::from([0; 32])); + let reply_to = Recipient::try_from_base58_string(RECIPIENT).unwrap(); + + let (msg, _) = v2::request::AuthenticatorRequest::new_initial_request( + v2::registration::InitMessage::new(pub_key), + reply_to, + ); + let upgraded_msg = v3::request::AuthenticatorRequest::from(msg); + + assert_eq!( + upgraded_msg.protocol, + Protocol { + version: 3, + service_provider_type: ServiceProviderType::Authenticator + } + ); + assert_eq!( + upgraded_msg.data, + v3::request::AuthenticatorRequestData::Initial(v3::registration::InitMessage { + pub_key + }) + ); + } + + #[test] + fn downgrade_initial_req() { + let pub_key = PeerPublicKey::new(PublicKey::from([0; 32])); + let reply_to = Recipient::try_from_base58_string(RECIPIENT).unwrap(); + + let (msg, _) = v3::request::AuthenticatorRequest::new_initial_request( + v3::registration::InitMessage::new(pub_key), + reply_to, + ); + let downgraded_msg = v2::request::AuthenticatorRequest::try_from(msg).unwrap(); + + assert_eq!( + downgraded_msg.protocol, + Protocol { + version: 2, + service_provider_type: ServiceProviderType::Authenticator + } + ); + assert_eq!( + downgraded_msg.data, + v2::request::AuthenticatorRequestData::Initial(v2::registration::InitMessage { + pub_key + }) + ); + } + + #[test] + fn upgrade_final_req() { + let mut rng = rand::thread_rng(); + + let local_secret = PrivateKey::new(&mut rng); + let remote_secret = x25519_dalek::StaticSecret::random_from_rng(&mut rng); + let private_ip = IpAddr::from_str("10.10.10.10").unwrap(); + let nonce = 42; + let gateway_client = v2::registration::GatewayClient::new( + &local_secret, + (&remote_secret).into(), + private_ip, + nonce, + ); + let credential = Some(CredentialSpendingData::try_from_bytes(&CREDENTIAL_BYTES).unwrap()); + let final_message = v2::registration::FinalMessage { + gateway_client, + credential: credential.clone(), + }; + let reply_to = Recipient::try_from_base58_string(RECIPIENT).unwrap(); + + let (msg, _) = + v2::request::AuthenticatorRequest::new_final_request(final_message, reply_to); + let upgraded_msg = v3::request::AuthenticatorRequest::from(msg); + + assert_eq!( + upgraded_msg.protocol, + Protocol { + version: 3, + service_provider_type: ServiceProviderType::Authenticator + } + ); + assert_eq!( + upgraded_msg.data, + v3::request::AuthenticatorRequestData::Final(Box::new( + v3::registration::FinalMessage { + gateway_client: v3::registration::GatewayClient::new( + &local_secret, + (&remote_secret).into(), + private_ip, + nonce, + ), + credential + } + )) + ); + } + + #[test] + fn downgrade_final_req() { + let mut rng = rand::thread_rng(); + + let local_secret = PrivateKey::new(&mut rng); + let remote_secret = x25519_dalek::StaticSecret::random_from_rng(&mut rng); + let private_ip = IpAddr::from_str("10.10.10.10").unwrap(); + let nonce = 42; + let gateway_client = v3::registration::GatewayClient::new( + &local_secret, + (&remote_secret).into(), + private_ip, + nonce, + ); + let credential = Some(CredentialSpendingData::try_from_bytes(&CREDENTIAL_BYTES).unwrap()); + let final_message = v3::registration::FinalMessage { + gateway_client, + credential: credential.clone(), + }; + let reply_to = Recipient::try_from_base58_string(RECIPIENT).unwrap(); + + let (msg, _) = + v3::request::AuthenticatorRequest::new_final_request(final_message, reply_to); + let upgraded_msg = v2::request::AuthenticatorRequest::try_from(msg).unwrap(); + + assert_eq!( + upgraded_msg.protocol, + Protocol { + version: 2, + service_provider_type: ServiceProviderType::Authenticator + } + ); + assert_eq!( + upgraded_msg.data, + v2::request::AuthenticatorRequestData::Final(Box::new( + v2::registration::FinalMessage { + gateway_client: v2::registration::GatewayClient::new( + &local_secret, + (&remote_secret).into(), + private_ip, + nonce, + ), + credential + } + )) + ); + } + + #[test] + fn upgrade_query_req() { + let pub_key = PeerPublicKey::new(PublicKey::from([0; 32])); + let reply_to = Recipient::try_from_base58_string(RECIPIENT).unwrap(); + + let (msg, _) = v2::request::AuthenticatorRequest::new_query_request(pub_key, reply_to); + let upgraded_msg = v3::request::AuthenticatorRequest::from(msg); + + assert_eq!( + upgraded_msg.protocol, + Protocol { + version: 3, + service_provider_type: ServiceProviderType::Authenticator + } + ); + assert_eq!( + upgraded_msg.data, + v3::request::AuthenticatorRequestData::QueryBandwidth(pub_key) + ); + } + + #[test] + fn downgrade_query_req() { + let pub_key = PeerPublicKey::new(PublicKey::from([0; 32])); + let reply_to = Recipient::try_from_base58_string(RECIPIENT).unwrap(); + + let (msg, _) = v3::request::AuthenticatorRequest::new_query_request(pub_key, reply_to); + let downgraded_msg = v2::request::AuthenticatorRequest::try_from(msg).unwrap(); + + assert_eq!( + downgraded_msg.protocol, + Protocol { + version: 2, + service_provider_type: ServiceProviderType::Authenticator + } + ); + assert_eq!( + downgraded_msg.data, + v2::request::AuthenticatorRequestData::QueryBandwidth(pub_key) + ); + } + + #[test] + fn downgrade_topup_req() { + let pub_key = PeerPublicKey::new(PublicKey::from([0; 32])); + let credential = CredentialSpendingData::try_from_bytes(&CREDENTIAL_BYTES).unwrap(); + let top_up_message = v3::topup::TopUpMessage { + pub_key, + credential, + }; + let reply_to = Recipient::try_from_base58_string(RECIPIENT).unwrap(); + + let (msg, _) = + v3::request::AuthenticatorRequest::new_topup_request(top_up_message, reply_to); + assert!(v2::request::AuthenticatorRequest::try_from(msg).is_err()); + } + + #[test] + fn upgrade_pending_reg_resp() { + let mut rng = rand::thread_rng(); + + let local_secret = PrivateKey::new(&mut rng); + let remote_secret = x25519_dalek::StaticSecret::random_from_rng(&mut rng); + let private_ip = IpAddr::from_str("10.10.10.10").unwrap(); + let nonce = 42; + let wg_port = 51822; + let gateway_data = v2::registration::GatewayClient::new( + &local_secret, + (&remote_secret).into(), + private_ip, + nonce, + ); + let registration_data = v2::registration::RegistrationData { + nonce, + gateway_data, + wg_port, + }; + let request_id = 123; + let reply_to = Recipient::try_from_base58_string(RECIPIENT).unwrap(); + + let msg = v2::response::AuthenticatorResponse::new_pending_registration_success( + registration_data, + request_id, + reply_to, + ); + let upgraded_msg = v3::response::AuthenticatorResponse::from(msg); + + assert_eq!( + upgraded_msg.protocol, + Protocol { + version: 3, + service_provider_type: ServiceProviderType::Authenticator + } + ); + assert_eq!( + upgraded_msg.data, + v3::response::AuthenticatorResponseData::PendingRegistration( + v3::response::PendingRegistrationResponse { + request_id, + reply_to, + reply: v3::registration::RegistrationData { + nonce, + gateway_data: v3::registration::GatewayClient::new( + &local_secret, + (&remote_secret).into(), + private_ip, + nonce, + ), + wg_port, + } + } + ) + ); + } + + #[test] + fn downgrade_pending_reg_resp() { + let mut rng = rand::thread_rng(); + + let local_secret = PrivateKey::new(&mut rng); + let remote_secret = x25519_dalek::StaticSecret::random_from_rng(&mut rng); + let private_ip = IpAddr::from_str("10.10.10.10").unwrap(); + let nonce = 42; + let wg_port = 51822; + let gateway_data = v3::registration::GatewayClient::new( + &local_secret, + (&remote_secret).into(), + private_ip, + nonce, + ); + let registration_data = v3::registration::RegistrationData { + nonce, + gateway_data, + wg_port, + }; + let request_id = 123; + let reply_to = Recipient::try_from_base58_string(RECIPIENT).unwrap(); + + let msg = v3::response::AuthenticatorResponse::new_pending_registration_success( + registration_data, + request_id, + reply_to, + ); + let downgraded_msg = v2::response::AuthenticatorResponse::try_from(msg).unwrap(); + + assert_eq!( + downgraded_msg.protocol, + Protocol { + version: 2, + service_provider_type: ServiceProviderType::Authenticator + } + ); + assert_eq!( + downgraded_msg.data, + v2::response::AuthenticatorResponseData::PendingRegistration( + v2::response::PendingRegistrationResponse { + request_id, + reply_to, + reply: v2::registration::RegistrationData { + nonce, + gateway_data: v2::registration::GatewayClient::new( + &local_secret, + (&remote_secret).into(), + private_ip, + nonce, + ), + wg_port, + } + } + ) + ); + } + + #[test] + fn upgrade_registered_resp() { + let pub_key = PeerPublicKey::new(PublicKey::from([0; 32])); + let private_ip = IpAddr::from_str("10.10.10.10").unwrap(); + let wg_port = 51822; + let registred_data = v2::registration::RegistredData { + pub_key, + private_ip, + wg_port, + }; + let request_id = 123; + let reply_to = Recipient::try_from_base58_string(RECIPIENT).unwrap(); + + let msg = v2::response::AuthenticatorResponse::new_registered( + registred_data, + reply_to, + request_id, + ); + let upgraded_msg = v3::response::AuthenticatorResponse::from(msg); + + assert_eq!( + upgraded_msg.protocol, + Protocol { + version: 3, + service_provider_type: ServiceProviderType::Authenticator + } + ); + assert_eq!( + upgraded_msg.data, + v3::response::AuthenticatorResponseData::Registered(v3::response::RegisteredResponse { + request_id, + reply_to, + reply: v3::registration::RegistredData { + wg_port, + pub_key, + private_ip + } + }) + ); + } + + #[test] + fn downgrade_registered_resp() { + let pub_key = PeerPublicKey::new(PublicKey::from([0; 32])); + let private_ip = IpAddr::from_str("10.10.10.10").unwrap(); + let wg_port = 51822; + let registred_data = v3::registration::RegistredData { + pub_key, + private_ip, + wg_port, + }; + let request_id = 123; + let reply_to = Recipient::try_from_base58_string(RECIPIENT).unwrap(); + + let msg = v3::response::AuthenticatorResponse::new_registered( + registred_data, + reply_to, + request_id, + ); + let downgraded_msg = v2::response::AuthenticatorResponse::try_from(msg).unwrap(); + + assert_eq!( + downgraded_msg.protocol, + Protocol { + version: 2, + service_provider_type: ServiceProviderType::Authenticator + } + ); + assert_eq!( + downgraded_msg.data, + v2::response::AuthenticatorResponseData::Registered(v2::response::RegisteredResponse { + request_id, + reply_to, + reply: v2::registration::RegistredData { + wg_port, + pub_key, + private_ip + } + }) + ); + } + + #[test] + fn upgrade_remaining_bandwidth_resp() { + let available_bandwidth = 42; + let remaining_bandwidth_data = Some(v2::registration::RemainingBandwidthData { + available_bandwidth, + }); + let request_id = 123; + let reply_to = Recipient::try_from_base58_string(RECIPIENT).unwrap(); + + let msg = v2::response::AuthenticatorResponse::new_remaining_bandwidth( + remaining_bandwidth_data, + reply_to, + request_id, + ); + let upgraded_msg = v3::response::AuthenticatorResponse::from(msg); + + assert_eq!( + upgraded_msg.protocol, + Protocol { + version: 3, + service_provider_type: ServiceProviderType::Authenticator + } + ); + assert_eq!( + upgraded_msg.data, + v3::response::AuthenticatorResponseData::RemainingBandwidth( + v3::response::RemainingBandwidthResponse { + request_id, + reply_to, + reply: Some(v3::registration::RemainingBandwidthData { + available_bandwidth, + }) + } + ) + ); + } + + #[test] + fn downgrade_remaining_bandwidth_resp() { + let available_bandwidth = 42; + let remaining_bandwidth_data = Some(v3::registration::RemainingBandwidthData { + available_bandwidth, + }); + let request_id = 123; + let reply_to = Recipient::try_from_base58_string(RECIPIENT).unwrap(); + + let msg = v3::response::AuthenticatorResponse::new_remaining_bandwidth( + remaining_bandwidth_data, + reply_to, + request_id, + ); + let downgraded_msg = v2::response::AuthenticatorResponse::try_from(msg).unwrap(); + + assert_eq!( + downgraded_msg.protocol, + Protocol { + version: 2, + service_provider_type: ServiceProviderType::Authenticator + } + ); + assert_eq!( + downgraded_msg.data, + v2::response::AuthenticatorResponseData::RemainingBandwidth( + v2::response::RemainingBandwidthResponse { + request_id, + reply_to, + reply: Some(v2::registration::RemainingBandwidthData { + available_bandwidth, + }) + } + ) + ); + } + + #[test] + fn downgrade_topup_resp() { + let available_bandwidth = 42; + let remaining_bandwidth_data = v3::registration::RemainingBandwidthData { + available_bandwidth, + }; + let request_id = 123; + let reply_to = Recipient::try_from_base58_string(RECIPIENT).unwrap(); + + let msg = v3::response::AuthenticatorResponse::new_topup_bandwidth( + remaining_bandwidth_data, + reply_to, + request_id, + ); + assert!(v2::response::AuthenticatorResponse::try_from(msg).is_err()); + } +} diff --git a/common/authenticator-requests/src/v3/registration.rs b/common/authenticator-requests/src/v3/registration.rs index 37234f7e1f..d9fac785a8 100644 --- a/common/authenticator-requests/src/v3/registration.rs +++ b/common/authenticator-requests/src/v3/registration.rs @@ -29,7 +29,7 @@ pub type Taken = Option; pub const BANDWIDTH_CAP_PER_DAY: u64 = 250 * 1024 * 1024 * 1024; // 250 GB -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] pub struct InitMessage { /// Base64 encoded x25519 public key pub pub_key: PeerPublicKey, @@ -41,7 +41,7 @@ impl InitMessage { } } -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] pub struct FinalMessage { /// Gateway client data pub gateway_client: GatewayClient, @@ -50,28 +50,28 @@ pub struct FinalMessage { pub credential: Option, } -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] pub struct RegistrationData { pub nonce: u64, pub gateway_data: GatewayClient, pub wg_port: u16, } -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] pub struct RegistredData { pub pub_key: PeerPublicKey, pub private_ip: IpAddr, pub wg_port: u16, } -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] pub struct RemainingBandwidthData { pub available_bandwidth: i64, } /// Client that wants to register sends its PublicKey bytes mac digest encrypted with a DH shared secret. /// Gateway/Nym node can then verify pub_key payload using the same process -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] pub struct GatewayClient { /// Base64 encoded x25519 public key pub pub_key: PeerPublicKey, @@ -147,7 +147,7 @@ impl GatewayClient { // TODO: change the inner type into generic array of size HmacSha256::OutputSize // TODO2: rely on our internal crypto/hmac -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq)] pub struct ClientMac(Vec); impl fmt::Display for ClientMac { diff --git a/common/authenticator-requests/src/v3/request.rs b/common/authenticator-requests/src/v3/request.rs index 32db17aed2..9a7940e1cc 100644 --- a/common/authenticator-requests/src/v3/request.rs +++ b/common/authenticator-requests/src/v3/request.rs @@ -106,7 +106,7 @@ impl AuthenticatorRequest { } } -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub enum AuthenticatorRequestData { Initial(InitMessage), Final(Box), diff --git a/common/authenticator-requests/src/v3/response.rs b/common/authenticator-requests/src/v3/response.rs index 370fc64671..ca44fb19f6 100644 --- a/common/authenticator-requests/src/v3/response.rs +++ b/common/authenticator-requests/src/v3/response.rs @@ -120,7 +120,7 @@ impl AuthenticatorResponse { } } -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub enum AuthenticatorResponseData { PendingRegistration(PendingRegistrationResponse), Registered(RegisteredResponse), @@ -128,28 +128,28 @@ pub enum AuthenticatorResponseData { TopUpBandwidth(TopUpBandwidthResponse), } -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub struct PendingRegistrationResponse { pub request_id: u64, pub reply_to: Recipient, pub reply: RegistrationData, } -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub struct RegisteredResponse { pub request_id: u64, pub reply_to: Recipient, pub reply: RegistredData, } -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub struct RemainingBandwidthResponse { pub request_id: u64, pub reply_to: Recipient, pub reply: Option, } -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub struct TopUpBandwidthResponse { pub request_id: u64, pub reply_to: Recipient, diff --git a/common/authenticator-requests/src/v3/topup.rs b/common/authenticator-requests/src/v3/topup.rs index 31a61a0659..1163d07f12 100644 --- a/common/authenticator-requests/src/v3/topup.rs +++ b/common/authenticator-requests/src/v3/topup.rs @@ -5,7 +5,7 @@ use nym_credentials_interface::CredentialSpendingData; use nym_wireguard_types::PeerPublicKey; use serde::{Deserialize, Serialize}; -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] pub struct TopUpMessage { /// Base64 encoded x25519 public key pub pub_key: PeerPublicKey, diff --git a/common/authenticator-requests/src/v4/conversion.rs b/common/authenticator-requests/src/v4/conversion.rs index 7b79b5f087..86a1c8791b 100644 --- a/common/authenticator-requests/src/v4/conversion.rs +++ b/common/authenticator-requests/src/v4/conversion.rs @@ -3,37 +3,82 @@ use nym_service_provider_requests_common::{Protocol, ServiceProviderType}; -use crate::{v2, v3, v4}; +use crate::{v3, v4}; -impl From for v4::request::AuthenticatorRequest { - fn from(authenticator_request: v3::request::AuthenticatorRequest) -> Self { - Self { +impl TryFrom for v4::request::AuthenticatorRequest { + type Error = crate::Error; + fn try_from( + authenticator_request: v3::request::AuthenticatorRequest, + ) -> Result { + Ok(Self { protocol: Protocol { version: 4, service_provider_type: ServiceProviderType::Authenticator, }, - data: authenticator_request.data.into(), + data: authenticator_request.data.try_into()?, reply_to: authenticator_request.reply_to, request_id: authenticator_request.request_id, + }) + } +} + +impl TryFrom for v3::request::AuthenticatorRequest { + type Error = crate::Error; + fn try_from( + authenticator_request: v4::request::AuthenticatorRequest, + ) -> Result { + Ok(Self { + protocol: Protocol { + version: 3, + service_provider_type: ServiceProviderType::Authenticator, + }, + data: authenticator_request.data.try_into()?, + reply_to: authenticator_request.reply_to, + request_id: authenticator_request.request_id, + }) + } +} + +impl TryFrom for v4::request::AuthenticatorRequestData { + type Error = crate::Error; + fn try_from( + authenticator_request_data: v3::request::AuthenticatorRequestData, + ) -> Result { + match authenticator_request_data { + v3::request::AuthenticatorRequestData::Initial(init_msg) => Ok( + v4::request::AuthenticatorRequestData::Initial(init_msg.into()), + ), + v3::request::AuthenticatorRequestData::Final(_) => Err(Self::Error::Conversion( + "mac hash breaking change".to_string(), + )), + v3::request::AuthenticatorRequestData::QueryBandwidth(pub_key) => Ok( + v4::request::AuthenticatorRequestData::QueryBandwidth(pub_key), + ), + v3::request::AuthenticatorRequestData::TopUpBandwidth(top_up_message) => Ok( + v4::request::AuthenticatorRequestData::TopUpBandwidth(top_up_message.into()), + ), } } } -impl From for v4::request::AuthenticatorRequestData { - fn from(authenticator_request_data: v3::request::AuthenticatorRequestData) -> Self { +impl TryFrom for v3::request::AuthenticatorRequestData { + type Error = crate::Error; + fn try_from( + authenticator_request_data: v4::request::AuthenticatorRequestData, + ) -> Result { match authenticator_request_data { - v3::request::AuthenticatorRequestData::Initial(init_msg) => { - v4::request::AuthenticatorRequestData::Initial(init_msg.into()) - } - v3::request::AuthenticatorRequestData::Final(gw_client) => { - v4::request::AuthenticatorRequestData::Final(gw_client.into()) - } - v3::request::AuthenticatorRequestData::QueryBandwidth(pub_key) => { - v4::request::AuthenticatorRequestData::QueryBandwidth(pub_key) - } - v3::request::AuthenticatorRequestData::TopUpBandwidth(top_up_message) => { - v4::request::AuthenticatorRequestData::TopUpBandwidth(top_up_message.into()) - } + v4::request::AuthenticatorRequestData::Initial(init_msg) => Ok( + v3::request::AuthenticatorRequestData::Initial(init_msg.into()), + ), + v4::request::AuthenticatorRequestData::Final(_) => Err(Self::Error::Conversion( + "mac hash breaking change".to_string(), + )), + v4::request::AuthenticatorRequestData::QueryBandwidth(pub_key) => Ok( + v3::request::AuthenticatorRequestData::QueryBandwidth(pub_key), + ), + v4::request::AuthenticatorRequestData::TopUpBandwidth(top_up_message) => Ok( + v3::request::AuthenticatorRequestData::TopUpBandwidth(top_up_message.into()), + ), } } } @@ -46,12 +91,11 @@ impl From for v4::registration::InitMessage { } } -impl From> for Box { - fn from(gw_client: Box) -> Self { - Box::new(v4::registration::FinalMessage { - gateway_client: gw_client.gateway_client.into(), - credential: gw_client.credential, - }) +impl From for v3::registration::InitMessage { + fn from(init_msg: v4::registration::InitMessage) -> Self { + Self { + pub_key: init_msg.pub_key, + } } } @@ -64,67 +108,26 @@ impl From> for Box { } } -impl From for v4::registration::GatewayClient { - fn from(gw_client: v2::registration::GatewayClient) -> Self { - Self { - pub_key: gw_client.pub_key, - private_ips: gw_client.private_ip.into(), - mac: gw_client.mac.into(), - } +impl From> for Box { + fn from(top_up_message: Box) -> Self { + Box::new(v3::topup::TopUpMessage { + pub_key: top_up_message.pub_key, + credential: top_up_message.credential, + }) } } -impl From for v4::registration::GatewayClient { - fn from(gw_client: v3::registration::GatewayClient) -> Self { - Self { - pub_key: gw_client.pub_key, - private_ips: gw_client.private_ip.into(), - mac: gw_client.mac.into(), - } - } -} - -impl From for v3::registration::GatewayClient { - fn from(gw_client: v4::registration::GatewayClient) -> Self { - Self { - pub_key: gw_client.pub_key, - private_ip: gw_client.private_ips.ipv4.into(), - mac: gw_client.mac.into(), - } - } -} - -impl From for v2::registration::GatewayClient { - fn from(gw_client: v4::registration::GatewayClient) -> Self { - Self { - pub_key: gw_client.pub_key, - private_ip: gw_client.private_ips.ipv4.into(), - mac: gw_client.mac.into(), - } - } -} - -impl From for v4::registration::ClientMac { - fn from(mac: v2::registration::ClientMac) -> Self { - Self::new(mac.to_vec()) - } -} - -impl From for v4::registration::ClientMac { - fn from(mac: v3::registration::ClientMac) -> Self { - Self::new(mac.to_vec()) - } -} - -impl From for v3::registration::ClientMac { - fn from(mac: v4::registration::ClientMac) -> Self { - Self::new(mac.to_vec()) - } -} - -impl From for v2::registration::ClientMac { - fn from(mac: v4::registration::ClientMac) -> Self { - Self::new(mac.to_vec()) +impl TryFrom for v4::response::AuthenticatorResponse { + type Error = crate::Error; + fn try_from(value: v3::response::AuthenticatorResponse) -> Result { + Ok(Self { + protocol: Protocol { + version: 4, + service_provider_type: value.protocol.service_provider_type, + }, + data: value.data.try_into()?, + reply_to: value.reply_to, + }) } } @@ -137,11 +140,40 @@ impl TryFrom for v3::response::Authenticato Ok(Self { data: authenticator_response.data.try_into()?, reply_to: authenticator_response.reply_to, - protocol: authenticator_response.protocol, + protocol: Protocol { + version: 3, + service_provider_type: authenticator_response.protocol.service_provider_type, + }, }) } } +impl TryFrom for v4::response::AuthenticatorResponseData { + type Error = crate::Error; + fn try_from( + authenticator_response_data: v3::response::AuthenticatorResponseData, + ) -> Result { + match authenticator_response_data { + v3::response::AuthenticatorResponseData::PendingRegistration(_) => Err( + Self::Error::Conversion("mac hash breaking change".to_string()), + ), + + v3::response::AuthenticatorResponseData::Registered(registered_response) => Ok( + v4::response::AuthenticatorResponseData::Registered(registered_response.into()), + ), + + v3::response::AuthenticatorResponseData::RemainingBandwidth( + remaining_bandwidth_response, + ) => Ok(v4::response::AuthenticatorResponseData::RemainingBandwidth( + remaining_bandwidth_response.into(), + )), + v3::response::AuthenticatorResponseData::TopUpBandwidth(top_up_response) => Ok( + v4::response::AuthenticatorResponseData::TopUpBandwidth(top_up_response.into()), + ), + } + } +} + impl TryFrom for v3::response::AuthenticatorResponseData { type Error = crate::Error; @@ -149,13 +181,10 @@ impl TryFrom for v3::response::Authenti authenticator_response_data: v4::response::AuthenticatorResponseData, ) -> Result { match authenticator_response_data { - v4::response::AuthenticatorResponseData::PendingRegistration( - pending_registration_response, - ) => Ok( - v3::response::AuthenticatorResponseData::PendingRegistration( - pending_registration_response.into(), - ), + v4::response::AuthenticatorResponseData::PendingRegistration(_) => Err( + Self::Error::Conversion("mac hash breaking change".to_string()), ), + v4::response::AuthenticatorResponseData::Registered(registered_response) => Ok( v3::response::AuthenticatorResponseData::Registered(registered_response.into()), ), @@ -173,8 +202,8 @@ impl TryFrom for v3::response::Authenti } } -impl From for v3::response::PendingRegistrationResponse { - fn from(value: v4::response::PendingRegistrationResponse) -> Self { +impl From for v3::response::RegisteredResponse { + fn from(value: v4::response::RegisteredResponse) -> Self { Self { request_id: value.request_id, reply_to: value.reply_to, @@ -183,8 +212,8 @@ impl From for v3::response::PendingRe } } -impl From for v3::response::RegisteredResponse { - fn from(value: v4::response::RegisteredResponse) -> Self { +impl From for v4::response::RegisteredResponse { + fn from(value: v3::response::RegisteredResponse) -> Self { Self { request_id: value.request_id, reply_to: value.reply_to, @@ -193,6 +222,16 @@ impl From for v3::response::RegisteredResponse } } +impl From for v4::response::RemainingBandwidthResponse { + fn from(value: v3::response::RemainingBandwidthResponse) -> Self { + Self { + request_id: value.request_id, + reply_to: value.reply_to, + reply: value.reply.map(Into::into), + } + } +} + impl From for v3::response::RemainingBandwidthResponse { fn from(value: v4::response::RemainingBandwidthResponse) -> Self { Self { @@ -203,11 +242,31 @@ impl From for v3::response::RemainingB } } -impl From for v3::registration::RegistrationData { - fn from(value: v4::registration::RegistrationData) -> Self { +impl From for v4::response::TopUpBandwidthResponse { + fn from(value: v3::response::TopUpBandwidthResponse) -> Self { Self { - nonce: value.nonce, - gateway_data: value.gateway_data.into(), + request_id: value.request_id, + reply_to: value.reply_to, + reply: value.reply.into(), + } + } +} + +impl From for v3::response::TopUpBandwidthResponse { + fn from(value: v4::response::TopUpBandwidthResponse) -> Self { + Self { + request_id: value.request_id, + reply_to: value.reply_to, + reply: value.reply.into(), + } + } +} + +impl From for v4::registration::RegistredData { + fn from(value: v3::registration::RegistredData) -> Self { + Self { + pub_key: value.pub_key, + private_ips: value.private_ip.into(), wg_port: value.wg_port, } } @@ -223,6 +282,14 @@ impl From for v3::registration::RegistredData { } } +impl From for v4::registration::RemainingBandwidthData { + fn from(value: v3::registration::RemainingBandwidthData) -> Self { + Self { + available_bandwidth: value.available_bandwidth, + } + } +} + impl From for v3::registration::RemainingBandwidthData { fn from(value: v4::registration::RemainingBandwidthData) -> Self { Self { @@ -230,3 +297,441 @@ impl From for v3::registration::Remain } } } + +#[cfg(test)] +mod tests { + use std::{ + net::{Ipv4Addr, Ipv6Addr}, + str::FromStr, + }; + + use nym_credentials_interface::CredentialSpendingData; + use nym_crypto::asymmetric::encryption::PrivateKey; + use nym_sphinx::addressing::Recipient; + use nym_wireguard_types::PeerPublicKey; + use x25519_dalek::PublicKey; + + use super::*; + use crate::util::tests::{CREDENTIAL_BYTES, RECIPIENT}; + + #[test] + fn upgrade_initial_req() { + let pub_key = PeerPublicKey::new(PublicKey::from([0; 32])); + let reply_to = Recipient::try_from_base58_string(RECIPIENT).unwrap(); + + let (msg, _) = v3::request::AuthenticatorRequest::new_initial_request( + v3::registration::InitMessage::new(pub_key), + reply_to, + ); + let upgraded_msg = v4::request::AuthenticatorRequest::try_from(msg).unwrap(); + + assert_eq!( + upgraded_msg.protocol, + Protocol { + version: 4, + service_provider_type: ServiceProviderType::Authenticator + } + ); + assert_eq!( + upgraded_msg.data, + v4::request::AuthenticatorRequestData::Initial(v4::registration::InitMessage { + pub_key + }) + ); + } + + #[test] + fn downgrade_initial_req() { + let pub_key = PeerPublicKey::new(PublicKey::from([0; 32])); + let reply_to = Recipient::try_from_base58_string(RECIPIENT).unwrap(); + + let (msg, _) = v4::request::AuthenticatorRequest::new_initial_request( + v4::registration::InitMessage::new(pub_key), + reply_to, + ); + let downgraded_msg = v3::request::AuthenticatorRequest::try_from(msg).unwrap(); + + assert_eq!( + downgraded_msg.protocol, + Protocol { + version: 3, + service_provider_type: ServiceProviderType::Authenticator + } + ); + assert_eq!( + downgraded_msg.data, + v3::request::AuthenticatorRequestData::Initial(v3::registration::InitMessage { + pub_key + }) + ); + } + + #[test] + fn upgrade_final_req() { + let mut rng = rand::thread_rng(); + + let local_secret = PrivateKey::new(&mut rng); + let remote_secret = x25519_dalek::StaticSecret::random_from_rng(&mut rng); + let ipv4 = Ipv4Addr::from_str("10.10.10.10").unwrap(); + let nonce = 42; + let gateway_client = v3::registration::GatewayClient::new( + &local_secret, + (&remote_secret).into(), + ipv4.into(), + nonce, + ); + let credential = Some(CredentialSpendingData::try_from_bytes(&CREDENTIAL_BYTES).unwrap()); + let final_message = v3::registration::FinalMessage { + gateway_client, + credential: credential.clone(), + }; + let reply_to = Recipient::try_from_base58_string(RECIPIENT).unwrap(); + + let (msg, _) = + v3::request::AuthenticatorRequest::new_final_request(final_message, reply_to); + assert!(v4::request::AuthenticatorRequest::try_from(msg).is_err()); + } + + #[test] + fn downgrade_final_req() { + let mut rng = rand::thread_rng(); + + let local_secret = PrivateKey::new(&mut rng); + let remote_secret = x25519_dalek::StaticSecret::random_from_rng(&mut rng); + let ipv4 = Ipv4Addr::from_str("10.10.10.10").unwrap(); + let private_ips = + v4::registration::IpPair::new(ipv4, Ipv6Addr::from_str("fc01::10").unwrap()); + let nonce = 42; + let gateway_client = v4::registration::GatewayClient::new( + &local_secret, + (&remote_secret).into(), + private_ips, + nonce, + ); + let credential = Some(CredentialSpendingData::try_from_bytes(&CREDENTIAL_BYTES).unwrap()); + let final_message = v4::registration::FinalMessage { + gateway_client, + credential: credential.clone(), + }; + let reply_to = Recipient::try_from_base58_string(RECIPIENT).unwrap(); + + let (msg, _) = + v4::request::AuthenticatorRequest::new_final_request(final_message, reply_to); + assert!(v3::request::AuthenticatorRequest::try_from(msg).is_err()); + } + + #[test] + fn upgrade_query_req() { + let pub_key = PeerPublicKey::new(PublicKey::from([0; 32])); + let reply_to = Recipient::try_from_base58_string(RECIPIENT).unwrap(); + + let (msg, _) = v3::request::AuthenticatorRequest::new_query_request(pub_key, reply_to); + let upgraded_msg = v4::request::AuthenticatorRequest::try_from(msg).unwrap(); + + assert_eq!( + upgraded_msg.protocol, + Protocol { + version: 4, + service_provider_type: ServiceProviderType::Authenticator + } + ); + assert_eq!( + upgraded_msg.data, + v4::request::AuthenticatorRequestData::QueryBandwidth(pub_key) + ); + } + + #[test] + fn downgrade_query_req() { + let pub_key = PeerPublicKey::new(PublicKey::from([0; 32])); + let reply_to = Recipient::try_from_base58_string(RECIPIENT).unwrap(); + + let (msg, _) = v4::request::AuthenticatorRequest::new_query_request(pub_key, reply_to); + let downgraded_msg = v3::request::AuthenticatorRequest::try_from(msg).unwrap(); + + assert_eq!( + downgraded_msg.protocol, + Protocol { + version: 3, + service_provider_type: ServiceProviderType::Authenticator + } + ); + assert_eq!( + downgraded_msg.data, + v3::request::AuthenticatorRequestData::QueryBandwidth(pub_key) + ); + } + + #[test] + fn downgrade_topup_req() { + let pub_key = PeerPublicKey::new(PublicKey::from([0; 32])); + let credential = CredentialSpendingData::try_from_bytes(&CREDENTIAL_BYTES).unwrap(); + let top_up_message = v4::topup::TopUpMessage { + pub_key, + credential: credential.clone(), + }; + let reply_to = Recipient::try_from_base58_string(RECIPIENT).unwrap(); + + let (msg, _) = + v4::request::AuthenticatorRequest::new_topup_request(top_up_message, reply_to); + let downgraded_msg = v3::request::AuthenticatorRequest::try_from(msg).unwrap(); + + assert_eq!( + downgraded_msg.protocol, + Protocol { + version: 3, + service_provider_type: ServiceProviderType::Authenticator + } + ); + assert_eq!( + downgraded_msg.data, + v3::request::AuthenticatorRequestData::TopUpBandwidth(Box::new( + v3::topup::TopUpMessage { + pub_key, + credential + } + )) + ); + } + + #[test] + fn upgrade_pending_reg_resp() { + let mut rng = rand::thread_rng(); + + let local_secret = PrivateKey::new(&mut rng); + let remote_secret = x25519_dalek::StaticSecret::random_from_rng(&mut rng); + let ipv4 = Ipv4Addr::from_str("10.10.10.10").unwrap(); + let nonce = 42; + let wg_port = 51822; + let gateway_data = v3::registration::GatewayClient::new( + &local_secret, + (&remote_secret).into(), + ipv4.into(), + nonce, + ); + let registration_data = v3::registration::RegistrationData { + nonce, + gateway_data, + wg_port, + }; + let request_id = 123; + let reply_to = Recipient::try_from_base58_string(RECIPIENT).unwrap(); + + let msg = v3::response::AuthenticatorResponse::new_pending_registration_success( + registration_data, + request_id, + reply_to, + ); + assert!(v4::response::AuthenticatorResponse::try_from(msg).is_err()); + } + + #[test] + fn downgrade_pending_reg_resp() { + let mut rng = rand::thread_rng(); + + let local_secret = PrivateKey::new(&mut rng); + let remote_secret = x25519_dalek::StaticSecret::random_from_rng(&mut rng); + let ipv4 = Ipv4Addr::from_str("10.10.10.10").unwrap(); + let private_ips = + v4::registration::IpPair::new(ipv4, Ipv6Addr::from_str("fc01::10").unwrap()); + let nonce = 42; + let wg_port = 51822; + let gateway_data = v4::registration::GatewayClient::new( + &local_secret, + (&remote_secret).into(), + private_ips, + nonce, + ); + let registration_data = v4::registration::RegistrationData { + nonce, + gateway_data, + wg_port, + }; + let request_id = 123; + let reply_to = Recipient::try_from_base58_string(RECIPIENT).unwrap(); + + let msg = v4::response::AuthenticatorResponse::new_pending_registration_success( + registration_data, + request_id, + reply_to, + ); + assert!(v3::response::AuthenticatorResponse::try_from(msg).is_err()); + } + + #[test] + fn upgrade_registered_resp() { + let pub_key = PeerPublicKey::new(PublicKey::from([0; 32])); + let ipv4 = Ipv4Addr::from_str("10.1.10.10").unwrap(); + let private_ips = + v4::registration::IpPair::new(ipv4, Ipv6Addr::from_str("fc01::a0a").unwrap()); + let wg_port = 51822; + let registred_data = v3::registration::RegistredData { + pub_key, + private_ip: ipv4.into(), + wg_port, + }; + let request_id = 123; + let reply_to = Recipient::try_from_base58_string(RECIPIENT).unwrap(); + + let msg = v3::response::AuthenticatorResponse::new_registered( + registred_data, + reply_to, + request_id, + ); + let upgraded_msg = v4::response::AuthenticatorResponse::try_from(msg).unwrap(); + + assert_eq!( + upgraded_msg.protocol, + Protocol { + version: 4, + service_provider_type: ServiceProviderType::Authenticator + } + ); + assert_eq!( + upgraded_msg.data, + v4::response::AuthenticatorResponseData::Registered(v4::response::RegisteredResponse { + request_id, + reply_to, + reply: v4::registration::RegistredData { + wg_port, + pub_key, + private_ips + } + }) + ); + } + + #[test] + fn downgrade_registered_resp() { + let pub_key = PeerPublicKey::new(PublicKey::from([0; 32])); + let ipv4 = Ipv4Addr::from_str("10.10.10.10").unwrap(); + let private_ips = + v4::registration::IpPair::new(ipv4, Ipv6Addr::from_str("fc01::10").unwrap()); + let wg_port = 51822; + let registred_data = v4::registration::RegistredData { + pub_key, + private_ips, + wg_port, + }; + let request_id = 123; + let reply_to = Recipient::try_from_base58_string(RECIPIENT).unwrap(); + + let msg = v4::response::AuthenticatorResponse::new_registered( + registred_data, + reply_to, + request_id, + ); + let downgraded_msg = v3::response::AuthenticatorResponse::try_from(msg).unwrap(); + + assert_eq!( + downgraded_msg.protocol, + Protocol { + version: 3, + service_provider_type: ServiceProviderType::Authenticator + } + ); + assert_eq!( + downgraded_msg.data, + v3::response::AuthenticatorResponseData::Registered(v3::response::RegisteredResponse { + request_id, + reply_to, + reply: v3::registration::RegistredData { + wg_port, + pub_key, + private_ip: ipv4.into() + } + }) + ); + } + + #[test] + fn upgrade_remaining_bandwidth_resp() { + let available_bandwidth = 42; + let remaining_bandwidth_data = Some(v3::registration::RemainingBandwidthData { + available_bandwidth, + }); + let request_id = 123; + let reply_to = Recipient::try_from_base58_string(RECIPIENT).unwrap(); + + let msg = v3::response::AuthenticatorResponse::new_remaining_bandwidth( + remaining_bandwidth_data, + reply_to, + request_id, + ); + let upgraded_msg = v4::response::AuthenticatorResponse::try_from(msg).unwrap(); + + assert_eq!( + upgraded_msg.protocol, + Protocol { + version: 4, + service_provider_type: ServiceProviderType::Authenticator + } + ); + assert_eq!( + upgraded_msg.data, + v4::response::AuthenticatorResponseData::RemainingBandwidth( + v4::response::RemainingBandwidthResponse { + request_id, + reply_to, + reply: Some(v4::registration::RemainingBandwidthData { + available_bandwidth, + }) + } + ) + ); + } + + #[test] + fn downgrade_remaining_bandwidth_resp() { + let available_bandwidth = 42; + let remaining_bandwidth_data = Some(v4::registration::RemainingBandwidthData { + available_bandwidth, + }); + let request_id = 123; + let reply_to = Recipient::try_from_base58_string(RECIPIENT).unwrap(); + + let msg = v4::response::AuthenticatorResponse::new_remaining_bandwidth( + remaining_bandwidth_data, + reply_to, + request_id, + ); + let downgraded_msg = v3::response::AuthenticatorResponse::try_from(msg).unwrap(); + + assert_eq!( + downgraded_msg.protocol, + Protocol { + version: 3, + service_provider_type: ServiceProviderType::Authenticator + } + ); + assert_eq!( + downgraded_msg.data, + v3::response::AuthenticatorResponseData::RemainingBandwidth( + v3::response::RemainingBandwidthResponse { + request_id, + reply_to, + reply: Some(v3::registration::RemainingBandwidthData { + available_bandwidth, + }) + } + ) + ); + } + + #[test] + fn downgrade_topup_resp() { + let available_bandwidth = 42; + let remaining_bandwidth_data = v4::registration::RemainingBandwidthData { + available_bandwidth, + }; + let request_id = 123; + let reply_to = Recipient::try_from_base58_string(RECIPIENT).unwrap(); + + let msg = v4::response::AuthenticatorResponse::new_topup_bandwidth( + remaining_bandwidth_data, + reply_to, + request_id, + ); + assert!(v3::response::AuthenticatorResponse::try_from(msg).is_err()); + } +} diff --git a/common/authenticator-requests/src/v4/registration.rs b/common/authenticator-requests/src/v4/registration.rs index a4a49c66a5..2595922f00 100644 --- a/common/authenticator-requests/src/v4/registration.rs +++ b/common/authenticator-requests/src/v4/registration.rs @@ -81,7 +81,7 @@ impl From for IpPair { } } -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] pub struct InitMessage { /// Base64 encoded x25519 public key pub pub_key: PeerPublicKey, @@ -93,7 +93,7 @@ impl InitMessage { } } -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] pub struct FinalMessage { /// Gateway client data pub gateway_client: GatewayClient, @@ -102,28 +102,28 @@ pub struct FinalMessage { pub credential: Option, } -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] pub struct RegistrationData { pub nonce: u64, pub gateway_data: GatewayClient, pub wg_port: u16, } -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] pub struct RegistredData { pub pub_key: PeerPublicKey, pub private_ips: IpPair, pub wg_port: u16, } -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] pub struct RemainingBandwidthData { pub available_bandwidth: i64, } /// Client that wants to register sends its PublicKey bytes mac digest encrypted with a DH shared secret. /// Gateway/Nym node can then verify pub_key payload using the same process -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] pub struct GatewayClient { /// Base64 encoded x25519 public key pub pub_key: PeerPublicKey, @@ -199,7 +199,7 @@ impl GatewayClient { // TODO: change the inner type into generic array of size HmacSha256::OutputSize // TODO2: rely on our internal crypto/hmac -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq)] pub struct ClientMac(Vec); impl fmt::Display for ClientMac { diff --git a/common/authenticator-requests/src/v4/request.rs b/common/authenticator-requests/src/v4/request.rs index aa4862b057..25cf0e0f1f 100644 --- a/common/authenticator-requests/src/v4/request.rs +++ b/common/authenticator-requests/src/v4/request.rs @@ -20,7 +20,7 @@ fn generate_random() -> u64 { rng.next_u64() } -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub struct AuthenticatorRequest { pub protocol: Protocol, pub data: AuthenticatorRequestData, @@ -106,7 +106,7 @@ impl AuthenticatorRequest { } } -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub enum AuthenticatorRequestData { Initial(InitMessage), Final(Box), diff --git a/common/authenticator-requests/src/v4/response.rs b/common/authenticator-requests/src/v4/response.rs index 370fc64671..9743e8db43 100644 --- a/common/authenticator-requests/src/v4/response.rs +++ b/common/authenticator-requests/src/v4/response.rs @@ -10,7 +10,7 @@ use crate::make_bincode_serializer; use super::VERSION; -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub struct AuthenticatorResponse { pub protocol: Protocol, pub data: AuthenticatorResponseData, @@ -120,7 +120,7 @@ impl AuthenticatorResponse { } } -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub enum AuthenticatorResponseData { PendingRegistration(PendingRegistrationResponse), Registered(RegisteredResponse), @@ -128,28 +128,28 @@ pub enum AuthenticatorResponseData { TopUpBandwidth(TopUpBandwidthResponse), } -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub struct PendingRegistrationResponse { pub request_id: u64, pub reply_to: Recipient, pub reply: RegistrationData, } -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub struct RegisteredResponse { pub request_id: u64, pub reply_to: Recipient, pub reply: RegistredData, } -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub struct RemainingBandwidthResponse { pub request_id: u64, pub reply_to: Recipient, pub reply: Option, } -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub struct TopUpBandwidthResponse { pub request_id: u64, pub reply_to: Recipient, diff --git a/common/authenticator-requests/src/v4/topup.rs b/common/authenticator-requests/src/v4/topup.rs index 31a61a0659..1163d07f12 100644 --- a/common/authenticator-requests/src/v4/topup.rs +++ b/common/authenticator-requests/src/v4/topup.rs @@ -5,7 +5,7 @@ use nym_credentials_interface::CredentialSpendingData; use nym_wireguard_types::PeerPublicKey; use serde::{Deserialize, Serialize}; -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] pub struct TopUpMessage { /// Base64 encoded x25519 public key pub pub_key: PeerPublicKey, diff --git a/common/service-provider-requests-common/src/lib.rs b/common/service-provider-requests-common/src/lib.rs index f9f0564e1d..3b294baba7 100644 --- a/common/service-provider-requests-common/src/lib.rs +++ b/common/service-provider-requests-common/src/lib.rs @@ -11,7 +11,7 @@ pub enum ServiceProviderType { Authenticator = 2, } -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub struct Protocol { pub version: u8, pub service_provider_type: ServiceProviderType, diff --git a/service-providers/authenticator/src/mixnet_listener.rs b/service-providers/authenticator/src/mixnet_listener.rs index 4235a9da15..753bcd2fbf 100644 --- a/service-providers/authenticator/src/mixnet_listener.rs +++ b/service-providers/authenticator/src/mixnet_listener.rs @@ -184,7 +184,12 @@ impl MixnetListener { v2::response::AuthenticatorResponse::new_pending_registration_success( v2::registration::RegistrationData { nonce: registration_data.nonce, - gateway_data: registration_data.gateway_data.clone().into(), + gateway_data: v2::registration::GatewayClient::new( + self.keypair().private_key(), + remote_public.inner(), + registration_data.gateway_data.private_ips.ipv4.into(), + registration_data.nonce, + ), wg_port: registration_data.wg_port, }, request_id, @@ -199,7 +204,12 @@ impl MixnetListener { v3::response::AuthenticatorResponse::new_pending_registration_success( v3::registration::RegistrationData { nonce: registration_data.nonce, - gateway_data: registration_data.gateway_data.clone().into(), + gateway_data: v3::registration::GatewayClient::new( + self.keypair().private_key(), + remote_public.inner(), + registration_data.gateway_data.private_ips.ipv4.into(), + registration_data.nonce, + ), wg_port: registration_data.wg_port, }, request_id,