Avoid possible timing attack in metadata api

Introduce a constant time comparison function to
nova utils for comparing authentication tokens.

Conflicts:
	nova/utils.py

Closes-bug: #1325128
Change-Id: I7374f2edc6f03c7da59cf73ae91a87147e53d0de
(cherry picked from commit 4a60c6a655)
This commit is contained in:
Grant Murphy 2014-07-08 03:35:40 +00:00
parent a4cf7c1142
commit 9f59ca751f
3 changed files with 27 additions and 1 deletions

View File

@ -30,6 +30,7 @@ from nova import exception
from nova.openstack.common.gettextutils import _
from nova.openstack.common import log as logging
from nova.openstack.common import memorycache
from nova import utils
from nova import wsgi
CACHE_EXPIRATION = 15 # in seconds
@ -169,7 +170,7 @@ class MetadataRequestHandler(wsgi.Application):
instance_id,
hashlib.sha256).hexdigest()
if expected_signature != signature:
if not utils.constant_time_compare(expected_signature, signature):
if instance_id:
LOG.warn(_('X-Instance-ID-Signature: %(signature)s does not '
'match the expected value: %(expected_signature)s '

View File

@ -979,3 +979,10 @@ class VersionTestCase(test.NoDBTestCase):
def test_convert_version_to_tuple(self):
self.assertEqual(utils.convert_version_to_tuple('6.7.0'), (6, 7, 0))
class ConstantTimeCompareTestCase(test.NoDBTestCase):
def test_constant_time_compare(self):
self.assertTrue(utils.constant_time_compare("abcd1234", "abcd1234"))
self.assertFalse(utils.constant_time_compare("abcd1234", "a"))
self.assertFalse(utils.constant_time_compare("abcd1234", "ABCD234"))

View File

@ -21,6 +21,7 @@ import contextlib
import datetime
import functools
import hashlib
import hmac
import inspect
import multiprocessing
import os
@ -1170,3 +1171,20 @@ def cpu_count():
return multiprocessing.cpu_count()
except NotImplementedError:
return 1
if hasattr(hmac, 'compare_digest'):
constant_time_compare = hmac.compare_digest
else:
def constant_time_compare(first, second):
"""Returns True if both string inputs are equal, otherwise False.
This function should take a constant amount of time regardless of
how many characters in the strings match.
"""
if len(first) != len(second):
return False
result = 0
for x, y in zip(first, second):
result |= ord(x) ^ ord(y)
return result == 0