From fa14c18f6603781ed6d629caa7da95a150850e71 Mon Sep 17 00:00:00 2001
From: Martin Nilsson <nilsson@opera.com>
Date: Thu, 7 Aug 2014 21:21:03 +0200
Subject: [PATCH] Correctly check the fragment size in the different stages of
 decoding.

---
 lib/modules/SSL.pmod/Packet.pike | 27 +++++++++++++++++-------
 lib/modules/SSL.pmod/State.pike  | 36 ++++++++++++++++++--------------
 2 files changed, 39 insertions(+), 24 deletions(-)

diff --git a/lib/modules/SSL.pmod/Packet.pike b/lib/modules/SSL.pmod/Packet.pike
index 6195e36fcd..34f4eeda5e 100644
--- a/lib/modules/SSL.pmod/Packet.pike
+++ b/lib/modules/SSL.pmod/Packet.pike
@@ -1,12 +1,7 @@
 #pike __REAL_VERSION__
 
-/*
- * SSL Record Layer
- */
-
 //! SSL Record Layer. Handle formatting and parsing of packets.
 
-
 import .Constants;
 
 int content_type;
@@ -38,11 +33,27 @@ protected void create(ProtocolVersion version, void|int extra)
   marginal_size = extra;
 }
 
-object check_size(int|void extra)
+protected object check_size(string data, int extra)
 {
+  if (sizeof(data) > (PACKET_MAX_SIZE + extra))
+    return Alert(ALERT_fatal, ALERT_unexpected_message, version);
   marginal_size = extra;
-  return (sizeof(fragment) > (PACKET_MAX_SIZE + extra))
-    ? Alert(ALERT_fatal, ALERT_unexpected_message, version) : this;
+  fragment = data;
+}
+
+object set_plaintext(string data)
+{
+  check_size(data, 0);
+}
+
+object set_compressed(string data)
+{
+  check_size(data, 1024);
+}
+
+object set_encrypted(string data)
+{
+  check_size(data, 2048);
 }
 
 //! Receive data read from the network.
diff --git a/lib/modules/SSL.pmod/State.pike b/lib/modules/SSL.pmod/State.pike
index 2a2a868ebe..93f9ed28ec 100644
--- a/lib/modules/SSL.pmod/State.pike
+++ b/lib/modules/SSL.pmod/State.pike
@@ -71,8 +71,9 @@ Alert|Packet decrypt_packet(Packet packet)
     string(8bit) digest = data[<hmac_size-1..];
     data = data[..<hmac_size];
 
-    // Set data without HMAC
-    packet->fragment = data;
+    // Set data without HMAC. This never returns an Alert as the data
+    // is smaller.
+    packet->set_encrypted(data);
 
     if (mac->hash_packet(packet, seq_num, hmac_size)[..hmac_size-1] != digest) {
       // Bad digest.
@@ -207,9 +208,6 @@ Alert|Packet decrypt_packet(Packet packet)
     data = data[tls_iv..];
   }
 
-  // Set decrypted data.
-  packet->fragment = data;
-
   if (hmac_size)
   {
 #ifdef SSL3_DEBUG_CRYPT
@@ -241,8 +239,8 @@ Alert|Packet decrypt_packet(Packet packet)
     }
     junk = mac->hash_raw(junk);
 
-    // Set data without HMAC.
-    packet->fragment = data;
+    // Set decrypted data without HMAC.
+    fail = fail || [object(Alert)]packet->set_compressed(data);
 
     if (digest != mac->hash_packet(packet, seq_num)[..hmac_size-1])
       {
@@ -260,6 +258,11 @@ Alert|Packet decrypt_packet(Packet packet)
       }
     seq_num++;
   }
+  else
+  {
+    // Set decrypted data.
+    fail = fail || [object(Alert)]packet->set_compressed(data);
+  }
 
   if (compress)
   {
@@ -275,12 +278,10 @@ Alert|Packet decrypt_packet(Packet packet)
                            "Inflated package >16K\n");
 
     // Set uncompressed data
-    packet->fragment = data;
+    fail = fail || [object(Alert)]packet->set_plaintext(data);
   }
 
-  if (fail) return fail;
-
-  return [object(Packet)]packet->check_size();
+  return fail || packet;
 }
 
 //! Encrypts a packet (including deflating and MAC-generation).
@@ -289,6 +290,7 @@ Alert|Packet encrypt_packet(Packet packet)
   ProtocolVersion version = packet->protocol_version;
   string data = packet->fragment;
   string digest;
+  Alert res;
 
   if (compress)
   {
@@ -298,7 +300,8 @@ Alert|Packet encrypt_packet(Packet packet)
     data = compress(data);
 
     // Set compressed data.
-    packet->fragment = data;
+    res = [object(Alert)]packet->set_compressed(data);
+    if(res) return res;
   }
 
   int hmac_size = mac && (session->truncated_hmac ? 10 :
@@ -365,17 +368,18 @@ Alert|Packet encrypt_packet(Packet packet)
     data += digest;
 
   // Set encrypted data.
-  packet->fragment = data;
+  res = [object(Alert)]packet->set_encrypted(data);
+  if(res) return res;
 
   if (hmac_size) {
     // Encrypt-then-MAC mode.
     data += mac->hash_packet(packet, seq_num, hmac_size)[..hmac_size-1];
 
     // Set HMAC protected data.
-    packet->fragment = data;
+    res = [object(Alert)]packet->set_encrypted(data);
+    if(res) return res;
   }
 
   seq_num++;
-
-  return [object(Packet)]packet->check_size(2048);
+  return packet;
 }
-- 
GitLab