diff --git a/tls_codec/CHANGELOG.md b/tls_codec/CHANGELOG.md index 2e70a71fb..58126421e 100644 --- a/tls_codec/CHANGELOG.md +++ b/tls_codec/CHANGELOG.md @@ -10,6 +10,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - [#2322](https://github.com/RustCrypto/formats/pull/2322): Add `VLByteVec` and `SecretVLByteVec`, which are `#[serde(transparent)]` wrappers serializing via `serde_bytes`. They produce a much more compact representation in `serde` formats that distinguish byte arrays from sequences of `u8` (e.g. CBOR, MessagePack, bincode). Their `serde` output is not compatible with `VLBytes` / `SecretVLBytes`, but their `Deserialize` impls are backwards-compatible: in self-describing `serde` formats they also accept the legacy `VLBytes` / `SecretVLBytes` encoding (a struct with a `vec` field containing a sequence of `u8`). Deprecate `VLBytes` and `SecretVLBytes` in favour of `VLByteVec` and `SecretVLByteVec`. - [#1656](https://github.com/RustCrypto/formats/pull/1656) Add `TlsVarInt` type for variable-length integers. +### Fixed +- [#2348](https://github.com/RustCrypto/formats/pull/2348) Use `write_all` everywhere instead of write to prevent partial writes from going undetected. The `Error::InvalidWriteLength` variant is deprecated as it is no longer returned. + ## 0.4.2 - [#1628](https://github.com/RustCrypto/formats/pull/1628) Bump MSRV to 1.74 diff --git a/tls_codec/src/arrays.rs b/tls_codec/src/arrays.rs index 3e6200896..e6d7ce441 100644 --- a/tls_codec/src/arrays.rs +++ b/tls_codec/src/arrays.rs @@ -11,14 +11,8 @@ impl Serialize for [u8; LEN] { #[cfg(feature = "std")] #[inline] fn tls_serialize(&self, writer: &mut W) -> Result { - let written = writer.write(self)?; - if written == LEN { - Ok(written) - } else { - Err(Error::InvalidWriteLength(format!( - "Expected to write {LEN} bytes but only {written} were written." - ))) - } + writer.write_all(self)?; + Ok(LEN) } } diff --git a/tls_codec/src/lib.rs b/tls_codec/src/lib.rs index cdd6cc155..a4a2a1eed 100644 --- a/tls_codec/src/lib.rs +++ b/tls_codec/src/lib.rs @@ -77,6 +77,9 @@ pub enum Error { InvalidVectorLength, /// Error writing everything out. + /// + /// **Deprecated:** This error variant is not returned anymore and only kept to avoid breaking + /// existing code. InvalidWriteLength(String), /// Invalid input when trying to decode a primitive integer. diff --git a/tls_codec/src/primitives.rs b/tls_codec/src/primitives.rs index cbea2d59e..55ad79ae6 100644 --- a/tls_codec/src/primitives.rs +++ b/tls_codec/src/primitives.rs @@ -32,8 +32,7 @@ impl Serialize for Option { fn tls_serialize(&self, writer: &mut W) -> Result { match self { Some(e) => { - let written = writer.write(&[1])?; - debug_assert_eq!(written, 1); + writer.write_all(&[1])?; e.tls_serialize(writer).map(|l| l + 1) } None => { @@ -156,9 +155,9 @@ macro_rules! impl_unsigned { #[cfg(feature = "std")] #[inline] fn tls_serialize(&self, writer: &mut W) -> Result { - let written = writer.write(&self.to_be_bytes())?; - debug_assert_eq!(written, $bytes); - Ok(written) + let bytes = &self.to_be_bytes(); + writer.write_all(bytes)?; + Ok($bytes) } } diff --git a/tls_codec/src/tls_vec.rs b/tls_codec/src/tls_vec.rs index 80a948543..83bdee167 100644 --- a/tls_codec/src/tls_vec.rs +++ b/tls_codec/src/tls_vec.rs @@ -155,7 +155,9 @@ macro_rules! impl_byte_serialize { let mut written = <$size as Serialize>::tls_serialize(&<$size>::try_from(byte_length).unwrap(), writer)?; // Now serialize the elements - written += writer.write($self.as_slice())?; + let bytes = $self.as_slice(); + writer.write_all(bytes)?; + written += bytes.len(); $self.assert_written_bytes(tls_serialized_len, written)?; Ok(written) diff --git a/tls_codec/tests/encode.rs b/tls_codec/tests/encode.rs index 8cb213c00..7dfed81f7 100644 --- a/tls_codec/tests/encode.rs +++ b/tls_codec/tests/encode.rs @@ -99,3 +99,30 @@ fn test_matching_vl_bytes_serialization() { SerializeBytes::tls_serialize(&byte_vec).expect("Error encoding byte vector") ); } + +struct SingleByteWriter(W); + +impl std::io::Write for SingleByteWriter { + fn write(&mut self, buf: &[u8]) -> std::io::Result { + if buf.is_empty() { + return Ok(0); + } + + self.0.write(&buf[..1]) + } + + fn flush(&mut self) -> std::io::Result<()> { + self.0.flush() + } +} + +#[test] +fn serialize_into_short_writer() { + let mut short_writer = SingleByteWriter(vec![0u8; 32]); + + let first = [0u8, 1, 2]; + + first.tls_serialize(&mut short_writer).unwrap(); + assert_eq!(short_writer.0.len(), 35); + assert_eq!(&short_writer.0[short_writer.0.len() - 3..], &[0, 1, 2]) +}