1919from .hmac import SYMKey
2020
2121
22- def key_from_jwk_dict (jwk_dict ):
22+ EC_PUBLIC_REQUIRED = frozenset (['crv' , 'x' , 'y' ])
23+ EC_PUBLIC = EC_PUBLIC_REQUIRED
24+ EC_PRIVATE_REQUIRED = frozenset (['d' ])
25+ EC_PRIVATE_OPTIONAL = frozenset ()
26+ EC_PRIVATE = EC_PRIVATE_REQUIRED | EC_PRIVATE_OPTIONAL
27+
28+ RSA_PUBLIC_REQUIRED = frozenset (['e' , 'n' ])
29+ RSA_PUBLIC = RSA_PUBLIC_REQUIRED
30+ RSA_PRIVATE_REQUIRED = frozenset (['p' , 'q' , 'd' ])
31+ RSA_PRIVATE_OPTIONAL = frozenset (['qi' , 'dp' , 'dq' ])
32+ RSA_PRIVATE = RSA_PRIVATE_REQUIRED | RSA_PRIVATE_OPTIONAL
33+
34+
35+ def ensure_ec_params (jwk_dict , private ):
36+ """Ensure all required EC parameters are present in dictionary"""
37+ provided = frozenset (jwk_dict .keys ())
38+ if private is not None and private :
39+ required = EC_PUBLIC_REQUIRED | EC_PRIVATE_REQUIRED
40+ else :
41+ required = EC_PUBLIC_REQUIRED
42+ return ensure_params ('EC' , provided , required )
43+
44+
45+ def ensure_rsa_params (jwk_dict , private ):
46+ """Ensure all required RSA parameters are present in dictionary"""
47+ provided = frozenset (jwk_dict .keys ())
48+ if private is not None and private :
49+ required = RSA_PUBLIC_REQUIRED | RSA_PRIVATE_REQUIRED
50+ else :
51+ required = RSA_PUBLIC_REQUIRED
52+ return ensure_params ('RSA' , provided , required )
53+
54+
55+ def ensure_params (kty , provided , required ):
56+ """Ensure all required parameters are present in dictionary"""
57+ if not required <= provided :
58+ missing = required - provided
59+ raise MissingValue ('Missing properties for kty={}, {}' .format (kty , str (list (missing ))))
60+
61+
62+ def key_from_jwk_dict (jwk_dict , private = None ):
2363 """Load JWK from dictionary
2464
2565 :param jwk_dict: Dictionary representing a JWK
@@ -28,7 +68,17 @@ def key_from_jwk_dict(jwk_dict):
2868 # uncouple from the original item
2969 _jwk_dict = copy .copy (jwk_dict )
3070
71+ if 'kty' not in _jwk_dict :
72+ raise MissingValue ('kty missing' )
73+
3174 if _jwk_dict ['kty' ] == 'EC' :
75+ ensure_ec_params (_jwk_dict , private )
76+
77+ if private is not None and not private :
78+ # remove private components
79+ for v in EC_PRIVATE :
80+ _jwk_dict .pop (v , None )
81+
3282 if _jwk_dict ["crv" ] in NIST2SEC :
3383 curve = NIST2SEC [_jwk_dict ["crv" ]]()
3484 else :
@@ -50,6 +100,13 @@ def key_from_jwk_dict(jwk_dict):
50100 backends .default_backend ())
51101 return ECKey (** _jwk_dict )
52102 elif _jwk_dict ['kty' ] == 'RSA' :
103+ ensure_rsa_params (_jwk_dict , private )
104+
105+ if private is not None and not private :
106+ # remove private components
107+ for v in RSA_PRIVATE :
108+ _jwk_dict .pop (v , None )
109+
53110 rsa_pub_numbers = rsa .RSAPublicNumbers (
54111 base64url_to_long (_jwk_dict ["e" ]),
55112 base64url_to_long (_jwk_dict ["n" ]))
@@ -81,13 +138,13 @@ def key_from_jwk_dict(jwk_dict):
81138 else :
82139 _jwk_dict ['pub_key' ] = rsa_pub_numbers .public_key (
83140 backends .default_backend ())
84-
141+
85142 if _jwk_dict ['kty' ] != "RSA" :
86143 raise WrongKeyType ('"{}" should have been "RSA"' .format (_jwk_dict [
87144 'kty' ]))
88145 return RSAKey (** _jwk_dict )
89146 elif _jwk_dict ['kty' ] == 'oct' :
90- if not 'key' in _jwk_dict and not 'k' in _jwk_dict :
147+ if 'key' not in _jwk_dict and 'k' not in _jwk_dict :
91148 raise MissingValue (
92149 'There has to be one of "k" or "key" in a symmetric key' )
93150
0 commit comments