From 96024d724438102661138fe2773f4c0c31fb671f Mon Sep 17 00:00:00 2001 From: Daira Hopwood Date: Tue, 2 Jun 2015 18:07:20 +0100 Subject: [PATCH] Add OpenSSL version check and tests. refs ticket:2215 Signed-off-by: Daira Hopwood --- src/allmydata/__init__.py | 26 +++++++++++++++++++++++++- src/allmydata/_auto_deps.py | 4 +++- src/allmydata/test/test_version.py | 29 ++++++++++++++++++++++++++++- 3 files changed, 56 insertions(+), 3 deletions(-) diff --git a/src/allmydata/__init__.py b/src/allmydata/__init__.py index 44f971f8..5f6cd8c1 100644 --- a/src/allmydata/__init__.py +++ b/src/allmydata/__init__.py @@ -152,6 +152,28 @@ def normalized_version(verstr, what=None): raise PackagingError, ("could not parse %s due to %s: %s" % (what or repr(verstr), cls.__name__, value)), trace +def get_openssl_version(): + try: + from OpenSSL import SSL + return extract_openssl_version(SSL) + except Exception: + return ("unknown", None, None) + +def extract_openssl_version(ssl_module): + openssl_version = ssl_module.SSLeay_version(ssl_module.SSLEAY_VERSION) + if openssl_version.startswith('OpenSSL '): + openssl_version = openssl_version[8 :] + + (version, _, comment) = openssl_version.partition(' ') + + try: + openssl_cflags = ssl_module.SSLeay_version(ssl_module.SSLEAY_CFLAGS) + if '-DOPENSSL_NO_HEARTBEATS' in openssl_cflags.split(' '): + comment += ", no heartbeats" + except Exception: + pass + + return (version, None, comment if comment else None) def get_package_versions_and_locations(): import warnings @@ -221,6 +243,8 @@ def get_package_versions_and_locations(): packages.append( (pkgname, (platform.python_version(), sys.executable, None)) ) elif pkgname == 'platform': packages.append( (pkgname, (get_platform(), None, None)) ) + elif pkgname == 'OpenSSL': + packages.append( (pkgname, get_openssl_version()) ) return packages @@ -297,7 +321,7 @@ def cross_check(pkg_resources_vers_and_locs, imported_vers_and_locs_list): from _auto_deps import not_import_versionable, ignorable errors = [] - not_pkg_resourceable = ['python', 'platform', __appname__.lower()] + not_pkg_resourceable = ['python', 'platform', __appname__.lower(), 'openssl'] for name, (imp_ver, imp_loc, imp_comment) in imported_vers_and_locs_list: name = name.lower() diff --git a/src/allmydata/_auto_deps.py b/src/allmydata/_auto_deps.py index 69a60815..18faacc1 100644 --- a/src/allmydata/_auto_deps.py +++ b/src/allmydata/_auto_deps.py @@ -69,6 +69,7 @@ package_imports = [ ('python', None), ('platform', None), ('pyOpenSSL', 'OpenSSL'), + ('OpenSSL', None), ('simplejson', 'simplejson'), ('pycrypto', 'Crypto'), ('pyasn1', 'pyasn1'), @@ -169,7 +170,8 @@ else: # not *directly* depend on pyOpenSSL. # # * pyOpenSSL >= 0.13 is needed in order to avoid -# . +# , and also to check the +# version of OpenSSL that pyOpenSSL is using. # # * pyOpenSSL >= 0.14 is built on the 'cryptography' package which depends # on 'cffi' (and indirectly several other packages). Unfortunately cffi diff --git a/src/allmydata/test/test_version.py b/src/allmydata/test/test_version.py index fc642777..9433e365 100644 --- a/src/allmydata/test/test_version.py +++ b/src/allmydata/test/test_version.py @@ -3,12 +3,27 @@ from pkg_resources import Requirement from twisted.trial import unittest -from allmydata import check_requirement, cross_check, PackagingError +from allmydata import check_requirement, cross_check, extract_openssl_version, 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): self._check_success("setuptools >= 0.6c6", {"setuptools": ("0.6", "", None)}) @@ -118,6 +133,18 @@ class CheckRequirement(unittest.TestCase): self.failUnlessEqual(len(res), 1) self.failUnlessIn("but version '2.0'", res[0]) + def test_extract_openssl_version(self): + self.failUnlessEqual(extract_openssl_version(MockSSL("")), + ("", None, None)) + self.failUnlessEqual(extract_openssl_version(MockSSL("NotOpenSSL a.b.c foo")), + ("NotOpenSSL", None, "a.b.c foo")) + self.failUnlessEqual(extract_openssl_version(MockSSL("OpenSSL a.b.c")), + ("a.b.c", None, None)) + self.failUnlessEqual(extract_openssl_version(MockSSL("OpenSSL 1.0.1e 11 Feb 2013")), + ("1.0.1e", None, "11 Feb 2013")) + self.failUnlessEqual(extract_openssl_version(MockSSL("OpenSSL 1.0.1e 11 Feb 2013", compiled_without_heartbeats=True)), + ("1.0.1e", None, "11 Feb 2013, no heartbeats")) + # based on https://bitbucket.org/tarek/distutilsversion/src/17df9a7d96ef/test_verlib.py -- 2.45.2