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
This commit is contained in:
Ade Lee 2020-10-01 15:50:18 -04:00
parent c0e54c0aa0
commit 8027d90710
5 changed files with 39 additions and 23 deletions

View File

@ -17,13 +17,12 @@
LRU Cache for Image Data LRU Cache for Image Data
""" """
import hashlib
from oslo_config import cfg from oslo_config import cfg
from oslo_log import log as logging from oslo_log import log as logging
from oslo_utils import encodeutils from oslo_utils import encodeutils
from oslo_utils import excutils from oslo_utils import excutils
from oslo_utils import importutils from oslo_utils import importutils
from oslo_utils.secretutils import md5
from oslo_utils import units from oslo_utils import units
from glance.common import exception from glance.common import exception
@ -347,7 +346,7 @@ class ImageCache(object):
def cache_tee_iter(self, image_id, image_iter, image_checksum): def cache_tee_iter(self, image_id, image_iter, image_checksum):
try: try:
current_checksum = hashlib.md5() current_checksum = md5(usedforsecurity=False)
with self.driver.open_for_write(image_id) as cache_file: with self.driver.open_for_write(image_id) as cache_file:
for chunk in image_iter: for chunk in image_iter:

View File

@ -21,6 +21,7 @@ import time
import uuid import uuid
from oslo_serialization import jsonutils from oslo_serialization import jsonutils
from oslo_utils.secretutils import md5
from oslo_utils import units from oslo_utils import units
import requests import requests
import six import six
@ -206,7 +207,8 @@ class TestImages(functional.FunctionalTest):
status='active', status='active',
max_sec=10, max_sec=10,
delay_sec=0.2) 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()) expect_h = six.text_type(hashlib.sha512(image_data).hexdigest())
func_utils.verify_image_hashes_and_status(self, func_utils.verify_image_hashes_and_status(self,
image_id, image_id,
@ -349,7 +351,8 @@ class TestImages(functional.FunctionalTest):
delay_sec=0.2, delay_sec=0.2,
start_delay_sec=1) start_delay_sec=1)
with requests.get(image_data_uri) as r: 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()) expect_h = six.text_type(hashlib.sha512(r.content).hexdigest())
func_utils.verify_image_hashes_and_status(self, func_utils.verify_image_hashes_and_status(self,
image_id, image_id,
@ -726,7 +729,8 @@ class TestImages(functional.FunctionalTest):
response = requests.put(path, headers=headers, data=image_data) response = requests.put(path, headers=headers, data=image_data)
self.assertEqual(http.NO_CONTENT, response.status_code) 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()) expect_h = six.text_type(hashlib.sha512(image_data).hexdigest())
func_utils.verify_image_hashes_and_status(self, image_id, expect_c, func_utils.verify_image_hashes_and_status(self, image_id, expect_c,
expect_h, 'active') expect_h, 'active')
@ -1165,7 +1169,8 @@ class TestImages(functional.FunctionalTest):
image_data = b'ZZZZZ' image_data = b'ZZZZZ'
response = requests.put(path, headers=headers, data=image_data) response = requests.put(path, headers=headers, data=image_data)
self.assertEqual(http.NO_CONTENT, response.status_code) 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()) expect_h = six.text_type(hashlib.sha512(image_data).hexdigest())
func_utils.verify_image_hashes_and_status(self, func_utils.verify_image_hashes_and_status(self,
image_id, image_id,
@ -1178,7 +1183,8 @@ class TestImages(functional.FunctionalTest):
image_data = b'WWWWW' image_data = b'WWWWW'
response = requests.put(path, headers=headers, data=image_data) response = requests.put(path, headers=headers, data=image_data)
self.assertEqual(http.NO_CONTENT, response.status_code) 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()) expect_h = six.text_type(hashlib.sha512(image_data).hexdigest())
func_utils.verify_image_hashes_and_status(self, func_utils.verify_image_hashes_and_status(self,
image2_id, image2_id,
@ -4621,7 +4627,8 @@ class TestImagesMultipleBackend(functional.MultipleBackendFunctionalTest):
status='active', status='active',
max_sec=15, max_sec=15,
delay_sec=0.2) 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()) expect_h = six.text_type(hashlib.sha512(image_data).hexdigest())
func_utils.verify_image_hashes_and_status(self, func_utils.verify_image_hashes_and_status(self,
image_id, image_id,
@ -4784,7 +4791,8 @@ class TestImagesMultipleBackend(functional.MultipleBackendFunctionalTest):
status='active', status='active',
max_sec=15, max_sec=15,
delay_sec=0.2) 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()) expect_h = six.text_type(hashlib.sha512(image_data).hexdigest())
func_utils.verify_image_hashes_and_status(self, func_utils.verify_image_hashes_and_status(self,
image_id, image_id,
@ -4948,7 +4956,8 @@ class TestImagesMultipleBackend(functional.MultipleBackendFunctionalTest):
delay_sec=0.2, delay_sec=0.2,
start_delay_sec=1) start_delay_sec=1)
with requests.get(image_data_uri) as r: 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()) expect_h = six.text_type(hashlib.sha512(r.content).hexdigest())
func_utils.verify_image_hashes_and_status(self, func_utils.verify_image_hashes_and_status(self,
image_id, image_id,
@ -5111,7 +5120,8 @@ class TestImagesMultipleBackend(functional.MultipleBackendFunctionalTest):
delay_sec=0.2, delay_sec=0.2,
start_delay_sec=1) start_delay_sec=1)
with requests.get(image_data_uri) as r: 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()) expect_h = six.text_type(hashlib.sha512(r.content).hexdigest())
func_utils.verify_image_hashes_and_status(self, func_utils.verify_image_hashes_and_status(self,
image_id, image_id,
@ -5273,7 +5283,8 @@ class TestImagesMultipleBackend(functional.MultipleBackendFunctionalTest):
delay_sec=0.2, delay_sec=0.2,
start_delay_sec=1) start_delay_sec=1)
with requests.get(image_data_uri) as r: 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()) expect_h = six.text_type(hashlib.sha512(r.content).hexdigest())
func_utils.verify_image_hashes_and_status(self, func_utils.verify_image_hashes_and_status(self,
image_id, image_id,
@ -5435,7 +5446,8 @@ class TestImagesMultipleBackend(functional.MultipleBackendFunctionalTest):
delay_sec=0.2, delay_sec=0.2,
start_delay_sec=1) start_delay_sec=1)
with requests.get(image_data_uri) as r: 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()) expect_h = six.text_type(hashlib.sha512(r.content).hexdigest())
func_utils.verify_image_hashes_and_status(self, func_utils.verify_image_hashes_and_status(self,
image_id, image_id,
@ -5630,7 +5642,8 @@ class TestImagesMultipleBackend(functional.MultipleBackendFunctionalTest):
delay_sec=0.2, delay_sec=0.2,
start_delay_sec=1) start_delay_sec=1)
with requests.get(image_data_uri) as r: 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()) expect_h = six.text_type(hashlib.sha512(r.content).hexdigest())
func_utils.verify_image_hashes_and_status(self, func_utils.verify_image_hashes_and_status(self,
image_id, image_id,
@ -5888,7 +5901,8 @@ class TestImagesMultipleBackend(functional.MultipleBackendFunctionalTest):
delay_sec=0.2, delay_sec=0.2,
start_delay_sec=1) start_delay_sec=1)
with requests.get(image_data_uri) as r: 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()) expect_h = six.text_type(hashlib.sha512(r.content).hexdigest())
func_utils.verify_image_hashes_and_status(self, func_utils.verify_image_hashes_and_status(self,
image_id, image_id,
@ -6029,7 +6043,8 @@ class TestImagesMultipleBackend(functional.MultipleBackendFunctionalTest):
response = requests.put(path, headers=headers, data=image_data) response = requests.put(path, headers=headers, data=image_data)
self.assertEqual(http.NO_CONTENT, response.status_code) 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()) expect_h = six.text_type(hashlib.sha512(image_data).hexdigest())
func_utils.verify_image_hashes_and_status(self, func_utils.verify_image_hashes_and_status(self,
image_id, image_id,
@ -6202,7 +6217,8 @@ class TestImagesMultipleBackend(functional.MultipleBackendFunctionalTest):
response = requests.put(path, headers=headers, data=image_data) response = requests.put(path, headers=headers, data=image_data)
self.assertEqual(http.NO_CONTENT, response.status_code) 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()) expect_h = six.text_type(hashlib.sha512(image_data).hexdigest())
func_utils.verify_image_hashes_and_status(self, func_utils.verify_image_hashes_and_status(self,
image_id, image_id,
@ -6738,7 +6754,8 @@ class TestCopyImagePermissions(functional.MultipleBackendFunctionalTest):
delay_sec=0.2, delay_sec=0.2,
start_delay_sec=1) start_delay_sec=1)
with requests.get(image_data_uri) as r: 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()) expect_h = six.text_type(hashlib.sha512(r.content).hexdigest())
func_utils.verify_image_hashes_and_status(self, func_utils.verify_image_hashes_and_status(self,
image_id, image_id,

View File

@ -15,11 +15,11 @@
from contextlib import contextmanager from contextlib import contextmanager
import datetime import datetime
import hashlib
import os import os
import time import time
import fixtures import fixtures
from oslo_utils import secretutils
from oslo_utils import units from oslo_utils import units
import six import six
# NOTE(jokke): simplified transition to py3, behaves like py2 xrange # NOTE(jokke): simplified transition to py3, behaves like py2 xrange
@ -409,7 +409,7 @@ class ImageCacheTestCase(object):
image = b"12345678990abcdefghijklmnop" image = b"12345678990abcdefghijklmnop"
image_id = 123 image_id = 123
md5 = hashlib.md5() md5 = secretutils.md5(usedforsecurity=False)
md5.update(image) md5.update(image)
checksum = md5.hexdigest() checksum = md5.hexdigest()

View File

@ -69,7 +69,7 @@ oslo.reports==1.18.0
oslo.serialization==2.25.0 oslo.serialization==2.25.0
oslo.service==1.41.1 oslo.service==1.41.1
oslo.upgradecheck==0.1.0 oslo.upgradecheck==0.1.0
oslo.utils==3.40.2 oslo.utils==4.7.0
oslotest==3.2.0 oslotest==3.2.0
osprofiler==1.4.0 osprofiler==1.4.0
Paste==2.0.2 Paste==2.0.2

View File

@ -19,7 +19,7 @@ oslo.config>=5.2.0 # Apache-2.0
oslo.concurrency>=3.26.0 # Apache-2.0 oslo.concurrency>=3.26.0 # Apache-2.0
oslo.context>=2.22.0 # Apache-2.0 oslo.context>=2.22.0 # Apache-2.0
oslo.upgradecheck>=0.1.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 stevedore!=3.0.0,>=1.20.0 # Apache-2.0
futurist>=1.2.0 # Apache-2.0 futurist>=1.2.0 # Apache-2.0
taskflow>=4.0.0 # Apache-2.0 taskflow>=4.0.0 # Apache-2.0