summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Behnel <stefan_ml@behnel.de>2022-07-20 18:19:44 +0200
committerStefan Behnel <stefan_ml@behnel.de>2022-07-20 18:19:44 +0200
commit3a373e2ccdddc79202d9ed13edc85d4b95616b26 (patch)
treea3bed9f6045df649692287cb640d5ce5ca04b459
parent4d626caa314c8d6de741185e3ec11199effb8f22 (diff)
downloadcython-3a373e2ccdddc79202d9ed13edc85d4b95616b26.tar.gz
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
-rw-r--r--Cython/Compiler/ParseTreeTransforms.py39
-rw-r--r--Cython/Compiler/Tests/TestParseTreeTransforms.py9
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