From 6577ac3e628beee946c467c68f2bf50da74243df Mon Sep 17 00:00:00 2001 From: Jimmy Zelinskie Date: Tue, 12 Apr 2016 13:36:17 -0400 Subject: [PATCH] mv JWK-canonicalization util.security.fingerprint --- data/model/service_keys.py | 7 ++----- util/__init__.py | 13 ------------- util/security/fingerprint.py | 35 +++++++++++++++++++++++++++++++++++ 3 files changed, 37 insertions(+), 18 deletions(-) create mode 100644 util/security/fingerprint.py diff --git a/data/model/service_keys.py b/data/model/service_keys.py index 49d70894a..784fb245e 100644 --- a/data/model/service_keys.py +++ b/data/model/service_keys.py @@ -1,8 +1,5 @@ -import json - from calendar import timegm from datetime import datetime, timedelta -from hashlib import sha256 from peewee import JOIN_LEFT_OUTER from Crypto.PublicKey import RSA @@ -11,7 +8,7 @@ from jwkest.jwk import RSAKey from data.database import db_for_update, User, ServiceKey, ServiceKeyApproval from data.model import ServiceKeyDoesNotExist, ServiceKeyAlreadyApproved, db_transaction, config from data.model.notification import create_notification, delete_all_notifications_by_path_prefix -from util import canonicalize +from util.security.fingerprint import canonical_kid def _expired_keys_clause(service): @@ -64,7 +61,7 @@ def generate_service_key(service, expiration_date, kid=None, name='', metadata=N private_key = RSA.generate(2048) jwk = RSAKey(key=private_key.publickey()).serialize() if kid is None: - kid = sha256(json.dumps(canonicalize(jwk), separators=(',', ':'))).hexdigest() + kid = canonical_kid(jwk) key = create_service_key(name, kid, service, jwk, metadata or {}, expiration_date) return (private_key, key) diff --git a/util/__init__.py b/util/__init__.py index 3b0d911d9..c45aad78f 100644 --- a/util/__init__.py +++ b/util/__init__.py @@ -1,6 +1,3 @@ -import collections - - def get_app_url(config): """ Returns the application's URL, based on the given config. """ return '%s://%s' % (config['PREFERRED_URL_SCHEME'], config['SERVER_HOSTNAME']) @@ -19,13 +16,3 @@ def slash_join(*args): args = [rmslash(path) for path in args] return '/'.join(args) - - -def canonicalize(json_obj): - """ Returns a JSON object sorted by key. """ - if isinstance(json_obj, collections.MutableMapping): - sorted_obj = sorted({key: canonicalize(val) for key, val in json_obj.items()}.items()) - return collections.OrderedDict(sorted_obj) - elif isinstance(json_obj, (list, tuple)): - return [canonicalize(val) for val in json_obj] - return json_obj diff --git a/util/security/fingerprint.py b/util/security/fingerprint.py new file mode 100644 index 000000000..1341d5780 --- /dev/null +++ b/util/security/fingerprint.py @@ -0,0 +1,35 @@ +import collections +import json + +from hashlib import sha256 + + +def canonicalize(json_obj): + """This function canonicalizes a Python object that will be serialized as JSON. + + Args: + json_obj (object): the Python object that will later be serialized as JSON. + + Returns: + object: json_obj now sorted to its canonical form. + + """ + if isinstance(json_obj, collections.MutableMapping): + sorted_obj = sorted({key: canonicalize(val) for key, val in json_obj.items()}.items()) + return collections.OrderedDict(sorted_obj) + elif isinstance(json_obj, (list, tuple)): + return [canonicalize(val) for val in json_obj] + return json_obj + + +def canonical_kid(jwk): + """This function returns the SHA256 hash of a canonical JWK. + + Args: + jwk (object): the JWK for which a kid will be generated. + + Returns: + string: the unique kid for the given JWK. + + """ + return sha256(json.dumps(canonicalize(jwk), separators=(',', ':'))).hexdigest()