Skip to content

Commit 0d452ed

Browse files
committed
fix(ra-tls): bound RA-TLS extension gzip decompression
1 parent f87c977 commit 0d452ed

1 file changed

Lines changed: 17 additions & 2 deletions

File tree

ra-tls/src/cert.rs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -478,6 +478,13 @@ pub struct CertPair {
478478
/// Magic prefix for gzip-compressed event log (version 1)
479479
pub const EVENTLOG_GZIP_MAGIC: &[u8] = b"ELGZv1";
480480

481+
/// Maximum allowed decompressed size of the event log extension (in bytes).
482+
///
483+
/// This protects against gzip decompression bombs in RA-TLS certificate
484+
/// extensions by bounding the amount of memory we are willing to allocate.
485+
/// 16 KiB is sufficient for typical event logs we embed in certs.
486+
pub const MAX_EVENTLOG_EXT_SIZE: u64 = 16 * 1024;
487+
481488
/// Compress a certificate extension value
482489
pub fn compress_ext_value(data: &[u8]) -> Result<Vec<u8>> {
483490
use flate2::write::GzEncoder;
@@ -507,11 +514,19 @@ pub fn decompress_ext_value(data: &[u8]) -> Result<Vec<u8>> {
507514
if data.starts_with(EVENTLOG_GZIP_MAGIC) {
508515
// Compressed format
509516
let compressed = &data[EVENTLOG_GZIP_MAGIC.len()..];
510-
let mut decoder = GzDecoder::new(compressed);
517+
let decoder = GzDecoder::new(compressed);
518+
// Limit the total amount of decompressed data to avoid gzip bombs.
519+
let mut limited = decoder.take(MAX_EVENTLOG_EXT_SIZE + 1);
511520
let mut decompressed = Vec::new();
512-
decoder
521+
limited
513522
.read_to_end(&mut decompressed)
514523
.context("failed to decompress event log")?;
524+
if decompressed.len() as u64 > MAX_EVENTLOG_EXT_SIZE {
525+
bail!(
526+
"event log extension too large (>{} bytes)",
527+
MAX_EVENTLOG_EXT_SIZE
528+
);
529+
}
515530
Ok(decompressed)
516531
} else {
517532
// Uncompressed format (backwards compatibility)

0 commit comments

Comments
 (0)