def test_verify_json_missing_key(): ec_key = ECKey().load_key(P256()) sym_key = SYMKey(key=b"My hollow echo chamber", alg="HS384") protected_headers_1 = {"foo": "bar", "alg": "ES256"} unprotected_headers_1 = {"abc": "xyz"} protected_headers_2 = {"foo": "bar", "alg": "HS384"} unprotected_headers_2 = {"abc": "zeb"} payload = "hello world" _jwt = JWS(msg=payload).sign_json( headers=[ (protected_headers_1, unprotected_headers_1), (protected_headers_2, unprotected_headers_2), ], keys=[ec_key, sym_key], ) # Only the EC key vkeys = [ECKey().load_key(ec_key.public_key())] with pytest.raises(NoSuitableSigningKeys): JWS().verify_json(_jwt, keys=vkeys) assert JWS().verify_json(_jwt, keys=vkeys, at_least_one=True) # Only the SYM key with pytest.raises(NoSuitableSigningKeys): JWS().verify_json(_jwt, keys=[sym_key]) assert JWS().verify_json(_jwt, keys=[sym_key], at_least_one=True) # With both assert JWS().verify_json(_jwt, keys=[vkeys[0], sym_key])
def setup(self): mkey = [ {"type": "RSA", "use": ["sig"]}, {"type": "RSA", "use": ["sig"]}, {"type": "RSA", "use": ["sig"]}, ] skey = [{"type": "RSA", "use": ["sig"]}] # Alice has multiple keys self.alice_keyjar = build_keyjar(mkey) # Bob has one single keys self.bob_keyjar = build_keyjar(skey) self.alice_keyjar.import_jwks( self.alice_keyjar.export_jwks(private=True, issuer_id=""), "Alice" ) self.bob_keyjar.import_jwks(self.bob_keyjar.export_jwks(private=True, issuer_id=""), "Bob") # To Alice's keyjar add Bob's public keys self.alice_keyjar.import_jwks(self.bob_keyjar.export_jwks(issuer_id="Bob"), "Bob") # To Bob's keyjar add Alice's public keys self.bob_keyjar.import_jwks(self.alice_keyjar.export_jwks(issuer_id="Alice"), "Alice") _jws = JWS('{"aud": "Bob", "iss": "Alice"}', alg="RS256") sig_key = self.alice_keyjar.get_signing_key("rsa", issuer_id="Alice")[0] self.sjwt_a = _jws.sign_compact([sig_key]) _jws = JWS('{"aud": "Alice", "iss": "Bob"}', alg="RS256") sig_key = self.bob_keyjar.get_signing_key("rsa", issuer_id="Bob")[0] self.sjwt_b = _jws.sign_compact([sig_key])
def test_hmac_from_keyrep(): payload = "Please take a moment to register today" symkeys = [k for k in SIGJWKS if k.kty == "oct"] _jws = JWS(payload, alg="HS512") _jwt = _jws.sign_compact(symkeys) _rj = JWS(alg="HS512") info = _rj.verify_compact(_jwt, symkeys) assert info == payload
def test_client_secret_jwt(self, entity): _service_context = entity.client_get("service_context") _service_context.token_endpoint = "https://example.com/token" _service_context.provider_info = { 'issuer': 'https://example.com/', 'token_endpoint': "https://example.com/token" } _service_context.registration_response = { 'token_endpoint_auth_signing_alg': "HS256" } csj = ClientSecretJWT() request = AccessTokenRequest() csj.construct(request, service=entity.client_get("service", 'accesstoken'), authn_endpoint='token_endpoint') assert request["client_assertion_type"] == JWT_BEARER assert "client_assertion" in request cas = request["client_assertion"] _kj = KeyJar() _kj.add_symmetric(_service_context.client_id, _service_context.client_secret, ['sig']) jso = JWT(key_jar=_kj, sign_alg='HS256').unpack(cas) assert _eq(jso.keys(), ["aud", "iss", "sub", "exp", "iat", 'jti']) _rj = JWS(alg='HS256') info = _rj.verify_compact( cas, _kj.get_signing_key(issuer_id=_service_context.client_id)) assert _eq(info.keys(), ["aud", "iss", "sub", "jti", "exp", "iat"]) assert info['aud'] == [ _service_context.provider_info['token_endpoint'] ]
def test_hmac_512(): payload = "Please take a moment to register today" keys = [SYMKey(key=b"My hollow echo chamber", alg="HS512")] _jws = JWS(payload, alg="HS512") _jwt = _jws.sign_compact(keys) _rj = JWS(alg="HS512") info = _rj.verify_compact(_jwt, keys) assert info == payload
def test_sign_json(): eck = ec.generate_private_key(ec.SECP256R1(), default_backend()) key = ECKey().load_key(eck) payload = "hello world" unprotected_headers = {"abc": "xyz"} protected_headers = {"foo": "bar"} _jwt = JWS(msg=payload, alg="ES256").sign_json(headers=[ (protected_headers, unprotected_headers) ], keys=[key]) jwt = json.loads(_jwt) assert b64d_enc_dec(jwt["payload"]) == payload assert len(jwt["signatures"]) == 1 assert jwt["signatures"][0]["header"] == unprotected_headers assert json.loads(b64d_enc_dec( jwt["signatures"][0]["protected"])) == protected_headers
def test_sign_json_flattened_syntax(): key = ECKey().load_key(P256()) protected_headers = {"foo": "bar"} unprotected_headers = {"abc": "xyz"} payload = "hello world" _jwt = JWS(msg=payload, alg="ES256").sign_json(headers=[ (protected_headers, unprotected_headers) ], keys=[key], flatten=True) json_jws = json.loads(_jwt) assert "signatures" not in json_jws assert b64d_enc_dec(json_jws["payload"]) == payload assert json_jws["header"] == unprotected_headers assert json.loads(b64d_enc_dec(json_jws["protected"])) == protected_headers
def test_signer_es(ec_func, alg): payload = "Please take a moment to register today" eck = ec.generate_private_key(ec_func(), default_backend()) keys = [ECKey().load_key(eck)] _jws = JWS(payload, alg=alg) _jwt = _jws.sign_compact(keys) _pubkey = ECKey().load_key(eck.public_key()) _rj = JWS(alg=alg) info = _rj.verify_compact(_jwt, [_pubkey]) assert info == payload
def test_signer_ps384(): payload = "Please take a moment to register today" _pkey = import_private_rsa_key_from_file(PRIV_KEY) keys = [RSAKey(priv_key=_pkey)] # keys[0]._keytype = "private" _jws = JWS(payload, alg="PS384") _jwt = _jws.sign_compact(keys) vkeys = [RSAKey(pub_key=_pkey.public_key())] _rj = JWS(alg="PS384") info = _rj.verify_compact(_jwt, vkeys) assert info == payload
def test_signer_ps256_fail(): payload = "Please take a moment to register today" _pkey = import_private_rsa_key_from_file(PRIV_KEY) keys = [RSAKey(priv_key=_pkey)] # keys[0]._keytype = "private" _jws = JWS(payload, alg="PS256") _jwt = _jws.sign_compact(keys)[:-5] + "abcde" vkeys = [RSAKey(pub_key=_pkey.public_key())] _rj = JWS(alg="PS256") try: _rj.verify_compact(_jwt, vkeys) except BadSignature: pass else: assert False
def test_signer_es256_verbose(): payload = "Please take a moment to register today" eck = ec.generate_private_key(ec.SECP256R1(), default_backend()) _key = ECKey().load_key(eck) keys = [_key] _jws = JWS(payload, alg="ES256") _jwt = _jws.sign_compact(keys) _pubkey = ECKey().load_key(eck.public_key()) _rj = JWS(alg="ES256") info = _rj.verify_compact_verbose(_jwt, [_pubkey]) assert info["msg"] == payload assert info["key"] == _pubkey
def test_no_alg_and_alg_none_same(): payload = "Please take a moment to register today" _jws = JWS(payload, alg="none") # Create a JWS (signed JWT) _jwt0 = _jws.sign_compact([]) # The class instance that sets up the signing operation _jws = JWS(payload, alg="none") # Create a JWS (signed JWT) _jwt1 = _jws.sign_compact([]) assert _jwt0 == _jwt1
def test_1(): claimset = { "iss": "joe", "exp": 1300819380, "http://example.com/is_root": True } _jws = JWS(claimset, cty="JWT", alg="none") _jwt = _jws.sign_compact() _jr = JWS() _msg = _jr.verify_compact(_jwt, allow_none=True) print(_jr) assert _jr.jwt.headers["alg"] == "none" assert _msg == claimset
def setup(self): mkey = [ { "type": "RSA", "use": ["sig"] }, { "type": "RSA", "use": ["sig"] }, { "type": "RSA", "use": ["sig"] }, ] skey = [ { "type": "RSA", "use": ["sig"] }, ] # Alice has multiple keys self.alice_keyjar = build_keyjar(mkey) # Bob has one single keys self.bob_keyjar = build_keyjar(skey) self.alice_keyjar['Alice'] = self.alice_keyjar[''] self.bob_keyjar['Bob'] = self.bob_keyjar[''] # To Alice's keyjar add Bob's public keys self.alice_keyjar.import_jwks( self.bob_keyjar.export_jwks(issuer='Bob'), 'Bob') # To Bob's keyjar add Alice's public keys self.bob_keyjar.import_jwks( self.alice_keyjar.export_jwks(issuer='Alice'), 'Alice') _jws = JWS('{"aud": "Bob", "iss": "Alice"}', alg='RS256') sig_key = self.alice_keyjar.get_signing_key('rsa', owner='Alice')[0] self.sjwt_a = _jws.sign_compact([sig_key]) _jws = JWS('{"aud": "Alice", "iss": "Bob"}', alg='RS256') sig_key = self.bob_keyjar.get_signing_key('rsa', owner='Bob')[0] self.sjwt_b = _jws.sign_compact([sig_key])
def test_rs256_rm_signature(): payload = "Please take a moment to register today" _pkey = import_private_rsa_key_from_file(PRIV_KEY) keys = [RSAKey(priv_key=_pkey)] # keys[0]._keytype = "private" _jws = JWS(payload, alg="RS256") _jwt = _jws.sign_compact(keys) p = _jwt.split(".") _jwt = ".".join(p[:-1]) vkeys = [RSAKey(key=_pkey.public_key())] _rj = JWS() try: _ = _rj.verify_compact(_jwt, vkeys) except WrongNumberOfParts: pass else: assert False
def test_signer_protected_headers(): payload = "Please take a moment to register today" eck = ec.generate_private_key(ec.SECP256R1(), default_backend()) _key = ECKey().load_key(eck) keys = [_key] _jws = JWS(payload, alg="ES256") protected = dict(header1=u"header1 is protected", header2="header2 is protected too", a=1) _jwt = _jws.sign_compact(keys, protected=protected) exp_protected = protected.copy() exp_protected['alg'] = 'ES256' enc_header, enc_payload, sig = _jwt.split('.') assert json.loads(b64d( enc_header.encode("utf-8")).decode("utf-8")) == exp_protected assert b64d(enc_payload.encode("utf-8")).decode("utf-8") == payload _pub_key = ECKey().load_key(eck.public_key()) _rj = JWS(alg='ES256') info = _rj.verify_compact(_jwt, [_pub_key]) assert info == payload
def test_verify_protected_headers(): payload = "Please take a moment to register today" eck = ec.generate_private_key(ec.SECP256R1(), default_backend()) _key = ECKey().load_key(eck) keys = [_key] _jws = JWS(payload, alg="ES256") protected = dict(header1=u"header1 is protected", header2="header2 is protected too", a=1) _jwt = _jws.sign_compact(keys, protected=protected) protectedHeader, enc_payload, sig = _jwt.split(".") data = dict(payload=enc_payload, signatures=[ dict( header=dict(alg=u"ES256", jwk=_key.serialize()), protected=protectedHeader, signature=sig, ) ]) # _pub_key = ECKey().load_key(eck.public_key()) _jws = JWS() assert _jws.verify_json(json.dumps(data)) == payload
def test_missing_payload(): jws = JWS() with pytest.raises(FormatError): jws.verify_json('{"foo":"bar"}')
def test_pick_alg_dont_get_alg_from_single_key_if_already_specified(): expected_alg = "RS512" _pkey = import_private_rsa_key_from_file(PRIV_KEY) vkeys = [RSAKey(pub_key=_pkey.public_key())] alg = JWS(alg=expected_alg)._pick_alg(vkeys) assert alg == expected_alg
def test_pick_alg_assume_alg_from_single_key(): expected_alg = "HS256" keys = [SYMKey(key="foobar subdued thought", alg=expected_alg)] alg = JWS(alg=expected_alg)._pick_alg(keys) assert alg == expected_alg
def test_pick_wrong_alg(): keys = KeyBundle(JWKS_b) _jws = JWS("foobar", alg="EC256", kid="rsa1") with pytest.raises(ValueError): _keys = _jws.pick_keys(keys, use="sig")
def test_pick_use(): keys = KeyBundle(JWK_b) _jws = JWS("foobar", alg="RS256", kid="MnC_VZcATfM5pOYiJHMba9goEKY") _keys = _jws.pick_keys(keys, use="sig") assert len(_keys) == 1
def test_is_jws_recognize_flattened_json_serialized_jws(): key = ECKey().load_key(P256()) jws = JWS(msg="hello world", alg="ES256").sign_json([key], flatten=True) assert JWS().is_jws(jws)
def test_is_jws_recognize_compact_jws(): key = ECKey().load_key(P256()) jws = JWS(msg="hello world", alg="ES256").sign_compact([key]) assert JWS().is_jws(jws)
def main(): """Main function""" parser = argparse.ArgumentParser(description="JWS verifier") parser.add_argument( "--trusted", dest="trusted", metavar="filename", help="Trusted keys (JWKS)", required=False, ) parser.add_argument( "--input", dest="jws_input", metavar="filename", help="JWS file input", required=True, ) parser.add_argument( "--output", dest="output", metavar="filename", help="Output", required=False, ) parser.add_argument( "--headers", dest="headers_output", metavar="filename", help="Headers output", required=False, ) parser.add_argument("--debug", dest="debug", action="store_true", help="Enable debugging") args = parser.parse_args() if args.debug: logging.basicConfig(level=logging.DEBUG) else: logging.basicConfig(level=logging.INFO) trusted_keys = [] if args.trusted: with open(args.trusted) as input_file: trusted_payload = json.load(input_file) if isinstance(trusted_payload, dict): trusted_keys.append(key_from_jwk_dict(trusted_payload)) elif isinstance(trusted_payload, dict): for jwk_dict in trusted_payload["keys"]: trusted_keys.append( key_from_jwk_dict(jwk_dict, private=False)) else: raise ValueError("Unknown trusted list format") with open(args.jws_input, "rt") as input_file: jws_file = input_file.read() protected_headers = [] jws_dict = json.loads(jws_file) if args.trusted: jws = JWS() message = jws.verify_json(jws_file, keys=trusted_keys) else: message = json.loads(b64d(jws_dict["payload"].encode()).decode()) for signatures in jws_dict["signatures"]: if "protected" in signatures: protected_headers.append(extract_headers(signatures["protected"])) if args.headers_output: with open(args.headers_output, "wt") as output_file: print(json.dumps(protected_headers, indent=4), file=output_file) else: if args.trusted: print("# JWS PROTECTED HEADERS (VERIFIED)") else: print("# JWS PROTECTED HEADERS (NOT VERIFIED)") print(json.dumps(protected_headers, indent=4, sort_keys=True)) if args.output: with open(args.output, "wt") as output_file: print(json.dumps(message, indent=4), file=output_file) else: if args.trusted: print("# JWS CONTENTS (VERIFIED)") else: print("# JWS CONTENTS (NOT VERIFIED)") print(json.dumps(message, indent=4, sort_keys=True))
def jws_sign_compact(self, message: bytes) -> str: """Create JWS of message""" return str( JWS(message, alg=self.signing_alg).sign_compact(keys=[self.signing_key]))
def test_jws_verifier_with_kid(): # Sign priv_key = key_from_jwk_dict( json.loads(test_vector.test_json_ecdsa_priv_key_kid1)) signer = JWS(test_vector.test_payload, **json.loads(test_vector.test_header_ecdsa_kid1)) signed_token_kid1 = signer.sign_compact([priv_key]) priv_key = key_from_jwk_dict( json.loads(test_vector.test_json_ecdsa_priv_key_kid2)) signer = JWS(test_vector.test_payload, **json.loads(test_vector.test_header_ecdsa_kid2)) signed_token_kid2 = signer.sign_compact([priv_key]) # Verify pub_key = key_from_jwk_dict( json.loads(test_vector.test_json_ecdsa_pub_key_kid1)) verifier = JWS(alg='ES256') assert verifier.verify_compact(signed_token_kid1, [pub_key]) # The signature is valid but the kids don't match. with pytest.raises(NoSuitableSigningKeys): verifier.verify_compact(signed_token_kid2, [pub_key])
def create_header(self) -> str: payload = {k: self[k] for k in self.body_params} _jws = JWS(payload, alg=self["alg"]) _jws_headers = {k: self[k] for k in self.header_params} _signed_jwt = _jws.sign_compact(keys=[self.key], **_jws_headers) return _signed_jwt