[Python-modules-commits] r26290 - in packages/python-crypto/branches/wheezy/debian (3 files)
sramacher at users.alioth.debian.org
sramacher at users.alioth.debian.org
Sat Oct 26 15:49:54 UTC 2013
Date: Saturday, October 26, 2013 @ 15:49:53
Author: sramacher
Revision: 26290
Import 2.6-4+deb7u3
Added:
packages/python-crypto/branches/wheezy/debian/patches/CVE-2013-1445.patch
Modified:
packages/python-crypto/branches/wheezy/debian/changelog
packages/python-crypto/branches/wheezy/debian/patches/series
Modified: packages/python-crypto/branches/wheezy/debian/changelog
===================================================================
--- packages/python-crypto/branches/wheezy/debian/changelog 2013-10-26 15:46:43 UTC (rev 26289)
+++ packages/python-crypto/branches/wheezy/debian/changelog 2013-10-26 15:49:53 UTC (rev 26290)
@@ -1,3 +1,25 @@
+python-crypto (2.6-4+deb7u3) wheezy-security; urgency=low
+
+ * debian/patches/CVE-2013-1445.patch: Disable multiprocessing tests on
+ kfreebsd-* completely since Python 2.6 and 2.7 report different errors if
+ multiprocessing is not working.
+
+ -- Sebastian Ramacher <sramacher at debian.org> Fri, 18 Oct 2013 14:21:33 +0200
+
+python-crypto (2.6-4+deb7u2) wheezy-security; urgency=low
+
+ * debian/patches/CVE-2013-1445.patch: Check if multiprocessing.synchronize
+ is working in the test suite to fix a build failure on kfreebsd-*.
+
+ -- Sebastian Ramacher <sramacher at debian.org> Fri, 18 Oct 2013 01:07:38 +0200
+
+python-crypto (2.6-4+deb7u1) wheezy-security; urgency=high
+
+ * debian/patches/CVE-2013-1445.patch: Apply upstream patch to fix
+ CVE-2013-1445: PRNG not correctly reseeded in some situations.
+
+ -- Sebastian Ramacher <sramacher at debian.org> Thu, 17 Oct 2013 21:55:30 +0200
+
python-crypto (2.6-4) unstable; urgency=low
* debian/python-crypto-dbg.preinst: Add preinst script to handle symlink to
Added: packages/python-crypto/branches/wheezy/debian/patches/CVE-2013-1445.patch
===================================================================
--- packages/python-crypto/branches/wheezy/debian/patches/CVE-2013-1445.patch (rev 0)
+++ packages/python-crypto/branches/wheezy/debian/patches/CVE-2013-1445.patch 2013-10-26 15:49:53 UTC (rev 26290)
@@ -0,0 +1,261 @@
+Description: Fix CVE-2013-1445
+ In PyCrypto before v2.6.1, the Crypto.Random pseudo-random number generator
+ (PRNG) exhibits a race condition that may cause it to generate the same
+ 'random' output in multiple processes that are forked from each other.
+ Depending on the application, this could reveal sensitive information or
+ cryptographic keys to remote attackers.
+ .
+ An application may be affected if, within 100 milliseconds, it performs the
+ following steps:
+ .
+ 1. Read from the Crypto.Random PRNG, causing an internal reseed;
+ 2. Fork the process and invoke Crypto.Random.atfork() in the child;
+ 3. Read from the Crypto.Random PRNG again, in at least two different
+ processes (parent and child, or multiple children).
+ .
+ Only applications that invoke Crypto.Random.atfork() and perform the above
+ steps are affected by this issue. Other applications are unaffected.
+ .
+ Note: Some PyCrypto functions, such as key generation and PKCS#1-related
+ functions, implicitly read from the Crypto.Random PRNG.
+Origin: upstream,
+ https://github.com/dlitz/pycrypto/commit/19dcf7b15d61b7dc1a125a367151de40df6ef175,
+ https://github.com/dlitz/pycrypto/commit/845055208d8f5fa153faf646f18876c4a1b9cc84
+Last-Update: 2013-10-18
+
+--- a/lib/Crypto/Random/Fortuna/FortunaAccumulator.py
++++ b/lib/Crypto/Random/Fortuna/FortunaAccumulator.py
+@@ -109,6 +109,15 @@
+ self.pools = [FortunaPool() for i in range(32)] # 32 pools
+ assert(self.pools[0] is not self.pools[1])
+
++ def _forget_last_reseed(self):
++ # This is not part of the standard Fortuna definition, and using this
++ # function frequently can weaken Fortuna's ability to resist a state
++ # compromise extension attack, but we need this in order to properly
++ # implement Crypto.Random.atfork(). Otherwise, forked child processes
++ # might continue to use their parent's PRNG state for up to 100ms in
++ # some cases. (e.g. CVE-2013-1445)
++ self.last_reseed = None
++
+ def random_data(self, bytes):
+ current_time = time.time()
+ if (self.last_reseed is not None and self.last_reseed > current_time): # Avoid float comparison to None to make Py3k happy
+--- a/lib/Crypto/Random/_UserFriendlyRNG.py
++++ b/lib/Crypto/Random/_UserFriendlyRNG.py
+@@ -90,9 +90,24 @@
+ """Initialize the random number generator and seed it with entropy from
+ the operating system.
+ """
++
++ # Save the pid (helps ensure that Crypto.Random.atfork() gets called)
+ self._pid = os.getpid()
++
++ # Collect entropy from the operating system and feed it to
++ # FortunaAccumulator
+ self._ec.reinit()
+
++ # Override FortunaAccumulator's 100ms minimum re-seed interval. This
++ # is necessary to avoid a race condition between this function and
++ # self.read(), which that can otherwise cause forked child processes to
++ # produce identical output. (e.g. CVE-2013-1445)
++ #
++ # Note that if this function can be called frequently by an attacker,
++ # (and if the bits from OSRNG are insufficiently random) it will weaken
++ # Fortuna's ability to resist a state compromise extension attack.
++ self._fa._forget_last_reseed()
++
+ def close(self):
+ self.closed = True
+ self._osrng = None
+--- a/lib/Crypto/SelfTest/Random/__init__.py
++++ b/lib/Crypto/SelfTest/Random/__init__.py
+@@ -32,6 +32,7 @@
+ from Crypto.SelfTest.Random import OSRNG; tests += OSRNG.get_tests(config=config)
+ from Crypto.SelfTest.Random import test_random; tests += test_random.get_tests(config=config)
+ from Crypto.SelfTest.Random import test_rpoolcompat; tests += test_rpoolcompat.get_tests(config=config)
++ from Crypto.SelfTest.Random import test__UserFriendlyRNG; tests += test__UserFriendlyRNG.get_tests(config=config)
+ return tests
+
+ if __name__ == '__main__':
+--- /dev/null
++++ b/lib/Crypto/SelfTest/Random/test__UserFriendlyRNG.py
+@@ -0,0 +1,178 @@
++# -*- coding: utf-8 -*-
++# Self-tests for the user-friendly Crypto.Random interface
++#
++# Written in 2013 by Dwayne C. Litzenberger <dlitz at dlitz.net>
++#
++# ===================================================================
++# The contents of this file are dedicated to the public domain. To
++# the extent that dedication to the public domain is not available,
++# everyone is granted a worldwide, perpetual, royalty-free,
++# non-exclusive license to exercise all rights associated with the
++# contents of this file for any purpose whatsoever.
++# No rights are reserved.
++#
++# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
++# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
++# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
++# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
++# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
++# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
++# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
++# SOFTWARE.
++# ===================================================================
++
++"""Self-test suite for generic Crypto.Random stuff """
++
++from __future__ import nested_scopes
++
++__revision__ = "$Id$"
++
++import binascii
++import pprint
++import unittest
++import os
++import time
++import sys
++if sys.version_info[0] == 2 and sys.version_info[1] == 1:
++ from Crypto.Util.py21compat import *
++from Crypto.Util.py3compat import *
++
++try:
++ import multiprocessing
++ import multiprocessing.synchronize
++except ImportError:
++ multiprocessing = None
++
++# disable multiprocessing test on GNU/kFreeBSD since it doesn't have a working
++# multiprocessing implementation
++import platform
++if platform.system() == 'GNU/kFreeBSD':
++ multiprocessing = None
++
++import Crypto.Random._UserFriendlyRNG
++import Crypto.Random.random
++
++class RNGForkTest(unittest.TestCase):
++
++ def _get_reseed_count(self):
++ """
++ Get `FortunaAccumulator.reseed_count`, the global count of the
++ number of times that the PRNG has been reseeded.
++ """
++ rng_singleton = Crypto.Random._UserFriendlyRNG._get_singleton()
++ rng_singleton._lock.acquire()
++ try:
++ return rng_singleton._fa.reseed_count
++ finally:
++ rng_singleton._lock.release()
++
++ def runTest(self):
++ # Regression test for CVE-2013-1445. We had a bug where, under the
++ # right conditions, two processes might see the same random sequence.
++
++ if sys.platform.startswith('win'): # windows can't fork
++ assert not hasattr(os, 'fork') # ... right?
++ return
++
++ # Wait 150 ms so that we don't trigger the rate-limit prematurely.
++ time.sleep(0.15)
++
++ reseed_count_before = self._get_reseed_count()
++
++ # One or both of these calls together should trigger a reseed right here.
++ Crypto.Random._UserFriendlyRNG._get_singleton().reinit()
++ Crypto.Random.get_random_bytes(1)
++
++ reseed_count_after = self._get_reseed_count()
++ self.assertNotEqual(reseed_count_before, reseed_count_after) # sanity check: test should reseed parent before forking
++
++ rfiles = []
++ for i in range(10):
++ rfd, wfd = os.pipe()
++ if os.fork() == 0:
++ # child
++ os.close(rfd)
++ f = os.fdopen(wfd, "wb")
++
++ Crypto.Random.atfork()
++
++ data = Crypto.Random.get_random_bytes(16)
++
++ f.write(data)
++ f.close()
++ os._exit(0)
++ # parent
++ os.close(wfd)
++ rfiles.append(os.fdopen(rfd, "rb"))
++
++ results = []
++ results_dict = {}
++ for f in rfiles:
++ data = binascii.hexlify(f.read())
++ results.append(data)
++ results_dict[data] = 1
++ f.close()
++
++ if len(results) != len(results_dict.keys()):
++ raise AssertionError("RNG output duplicated across fork():\n%s" %
++ (pprint.pformat(results)))
++
++
++# For RNGMultiprocessingForkTest
++def _task_main(q):
++ a = Crypto.Random.get_random_bytes(16)
++ time.sleep(0.1) # wait 100 ms
++ b = Crypto.Random.get_random_bytes(16)
++ q.put(binascii.b2a_hex(a))
++ q.put(binascii.b2a_hex(b))
++ q.put(None) # Wait for acknowledgment
++
++
++class RNGMultiprocessingForkTest(unittest.TestCase):
++
++ def runTest(self):
++ # Another regression test for CVE-2013-1445. This is basically the
++ # same as RNGForkTest, but less compatible with old versions of Python,
++ # and a little easier to read.
++
++ n_procs = 5
++ manager = multiprocessing.Manager()
++ queues = [manager.Queue(1) for i in range(n_procs)]
++
++ # Reseed the pool
++ time.sleep(0.15)
++ Crypto.Random._UserFriendlyRNG._get_singleton().reinit()
++ Crypto.Random.get_random_bytes(1)
++
++ # Start the child processes
++ pool = multiprocessing.Pool(processes=n_procs, initializer=Crypto.Random.atfork)
++ map_result = pool.map_async(_task_main, queues)
++
++ # Get the results, ensuring that no pool processes are reused.
++ aa = [queues[i].get(30) for i in range(n_procs)]
++ bb = [queues[i].get(30) for i in range(n_procs)]
++ res = list(zip(aa, bb))
++
++ # Shut down the pool
++ map_result.get(30)
++ pool.close()
++ pool.join()
++
++ # Check that the results are unique
++ if len(set(aa)) != len(aa) or len(set(res)) != len(res):
++ raise AssertionError("RNG output duplicated across fork():\n%s" %
++ (pprint.pformat(res),))
++
++
++def get_tests(config={}):
++ tests = []
++ tests += [RNGForkTest()]
++ if multiprocessing is not None:
++ tests += [RNGMultiprocessingForkTest()]
++ return tests
++
++if __name__ == '__main__':
++ suite = lambda: unittest.TestSuite(get_tests())
++ unittest.main(defaultTest='suite')
++
++# vim:set ts=4 sw=4 sts=4 expandtab:
Modified: packages/python-crypto/branches/wheezy/debian/patches/series
===================================================================
--- packages/python-crypto/branches/wheezy/debian/patches/series 2013-10-26 15:46:43 UTC (rev 26289)
+++ packages/python-crypto/branches/wheezy/debian/patches/series 2013-10-26 15:49:53 UTC (rev 26290)
@@ -5,3 +5,4 @@
reenable-redefined-tests.patch
fix-py3-errors.patch
fix-except-shadows-builtin.patch
+CVE-2013-1445.patch
More information about the Python-modules-commits
mailing list