Beispiel #1
0
  def test_signed_compact_create_split(self):
    payload = '{"iss":"joe"}'
    signature = _jwt_format.decode_signature(
        b'dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk')
    unsigned_compact = _jwt_format.create_unsigned_compact(
        'RS256', 'JWT', None, payload)
    signed_compact = _jwt_format.create_signed_compact(unsigned_compact,
                                                       signature)
    un_comp, hdr, pay, sig = _jwt_format.split_signed_compact(signed_compact)

    self.assertEqual(
        unsigned_compact,
        b'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJqb2UifQ')
    self.assertEqual(
        signed_compact, 'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.'
        'eyJpc3MiOiJqb2UifQ.dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk')
    self.assertEqual(un_comp, unsigned_compact)
    self.assertEqual(sig, signature)
    self.assertEqual(hdr, '{"alg":"RS256","typ":"JWT"}')
    header = _jwt_format.json_loads(hdr)
    _jwt_format.validate_header(header, 'RS256')
    self.assertEqual(pay, payload)
    self.assertEqual(_jwt_format.get_type_header(header), 'JWT')
Beispiel #2
0
  def test_signed_compact_create_split_with_kid(self):
    payload = '{"iss":"joe"}'
    signature = _jwt_format.decode_signature(
        b'dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk')
    unsigned_compact = _jwt_format.create_unsigned_compact(
        'RS256', None, 'AZxkm2U', payload)
    signed_compact = _jwt_format.create_signed_compact(unsigned_compact,
                                                       signature)
    un_comp, hdr, pay, sig = _jwt_format.split_signed_compact(signed_compact)

    self.assertEqual(
        unsigned_compact,
        b'eyJraWQiOiJBWnhrbTJVIiwiYWxnIjoiUlMyNTYifQ.eyJpc3MiOiJqb2UifQ')
    self.assertEqual(
        signed_compact,
        'eyJraWQiOiJBWnhrbTJVIiwiYWxnIjoiUlMyNTYifQ.eyJpc3MiOiJqb2UifQ'
        '.dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk')
    self.assertEqual(un_comp, unsigned_compact)
    self.assertEqual(sig, signature)
    self.assertEqual(hdr, '{"kid":"AZxkm2U","alg":"RS256"}')
    header = _jwt_format.json_loads(hdr)
    _jwt_format.validate_header(header, 'RS256')
    self.assertEqual(pay, payload)
    self.assertIsNone(_jwt_format.get_type_header(header))
    def compute_mac_and_encode_with_kid(self, raw_jwt: _raw_jwt.RawJwt,
                                        kid: Optional[str]) -> str:
        """Computes a MAC and encodes the token.

    Args:
      raw_jwt: The RawJwt token to be MACed and encoded.
      kid: Optional "kid" header value. It is set by the wrapper for keys with
        output prefix TINK, and it is None for output prefix RAW.

    Returns:
      The MACed token encoded in the JWS compact serialization format.
    Raises:
      tink.TinkError if the operation fails.
    """
        if self._custom_kid is not None:
            if kid is not None:
                raise _jwt_error.JwtInvalidError(
                    'custom_kid must not be set for keys with output prefix type TINK'
                )
            kid = self._custom_kid
        unsigned = _jwt_format.create_unsigned_compact(self._algorithm, kid,
                                                       raw_jwt)
        return _jwt_format.create_signed_compact(unsigned,
                                                 self._compute_mac(unsigned))
 def compute_mac_and_encode(self, raw_jwt: _raw_jwt.RawJwt) -> Text:
     """Computes a MAC and encodes the token."""
     unsigned = _jwt_format.create_unsigned_compact(self._algorithm,
                                                    raw_jwt.json_payload())
     return _jwt_format.create_signed_compact(unsigned,
                                              self._compute_mac(unsigned))
def gen_compact(json_header: str, json_payload: str, raw_sign) -> str:
    unsigned_compact = (_jwt_format.encode_header(json_header) + b'.' +
                        _jwt_format.encode_payload(json_payload))
    signature = raw_sign.sign(unsigned_compact)
    return _jwt_format.create_signed_compact(unsigned_compact, signature)
    def test_weird_tokens_with_valid_signatures(self):
        handle = tink.new_keyset_handle(jwt.raw_jwt_es256_template())
        sign = handle.primitive(jwt.JwtPublicKeySign)
        # Get the internal PublicKeySign primitive to create valid signatures.
        wrapped = cast(_jwt_signature_wrappers._WrappedJwtPublicKeySign, sign)
        raw_sign = cast(
            _jwt_signature_key_manager._JwtPublicKeySign,
            wrapped._primitive_set.primary().primitive)._public_key_sign

        verify = handle.public_keyset_handle().primitive(
            jwt.JwtPublicKeyVerify)
        validator = jwt.new_validator(expected_issuer='issuer',
                                      allow_missing_expiration=True)

        # Normal token.
        valid = gen_compact('{"alg":"ES256"}', '{"iss":"issuer"}', raw_sign)
        verified_jwt = verify.verify_and_decode(valid, validator)
        self.assertEqual(verified_jwt.issuer(), 'issuer')

        # Token with unknown header is valid.
        unknown_header = gen_compact(
            '{"alg":"ES256","unknown_header":"abc"} \n ', '{"iss":"issuer" }',
            raw_sign)
        verified_jwt = verify.verify_and_decode(unknown_header, validator)
        self.assertEqual(verified_jwt.issuer(), 'issuer')

        # Token with unknown kid is valid, since primitives with output prefix type
        # RAW ignore kid headers.
        unknown_header = gen_compact('{"alg":"ES256","kid":"unknown"} \n ',
                                     '{"iss":"issuer" }', raw_sign)
        verified_jwt = verify.verify_and_decode(unknown_header, validator)
        self.assertEqual(verified_jwt.issuer(), 'issuer')

        # Token with invalid alg header
        alg_invalid = gen_compact('{"alg":"ES384"}', '{"iss":"issuer"}',
                                  raw_sign)
        with self.assertRaises(tink.TinkError):
            verify.verify_and_decode(alg_invalid, validator)

        # Token with empty header
        empty_header = gen_compact('{}', '{"iss":"issuer"}', raw_sign)
        with self.assertRaises(tink.TinkError):
            verify.verify_and_decode(empty_header, validator)

        # Token header is not valid JSON
        header_invalid = gen_compact('{"alg":"ES256"', '{"iss":"issuer"}',
                                     raw_sign)
        with self.assertRaises(tink.TinkError):
            verify.verify_and_decode(header_invalid, validator)

        # Token payload is not valid JSON
        payload_invalid = gen_compact('{"alg":"ES256"}', '{"iss":"issuer"',
                                      raw_sign)
        with self.assertRaises(tink.TinkError):
            verify.verify_and_decode(payload_invalid, validator)

        # Token with whitespace in header JSON string is valid.
        whitespace_in_header = gen_compact(' {"alg":   \n  "ES256"} \n ',
                                           '{"iss":"issuer" }', raw_sign)
        verified_jwt = verify.verify_and_decode(whitespace_in_header,
                                                validator)
        self.assertEqual(verified_jwt.issuer(), 'issuer')

        # Token with whitespace in payload JSON string is valid.
        whitespace_in_payload = gen_compact('{"alg":"ES256"}',
                                            ' {"iss": \n"issuer" } \n',
                                            raw_sign)
        verified_jwt = verify.verify_and_decode(whitespace_in_payload,
                                                validator)
        self.assertEqual(verified_jwt.issuer(), 'issuer')

        # Token with whitespace in base64-encoded header is invalid.
        with_whitespace = (_jwt_format.encode_header('{"alg":"ES256"}') +
                           b' .' +
                           _jwt_format.encode_payload('{"iss":"issuer"}'))
        token_with_whitespace = _jwt_format.create_signed_compact(
            with_whitespace, raw_sign.sign(with_whitespace))
        with self.assertRaises(tink.TinkError):
            verify.verify_and_decode(token_with_whitespace, validator)

        # Token with invalid character is invalid.
        with_invalid_char = (_jwt_format.encode_header('{"alg":"ES256"}') +
                             b'.?' +
                             _jwt_format.encode_payload('{"iss":"issuer"}'))
        token_with_invalid_char = _jwt_format.create_signed_compact(
            with_invalid_char, raw_sign.sign(with_invalid_char))
        with self.assertRaises(tink.TinkError):
            verify.verify_and_decode(token_with_invalid_char, validator)

        # Token with additional '.' is invalid.
        with_dot = (_jwt_format.encode_header('{"alg":"ES256"}') + b'.' +
                    _jwt_format.encode_payload('{"iss":"issuer"}') + b'.')
        token_with_dot = _jwt_format.create_signed_compact(
            with_dot, raw_sign.sign(with_dot))
        with self.assertRaises(tink.TinkError):
            verify.verify_and_decode(token_with_dot, validator)

        # num_recursions has been chosen such that parsing of this token fails
        # in all languages. We want to make sure that the algorithm does not
        # hang or crash in this case, but only returns a parsing error.
        num_recursions = 10000
        rec_payload = ('{"a":' * num_recursions) + '""' + ('}' *
                                                           num_recursions)
        rec_token = gen_compact('{"alg":"ES256"}', rec_payload, raw_sign)
        with self.assertRaises(tink.TinkError):
            verify.verify_and_decode(
                rec_token,
                validator=jwt.new_validator(allow_missing_expiration=True))

        # test wrong types
        with self.assertRaises(tink.TinkError):
            verify.verify_and_decode(cast(str, None), validator)
        with self.assertRaises(tink.TinkError):
            verify.verify_and_decode(cast(str, 123), validator)
        with self.assertRaises(tink.TinkError):
            valid_bytes = valid.encode('utf8')
            verify.verify_and_decode(cast(str, valid_bytes), validator)
