mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 13:41:24 +00:00 
			
		
		
		
	gh-130149: cleanup refactorization of test_hmac.py (#131318)
				
					
				
			New features: * refactor `hashlib_helper.requires_hashdigest` in prevision of a future `hashlib_helper.requires_builtin_hashdigest` for built-in hashes only * add `hashlib_helper.requires_openssl_hashdigest` to request OpenSSL hashes, assuming that `_hashlib` exists. Refactoring: * split hmac.copy() test by implementation * update how algorithms are discovered for RFC test cases * simplify how OpenSSL hash digests are requested * refactor hexdigest tests for RFC test vectors * typo fix: `assert_hmac_hexdigest_by_new` -> `assert_hmac_hexdigest_by_name` Improvements: * strengthen contract on `hmac_new_by_name` and `hmac_digest_by_name` * rename mixin classes to better match their responsibility
This commit is contained in:
		
							parent
							
								
									85c04f80fd
								
							
						
					
					
						commit
						de8890f5ab
					
				
					 3 changed files with 263 additions and 147 deletions
				
			
		|  | @ -1,6 +1,7 @@ | |||
| import functools | ||||
| import hashlib | ||||
| import unittest | ||||
| from test.support.import_helper import import_module | ||||
| 
 | ||||
| try: | ||||
|     import _hashlib | ||||
|  | @ -12,44 +13,81 @@ def requires_hashlib(): | |||
|     return unittest.skipIf(_hashlib is None, "requires _hashlib") | ||||
| 
 | ||||
| 
 | ||||
| def requires_hashdigest(digestname, openssl=None, usedforsecurity=True): | ||||
|     """Decorator raising SkipTest if a hashing algorithm is not available | ||||
| def _decorate_func_or_class(func_or_class, decorator_func): | ||||
|     if not isinstance(func_or_class, type): | ||||
|         return decorator_func(func_or_class) | ||||
| 
 | ||||
|     The hashing algorithm could be missing or blocked by a strict crypto | ||||
|     policy. | ||||
|     decorated_class = func_or_class | ||||
|     setUpClass = decorated_class.__dict__.get('setUpClass') | ||||
|     if setUpClass is None: | ||||
|         def setUpClass(cls): | ||||
|             super(decorated_class, cls).setUpClass() | ||||
|         setUpClass.__qualname__ = decorated_class.__qualname__ + '.setUpClass' | ||||
|         setUpClass.__module__ = decorated_class.__module__ | ||||
|     else: | ||||
|         setUpClass = setUpClass.__func__ | ||||
|     setUpClass = classmethod(decorator_func(setUpClass)) | ||||
|     decorated_class.setUpClass = setUpClass | ||||
|     return decorated_class | ||||
| 
 | ||||
| 
 | ||||
| def requires_hashdigest(digestname, openssl=None, usedforsecurity=True): | ||||
|     """Decorator raising SkipTest if a hashing algorithm is not available. | ||||
| 
 | ||||
|     The hashing algorithm may be missing, blocked by a strict crypto policy, | ||||
|     or Python may be configured with `--with-builtin-hashlib-hashes=no`. | ||||
| 
 | ||||
|     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. | ||||
|     the algorithm. Otherwise the check falls back to (optional) built-in | ||||
|     HACL* implementations. | ||||
| 
 | ||||
|     The usedforsecurity flag is passed to the constructor but has no effect | ||||
|     on HACL* implementations. | ||||
| 
 | ||||
|     Examples of exceptions being suppressed: | ||||
|     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 | ||||
|     if openssl and _hashlib is not None: | ||||
|         def test_availability(): | ||||
|             _hashlib.new(digestname, usedforsecurity=usedforsecurity) | ||||
|     else: | ||||
|         def test_availability(): | ||||
|             hashlib.new(digestname, usedforsecurity=usedforsecurity) | ||||
| 
 | ||||
|         @functools.wraps(func_or_class) | ||||
|     def decorator_func(func): | ||||
|         @functools.wraps(func) | ||||
|         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!r} is not available." | ||||
|                 ) | ||||
|             return func_or_class(*args, **kwargs) | ||||
|                 test_availability() | ||||
|             except ValueError as exc: | ||||
|                 msg = f"missing hash algorithm: {digestname!r}" | ||||
|                 raise unittest.SkipTest(msg) from exc | ||||
|             return func(*args, **kwargs) | ||||
|         return wrapper | ||||
| 
 | ||||
|     def decorator(func_or_class): | ||||
|         return _decorate_func_or_class(func_or_class, decorator_func) | ||||
|     return decorator | ||||
| 
 | ||||
| 
 | ||||
| def requires_openssl_hashdigest(digestname, *, usedforsecurity=True): | ||||
|     """Decorator raising SkipTest if an OpenSSL hashing algorithm is missing. | ||||
| 
 | ||||
|     The hashing algorithm may be missing or blocked by a strict crypto policy. | ||||
|     """ | ||||
|     def decorator_func(func): | ||||
|         @requires_hashlib() | ||||
|         @functools.wraps(func) | ||||
|         def wrapper(*args, **kwargs): | ||||
|             try: | ||||
|                 _hashlib.new(digestname, usedforsecurity=usedforsecurity) | ||||
|             except ValueError: | ||||
|                 msg = f"missing OpenSSL hash algorithm: {digestname!r}" | ||||
|                 raise unittest.SkipTest(msg) | ||||
|             return func(*args, **kwargs) | ||||
|         return wrapper | ||||
| 
 | ||||
|     def decorator(func_or_class): | ||||
|         return _decorate_func_or_class(func_or_class, decorator_func) | ||||
|     return decorator | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Bénédikt Tran
						Bénédikt Tran