Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

8 tests fail on a FIPS enabled system #1897

Closed
PritamDutt opened this issue Jul 22, 2020 · 4 comments · Fixed by #2009
Closed

8 tests fail on a FIPS enabled system #1897

PritamDutt opened this issue Jul 22, 2020 · 4 comments · Fixed by #2009
Milestone

Comments

@PritamDutt
Copy link

When using werkzeug on a linux system with FIPS enabled, following tests fail:

FAILED tests/test_debug.py::TestDebugHelpers::test_exc_divider_found_on_chained_exception - ValueError: [digital envelope routines: EVP_DigestInit_ex] disabled for fips
FAILED tests/test_debug.py::test_basic[True] - assert 'The debugger caught an exception in your WSGI application' in '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">\n<title>500 Internal Server Error</title>\n<h1>Internal Serve...
FAILED tests/test_http.py::TestHTTPUtility::test_is_resource_modified - ValueError: [digital envelope routines: EVP_DigestInit_ex] disabled for fips
FAILED tests/test_http.py::TestHTTPUtility::test_is_resource_modified_for_range_requests - ValueError: [digital envelope routines: EVP_DigestInit_ex] disabled for fips
FAILED tests/test_security.py::test_password_hashing - ValueError: [digital envelope routines: EVP_DigestInit_ex] disabled for fips
FAILED tests/test_wrappers.py::test_etag_response_mixin - ValueError: [digital envelope routines: EVP_DigestInit_ex] disabled for fips
FAILED tests/test_wrappers.py::test_etag_response_412 - ValueError: [digital envelope routines: EVP_DigestInit_ex] disabled for fips
FAILED tests/test_wrappers.py::test_etag_response_mixin_freezing - ValueError: [digital envelope routines: EVP_DigestInit_ex] disabled for fips

These tests have been run after cloning this project.

Environment:

  • Python version: 3.8.0
  • Werkzeug version: master branch

The root cause for failure of these tests appear to be MD5, as it does not appear in the list of approved hashing algorithms (SHA-1, SHA-224, SHA-256, SHA-384, SHA512, SHA-512/224 and SHA-512/256).

Is it a possibility to migrate to SHA1 for hashing?

============================================================================================================ test session starts =============================================================================================================
platform linux -- Python 3.8.0, pytest-5.4.3, py-1.8.1, pluggy-0.13.1
rootdir: /home/ec2-user/werkzeug, inifile: setup.cfg, testpaths: tests
plugins: timeout-1.4.2, xprocess-0.13.1
collected 660 items

tests/test_datastructures.py ...................................................................................................                                                                                                       [ 15%]
tests/test_debug.py ..............F....F....                                                                                                                                                                                           [ 18%]
tests/test_exceptions.py .......................................................                                                                                                                                                       [ 26%]
tests/test_formparser.py ...........................                                                                                                                                                                                   [ 31%]
tests/test_http.py .........................FF..........................                                                                                                                                                               [ 39%]
tests/test_internal.py ...                                                                                                                                                                                                             [ 39%]
tests/test_local.py ..........                                                                                                                                                                                                         [ 41%]
tests/test_routing.py ......................................................................                                                                                                                                           [ 51%]
tests/test_security.py ..F...                                                                                                                                                                                                          [ 52%]
tests/test_send_file.py .........................                                                                                                                                                                                      [ 56%]
tests/test_serving.py .....................                                                                                                                                                                                            [ 59%]
tests/test_test.py ......................................................                                                                                                                                                              [ 67%]
tests/test_urls.py ...........................................                                                                                                                                                                         [ 74%]
tests/test_useragents.py ...                                                                                                                                                                                                           [ 74%]
tests/test_utils.py .................                                                                                                                                                                                                  [ 77%]
tests/test_wrappers.py ....................................FF......F..............................................                                                                                                                     [ 91%]
tests/test_wsgi.py ................................                                                                                                                                                                                    [ 95%]
tests/middleware/test_dispatcher.py .                                                                                                                                                                                                  [ 96%]
tests/middleware/test_http_proxy.py .                                                                                                                                                                                                  [ 96%]
tests/middleware/test_lint.py .........                                                                                                                                                                                                [ 97%]
tests/middleware/test_proxy_fix.py ..............                                                                                                                                                                                      [ 99%]
tests/middleware/test_shared_data.py ..                                                                                                                                                                                                [100%]

