Skip to content

Commit c85b638

Browse files
committed
Fixed a problem with going from a JWK dictionary to a JWK class instance.
1 parent 817440b commit c85b638

3 files changed

Lines changed: 90 additions & 6 deletions

File tree

doc/keyhandling.rst

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,67 @@ and::
8686
>>> ec_key.has_private_key()
8787
True
8888

89+
When it comes to exporting keys a :py:class:`cryptojwt.jwk.JWK` instance
90+
only know how to serialize into the format described in JWK_.
91+
92+
>>> from cryptojwt.jwk.rsa import new_rsa_key
93+
>>> rsa_key = new_rsa_key()
94+
>>> rsa_key.serialize()
95+
{
96+
'kty': 'RSA',
97+
'kid': 'NXhZYllJOXdLSW50aUVkcGY4XzZrSVF5blI5aEYxeEJDdFZLV2tHZDlFUQ',
98+
'n': 'xRgpX7q-kvQ02EhkHi63TQBR0RMcGCnxCugxtcPmaIX8brilwbkwQyZraEHzW
99+
zj-gaQyro_dWR7QqbhgiQ6U9Hj3x6HINJuw7LbqR_GE4TvTu3rJXPh3MqTs7yK6GcgK
100+
soTv8wQy6Pwl7gjrQRk37zfIHWLkxU-crz2dd1QdSmStlxRjbczik66llF5ENXE3wVz
101+
raPAdjIv1Y4n5dT3kw7QerVv2Dntn5TJ_8QSkmDJW-FA2TQbKBnOd_OgYeKZnGx5cng
102+
uWa23uQZTxfGnE7IXA2XYpZhHIgAGMXQ0SaR07MwIZDmreI_Mxypg2ES7XT42qhnxXU
103+
iGm9fA8nhHjwQ',
104+
'e': 'AQAB'
105+
}
106+
107+
108+
What you get when doing it like above is the representation of the public key.
109+
You can also get the values for the private key like this::
110+
111+
>>> from cryptojwt.jwk.rsa import new_rsa_key
112+
>>> rsa_key = new_rsa_key()
113+
>>> rsa_key.serialize(private=True)
114+
{
115+
'kty': 'RSA',
116+
'kid': 'NXhZYllJOXdLSW50aUVkcGY4XzZrSVF5blI5aEYxeEJDdFZLV2tHZDlFUQ',
117+
'n': 'xRgpX7q-kvQ02EhkHi63TQBR0RMcGCnxCugxtcPmaIX8brilwbkwQyZraEHz
118+
Wzj-gaQyro_dWR7QqbhgiQ6U9Hj3x6HINJuw7LbqR_GE4TvTu3rJXPh3MqTs7yK6Gc
119+
gKsoTv8wQy6Pwl7gjrQRk37zfIHWLkxU-crz2dd1QdSmStlxRjbczik66llF5ENXE3
120+
wVzraPAdjIv1Y4n5dT3kw7QerVv2Dntn5TJ_8QSkmDJW-FA2TQbKBnOd_OgYeKZnGx
121+
5cnguWa23uQZTxfGnE7IXA2XYpZhHIgAGMXQ0SaR07MwIZDmreI_Mxypg2ES7XT42q
122+
hnxXUiGm9fA8nhHjwQ',
123+
'e': 'AQAB',
124+
'd': 's-2jz73WvqdsGsqzg45YTlZtWrXcXv7jC3b_8pTdoiw3UAkHYXwjYBoR0cLr
125+
XCsCxO1WS2AQzYxBJ7-neVezih9o7Hl4IPbFJMSzymvlSA1q9OtaKqK1hqljl8gXJv
126+
QlN-X-e9coduPB6LWBtxNDqgI9kP44JRzRyHUybL6AYuk970_RoqxH2nr8FqMZbNWl
127+
Vk2X-v06EcO4E_ROSl8vqpb811UidXIvWAJw36LAUw0BTpdvpejSVM1B7PZWbzD91T
128+
4vwJYOAVdwWxpmA5HEXRbpNJLnMJus7iq7EVyG2ZbA4TXT-EIoASKMyxJtAuKMDk6c
129+
SISWay6LwjdBgVMAAQ',
130+
'p': '588dwE505-i7wL5mWkhH19xS1RzKahFhA66ZVmPjBaA88TBlaZxsdqEADwqX
131+
oMq_XIUh-P5Tc-ueiCw5rUVNTMb45HWr5fnQXtnJt4yMukNpERABIcWvZWLQg_ONW4
132+
iAKid9MLg5EYd2VkAAwXwzzdD1hiYEcxMwQVQ3nLmQ8AE',
133+
'q': '2amgmjQD5Jx7kAR-9oLFjnuvgbUMBOUieQKUCpeJu8q00S7kHb2Hy6ZsanJ-
134+
-Biu1XKz1lxelpN2upsjiKU7f08PB_IPCenBZIU3YwozZd15wCoSyKtffgqk5RXeyi
135+
3I1ULKXHxr3L7g-7Yi_APgtInQncNnm0Q_t7A_c-P888E'
136+
}
137+
138+
And you can of course create a key from a JWK representation::
139+
140+
>>> from cryptojwt.jwk.rsa import new_rsa_key
141+
>>> from cryptojwt.jwk.jwk import key_from_jwk_dict
142+
>>> rsa_key = new_rsa_key()
143+
>>> jwk = rsa_key.serialize(private=True)
144+
>>> _key = key_from_jwk_dict(jwk)
145+
>>> type(_key)
146+
<class 'cryptojwt.jwk.rsa.RSAKey'>
147+
>>> _key.has_private_key()
148+
True
149+
89150

