From 3a174001ad1f9ee7ef61c0c18995b028d97966dc Mon Sep 17 00:00:00 2001 From: Daira Hopwood Date: Tue, 20 May 2014 17:57:53 +0100 Subject: [PATCH] Work in progress. Signed-off-by: Daira Hopwood --- src/allmydata/test/test_version.py | 66 +++++++++++---------------- src/allmydata/util/check_pyopenssl.py | 47 ++++++------------- 2 files changed, 42 insertions(+), 71 deletions(-) diff --git a/src/allmydata/test/test_version.py b/src/allmydata/test/test_version.py index 8628f281..a0968630 100644 --- a/src/allmydata/test/test_version.py +++ b/src/allmydata/test/test_version.py @@ -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 diff --git a/src/allmydata/util/check_pyopenssl.py b/src/allmydata/util/check_pyopenssl.py index ebf2e123..3a5c1a9e 100644 --- a/src/allmydata/util/check_pyopenssl.py +++ b/src/allmydata/util/check_pyopenssl.py @@ -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." -- 2.45.2