summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAde Lee <alee@redhat.com>2020-09-04 15:55:31 -0400
committerAde Lee <alee@redhat.com>2020-09-16 16:47:07 -0400
commit603fa500c1a24ad8753b680b8d75468abbd3dd76 (patch)
tree237ca464a7f5946843ca69fbbee1f763db0268a1
parent7c4a94c0c3fcbd8f05541944851728f30deadd9b (diff)
downloadoslo-utils-603fa500c1a24ad8753b680b8d75468abbd3dd76.tar.gz
Add function to encapsule md5 for FIPS systems
For systems in FIPS mode, invocations of MD5 will fail. This occurs even in cases where the MD5 is used in a non-cryptographical context eg. for an etag in swift. There is a proposal in Python to allow developers to mark these non-crypto cases as valid through a new usedforsecurity keyword. See https://bugs.python.org/issue9216. Some downstream versions of python already implement this keyword. To permit OpenStack to run in FIPS enabled systems with these versions of python, we add a simple encapsulation of hashlib.md5() here. Once the issue is resolved in upstream python, we can remove this function. Change-Id: I09433fea6ad6e6849677a93b269e24dec5c05b69
-rw-r--r--oslo_utils/secretutils.py21
-rw-r--r--oslo_utils/tests/test_secretutils.py47
-rw-r--r--releasenotes/notes/add-md5-wrapper-7bf81c2464a7a224.yaml16
3 files changed, 84 insertions, 0 deletions
diff --git a/oslo_utils/secretutils.py b/oslo_utils/secretutils.py
index ad350d2..f6a465c 100644
--- a/oslo_utils/secretutils.py
+++ b/oslo_utils/secretutils.py
@@ -18,6 +18,7 @@ Secret utilities.
.. versionadded:: 3.5
"""
+import hashlib
import hmac
@@ -44,3 +45,23 @@ try:
constant_time_compare = hmac.compare_digest
except AttributeError:
constant_time_compare = _constant_time_compare
+
+try:
+ _ = hashlib.md5(usedforsecurity=False) # nosec
+
+ def md5(string=b'', usedforsecurity=True):
+ """Return an md5 hashlib object using usedforsecurity parameter
+
+ For python distributions that support the usedforsecurity keyword
+ parameter, this passes the parameter through as expected.
+ See https://bugs.python.org/issue9216
+ """
+ return hashlib.md5(string, usedforsecurity=usedforsecurity) # nosec
+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
diff --git a/oslo_utils/tests/test_secretutils.py b/oslo_utils/tests/test_secretutils.py
index 87f6218..60625c9 100644
--- a/oslo_utils/tests/test_secretutils.py
+++ b/oslo_utils/tests/test_secretutils.py
@@ -61,3 +61,50 @@ class SecretUtilsTest(testscenarios.TestWithScenarios,
self.assertFalse(ctc(self.converter(u'abcd1234'),
self.converter(u'1234abcd')))
self.assertFalse(ctc('abcd1234', '1234abcd'))
+
+ _test_data = "Openstack forever".encode('utf-8')
+ _md5_digest = hashlib.md5(_test_data).digest()
+
+ def test_md5_with_data(self):
+ digest = secretutils.md5(self._test_data).digest()
+ self.assertEqual(digest, self._md5_digest)
+
+ digest = secretutils.md5(self._test_data,
+ usedforsecurity=True).digest()
+ self.assertEqual(digest, self._md5_digest)
+
+ digest = secretutils.md5(self._test_data,
+ usedforsecurity=False).digest()
+ self.assertEqual(digest, self._md5_digest)
+
+ def test_md5_without_data(self):
+ md5 = secretutils.md5()
+ md5.update(self._test_data)
+ digest = md5.digest()
+ self.assertEqual(digest, self._md5_digest)
+
+ md5 = secretutils.md5(usedforsecurity=True)
+ md5.update(self._test_data)
+ digest = md5.digest()
+ self.assertEqual(digest, self._md5_digest)
+
+ md5 = secretutils.md5(usedforsecurity=False)
+ md5.update(self._test_data)
+ digest = md5.digest()
+ self.assertEqual(digest, self._md5_digest)
+
+ def test_string_data_raises_type_error(self):
+ self.assertRaises(TypeError, hashlib.md5, 'foo')
+ self.assertRaises(TypeError, secretutils.md5, 'foo')
+ self.assertRaises(
+ TypeError, secretutils.md5, 'foo', usedforsecurity=True)
+ self.assertRaises(
+ TypeError, secretutils.md5, 'foo', usedforsecurity=False)
+
+ def test_none_data_raises_type_error(self):
+ self.assertRaises(TypeError, hashlib.md5, None)
+ self.assertRaises(TypeError, secretutils.md5, None)
+ self.assertRaises(
+ TypeError, secretutils.md5, None, usedforsecurity=True)
+ self.assertRaises(
+ TypeError, secretutils.md5, None, usedforsecurity=False)
diff --git a/releasenotes/notes/add-md5-wrapper-7bf81c2464a7a224.yaml b/releasenotes/notes/add-md5-wrapper-7bf81c2464a7a224.yaml
new file mode 100644
index 0000000..b28b120
--- /dev/null
+++ b/releasenotes/notes/add-md5-wrapper-7bf81c2464a7a224.yaml
@@ -0,0 +1,16 @@
+---
+features:
+ - |
+ A wrapper for hashlib.md5() has been added to allow OpenStack to run on
+ systems where FIPS is enabled. Under FIPS, md5 is disabled and calls to
+ hashlib.md5() will fail. In most cases in OpenStack, though, md5 is not
+ used within a security context.
+
+ In https://bugs.python.org/issue9216, a proposal has been made to allow
+ the addition of a keyword parameter usedforsecurity, which can be used to
+ designate non-security context uses. In this case, md5() operations would
+ be permitted. This feature is expected to be delivered in python 3.9.
+
+ Downstream python already supports this option, though. This wrapper
+ simply allows for this option to be supported where the underlying python
+ version supports it.