def test_ec_verify_should_return_true_for_test_vector(self): """ This test verifies that ECDSA verification works with a known good signature and key. Reference: https://tools.ietf.org/html/rfc7520#section-4.3 """ signing_input = ( b"eyJhbGciOiJFUzUxMiIsImtpZCI6ImJpbGJvLmJhZ2dpbnNAaG9iYml0b24uZXhhb" b"XBsZSJ9.SXTigJlzIGEgZGFuZ2Vyb3VzIGJ1c2luZXNzLCBGcm9kbywgZ29pbmcgb" b"3V0IHlvdXIgZG9vci4gWW91IHN0ZXAgb250byB0aGUgcm9hZCwgYW5kIGlmIHlvdS" b"Bkb24ndCBrZWVwIHlvdXIgZmVldCwgdGhlcmXigJlzIG5vIGtub3dpbmcgd2hlcmU" b"geW91IG1pZ2h0IGJlIHN3ZXB0IG9mZiB0by4" ) signature = base64url_decode( b"AE_R_YZCChjn4791jSQCrdPZCNYqHXCTZH0-JZGYNlaAjP2kqaluUIIUnC9qvbu9P" b"lon7KRTzoNEuT4Va2cmL1eJAQy3mtPBu_u_sDDyYjnAMDxXPn7XrT0lw-kvAD890j" b"l8e2puQens_IEKBpHABlsbEPX6sFY8OcGDqoRuBomu9xQ2" ) algo = ECAlgorithm(ECAlgorithm.SHA512) key = algo.prepare_key(load_ec_pub_key_p_521()) result = algo.verify(signing_input, key, signature) assert result # private key can also be used. with open(key_path("jwk_ec_key_P-521.json")) as keyfile: private_key = algo.from_jwk(keyfile.read()) result = algo.verify(signing_input, private_key, signature) assert result
def test_ec_jwk_public_and_private_keys_should_parse_and_verify(self): tests = { "P-256": ECAlgorithm.SHA256, "P-384": ECAlgorithm.SHA384, "P-521": ECAlgorithm.SHA512, } for (curve, hash) in tests.items(): algo = ECAlgorithm(hash) with open(key_path(f"jwk_ec_pub_{curve}.json")) as keyfile: pub_key = algo.from_jwk(keyfile.read()) with open(key_path(f"jwk_ec_key_{curve}.json")) as keyfile: priv_key = algo.from_jwk(keyfile.read()) signature = algo.sign(b"Hello World!", priv_key) assert algo.verify(b"Hello World!", pub_key, signature)
async def populate_oidc_config(): http_client = tornado.httpclient.AsyncHTTPClient() metadata_url = config.get("get_user_by_oidc_settings.metadata_url") if metadata_url: res = await http_client.fetch( metadata_url, method="GET", headers={ "Content-Type": "application/x-www-form-urlencoded", "Accept": "application/json", }, ) oidc_config = json.loads(res.body) else: authorization_endpoint = config.get( "get_user_by_oidc_settings.authorization_endpoint") token_endpoint = config.get("get_user_by_oidc_settings.token_endpoint") jwks_uri = config.get("get_user_by_oidc_settings.jwks_uri") if not (authorization_endpoint or token_endpoint or jwks_uri): raise MissingConfigurationValue("Missing OIDC Configuration.") oidc_config = { "authorization_endpoint": authorization_endpoint, "token_endpoint": token_endpoint, "jwks_uri": jwks_uri, } client_id = config.get("oidc_secrets.client_id") client_secret = config.get("oidc_secrets.secret") if not (client_id or client_secret): raise MissingConfigurationValue("Missing OIDC Secrets") oidc_config["client_id"] = client_id oidc_config["client_secret"] = client_secret # Fetch jwks_uri for jwt validation res = await http_client.fetch( oidc_config["jwks_uri"], method="GET", headers={ "Content-Type": "application/x-www-form-urlencoded", "Accept": "application/json", }, ) oidc_config["jwks_data"] = json.loads(res.body) oidc_config["jwt_keys"] = {} for k in oidc_config["jwks_data"]["keys"]: key_type = k["kty"] key_id = k["kid"] if key_type == "RSA": oidc_config["jwt_keys"][key_id] = RSAAlgorithm.from_jwk( json.dumps(k)) elif key_type == "EC": oidc_config["jwt_keys"][key_id] = ECAlgorithm.from_jwk( json.dumps(k)) return oidc_config
async def populate_oidc_config(): http_client = tornado.httpclient.AsyncHTTPClient() metadata_url = config.get( "get_user_by_aws_alb_auth_settings.access_token_validation.metadata_url" ) if metadata_url: res = await http_client.fetch( metadata_url, method="GET", headers={ "Content-Type": "application/x-www-form-urlencoded", "Accept": "application/json", }, ) oidc_config = json.loads(res.body) else: jwks_uri = config.get( "get_user_by_aws_alb_auth_settings.access_token_validation.jwks_uri" ) if not jwks_uri: raise MissingConfigurationValue("Missing OIDC Configuration.") oidc_config = { "jwks_uri": jwks_uri, } # Fetch jwks_uri for jwt validation res = await http_client.fetch( oidc_config["jwks_uri"], method="GET", headers={ "Content-Type": "application/x-www-form-urlencoded", "Accept": "application/json", }, ) oidc_config["jwks_data"] = json.loads(res.body) oidc_config["jwt_keys"] = {} for k in oidc_config["jwks_data"]["keys"]: key_type = k["kty"] key_id = k["kid"] if key_type == "RSA": oidc_config["jwt_keys"][key_id] = RSAAlgorithm.from_jwk( json.dumps(k)) elif key_type == "EC": oidc_config["jwt_keys"][key_id] = ECAlgorithm.from_jwk( json.dumps(k)) oidc_config["aud"] = config.get( "get_user_by_aws_alb_auth_settings.access_token_validation.client_id") return oidc_config
def test_ec_jwk_fails_on_invalid_json(self): algo = ECAlgorithm(ECAlgorithm.SHA512) valid_points = { "P-256": { "x": "PTTjIY84aLtaZCxLTrG_d8I0G6YKCV7lg8M4xkKfwQ4=", "y": "ank6KA34vv24HZLXlChVs85NEGlpg2sbqNmR_BcgyJU=", }, "P-384": { "x": "IDC-5s6FERlbC4Nc_4JhKW8sd51AhixtMdNUtPxhRFP323QY6cwWeIA3leyZhz-J", "y": "eovmN9ocANS8IJxDAGSuC1FehTq5ZFLJU7XSPg36zHpv4H2byKGEcCBiwT4sFJsy", }, "P-521": { "x": "AHKZLLOsCOzz5cY97ewNUajB957y-C-U88c3v13nmGZx6sYl_oJXu9A5RkTKqjqvjyekWF-7ytDyRXYgCF5cj0Kt", "y": "AdymlHvOiLxXkEhayXQnNCvDX4h9htZaCJN34kfmC6pV5OhQHiraVySsUdaQkAgDPrwQrJmbnX9cwlGfP-HqHZR1", }, } # Invalid JSON with pytest.raises(InvalidKeyError): algo.from_jwk("<this isn't json>") # Bad key type with pytest.raises(InvalidKeyError): algo.from_jwk('{"kty": "RSA"}') # Missing data with pytest.raises(InvalidKeyError): algo.from_jwk('{"kty": "EC"}') with pytest.raises(InvalidKeyError): algo.from_jwk('{"kty": "EC", "x": "1"}') with pytest.raises(InvalidKeyError): algo.from_jwk('{"kty": "EC", "y": "1"}') # Missing curve with pytest.raises(InvalidKeyError): algo.from_jwk('{"kty": "EC", "x": "dGVzdA==", "y": "dGVzdA=="}') # EC coordinates not equally long with pytest.raises(InvalidKeyError): algo.from_jwk('{"kty": "EC", "x": "dGVzdHRlc3Q=", "y": "dGVzdA=="}') # EC coordinates length invalid for curve in ("P-256", "P-384", "P-521"): with pytest.raises(InvalidKeyError): algo.from_jwk( '{{"kty": "EC", "crv": "{}", "x": "dGVzdA==", ' '"y": "dGVzdA=="}}'.format(curve) ) # EC private key length invalid for (curve, point) in valid_points.items(): with pytest.raises(InvalidKeyError): algo.from_jwk( '{{"kty": "EC", "crv": "{}", "x": "{}", "y": "{}", ' '"d": "dGVzdA=="}}'.format(curve, point["x"], point["y"]) )