================================================================================================================== FAILURES ==================================================================================================================
________________________________________________________________________________________ TestDebugHelpers.test_exc_divider_found_on_chained_exception ________________________________________________________________________________________

request = <Request 'http://localhost/' [GET]>

    @Request.application
    def app(request):
        def do_something():
            raise ValueError("inner")

        try:
>           do_something()

tests/test_debug.py:233:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

    def do_something():
>       raise ValueError("inner")
E       ValueError: inner

tests/test_debug.py:230: ValueError

During handling of the above exception, another exception occurred:

self = <werkzeug.debug.DebuggedApplication object at 0x7f6ceb2e4250>, environ = {'HTTP_HOST': 'localhost', 'PATH_INFO': '/', 'QUERY_STRING': '', 'RAW_URI': '/', ...}
start_response = <function run_wsgi_app.<locals>.start_response at 0x7f6cebe9b160>

    def debug_application(self, environ, start_response):
        """Run the application and conserve the traceback frames."""
        app_iter = None
        try:
>           app_iter = self.app(environ, start_response)

src/werkzeug/debug/__init__.py:289:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

args = ({'HTTP_HOST': 'localhost', 'PATH_INFO': '/', 'QUERY_STRING': '', 'RAW_URI': '/', ...}, <function run_wsgi_app.<locals>.start_response at 0x7f6cebe9b160>), request = <Request 'http://localhost/' [GET]>

    def application(*args):
        request = cls(args[-2])
        with request:
            try:
>               resp = f(*args[:-2] + (request,))

src/werkzeug/wrappers/base_request.py:236:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

request = <Request 'http://localhost/' [GET]>

    @Request.application
    def app(request):
        def do_something():
            raise ValueError("inner")

        try:
            do_something()
        except ValueError:
>           raise KeyError("outer")
E           KeyError: 'outer'

tests/test_debug.py:235: KeyError

During handling of the above exception, another exception occurred:

self = <test_debug.TestDebugHelpers object at 0x7f6cec9beb50>

    def test_exc_divider_found_on_chained_exception(self):
        @Request.application
        def app(request):
            def do_something():
                raise ValueError("inner")

            try:
                do_something()
            except ValueError:
                raise KeyError("outer")

        debugged = DebuggedApplication(app)
        client = Client(debugged, Response)
>       response = client.get("/")

tests/test_debug.py:239:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
src/werkzeug/test.py:995: in get
    return self.open(*args, **kw)
src/werkzeug/test.py:959: in open
    response = self.run_wsgi_app(environ.copy(), buffered=buffered)
src/werkzeug/test.py:850: in run_wsgi_app
    rv = run_wsgi_app(self.application, environ, buffered=buffered)
src/werkzeug/test.py:1106: in run_wsgi_app
    for item in app_iter:
src/werkzeug/debug/__init__.py:326: in debug_application
    is_trusted = bool(self.check_pin_trust(environ))
src/werkzeug/debug/__init__.py:370: in check_pin_trust
    if self.pin is None:
src/werkzeug/debug/__init__.py:271: in pin
    self._pin, self._pin_cookie = get_pin_and_cookie_name(self.app)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