Beispiel #7
0
  def test_weird_tokens_with_valid_macs(self):
    jwt_hmac = create_fixed_jwt_hmac()
    validator = jwt.new_validator(
        expected_issuer='joe', allow_missing_expiration=True)
    cc_mac = _cc_mac()

    # Normal token.
    valid_token = gen_token('{"alg":"HS256"}', '{"iss":"joe"}')
    verified = jwt_hmac.verify_mac_and_decode_with_kid(
        valid_token, validator, kid=None)
    self.assertEqual(verified.issuer(), 'joe')

    # Token with unknown header is valid.
    token_with_unknown_header = gen_token(
        '{"unknown_header":"123","alg":"HS256"}', '{"iss":"joe"}')
    verified2 = jwt_hmac.verify_mac_and_decode_with_kid(
        token_with_unknown_header, validator, kid=None)
    self.assertEqual(verified2.issuer(), 'joe')

    # Token with unknown kid is valid, since primitives with output prefix type
    # RAW ignore kid headers.
    token_with_unknown_kid = gen_token('{"kid":"unknown","alg":"HS256"}',
                                       '{"iss":"joe"}')
    verified2 = jwt_hmac.verify_mac_and_decode_with_kid(
        token_with_unknown_kid, validator, kid=None)
    self.assertEqual(verified2.issuer(), 'joe')

    # Token with invalid alg header
    alg_invalid = gen_token('{"alg":"HS384"}', '{"iss":"joe"}')
    with self.assertRaises(tink.TinkError):
      jwt_hmac.verify_mac_and_decode_with_kid(alg_invalid, validator, kid=None)

    # Token with empty header
    empty_header = gen_token('{}', '{"iss":"joe"}')
    with self.assertRaises(tink.TinkError):
      jwt_hmac.verify_mac_and_decode_with_kid(empty_header, validator, kid=None)

    # Token header is not valid JSON
    header_invalid = gen_token('{"alg":"HS256"', '{"iss":"joe"}')
    with self.assertRaises(tink.TinkError):
      jwt_hmac.verify_mac_and_decode_with_kid(
          header_invalid, validator, kid=None)

    # Token payload is not valid JSON
    payload_invalid = gen_token('{"alg":"HS256"}', '{"iss":"joe"')
    with self.assertRaises(tink.TinkError):
      jwt_hmac.verify_mac_and_decode_with_kid(
          payload_invalid, validator, kid=None)

    # Token with whitespace in header JSON string is valid.
    whitespace_in_header = gen_token(' {"alg":   \n  "HS256"} \n ',
                                     '{"iss":"joe" }')
    verified_jwt = jwt_hmac.verify_mac_and_decode_with_kid(
        whitespace_in_header, validator, kid=None)
    self.assertEqual(verified_jwt.issuer(), 'joe')

    # Token with whitespace in payload JSON string is valid.
    whitespace_in_payload = gen_token('{"alg":"HS256"}',
                                      ' {"iss": \n"joe" } \n')
    verified_jwt = jwt_hmac.verify_mac_and_decode_with_kid(
        whitespace_in_payload, validator, kid=None)
    self.assertEqual(verified_jwt.issuer(), 'joe')

    # Token with whitespace in base64-encoded header is invalid.
    with_whitespace_in_encoding = (
        _jwt_format.encode_header('{"alg":"HS256"}') + b' .' +
        _jwt_format.encode_payload('{"iss":"joe"}'))
    token_with_whitespace_in_encoding = _jwt_format.create_signed_compact(
        with_whitespace_in_encoding,
        cc_mac.compute_mac(with_whitespace_in_encoding))
    with self.assertRaises(tink.TinkError):
      jwt_hmac.verify_mac_and_decode_with_kid(
          token_with_whitespace_in_encoding, validator, kid=None)

    # Token with invalid character is invalid.
    with_invalid_char = (
        _jwt_format.encode_header('{"alg":"HS256"}') + b'.?' +
        _jwt_format.encode_payload('{"iss":"joe"}'))
    token_with_invalid_char = _jwt_format.create_signed_compact(
        with_invalid_char, cc_mac.compute_mac(with_invalid_char))
    with self.assertRaises(tink.TinkError):
      jwt_hmac.verify_mac_and_decode_with_kid(
          token_with_invalid_char, validator, kid=None)

    # Token with additional '.' is invalid.
    with_dot = (
        _jwt_format.encode_header('{"alg":"HS256"}') + b'.' +
        _jwt_format.encode_payload('{"iss":"joe"}') + b'.')
    token_with_dot = _jwt_format.create_signed_compact(
        with_dot, cc_mac.compute_mac(with_dot))
    with self.assertRaises(tink.TinkError):
      jwt_hmac.verify_mac_and_decode_with_kid(
          token_with_dot, validator, kid=None)

    # num_recursions has been chosen such that parsing of this token fails
    # in all languages. We want to make sure that the algorithm does not
    # hang or crash in this case, but only returns a parsing error.
    num_recursions = 10000
    rec_payload = ('{"a":' * num_recursions) + '""' + ('}' * num_recursions)
    rec_token = gen_token('{"alg":"HS256"}', rec_payload)
    with self.assertRaises(tink.TinkError):
      jwt_hmac.verify_mac_and_decode_with_kid(
          rec_token,
          validator=jwt.new_validator(allow_missing_expiration=True),
          kid=None)

    # test wrong types
    with self.assertRaises(tink.TinkError):
      jwt_hmac.verify_mac_and_decode_with_kid(
          cast(str, None), validator, kid=None)
    with self.assertRaises(tink.TinkError):
      jwt_hmac.verify_mac_and_decode_with_kid(
          cast(str, 123), validator, kid=None)
    with self.assertRaises(tink.TinkError):
      valid_token_bytes = valid_token.encode('utf8')
      jwt_hmac.verify_mac_and_decode_with_kid(
          cast(str, valid_token_bytes), validator, kid=None)