X-Git-Url: https://code.grnet.gr/git/ganeti-local/blobdiff_plain/02141fb152addda9835956ab84287c559e297371..31155d60eed6d14d25979c41c031f746e51d3c7d:/lib/serializer.py diff --git a/lib/serializer.py b/lib/serializer.py index 43dfaa7..9a5f1ce 100644 --- a/lib/serializer.py +++ b/lib/serializer.py @@ -24,17 +24,16 @@ This module introduces a simple abstraction over the serialization backend (currently json). """ +# pylint: disable-msg=C0103 + +# C0103: Invalid name, since pylint doesn't see that Dump points to a +# function and not a constant import simplejson import re -import hmac from ganeti import errors - -try: - from hashlib import sha1 -except ImportError: - import sha as sha1 +from ganeti import utils _JSON_INDENT = 2 @@ -97,11 +96,13 @@ def LoadJson(txt): return simplejson.loads(txt) -def DumpSignedJson(data, key, salt=None): +def DumpSignedJson(data, key, salt=None, key_selector=None): """Serialize a given object and authenticate it. @param data: the data to serialize @param key: shared hmac key + @param key_selector: name/id that identifies the key (in case there are + multiple keys in use, e.g. in a multi-cluster environment) @return: the string representation of data signed by the hmac key """ @@ -111,8 +112,15 @@ def DumpSignedJson(data, key, salt=None): signed_dict = { 'msg': txt, 'salt': salt, - 'hmac': hmac.new(key, salt + txt, sha1).hexdigest(), - } + } + + if key_selector: + signed_dict["key_selector"] = key_selector + else: + key_selector = "" + + signed_dict["hmac"] = utils.Sha1Hmac(key, txt, salt=salt + key_selector) + return DumpJson(signed_dict, indent=False) @@ -120,7 +128,9 @@ def LoadSignedJson(txt, key): """Verify that a given message was signed with the given key, and load it. @param txt: json-encoded hmac-signed message - @param key: shared hmac key + @param key: the shared hmac key or a callable taking one argument (the key + selector), which returns the hmac key belonging to the key selector. + Typical usage is to pass a reference to the get method of a dict. @rtype: tuple of original data, string @return: original data, salt @raises errors.SignatureError: if the message signature doesn't verify @@ -136,7 +146,19 @@ def LoadSignedJson(txt, key): except KeyError: raise errors.SignatureError('Invalid external message') - if hmac.new(key, salt + msg, sha1).hexdigest() != hmac_sign: + if callable(key): + # pylint: disable-msg=E1103 + key_selector = signed_dict.get("key_selector", None) + hmac_key = key(key_selector) + if not hmac_key: + raise errors.SignatureError("No key with key selector '%s' found" % + key_selector) + else: + key_selector = "" + hmac_key = key + + if not utils.VerifySha1Hmac(hmac_key, msg, hmac_sign, + salt=salt + key_selector): raise errors.SignatureError('Invalid Signature') return LoadJson(msg), salt