Avoid possible timing attack in metadata api

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

Change-Id: I7374f2edc6f03c7da59cf73ae91a87147e53d0de
Closes-bug: #1325128
This commit is contained in:
Grant Murphy 2014-07-08 03:35:40 +00:00
parent 62d4d458d6
commit 4a60c6a655
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
@ -175,7 +176,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

@ -962,3 +962,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 os
import pyclbr
@ -1144,3 +1145,20 @@ def get_image_from_system_metadata(system_meta):
def get_hash_str(base_str):
"""returns string that represents hash of base_str (in hex format)."""
return hashlib.md5(base_str).hexdigest()
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