Beispiel #1
0
 def test_pull_short_header(self):
     buf = Buffer(data=load("short_header.bin"))
     header = pull_quic_header(buf, host_cid_length=8)
     self.assertFalse(header.is_long_header)
     self.assertEqual(header.version, None)
     self.assertEqual(header.packet_type, 0x50)
     self.assertEqual(header.destination_cid,
                      binascii.unhexlify("f45aa7b59c0e1ad6"))
     self.assertEqual(header.source_cid, b"")
     self.assertEqual(header.original_destination_cid, b"")
     self.assertEqual(header.token, b"")
     self.assertEqual(header.rest_length, 12)
     self.assertEqual(buf.tell(), 9)
Beispiel #2
0
    def test_params_disable_migration(self):
        data = binascii.unhexlify("0004000c0000")

        # parse
        buf = Buffer(data=data)
        params = pull_quic_transport_parameters(buf)
        self.assertEqual(params,
                         QuicTransportParameters(disable_migration=True))

        # serialize
        buf = Buffer(capacity=len(data))
        push_quic_transport_parameters(buf, params)
        self.assertEqual(buf.data, data)
Beispiel #3
0
    def test_transport_close(self):
        data = binascii.unhexlify(
            "000a0212696c6c6567616c2041434b206672616d6500")

        # parse
        buf = Buffer(data=data)
        frame = packet.pull_transport_close_frame(buf)
        self.assertEqual(frame, (10, 2, "illegal ACK frame\x00"))

        # serialize
        buf = Buffer(capacity=len(data))
        packet.push_transport_close_frame(buf, *frame)
        self.assertEqual(buf.data, data)
Beispiel #4
0
    def test_ack_frame_with_one_range_3(self):
        data = b"\x05\x02\x01\x00\x01\x02"

        # parse
        buf = Buffer(data=data)
        rangeset, delay = packet.pull_ack_frame(buf)
        self.assertEqual(list(rangeset), [range(0, 3), range(5, 6)])
        self.assertEqual(delay, 2)

        # serialize
        buf = Buffer(capacity=len(data))
        packet.push_ack_frame(buf, rangeset, delay)
        self.assertEqual(buf.data, data)
Beispiel #5
0
 def test_pull_initial_client(self):
     buf = Buffer(data=load("initial_client.bin"))
     header = pull_quic_header(buf, host_cid_length=8)
     self.assertTrue(header.is_long_header)
     self.assertEqual(header.version, QuicProtocolVersion.VERSION_1)
     self.assertEqual(header.packet_type, PACKET_TYPE_INITIAL)
     self.assertEqual(header.destination_cid,
                      binascii.unhexlify("858b39368b8e3c6e"))
     self.assertEqual(header.source_cid, b"")
     self.assertEqual(header.token, b"")
     self.assertEqual(header.integrity_tag, b"")
     self.assertEqual(header.rest_length, 1262)
     self.assertEqual(buf.tell(), 18)
Beispiel #6
0
 def test_pull_initial_client(self):
     buf = Buffer(data=load("initial_client.bin"))
     header = pull_quic_header(buf, host_cid_length=8)
     self.assertTrue(header.is_long_header)
     self.assertEqual(header.version, QuicProtocolVersion.DRAFT_17)
     self.assertEqual(header.packet_type, PACKET_TYPE_INITIAL)
     self.assertEqual(header.destination_cid,
                      binascii.unhexlify("90ed1e1c7b04b5d3"))
     self.assertEqual(header.source_cid, b"")
     self.assertEqual(header.original_destination_cid, b"")
     self.assertEqual(header.token, b"")
     self.assertEqual(header.rest_length, 1263)
     self.assertEqual(buf.tell(), 17)
Beispiel #7
0
    def test_ack_frame_with_two_ranges(self):
        data = b"\x04\x02\x02\x00\x00\x00\x00\x00"

        # parse
        buf = Buffer(data=data)
        rangeset, delay = packet.pull_ack_frame(buf)
        self.assertEqual(list(rangeset), [range(0, 1), range(2, 3), range(4, 5)])
        self.assertEqual(delay, 2)

        # serialize
        buf = Buffer(capacity=len(data))
        packet.push_ack_frame(buf, rangeset, delay)
        self.assertEqual(buf.data, data)
Beispiel #8
0
 def test_pull_initial_server(self):
     buf = Buffer(data=load("initial_server.bin"))
     header = pull_quic_header(buf, host_cid_length=8)
     self.assertTrue(header.is_long_header)
     self.assertEqual(header.version, QuicProtocolVersion.DRAFT_25)
     self.assertEqual(header.packet_type, PACKET_TYPE_INITIAL)
     self.assertEqual(header.destination_cid, b"")
     self.assertEqual(header.source_cid,
                      binascii.unhexlify("195c68344e28d479"))
     self.assertEqual(header.token, b"")
     self.assertEqual(header.integrity_tag, b"")
     self.assertEqual(header.rest_length, 184)
     self.assertEqual(buf.tell(), 18)
Beispiel #9
0
def parse_settings(data: bytes) -> Dict[int, int]:
    buf = Buffer(data=data)
    settings: Dict[int, int] = {}
    while not buf.eof():
        setting = buf.pull_uint_var()
        value = buf.pull_uint_var()
        if setting in RESERVED_SETTINGS:
            raise SettingsError("Setting identifier 0x%x is reserved" %
                                setting)
        if setting in settings:
            raise SettingsError("Setting identifier 0x%x is included twice" %
                                setting)
        settings[setting] = value
    return dict(settings)
Beispiel #10
0
    def test_pull_retry(self):
        original_destination_cid = binascii.unhexlify("fbbd219b7363b64b")

        data = load("retry.bin")
        buf = Buffer(data=data)
        header = pull_quic_header(buf, host_cid_length=8)
        self.assertTrue(header.is_long_header)
        self.assertEqual(header.version, QuicProtocolVersion.VERSION_1)
        self.assertEqual(header.packet_type, PACKET_TYPE_RETRY)
        self.assertEqual(header.destination_cid,
                         binascii.unhexlify("e9d146d8d14cb28e"))
        self.assertEqual(
            header.source_cid,
            binascii.unhexlify("0b0a205a648fcf82d85f128b67bbe08053e6"),
        )
        self.assertEqual(
            header.token,
            binascii.unhexlify(
                "44397a35d698393c134b08a932737859f446d3aadd00ed81540c8d8de172"
                "906d3e7a111b503f9729b8928e7528f9a86a4581f9ebb4cb3b53c283661e"
                "8530741a99192ee56914c5626998ec0f"),
        )
        self.assertEqual(
            header.integrity_tag,
            binascii.unhexlify("4620aafd42f1d630588b27575a12da5c"))
        self.assertEqual(header.rest_length, 0)
        self.assertEqual(buf.tell(), 125)

        # check integrity
        if False:
            self.assertEqual(
                get_retry_integrity_tag(
                    buf.data_slice(0, 109),
                    original_destination_cid,
                    version=header.version,
                ),
                header.integrity_tag,
            )

        # serialize
        encoded = encode_quic_retry(
            version=header.version,
            source_cid=header.source_cid,
            destination_cid=header.destination_cid,
            original_destination_cid=original_destination_cid,
            retry_token=header.token,
        )
        with open("bob.bin", "wb") as fp:
            fp.write(encoded)
        self.assertEqual(encoded, data)
Beispiel #11
0
    def append(self, data: bytes) -> None:
        """
        Appends the given bytes to this decoder.
        """
        assert not self._final

        if len(data) == 0:
            return
        if self._buffer:
            remaining = self._buffer.pull_bytes(self._buffer.capacity -
                                                self._buffer.tell())
            self._buffer = Buffer(data=(remaining + data))
        else:
            self._buffer = Buffer(data=data)
Beispiel #12
0
 def test_pull_version_negotiation(self):
     buf = Buffer(data=load("version_negotiation.bin"))
     header = pull_quic_header(buf, host_cid_length=8)
     self.assertTrue(header.is_long_header)
     self.assertEqual(header.version, QuicProtocolVersion.NEGOTIATION)
     self.assertEqual(header.packet_type, None)
     self.assertEqual(header.destination_cid,
                      binascii.unhexlify("9aac5a49ba87a849"))
     self.assertEqual(header.source_cid,
                      binascii.unhexlify("f92f4336fa951ba1"))
     self.assertEqual(header.original_destination_cid, b"")
     self.assertEqual(header.token, b"")
     self.assertEqual(header.rest_length, 8)
     self.assertEqual(buf.tell(), 23)
Beispiel #13
0
def encode_frame(frame_type: int, frame_data: bytes) -> bytes:
    frame_length = len(frame_data)
    buf = Buffer(capacity=frame_length + 16)
    buf.push_uint_var(frame_type)
    buf.push_uint_var(frame_length)
    buf.push_bytes(frame_data)
    return buf.data
Beispiel #14
0
 def test_pull_version_negotiation(self):
     buf = Buffer(data=load("version_negotiation.bin"))
     header = pull_quic_header(buf, host_cid_length=8)
     self.assertTrue(header.is_long_header)
     self.assertEqual(header.version, QuicProtocolVersion.NEGOTIATION)
     self.assertEqual(header.packet_type, None)
     self.assertEqual(header.destination_cid,
                      binascii.unhexlify("dae1889b81a91c26"))
     self.assertEqual(header.source_cid,
                      binascii.unhexlify("f49243784f9bf3be"))
     self.assertEqual(header.original_destination_cid, b"")
     self.assertEqual(header.token, b"")
     self.assertEqual(header.rest_length, 8)
     self.assertEqual(buf.tell(), 22)
Beispiel #15
0
    def test_data_slice(self):
        buf = Buffer(data=b"\x08\x07\x06\x05\x04\x03\x02\x01")
        self.assertEqual(buf.data_slice(0, 8), b"\x08\x07\x06\x05\x04\x03\x02\x01")
        self.assertEqual(buf.data_slice(1, 3), b"\x07\x06")

        with self.assertRaises(BufferReadError):
            buf.data_slice(-1, 3)
        with self.assertRaises(BufferReadError):
            buf.data_slice(0, 9)
        with self.assertRaises(BufferReadError):
            buf.data_slice(1, 0)
Beispiel #16
0
    def test_pull_uint_var_truncated(self):
        buf = Buffer(capacity=0)
        with self.assertRaises(BufferReadError):
            buf.pull_uint_var()

        buf = Buffer(data=b"\xff")
        with self.assertRaises(BufferReadError):
            buf.pull_uint_var()
Beispiel #17
0
    def test_params_disable_active_migration_legacy(self):
        data = binascii.unhexlify("0004000c0000")

        # parse
        buf = Buffer(data=data)
        params = pull_quic_transport_parameters(
            buf, protocol_version=QuicProtocolVersion.DRAFT_25)
        self.assertEqual(
            params, QuicTransportParameters(disable_active_migration=True))

        # serialize
        buf = Buffer(capacity=len(data))
        push_quic_transport_parameters(
            buf, params, protocol_version=QuicProtocolVersion.DRAFT_25)
        self.assertEqual(buf.data, data)
Beispiel #18
0
    def roundtrip(self, data, value):
        buf = Buffer(data=data)
        self.assertEqual(buf.pull_uint_var(), value)
        self.assertEqual(buf.tell(), len(data))

        buf = Buffer(capacity=8)
        buf.push_uint_var(value)
        self.assertEqual(buf.data, data)
Beispiel #19
0
    def test_application_close_not_utf8(self):
        data = binascii.unhexlify("0008676f6f6462798200")

        # parse
        buf = Buffer(data=data)
        frame = packet.pull_application_close_frame(buf)
        self.assertEqual(frame, (0, ""))
Beispiel #20
0
    def test_transport_close(self):
        data = binascii.unhexlify("0a0212696c6c6567616c2041434b206672616d6500")

        # parse
        buf = Buffer(data=data)
        frame = packet.pull_transport_close_frame(buf)
        self.assertEqual(frame, (10, 2, "illegal ACK frame\x00"))
Beispiel #21
0
    def test_params_unknown(self):
        # fb.mvfst.net sends a proprietary parameter 65280
        data = binascii.unhexlify(
            "006400050004800104000006000480010400000700048001040000040004801"
            "0000000080008c0000000ffffffff00090008c0000000ffffffff0001000480"
            "00ea60000a00010300030002500000020010616161616262626263636363646"
            "46464ff00000100")

        # parse
        buf = Buffer(data=data)
        params = pull_quic_transport_parameters(buf)
        self.assertEqual(
            params,
            QuicTransportParameters(
                idle_timeout=60000,
                stateless_reset_token=b"aaaabbbbccccdddd",
                max_packet_size=4096,
                initial_max_data=1048576,
                initial_max_stream_data_bidi_local=66560,
                initial_max_stream_data_bidi_remote=66560,
                initial_max_stream_data_uni=66560,
                initial_max_streams_bidi=4294967295,
                initial_max_streams_uni=4294967295,
                ack_delay_exponent=3,
            ),
        )
Beispiel #22
0
    def test_handle_stream_data_blocked_frame_send_only(self):
        client = QuicConnection(is_client=True)
        server = QuicConnection(
            is_client=False,
            certificate=SERVER_CERTIFICATE,
            private_key=SERVER_PRIVATE_KEY,
        )

        # perform handshake
        client_transport, server_transport = create_transport(client, server)

        # client creates unidirectional stream 2
        client.create_stream(is_unidirectional=True)

        # client receives STREAM_DATA_BLOCKED
        with self.assertRaises(QuicConnectionError) as cm:
            client._handle_stream_data_blocked_frame(
                tls.Epoch.ONE_RTT,
                QuicFrameType.STREAM_DATA_BLOCKED,
                Buffer(data=b"\x02\x01"),
            )
        self.assertEqual(cm.exception.error_code,
                         QuicErrorCode.STREAM_STATE_ERROR)
        self.assertEqual(cm.exception.frame_type,
                         QuicFrameType.STREAM_DATA_BLOCKED)
        self.assertEqual(cm.exception.reason_phrase, "Stream is send-only")
Beispiel #23
0
    def test_send_stream_data_over_max_streams_uni(self):
        with client_and_server() as (client, server):
            # create streams
            for i in range(128):
                stream_id = i * 4 + 2
                client.send_stream_data(stream_id, b"")
                self.assertFalse(client._streams[stream_id].is_blocked)
            self.assertEqual(len(client._streams_blocked_bidi), 0)
            self.assertEqual(len(client._streams_blocked_uni), 0)
            self.assertEqual(roundtrip(client, server), (0, 0))

            # create one too many -> STREAMS_BLOCKED
            stream_id = 128 * 4 + 2
            client.send_stream_data(stream_id, b"")
            self.assertTrue(client._streams[stream_id].is_blocked)
            self.assertEqual(len(client._streams_blocked_bidi), 0)
            self.assertEqual(len(client._streams_blocked_uni), 1)
            self.assertEqual(roundtrip(client, server), (1, 1))

            # peer raises max streams
            client._handle_max_streams_uni_frame(
                client_receive_context(client),
                QuicFrameType.MAX_STREAMS_UNI,
                Buffer(data=encode_uint_var(129)),
            )
            self.assertFalse(client._streams[stream_id].is_blocked)
Beispiel #24
0
    def test_push_certificate(self):
        certificate = Certificate(request_context=b"",
                                  certificates=[(CERTIFICATE_DATA, b"")])

        buf = Buffer(1600)
        push_certificate(buf, certificate)
        self.assertEqual(buf.data, load("tls_certificate.bin"))
Beispiel #25
0
 def test_handle_ack_frame_ecn(self):
     client = QuicConnection(is_client=True)
     client._handle_ack_frame(
         tls.Epoch.ONE_RTT,
         QuicFrameType.ACK_ECN,
         Buffer(data=b"\x00\x02\x00\x00\x00\x00\x00"),
     )
Beispiel #26
0
    def test_handle_stop_sending_frame_receive_only(self):
        client = QuicConnection(is_client=True)
        server = QuicConnection(
            is_client=False,
            certificate=SERVER_CERTIFICATE,
            private_key=SERVER_PRIVATE_KEY,
        )

        # perform handshake
        client_transport, server_transport = create_transport(client, server)

        # server creates unidirectional stream 3
        server.create_stream(is_unidirectional=True)

        # client receives STOP_SENDING
        with self.assertRaises(QuicConnectionError) as cm:
            client._handle_stop_sending_frame(
                tls.Epoch.ONE_RTT,
                QuicFrameType.STOP_SENDING,
                Buffer(data=b"\x03\x11\x22"),
            )
        self.assertEqual(cm.exception.error_code,
                         QuicErrorCode.STREAM_STATE_ERROR)
        self.assertEqual(cm.exception.frame_type, QuicFrameType.STOP_SENDING)
        self.assertEqual(cm.exception.reason_phrase, "Stream is receive-only")
Beispiel #27
0
    async def handle(self, event: Event) -> None:
        if isinstance(event, RawData):
            try:
                header = pull_quic_header(Buffer(data=event.data), host_cid_length=8)
            except ValueError:
                return
            if (
                header.version is not None
                and header.version not in self.quic_config.supported_versions
            ):
                data = encode_quic_version_negotiation(
                    source_cid=header.destination_cid,
                    destination_cid=header.source_cid,
                    supported_versions=self.quic_config.supported_versions,
                )
                await self.send(RawData(data=data, address=event.address))
                return

            connection = self.connections.get(header.destination_cid)
            if (
                connection is None
                and len(event.data) >= 1200
                and header.packet_type == PACKET_TYPE_INITIAL
            ):
                connection = QuicConnection(
                    configuration=self.quic_config, original_connection_id=None
                )
                self.connections[header.destination_cid] = connection
                self.connections[connection.host_cid] = connection

            if connection is not None:
                connection.receive_datagram(event.data, event.address, now=self.now())
                await self._handle_events(connection, event.address)
        elif isinstance(event, Closed):
            pass
Beispiel #28
0
    def test_params_unknown(self):
        data = binascii.unhexlify("8000ff000100")

        # parse
        buf = Buffer(data=data)
        params = pull_quic_transport_parameters(buf)
        self.assertEqual(params, QuicTransportParameters())
Beispiel #29
0
    def test_handle_stream_frame_over_max_stream_data(self):
        client = QuicConnection(is_client=True)
        server = QuicConnection(
            is_client=False,
            certificate=SERVER_CERTIFICATE,
            private_key=SERVER_PRIVATE_KEY,
        )

        # perform handshake
        client_transport, server_transport = create_transport(client, server)

        # client receives STREAM frame
        frame_type = QuicFrameType.STREAM_BASE | QuicStreamFlag.OFF
        stream_id = 1
        with self.assertRaises(QuicConnectionError) as cm:
            client._handle_stream_frame(
                tls.Epoch.ONE_RTT,
                frame_type,
                Buffer(
                    data=encode_uint_var(stream_id) +
                    encode_uint_var(client._local_max_stream_data_bidi_remote +
                                    1)),
            )
        self.assertEqual(cm.exception.error_code,
                         QuicErrorCode.FLOW_CONTROL_ERROR)
        self.assertEqual(cm.exception.frame_type, frame_type)
        self.assertEqual(cm.exception.reason_phrase, "Over stream data limit")
Beispiel #30
0
 def encode(self) -> bytes:
     """
     Encodes this H3Capsule and return the bytes.
     """
     buffer = Buffer(capacity=len(self.data) + 2 * UINT_VAR_MAX_SIZE)
     buffer.push_uint_var(self.type)
     buffer.push_uint_var(len(self.data))
     buffer.push_bytes(self.data)
     return buffer.data