Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix recommended read buffer size #126

Merged
merged 2 commits into from
Sep 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## Unreleased

- Corrected recommended read buffer size (16640 bytes instead of 16384)

## 0.15.0 - 2023-08-26

- Updated p256 dependency from 0.11 to 0.13.2 (#124)
- Fix reading buffered data in multiple steps (#121, #122)
- Fix error in NewSessionTicket message handling (#120)
Expand Down
10 changes: 5 additions & 5 deletions src/asynch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,12 @@ where
/// Create a new TLS connection with the provided context and a async I/O implementation
///
/// NOTE: The record read buffer should be sized to fit an encrypted TLS record. The size of this record
/// depends on the server configuration, but the maximum allowed value for a TLS record is 16 kB, which
/// should be a safe value to use.
/// depends on the server configuration, but the maximum allowed value for a TLS record is 16640 bytes,
/// which should be a safe value to use.
///
/// The write record buffer can be smaller than the read buffer. During write [`TLS_RECORD_OVERHEAD`] over overhead
/// is added per record, so the buffer must at least be this large. Large writes are split into multiple records if
/// depending on the size of the write buffer.
/// The write record buffer can be smaller than the read buffer. During writes [`TLS_RECORD_OVERHEAD`] bytes of
/// overhead is added per record, so the buffer must at least be this large. Large writes are split into multiple
/// records if depending on the size of the write buffer.
/// The largest of the two buffers will be used to encode the TLS handshake record, hence either of the
/// buffers must at least be large enough to encode a handshake.
pub fn new(
Expand Down
10 changes: 5 additions & 5 deletions src/blocking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,12 @@ where
/// Create a new TLS connection with the provided context and a blocking I/O implementation
///
/// NOTE: The record read buffer should be sized to fit an encrypted TLS record. The size of this record
/// depends on the server configuration, but the maximum allowed value for a TLS record is 16 kB, which
/// should be a safe value to use.
/// depends on the server configuration, but the maximum allowed value for a TLS record is 16640 bytes,
/// which should be a safe value to use.
///
/// The write record buffer can be smaller than the read buffer. During write [`TLS_RECORD_OVERHEAD`] over overhead
/// is added per record, so the buffer must at least be this large. Large writes are split into multiple records if
/// depending on the size of the write buffer.
/// The write record buffer can be smaller than the read buffer. During writes [`TLS_RECORD_OVERHEAD`] bytes of
/// overhead is added per record, so the buffer must at least be this large. Large writes are split into multiple
/// records if depending on the size of the write buffer.
/// The largest of the two buffers will be used to encode the TLS handshake record, hence either of the
/// buffers must at least be large enough to encode a handshake.
pub fn new(
Expand Down
10 changes: 10 additions & 0 deletions src/buffer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ impl<'b> CryptoBuffer<'b> {
self.len += 1;
Ok(())
} else {
error!("Failed to push byte");
Err(TlsError::InsufficientSpace)
}
}
Expand All @@ -63,6 +64,10 @@ impl<'b> CryptoBuffer<'b> {
self.buf[self.offset + idx] = val;
Ok(())
} else {
error!(
"Failed to set byte: index {} is out of range for {} elements",
idx, self.len
);
Err(TlsError::InsufficientSpace)
}
}
Expand Down Expand Up @@ -92,6 +97,11 @@ impl<'b> CryptoBuffer<'b> {

fn extend_internal(&mut self, other: &[u8]) -> Result<(), TlsError> {
if self.space() < other.len() {
error!(
"Failed to extend buffer. Space: {} required: {}",
self.space(),
other.len()
);
Err(TlsError::InsufficientSpace)
} else {
let start = self.offset + self.len;
Expand Down
2 changes: 1 addition & 1 deletion src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use typenum::{Sum, U10, U12, U16, U32};

pub use crate::extensions::extension_data::max_fragment_length::MaxFragmentLength;

const TLS_RECORD_MAX: usize = 16384;
pub(crate) const TLS_RECORD_MAX: usize = 16384;
pub const TLS_RECORD_OVERHEAD: usize = 128;

// longest label is 12b -> buf <= 2 + 1 + 6 + longest + 1 + hash_out = hash_out + 22
Expand Down
7 changes: 4 additions & 3 deletions src/handshake/certificate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,10 @@ impl<'a> CertificateRef<'a> {
}

pub fn add(&mut self, entry: CertificateEntryRef<'a>) -> Result<(), TlsError> {
self.entries
.push(entry)
.map_err(|_| TlsError::InsufficientSpace)
self.entries.push(entry).map_err(|_| {
error!("CertificateRef: InsufficientSpace");
TlsError::InsufficientSpace
})
}

pub fn parse(buf: &mut ParseBuffer<'a>) -> Result<Self, TlsError> {
Expand Down
5 changes: 4 additions & 1 deletion src/handshake/certificate_request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,10 @@ impl<'a> TryFrom<CertificateRequestRef<'a>> for CertificateRequest {
let mut request_context = Vec::new();
request_context
.extend_from_slice(cert.request_context)
.map_err(|_| TlsError::InsufficientSpace)?;
.map_err(|_| {
error!("CertificateRequest: InsufficientSpace");
TlsError::InsufficientSpace
})?;
Ok(Self { request_context })
}
}
8 changes: 4 additions & 4 deletions src/handshake/server_hello.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,10 @@ impl<'a> ServerHello<'a> {

let extensions = ServerHelloExtension::parse_vector(buf)?;

// info!("server random {:x?}", random);
// info!("server session-id {:x?}", session_id.as_slice());
// info!("server cipher_suite {:x?}", cipher_suite);
// info!("server extensions {:?}", extensions);
// debug!("server random {:x}", random);
// debug!("server session-id {:x}", session_id.as_slice());
debug!("server cipher_suite {:?}", cipher_suite);
debug!("server extensions {:?}", extensions);

Ok(Self {
random,
Expand Down
5 changes: 4 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,10 @@ impl embedded_io::Error for TlsError {
fn kind(&self) -> embedded_io::ErrorKind {
match self {
Self::Io(k) => *k,
_ => embedded_io::ErrorKind::Other,
_ => {
error!("TLS error: {:?}", self);
embedded_io::ErrorKind::Other
}
}
}
}
Expand Down
22 changes: 17 additions & 5 deletions src/parse_buffer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,11 +124,22 @@ impl<'b> ParseBuffer<'b> {
dest: &mut Vec<u8, N>,
num_bytes: usize,
) -> Result<(), ParseError> {
if (dest.capacity() - dest.len()) < num_bytes {
let space = dest.capacity() - dest.len();
if space < num_bytes {
error!(
"Insufficient space in destination buffer. Space: {} required: {}",
space, num_bytes
);
Err(ParseError::InsufficientSpace)
} else if self.pos + num_bytes <= self.buffer.len() {
dest.extend_from_slice(&self.buffer[self.pos..self.pos + num_bytes])
.map_err(|_| ParseError::InsufficientSpace)?;
.map_err(|_| {
error!(
"Failed to extend destination buffer. Space: {} required: {}",
space, num_bytes
);
ParseError::InsufficientSpace
})?;
self.pos += num_bytes;
Ok(())
} else {
Expand All @@ -145,9 +156,10 @@ impl<'b> ParseBuffer<'b> {

let mut data = self.slice(data_length)?;
while !data.is_empty() {
result
.push(read(&mut data)?)
.map_err(|_| ParseError::InsufficientSpace)?;
result.push(read(&mut data)?).map_err(|_| {
error!("Failed to store parse result");
ParseError::InsufficientSpace
})?;
}

Ok(result)
Expand Down
4 changes: 2 additions & 2 deletions src/record.rs
Original file line number Diff line number Diff line change
Expand Up @@ -174,11 +174,11 @@ pub struct RecordHeader {
impl RecordHeader {
pub fn content_type(&self) -> ContentType {
// Content type already validated in read
ContentType::of(self.header[0]).unwrap()
unwrap!(ContentType::of(self.header[0]))
}

pub fn content_length(&self) -> usize {
// Content lenth already validated in read
// Content length already validated in read
u16::from_be_bytes([self.header[3], self.header[4]]) as usize
}

Expand Down
13 changes: 13 additions & 0 deletions src/record_reader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ where
CipherSuite: TlsCipherSuite,
{
pub fn new(buf: &'a mut [u8]) -> Self {
if buf.len() < 16640 {
warn!("Read buffer is smaller than 16640 bytes, which may cause problems!");
}
Self {
buf,
decoded: 0,
Expand All @@ -47,6 +50,11 @@ where
let header = RecordHeader::decode(header.try_into().unwrap())?;

let content_length = header.content_length();
debug!(
"advance: {:?} - content_length = {} bytes",
header.content_type(),
content_length
);
let data = self.advance(transport, content_length).await?;
ServerRecord::decode(header, data, key_schedule.transcript_hash())
}
Expand Down Expand Up @@ -115,6 +123,11 @@ where
fn ensure_contiguous(&mut self, len: usize) -> Result<(), TlsError> {
if self.decoded + len > self.buf.len() {
if len > self.buf.len() {
error!(
"Record too large for buffer. Size: {} Buffer size: {}",
len,
self.buf.len()
);
return Err(TlsError::InsufficientSpace);
}
self.buf
Expand Down