def _validate_json_jws(self, payload_segment, payload, header_obj, key): protected_segment = header_obj.get('protected') if not protected_segment: raise DecodeError('Missing "protected" value') signature_segment = header_obj.get('signature') if not signature_segment: raise DecodeError('Missing "signature" value') protected_segment = to_bytes(protected_segment) protected = _extract_header(protected_segment) header = header_obj.get('header') if header and not isinstance(header, dict): raise DecodeError('Invalid "header" value') jws_header = JWSHeader(protected, header) self._validate_header(jws_header) algorithm, key = prepare_algorithm_key(self._algorithms, jws_header, payload, key) signing_input = b'.'.join([protected_segment, payload_segment]) signature = _extract_signature(to_bytes(signature_segment)) if algorithm.verify(signing_input, key, signature): return jws_header, True return jws_header, False
def serialize_compact(self, protected, payload, key): """Generate a JWS Compact Serialization. The JWS Compact Serialization represents digitally signed or MACed content as a compact, URL-safe string, per `Section 7.1`_. .. code-block:: text BASE64URL(UTF8(JWS Protected Header)) || '.' || BASE64URL(JWS Payload) || '.' || BASE64URL(JWS Signature) :param protected: A dict of protected header :param payload: A bytes/string of payload :param key: Private key used to generate signature :return: byte """ jws_header = JWSHeader(protected, None) self._validate_header(jws_header) protected_segment = json_b64encode(jws_header.protected) payload_segment = urlsafe_b64encode(to_bytes(payload)) # calculate signature signing_input = b'.'.join([protected_segment, payload_segment]) algorithm, key = prepare_algorithm_key(self._algorithms, jws_header, payload, key, private=True) signature = urlsafe_b64encode(algorithm.sign(signing_input, key)) return b'.'.join([protected_segment, payload_segment, signature])
def _prepare_alg_enc_key(self, header, key, private=False): algorithm, key = prepare_algorithm_key(self._alg_algorithms, header, None, key, private=private) enc_alg = self._enc_algorithms[header['enc']] return algorithm, enc_alg, key
def _sign(jws_header): self._validate_header(jws_header) _alg, _key = prepare_algorithm_key(self._algorithms, jws_header, payload, key) protected_segment = json_b64encode(jws_header.protected) signing_input = b'.'.join([protected_segment, payload_segment]) signature = urlsafe_b64encode(_alg.sign(signing_input, _key)) rv = { 'protected': to_unicode(protected_segment), 'signature': to_unicode(signature) } if jws_header.header is not None: rv['header'] = jws_header.header return rv
def deserialize_compact(self, s, key, decode=None): """Exact JWS Compact Serialization, and validate with the given key. If key is not provided, the returned dict will contain the signature, and signing input values. Via `Section 7.1`_. :param s: text of JWS Compact Serialization :param key: key used to verify the signature :param decode: a function to decode payload data :return: JWSObject :raise: BadSignatureError .. _`Section 7.1`: https://tools.ietf.org/html/rfc7515#section-7.1 """ try: s = to_bytes(s) signing_input, signature_segment = s.rsplit(b'.', 1) protected_segment, payload_segment = signing_input.split(b'.', 1) except ValueError: raise DecodeError('Not enough segments') protected = _extract_header(protected_segment) jws_header = JWSHeader(protected, None) payload = _extract_payload(payload_segment) if decode: payload = decode(payload) signature = _extract_signature(signature_segment) self._validate_header(jws_header) rv = JWSObject(jws_header, payload, 'compact') algorithm, key = prepare_algorithm_key(self._algorithms, jws_header, payload, key) if algorithm.verify(signing_input, key, signature): return rv raise BadSignatureError(rv)