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 = ensure_bytes( 'eyJhbGciOiJFUzUxMiIsImtpZCI6ImJpbGJvLmJhZ2dpbnNAaG9iYml0b24uZXhhb' 'XBsZSJ9.SXTigJlzIGEgZGFuZ2Vyb3VzIGJ1c2luZXNzLCBGcm9kbywgZ29pbmcgb' '3V0IHlvdXIgZG9vci4gWW91IHN0ZXAgb250byB0aGUgcm9hZCwgYW5kIGlmIHlvdS' 'Bkb24ndCBrZWVwIHlvdXIgZmVldCwgdGhlcmXigJlzIG5vIGtub3dpbmcgd2hlcmU' 'geW91IG1pZ2h0IGJlIHN3ZXB0IG9mZiB0by4' ) signature = base64url_decode(ensure_bytes( 'AE_R_YZCChjn4791jSQCrdPZCNYqHXCTZH0-JZGYNlaAjP2kqaluUIIUnC9qvbu9P' 'lon7KRTzoNEuT4Va2cmL1eJAQy3mtPBu_u_sDDyYjnAMDxXPn7XrT0lw-kvAD890j' 'l8e2puQens_IEKBpHABlsbEPX6sFY8OcGDqoRuBomu9xQ2' )) algo = ECAlgorithm(ECAlgorithm.SHA512) key = algo.prepare_key(load_ec_pub_key()) result = algo.verify(signing_input, key, signature) assert result
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 = ensure_bytes( 'eyJhbGciOiJFUzUxMiIsImtpZCI6ImJpbGJvLmJhZ2dpbnNAaG9iYml0b24uZXhhb' 'XBsZSJ9.SXTigJlzIGEgZGFuZ2Vyb3VzIGJ1c2luZXNzLCBGcm9kbywgZ29pbmcgb' '3V0IHlvdXIgZG9vci4gWW91IHN0ZXAgb250byB0aGUgcm9hZCwgYW5kIGlmIHlvdS' 'Bkb24ndCBrZWVwIHlvdXIgZmVldCwgdGhlcmXigJlzIG5vIGtub3dpbmcgd2hlcmU' 'geW91IG1pZ2h0IGJlIHN3ZXB0IG9mZiB0by4') signature = base64url_decode( ensure_bytes( 'AE_R_YZCChjn4791jSQCrdPZCNYqHXCTZH0-JZGYNlaAjP2kqaluUIIUnC9qvbu9P' 'lon7KRTzoNEuT4Va2cmL1eJAQy3mtPBu_u_sDDyYjnAMDxXPn7XrT0lw-kvAD890j' 'l8e2puQens_IEKBpHABlsbEPX6sFY8OcGDqoRuBomu9xQ2')) algo = ECAlgorithm(ECAlgorithm.SHA512) key = algo.prepare_key(load_ec_pub_key()) result = algo.verify(signing_input, key, signature) assert result
def test_ec_verify_should_return_false_if_signature_wrong_length(self): algo = ECAlgorithm(ECAlgorithm.SHA256) message = ensure_bytes('Hello World!') sig = base64.b64decode(ensure_bytes('AC+m4Jf/xI3guAC6w0w3')) with open(key_path('testkey_ec.pub'), 'r') as keyfile: pub_key = algo.prepare_key(keyfile.read()) result = algo.verify(message, pub_key, sig) assert not result
def test_ec_sign_then_verify_should_return_true(self): algo = ECAlgorithm(ECAlgorithm.SHA256) message = ensure_bytes('Hello World!') with open(key_path('testkey_ec'), 'r') as keyfile: priv_key = algo.prepare_key(keyfile.read()) sig = algo.sign(message, priv_key) with open(key_path('testkey_ec.pub'), 'r') as keyfile: pub_key = algo.prepare_key(keyfile.read()) result = algo.verify(message, pub_key, sig) assert result
def test_ec_verify_should_return_true_if_signature_valid(self): algo = ECAlgorithm(ECAlgorithm.SHA256) message = ensure_bytes('Hello World!') sig = base64.b64decode(ensure_bytes( 'AC+m4Jf/xI3guAC6w0w37t5zRpSCF6F4udEz5LiMiTIjCS4vcVe6dDOxK+M' 'mvkF8PxJuvqxP2CO3TR3okDPCl/NjATTO1jE+qBZ966CRQSSzcCM+tzcHzw' 'LZS5kbvKu0Acd/K6Ol2/W3B1NeV5F/gjvZn/jOwaLgWEUYsg0o4XVrAg65')) with open(key_path('testkey_ec.pub'), 'r') as keyfile: pub_key = algo.prepare_key(keyfile.read()) result = algo.verify(message, pub_key, sig) assert result
def test_ec_verify_should_return_false_if_signature_invalid(self): algo = ECAlgorithm(ECAlgorithm.SHA256) message = force_bytes('Hello World!') # Mess up the signature by replacing a known byte sig = base64.b64decode(force_bytes( 'AC+m4Jf/xI3guAC6w0w37t5zRpSCF6F4udEz5LiMiTIjCS4vcVe6dDOxK+M' 'mvkF8PxJuvqxP2CO3TR3okDPCl/NjATTO1jE+qBZ966CRQSSzcCM+tzcHzw' 'LZS5kbvKu0Acd/K6Ol2/W3B1NeV5F/gjvZn/jOwaLgWEUYsg0o4XVrAg65'.replace('r', 's'))) with open(key_path('testkey_ec.pub'), 'r') as keyfile: pub_key = algo.prepare_key(keyfile.read()) result = algo.verify(message, pub_key, sig) assert not result
def test_ec_verify_should_return_true_if_signature_valid(self): algo = ECAlgorithm(ECAlgorithm.SHA256) jwt_message = ensure_bytes('Hello World!') jwt_sig = base64.b64decode(ensure_bytes( 'MIGIAkIB9vYz+inBL8aOTA4auYz/zVuig7TT1bQgKROIQX9YpViHkFa4DT5' '5FuFKn9XzVlk90p6ldEj42DC9YecXHbC2t+cCQgCicY+8f3f/KCNtWK7cif' '6vdsVwm6Lrjs0Ag6ZqCf+olN11hVt1qKBC4lXppqB1gNWEmNQaiz1z2QRyc' 'zJ8hSJmbw==')) with open(key_path('testkey_ec.pub'), 'r') as keyfile: jwt_pub_key = algo.prepare_key(keyfile.read()) result = algo.verify(jwt_message, jwt_pub_key, jwt_sig) self.assertTrue(result)
def test_ec_with_password_sign_then_verify_should_return_true(self): algo = ECAlgorithm(ECAlgorithm.SHA256) message = ensure_bytes('Hello World!') with open(key_path('testkey_ec_encrypted.password'), 'r') as pw: password = pw.read().rstrip() with open(key_path('testkey_ec_encrypted'), 'r') as keyfile: priv_key = algo.prepare_key(keyfile.read(), password=password) sig = algo.sign(message, priv_key) with open(key_path('testkey_ec.pub'), 'r') as keyfile: pub_key = algo.prepare_key(keyfile.read()) result = algo.verify(message, pub_key, sig) assert result
def test_ec_verify_should_return_false_if_signature_invalid(self): algo = ECAlgorithm(ECAlgorithm.SHA256) message = ensure_bytes('Hello World!') # Mess up the signature by replacing a known byte sig = base64.b64decode(ensure_bytes( 'MIGIAkIB9vYz+inBL8aOTA4auYz/zVuig7TT1bQgKROIQX9YpViHkFa4DT5' '5FuFKn9XzVlk90p6ldEj42DC9YecXHbC2t+cCQgCicY+8f3f/KCNtWK7cif' '6vdsVwm6Lrjs0Ag6ZqCf+olN11hVt1qKBC4lXppqB1gNWEmNQaiz1z2QRyc' 'zJ8hSJmbw=='.replace('r', 's'))) with open(key_path('testkey_ec.pub'), 'r') as keyfile: pub_key = algo.prepare_key(keyfile.read()) result = algo.verify(message, pub_key, sig) assert not result
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
def __init__(self, config, trustmodel): super(BaseSSI, self).__init__() # Setup jwt ES256K algorithm for token decoding verification and encoding try: jwt.register_algorithm('ES256K', ECAlgorithm(ECAlgorithm.SHA256)) except ValueError as ve: log.debug(str(ve)) self.comm = uPortWS(config['proxy_url'], config['appname'], config['appid'], config['key']) self.appid = config['appid'] self.trustmodel = trustmodel
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_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)
def test_ec_should_accept_pem_private_key_bytes(self): algo = ECAlgorithm(ECAlgorithm.SHA256) with open(key_path("testkey_ec.priv"), "rb") as ec_key: algo.prepare_key(ec_key.read())
def test_ec_should_accept_pem_private_key_bytes(self): algo = ECAlgorithm(ECAlgorithm.SHA256) with open(key_path('testkey_ec'), 'rb') as ec_key: algo.prepare_key(ec_key.read())
def test_ec_should_accept_unicode_key(self): algo = ECAlgorithm(ECAlgorithm.SHA256) with open(key_path('testkey_ec'), 'r') as ec_key: algo.prepare_key(ensure_unicode(ec_key.read()))
def test_ec_should_reject_non_string_key(self): algo = ECAlgorithm(ECAlgorithm.SHA256) with pytest.raises(TypeError): algo.prepare_key(None)
def test_ec_should_reject_non_string_key(self): algo = ECAlgorithm(ECAlgorithm.SHA256) with self.assertRaises(TypeError): algo.prepare_key(None)
def test_ec_should_accept_ssh_public_key_bytes(self): algo = ECAlgorithm(ECAlgorithm.SHA256) with open(key_path("testkey_ec_ssh.pub")) as ec_key: algo.prepare_key(ec_key.read())
def test_ec_should_accept_unicode_key(self): algo = ECAlgorithm(ECAlgorithm.SHA256) with open(key_path("testkey_ec")) as ec_key: algo.prepare_key(force_unicode(ec_key.read()))
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"]) )