Exemplo n.º 1
0
    def test_pull_certificate_verify(self):
        buf = Buffer(data=load("tls_certificate_verify.bin"))
        verify = pull_certificate_verify(buf)
        self.assertTrue(buf.eof())

        self.assertEqual(verify.algorithm, tls.SignatureAlgorithm.RSA_PSS_RSAE_SHA256)
        self.assertEqual(verify.signature, CERTIFICATE_VERIFY_SIGNATURE)
Exemplo n.º 2
0
 def test_push_uint_var_too_big(self):
     buf = Buffer(capacity=8)
     with self.assertRaises(ValueError) as cm:
         buf.push_uint_var(4611686018427387904)
     self.assertEqual(
         str(cm.exception), "Integer is too big for a variable-length integer"
     )
Exemplo n.º 3
0
    def test_pull_certificate(self):
        buf = Buffer(data=load("tls_certificate.bin"))
        certificate = pull_certificate(buf)
        self.assertTrue(buf.eof())

        self.assertEqual(certificate.request_context, b"")
        self.assertEqual(certificate.certificates, [(CERTIFICATE_DATA, b"")])
Exemplo n.º 4
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
Exemplo n.º 5
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
Exemplo n.º 6
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())
Exemplo n.º 7
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, ""))
Exemplo n.º 8
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,
            ),
        )
Exemplo n.º 9
0
    def test_pull_server_hello(self):
        buf = Buffer(data=load("tls_server_hello.bin"))
        hello = pull_server_hello(buf)
        self.assertTrue(buf.eof())

        self.assertEqual(
            hello.random,
            binascii.unhexlify(
                "ada85271d19680c615ea7336519e3fdf6f1e26f3b1075ee1de96ffa8884e8280"
            ),
        )
        self.assertEqual(
            hello.session_id,
            binascii.unhexlify(
                "9aee82a2d186c1cb32a329d9dcfe004a1a438ad0485a53c6bfcf55c132a23235"
            ),
        )
        self.assertEqual(hello.cipher_suite, tls.CipherSuite.AES_256_GCM_SHA384)
        self.assertEqual(hello.compression_method, tls.CompressionMethod.NULL)
        self.assertEqual(
            hello.key_share,
            (
                tls.Group.SECP256R1,
                binascii.unhexlify(
                    "048b27d0282242d84b7fcc02a9c4f13eca0329e3c7029aa34a33794e6e7ba189"
                    "5cca1c503bf0378ac6937c354912116ff3251026bca1958d7f387316c83ae6cf"
                    "b2"
                ),
            ),
        )
        self.assertEqual(hello.pre_shared_key, None)
        self.assertEqual(hello.supported_version, tls.TLS_VERSION_1_3)
Exemplo n.º 10
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"))
Exemplo n.º 11
0
 def test_handle_new_token_frame(self):
     with client_and_server() as (client, server):
         # client receives NEW_TOKEN
         client._handle_new_token_frame(
             client_receive_context(client),
             QuicFrameType.NEW_TOKEN,
             Buffer(data=binascii.unhexlify("080102030405060708")),
         )
Exemplo n.º 12
0
    def test_handle_ack_frame_ecn(self):
        client = create_standalone_client(self)

        client._handle_ack_frame(
            client_receive_context(client),
            QuicFrameType.ACK_ECN,
            Buffer(data=b"\x00\x02\x00\x00\x00\x00\x00"),
        )
Exemplo n.º 13
0
 def test_handle_streams_blocked_uni_frame(self):
     with client_and_server() as (client, server):
         # client receives STREAMS_BLOCKED_UNI: 0
         client._handle_streams_blocked_frame(
             client_receive_context(client),
             QuicFrameType.STREAMS_BLOCKED_UNI,
             Buffer(data=b"\x00"),
         )
Exemplo n.º 14
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"))
Exemplo n.º 15
0
 def test_pull_long_header_scid_too_long(self):
     buf = Buffer(data=binascii.unhexlify(
         "c2ff0000160015000000000000000000000000000000000000000000004"
         "01cfcee99ec4bbf1f7a30f9b0c9417b8c263cdd8cc972a4439d68a46320"))
     with self.assertRaises(ValueError) as cm:
         pull_quic_header(buf, host_cid_length=8)
     self.assertEqual(str(cm.exception),
                      "Source CID is too long (21 bytes)")
Exemplo n.º 16
0
 def test_pull_long_header_dcid_too_long(self):
     buf = Buffer(data=binascii.unhexlify(
         "c6ff0000161500000000000000000000000000000000000000000000004"
         "01c514f99ec4bbf1f7a30f9b0c94fef717f1c1d07fec24c99a864da7ede"))
     with self.assertRaises(ValueError) as cm:
         pull_quic_header(buf, host_cid_length=8)
     self.assertEqual(str(cm.exception),
                      "Destination CID is too long (21 bytes)")
