From 212331450234b08bf85b3bd2e85c89964830e93d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bogdan-=C8=98tefan=20Neac=C5=9Fu?= Date: Fri, 20 Oct 2023 13:57:38 +0300 Subject: [PATCH 1/3] Return wg gateway data on handshake init --- common/wireguard-types/src/registration.rs | 9 +++++++-- gateway/src/http/mod.rs | 7 ++++++- .../wireguard/client_registry.rs | 14 ++++++++++++- .../client_interfaces/wireguard/mod.rs | 20 ++++++++++++++++--- 4 files changed, 43 insertions(+), 7 deletions(-) diff --git a/common/wireguard-types/src/registration.rs b/common/wireguard-types/src/registration.rs index c899be5d02..6da0ed0bbd 100644 --- a/common/wireguard-types/src/registration.rs +++ b/common/wireguard-types/src/registration.rs @@ -54,8 +54,13 @@ impl InitMessage { #[serde(tag = "type", rename_all = "camelCase")] #[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))] pub enum ClientRegistrationResponse { - PendingRegistration { nonce: u64 }, - Registered { success: bool }, + PendingRegistration { + nonce: u64, + gateway_data: GatewayClient, + }, + Registered { + success: bool, + }, } /// Client that wants to register sends its PublicKey and SocketAddr bytes mac digest encrypted with a DH shared secret. diff --git a/gateway/src/http/mod.rs b/gateway/src/http/mod.rs index eabb377456..7a6f9ca16f 100644 --- a/gateway/src/http/mod.rs +++ b/gateway/src/http/mod.rs @@ -130,7 +130,12 @@ pub(crate) fn start_http_api( .with_network_requester(load_network_requester_details(gateway_config, nr_config)?) } - let wg_state = WireguardAppState::new(sphinx_keypair, client_registry, Default::default()); + let wg_state = WireguardAppState::new( + sphinx_keypair, + client_registry, + Default::default(), + Arc::new(gateway_config.wireguard.bind_address), + ); let router = nym_node::http::NymNodeRouter::new(config, Some(wg_state)); let server = router diff --git a/nym-node/src/http/router/api/v1/gateway/client_interfaces/wireguard/client_registry.rs b/nym-node/src/http/router/api/v1/gateway/client_interfaces/wireguard/client_registry.rs index f21a1e719f..c5d251608c 100644 --- a/nym-node/src/http/router/api/v1/gateway/client_interfaces/wireguard/client_registry.rs +++ b/nym-node/src/http/router/api/v1/gateway/client_interfaces/wireguard/client_registry.rs @@ -10,6 +10,7 @@ use crate::wireguard::error::WireguardError; use axum::extract::{Path, Query, State}; use axum::http::StatusCode; use axum::Json; +use nym_crypto::asymmetric::encryption::PublicKey; use nym_node_requests::api::v1::gateway::client_interfaces::wireguard::models::{ ClientMessage, ClientRegistrationResponse, GatewayClient, InitMessage, Nonce, PeerPublicKey, }; @@ -87,8 +88,19 @@ pub(crate) async fn register_client( match payload { ClientMessage::Initial(init) => { + let remote_public = PublicKey::from_bytes(init.pub_key().as_bytes()) + .map_err(|_| RequestError::new_status(StatusCode::BAD_REQUEST))?; let nonce = process_init_message(init, state).await; - let response = ClientRegistrationResponse::PendingRegistration { nonce }; + let gateway_data = GatewayClient::new( + state.dh_keypair.private_key(), + remote_public, + *state.socket_address, + nonce, + ); + let response = ClientRegistrationResponse::PendingRegistration { + nonce, + gateway_data, + }; Ok(output.to_response(response)) } ClientMessage::Final(finalize) => { diff --git a/nym-node/src/http/router/api/v1/gateway/client_interfaces/wireguard/mod.rs b/nym-node/src/http/router/api/v1/gateway/client_interfaces/wireguard/mod.rs index 8e29d8c0fb..9004d69a5a 100644 --- a/nym-node/src/http/router/api/v1/gateway/client_interfaces/wireguard/mod.rs +++ b/nym-node/src/http/router/api/v1/gateway/client_interfaces/wireguard/mod.rs @@ -9,6 +9,7 @@ use axum::routing::{get, post}; use axum::Router; use nym_crypto::asymmetric::encryption; use nym_node_requests::routes::api::v1::gateway::client_interfaces::wireguard; +use std::net::SocketAddr; use std::sync::Arc; pub(crate) mod client_registry; @@ -25,12 +26,14 @@ impl WireguardAppState { dh_keypair: Arc, client_registry: Arc, registration_in_progress: Arc, + socket_address: Arc, ) -> Self { WireguardAppState { inner: Some(WireguardAppStateInner { dh_keypair, client_registry, registration_in_progress, + socket_address, }), } } @@ -74,6 +77,7 @@ pub(crate) struct WireguardAppStateInner { dh_keypair: Arc, client_registry: Arc, registration_in_progress: Arc, + socket_address: Arc, } pub(crate) fn routes(initial_state: WireguardAppState) -> Router { @@ -102,6 +106,7 @@ mod test { }; use nym_node_requests::routes::api::v1::gateway::client_interfaces::wireguard; use nym_wireguard_types::registration::HmacSha256; + use std::net::{IpAddr, Ipv4Addr, SocketAddr}; use std::sync::Arc; use tower::Service; use tower::ServiceExt; @@ -139,6 +144,10 @@ mod test { client_registry: Arc::clone(&client_registry), dh_keypair: Arc::new(gateway_key_pair), registration_in_progress: Arc::clone(®istration_in_progress), + socket_address: Arc::new(SocketAddr::new( + IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), + 8080, + )), }), }; @@ -167,12 +176,17 @@ mod test { assert_eq!(response.status(), StatusCode::OK); assert!(!registration_in_progress.is_empty()); - let ClientRegistrationResponse::PendingRegistration { nonce } = - serde_json::from_slice(&hyper::body::to_bytes(response.into_body()).await.unwrap()) - .unwrap() + let ClientRegistrationResponse::PendingRegistration { + nonce, + gateway_data, + } = serde_json::from_slice(&hyper::body::to_bytes(response.into_body()).await.unwrap()) + .unwrap() else { panic!("invalid response") }; + assert!(gateway_data + .verify(client_key_pair.private_key(), nonce) + .is_ok()); let mut mac = HmacSha256::new_from_slice(client_dh.as_bytes()).unwrap(); mac.update(client_static_public.as_bytes()); From 2f8f03dfaddd88d0511b06ad377e66f84c97505e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bogdan-=C8=98tefan=20Neac=C5=9Fu?= Date: Tue, 24 Oct 2023 16:13:31 +0300 Subject: [PATCH 2/3] Add wg register to gateway api client --- nym-node/nym-node-requests/src/api/client.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/nym-node/nym-node-requests/src/api/client.rs b/nym-node/nym-node-requests/src/api/client.rs index 1967b6963e..6815b1a023 100644 --- a/nym-node/nym-node-requests/src/api/client.rs +++ b/nym-node/nym-node-requests/src/api/client.rs @@ -8,6 +8,7 @@ use crate::routes; use async_trait::async_trait; use http_api_client::{ApiClient, HttpClientError}; use nym_bin_common::build_information::BinaryBuildInformationOwned; +use nym_wireguard_types::{ClientMessage, ClientRegistrationResponse}; use crate::api::v1::health::models::NodeHealth; pub use http_api_client::Client; @@ -40,6 +41,17 @@ pub trait NymNodeApiClientExt: ApiClient { ) .await } + + async fn post_gateway_register_client( + &self, + client_message: &ClientMessage, + ) -> Result { + self.post_json_data_to( + routes::api::v1::gateway::client_interfaces::wireguard::client_absolute(), + client_message, + ) + .await + } } #[cfg_attr(target_arch = "wasm32", async_trait(?Send))] From 0aa8e2deb5d5b4b917b096fc6378db3003f0a1ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bogdan-=C8=98tefan=20Neac=C5=9Fu?= Date: Thu, 26 Oct 2023 12:41:41 +0300 Subject: [PATCH 3/3] Remove socket addr and return just wg port --- common/wireguard-types/src/registration.rs | 26 +++---------------- gateway/src/http/mod.rs | 2 +- .../wireguard/client_registry.rs | 9 +++---- .../client_interfaces/wireguard/mod.rs | 17 ++++-------- 4 files changed, 12 insertions(+), 42 deletions(-) diff --git a/common/wireguard-types/src/registration.rs b/common/wireguard-types/src/registration.rs index 6da0ed0bbd..1da614aaa0 100644 --- a/common/wireguard-types/src/registration.rs +++ b/common/wireguard-types/src/registration.rs @@ -6,7 +6,6 @@ use crate::PeerPublicKey; use base64::{engine::general_purpose, Engine}; use dashmap::DashMap; use serde::{Deserialize, Serialize}; -use std::net::SocketAddr; use std::{fmt, ops::Deref, str::FromStr}; #[cfg(feature = "verify")] @@ -57,13 +56,14 @@ pub enum ClientRegistrationResponse { PendingRegistration { nonce: u64, gateway_data: GatewayClient, + wg_port: u16, }, Registered { success: bool, }, } -/// Client that wants to register sends its PublicKey and SocketAddr bytes mac digest encrypted with a DH shared secret. +/// 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)] #[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))] @@ -72,10 +72,6 @@ pub struct GatewayClient { #[cfg_attr(feature = "openapi", schema(value_type = String, format = Byte))] pub pub_key: PeerPublicKey, - /// Client's socket address - #[cfg_attr(feature = "openapi", schema(example = "1.2.3.4:51820", value_type = String))] - pub socket: SocketAddr, - /// Sha256 hmac on the data (alongside the prior nonce) #[cfg_attr(feature = "openapi", schema(value_type = String, format = Byte))] pub mac: ClientMac, @@ -83,12 +79,7 @@ pub struct GatewayClient { impl GatewayClient { #[cfg(feature = "verify")] - pub fn new( - local_secret: &PrivateKey, - remote_public: PublicKey, - socket_address: SocketAddr, - nonce: u64, - ) -> Self { + pub fn new(local_secret: &PrivateKey, remote_public: PublicKey, nonce: u64) -> Self { // convert from 1.0 x25519-dalek private key into 2.0 x25519-dalek #[allow(clippy::expect_used)] let static_secret = boringtun::x25519::StaticSecret::try_from(local_secret.to_bytes()) @@ -105,13 +96,10 @@ impl GatewayClient { .expect("x25519 shared secret is always 32 bytes long"); mac.update(local_public.as_bytes()); - mac.update(socket_address.ip().to_string().as_bytes()); - mac.update(socket_address.port().to_string().as_bytes()); mac.update(&nonce.to_le_bytes()); GatewayClient { pub_key: PeerPublicKey::new(local_public), - socket: socket_address, mac: ClientMac(mac.finalize().into_bytes().to_vec()), } } @@ -133,8 +121,6 @@ impl GatewayClient { .expect("x25519 shared secret is always 32 bytes long"); mac.update(self.pub_key.as_bytes()); - mac.update(self.socket.ip().to_string().as_bytes()); - mac.update(self.socket.port().to_string().as_bytes()); mac.update(&nonce.to_le_bytes()); mac.verify_slice(&self.mac) @@ -147,10 +133,6 @@ impl GatewayClient { pub fn pub_key(&self) -> PeerPublicKey { self.pub_key } - - pub fn socket(&self) -> SocketAddr { - self.socket - } } // TODO: change the inner type into generic array of size HmacSha256::OutputSize @@ -222,13 +204,11 @@ mod tests { let gateway_key_pair = encryption::KeyPair::new(&mut rng); let client_key_pair = encryption::KeyPair::new(&mut rng); - let socket: SocketAddr = "1.2.3.4:5678".parse().unwrap(); let nonce = 1234567890; let client = GatewayClient::new( client_key_pair.private_key(), *gateway_key_pair.public_key(), - socket, nonce, ); assert!(client.verify(gateway_key_pair.private_key(), nonce).is_ok()) diff --git a/gateway/src/http/mod.rs b/gateway/src/http/mod.rs index 7a6f9ca16f..0428322245 100644 --- a/gateway/src/http/mod.rs +++ b/gateway/src/http/mod.rs @@ -134,7 +134,7 @@ pub(crate) fn start_http_api( sphinx_keypair, client_registry, Default::default(), - Arc::new(gateway_config.wireguard.bind_address), + gateway_config.wireguard.bind_address.port(), ); let router = nym_node::http::NymNodeRouter::new(config, Some(wg_state)); diff --git a/nym-node/src/http/router/api/v1/gateway/client_interfaces/wireguard/client_registry.rs b/nym-node/src/http/router/api/v1/gateway/client_interfaces/wireguard/client_registry.rs index c5d251608c..850443e325 100644 --- a/nym-node/src/http/router/api/v1/gateway/client_interfaces/wireguard/client_registry.rs +++ b/nym-node/src/http/router/api/v1/gateway/client_interfaces/wireguard/client_registry.rs @@ -91,15 +91,12 @@ pub(crate) async fn register_client( let remote_public = PublicKey::from_bytes(init.pub_key().as_bytes()) .map_err(|_| RequestError::new_status(StatusCode::BAD_REQUEST))?; let nonce = process_init_message(init, state).await; - let gateway_data = GatewayClient::new( - state.dh_keypair.private_key(), - remote_public, - *state.socket_address, - nonce, - ); + let gateway_data = + GatewayClient::new(state.dh_keypair.private_key(), remote_public, nonce); let response = ClientRegistrationResponse::PendingRegistration { nonce, gateway_data, + wg_port: state.binding_port, }; Ok(output.to_response(response)) } diff --git a/nym-node/src/http/router/api/v1/gateway/client_interfaces/wireguard/mod.rs b/nym-node/src/http/router/api/v1/gateway/client_interfaces/wireguard/mod.rs index 9004d69a5a..37348be94e 100644 --- a/nym-node/src/http/router/api/v1/gateway/client_interfaces/wireguard/mod.rs +++ b/nym-node/src/http/router/api/v1/gateway/client_interfaces/wireguard/mod.rs @@ -9,7 +9,6 @@ use axum::routing::{get, post}; use axum::Router; use nym_crypto::asymmetric::encryption; use nym_node_requests::routes::api::v1::gateway::client_interfaces::wireguard; -use std::net::SocketAddr; use std::sync::Arc; pub(crate) mod client_registry; @@ -26,14 +25,14 @@ impl WireguardAppState { dh_keypair: Arc, client_registry: Arc, registration_in_progress: Arc, - socket_address: Arc, + binding_port: u16, ) -> Self { WireguardAppState { inner: Some(WireguardAppStateInner { dh_keypair, client_registry, registration_in_progress, - socket_address, + binding_port, }), } } @@ -77,7 +76,7 @@ pub(crate) struct WireguardAppStateInner { dh_keypair: Arc, client_registry: Arc, registration_in_progress: Arc, - socket_address: Arc, + binding_port: u16, } pub(crate) fn routes(initial_state: WireguardAppState) -> Router { @@ -106,7 +105,6 @@ mod test { }; use nym_node_requests::routes::api::v1::gateway::client_interfaces::wireguard; use nym_wireguard_types::registration::HmacSha256; - use std::net::{IpAddr, Ipv4Addr, SocketAddr}; use std::sync::Arc; use tower::Service; use tower::ServiceExt; @@ -144,10 +142,7 @@ mod test { client_registry: Arc::clone(&client_registry), dh_keypair: Arc::new(gateway_key_pair), registration_in_progress: Arc::clone(®istration_in_progress), - socket_address: Arc::new(SocketAddr::new( - IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), - 8080, - )), + binding_port: 8080, }), }; @@ -179,6 +174,7 @@ mod test { let ClientRegistrationResponse::PendingRegistration { nonce, gateway_data, + wg_port: 8080, } = serde_json::from_slice(&hyper::body::to_bytes(response.into_body()).await.unwrap()) .unwrap() else { @@ -190,14 +186,11 @@ mod test { let mut mac = HmacSha256::new_from_slice(client_dh.as_bytes()).unwrap(); mac.update(client_static_public.as_bytes()); - mac.update("127.0.0.1".as_bytes()); - mac.update("8080".as_bytes()); mac.update(&nonce.to_le_bytes()); let mac = mac.finalize().into_bytes(); let finalized_message = ClientMessage::Final(GatewayClient { pub_key: PeerPublicKey::new(client_static_public), - socket: "127.0.0.1:8080".parse().unwrap(), mac: ClientMac::new(mac.as_slice().to_vec()), });