app = <function TestDebugHelpers.test_exc_divider_found_on_chained_exception.<locals>.app at 0x7f6cebe9b5e0>

    def get_pin_and_cookie_name(app):
        """Given an application object this returns a semi-stable 9 digit pin
        code and a random key.  The hope is that this is stable between
        restarts to not make debugging particularly frustrating.  If the pin
        was forcefully disabled this returns `None`.

        Second item in the resulting tuple is the cookie name for remembering.
        """
        pin = os.environ.get("WERKZEUG_DEBUG_PIN")
        rv = None
        num = None

        # Pin was explicitly disabled
        if pin == "off":
            return None, None

        # Pin was provided explicitly
        if pin is not None and pin.replace("-", "").isdigit():
            # If there are separators in the pin, return it directly
            if "-" in pin:
                rv = pin
            else:
                num = pin

        modname = getattr(app, "__module__", app.__class__.__module__)

        try:
            # getuser imports the pwd module, which does not exist in Google
            # App Engine. It may also raise a KeyError if the UID does not
            # have a username, such as in Docker.
            username = getpass.getuser()
        except (ImportError, KeyError):
            username = None

        mod = sys.modules.get(modname)

        # This information only exists to make the cookie unique on the
        # computer, not as a security feature.
        probably_public_bits = [
            username,
            modname,
            getattr(app, "__name__", type(app).__name__),
            getattr(mod, "__file__", None),
        ]

        # This information is here to make it harder for an attacker to
        # guess the cookie name.  They are unlikely to be contained anywhere
        # within the unauthenticated debug page.
        private_bits = [str(uuid.getnode()), get_machine_id()]

>       h = hashlib.md5()
E       ValueError: [digital envelope routines: EVP_DigestInit_ex] disabled for fips

src/werkzeug/debug/__init__.py:172: ValueError
______________________________________________________________________________________________________________ test_basic[True] ______________________________________________________________________________________________________________

dev_server = <function dev_server.<locals>.run_dev_server at 0x7f6cee774e50>, crash = True

    @pytest.mark.parametrize("crash", (True, False))
    def test_basic(dev_server, crash):
        server = dev_server(
            f"""
            from werkzeug.debug import DebuggedApplication

            @DebuggedApplication
            def app(environ, start_response):
                if {crash}:
                    1 / 0
                start_response('200 OK', [('Content-Type', 'text/html')])
                return [b'hello']
            """
        )

        r = requests.get(server.url)
        assert r.status_code == 500 if crash else 200
        if crash:
>           assert "The debugger caught an exception in your WSGI application" in r.text
E           assert 'The debugger caught an exception in your WSGI application' in '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">\n<title>500 Internal Server Error</title>\n<h1>Internal Serve...nd was unable to complete your request. Either the server is overloaded or there is an error in the application.</p>\n'
E            +  where '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">\n<title>500 Internal Server Error</title>\n<h1>Internal Serve...nd was unable to complete your request. Either the server is overloaded or there is an error in the application.</p>\n' = <Response [500]>.text

tests/test_debug.py:325: AssertionError
------------------------------------------------------------------------------------------------------------ Captured stdout call ------------------------------------------------------------------------------------------------------------
/home/ec2-user/werkzeug/.xprocess/dev_server$ /home/ec2-user/werkzeug/env/bin/python3 /home/ec2-user/werkzeug/tests/conftest.py /tmp/pytest-of-ec2-user/pytest-0/test_basic_True_0
process 'dev_server' started pid=9845
 * Running on http://localhost:13220/ (Press CTRL+C to quit)

pid=9845

