Skip to content

Commit 1188f4a

Browse files
committed
fix how large messages and keys are rejected by HMAC
1 parent 1e67293 commit 1188f4a

File tree

3 files changed

+73
-5
lines changed

3 files changed

+73
-5
lines changed

Lib/hmac.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -241,13 +241,23 @@ def digest(key, msg, digest):
241241
if _hashopenssl and isinstance(digest, (str, _functype)):
242242
try:
243243
return _hashopenssl.hmac_digest(key, msg, digest)
244+
except OverflowError:
245+
try:
246+
return _hashopenssl.hmac_new(key, msg, digest).digest()
247+
except _hashopenssl.UnsupportedDigestmodError:
248+
pass
244249
except _hashopenssl.UnsupportedDigestmodError:
245250
pass
246251

247252
if _hmac and isinstance(digest, str):
248253
try:
249254
return _hmac.compute_digest(key, msg, digest)
250-
except (OverflowError, _hmac.UnknownHashError):
255+
except OverflowError:
256+
try:
257+
return _hmac.new(key, msg, digest).digest()
258+
except _hmac.UnknownHashError:
259+
pass
260+
except _hmac.UnknownHashError:
251261
pass
252262

253263
return _compute_digest_fallback(key, msg, digest)

Lib/test/test_hmac.py

Lines changed: 59 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,20 +21,22 @@
2121
import hmac
2222
import hashlib
2323
import random
24-
import test.support.hashlib_helper as hashlib_helper
2524
import types
2625
import unittest
2726
import unittest.mock as mock
2827
import warnings
2928
from _operator import _compare_digest as operator_compare_digest
29+
from test.support import _4G, bigmemtest
3030
from test.support import check_disallow_instantiation
31+
from test.support import hashlib_helper, import_helper
3132
from test.support.hashlib_helper import (
3233
BuiltinHashFunctionsTrait,
3334
HashFunctionsTrait,
3435
NamedHashFunctionsTrait,
3536
OpenSSLHashFunctionsTrait,
3637
)
37-
from test.support.import_helper import import_fresh_module, import_module
38+
from test.support.import_helper import import_fresh_module
39+
from unittest.mock import patch
3840

3941
try:
4042
import _hashlib
@@ -949,7 +951,11 @@ class PyConstructorTestCase(ThroughObjectMixin, PyConstructorBaseMixin,
949951

950952
class PyModuleConstructorTestCase(ThroughModuleAPIMixin, PyConstructorBaseMixin,
951953
unittest.TestCase):
952-
"""Test the hmac.new() and hmac.digest() functions."""
954+
"""Test the hmac.new() and hmac.digest() functions.
955+
956+
Note that "self.hmac" is imported by blocking "_hashlib" and "_hmac".
957+
For testing functions in "hmac", extend PyMiscellaneousTests instead.
958+
"""
953959

954960
def test_hmac_digest_digestmod_parameter(self):
955961
func = self.hmac_digest
@@ -1499,6 +1505,55 @@ def test_with_fallback(self):
14991505
finally:
15001506
cache.pop('foo')
15011507

1508+
@hashlib_helper.requires_openssl_hashdigest("md5")
1509+
@bigmemtest(size=_4G, memuse=2, dry_run=False)
1510+
def test_hmac_digest_overflow_error_openssl_only(self, size):
1511+
self.do_test_hmac_digest_overflow_error_fast(size, openssl=True)
1512+
1513+
@hashlib_helper.requires_builtin_hashdigest("_md5", "md5")
1514+
@bigmemtest(size=_4G , memuse=2, dry_run=False)
1515+
def test_hmac_digest_overflow_error_builtin_only(self, size):
1516+
self.do_test_hmac_digest_overflow_error_fast(size, openssl=False)
1517+
1518+
def do_test_hmac_digest_overflow_error_fast(self, size, *, openssl):
1519+
"""Check that C hmac.digest() works for large inputs."""
1520+
1521+
if openssl:
1522+
hmac = import_fresh_module("hmac", blocked=["_hashlib"])
1523+
c_module_name, c_method_name = "_hmac", "new"
1524+
else:
1525+
hmac = import_fresh_module("hmac", blocked=["_hmac"])
1526+
c_module_name, c_method_name = "_hashlib", "hmac_new"
1527+
1528+
cext = import_helper.import_module(c_module_name)
1529+
cnew = getattr(cext, c_method_name)
1530+
1531+
bigkey = b'K' * size
1532+
bigmsg = b'M' * size
1533+
1534+
with patch.object(hmac, "_compute_digest_fallback") as slow:
1535+
with patch.object(cext, c_method_name, wraps=cnew) as new:
1536+
self.assertIsInstance(hmac.digest(bigkey, b'm', "md5"), bytes)
1537+
new.assert_called_once()
1538+
with patch.object(cext, c_method_name, wraps=cnew) as new:
1539+
self.assertIsInstance(hmac.digest(b'k', bigmsg, "md5"), bytes)
1540+
new.assert_called_once()
1541+
slow.assert_not_called()
1542+
1543+
@hashlib_helper.requires_hashdigest("md5", openssl=True)
1544+
@bigmemtest(size=_4G, memuse=2, dry_run=False)
1545+
def test_hmac_digest_no_overflow_error_in_fallback(self, size):
1546+
hmac = import_fresh_module("hmac", blocked=["_hashlib", "_hmac"])
1547+
1548+
for key, msg in [(b'K' * size, b'm'), (b'k', b'M' * size)]:
1549+
with self.subTest(keysize=len(key), msgsize=len(msg)):
1550+
with unittest.mock.patch.object(
1551+
hmac, "_compute_digest_fallback",
1552+
wraps=hmac._compute_digest_fallback,
1553+
) as f:
1554+
self.assertIsInstance(hmac.digest(key, msg, "md5"), bytes)
1555+
f.assert_called_once()
1556+
15021557

15031558
class BuiltinMiscellaneousTests(BuiltinModuleMixin, unittest.TestCase):
15041559
"""HMAC-BLAKE2 is not standardized as BLAKE2 is a keyed hash function.
@@ -1511,7 +1566,7 @@ class BuiltinMiscellaneousTests(BuiltinModuleMixin, unittest.TestCase):
15111566
@classmethod
15121567
def setUpClass(cls):
15131568
super().setUpClass()
1514-
cls.blake2 = import_module("_blake2")
1569+
cls.blake2 = import_helper.import_module("_blake2")
15151570
cls.blake2b = cls.blake2.blake2b
15161571
cls.blake2s = cls.blake2.blake2s
15171572

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
:func:`hmac.digest` now properly rejects keys and messages whose length
2+
exceeds its capabililties. The exact limit is implementation-defined. Patch
3+
by Bénédikt Tran.

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy