Bug 2102083 - Python3.9 - functools.partial(hashlib.new, "sha256") no longer works with FIPS enabled on RHEL9
Summary: Python3.9 - functools.partial(hashlib.new, "sha256") no longer works with FIP...
Keywords:
Status: CLOSED NOTABUG
Alias: None
Product: Red Hat Enterprise Linux 9
Classification: Red Hat
Component: python3.9
Version: 9.0
Hardware: Unspecified
OS: Unspecified
unspecified
unspecified
Target Milestone: rc
: ---
Assignee: Python Maintainers
QA Contact:
URL:
Whiteboard:
Depends On:
Blocks:
TreeView+ depends on / blocked
 
Reported: 2022-06-29 10:08 UTC by Christian Schwede (cschwede)
Modified: 2022-06-30 09:14 UTC (History)
3 users (show)

Fixed In Version:
Doc Type: If docs needed, set a value
Doc Text:
Clone Of:
Environment:
Last Closed: 2022-06-30 09:14:31 UTC
Type: Bug
Target Upstream Version:
Embargoed:


Attachments (Terms of Use)


Links
System ID Private Priority Status Summary Last Updated
Red Hat Issue Tracker RHELPLAN-126566 0 None None None 2022-06-29 10:13:27 UTC

Description Christian Schwede (cschwede) 2022-06-29 10:08:21 UTC
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

Comment 1 Petr Viktorin 2022-06-29 11:24:19 UTC
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?

Comment 2 Christian Schwede (cschwede) 2022-06-29 13:33:44 UTC
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!

Comment 3 Petr Viktorin 2022-06-30 09:14:31 UTC
It is a regression, but an expected one.
Thanks for reaching out!


Note You need to log in before you can comment on or make changes to this bug.