90151

91152
.. _cryptography: https://cryptography.io/en/latest/

src/cryptojwt/jwk/jwk.py

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
from cryptography.hazmat import backends
44
from cryptography.hazmat.primitives.asymmetric import rsa
55
from cryptography.hazmat.primitives.asymmetric import ec
6+
from cryptography.hazmat.primitives.asymmetric.rsa import rsa_crt_dmp1
7+
from cryptography.hazmat.primitives.asymmetric.rsa import rsa_crt_dmq1
8+
from cryptography.hazmat.primitives.asymmetric.rsa import rsa_crt_iqmp
69

710
from ..exception import WrongKeyType
811
from ..exception import UnknownKeyType
@@ -53,13 +56,26 @@ def key_from_jwk_dict(jwk_dict):
5356
base64url_to_long(_jwk_dict["n"]))
5457
if _jwk_dict.get("p", None) is not None:
5558
# Rsa private key.
59+
p_long = base64url_to_long(_jwk_dict["p"])
60+
q_long = base64url_to_long(_jwk_dict["q"])
61+
d_long = base64url_to_long(_jwk_dict["d"])
62+
63+
if 'dp' not in _jwk_dict:
64+
dp_long = rsa_crt_dmp1(d_long, p_long)
65+
else:
66+
dp_long = base64url_to_long(_jwk_dict["dp"])
67+
if 'dq' not in _jwk_dict:
68+
dq_long = rsa_crt_dmq1(d_long, q_long)
69+
else:
70+
dq_long = base64url_to_long(_jwk_dict["dq"])
71+
if 'qi' not in _jwk_dict:
72+
qi_long = rsa_crt_iqmp(p_long, q_long)
73+
else:
74+
qi_long = base64url_to_long(_jwk_dict["qi"])
75+
5676
rsa_priv_numbers = rsa.RSAPrivateNumbers(
57-
base64url_to_long(_jwk_dict["p"]),
58-
base64url_to_long(_jwk_dict["q"]),
59-
base64url_to_long(_jwk_dict["d"]),
60-
base64url_to_long(_jwk_dict["dp"]),
61-
base64url_to_long(_jwk_dict["dq"]),
62-
base64url_to_long(_jwk_dict["qi"]), rsa_pub_numbers)
77+
p_long, q_long, d_long,
78+
dp_long, dq_long, qi_long, rsa_pub_numbers)
6379
_jwk_dict['priv_key'] = rsa_priv_numbers.private_key(
6480
backends.default_backend())
6581
_jwk_dict['pub_key'] = _jwk_dict['priv_key'].public_key()

tests/test_02_jwk.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -574,3 +574,10 @@ def test_load_pem_file_ec():
574574
key = ECKey().load(full_path('570-ec-sect571r1-keypair.pem'))
575575
assert key.has_private_key()
576576

577+
578+
def test_key_from_jwk_dict():
579+
rsa_key = new_rsa_key()
580+
jwk = rsa_key.serialize(private=True)
581+
_key = key_from_jwk_dict(jwk)
582+
assert isinstance(_key, RSAKey)
583+
assert _key.has_private_key()

0 commit comments

Comments
 (0)