8000 [3.14] gh-134696: align OpenSSL and HACL*-based hash functions constr… · python/cpython@777fd49 · GitHub
[go: up one dir, main page]

Skip to content
  • Commit 777fd49

    Browse files
    authored
    [3.14] gh-134696: align OpenSSL and HACL*-based hash functions constructors AC signatures (GH-134713) (#134961)
    OpenSSL and HACL*-based hash functions constructors now support both `data` and `string` parameters. Previously these constructor functions inconsistently supported sometimes `data` and sometimes `string`, while the documentation expected `data` to be given in all cases. (cherry picked from commit c6e63d9) (cherry picked from commit 379d0bc)
    1 parent 5d07d16 commit 777fd49

    16 files changed

    +873
    -438
    lines changed

    Lib/hashlib.py

    Lines changed: 6 additions & 6 deletions
    Original file line numberDiff line numberDiff line change
    @@ -141,29 +141,29 @@ def __get_openssl_constructor(name):
    141141
    return __get_builtin_constructor(name)
    142142

    143143

    144-
    def __py_new(name, data=b'', **kwargs):
    144+
    def __py_new(name, *args, **kwargs):
    145145
    """new(name, data=b'', **kwargs) - Return a new hashing object using the
    146146
    named algorithm; optionally initialized with data (which must be
    147147
    a bytes-like object).
    148148
    """
    149-
    return __get_builtin_constructor(name)(data, **kwargs)
    149+
    return __get_builtin_constructor(name)(*args, **kwargs)
    150150

    151151

    152-
    def __hash_new(name, data=b'', **kwargs):
    152+
    def __hash_new(name, *args, **kwargs):
    153153
    """new(name, data=b'') - Return a new hashing object using the named algorithm;
    154154
    optionally initialized with data (which must be a bytes-like object).
    155155
    """
    156156
    if name in __block_openssl_constructor:
    157157
    # Prefer our builtin blake2 implementation.
    158-
    return __get_builtin_constructor(name)(data, **kwargs)
    158+
    return __get_builtin_constructor(name)(*args, **kwargs)
    159159
    try:
    160-
    return _hashlib.new(name, data, **kwargs)
    160+
    return _hashlib.new(name, *args, **kwargs)
    161161
    except ValueError:
    162162
    # If the _hashlib module (OpenSSL) doesn't support the named
    163163
    # hash, try using our builtin implementations.
    164164
    # This allows for SHA224/256 and SHA384/512 support even though
    165165
    # the OpenSSL library prior to 0.9.8 doesn't provide them.
    166-
    return __get_builtin_constructor(name)(data)
    166+
    return __get_builtin_constructor(name)(*args, **kwargs)
    167167

    168168

    169169
    try:

    Lib/test/test_hashlib.py

    Lines changed: 74 additions & 7 deletions
    Original file line numberDiff line numberDiff line change
    @@ -12,6 +12,7 @@
    1212
    import itertools
    1313
    import logging
    1414
    import os
    15+
    import re
    1516
    import sys
    1617
    import sysconfig
    1718
    import tempfile
    @@ -141,11 +142,10 @@ def __init__(self, *args, **kwargs):
    141142
    # of hashlib.new given the algorithm name.
    142143
    for algorithm, constructors in self.constructors_to_test.items():
    143144
    constructors.add(getattr(hashlib, algorithm))
    144-
    def _test_algorithm_via_hashlib_new(data=None, _alg=algorithm, **kwargs):
    145-
    if data is None:
    146-
    return hashlib.new(_alg, **kwargs)
    147-
    return hashlib.new(_alg, data, **kwargs)
    148-
    constructors.add(_test_algorithm_via_hashlib_new)
    145+
    def c(*args, __algorithm_name=algorithm, **kwargs):
    146+
    return hashlib.new(__algorithm_name, *args, **kwargs)
    147+
    c.__name__ = f'do_test_algorithm_via_hashlib_new_{algorithm}'
    148+
    constructors.add(c)
    149149

    150150
    _hashlib = self._conditional_import_module('_hashlib')
    151151
    self._hashlib = _hashlib
    @@ -250,6 +250,75 @@ def test_usedforsecurity_false(self):
    250250
    self._hashlib.new("md5", usedforsecurity=False)
    251251
    self._hashlib.openssl_md5(usedforsecurity=False)
    252252

    253+
    @unittest.skipIf(get_fips_mode(), "skip in FIPS mode")
    254+
    def test_clinic_signature(self):
    255+
    for constructor in self.hash_constructors:
    256+
    with self.subTest(constructor.__name__):
    257+
    constructor(b'')
    258+
    constructor(data=b'')
    259+
    constructor(string=b'') # should be deprecated in the future
    260+
    261+
    digest_name = constructor(b'').name
    262+
    with self.subTest(digest_name):
    263+
    hashlib.new(digest_name, b'')
    264+
    hashlib.new(digest_name, data=b'')
    265+
    hashlib.new(digest_name, string=b'')
    266+
    if self._hashlib:
    267+
    self._hashlib.new(digest_name, b'')
    268+
    self._hashlib.new(digest_name, data=b'')
    269+
    self._hashlib.new(digest_name, string=b'')
    270+
    1E79
    271+
    @unittest.skipIf(get_fips_mode(), "skip in FIPS mode")
    272+
    def test_clinic_signature_errors(self):
    273+
    nomsg = b''
    274+
    mymsg = b'msg'
    275+
    conflicting_call = re.escape(
    276+
    "'data' and 'string' are mutually exclusive "
    277+
    "and support for 'string' keyword parameter "
    278+
    "is slated for removal in a future version."
    279+
    )
    280+
    duplicated_param = re.escape("given by name ('data') and position")
    281+
    unexpected_param = re.escape("got an unexpected keyword argument '_'")
    282+
    for args, kwds, errmsg in [
    283+
    # Reject duplicated arguments before unknown keyword arguments.
    284+
    ((nomsg,), dict(data=nomsg, _=nomsg), duplicated_param),
    285+
    ((mymsg,), dict(data=nomsg, _=nomsg), duplicated_param),
    286+
    # Reject duplicated arguments before conflicting ones.
    287+
    *itertools.product(
    288+
    [[nomsg], [mymsg]],
    289+
    [dict(data=nomsg), dict(data=nomsg, string=nomsg)],
    290+
    [duplicated_param]
    291+
    ),
    292+
    # Reject unknown keyword arguments before conflicting ones.
    293+
    *itertools.product(
    294+
    [()],
    295+
    [
    296+
    dict(_=None),
    297+
    dict(data=nomsg, _=None),
    298+
    dict(string=nomsg, _=None),
    299+
    dict(string=nomsg, data=nomsg, _=None),
    300+
    ],
    301+
    [unexpected_param]
    302+
    ),
    303+
    ((nomsg,), dict(_=None), unexpected_param),
    304+
    ((mymsg,), dict(_=None), unexpected_param),
    305+
    # Reject conflicting arguments.
    306+
    [(nomsg,), dict(string=nomsg), conflicting_call],
    307+
    [(mymsg,), dict(string=nomsg), conflicting_call],
    308+
    [(), dict(data=nomsg, string=nomsg), conflicting_call],
    309+
    ]:
    310+
    for constructor in self.hash_constructors:
    311+
    digest_name = constructor(b'').name
    312+
    with self.subTest(constructor.__name__, args=args, kwds=kwds):
    313+
    with self.assertRaisesRegex(TypeError, errmsg):
    314+
    constructor(*args, **kwds)
    315+
    with self.subTest(digest_name, args=args, kwds=kwds):
    316+
    with self.assertRaisesRegex(TypeError, errmsg):
    317+
    hashlib.new(digest_name, *args, **kwds)
    318+
    if self._hashlib:
    319+
    with self.assertRaisesRegex(TypeError, errmsg):
    320+
    self._hashlib.new(digest_name, *args, **kwds)
    321+
    253322
    def test_unknown_hash(self):
    254323
    self.assertRaises(ValueError, hashlib.new, 'spam spam spam spam spam')
    255324
    self.assertRaises(TypeError, hashlib.new, 1)
    @@ -719,8 +788,6 @@ def check_blake2(self, constructor, salt_size, person_size, key_size,
    719788
    self.assertRaises(ValueError, constructor, node_offset=-1)
    720789
    self.assertRaises(OverflowError, constructor, node_offset=max_offset+1)
    721790

    722-
    self.assertRaises(TypeError, constructor, data=b'')
    723-
    self.assertRaises(TypeError, constructor, string=b'')
    724791
    self.assertRaises(TypeError, constructor, '')
    725792

    726793
    constructor(
    Lines changed: 5 additions & 0 deletions
    Original file line numberDiff line numberDiff line change
    @@ -0,0 +1,5 @@
    1+
    Built-in HACL* and OpenSSL implementations of hash function constructors
    2+
    now correctly accept the same *documented* named arguments. For instance,
    3+
    :func:`~hashlib.md5` could be previously invoked as ``md5(data=data)``
    4+
    or ``md5(string=string)`` depending on the underlying implementation
    5+
    but these calls were not compatible. Patch by Bénédikt Tran.

    0 commit comments

    Comments
     (0)
    0