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.

In this case, all hashlib.md5() invocations are to run tempest tests
so this is not a security context.  With this patch, we can run tempest
tests from a FIPS enabled machine.

Change-Id: Ib301466bb0a1996997c63599918fa96059a927bd
This commit is contained in:
Ade Lee 2021-02-25 15:45:02 -05:00
parent 35bc9bef6a
commit 56860ccae7
4 changed files with 19 additions and 18 deletions

View File

@ -13,12 +13,12 @@
# License for the specific language governing permissions and limitations
# under the License.
import hashlib
import random
import re
import time
import zlib
from oslo_utils.secretutils import md5
from tempest.api.object_storage import base
from tempest.common import custom_matchers
from tempest import config
@ -151,8 +151,8 @@ class ObjectTest(base.BaseObjectTest):
"""Test creating object with Etag"""
object_name = data_utils.rand_name(name='TestObject')
data = data_utils.random_bytes()
md5 = hashlib.md5(data).hexdigest()
metadata = {'Etag': md5}
create_md5 = md5(data, usedforsecurity=False).hexdigest()
metadata = {'Etag': create_md5}
resp, _ = self.object_client.create_object(
self.container_name,
object_name,
@ -641,7 +641,7 @@ class ObjectTest(base.BaseObjectTest):
"""Test getting object with if_match"""
object_name = data_utils.rand_name(name='TestObject')
data = data_utils.random_bytes(10)
create_md5 = hashlib.md5(data).hexdigest()
create_md5 = md5(data, usedforsecurity=False).hexdigest()
create_metadata = {'Etag': create_md5}
self.object_client.create_object(self.container_name,
object_name,
@ -681,7 +681,7 @@ class ObjectTest(base.BaseObjectTest):
"""Test getting object with if_none_match"""
object_name = data_utils.rand_name(name='TestObject')
data = data_utils.random_bytes()
create_md5 = hashlib.md5(data).hexdigest()
create_md5 = md5(data, usedforsecurity=False).hexdigest()
create_metadata = {'Etag': create_md5}
self.object_client.create_object(self.container_name,
object_name,
@ -689,7 +689,7 @@ class ObjectTest(base.BaseObjectTest):
metadata=create_metadata)
list_data = data_utils.random_bytes()
list_md5 = hashlib.md5(list_data).hexdigest()
list_md5 = md5(list_data, usedforsecurity=False).hexdigest()
list_metadata = {'If-None-Match': list_md5}
resp, body = self.object_client.get_object(
self.container_name,
@ -978,8 +978,8 @@ class ObjectTest(base.BaseObjectTest):
"""
object_name, data = self.create_object(self.container_name)
# local copy is identical, no download
md5 = hashlib.md5(data).hexdigest()
headers = {'If-None-Match': md5}
object_md5 = md5(data, usedforsecurity=False).hexdigest()
headers = {'If-None-Match': object_md5}
url = "%s/%s" % (self.container_name, object_name)
resp, _ = self.object_client.get(url, headers=headers)
self.assertEqual(resp['status'], '304')
@ -993,8 +993,8 @@ class ObjectTest(base.BaseObjectTest):
# local copy is different, download
local_data = "something different"
md5 = hashlib.md5(local_data.encode()).hexdigest()
headers = {'If-None-Match': md5}
other_md5 = md5(local_data.encode(), usedforsecurity=False).hexdigest()
headers = {'If-None-Match': other_md5}
resp, _ = self.object_client.get(url, headers=headers)
self.assertHeaders(resp, 'Object', 'GET')

View File

@ -12,10 +12,9 @@
# License for the specific language governing permissions and limitations
# under the License.
import hashlib
from oslo_serialization import jsonutils as json
from oslo_utils.secretutils import md5
from tempest.api.object_storage import base
from tempest.common import utils
from tempest.lib.common.utils import data_utils
@ -70,10 +69,12 @@ class ObjectSloTest(base.BaseObjectTest):
path_object_2 = '/%s/%s' % (self.container_name,
object_name_base_2)
data_manifest = [{'path': path_object_1,
'etag': hashlib.md5(self.content).hexdigest(),
'etag': md5(self.content,
usedforsecurity=False).hexdigest(),
'size_bytes': data_size},
{'path': path_object_2,
'etag': hashlib.md5(self.content).hexdigest(),
'etag': md5(self.content,
usedforsecurity=False).hexdigest(),
'size_bytes': data_size}]
return json.dumps(data_manifest)

View File

@ -12,11 +12,11 @@
# License for the specific language governing permissions and limitations
# under the License.
import hashlib
import os
from oslo_concurrency import lockutils
from oslo_log import log as logging
from oslo_utils.secretutils import md5
import yaml
from tempest.lib import auth
@ -134,7 +134,7 @@ class PreProvisionedCredentialProvider(cred_provider.CredentialProvider):
scope = 'domain'
elif 'system' in account:
scope = 'system'
temp_hash = hashlib.md5()
temp_hash = md5(usedforsecurity=False)
account_for_hash = dict((k, v) for (k, v) in account.items()
if k in cls.HASH_CRED_FIELDS)
temp_hash.update(str(account_for_hash).encode('utf-8'))

View File

@ -12,7 +12,6 @@
# License for the specific language governing permissions and limitations
# under the License.
import hashlib
import os
import shutil
from unittest import mock
@ -22,6 +21,7 @@ import testtools
import fixtures
from oslo_concurrency.fixture import lockutils as lockutils_fixtures
from oslo_config import cfg
from oslo_utils.secretutils import md5
from tempest import config
from tempest.lib import auth
@ -105,7 +105,7 @@ class TestPreProvisionedCredentials(base.TestCase):
hash_fields = (
preprov_creds.PreProvisionedCredentialProvider.HASH_CRED_FIELDS)
for account in accounts_list:
hash = hashlib.md5()
hash = md5(usedforsecurity=False)
account_for_hash = dict((k, v) for (k, v) in account.items()
if k in hash_fields)
hash.update(str(account_for_hash).encode('utf-8'))