[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[minion-cvs] Add basic functionality to ameliorate zlib bombing



Update of /home/minion/cvsroot/src/minion/lib/mixminion
In directory moria.mit.edu:/tmp/cvs-serv3253/lib/mixminion

Modified Files:
	Crypto.py BuildMessage.py 
Log Message:
Add basic functionality to ameliorate zlib bombing

Index: Crypto.py
===================================================================
RCS file: /home/minion/cvsroot/src/minion/lib/mixminion/Crypto.py,v
retrieving revision 1.28
retrieving revision 1.29
diff -u -d -r1.28 -r1.29
--- Crypto.py	16 Dec 2002 02:40:11 -0000	1.28
+++ Crypto.py	20 Dec 2002 23:51:22 -0000	1.29
@@ -18,13 +18,14 @@
 from mixminion.Common import MixError, MixFatalError, floorDiv, ceilDiv, LOG
 
 __all__ = [ 'AESCounterPRNG', 'CryptoError', 'Keyset', 'bear_decrypt',
-            'bear_encrypt', 'ctr_crypt', 'init_crypto', 'lioness_decrypt',
-            'lioness_encrypt', 'openssl_seed', 'pk_check_signature',
-            'pk_decode_private_key', 'pk_decrypt', 'pk_encode_private_key',
-            'pk_encrypt', 'pk_from_modulus', 'pk_generate', 'pk_get_modulus',
-            'pk_sign', 'prng', 'sha1', 'strxor', 'trng',
-            'AES_KEY_LEN', 'DIGEST_LEN', 'HEADER_SECRET_MODE', 'PRNG_MODE',
-            'RANDOM_JUNK_MODE', 'HEADER_ENCRYPT_MODE', 'APPLICATION_KEY_MODE',
+            'bear_encrypt', 'ctr_crypt', 'getCommonPRNG', 'init_crypto',
+            'lioness_decrypt', 'lioness_encrypt', 'openssl_seed',
+            'pk_check_signature', 'pk_decode_private_key', 'pk_decrypt',
+            'pk_encode_private_key', 'pk_encrypt', 'pk_from_modulus',
+            'pk_generate', 'pk_get_modulus', 'pk_sign', 'prng', 'sha1',
+            'strxor', 'trng', 'AES_KEY_LEN', 'DIGEST_LEN',
+            'HEADER_SECRET_MODE', 'PRNG_MODE', 'RANDOM_JUNK_MODE',
+            'HEADER_ENCRYPT_MODE', 'APPLICATION_KEY_MODE',
             'PAYLOAD_ENCRYPT_MODE', 'HIDE_HEADER_MODE' ]
 
 # Expose _minionlib.CryptoError as Crypto.CryptoError

Index: BuildMessage.py
===================================================================
RCS file: /home/minion/cvsroot/src/minion/lib/mixminion/BuildMessage.py,v
retrieving revision 1.23
retrieving revision 1.24
diff -u -d -r1.23 -r1.24
--- BuildMessage.py	16 Dec 2002 02:40:11 -0000	1.23
+++ BuildMessage.py	20 Dec 2002 23:51:22 -0000	1.24
@@ -551,8 +551,18 @@
     assert overhead in (0, ENC_FWD_OVERHEAD)
 
     # Compress the data, and figure out how much padding we'll need.
+    origLength = len(payload)
     payload = compressData(payload)
     length = len(payload)
+    
+    # FFFF This is an ugly workaround for too-compressable data, so we don't
+    # FFFF create messages that will necessarily be dropped.  We should be
+    # FFFF more sensible on the output side.
+    if length > 1024 and length*20 <= origLength:
+        LOG.warn("Double-compressing message so it won't look like a z-bomb")
+        payload = compressData(payload)
+        length = len(payload)
+
     paddingLen = PAYLOAD_LEN - SINGLETON_PAYLOAD_OVERHEAD - overhead - length
 
     # If the compressed payload doesn't fit in 28K, then we need to bail out.
@@ -583,7 +593,13 @@
         raise MixError("Message fragments not yet supported")
 
     # Uncompress the body.
-    return uncompressData(payload.getContents())
+    contents = payload.getContents()
+    # FFFF - We should make this rule configurable.
+    maxLen = max(20*1024, 20*len(contents))
+    # FFFF - On encountering an overcompressed piece of data, we should
+    # FFFF   deliver it, still compressed, with a warning -- not merely
+    # FFFF   drop it as a _definite_ bomb.
+    return uncompressData(payload.getContents(), maxLength=maxLen)
 
 def _checkPayload(payload):
     'Return true iff the hash on the given payload seems valid'
@@ -620,12 +636,16 @@
     assert s[1] == '\xda' # no dict, max compression
     return s
 
-def uncompressData(payload):
-    """Uncompress a string 'payload'; raise ParseError if it is not valid
-       compressed data."""
-    # FFFF We should prevent zlib bombing.  Somebody could compress 28MB of
-    # FFFF zero bytes down to fit in a single payload and use us to
-    # FFFF mailbomb people, hard.
+class CompressedDataTooLong(MixError):
+    """Exception: raised when try to uncompress data that turns out to be
+       longer than we had expected."""
+    pass
+
+def uncompressData(payload, maxLength=None):
+    """Uncompress a string 'payload'; raise ParseError if it is not
+       valid compressed data.  If the expanded data is longer than
+       maxLength, we raise 'CompressedDataTooLong'."""
+
     if len(payload) < 6 or payload[0:2] != '\x78\xDA':
         raise ParseError("Invalid zlib header")
     try:
@@ -633,7 +653,13 @@
         # want to limit the output size.
         zobj = zlib.decompressobj(zlib.MAX_WBITS)
         # Decompress the payload.
-        d = zobj.decompress(payload)
+        if maxLength is None:
+            d = zobj.decompress(payload)
+        else:
+            d = zobj.decompress(payload, maxLength)
+        if zobj.unconsumed_tail:
+            raise CompressedDataTooLong()
+            
         # Get any leftovers, which shouldn't exist.
         nil = zobj.flush()
         if nil != '':