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(),