In OpenStack Swift we're using some code similar to this to create a HMAC with a configurable algorithm: import hashlib import hmac import functools key = "mykey".encode('utf8') msg = b"hello world" digestmod = functools.partial(hashlib.new, "sha1") print(hmac.new(key, msg, digestmod).hexdigest()) This works fine on Python 2.7 & 3.6+ with and without FIPS on RHEL7+8. However, on RHEL9+FIPS enabled this fails with an error like this (works without FIPS)[1]: Traceback (most recent call last): File "/root/testhmac.py", line 23, in <module> print(hmac.new(key, msg, digestmod).hexdigest()) File "/usr/lib64/python3.9/hmac.py", line 190, in new return HMAC(key, msg, digestmod) File "/usr/lib64/python3.9/hmac.py", line 60, in __init__ self._init_hmac(key, msg, digestmod) File "/usr/lib64/python3.9/hmac.py", line 70, in _init_hmac self._hmac = _hashopenssl.hmac_new(key, msg, digestmod=digestmod) _hashlib.UnsupportedDigestmodError: Unsupported digestmod functools.partial(<function __hash_new at 0x7fd0b4fd0670>, 'sha1') I'm wondering if this is an actual bug in our Python3.9/FIPS distribution[2] given that this only fails on RHEL9 with FIPS enabled. A possible workaround might look like this, but I'd prefer a fix the issue itself. digestmod = getattr(hashlib, "sha1") print(hmac.new(key, msg, digestmod).hexdigest()) [1] http://rhos-ci-logs.lab.eng.tlv2.redhat.com/logs/staging/DFG-all-unified-17.0_d-rhel-vhost-3cont_2comp-ipv4-vxlan-lvm-fips-non-tls-everywhere-poc/9/controller-0/var/log/containers/swift/swift.log.gz [2] https://gitlab.com/redhat/centos-stream/rpms/python3.9/-/blob/c9s/00329-fips.patch#L1816-1831
This is intended. Under FIPS mode, Python needs to ensure that all cryptography for a HMAC is done by OpenSSL, and so it only accepts a limited set of objects for *digestmod*: native ssl functions and names. We could extend this to allow partial(hashlib.new, string), but that's starting a game of whack-a-mole. We wouldn't want to end up inspecting bytecode of custom functions. A better workaround is using the name for hmac.new directly: print(hmac.new(key, msg, 'sha1').hexdigest()) Can you switch to that?
Thanks Petr for looking into this quickly! (In reply to Petr Viktorin from comment #1) > This is intended. Under FIPS mode, Python needs to ensure that all > cryptography for a HMAC is done by OpenSSL, and so it only accepts a limited > set of objects for *digestmod*: native ssl functions and names. I was wondering if this is a kind of regression, given that this worked on RHEL8 with FIPS enabled. > We could extend this to allow partial(hashlib.new, string), but that's > starting a game of whack-a-mole. We wouldn't want to end up inspecting > bytecode of custom functions. Yes, fully agree! > A better workaround is using the name for hmac.new directly: > > print(hmac.new(key, msg, 'sha1').hexdigest()) > > Can you switch to that? We're going to switch to use digestmod = getattr(hashlib, "sha1") to make this backward-compatible with Python 2.7, but the result should be the same. If this is no regression in RHEL9, we can close this BZ - thx for the input!
It is a regression, but an expected one. Thanks for reaching out!