Skip to content

Extend and improve the importing and exporting of keys.#52

Merged
mpdavis merged 8 commits intompdavis:masterfrom
TobiasKappe:pullreq-serialization-deserialization
Jun 6, 2017
Merged

Extend and improve the importing and exporting of keys.#52
mpdavis merged 8 commits intompdavis:masterfrom
TobiasKappe:pullreq-serialization-deserialization

Conversation

@TobiasKappe
Copy link
Contributor

I noticed that the current library does not have functionality to export a Key implementation to a JWK as specified in RFC7518. This PR adds a method called as_dict to every Key implementation, which returns a dictionary version of the JWK, ready to be exported to JSON.

I also added functionality to the _process_jwk functions to recognize when a dictionary encodes a private key, and import the private key parameters if possible.

As far as I can tell, the curve P-256 in RFC7518 refers to the curve secp256r1
(which is also the curve supported elsewhere in the code), not the curve
secp256k1.
…entation.

To export a key in JSON, i.e., according to RFC7518, we need to obtain some
values from the backend and return those as a dictionary. This commit takes
care of that by implementing the as_dict function on all backends.
Up until now, the private components of a JWK dictionary were ignored when
constructing the key. This commit changes that by reading the private
parameters and passing them to the backend to generate a private key, if those
parameters are present.
"d": "AAhRON2r9cqXX1hg-RoI6R1tX5p2rUAYdmpHZoC1XNM56KtscrX6zbKipQrCW9CGZH3T4ubpnoTKLDYJ_fF3_rJt",
}

ECDSAECKey(key, ALGORITHMS.ES512)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be sensible to check if the keys returned are actually public or private in this test.

@codecov-io
Copy link

codecov-io commented May 14, 2017

Codecov Report

Merging #52 into master will decrease coverage by 1.11%.
The diff coverage is 87.87%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master      #52      +/-   ##
==========================================
- Coverage   95.64%   94.52%   -1.12%     
==========================================
  Files          12       12              
  Lines         734      840     +106     
==========================================
+ Hits          702      794      +92     
- Misses         32       46      +14
Impacted Files Coverage Δ
jose/backends/pycrypto_backend.py 97.11% <100%> (+0.68%) ⬆️
jose/backends/cryptography_backend.py 100% <100%> (ø) ⬆️
jose/jwk.py 95.12% <100%> (+0.18%) ⬆️
jose/utils.py 73.68% <22.22%> (-23.76%) ⬇️
jose/backends/base.py 76.92% <50%> (-4.9%) ⬇️
jose/backends/ecdsa_backend.py 98.66% <96%> (+2.05%) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 7403dff...b5bc420. Read the comment docs.

@mpdavis
Copy link
Owner

mpdavis commented May 15, 2017

@TobiasKappe I appreciate the contribution.

I need to look over it in more depth, but at first look this appears to be good. I agree that this functionality is beneficial to the library.

Copy link
Owner

@mpdavis mpdavis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Other than some nit-picky comments about splitting up unit tests, this looks great to me.

Again, I appreciate you jumping in.

with pytest.raises(JWKError):
ECDSAECKey({'kty': 'bla'}, ALGORITHMS.ES256)

def test_EC_jwk(self):
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know that it makes for some duplicate code, but can you split this test into separate tests? I get much more value out of seeing every test that fails in a single test run instead of fixing one portion of a test only to see another portion has failed.

I see this as:

  • test_ECDSAECKey_public_jwk
  • test_ECDSAECKey_private_jwk
  • test_ECDSAECKey_invalid_jwk
  • test_CryptographyECKey_public_jwk
  • test_CryptographyECKey_private_jwk
  • test_CryptographyECKey_invalid_jwk

# Private parameters should be absent
assert 'd' not in as_dict

def test_to_dict(self):
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Split this into:

  • test_CryptographyECKey_public_to_dict
  • test_CryptographyECKey_private_to_dict
  • test_ ECDSAECKey_public_to_dict
  • test_ ECDSAECKey_private_to_dict

@@ -118,12 +120,47 @@ def test_invalid_algorithm(self):
CryptographyRSAKey({'kty': 'bla'}, ALGORITHMS.RS256)

def test_RSA_jwk(self):
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Split this up.

def assert_roundtrip(self, key, impl):
assert impl(key.to_dict(), ALGORITHMS.RS256).to_dict() == key.to_dict()

def test_to_dict(self):
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Split this up.

@TobiasKappe
Copy link
Contributor Author

Sure, splitting up the tests is a good idea. I'll get on this later today.

…rors.

This is to mirror the behavior of the PyCrypto backend.
Some tests had duplicated code within them to test for backends, and for other
tests there were different testing harnesses that tested parts of each backend.
This commit unifies the tests to be as backend-agnostic as possible, and
execute them for each backend using pytest's parametrization.
@TobiasKappe
Copy link
Contributor Author

Any further feedback?

@mpdavis
Copy link
Owner

mpdavis commented Jun 6, 2017

@TobiasKappe No, this looks great! I apologize for the wait, I was skimming this too quickly and reading too much into the "failing" checks.

I appreciate the work!

@mpdavis mpdavis merged commit b54c12a into mpdavis:master Jun 6, 2017
@TobiasKappe
Copy link
Contributor Author

Great, thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants