async def test_authenticated_handshake_unknown_device(backend, server_factory, mallory): ch = AuthenticatedClientHandshake( organization_id=mallory.organization_id, device_id=mallory.device_id, user_signkey=mallory.signing_key, root_verify_key=mallory.root_verify_key, ) async with server_factory(backend.handle_client) as server: stream = server.connection_factory() transport = await Transport.init_for_client(stream, server.addr.hostname) challenge_req = await transport.recv() answer_req = ch.process_challenge_req(challenge_req) await transport.send(answer_req) result_req = await transport.recv() with pytest.raises(HandshakeBadIdentity): ch.process_result_req(result_req)
async def test_authenticated_handshake_bad_rvk(backend, server_factory, alice, otherorg): ch = AuthenticatedClientHandshake( organization_id=alice.organization_id, device_id=alice.device_id, user_signkey=alice.signing_key, root_verify_key=otherorg.root_verify_key, ) async with server_factory(backend.handle_client) as server: stream = server.connection_factory() transport = await Transport.init_for_client(stream, server.addr.hostname) challenge_req = await transport.recv() answer_req = ch.process_challenge_req(challenge_req) await transport.send(answer_req) result_req = await transport.recv() with pytest.raises(HandshakeRVKMismatch): ch.process_result_req(result_req)
async def test_authenticated_handshake_good(backend, server_factory, alice): ch = AuthenticatedClientHandshake( organization_id=alice.organization_id, device_id=alice.device_id, user_signkey=alice.signing_key, root_verify_key=alice.root_verify_key, ) async with server_factory(backend.handle_client) as server: stream = await server.connection_factory() transport = await Transport.init_for_client(stream, "127.0.0.1") challenge_req = await transport.recv() answer_req = ch.process_challenge_req(challenge_req) await transport.send(answer_req) result_req = await transport.recv() ch.process_result_req(result_req) assert ch.client_api_version == API_VERSION assert ch.backend_api_version == API_VERSION
async def _backend_sock_factory(backend, auth_as: LocalDevice, freeze_on_transport_error=True, keepalive=None): async with backend_raw_transport_factory( backend, freeze_on_transport_error=freeze_on_transport_error, keepalive=keepalive) as transport: # Handshake ch = AuthenticatedClientHandshake( auth_as.organization_id, auth_as.device_id, auth_as.signing_key, auth_as.root_verify_key, ) challenge_req = await transport.recv() answer_req = ch.process_challenge_req(challenge_req) await transport.send(answer_req) result_req = await transport.recv() ch.process_result_req(result_req) yield transport
def test_process_challenge_req_bad_format(alice, req): ch = AuthenticatedClientHandshake( alice.organization_id, alice.device_id, alice.signing_key, alice.root_verify_key ) with pytest.raises(InvalidMessageError): ch.process_challenge_req(packb(req))
async def test_handle_client_coroutine_destroyed_on_client_left( backend, alice, close_on, clean_close, recwarn): # For this test we want to use a real TCP socket (instead of relying on # the `tcp_stream_spy` mock fixture) test the backend on outcome = None outcome_available = trio.Event() async def _handle_client_with_captured_outcome(stream): nonlocal outcome try: ret = await backend.handle_client(stream) except BaseException as exc: outcome = ("exception", exc) outcome_available.set() raise else: outcome = ("return", ret) outcome_available.set() return ret async with trio.open_nursery() as nursery: try: # Start server listeners = await nursery.start( trio.serve_tcp, _handle_client_with_captured_outcome, 0) # Client connect to the server client_stream = await open_stream_to_socket_listener(listeners[0]) async def _do_close_client(): if clean_close: await client_stream.aclose() else: # Reset the tcp socket instead of regular clean close # See https://stackoverflow.com/a/54065411 l_onoff = 1 l_linger = 0 client_stream.setsockopt( socket.SOL_SOCKET, socket.SO_LINGER, struct.pack("ii", l_onoff, l_linger)) client_stream.socket.close() with trio.fail_after(1): await outcome_available.wait() if close_on == "tcp_ready": await _do_close_client() else: if close_on == "before_http_request": # Send the beginning of an http request await client_stream.send_all(b"GET / HTTP/1.1\r\n") await _do_close_client() elif close_on in ("after_http_request"): # Send an entire http request await client_stream.send_all(b"GET / HTTP/1.0\r\n\r\n") # Peer will realize connection is closed after having sent # the answer for the previous request await _do_close_client() else: # First request doing websocket negotiation hostname = f"127.0.0.1:{listeners[0].socket.getsockname()}" transport = await Transport.init_for_client( client_stream, hostname) if close_on == "websocket_ready": await _do_close_client() else: # Client do the handshake ch = AuthenticatedClientHandshake( alice.organization_id, alice.device_id, alice.signing_key, alice.root_verify_key, ) challenge_req = await transport.recv() answer_req = ch.process_challenge_req(challenge_req) if close_on == "handshake_started": await _do_close_client() else: await transport.send(answer_req) result_req = await transport.recv() ch.process_result_req(result_req) assert close_on == "handshake_done" # Sanity check await _do_close_client() # Outcome should aways be the same assert outcome == ("return", None) finally: nursery.cancel_scope.cancel()