From 8027d907109b6b3c96623f9793aff752cec8ed12 Mon Sep 17 00:00:00 2001 From: Ade Lee Date: Thu, 1 Oct 2020 15:50:18 -0400 Subject: [PATCH] Replace md5 with oslo version md5 is not an approved algorithm in FIPS mode, and trying to instantiate a hashlib.md5() will fail when the system is running in FIPS mode. md5 is allowed when in a non-security context. There is a plan to add a keyword parameter (usedforsecurity) to hashlib.md5() to annotate whether or not the instance is being used in a security context. In the case where it is not, the instantiation of md5 will be allowed. See https://bugs.python.org/issue9216 for more details. Some downstream python versions already support this parameter. To support these versions, a new encapsulation of md5() has been added to oslo_utils. See https://review.opendev.org/#/c/750031/ This patch is to replace the instances of hashlib.md5() with this new encapsulation, adding an annotation indicating whether the usage is a security context or not. Reviewers need to pay particular attention as to whether the keyword parameter (usedforsecurity) is set correctly. It looks like the usage of md5() here is solely to determine a checksum of an image. With this patch and the dependent patch for glance_store, all the unit and functional tests pass on a FIPS enabled system. Depends-On: https://review.opendev.org/#/c/756157 Depends-On: https://review.opendev.org/#/c/760160 Change-Id: I3b6d78d9792d4655bf0f4989cf82aced3f27491b --- glance/image_cache/__init__.py | 5 +-- glance/tests/functional/v2/test_images.py | 49 +++++++++++++++-------- glance/tests/unit/test_image_cache.py | 4 +- lower-constraints.txt | 2 +- requirements.txt | 2 +- 5 files changed, 39 insertions(+), 23 deletions(-) diff --git a/glance/image_cache/__init__.py b/glance/image_cache/__init__.py index 51b5a2a9e2..77a11796c9 100644 --- a/glance/image_cache/__init__.py +++ b/glance/image_cache/__init__.py @@ -17,13 +17,12 @@ LRU Cache for Image Data """ -import hashlib - from oslo_config import cfg from oslo_log import log as logging from oslo_utils import encodeutils from oslo_utils import excutils from oslo_utils import importutils +from oslo_utils.secretutils import md5 from oslo_utils import units from glance.common import exception @@ -347,7 +346,7 @@ class ImageCache(object): def cache_tee_iter(self, image_id, image_iter, image_checksum): try: - current_checksum = hashlib.md5() + current_checksum = md5(usedforsecurity=False) with self.driver.open_for_write(image_id) as cache_file: for chunk in image_iter: diff --git a/glance/tests/functional/v2/test_images.py b/glance/tests/functional/v2/test_images.py index c9a6826a31..ac80420284 100644 --- a/glance/tests/functional/v2/test_images.py +++ b/glance/tests/functional/v2/test_images.py @@ -21,6 +21,7 @@ import time import uuid from oslo_serialization import jsonutils +from oslo_utils.secretutils import md5 from oslo_utils import units import requests import six @@ -206,7 +207,8 @@ class TestImages(functional.FunctionalTest): status='active', max_sec=10, delay_sec=0.2) - expect_c = six.text_type(hashlib.md5(image_data).hexdigest()) + expect_c = six.text_type(md5(image_data, + usedforsecurity=False).hexdigest()) expect_h = six.text_type(hashlib.sha512(image_data).hexdigest()) func_utils.verify_image_hashes_and_status(self, image_id, @@ -349,7 +351,8 @@ class TestImages(functional.FunctionalTest): delay_sec=0.2, start_delay_sec=1) with requests.get(image_data_uri) as r: - expect_c = six.text_type(hashlib.md5(r.content).hexdigest()) + expect_c = six.text_type(md5(r.content, + usedforsecurity=False).hexdigest()) expect_h = six.text_type(hashlib.sha512(r.content).hexdigest()) func_utils.verify_image_hashes_and_status(self, image_id, @@ -726,7 +729,8 @@ class TestImages(functional.FunctionalTest): response = requests.put(path, headers=headers, data=image_data) self.assertEqual(http.NO_CONTENT, response.status_code) - expect_c = six.text_type(hashlib.md5(image_data).hexdigest()) + expect_c = six.text_type(md5(image_data, + usedforsecurity=False).hexdigest()) expect_h = six.text_type(hashlib.sha512(image_data).hexdigest()) func_utils.verify_image_hashes_and_status(self, image_id, expect_c, expect_h, 'active') @@ -1165,7 +1169,8 @@ class TestImages(functional.FunctionalTest): image_data = b'ZZZZZ' response = requests.put(path, headers=headers, data=image_data) self.assertEqual(http.NO_CONTENT, response.status_code) - expect_c = six.text_type(hashlib.md5(image_data).hexdigest()) + expect_c = six.text_type(md5(image_data, + usedforsecurity=False).hexdigest()) expect_h = six.text_type(hashlib.sha512(image_data).hexdigest()) func_utils.verify_image_hashes_and_status(self, image_id, @@ -1178,7 +1183,8 @@ class TestImages(functional.FunctionalTest): image_data = b'WWWWW' response = requests.put(path, headers=headers, data=image_data) self.assertEqual(http.NO_CONTENT, response.status_code) - expect_c = six.text_type(hashlib.md5(image_data).hexdigest()) + expect_c = six.text_type(md5(image_data, + usedforsecurity=False).hexdigest()) expect_h = six.text_type(hashlib.sha512(image_data).hexdigest()) func_utils.verify_image_hashes_and_status(self, image2_id, @@ -4621,7 +4627,8 @@ class TestImagesMultipleBackend(functional.MultipleBackendFunctionalTest): status='active', max_sec=15, delay_sec=0.2) - expect_c = six.text_type(hashlib.md5(image_data).hexdigest()) + expect_c = six.text_type(md5(image_data, + usedforsecurity=False).hexdigest()) expect_h = six.text_type(hashlib.sha512(image_data).hexdigest()) func_utils.verify_image_hashes_and_status(self, image_id, @@ -4784,7 +4791,8 @@ class TestImagesMultipleBackend(functional.MultipleBackendFunctionalTest): status='active', max_sec=15, delay_sec=0.2) - expect_c = six.text_type(hashlib.md5(image_data).hexdigest()) + expect_c = six.text_type(md5(image_data, + usedforsecurity=False).hexdigest()) expect_h = six.text_type(hashlib.sha512(image_data).hexdigest()) func_utils.verify_image_hashes_and_status(self, image_id, @@ -4948,7 +4956,8 @@ class TestImagesMultipleBackend(functional.MultipleBackendFunctionalTest): delay_sec=0.2, start_delay_sec=1) with requests.get(image_data_uri) as r: - expect_c = six.text_type(hashlib.md5(r.content).hexdigest()) + expect_c = six.text_type(md5(r.content, + usedforsecurity=False).hexdigest()) expect_h = six.text_type(hashlib.sha512(r.content).hexdigest()) func_utils.verify_image_hashes_and_status(self, image_id, @@ -5111,7 +5120,8 @@ class TestImagesMultipleBackend(functional.MultipleBackendFunctionalTest): delay_sec=0.2, start_delay_sec=1) with requests.get(image_data_uri) as r: - expect_c = six.text_type(hashlib.md5(r.content).hexdigest()) + expect_c = six.text_type(md5(r.content, + usedforsecurity=False).hexdigest()) expect_h = six.text_type(hashlib.sha512(r.content).hexdigest()) func_utils.verify_image_hashes_and_status(self, image_id, @@ -5273,7 +5283,8 @@ class TestImagesMultipleBackend(functional.MultipleBackendFunctionalTest): delay_sec=0.2, start_delay_sec=1) with requests.get(image_data_uri) as r: - expect_c = six.text_type(hashlib.md5(r.content).hexdigest()) + expect_c = six.text_type(md5(r.content, + usedforsecurity=False).hexdigest()) expect_h = six.text_type(hashlib.sha512(r.content).hexdigest()) func_utils.verify_image_hashes_and_status(self, image_id, @@ -5435,7 +5446,8 @@ class TestImagesMultipleBackend(functional.MultipleBackendFunctionalTest): delay_sec=0.2, start_delay_sec=1) with requests.get(image_data_uri) as r: - expect_c = six.text_type(hashlib.md5(r.content).hexdigest()) + expect_c = six.text_type(md5(r.content, + usedforsecurity=False).hexdigest()) expect_h = six.text_type(hashlib.sha512(r.content).hexdigest()) func_utils.verify_image_hashes_and_status(self, image_id, @@ -5630,7 +5642,8 @@ class TestImagesMultipleBackend(functional.MultipleBackendFunctionalTest): delay_sec=0.2, start_delay_sec=1) with requests.get(image_data_uri) as r: - expect_c = six.text_type(hashlib.md5(r.content).hexdigest()) + expect_c = six.text_type(md5(r.content, + usedforsecurity=False).hexdigest()) expect_h = six.text_type(hashlib.sha512(r.content).hexdigest()) func_utils.verify_image_hashes_and_status(self, image_id, @@ -5888,7 +5901,8 @@ class TestImagesMultipleBackend(functional.MultipleBackendFunctionalTest): delay_sec=0.2, start_delay_sec=1) with requests.get(image_data_uri) as r: - expect_c = six.text_type(hashlib.md5(r.content).hexdigest()) + expect_c = six.text_type(md5(r.content, + usedforsecurity=False).hexdigest()) expect_h = six.text_type(hashlib.sha512(r.content).hexdigest()) func_utils.verify_image_hashes_and_status(self, image_id, @@ -6029,7 +6043,8 @@ class TestImagesMultipleBackend(functional.MultipleBackendFunctionalTest): response = requests.put(path, headers=headers, data=image_data) self.assertEqual(http.NO_CONTENT, response.status_code) - expect_c = six.text_type(hashlib.md5(image_data).hexdigest()) + expect_c = six.text_type(md5(image_data, + usedforsecurity=False).hexdigest()) expect_h = six.text_type(hashlib.sha512(image_data).hexdigest()) func_utils.verify_image_hashes_and_status(self, image_id, @@ -6202,7 +6217,8 @@ class TestImagesMultipleBackend(functional.MultipleBackendFunctionalTest): response = requests.put(path, headers=headers, data=image_data) self.assertEqual(http.NO_CONTENT, response.status_code) - expect_c = six.text_type(hashlib.md5(image_data).hexdigest()) + expect_c = six.text_type(md5(image_data, + usedforsecurity=False).hexdigest()) expect_h = six.text_type(hashlib.sha512(image_data).hexdigest()) func_utils.verify_image_hashes_and_status(self, image_id, @@ -6738,7 +6754,8 @@ class TestCopyImagePermissions(functional.MultipleBackendFunctionalTest): delay_sec=0.2, start_delay_sec=1) with requests.get(image_data_uri) as r: - expect_c = six.text_type(hashlib.md5(r.content).hexdigest()) + expect_c = six.text_type(md5(r.content, + usedforsecurity=False).hexdigest()) expect_h = six.text_type(hashlib.sha512(r.content).hexdigest()) func_utils.verify_image_hashes_and_status(self, image_id, diff --git a/glance/tests/unit/test_image_cache.py b/glance/tests/unit/test_image_cache.py index bfdef3d684..92fc3000a6 100644 --- a/glance/tests/unit/test_image_cache.py +++ b/glance/tests/unit/test_image_cache.py @@ -15,11 +15,11 @@ from contextlib import contextmanager import datetime -import hashlib import os import time import fixtures +from oslo_utils import secretutils from oslo_utils import units import six # NOTE(jokke): simplified transition to py3, behaves like py2 xrange @@ -409,7 +409,7 @@ class ImageCacheTestCase(object): image = b"12345678990abcdefghijklmnop" image_id = 123 - md5 = hashlib.md5() + md5 = secretutils.md5(usedforsecurity=False) md5.update(image) checksum = md5.hexdigest() diff --git a/lower-constraints.txt b/lower-constraints.txt index 48086a67e2..d64543d4c8 100644 --- a/lower-constraints.txt +++ b/lower-constraints.txt @@ -69,7 +69,7 @@ oslo.reports==1.18.0 oslo.serialization==2.25.0 oslo.service==1.41.1 oslo.upgradecheck==0.1.0 -oslo.utils==3.40.2 +oslo.utils==4.7.0 oslotest==3.2.0 osprofiler==1.4.0 Paste==2.0.2 diff --git a/requirements.txt b/requirements.txt index 6f5bf1412b..d45d134236 100644 --- a/requirements.txt +++ b/requirements.txt @@ -19,7 +19,7 @@ oslo.config>=5.2.0 # Apache-2.0 oslo.concurrency>=3.26.0 # Apache-2.0 oslo.context>=2.22.0 # Apache-2.0 oslo.upgradecheck>=0.1.0 # Apache-2.0 -oslo.utils>=3.40.2 # Apache-2.0 +oslo.utils>=4.7.0 # Apache-2.0 stevedore!=3.0.0,>=1.20.0 # Apache-2.0 futurist>=1.2.0 # Apache-2.0 taskflow>=4.0.0 # Apache-2.0