1
1
import functools
2
2
import hashlib
3
3
import unittest
4
+ from test .support .import_helper import import_module
4
5
5
6
try :
6
7
import _hashlib
@@ -12,44 +13,81 @@ def requires_hashlib():
12
13
return unittest .skipIf (_hashlib is None , "requires _hashlib" )
13
14
14
15
16
+ def _decorate_func_or_class (func_or_class , decorator_func ):
17
+ if not isinstance (func_or_class , type ):
18
+ return decorator_func (func_or_class )
19
+
20
+ decorated_class = func_or_class
21
+ setUpClass = decorated_class .__dict__ .get ('setUpClass' )
22
+ if setUpClass is None :
23
+ def setUpClass (cls ):
24
+ super (decorated_class , cls ).setUpClass ()
25
+ setUpClass .__qualname__ = decorated_class .__qualname__ + '.setUpClass'
26
+ setUpClass .__module__ = decorated_class .__module__
27
+ else :
28
+ setUpClass = setUpClass .__func__
29
+ setUpClass = classmethod (decorator_func (setUpClass ))
30
+ decorated_class .setUpClass = setUpClass
31
+ return decorated_class
32
+
33
+
15
34
def requires_hashdigest (digestname , openssl = None , usedforsecurity = True ):
16
- """Decorator raising SkipTest if a hashing algorithm is not available
35
+ """Decorator raising SkipTest if a hashing algorithm is not available.
17
36
18
- The hashing algorithm could be missing or blocked by a strict crypto
19
- policy .
37
+ The hashing algorithm may be missing, blocked by a strict crypto policy,
38
+ or Python may be configured with `--with-builtin-hashlib-hashes=no` .
20
39
21
40
If 'openssl' is True, then the decorator checks that OpenSSL provides
22
- the algorithm. Otherwise the check falls back to built-in
23
- implementations. The usedforsecurity flag is passed to the constructor.
41
+ the algorithm. Otherwise the check falls back to (optional) built-in
42
+ HACL* implementations.
43
+
44
+ The usedforsecurity flag is passed to the constructor but has no effect
45
+ on HACL* implementations.
24
46
47
+ Examples of exceptions being suppressed:
25
48
ValueError: [digital envelope routines: EVP_DigestInit_ex] disabled for FIPS
26
49
ValueError: unsupported hash type md4
27
50
"""
51
+ if openssl and _hashlib is not None :
52
+ def test_availability ():
53
+ _hashlib .new (digestname , usedforsecurity = usedforsecurity )
54
+ else :
55
+ def test_availability ():
56
+ hashlib .new (digestname , usedforsecurity = usedforsecurity )
57
+
58
+ def decorator_func (func ):
59
+ @functools .wraps (func )
60
+ def wrapper (* args , ** kwargs ):
61
+ try :
62
+ test_availability ()
63
+ except ValueError as exc :
64
+ msg = f"missing hash algorithm: { digestname !r} "
65
+ raise unittest .SkipTest (msg ) from exc
66
+ return func (* args , ** kwargs )
67
+ return wrapper
68
+
28
69
def decorator (func_or_class ):
29
- if isinstance (func_or_class , type ):
30
- setUpClass = func_or_class .__dict__ .get ('setUpClass' )
31
- if setUpClass is None :
32
- def setUpClass (cls ):
33
- super (func_or_class , cls ).setUpClass ()
34
- setUpClass .__qualname__ = func_or_class .__qualname__ + '.setUpClass'
35
- setUpClass .__module__ = func_or_class .__module__
36
- else :
37
- setUpClass = setUpClass .__func__
38
- setUpClass = classmethod (decorator (setUpClass ))
39
- func_or_class .setUpClass = setUpClass
40
- return func_or_class
41
-
42
- @functools .wraps (func_or_class )
70
+ return _decorate_func_or_class (func_or_class , decorator_func )
71
+ return decorator
72
+
73
+
74
+ def requires_openssl_hashdigest (digestname , * , usedforsecurity = True ):
75
+ """Decorator raising SkipTest if an OpenSSL hashing algorithm is missing.
76
+
77
+ The hashing algorithm may be missing or blocked by a strict crypto policy.
78
+ """
79
+ def decorator_func (func ):
80
+ @requires_hashlib ()
81
+ @functools .wraps (func )
43
82
def wrapper (* args , ** kwargs ):
44
83
try :
45
- if openssl and _hashlib is not None :
46
- _hashlib .new (digestname , usedforsecurity = usedforsecurity )
47
- else :
48
- hashlib .new (digestname , usedforsecurity = usedforsecurity )
84
+ _hashlib .new (digestname , usedforsecurity = usedforsecurity )
49
85
except ValueError :
50
- raise unittest .SkipTest (
51
- f"hash digest { digestname !r} is not available."
52
- )
53
- return func_or_class (* args , ** kwargs )
86
+ msg = f"missing OpenSSL hash algorithm: { digestname !r} "
87
+ raise unittest .SkipTest (msg )
88
+ return func (* args , ** kwargs )
54
89
return wrapper
90
+
91
+ def decorator (func_or_class ):
92
+ return _decorate_func_or_class (func_or_class , decorator_func )
55
93
return decorator
0 commit comments