From f8e2c92347925094c6b15057ee190307cc02fbe2 Mon Sep 17 00:00:00 2001 From: Gasper Zejn Date: Sun, 14 Apr 2019 11:43:30 +0200 Subject: [PATCH 1/3] Key.to_dict() now always returns JSON encodeable keys and values. Fixes #137. --- CHANGELOG.rst | 2 ++ jose/backends/cryptography_backend.py | 22 +++++++++++----------- jose/backends/ecdsa_backend.py | 6 +++--- jose/backends/pycrypto_backend.py | 16 ++++++++-------- jose/backends/rsa_backend.py | 16 ++++++++-------- jose/jwk.py | 2 +- tests/algorithms/test_EC.py | 4 ++++ tests/algorithms/test_HMAC.py | 6 +++++- tests/algorithms/test_RSA.py | 4 ++++ 9 files changed, 46 insertions(+), 32 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index b58692b4..91feea4b 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -25,6 +25,8 @@ Bugfixes * Fix invalid RSA private key PKCS8 encoding by python-rsa backend. `#120 `_ +* Fix to_dict output, which should always be JSON encodeable. + `#139 `_ Housekeeping """""""""""" diff --git a/jose/backends/cryptography_backend.py b/jose/backends/cryptography_backend.py index b9bdc0dc..58bef507 100644 --- a/jose/backends/cryptography_backend.py +++ b/jose/backends/cryptography_backend.py @@ -183,15 +183,15 @@ def to_dict(self): 'alg': self._algorithm, 'kty': 'EC', 'crv': crv, - 'x': long_to_base64(public_key.public_numbers().x, size=key_size), - 'y': long_to_base64(public_key.public_numbers().y, size=key_size), + 'x': long_to_base64(public_key.public_numbers().x, size=key_size).decode('ASCII'), + 'y': long_to_base64(public_key.public_numbers().y, size=key_size).decode('ASCII'), } if not self.is_public(): data['d'] = long_to_base64( self.prepared_key.private_numbers().private_value, size=key_size - ) + ).decode('ASCII') return data @@ -354,18 +354,18 @@ def to_dict(self): data = { 'alg': self._algorithm, 'kty': 'RSA', - 'n': long_to_base64(public_key.public_numbers().n), - 'e': long_to_base64(public_key.public_numbers().e), + 'n': long_to_base64(public_key.public_numbers().n).decode('ASCII'), + 'e': long_to_base64(public_key.public_numbers().e).decode('ASCII'), } if not self.is_public(): data.update({ - 'd': long_to_base64(self.prepared_key.private_numbers().d), - 'p': long_to_base64(self.prepared_key.private_numbers().p), - 'q': long_to_base64(self.prepared_key.private_numbers().q), - 'dp': long_to_base64(self.prepared_key.private_numbers().dmp1), - 'dq': long_to_base64(self.prepared_key.private_numbers().dmq1), - 'qi': long_to_base64(self.prepared_key.private_numbers().iqmp), + 'd': long_to_base64(self.prepared_key.private_numbers().d).decode('ASCII'), + 'p': long_to_base64(self.prepared_key.private_numbers().p).decode('ASCII'), + 'q': long_to_base64(self.prepared_key.private_numbers().q).decode('ASCII'), + 'dp': long_to_base64(self.prepared_key.private_numbers().dmp1).decode('ASCII'), + 'dq': long_to_base64(self.prepared_key.private_numbers().dmq1).decode('ASCII'), + 'qi': long_to_base64(self.prepared_key.private_numbers().iqmp).decode('ASCII'), }) return data diff --git a/jose/backends/ecdsa_backend.py b/jose/backends/ecdsa_backend.py index 8b8b9a23..4330f357 100644 --- a/jose/backends/ecdsa_backend.py +++ b/jose/backends/ecdsa_backend.py @@ -131,14 +131,14 @@ def to_dict(self): 'alg': self._algorithm, 'kty': 'EC', 'crv': crv, - 'x': long_to_base64(public_key.pubkey.point.x(), size=key_size), - 'y': long_to_base64(public_key.pubkey.point.y(), size=key_size), + 'x': long_to_base64(public_key.pubkey.point.x(), size=key_size).decode('ASCII'), + 'y': long_to_base64(public_key.pubkey.point.y(), size=key_size).decode('ASCII'), } if not self.is_public(): data['d'] = long_to_base64( self.prepared_key.privkey.secret_multiplier, size=key_size - ) + ).decode('ASCII') return data diff --git a/jose/backends/pycrypto_backend.py b/jose/backends/pycrypto_backend.py index a12e861c..1fd2afb1 100644 --- a/jose/backends/pycrypto_backend.py +++ b/jose/backends/pycrypto_backend.py @@ -185,8 +185,8 @@ def to_dict(self): data = { 'alg': self._algorithm, 'kty': 'RSA', - 'n': long_to_base64(self.prepared_key.n), - 'e': long_to_base64(self.prepared_key.e), + 'n': long_to_base64(self.prepared_key.n).decode('ASCII'), + 'e': long_to_base64(self.prepared_key.e).decode('ASCII'), } if not self.is_public(): @@ -201,12 +201,12 @@ def to_dict(self): dp = self.prepared_key.d % (self.prepared_key.p - 1) dq = self.prepared_key.d % (self.prepared_key.q - 1) data.update({ - 'd': long_to_base64(self.prepared_key.d), - 'p': long_to_base64(self.prepared_key.q), - 'q': long_to_base64(self.prepared_key.p), - 'dp': long_to_base64(dq), - 'dq': long_to_base64(dp), - 'qi': long_to_base64(self.prepared_key.u), + 'd': long_to_base64(self.prepared_key.d).decode('ASCII'), + 'p': long_to_base64(self.prepared_key.q).decode('ASCII'), + 'q': long_to_base64(self.prepared_key.p).decode('ASCII'), + 'dp': long_to_base64(dq).decode('ASCII'), + 'dq': long_to_base64(dp).decode('ASCII'), + 'qi': long_to_base64(self.prepared_key.u).decode('ASCII'), }) return data diff --git a/jose/backends/rsa_backend.py b/jose/backends/rsa_backend.py index c1f5539d..0f3511a3 100644 --- a/jose/backends/rsa_backend.py +++ b/jose/backends/rsa_backend.py @@ -246,18 +246,18 @@ def to_dict(self): data = { 'alg': self._algorithm, 'kty': 'RSA', - 'n': long_to_base64(public_key.n), - 'e': long_to_base64(public_key.e), + 'n': long_to_base64(public_key.n).decode('ASCII'), + 'e': long_to_base64(public_key.e).decode('ASCII'), } if not self.is_public(): data.update({ - 'd': long_to_base64(self._prepared_key.d), - 'p': long_to_base64(self._prepared_key.p), - 'q': long_to_base64(self._prepared_key.q), - 'dp': long_to_base64(self._prepared_key.exp1), - 'dq': long_to_base64(self._prepared_key.exp2), - 'qi': long_to_base64(self._prepared_key.coef), + 'd': long_to_base64(self._prepared_key.d).decode('ASCII'), + 'p': long_to_base64(self._prepared_key.p).decode('ASCII'), + 'q': long_to_base64(self._prepared_key.q).decode('ASCII'), + 'dp': long_to_base64(self._prepared_key.exp1).decode('ASCII'), + 'dq': long_to_base64(self._prepared_key.exp2).decode('ASCII'), + 'qi': long_to_base64(self._prepared_key.coef).decode('ASCII'), }) return data diff --git a/jose/jwk.py b/jose/jwk.py index 87f30b41..1b8b7dee 100644 --- a/jose/jwk.py +++ b/jose/jwk.py @@ -138,5 +138,5 @@ def to_dict(self): return { 'alg': self._algorithm, 'kty': 'oct', - 'k': base64url_encode(self.prepared_key), + 'k': base64url_encode(self.prepared_key).decode('ascii'), } diff --git a/tests/algorithms/test_EC.py b/tests/algorithms/test_EC.py index 7f012afb..1b946d9b 100644 --- a/tests/algorithms/test_EC.py +++ b/tests/algorithms/test_EC.py @@ -194,6 +194,10 @@ def assert_parameters(self, as_dict, private): # Private parameters should be absent assert 'd' not in as_dict + # as_dict should be serializable to JSON + import json + json.dumps(as_dict) + def test_to_dict(self): key = ECKey(private_key, ALGORITHMS.ES256) self.assert_parameters(key.to_dict(), private=True) diff --git a/tests/algorithms/test_HMAC.py b/tests/algorithms/test_HMAC.py index e84c2c02..59de30dc 100644 --- a/tests/algorithms/test_HMAC.py +++ b/tests/algorithms/test_HMAC.py @@ -31,7 +31,7 @@ def test_RSA_key(self): def test_to_dict(self): passphrase = 'The quick brown fox jumps over the lazy dog' - encoded = b'VGhlIHF1aWNrIGJyb3duIGZveCBqdW1wcyBvdmVyIHRoZSBsYXp5IGRvZw' + encoded = 'VGhlIHF1aWNrIGJyb3duIGZveCBqdW1wcyBvdmVyIHRoZSBsYXp5IGRvZw' key = HMACKey(passphrase, ALGORITHMS.HS256) as_dict = key.to_dict() @@ -43,3 +43,7 @@ def test_to_dict(self): assert 'k' in as_dict assert as_dict['k'] == encoded + + # as_dict should be serializable to JSON + import json + json.dumps(as_dict) diff --git a/tests/algorithms/test_RSA.py b/tests/algorithms/test_RSA.py index 97aeb20e..c7607052 100644 --- a/tests/algorithms/test_RSA.py +++ b/tests/algorithms/test_RSA.py @@ -370,6 +370,10 @@ def assert_parameters(self, as_dict, private): assert 'dq' not in as_dict assert 'qi' not in as_dict + # as_dict should be serializable to JSON + import json + json.dumps(as_dict) + def assert_roundtrip(self, key): assert RSAKey( key.to_dict(), From 3ef05cdd26c48ff8df16cbfe7d2c77a1cffa7853 Mon Sep 17 00:00:00 2001 From: blag Date: Tue, 17 Dec 2019 15:51:31 -0800 Subject: [PATCH 2/3] Import json at the top of the module --- tests/algorithms/test_EC.py | 2 +- tests/algorithms/test_HMAC.py | 2 +- tests/algorithms/test_RSA.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/algorithms/test_EC.py b/tests/algorithms/test_EC.py index 1b946d9b..62b952c5 100644 --- a/tests/algorithms/test_EC.py +++ b/tests/algorithms/test_EC.py @@ -1,3 +1,4 @@ +import json from jose.constants import ALGORITHMS from jose.exceptions import JOSEError, JWKError @@ -195,7 +196,6 @@ def assert_parameters(self, as_dict, private): assert 'd' not in as_dict # as_dict should be serializable to JSON - import json json.dumps(as_dict) def test_to_dict(self): diff --git a/tests/algorithms/test_HMAC.py b/tests/algorithms/test_HMAC.py index 59de30dc..843d3a28 100644 --- a/tests/algorithms/test_HMAC.py +++ b/tests/algorithms/test_HMAC.py @@ -1,3 +1,4 @@ +import json from jose.constants import ALGORITHMS from jose.exceptions import JOSEError @@ -45,5 +46,4 @@ def test_to_dict(self): assert as_dict['k'] == encoded # as_dict should be serializable to JSON - import json json.dumps(as_dict) diff --git a/tests/algorithms/test_RSA.py b/tests/algorithms/test_RSA.py index c7607052..cdcb1dae 100644 --- a/tests/algorithms/test_RSA.py +++ b/tests/algorithms/test_RSA.py @@ -1,4 +1,5 @@ import base64 +import json import sys try: @@ -371,7 +372,6 @@ def assert_parameters(self, as_dict, private): assert 'qi' not in as_dict # as_dict should be serializable to JSON - import json json.dumps(as_dict) def assert_roundtrip(self, key): From 9df2861f38d4c30b15793a00099d4e285024bf62 Mon Sep 17 00:00:00 2001 From: blag Date: Tue, 17 Dec 2019 15:51:55 -0800 Subject: [PATCH 3/3] Uppercase encoding name --- jose/jwk.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jose/jwk.py b/jose/jwk.py index c920e27f..b2c1113a 100644 --- a/jose/jwk.py +++ b/jose/jwk.py @@ -137,5 +137,5 @@ def to_dict(self): return { 'alg': self._algorithm, 'kty': 'oct', - 'k': base64url_encode(self.prepared_key).decode('ascii'), + 'k': base64url_encode(self.prepared_key).decode('ASCII'), }