codekingpro/portable-devtools
114k
1import hashlib2from collections import OrderedDict3from authlib.common.encoding import (4 json_dumps,5 to_bytes,6 to_unicode,7 urlsafe_b64encode,8)9from ..errors import InvalidUseError10 11 12class Key:13 """This is the base class for a JSON Web Key."""14 kty = '_'15 16 ALLOWED_PARAMS = [17 'use', 'key_ops', 'alg', 'kid',18 'x5u', 'x5c', 'x5t', 'x5t#S256'19 ]20 21 PRIVATE_KEY_OPS = [22 'sign', 'decrypt', 'unwrapKey',23 ]24 PUBLIC_KEY_OPS = [25 'verify', 'encrypt', 'wrapKey',26 ]27 28 REQUIRED_JSON_FIELDS = []29 30 def __init__(self, options=None):31 self.options = options or {}32 self._dict_data = {}33 34 @property35 def tokens(self):36 if not self._dict_data:37 self.load_dict_key()38 39 rv = dict(self._dict_data)40 rv['kty'] = self.kty41 for k in self.ALLOWED_PARAMS:42 if k not in rv and k in self.options:43 rv[k] = self.options[k]44 return rv45 46 @property47 def kid(self):48 return self.tokens.get('kid')49 50 def keys(self):51 return self.tokens.keys()52 53 def __getitem__(self, item):54 return self.tokens[item]55 56 @property57 def public_only(self):58 raise NotImplementedError()59 60 def load_raw_key(self):61 raise NotImplementedError()62 63 def load_dict_key(self):64 raise NotImplementedError()65 66 def check_key_op(self, operation):67 """Check if the given key_op is supported by this key.68 69 :param operation: key operation value, such as "sign", "encrypt".70 :raise: ValueError71 """72 key_ops = self.tokens.get('key_ops')73 if key_ops is not None and operation not in key_ops:74 raise ValueError(f'Unsupported key_op "{operation}"')75 76 if operation in self.PRIVATE_KEY_OPS and self.public_only:77 raise ValueError(f'Invalid key_op "{operation}" for public key')78 79 use = self.tokens.get('use')80 if use:81 if operation in ['sign', 'verify']:82 if use != 'sig':83 raise InvalidUseError()84 elif operation in ['decrypt', 'encrypt', 'wrapKey', 'unwrapKey']:85 if use != 'enc':86 raise InvalidUseError()87 88 def as_dict(self, is_private=False, **params):89 raise NotImplementedError()90 91 def as_json(self, is_private=False, **params):92 """Represent this key as a JSON string."""93 obj = self.as_dict(is_private, **params)94 return json_dumps(obj)95 96 def thumbprint(self):97 """Implementation of RFC7638 JSON Web Key (JWK) Thumbprint."""98 fields = list(self.REQUIRED_JSON_FIELDS)99 fields.append('kty')100 fields.sort()101 data = OrderedDict()102 103 for k in fields:104 data[k] = self.tokens[k]105 106 json_data = json_dumps(data)107 digest_data = hashlib.sha256(to_bytes(json_data)).digest()108 return to_unicode(urlsafe_b64encode(digest_data))109 110 @classmethod111 def check_required_fields(cls, data):112 for k in cls.REQUIRED_JSON_FIELDS:113 if k not in data:114 raise ValueError(f'Missing required field: "{k}"')115 116 @classmethod117 def validate_raw_key(cls, key):118 raise NotImplementedError()119 