From 3a373e2ccdddc79202d9ed13edc85d4b95616b26 Mon Sep 17 00:00:00 2001 From: Stefan Behnel Date: Wed, 20 Jul 2022 18:19:44 +0200 Subject: Make pickle checksum calculation succeed even if one of the hash algorithms is blocked at runtime. Also, pass "usedforsecurity=False" in Py3.9+ to unblock MD5 also on some security constrained systems (FIPS). Closes https://github.com/cython/cython/issues/4909 --- Cython/Compiler/ParseTreeTransforms.py | 39 +++++++++++++----------- Cython/Compiler/Tests/TestParseTreeTransforms.py | 9 +++++- 2 files changed, 29 insertions(+), 19 deletions(-) diff --git a/Cython/Compiler/ParseTreeTransforms.py b/Cython/Compiler/ParseTreeTransforms.py index 8e0cbc303..5799c4945 100644 --- a/Cython/Compiler/ParseTreeTransforms.py +++ b/Cython/Compiler/ParseTreeTransforms.py @@ -8,6 +8,7 @@ cython.declare(PyrexTypes=object, Naming=object, ExprNodes=object, Nodes=object, import copy import hashlib +import sys from . import PyrexTypes from . import Naming @@ -1700,24 +1701,9 @@ if VALUE is not None: if not e.type.is_pyobject: e.type.create_to_py_utility_code(env) e.type.create_from_py_utility_code(env) - all_members_names = sorted([e.name for e in all_members]) - - # Cython 0.x used MD5 for the checksum, which a few Python installations remove for security reasons. - # SHA-256 should be ok for years to come, but early Cython 3.0 alpha releases used SHA-1, - # which may not be. - checksum_algos = [] - try: - checksum_algos.append(hashlib.md5) - except AttributeError: - pass - checksum_algos.append(hashlib.sha256) - checksum_algos.append(hashlib.sha1) - - member_names_string = ' '.join(all_members_names).encode('utf-8') - checksums = [ - '0x' + mkchecksum(member_names_string).hexdigest()[:7] - for mkchecksum in checksum_algos - ] + all_members_names = [e.name for e in all_members] + checksums = _calculate_pickle_checksums(all_members_names) + unpickle_func_name = '__pyx_unpickle_%s' % node.class_name # TODO(robertwb): Move the state into the third argument @@ -2136,6 +2122,23 @@ if VALUE is not None: return property +def _calculate_pickle_checksums(member_names): + # Cython 0.x used MD5 for the checksum, which a few Python installations remove for security reasons. + # SHA-256 should be ok for years to come, but early Cython 3.0 alpha releases used SHA-1, + # which may not be. + member_names_string = ' '.join(member_names).encode('utf-8') + hash_kwargs = {'usedforsecurity': False} if sys.version_info >= (3, 9) else {} + checksums = [] + for algo_name in ['md5', 'sha256', 'sha1']: + try: + mkchecksum = getattr(hashlib, algo_name) + checksums.append('0x' + mkchecksum(member_names_string, **hash_kwargs).hexdigest()[:7]) + except (AttributeError, ValueError): + # The algorithm (i.e. MD5) might not be there at all, or might be blocked at runtime + continue + return checksums + + class CalculateQualifiedNamesTransform(EnvTransform): """ Calculate and store the '__qualname__' and the global diff --git a/Cython/Compiler/Tests/TestParseTreeTransforms.py b/Cython/Compiler/Tests/TestParseTreeTransforms.py index 234b45db5..8a16f98cc 100644 --- a/Cython/Compiler/Tests/TestParseTreeTransforms.py +++ b/Cython/Compiler/Tests/TestParseTreeTransforms.py @@ -1,7 +1,9 @@ -import os +import os.path +import unittest from Cython.TestUtils import TransformTest from Cython.Compiler.ParseTreeTransforms import * +from Cython.Compiler.ParseTreeTransforms import _calculate_pickle_checksums from Cython.Compiler.Nodes import * from Cython.Compiler import Main, Symtab @@ -276,6 +278,11 @@ class TestDebugTransform(DebuggerTestCase): raise +class TestAnalyseDeclarationsTransform(unittest.TestCase): + def test_calculate_pickle_checksums(self): + checksums = _calculate_pickle_checksums(['member1', 'member2', 'member3']) + assert 2 <= len(checksums) <= 3, checksums # expecting ['0xc0af380' (MD5), '0x0c75bd4', '0xa7a7b94'] + if __name__ == "__main__": import unittest -- cgit v1.2.1