summaryrefslogtreecommitdiffstats
path: root/openpgp
diff options
context:
space:
mode:
authorJustus Winter <justus@sequoia-pgp.org>2021-08-19 14:30:35 +0200
committerJustus Winter <justus@sequoia-pgp.org>2021-09-08 11:08:19 +0200
commit0c0621ed263657e1d1348a62d7ceb59f2823bf76 (patch)
tree89f51764e2dc8bdca6b671f716108d6fcce37a59 /openpgp
parentf6abef476d180fc1f16e95641248eac230f3c10e (diff)
openpgp: Constrain AEAD chunk sizes.
- Make sure that chunk sizes are between 64B and 4MiB. - Fixes a DoS resulting from unconstrained, attacker-controlled heap allocations. - Fixes #738.
Diffstat (limited to 'openpgp')
-rw-r--r--openpgp/NEWS4
-rw-r--r--openpgp/src/crypto/aead.rs20
-rw-r--r--openpgp/src/parse.rs4
-rw-r--r--openpgp/tests/data/messages/aed/msg-aes128-eax-chunk-size-4194304-password-123.pgpbin0 -> 5314 bytes
4 files changed, 26 insertions, 2 deletions
diff --git a/openpgp/NEWS b/openpgp/NEWS
index 4606ac1b..9fc36a9c 100644
--- a/openpgp/NEWS
+++ b/openpgp/NEWS
@@ -12,6 +12,10 @@
** Notable fixes
- Filters set using CertParser::unvalidated_cert_filter are now
preserved during iterations.
+* Changes in 1.3.1
+** Notable fixes
+ - Fixed a crash resulting from unconstrained, attacker-controlled
+ heap allocations.
* Changes in 1.3.0
** New functionality
- CertBuilder::add_subkey_with
diff --git a/openpgp/src/crypto/aead.rs b/openpgp/src/crypto/aead.rs
index 9418d847..8ca021cb 100644
--- a/openpgp/src/crypto/aead.rs
+++ b/openpgp/src/crypto/aead.rs
@@ -19,6 +19,16 @@ use crate::crypto::mem::secure_cmp;
use crate::seal;
use crate::parse::Cookie;
+/// Minimum AEAD chunk size.
+///
+/// Implementations MUST support chunk sizes down to 64B.
+const MIN_CHUNK_SIZE: usize = 1 << 6; // 64B
+
+/// Maximum AEAD chunk size.
+///
+/// Implementations MUST support chunk sizes up to 4MiB.
+const MAX_CHUNK_SIZE: usize = 1 << 22; // 4MiB
+
/// Disables authentication checks.
///
/// This is DANGEROUS, and is only useful for debugging problems with
@@ -140,6 +150,11 @@ impl<'a> Decryptor<'a> {
source: Box<dyn 'a + BufferedReader<Cookie>>)
-> Result<Self>
{
+ if chunk_size < MIN_CHUNK_SIZE || chunk_size > MAX_CHUNK_SIZE {
+ return Err(Error::InvalidArgument(
+ format!("Invalid AEAD chunk size: {}", chunk_size)).into());
+ }
+
Ok(Decryptor {
source,
sym_algo,
@@ -552,6 +567,11 @@ impl<W: io::Write> Encryptor<W> {
pub fn new(version: u8, sym_algo: SymmetricAlgorithm, aead: AEADAlgorithm,
chunk_size: usize, iv: &[u8], key: &SessionKey, sink: W)
-> Result<Self> {
+ if chunk_size < MIN_CHUNK_SIZE || chunk_size > MAX_CHUNK_SIZE {
+ return Err(Error::InvalidArgument(
+ format!("Invalid AEAD chunk size: {}", chunk_size)).into());
+ }
+
let mut scratch = Vec::with_capacity(chunk_size);
unsafe { scratch.set_len(chunk_size); }
diff --git a/openpgp/src/parse.rs b/openpgp/src/parse.rs
index 7b747180..fbb5cfff 100644
--- a/openpgp/src/parse.rs
+++ b/openpgp/src/parse.rs
@@ -5482,9 +5482,9 @@ mod test {
],
},
DecryptTest {
- filename: "aed/msg-aes128-eax-chunk-size-134217728-password-123.pgp",
+ filename: "aed/msg-aes128-eax-chunk-size-4194304-password-123.pgp",
algo: SymmetricAlgorithm::AES128,
- key_hex: "D7EE3F3B049DE011687EC9E08D6DCBB0",
+ key_hex: "918E6BF5C6CE4320D014735AF27BFA76",
plaintext: Data::File("a-cypherpunks-manifesto.txt"),
paths: &[
(Tag::SKESK, &[ 0 ]),
diff --git a/openpgp/tests/data/messages/aed/msg-aes128-eax-chunk-size-4194304-password-123.pgp b/openpgp/tests/data/messages/aed/msg-aes128-eax-chunk-size-4194304-password-123.pgp
new file mode 100644
index 00000000..145ab4a4
--- /dev/null
+++ b/openpgp/tests/data/messages/aed/msg-aes128-eax-chunk-size-4194304-password-123.pgp
Binary files differ