Avoid possible timing attack in metadata api

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

Conflicts:
	nova/tests/test_utils.py
	nova/utils.py

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

View File

@ -31,6 +31,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
@ -172,7 +173,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

@ -1083,3 +1083,10 @@ class GetImageFromSystemMetadataTestCase(test.NoDBTestCase):
# Verify that the foo1 key has not been inherited
self.assertTrue("foo1" not in image)
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

@ -23,6 +23,7 @@ import contextlib
import datetime
import functools
import hashlib
import hmac
import inspect
import os
import pyclbr
@ -1302,3 +1303,20 @@ def get_boolean(value):
return value
else:
return strutils.bool_from_string(value)
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