Skip to content

Commit

Permalink
Introduce fips_safe_md5, see issue #7611
Browse files Browse the repository at this point in the history
  • Loading branch information
lhupfeldt committed May 4, 2020
1 parent 153682d commit 1b8415a
Show file tree
Hide file tree
Showing 6 changed files with 25 additions and 10 deletions.
1 change: 1 addition & 0 deletions AUTHORS
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ Other contributors, listed alphabetically, are:
* Daniel Pizetta -- inheritance diagram improvements
* KINEBUCHI Tomohiko -- typing Sphinx as well as docutils
* Adrián Chaves (Gallaecio) -- coverage builder improvements
* Lars Hupfeldt Nielsen - OpenSSL FIPS mode md5 bug fix

Many thanks for all contributions!

Expand Down
1 change: 1 addition & 0 deletions CHANGES
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ Bugs fixed
----------

* #7567: autodoc: parametrized types are shown twice for generic types
* #7611: md5 fails when OpenSSL FIPS is enabled

Testing
--------
Expand Down
5 changes: 2 additions & 3 deletions sphinx/builders/html/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
import re
import sys
import warnings
from hashlib import md5
from os import path
from typing import Any, Dict, IO, Iterable, Iterator, List, Set, Tuple

Expand All @@ -38,7 +37,7 @@
from sphinx.locale import _, __
from sphinx.search import js_index
from sphinx.theming import HTMLThemeFactory
from sphinx.util import logging, progress_message, status_iterator
from sphinx.util import logging, progress_message, status_iterator, fips_safe_md5
from sphinx.util.docutils import is_html5_writer_available, new_document
from sphinx.util.fileutil import copy_asset
from sphinx.util.i18n import format_date
Expand Down Expand Up @@ -77,7 +76,7 @@ def get_stable_hash(obj: Any) -> str:
return get_stable_hash(list(obj.items()))
elif isinstance(obj, (list, tuple)):
obj = sorted(get_stable_hash(o) for o in obj)
return md5(str(obj).encode()).hexdigest()
return fips_safe_md5(str(obj).encode()).hexdigest()


class Stylesheet(str):
Expand Down
4 changes: 2 additions & 2 deletions sphinx/ext/inheritance_diagram.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ class E(B): pass
import builtins
import inspect
import re
from hashlib import md5
from importlib import import_module
from typing import Any, Dict, Iterable, List, Tuple
from typing import cast
Expand All @@ -55,6 +54,7 @@ class E(B): pass
graphviz, figure_wrapper,
render_dot_html, render_dot_latex, render_dot_texinfo
)
from sphinx.util import fips_safe_md5
from sphinx.util.docutils import SphinxDirective
from sphinx.writers.html import HTMLTranslator
from sphinx.writers.latex import LaTeXTranslator
Expand Down Expand Up @@ -387,7 +387,7 @@ def run(self) -> List[Node]:

def get_graph_hash(node: inheritance_diagram) -> str:
encoded = (node['content'] + str(node['parts'])).encode()
return md5(encoded).hexdigest()[-10:]
return fips_safe_md5(encoded).hexdigest()[-10:]


def html_visit_inheritance_diagram(self: HTMLTranslator, node: inheritance_diagram) -> None:
Expand Down
17 changes: 16 additions & 1 deletion sphinx/util/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,21 @@ def __setstate__(self, state: Set[str]) -> None:
self._existing = state


def fips_safe_md5(data=b'', **kwargs):
"""Wrapper around hashlib.md5
Attempt call with 'usedforsecurity=False' if we get a ValueError, which happens when OpenSSL FIPS mode is enabled:
ValueError: error:060800A3:digital envelope routines:EVP_DigestInit_ex:disabled for fips
See: https://github.com/sphinx-doc/sphinx/issues/7611
"""

try:
return md5(data, **kwargs)
except ValueError:
return md5(data, **kwargs, usedforsecurity=False)


class DownloadFiles(dict):
"""A special dictionary for download files.
Expand All @@ -179,7 +194,7 @@ class DownloadFiles(dict):

def add_file(self, docname: str, filename: str) -> str:
if filename not in self:
digest = md5(filename.encode()).hexdigest()
digest = fips_safe_md5(filename.encode()).hexdigest()
dest = '%s/%s' % (digest, os.path.basename(filename))
self[filename] = (set(), dest)

Expand Down
7 changes: 3 additions & 4 deletions tests/test_build_html.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@

import os
import re
from hashlib import md5
from itertools import cycle, chain

import pytest
Expand All @@ -19,7 +18,7 @@
from sphinx.builders.html import validate_html_extra_path, validate_html_static_path
from sphinx.errors import ConfigError
from sphinx.testing.util import strip_escseq
from sphinx.util import docutils
from sphinx.util import docutils, fips_safe_md5
from sphinx.util.inventory import InventoryFile


Expand Down Expand Up @@ -450,9 +449,9 @@ def test_html_download(app):
@pytest.mark.sphinx('html', testroot='roles-download')
def test_html_download_role(app, status, warning):
app.build()
digest = md5(b'dummy.dat').hexdigest()
digest = fips_safe_md5(b'dummy.dat').hexdigest()
assert (app.outdir / '_downloads' / digest / 'dummy.dat').exists()
digest_another = md5(b'another/dummy.dat').hexdigest()
digest_another = fips_safe_md5(b'another/dummy.dat').hexdigest()
assert (app.outdir / '_downloads' / digest_another / 'dummy.dat').exists()

content = (app.outdir / 'index.html').read_text()
Expand Down

0 comments on commit 1b8415a

Please sign in to comment.