|
import functools |
|
import hashlib |
|
import unittest |
|
|
|
try: |
|
import _hashlib |
|
except ImportError: |
|
_hashlib = None |
|
|
|
|
|
def requires_hashdigest(digestname, openssl=None, usedforsecurity=True): |
|
"""Decorator raising SkipTest if a hashing algorithm is not available |
|
|
|
The hashing algorithm could be missing or blocked by a strict crypto |
|
policy. |
|
|
|
If 'openssl' is True, then the decorator checks that OpenSSL provides |
|
the algorithm. Otherwise the check falls back to built-in |
|
implementations. The usedforsecurity flag is passed to the constructor. |
|
|
|
ValueError: [digital envelope routines: EVP_DigestInit_ex] disabled for FIPS |
|
ValueError: unsupported hash type md4 |
|
""" |
|
def decorator(func_or_class): |
|
if isinstance(func_or_class, type): |
|
setUpClass = func_or_class.__dict__.get('setUpClass') |
|
if setUpClass is None: |
|
def setUpClass(cls): |
|
super(func_or_class, cls).setUpClass() |
|
setUpClass.__qualname__ = func_or_class.__qualname__ + '.setUpClass' |
|
setUpClass.__module__ = func_or_class.__module__ |
|
else: |
|
setUpClass = setUpClass.__func__ |
|
setUpClass = classmethod(decorator(setUpClass)) |
|
func_or_class.setUpClass = setUpClass |
|
return func_or_class |
|
|
|
@functools.wraps(func_or_class) |
|
def wrapper(*args, **kwargs): |
|
try: |
|
if openssl and _hashlib is not None: |
|
_hashlib.new(digestname, usedforsecurity=usedforsecurity) |
|
else: |
|
hashlib.new(digestname, usedforsecurity=usedforsecurity) |
|
except ValueError: |
|
raise unittest.SkipTest( |
|
f"hash digest '{digestname}' is not available." |
|
) |
|
return func_or_class(*args, **kwargs) |
|
return wrapper |
|
return decorator |
|
|