From 420831cd09428c9612935334fb5de2e49a85d904 Mon Sep 17 00:00:00 2001 From: Alex Emmet <111742636+Alex-Emmet@users.noreply.github.com> Date: Thu, 20 Aug 2026 21:42:23 +0200 Subject: [PATCH 1/3] [Add] Docs & patches --- host/src/engine.rs | 8 ++++++++ transport/src/generic_connection.rs | 11 ++++++++++- wasm/src/client/authentication.rs | 13 +++++++++++-- 3 files changed, 29 insertions(+), 3 deletions(-) mode change 100644 => 100755 host/src/engine.rs diff --git a/host/src/engine.rs b/host/src/engine.rs old mode 100644 new mode 100755 index d1ebd19..08ca87f --- a/host/src/engine.rs +++ b/host/src/engine.rs @@ -309,6 +309,12 @@ impl HandshakeEngine { ) || registration || first_msg.get_data(DataType::PublicKeys).is_some() || claimed_client_id.is_some_and(|client_id| client_id != 0); + tracing::info!( + claimed_client_id = ?claimed_client_id, + registration, + authentication_requested, + "classified MTP opening authentication mode" + ); if authentication_requested { let attempt = crate::config::AuthenticationAttempt { peer_network_identity: _authentication_context.peer_network_identity.clone(), @@ -566,6 +572,7 @@ impl HandshakeEngine { } // Unknown or zero ID: fall back to guest + tracing::info!("allocating MTP guest identity"); let guest_id_lease = match self.assign_guest_id().await { Ok(lease) => lease, Err(error) => { @@ -574,6 +581,7 @@ impl HandshakeEngine { } }; let guest_id = guest_id_lease.id; + tracing::info!(guest_id, "allocated MTP guest identity"); send_accepted_generic(sender, &negotiated, tm, Some(guest_id)) .await .map_err(AcceptError::Send)?; diff --git a/transport/src/generic_connection.rs b/transport/src/generic_connection.rs index 830fb40..a7a32de 100644 --- a/transport/src/generic_connection.rs +++ b/transport/src/generic_connection.rs @@ -9,7 +9,7 @@ use crate::{ connection::{DecodeRejectionCounters, RuntimePolicy, classify_decode_error}, framing::{RetryClassifier, write_frame}, }; -use mtp_codec::{CommunicationValue, DecodeLimits, TypeMap}; +use mtp_codec::{CommunicationValue, DataType, DecodeLimits, TypeMap}; use mtp_common::CommunicationError; use std::sync::Arc; use std::sync::atomic::{AtomicU64, Ordering}; @@ -67,6 +67,15 @@ impl GenericSender { if self.connection.close_reason().is_some() { return Err(CommunicationError::StreamClosed); } + if let Some(version) = value.get_str(DataType::Version) { + tracing::debug!( + message_type = ?value.get_type(), + version, + connected = ?value.get_data(DataType::Connected), + client_id = ?value.get_data(DataType::Id), + "sending MTP handshake response frame" + ); + } match self.policy.send_mode { crate::SendMode::SingleStreamPerMessage => { let mut stream = self.open().await?; diff --git a/wasm/src/client/authentication.rs b/wasm/src/client/authentication.rs index df7989e..73bfc9f 100644 --- a/wasm/src/client/authentication.rs +++ b/wasm/src/client/authentication.rs @@ -99,10 +99,19 @@ impl WasmClient { return Err(js_error(message)); } + let missing_version = || { + js_error(format!( + "host omitted a valid negotiated protocol version (response_type={:?}, connected={:?}, frame_len={})", + outcome.get_type(), + outcome.get_data(DataType::Connected), + outcome_bytes.len(), + )) + }; + let negotiated_version = match outcome.get_data(DataType::Version) { Some(DataValue::Str(version)) => mtp_codec::Version::parse(version) - .ok_or_else(|| js_error("host omitted a valid negotiated protocol version"))?, - _ => return Err(js_error("host omitted a valid negotiated protocol version")), + .ok_or_else(|| missing_version())?, + _ => return Err(missing_version()), }; if negotiated_version != PROTOCOL_VERSION { return Err(js_error( From 101b8322a1eb76490fee70c4606c7ded18327fe9 Mon Sep 17 00:00:00 2001 From: Alex Emmet <111742636+Alex-Emmet@users.noreply.github.com> Date: Thu, 20 Aug 2026 21:59:57 +0200 Subject: [PATCH 2/3] [Fix] Policy overwrites --- host/src/config.rs | 83 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 82 insertions(+), 1 deletion(-) diff --git a/host/src/config.rs b/host/src/config.rs index 0cef52a..99d62a2 100644 --- a/host/src/config.rs +++ b/host/src/config.rs @@ -251,6 +251,8 @@ pub struct HostConfig { #[cfg(feature = "crypto")] pub authentication_policy: AuthenticationPolicy, #[cfg(feature = "crypto")] + authentication_policy_explicit: bool, + #[cfg(feature = "crypto")] pub auth_timeout: Duration, #[cfg(feature = "crypto")] pub require_pq: bool, @@ -288,6 +290,8 @@ impl HostConfig { #[cfg(feature = "crypto")] authentication_policy: AuthenticationPolicy::Unauthenticated, #[cfg(feature = "crypto")] + authentication_policy_explicit: false, + #[cfg(feature = "crypto")] auth_timeout: Duration::from_secs(30), #[cfg(feature = "crypto")] require_pq: true, @@ -341,7 +345,9 @@ impl HostConfig { get_existing_client: GetExistingClient, complete_register: CompleteRegister, ) -> Self { - self.authentication_policy = AuthenticationPolicy::ForceAuthentication; + if !self.authentication_policy_explicit { + self.authentication_policy = AuthenticationPolicy::ForceAuthentication; + } self.host_keyring = host_keyring; self.get_existing_client = Box::new(get_existing_client); self.complete_register = Box::new(complete_register); @@ -351,6 +357,7 @@ impl HostConfig { #[cfg(feature = "crypto")] pub fn with_authentication_policy(mut self, policy: AuthenticationPolicy) -> Self { self.authentication_policy = policy; + self.authentication_policy_explicit = true; self } @@ -441,4 +448,78 @@ mod tests { .expect("repeated registration decision") ); } + + fn test_keyring() -> mtp_crypto::Keyring { + mtp_crypto::Keyring::new( + mtp_crypto::KemPublicKey::new(Vec::new()), + mtp_crypto::KemPrivateKey::new(Vec::new()), + mtp_crypto::SignaturePqPublicKey::new(Vec::new()), + mtp_crypto::SignaturePqPrivateKey::new(Vec::new()), + mtp_crypto::SignaturePublicKey::new(Vec::new()), + mtp_crypto::SignaturePrivateKey::new(Vec::new()), + ) + } + + fn test_get_existing_client() -> GetExistingClient { + Box::new(|_, _| Box::pin(async { None })) + } + + fn test_complete_register() -> CompleteRegister { + Box::new(|_, _| Box::pin(async { 1 })) + } + + fn test_config() -> HostConfig { + HostConfig::new( + IpAddr::V4(std::net::Ipv4Addr::LOCALHOST), + 4433, + Vec::new(), + Vec::new(), + ) + } + + #[test] + fn with_authentication_defaults_to_force_authentication() { + let config = test_config().with_authentication( + test_keyring(), + test_get_existing_client(), + test_complete_register(), + ); + + assert_eq!( + config.authentication_policy, + AuthenticationPolicy::ForceAuthentication + ); + } + + #[test] + fn explicit_authentication_policy_before_with_authentication_is_preserved() { + let config = test_config() + .with_authentication_policy(AuthenticationPolicy::AllowAuthentication) + .with_authentication( + test_keyring(), + test_get_existing_client(), + test_complete_register(), + ); + + assert_eq!( + config.authentication_policy, + AuthenticationPolicy::AllowAuthentication + ); + } + + #[test] + fn explicit_authentication_policy_after_with_authentication_is_preserved() { + let config = test_config() + .with_authentication( + test_keyring(), + test_get_existing_client(), + test_complete_register(), + ) + .with_authentication_policy(AuthenticationPolicy::AllowAuthentication); + + assert_eq!( + config.authentication_policy, + AuthenticationPolicy::AllowAuthentication + ); + } } From 44b165df27a33760e85335c9e9b2d70fc542a336 Mon Sep 17 00:00:00 2001 From: Rasensprenger Date: Thu, 20 Aug 2026 23:00:47 +0300 Subject: [PATCH 3/3] Update Rust crate aes-gcm to 0.11 --- crypto/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crypto/Cargo.toml b/crypto/Cargo.toml index 88a37f4..47c5ad8 100644 --- a/crypto/Cargo.toml +++ b/crypto/Cargo.toml @@ -8,7 +8,7 @@ ignored = ["rand_core"] [dependencies] chacha20poly1305 = { version = "0.10", optional = true } -aes-gcm = { version = "0.10", optional = true } +aes-gcm = { version = "0.11", optional = true } ed25519-dalek = { version = "3.0", optional = true, features = [ "pkcs8", "pem",