Exemplo n.º 17
0
    def test_params_unknown(self):
        data = binascii.unhexlify("8000ff000100")

        # parse
        buf = Buffer(data=data)
        params = pull_quic_transport_parameters(
            buf, protocol_version=QuicProtocolVersion.DRAFT_27)
        self.assertEqual(params, QuicTransportParameters())
Exemplo n.º 18
0
def parse_settings(data: bytes) -> Dict[int, int]:
    buf = Buffer(data=data)
    settings = []
    while not buf.eof():
        setting = buf.pull_uint_var()
        value = buf.pull_uint_var()
        settings.append((setting, value))
    return dict(settings)
Exemplo n.º 19
0
 def test_handle_data_blocked_frame(self):
     with client_and_server() as (client, server):
         # client receives DATA_BLOCKED: 12345
         client._handle_data_blocked_frame(
             client_receive_context(client),
             QuicFrameType.DATA_BLOCKED,
             Buffer(data=encode_uint_var(12345)),
         )
Exemplo n.º 20
0
    def _receive_data_on_session_stream(self, data: bytes, fin: bool) -> None:
        self._capsule_decoder_for_session_stream.append(data)
        if fin:
            self._capsule_decoder_for_session_stream.final()
        for capsule in self._capsule_decoder_for_session_stream:
            if capsule.type in {
                    CapsuleType.DATAGRAM,
                    CapsuleType.REGISTER_DATAGRAM_CONTEXT,
                    CapsuleType.CLOSE_DATAGRAM_CONTEXT
            }:
                raise ProtocolError(
                    f"Unimplemented capsule type: {capsule.type}")
            if capsule.type in {
                    CapsuleType.REGISTER_DATAGRAM_NO_CONTEXT,
                    CapsuleType.CLOSE_WEBTRANSPORT_SESSION
            }:
                # We'll handle this case below.
                pass
            else:
                # We should ignore unknown capsules.
                continue

            if self._close_info is not None:
                raise ProtocolError(
                    ("Receiving a capsule with type = {} after receiving " +
                     "CLOSE_WEBTRANSPORT_SESSION").format(capsule.type))

            if capsule.type == CapsuleType.REGISTER_DATAGRAM_NO_CONTEXT:
                buffer = Buffer(data=capsule.data)
                format_type = buffer.pull_uint_var()
                # https://ietf-wg-webtrans.github.io/draft-ietf-webtrans-http3/draft-ietf-webtrans-http3.html#name-datagram-format-type
                WEBTRANPORT_FORMAT_TYPE = 0xff7c00
                if format_type != WEBTRANPORT_FORMAT_TYPE:
                    raise ProtocolError(
                        "Unexpected datagram format type: {}".format(
                            format_type))
                self._allow_datagrams = True
            elif capsule.type == CapsuleType.CLOSE_WEBTRANSPORT_SESSION:
                buffer = Buffer(data=capsule.data)
                code = buffer.pull_uint32()
                # 4 bytes for the uint32.
                reason = buffer.pull_bytes(len(capsule.data) - 4)
                # TODO(yutakahirano): Make sure `reason` is a UTF-8 text.
                self._close_info = (code, reason)
                if fin:
                    self._call_session_closed(self._close_info, abruptly=False)
Exemplo n.º 21
0
    def test_push_finished(self):
        finished = Finished(verify_data=binascii.unhexlify(
            "f157923234ff9a4921aadb2e0ec7b1a30fce73fb9ec0c4276f9af268f408ec68")
                            )

        buf = Buffer(128)
        push_finished(buf, finished)
        self.assertEqual(buf.data, load("tls_finished.bin"))
Exemplo n.º 22
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
Exemplo n.º 23
0
    def test_push_certificate_verify(self):
        verify = CertificateVerify(
            algorithm=tls.SignatureAlgorithm.RSA_PSS_RSAE_SHA256,
            signature=CERTIFICATE_VERIFY_SIGNATURE,
        )

        buf = Buffer(400)
        push_certificate_verify(buf, verify)
        self.assertEqual(buf.data, load("tls_certificate_verify.bin"))
