Merge "encapsulate md5 calls for fips"

This commit is contained in:
Zuul
2021-02-15 22:21:00 +00:00
committed by Gerrit Code Review
6 changed files with 112 additions and 7 deletions

View File

@@ -28,6 +28,7 @@ from openstack.cloud import _normalize
from openstack.cloud import _utils from openstack.cloud import _utils
from openstack import exceptions from openstack import exceptions
from openstack import proxy from openstack import proxy
from openstack import utils
DEFAULT_OBJECT_SEGMENT_SIZE = 1073741824 # 1GB DEFAULT_OBJECT_SEGMENT_SIZE = 1073741824 # 1GB
@@ -218,7 +219,7 @@ class ObjectStoreCloudMixin(_normalize.Normalizer):
self._file_hash_cache[file_key]['sha256']) self._file_hash_cache[file_key]['sha256'])
def _calculate_data_hashes(self, data): def _calculate_data_hashes(self, data):
md5 = hashlib.md5() md5 = utils.md5(usedforsecurity=False)
sha256 = hashlib.sha256() sha256 = hashlib.sha256()
if hasattr(data, 'read'): if hasattr(data, 'read'):

View File

@@ -10,7 +10,6 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
import io import io
import hashlib
from openstack import exceptions from openstack import exceptions
from openstack import utils from openstack import utils
@@ -45,7 +44,7 @@ class DownloadMixin:
details = self.fetch(session) details = self.fetch(session)
checksum = details.checksum checksum = details.checksum
md5 = hashlib.md5() md5 = utils.md5(usedforsecurity=False)
if output: if output:
try: try:
if isinstance(output, io.IOBase): if isinstance(output, io.IOBase):
@@ -73,7 +72,8 @@ class DownloadMixin:
return resp return resp
if checksum is not None: if checksum is not None:
_verify_checksum(hashlib.md5(resp.content), checksum) _verify_checksum(utils.md5(resp.content, usedforsecurity=False),
checksum)
else: else:
session.log.warning( session.log.warning(
"Unable to verify the integrity of image %s", (self.id)) "Unable to verify the integrity of image %s", (self.id))

View File

@@ -24,6 +24,7 @@ import uuid
from openstack.orchestration.util import template_format from openstack.orchestration.util import template_format
from openstack.cloud import meta from openstack.cloud import meta
from openstack import utils
PROJECT_ID = '1c36b64c840a42cd9e9b931a369337f0' PROJECT_ID = '1c36b64c840a42cd9e9b931a369337f0'
FLAVOR_ID = u'0c1d9008-f546-4608-9e8f-f8bdaec8dddd' FLAVOR_ID = u'0c1d9008-f546-4608-9e8f-f8bdaec8dddd'
@@ -225,7 +226,7 @@ def make_fake_image(
data=None, data=None,
checksum=u'ee36e35a297980dee1b514de9803ec6d'): checksum=u'ee36e35a297980dee1b514de9803ec6d'):
if data: if data:
md5 = hashlib.md5() md5 = utils.md5(usedforsecurity=False)
sha256 = hashlib.sha256() sha256 = hashlib.sha256()
with open(data, 'rb') as file_obj: with open(data, 'rb') as file_obj:
for chunk in iter(lambda: file_obj.read(8192), b''): for chunk in iter(lambda: file_obj.read(8192), b''):

View File

@@ -9,7 +9,6 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
import hashlib
import io import io
import operator import operator
import tempfile import tempfile
@@ -22,6 +21,7 @@ from openstack import _log
from openstack import exceptions from openstack import exceptions
from openstack.image.v2 import image from openstack.image.v2 import image
from openstack.tests.unit import base from openstack.tests.unit import base
from openstack import utils
IDENTIFIER = 'IDENTIFIER' IDENTIFIER = 'IDENTIFIER'
EXAMPLE = { EXAMPLE = {
@@ -89,7 +89,7 @@ EXAMPLE = {
def calculate_md5_checksum(data): def calculate_md5_checksum(data):
checksum = hashlib.md5() checksum = utils.md5(usedforsecurity=False)
for chunk in data: for chunk in data:
checksum.update(chunk) checksum.update(chunk)
return checksum.hexdigest() return checksum.hexdigest()

View File

@@ -13,8 +13,10 @@
# under the License. # under the License.
import concurrent.futures import concurrent.futures
import hashlib
import logging import logging
from unittest import mock from unittest import mock
from unittest import skipIf
import sys import sys
import fixtures import fixtures
@@ -302,3 +304,87 @@ class TestTinyDAG(base.TestCase):
def test_walker_fn(graph, node, lst): def test_walker_fn(graph, node, lst):
lst.append(node) lst.append(node)
graph.node_done(node) graph.node_done(node)
class Test_md5(base.TestCase):
def setUp(self):
super(Test_md5, self).setUp()
self.md5_test_data = "Openstack forever".encode('utf-8')
try:
self.md5_digest = hashlib.md5( # nosec
self.md5_test_data).hexdigest()
self.fips_enabled = False
except ValueError:
self.md5_digest = '0d6dc3c588ae71a04ce9a6beebbbba06'
self.fips_enabled = True
def test_md5_with_data(self):
if not self.fips_enabled:
digest = utils.md5(self.md5_test_data).hexdigest()
self.assertEqual(digest, self.md5_digest)
else:
# on a FIPS enabled system, this throws a ValueError:
# [digital envelope routines: EVP_DigestInit_ex] disabled for FIPS
self.assertRaises(ValueError, utils.md5, self.md5_test_data)
if not self.fips_enabled:
digest = utils.md5(self.md5_test_data,
usedforsecurity=True).hexdigest()
self.assertEqual(digest, self.md5_digest)
else:
self.assertRaises(
ValueError, utils.md5, self.md5_test_data,
usedforsecurity=True)
digest = utils.md5(self.md5_test_data,
usedforsecurity=False).hexdigest()
self.assertEqual(digest, self.md5_digest)
def test_md5_without_data(self):
if not self.fips_enabled:
test_md5 = utils.md5()
test_md5.update(self.md5_test_data)
digest = test_md5.hexdigest()
self.assertEqual(digest, self.md5_digest)
else:
self.assertRaises(ValueError, utils.md5)
if not self.fips_enabled:
test_md5 = utils.md5(usedforsecurity=True)
test_md5.update(self.md5_test_data)
digest = test_md5.hexdigest()
self.assertEqual(digest, self.md5_digest)
else:
self.assertRaises(ValueError, utils.md5, usedforsecurity=True)
test_md5 = utils.md5(usedforsecurity=False)
test_md5.update(self.md5_test_data)
digest = test_md5.hexdigest()
self.assertEqual(digest, self.md5_digest)
@skipIf(sys.version_info.major == 2,
"hashlib.md5 does not raise TypeError here in py2")
def test_string_data_raises_type_error(self):
if not self.fips_enabled:
self.assertRaises(TypeError, hashlib.md5, u'foo')
self.assertRaises(TypeError, utils.md5, u'foo')
self.assertRaises(
TypeError, utils.md5, u'foo', usedforsecurity=True)
else:
self.assertRaises(ValueError, hashlib.md5, u'foo')
self.assertRaises(ValueError, utils.md5, u'foo')
self.assertRaises(
ValueError, utils.md5, u'foo', usedforsecurity=True)
self.assertRaises(
TypeError, utils.md5, u'foo', usedforsecurity=False)
def test_none_data_raises_type_error(self):
if not self.fips_enabled:
self.assertRaises(TypeError, hashlib.md5, None)
self.assertRaises(TypeError, utils.md5, None)
self.assertRaises(
TypeError, utils.md5, None, usedforsecurity=True)
else:
self.assertRaises(ValueError, hashlib.md5, None)
self.assertRaises(ValueError, utils.md5, None)
self.assertRaises(
ValueError, utils.md5, None, usedforsecurity=True)
self.assertRaises(
TypeError, utils.md5, None, usedforsecurity=False)

View File

@@ -10,6 +10,7 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
import hashlib
import queue import queue
import string import string
import threading import threading
@@ -232,6 +233,22 @@ def maximum_supported_microversion(adapter, client_maximum):
return discover.version_to_string(result) return discover.version_to_string(result)
try:
_test_md5 = hashlib.md5(usedforsecurity=False) # nosec
# Python distributions that support a hashlib.md5 with the usedforsecurity
# keyword can just use that md5 definition as-is
# See https://bugs.python.org/issue9216
md5 = hashlib.md5
except TypeError:
def md5(string=b'', usedforsecurity=True):
"""Return an md5 hashlib object without usedforsecurity parameter
For python distributions that do not yet support this keyword
parameter, we drop the parameter
"""
return hashlib.md5(string) # nosec
class TinyDAG: class TinyDAG:
"""Tiny DAG """Tiny DAG