def test_handshake_challenge_schema_for_client_server_api_compatibility( mallory, alice, monkeypatch): ash = ServerHandshake() bch = AuthenticatedClientHandshake(mallory.organization_id, mallory.device_id, mallory.signing_key, mallory.root_verify_key) challenge = b"1234567890" # Backend API >= 2.5 and Client API < 2.5 client_version = ApiVersion(2, 4) backend_version = ApiVersion(2, 5) answer = { "handshake": "answer", "type": HandshakeType.AUTHENTICATED.value, "client_api_version": client_version, "organization_id": str(alice.organization_id), "device_id": str(alice.device_id), "rvk": alice.root_verify_key.encode(), "answer": alice.signing_key.sign(challenge), } ash.build_challenge_req() ash.challenge = challenge ash.process_answer_req(packb(answer)) result_req = ash.build_result_req(alice.verify_key) result = handshake_result_serializer.loads(result_req) assert result["result"] == "ok" # Backend API < 2.5 and Client API >= 2.5 client_version = ApiVersion(2, 5) backend_version = ApiVersion(2, 4) req = { "handshake": "challenge", "challenge": challenge, "supported_api_versions": [backend_version], "backend_timestamp": pendulum.now(), "ballpark_client_early_offset": BALLPARK_CLIENT_EARLY_OFFSET, "ballpark_client_late_offset": BALLPARK_CLIENT_LATE_OFFSET, } monkeypatch.setattr(bch, "SUPPORTED_API_VERSIONS", [client_version]) answer_req = bch.process_challenge_req(packb(req)) answer = handshake_answer_serializer.loads(answer_req) assert mallory.verify_key.verify(answer["answer"]) == challenge
def test_good_anonymous_handshake(coolorg, check_rvk): sh = ServerHandshake() if check_rvk: ch = APIV1_AnonymousClientHandshake(coolorg.organization_id, coolorg.root_verify_key) else: ch = APIV1_AnonymousClientHandshake(coolorg.organization_id) assert sh.state == "stalled" challenge_req = sh.build_challenge_req() assert sh.state == "challenge" answer_req = ch.process_challenge_req(challenge_req) sh.process_answer_req(answer_req) assert sh.state == "answer" assert sh.answer_type == APIV1_HandshakeType.ANONYMOUS if check_rvk: assert sh.answer_data == { "client_api_version": API_V1_VERSION, "organization_id": coolorg.organization_id, "rvk": coolorg.root_verify_key, } else: assert sh.answer_data == { "client_api_version": API_V1_VERSION, "organization_id": coolorg.organization_id, "rvk": None, } result_req = sh.build_result_req() assert sh.state == "result" ch.process_result_req(result_req) assert sh.client_api_version == API_V1_VERSION
def test_good_handshake(alice): sh = ServerHandshake() ch = APIV1_AuthenticatedClientHandshake(alice.organization_id, alice.device_id, alice.signing_key, alice.root_verify_key) assert sh.state == "stalled" challenge_req = sh.build_challenge_req() assert sh.state == "challenge" answer_req = ch.process_challenge_req(challenge_req) sh.process_answer_req(answer_req) assert sh.state == "answer" assert sh.answer_type == APIV1_HandshakeType.AUTHENTICATED assert sh.answer_data == { "answer": ANY, "client_api_version": API_V1_VERSION, "organization_id": alice.organization_id, "device_id": alice.device_id, "rvk": alice.root_verify_key, } result_req = sh.build_result_req(alice.verify_key) assert sh.state == "result" ch.process_result_req(result_req) assert sh.client_api_version == API_V1_VERSION
def test_build_result_req_bad_challenge(alice): sh = ServerHandshake() sh.build_challenge_req() answer = { "handshake": "answer", "type": "authenticated", "client_api_version": API_V1_VERSION, "organization_id": alice.organization_id, "device_id": alice.device_id, "rvk": alice.root_verify_key.encode(), "answer": alice.signing_key.sign(sh.challenge + b"-dummy"), } sh.process_answer_req(packb(answer)) with pytest.raises(HandshakeFailedChallenge): sh.build_result_req(alice.verify_key)
def test_process_answer_req_bad_format(req, alice): for key, good_value in [ ("organization_id", str(alice.organization_id)), ("device_id", str(alice.device_id)), ("rvk", alice.root_verify_key.encode()), ]: if req.get(key) == "<good>": req[key] = good_value req["client_api_version"] = API_V1_VERSION sh = ServerHandshake() sh.build_challenge_req() with pytest.raises(InvalidMessageError): sh.process_answer_req(packb(req))
def test_build_bad_outcomes(alice, method, expected_result): sh = ServerHandshake() sh.build_challenge_req() answer = { "handshake": "answer", "type": "authenticated", "client_api_version": API_V1_VERSION, "organization_id": alice.organization_id, "device_id": alice.device_id, "rvk": alice.root_verify_key.encode(), "answer": alice.signing_key.sign(sh.challenge), } sh.process_answer_req(packb(answer)) req = getattr(sh, method)() assert unpackb(req) == {"handshake": "result", "result": expected_result, "help": ANY}
def test_build_bad_outcomes(alice, method, expected_result): sh = ServerHandshake() sh.build_challenge_req() answer = { "handshake": "answer", "type": APIV1_HandshakeType.ANONYMOUS.value, "client_api_version": API_V1_VERSION, "organization_id": str(alice.organization_id), "answer": alice.signing_key.sign(sh.challenge), } sh.process_answer_req(packb(answer)) req = getattr(sh, method)() assert unpackb(req) == { "handshake": "result", "result": expected_result, "help": ANY }
def test_good_administration_handshake(): admin_token = "Xx" * 16 sh = ServerHandshake() ch = APIV1_AdministrationClientHandshake(admin_token) assert sh.state == "stalled" challenge_req = sh.build_challenge_req() assert sh.state == "challenge" answer_req = ch.process_challenge_req(challenge_req) sh.process_answer_req(answer_req) assert sh.state == "answer" assert sh.answer_type == APIV1_HandshakeType.ADMINISTRATION assert sh.answer_data == {"client_api_version": API_V1_VERSION, "token": admin_token} result_req = sh.build_result_req() assert sh.state == "result" ch.process_result_req(result_req) assert sh.client_api_version == API_V1_VERSION