diff --git a/implementations/rust/ockam/ockam_core/src/cbor.rs b/implementations/rust/ockam/ockam_core/src/cbor.rs index 39ec44b3f7d..43982a7a12c 100644 --- a/implementations/rust/ockam/ockam_core/src/cbor.rs +++ b/implementations/rust/ockam/ockam_core/src/cbor.rs @@ -7,7 +7,7 @@ pub(crate) mod schema; use crate::compat::vec::Vec; use crate::Result; -use minicbor::{CborLen, Encode, Encoder}; +use minicbor::{CborLen, Encode}; /// Encode a type implementing [`Encode`] and return the encoded byte vector. /// @@ -17,9 +17,10 @@ pub fn cbor_encode_preallocate(x: T) -> Result> where T: Encode<()> + CborLen<()>, { - let output_len = minicbor::len(&x); - let output = Vec::with_capacity(output_len); - let mut e = Encoder::new(output); - x.encode(&mut e, &mut ())?; - Ok(e.into_writer()) + // Due to minicbor bug this value is bigger than should be for structures having + // #[cbor(transparent)] attribute. + let max_expected_len = minicbor::len(&x); + let mut output = Vec::with_capacity(max_expected_len); + minicbor::encode(x, &mut output)?; + Ok(output) } diff --git a/implementations/rust/ockam/ockam_transport_core/src/error.rs b/implementations/rust/ockam/ockam_transport_core/src/error.rs index b493594a183..6db96a30c19 100644 --- a/implementations/rust/ockam/ockam_transport_core/src/error.rs +++ b/implementations/rust/ockam/ockam_transport_core/src/error.rs @@ -45,6 +45,8 @@ pub enum TransportError { InvalidProtocolVersion, /// Message is longer than allowed MessageLengthExceeded, + /// Should not happen + EncodingInternalError, } impl ockam_core::compat::error::Error for TransportError {} @@ -69,6 +71,7 @@ impl core::fmt::Display for TransportError { Self::AttackAttempt => write!(f, "excessive length of header, possible DoS attack"), Self::InvalidProtocolVersion => write!(f, "invalid protocol version"), Self::MessageLengthExceeded => write!(f, "message length exceeded"), + Self::EncodingInternalError => write!(f, "encoding internal error"), } } } @@ -96,6 +99,7 @@ impl From for Error { AttackAttempt => Kind::Misuse, InvalidProtocolVersion => Kind::Invalid, MessageLengthExceeded => Kind::Unsupported, + EncodingInternalError => Kind::Internal, }; Error::new(Origin::Transport, kind, err) diff --git a/implementations/rust/ockam/ockam_transport_tcp/src/workers/sender.rs b/implementations/rust/ockam/ockam_transport_tcp/src/workers/sender.rs index f9521c42295..ffb9e63df64 100644 --- a/implementations/rust/ockam/ockam_transport_tcp/src/workers/sender.rs +++ b/implementations/rust/ockam/ockam_transport_tcp/src/workers/sender.rs @@ -123,23 +123,35 @@ impl TcpSendWorker { // Create a message buffer with prepended length let transport_message = TcpTransportMessage::from(local_message); - let msg_len = minicbor::len(&transport_message); + // Due to minicbor bug this value is bigger than should be for structures having + // #[cbor(transparent)] attribute. So, this code accounts for that. + let max_expected_payload_len = minicbor::len(&transport_message); - if msg_len > MAX_MESSAGE_SIZE { - return Err(TransportError::MessageLengthExceeded)?; + const LENGTH_VALUE_SIZE: usize = 4; // u32 + let mut vec = Vec::with_capacity(LENGTH_VALUE_SIZE + max_expected_payload_len); + + // Let's write zeros instead of actual length, since we don't know it yet. + vec.extend_from_slice(&[0u8; LENGTH_VALUE_SIZE]); + + // Append encoded payload + minicbor::encode(&transport_message, &mut vec).map_err(|_| TransportError::Encoding)?; + + // Should not ever happen... + if vec.len() < LENGTH_VALUE_SIZE { + return Err(TransportError::Encoding)?; } - // Prepending message with u32 (4 bytes) length - let len = 4 + msg_len; + let payload_len = vec.len() - LENGTH_VALUE_SIZE; - let msg_len_u32 = - u32::try_from(msg_len).map_err(|_| TransportError::MessageLengthExceeded)?; + if payload_len > MAX_MESSAGE_SIZE { + return Err(TransportError::MessageLengthExceeded)?; + } - let mut vec = vec![0u8; len]; + let payload_len_u32 = + u32::try_from(payload_len).map_err(|_| TransportError::MessageLengthExceeded)?; - vec[..4].copy_from_slice(&msg_len_u32.to_be_bytes()); - minicbor::encode(&transport_message, &mut vec[4..]) - .map_err(|_| TransportError::Encoding)?; + // Replace zeros with actual length + vec[..LENGTH_VALUE_SIZE].copy_from_slice(&payload_len_u32.to_be_bytes()); Ok(vec) }