Exemplo n.º 24
0
    def _make_connection(self, channel, data):
        ctx = channel.server.ctx

        buf = Buffer(data=data)
        header = pull_quic_header(buf,
                                  host_cid_length=ctx.connection_id_length)
        # version negotiation
        if header.version is not None and header.version not in ctx.supported_versions:
            self.channel.push(
                encode_quic_version_negotiation(
                    source_cid=header.destination_cid,
                    destination_cid=header.source_cid,
                    supported_versions=ctx.supported_versions,
                ))
            return

        conn = self.conns.get(header.destination_cid)
        if conn:
            conn._linked_channel.close()
            conn._linked_channel = channel
            self.quic = conn._quic
            self.conn = conn
            return

        if header.packet_type != PACKET_TYPE_INITIAL or len(data) < 1200:
            return

        original_connection_id = None
        if self._retry is not None:
            if not header.token:
                # create a retry token
                channel.push(
                    encode_quic_retry(
                        version=header.version,
                        source_cid=os.urandom(8),
                        destination_cid=header.source_cid,
                        original_destination_cid=header.destination_cid,
                        retry_token=self._retry.create_token(
                            channel.addr, header.destination_cid)))
                return
            else:
                try:
                    original_connection_id = self._retry.validate_token(
                        channel.addr, header.token)
                except ValueError:
                    return

        self.quic = QuicConnection(
            configuration=ctx,
            logger_connection_id=original_connection_id
            or header.destination_cid,
            original_connection_id=original_connection_id,
            session_ticket_fetcher=channel.server.ticket_store.pop,
            session_ticket_handler=channel.server.ticket_store.add)
        self.conn = H3Connection(self.quic)
        self.conn._linked_channel = channel
Exemplo n.º 25
0
    def test_handle_max_streams_uni_frame(self):
        with client_and_server() as (client, server):
            self.assertEqual(client._remote_max_streams_uni, 128)

            # client receives MAX_STREAMS_UNI raising limit
            client._handle_max_streams_uni_frame(
                client_receive_context(client),
                QuicFrameType.MAX_STREAMS_UNI,
                Buffer(data=encode_uint_var(129)),
            )
            self.assertEqual(client._remote_max_streams_uni, 129)

            # client receives MAX_STREAMS_UNI raising limit
            client._handle_max_streams_uni_frame(
                client_receive_context(client),
                QuicFrameType.MAX_STREAMS_UNI,
                Buffer(data=encode_uint_var(127)),
            )
            self.assertEqual(client._remote_max_streams_uni, 129)
Exemplo n.º 26
0
 def _receive_datagram(self, data: bytes) -> List[H3Event]:
     """
     Handle a datagram.
     """
     buf = Buffer(data=data)
     try:
         flow_id = buf.pull_uint_var()
     except BufferReadError:
         raise ProtocolError("Could not parse flow ID")
     return [DatagramReceived(data=data[buf.tell():], flow_id=flow_id)]
Exemplo n.º 27
0
    def test_encrypted_extensions(self):
        data = load("tls_encrypted_extensions.bin")
        buf = Buffer(data=data)
        extensions = pull_encrypted_extensions(buf)
        self.assertIsNotNone(extensions)
        self.assertTrue(buf.eof())

        self.assertEqual(
            extensions,
            EncryptedExtensions(other_extensions=[(
                tls.ExtensionType.QUIC_TRANSPORT_PARAMETERS,
                SERVER_QUIC_TRANSPORT_PARAMETERS,
            )]),
        )

        # serialize
        buf = Buffer(capacity=100)
        push_encrypted_extensions(buf, extensions)
        self.assertEqual(buf.data, data)
Exemplo n.º 28
0
    def test_handle_stop_sending_frame(self):
        with client_and_server() as (client, server):
            # client creates bidirectional stream 0
            client.send_stream_data(stream_id=0, data=b"hello")

            # client receives STOP_SENDING
            client._handle_stop_sending_frame(
                client_receive_context(client),
                QuicFrameType.STOP_SENDING,
                Buffer(data=b"\x00\x11\x22"),
            )
Exemplo n.º 29
0
    def test_handle_stream_data_blocked_frame(self):
        with client_and_server() as (client, server):
            # client creates bidirectional stream 0
            client.send_stream_data(stream_id=0, data=b"hello")

            # client receives STREAM_DATA_BLOCKED
            client._handle_stream_data_blocked_frame(
                client_receive_context(client),
                QuicFrameType.STREAM_DATA_BLOCKED,
                Buffer(data=b"\x00\x01"),
            )
Exemplo n.º 30
0
    def test_pull_finished(self):
        buf = Buffer(data=load("tls_finished.bin"))
        finished = pull_finished(buf)
        self.assertTrue(buf.eof())

        self.assertEqual(
            finished.verify_data,
            binascii.unhexlify(
                "f157923234ff9a4921aadb2e0ec7b1a30fce73fb9ec0c4276f9af268f408ec68"
            ),
        )