Skip to content

Commit 8ed682b

Browse files
committed
PYTHON-974 - Use appropriate hash comparators for sensitive functions
1 parent 202215d commit 8ed682b

File tree

1 file changed

+30
-1
lines changed

1 file changed

+30
-1
lines changed

pymongo/auth.py

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,35 @@ def _digest(msg, mac=mac):
131131
_ui ^= from_bytes(_u1, 'big')
132132
return to_bytes(_ui, 20, 'big')
133133

134+
try:
135+
from hmac import compare_digest
136+
except ImportError:
137+
if PY3:
138+
def _xor_bytes(a, b):
139+
return a ^ b
140+
else:
141+
def _xor_bytes(a, b, _ord=ord):
142+
return _ord(a) ^ _ord(b)
143+
144+
# Python 2.x < 2.7.7 and Python 3.x < 3.3
145+
# References:
146+
# - http://bugs.python.org/issue14532
147+
# - http://bugs.python.org/issue14955
148+
# - http://bugs.python.org/issue15061
149+
def compare_digest(a, b, _xor_bytes=_xor_bytes):
150+
left = None
151+
right = b
152+
if len(a) == len(b):
153+
left = a
154+
result = 0
155+
if len(a) != len(b):
156+
left = b
157+
result = 1
158+
159+
for x, y in zip(left, right):
160+
result |= _xor_bytes(x, y)
161+
return result == 0
162+
134163

135164
def _parse_scram_response(response):
136165
"""Split a scram response into key, value pairs."""
@@ -187,7 +216,7 @@ def _authenticate_scram_sha1(credentials, sock_info):
187216
res = sock_info.command(source, cmd)
188217

189218
parsed = _parse_scram_response(res['payload'])
190-
if parsed[b'v'] != server_sig:
219+
if not compare_digest(parsed[b'v'], server_sig):
191220
raise OperationFailure("Server returned an invalid signature.")
192221

193222
# Depending on how it's configured, Cyrus SASL (which the server uses)

0 commit comments

Comments
 (0)