]> git.rkrishnan.org Git - tahoe-lafs/tahoe-lafs.git/commitdiff
Work in progress. 2215.refuse-vulnerable-openssl.3
authorDaira Hopwood <daira@jacaranda.org>
Tue, 20 May 2014 16:57:53 +0000 (17:57 +0100)
committerDaira Hopwood <daira@jacaranda.org>
Mon, 1 Jun 2015 13:52:11 +0000 (14:52 +0100)
Signed-off-by: Daira Hopwood <daira@jacaranda.org>
src/allmydata/test/test_version.py
src/allmydata/util/check_pyopenssl.py

index 8628f2812e90ea8c49b1ca014d0bfd4c0d507269..a0968630179cd3c5df09edd15b8e7c9898a3e763 100644 (file)
@@ -3,7 +3,8 @@ from pkg_resources import Requirement
 
 from twisted.trial import unittest
 
-from allmydata import check_requirement, cross_check, check_openssl_version, parse_build_date, PackagingError
+from allmydata import check_requirement, cross_check, PackagingError
+from allmydata.util.check_pyopenssl import check_openssl_version, check_resistant_to_heartbleed, OpenSSLVersionError
 from allmydata.util.verlib import NormalizedVersion as V, \
                                   IrrationalVersionError, \
                                   suggest_normalized_version as suggest
@@ -11,14 +12,10 @@ from allmydata.util.verlib import NormalizedVersion as V, \
 
 class MockSSL(object):
     SSLEAY_VERSION = 0
-    SSLEAY_CFLAGS = 2
 
-    def __init__(self, version, compiled_without_heartbeats=False):
-        self.opts = {
-            self.SSLEAY_VERSION: version,
-            self.SSLEAY_CFLAGS: compiled_without_heartbeats and 'compiler: gcc -DOPENSSL_NO_HEARTBEATS'
-                                                             or 'compiler: gcc',
-        }
+    def __init__(self, version, is_vulnerable=False):
+        self.is_vulnerable = is_vulnerable
+        self.opts = { self.SSLEAY_VERSION: version }
 
     def SSLeay_version(self, which):
         return self.opts[which]
@@ -134,31 +131,28 @@ class CheckRequirement(unittest.TestCase):
         self.failUnlessIn("but version '2.0'", res[0])
 
     def test_check_openssl_version(self):
-        self.failUnlessRaises(PackagingError, check_openssl_version, MockSSL(""))
-        self.failUnlessRaises(PackagingError, check_openssl_version, MockSSL("NotOpenSSL"))
-        self.failUnlessRaises(PackagingError, check_openssl_version, MockSSL("OpenSSL a.b.c"))
-        self.failUnlessRaises(PackagingError, check_openssl_version, MockSSL("OpenSSL 1.1.x"))
-        self.failUnlessRaises(PackagingError, check_openssl_version, MockSSL("OpenSSL 0.9"))
-        self.failUnlessRaises(PackagingError, check_openssl_version, MockSSL("OpenSSL 0.9.0"))
-        self.failUnlessRaises(PackagingError, check_openssl_version, MockSSL("OpenSSL 0.9.8"))
-        self.failUnlessRaises(PackagingError, check_openssl_version, MockSSL("OpenSSL 0.9.8", True))
-        self.failUnlessRaises(PackagingError, check_openssl_version, MockSSL("OpenSSL 0.9.8x"))
-        self.failUnlessRaises(PackagingError, check_openssl_version, MockSSL("OpenSSL 1.0.0"))
-        self.failUnlessRaises(PackagingError, check_openssl_version, MockSSL("OpenSSL 1.0.0", True))
-        self.failUnlessRaises(PackagingError, check_openssl_version, MockSSL("OpenSSL 1.0.0k"))
-        self.failUnlessRaises(PackagingError, check_openssl_version, MockSSL("OpenSSL 1.0.1"))
-        self.failUnlessRaises(PackagingError, check_openssl_version, MockSSL("OpenSSL 1.0.1", True))
-        self.failUnlessRaises(PackagingError, check_openssl_version, MockSSL("OpenSSL 1.0.1c", True))
-        self.failUnlessRaises(PackagingError, check_openssl_version, MockSSL("OpenSSL 1.0.1e 11 Feb 2013"))
-        self.failUnlessRaises(PackagingError, check_openssl_version, MockSSL("OpenSSL 1.0.1e 5 Apr 2014"))
-        self.failUnlessRaises(PackagingError, check_openssl_version, MockSSL("OpenSSL 1.0.1e 7 Abc 2014"))
-        self.failUnlessRaises(PackagingError, check_openssl_version, MockSSL("OpenSSL 1.0.1e invalid_date"))
-        self.failUnlessRaises(PackagingError, check_openssl_version, MockSSL("OpenSSL 1.0.1e 7 Apr"))
-        self.failUnlessRaises(PackagingError, check_openssl_version, MockSSL("OpenSSL 1.0.2-beta1"))
-        self.failUnlessRaises(PackagingError, check_openssl_version, MockSSL("OpenSSL 0.10"))
-        self.failUnlessRaises(PackagingError, check_openssl_version, MockSSL("OpenSSL 0.10.0"))
-        self.failUnlessRaises(PackagingError, check_openssl_version, MockSSL("OpenSSL 1.0.0"))
-        self.failUnlessRaises(PackagingError, check_openssl_version, MockSSL("OpenSSL 1.0.0 1 Jan 2000"))
+        self.failUnlessRaises(OpenSSLVersionError, check_openssl_version, MockSSL(""))
+        self.failUnlessRaises(OpenSSLVersionError, check_openssl_version, MockSSL("NotOpenSSL"))
+        self.failUnlessRaises(OpenSSLVersionError, check_openssl_version, MockSSL("OpenSSL a.b.c"))
+        self.failUnlessRaises(OpenSSLVersionError, check_openssl_version, MockSSL("OpenSSL 1.1.x"))
+        self.failUnlessRaises(OpenSSLVersionError, check_openssl_version, MockSSL("OpenSSL 0.9"))
+        self.failUnlessRaises(OpenSSLVersionError, check_openssl_version, MockSSL("OpenSSL 0.9.0"))
+        self.failUnlessRaises(OpenSSLVersionError, check_openssl_version, MockSSL("OpenSSL 0.9.8"))
+        self.failUnlessRaises(OpenSSLVersionError, check_openssl_version, MockSSL("OpenSSL 0.9.8x"))
+        self.failUnlessRaises(OpenSSLVersionError, check_openssl_version, MockSSL("OpenSSL 1.0.0"))
+        self.failUnlessRaises(OpenSSLVersionError, check_openssl_version, MockSSL("OpenSSL 1.0.0k"))
+        self.failUnlessRaises(OpenSSLVersionError, check_openssl_version, MockSSL("OpenSSL 1.0.1", True))
+        self.failUnlessRaises(OpenSSLVersionError, check_openssl_version, MockSSL("OpenSSL 1.0.1c", True))
+        self.failUnlessRaises(OpenSSLVersionError, check_openssl_version, MockSSL("OpenSSL 1.0.1e 11 Feb 2013"))
+        self.failUnlessRaises(OpenSSLVersionError, check_openssl_version, MockSSL("OpenSSL 1.0.1e 5 Apr 2014"))
+        self.failUnlessRaises(OpenSSLVersionError, check_openssl_version, MockSSL("OpenSSL 1.0.1e 7 Abc 2014"))
+        self.failUnlessRaises(OpenSSLVersionError, check_openssl_version, MockSSL("OpenSSL 1.0.1e invalid_date"))
+        self.failUnlessRaises(OpenSSLVersionError, check_openssl_version, MockSSL("OpenSSL 1.0.1e 7 Apr"))
+        self.failUnlessRaises(OpenSSLVersionError, check_openssl_version, MockSSL("OpenSSL 1.0.2-beta1"))
+        self.failUnlessRaises(OpenSSLVersionError, check_openssl_version, MockSSL("OpenSSL 0.10"))
+        self.failUnlessRaises(OpenSSLVersionError, check_openssl_version, MockSSL("OpenSSL 0.10.0"))
+        self.failUnlessRaises(OpenSSLVersionError, check_openssl_version, MockSSL("OpenSSL 1.0.0"))
+        self.failUnlessRaises(OpenSSLVersionError, check_openssl_version, MockSSL("OpenSSL 1.0.0 1 Jan 2000"))
 
         check_openssl_version(MockSSL("OpenSSL 0.9.8y"))
         check_openssl_version(MockSSL("OpenSSL 0.9.8z"))
@@ -184,12 +178,6 @@ class CheckRequirement(unittest.TestCase):
         check_openssl_version(MockSSL("OpenSSL 2.0.0 31 Dec 2020"))
         check_openssl_version(MockSSL("OpenSSL 10.0.0 31 Dec 2099"))
 
-        self.failUnlessEqual(parse_build_date(['1', 'Jan', '2000']), (2000, 1, 1))
-        self.failUnlessEqual(parse_build_date(['5', 'Apr', '2014']), (2014, 4, 5))
-        self.failUnlessEqual(parse_build_date(['7', 'Apr', '2014']), (2014, 4, 7))
-        self.failUnlessRaises(Exception, parse_build_date, [])
-        self.failUnlessRaises(Exception, parse_build_date, ['1', 'Abc' '2000'])
-
 
 # based on https://bitbucket.org/tarek/distutilsversion/src/17df9a7d96ef/test_verlib.py
 
index ebf2e12350342f10a7756c4297a4968a90a1960a..3a5c1a9ebc1ed99ff54cd0b0461eb1a332406f43 100644 (file)
@@ -3,7 +3,7 @@
 import re
 
 
-class OpenSSLVersionError(EnvironmentError):
+class UnsafeOpenSSLError(EnvironmentError):
     pass
 
 
@@ -12,7 +12,7 @@ def check_openssl_version(SSL):
     split_version = openssl_version.split(' ')
 
     if len(split_version) < 2 or split_version[0] != 'OpenSSL':
-        raise OpenSSLVersionError("could not understand OpenSSL version string %s" % (openssl_version,))
+        raise UnsafeOpenSSLError("could not understand OpenSSL version string %s" % (openssl_version,))
 
     try:
         components = split_version[1].split('.')
@@ -28,40 +28,23 @@ def check_openssl_version(SSL):
             (numeric_components == [1, 0, 2] and not components[2].startswith('2-beta')) or
             (numeric_components >= [1, 0, 3])):
             return
-    except Exception, e:
-        #import traceback
-        #traceback.print_exc()
-        pass
-    else:
-        if numeric_components == [1, 0, 1] and components[2] >= '1d':
-            # Unfortunately, Debian and Ubuntu patched the Heartbleed bug without bumping
-            # the version number or providing any other way to detect the patch status.
-            # (BAD! STOP DOING THIS!)
-
-            # Allow versions 1.0.1d through 1.0.1f if compiled with -DOPENSSL_NO_HEARTBEATS:
-            try:
-                openssl_cflags = SSL.SSLeay_version(SSL.SSLEAY_CFLAGS)
-            except Exception, e:
-                raise OpenSSLVersionError("refusing to use %s which may be vulnerable to security bugs.\n"
-                                          "Unable to check compilation flags due to %s: %s\n"
-                                          "Please upgrade to OpenSSL 1.0.1g or later."
-                                          % (openssl_version, e.__class__.__name__, e))
-            else:
-                if '-DOPENSSL_NO_HEARTBEATS' in openssl_cflags.split(' '):
-                    return
 
         if numeric_components == [1, 0, 1]:
             # Also allow versions 1.0.1 through 1.0.1f if a Heartbleed vulnerability test passes.
             # We assume that a library patched for Heartbleed is also patched for previous
             # security bugs that affected 1.0.1 through 1.0.1c.
             #
-            # We do this check only if the version and compiler flag checks are inconclusive, to
-            # minimize the chance for the test to break or give the wrong result somehow.
-            if not is_vulnerable(SSL):
-                return
+            # We do this check only if the version check above is inconclusive, to minimize the
+            # chance for the test to break or give the wrong result somehow.
+            check_resistant_to_heartbleed(SSL)
+
+    except Exception, e:
+        #import traceback
+        #traceback.print_exc()
+        pass
 
-    raise OpenSSLVersionError("refusing to use %s which may be vulnerable to security bugs.\n"
-                              "Please upgrade to OpenSSL 1.0.1g or later." % (openssl_version,))
+    raise UnsafeOpenSSLError("refusing to use %s which may be vulnerable to security bugs.\n"
+                             "Please upgrade to OpenSSL 1.0.1g or later." % (openssl_version,))
 
 
 # As simple as possible, but no simpler.
@@ -99,7 +82,7 @@ _HEARTBEAT2 = (
   '\x00\x01'             #   payload length (0 bytes)
 ) + '\x00'*33
 
-def is_vulnerable(SSL):
+def check_resistant_to_heartbleed(SSL):
     def verify_callback(connection, x509, errnum, errdepth, ok):
         return ok
 
@@ -156,6 +139,6 @@ def is_vulnerable(SSL):
 if __name__ == '__main__':
     from OpenSSL import SSL
     #check_openssl_version(SSL)
-    #print "Not vulnerable."
-    print is_vulnerable(SSL)
+    check_resistant_to_heartbleed(SSL)
+    print "Not vulnerable."