dev_server process startup detected
------------------------------------------------------------------------------------------------------------ Captured stderr call ------------------------------------------------------------------------------------------------------------
Exception ignored in: <function Popen.__del__ at 0x7f6ceec6ae50>
Traceback (most recent call last):
  File "/opt/rh/rh-python38/root/usr/lib64/python3.8/subprocess.py", line 942, in __del__
    _warn("subprocess %s is still running" % self.pid,
ResourceWarning: subprocess 9845 is still running
_________________________________________________________________________________________________ TestHTTPUtility.test_is_resource_modified __________________________________________________________________________________________________

self = <test_http.TestHTTPUtility object at 0x7f6ceb9589d0>

    def test_is_resource_modified(self):
        env = create_environ()

        # any method is allowed
        env["REQUEST_METHOD"] = "POST"
        assert http.is_resource_modified(env, etag="testing")
        env["REQUEST_METHOD"] = "GET"

        # etagify from data
        pytest.raises(TypeError, http.is_resource_modified, env, data="42", etag="23")
>       env["HTTP_IF_NONE_MATCH"] = http.generate_etag(b"awesome")

tests/test_http.py:390:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

data = b'awesome'

    def generate_etag(data):
        """Generate an etag for some data."""
>       return md5(data).hexdigest()
E       ValueError: [digital envelope routines: EVP_DigestInit_ex] disabled for fips

src/werkzeug/http.py:797: ValueError
________________________________________________________________________________________ TestHTTPUtility.test_is_resource_modified_for_range_requests ________________________________________________________________________________________

self = <test_http.TestHTTPUtility object at 0x7f6ceb977d90>

    def test_is_resource_modified_for_range_requests(self):
        env = create_environ()

        env["HTTP_IF_MODIFIED_SINCE"] = http.http_date(datetime(2008, 1, 1, 12, 30))
>       env["HTTP_IF_RANGE"] = http.generate_etag(b"awesome_if_range")

tests/test_http.py:405:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

data = b'awesome_if_range'

    def generate_etag(data):
        """Generate an etag for some data."""
>       return md5(data).hexdigest()
E       ValueError: [digital envelope routines: EVP_DigestInit_ex] disabled for fips

src/werkzeug/http.py:797: ValueError
___________________________________________________________________________________________________________ test_password_hashing ____________________________________________________________________________________________________________

    def test_password_hashing():
        hash0 = generate_password_hash("default")
        assert check_password_hash(hash0, "default")
        assert hash0.startswith("pbkdf2:sha256:150000$")

        hash1 = generate_password_hash("default", "sha1")
        hash2 = generate_password_hash("default", method="sha1")
        assert hash1 != hash2
        assert check_password_hash(hash1, "default")
        assert check_password_hash(hash2, "default")
        assert hash1.startswith("sha1$")
        assert hash2.startswith("sha1$")

        with pytest.raises(ValueError):
            check_password_hash("$made$up$", "default")

        with pytest.raises(ValueError):
            generate_password_hash("default", "sha1", salt_length=0)

        fakehash = generate_password_hash("default", method="plain")
        assert fakehash == "plain$$default"
        assert check_password_hash(fakehash, "default")

>       mhash = generate_password_hash("default", method="md5")

tests/test_security.py:58:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
src/werkzeug/security.py:181: in generate_password_hash
    h, actual_method = _hash_internal(method, salt, password)
src/werkzeug/security.py:138: in _hash_internal
    mac = _create_mac(salt, password, method)
src/werkzeug/security.py:152: in _create_mac
    return hmac.HMAC(key, msg, hashfunc)
/opt/rh/rh-python38/root/usr/lib64/python3.8/hmac.py:162: in __new__
    name = _get_openssl_name(digestmod)
/opt/rh/rh-python38/root/usr/lib64/python3.8/hmac.py:149: in _get_openssl_name
    digestmod = digestmod(b'')
src/werkzeug/security.py:150: in hashfunc
    return hashlib.new(method, d)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

name = 'md5', data = b'', kwargs = {}

    def __hash_new(name, data=b'', **kwargs):
        """new(name, data=b'') - Return a new hashing object using the named algorithm;
        optionally initialized with data (which must be a bytes-like object).
        """
        if not _hashlib.get_fips_mode():
            if name in __block_openssl_constructor:
                # Prefer our blake2 and sha3 implementation
                # OpenSSL 1.1.0 comes with a limited implementation of blake2b/s.
                # It does neither support keyed blake2 nor advanced features like
                # salt, personal, tree hashing or SSE.
                return __get_builtin_constructor(name)(data, **kwargs)
        try:
>           return _hashlib.new(name, data, **kwargs)
E           ValueError: [digital envelope routines: EVP_DigestInit_ex] disabled for fips

/opt/rh/rh-python38/root/usr/lib64/python3.8/hashlib.py:169: ValueError
__________________________________________________________________________________________________________ test_etag_response_mixin __________________________________________________________________________________________________________

    def test_etag_response_mixin():
        response = wrappers.Response("Hello World")
        assert response.get_etag() == (None, None)
>       response.add_etag()

tests/test_wrappers.py:747:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
src/werkzeug/wrappers/etag.py:241: in add_etag
    self.set_etag(generate_etag(self.get_data()), weak)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

data = b'Hello World'

    def generate_etag(data):
        """Generate an etag for some data."""
>       return md5(data).hexdigest()
E       ValueError: [digital envelope routines: EVP_DigestInit_ex] disabled for fips

src/werkzeug/http.py:797: ValueError
___________________________________________________________________________________________________________ test_etag_response_412 ___________________________________________________________________________________________________________

    def test_etag_response_412():
        response = wrappers.Response("Hello World")
        assert response.get_etag() == (None, None)
>       response.add_etag()

tests/test_wrappers.py:788:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
src/werkzeug/wrappers/etag.py:241: in add_etag
    self.set_etag(generate_etag(self.get_data()), weak)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

data = b'Hello World'

    def generate_etag(data):
        """Generate an etag for some data."""
>       return md5(data).hexdigest()
E       ValueError: [digital envelope routines: EVP_DigestInit_ex] disabled for fips

src/werkzeug/http.py:797: ValueError
_____________________________________________________________________________________________________ test_etag_response_mixin_freezing ______________________________________________________________________________________________________

    def test_etag_response_mixin_freezing():
        class WithFreeze(wrappers.ETagResponseMixin, wrappers.BaseResponse):
            pass

        class WithoutFreeze(  # type: ignore
            wrappers.BaseResponse, wrappers.ETagResponseMixin
        ):
            pass

        response = WithFreeze("Hello World")
>       response.freeze()

tests/test_wrappers.py:917:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
src/werkzeug/wrappers/etag.py:259: in freeze
    self.add_etag()
src/werkzeug/wrappers/etag.py:241: in add_etag
    self.set_etag(generate_etag(self.get_data()), weak)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

data = b'Hello World'

    def generate_etag(data):
        """Generate an etag for some data."""
>       return md5(data).hexdigest()
E       ValueError: [digital envelope routines: EVP_DigestInit_ex] disabled for fips

src/werkzeug/http.py:797: ValueError
========================================================================================================== short test summary info ===========================================================================================================
FAILED tests/test_debug.py::TestDebugHelpers::test_exc_divider_found_on_chained_exception - ValueError: [digital envelope routines: EVP_DigestInit_ex] disabled for fips
FAILED tests/test_debug.py::test_basic[True] - assert 'The debugger caught an exception in your WSGI application' in '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">\n<title>500 Internal Server Error</title>\n<h1>Internal Serve...
FAILED tests/test_http.py::TestHTTPUtility::test_is_resource_modified - ValueError: [digital envelope routines: EVP_DigestInit_ex] disabled for fips
FAILED tests/test_http.py::TestHTTPUtility::test_is_resource_modified_for_range_requests - ValueError: [digital envelope routines: EVP_DigestInit_ex] disabled for fips
FAILED tests/test_security.py::test_password_hashing - ValueError: [digital envelope routines: EVP_DigestInit_ex] disabled for fips
FAILED tests/test_wrappers.py::test_etag_response_mixin - ValueError: [digital envelope routines: EVP_DigestInit_ex] disabled for fips
FAILED tests/test_wrappers.py::test_etag_response_412 - ValueError: [digital envelope routines: EVP_DigestInit_ex] disabled for fips
FAILED tests/test_wrappers.py::test_etag_response_mixin_freezing - ValueError: [digital envelope routines: EVP_DigestInit_ex] disabled for fips
================================================================================================== 8 failed, 652 passed in 98.71s (0:01:38) ==================================================================================================
@kam193
Copy link
Contributor

kam193 commented Jul 30, 2020

Although using MD5 in this case isn't a security problem and should generally work, in my opinion also it would be better to migrate it. Changing the hash function will improve a bit the quality of Etag and shouldn't introduce any significant compatibility problems.

@PritamDutt
Copy link
Author

In reality MD5 and SHA1 both have security vulnerabilities. Please see

@kam193
Copy link
Contributor

kam193 commented Aug 4, 2020

Of course, probably it would be better to choose a modern hash. Anyway, this place it's not a secure risky - but of course, still better remove usage of MD5/SHA1

@davidism
Copy link
Member

@PritamDutt I don't have access to a FIPS 140 system. It would be helpful if you can confirm that the tests pass now.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Feb 2, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants