except (ImportError, PackagingError), e:
errors.append("%s: %s" % (e.__class__.__name__, e))
+ try:
+ from OpenSSL import SSL
+ check_openssl_version(SSL)
+ except PackagingError, e:
+ errors.append("%s: %s" % (e.__class__.__name__, e))
+ except Exception, e:
+ errors.append("Unable to check OpenSSL version due to %s: %s" % (e.__class__.__name__, e))
+
if errors:
raise PackagingError(get_error_string(errors, debug=True))
+MONTHS = {'Jan': 1, 'Feb':2, 'Mar':3, 'Apr':4, 'May':5, 'Jun':6, 'Jul':7, 'Aug':8, 'Sep':9, 'Oct':10, 'Nov':11, 'Dec':12}
+
+def parse_build_date(build_date):
+ day = int(build_date[0])
+ month = MONTHS[build_date[1]]
+ year = int(build_date[2])
+ return (year, month, day)
+
+def check_openssl_version(SSL):
+ openssl_version = SSL.SSLeay_version(SSL.SSLEAY_VERSION)
+ split_version = openssl_version.split(' ')
+
+ if len(split_version) < 2 or split_version[0] != 'OpenSSL':
+ raise PackagingError("could not understand OpenSSL version string %s" % (openssl_version,))
+
+ try:
+ components = split_version[1].split('.')
+ numeric_components = map(int, components[:2])
+ if len(components) > 2:
+ m = re.match(r'[0-9]*', components[2])
+ numeric_components += [int(m.group(0))]
+
+ if ((numeric_components == [0, 9, 8] and components[2] >= '8y') or
+ (numeric_components == [1, 0, 0] and components[2] >= '0l') or
+ (numeric_components == [1, 0, 1] and components[2] >= '1g') or
+ (numeric_components >= [1, 0, 2])):
+ return
+
+ 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!) So we allow versions 1.0.1d through 1.0.1f provided
+ # they were compiled on or after 6 April 2014.
+ if len(split_version) >= 5 and parse_build_date(split_version[2:5]) >= (2014, 4, 6):
+ return
+
+ # We also allow those versions if compiled with -DOPENSSL_NO_HEARTBEATS.
+ try:
+ openssl_cflags = SSL.SSLeay_version(SSL.SSLEAY_CFLAGS)
+ except Exception, e:
+ raise PackagingError("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
+ except Exception, e:
+ pass
+
+ raise PackagingError("refusing to use %s which may be vulnerable to security bugs.\n"
+ "Please upgrade to OpenSSL 1.0.1g or later." % (openssl_version,))
+
+
check_all_requirements()
from twisted.trial import unittest
-from allmydata import check_requirement, cross_check, PackagingError
+from allmydata import check_requirement, cross_check, check_openssl_version, parse_build_date, PackagingError
from allmydata.util.verlib import NormalizedVersion as V, \
IrrationalVersionError, \
suggest_normalized_version as suggest
+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 SSLeay_version(self, which):
+ return self.opts[which]
+
+
class CheckRequirement(unittest.TestCase):
def test_check_requirement(self):
check_requirement("setuptools >= 0.6c6", {"setuptools": ("0.6", "", None)})
self.failUnlessEqual(len(res), 1)
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.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 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"))
+
+ check_openssl_version(MockSSL("OpenSSL 0.9.8y"))
+ check_openssl_version(MockSSL("OpenSSL 0.9.8z"))
+ check_openssl_version(MockSSL("OpenSSL 1.0.0l"))
+ check_openssl_version(MockSSL("OpenSSL 1.0.0m"))
+ check_openssl_version(MockSSL("OpenSSL 1.0.1", True))
+ check_openssl_version(MockSSL("OpenSSL 1.0.1e 11 Feb 2013", True))
+ check_openssl_version(MockSSL("OpenSSL 1.0.1 7 Apr 2014"))
+ check_openssl_version(MockSSL("OpenSSL 1.0.1e 7 Apr 2014"))
+ check_openssl_version(MockSSL("OpenSSL 1.0.1g 1 Mar 2014"))
+ check_openssl_version(MockSSL("OpenSSL 1.0.1h 1 Jan 2015"))
+ check_openssl_version(MockSSL("OpenSSL 1.0.1zzz"))
+ check_openssl_version(MockSSL("OpenSSL 1.0.2"))
+ check_openssl_version(MockSSL("OpenSSL 1.0.2a"))
+ check_openssl_version(MockSSL("OpenSSL 1.0.10a"))
+ check_openssl_version(MockSSL("OpenSSL 1.1"))
+ check_openssl_version(MockSSL("OpenSSL 1.1.0"))
+ check_openssl_version(MockSSL("OpenSSL 1.1.0a"))
+ check_openssl_version(MockSSL("OpenSSL 1.10"))
+ check_openssl_version(MockSSL("OpenSSL 1.10.10a"))
+ check_openssl_version(MockSSL("OpenSSL 2"))
+ 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