def test_entrylist_first_by_id(self):
     el = tlv8.EntryList([
         tlv8.Entry(2, b'\x23'),
         tlv8.Entry(2, b'\x42')
     ])
     self.assertEqual(el.first_by_id(1), None)
     self.assertEqual(el.first_by_id(2), el[0])
Example #2
0
    def do_char_write(self, tid, value):
        """The value is actually a TLV with a command to perform"""

        request = {
            entry.type_id: entry.data
            for entry in tlv8.decode(
                value, {
                    TlvTypes.State: tlv8.DataType.INTEGER,
                    TlvTypes.Method: tlv8.DataType.INTEGER,
                    TlvTypes.Identifier: tlv8.DataType.BYTES,
                })
        }
        logging.debug('%s', request)

        assert request[TlvTypes.State] == States.M1

        if request[TlvTypes.Method] == Methods.RemovePairing:
            ident = request[TlvTypes.Identifier].decode()
            self.service.device.peers.pop(ident, None)

            # If ident == this session then disconnect it
            # self.service.device.disconnect()

        response = bytearray([0x02, tid, 0x00])

        inner = tlv8.encode([
            tlv8.Entry(TlvTypes.State, States.M2),
        ])

        outer = tlv8.encode(
            [tlv8.Entry(AdditionalParameterTypes.Value, inner)])
        response.extend(len(outer).to_bytes(length=2, byteorder='little'))
        response.extend(outer)

        self.queue_read_response(self.encrypt_value(bytes(response)))
Example #3
0
 def test_decode_example_3(self):
     input_data = b'\x01\x15\x01\x10e\xad\x8b\xe8\xb3fD\xcb\xbde#\xccc\n\xb8\xef\x02\x01\x01'
     structure = {
         1: {
             1: tlv8.DataType.BYTES,
             2: tlv8.DataType.INTEGER,
         },
         2: {
             1: tlv8.DataType.INTEGER,
             2: tlv8.DataType.BYTES,
             3: tlv8.DataType.BYTES,
             4: tlv8.DataType.BYTES
         },
         3: {
             1: tlv8.DataType.INTEGER,
             2: tlv8.DataType.INTEGER,
             3: tlv8.DataType.INTEGER,
             4: tlv8.DataType.INTEGER,
             5: tlv8.DataType.INTEGER
         }
     }
     result = tlv8.decode(input_data, structure)
     expected = tlv8.EntryList([
         tlv8.Entry(1, tlv8.EntryList([
             tlv8.Entry(1, b'e\xad\x8b\xe8\xb3fD\xcb\xbde#\xccc\n\xb8\xef'),
             tlv8.Entry(2, 1),
         ])),
     ])
     self.assertEqual(expected, result)
Example #4
0
 def test_decode_missing_separator_nonstrict(self):
     data = b'\x01\x01\x02\x01\x01\x02'
     result = tlv8.deep_decode(data, strict_mode=False)
     self.assertEqual(
         result,
         tlv8.EntryList([tlv8.Entry(1, b'\x02'),
                         tlv8.Entry(1, b'\x02')]))
    def add_pairing(self, additional_controller_pairing_identifier,
                    ios_device_ltpk, permissions):
        if not self.session:
            self.session = IpSession(self.pairing_data)
        if permissions == 'User':
            permissions = TlvTypes.Permission_RegularUser
        elif permissions == 'Admin':
            permissions = TlvTypes.Permission_AdminUser
        else:
            print('UNKNOWN')

        request_tlv = tlv8.encode([
            tlv8.Entry(TlvTypes.State, States.M1),
            tlv8.Entry(TlvTypes.Method, Methods.AddPairing),
            tlv8.Entry(TlvTypes.Identifier,
                       additional_controller_pairing_identifier.encode()),
            tlv8.Entry(TlvTypes.PublicKey, bytes.fromhex(ios_device_ltpk)),
            tlv8.Entry(TlvTypes.Permissions, permissions)
        ])

        response = self.session.sec_http.post('/pairings', request_tlv)
        data = response.read()
        data = tlv8.decode(
            data, {
                TlvTypes.State: tlv8.DataType.INTEGER,
                TlvTypes.Error: tlv8.DataType.BYTES,
            })
        # TODO handle the response properly
        self.session.close()
 def test_entrylist_encode_same_sep_type(self):
     el = tlv8.EntryList([
         tlv8.Entry(2, b'\x23'),
         tlv8.Entry(2, b'\x42')
     ])
     result = el.encode(1)
     self.assertEqual(b'\x02\x01\x23\x01\x00\x02\x01\x42', result)
 def test_entrylist_index(self):
     el = tlv8.EntryList()
     e1 = tlv8.Entry(1, 2)
     e2 = tlv8.Entry(3, 4)
     el.append(e1)
     el.append(e2)
     self.assertEqual(e2, el[1])
 def test_entrylist_length(self):
     el = tlv8.EntryList()
     self.assertEqual(0, len(el))
     el.append(tlv8.Entry(1, 2))
     self.assertEqual(1, len(el))
     el.append(tlv8.Entry(1, 2))
     self.assertEqual(2, len(el))
 def test_entrylist_by_id(self):
     el = tlv8.EntryList([
         tlv8.Entry(2, b'\x23'),
         tlv8.Entry(2, b'\x42')
     ])
     self.assertEqual(el.by_id(1), tlv8.EntryList())
     self.assertEqual(el.by_id(2), el)
Example #10
0
 def test_encode_different(self):
     data = [
         tlv8.Entry(23, b'23', tlv8.DataType.BYTES),
         tlv8.Entry(22, '23', tlv8.DataType.STRING)
     ]
     result = tlv8.encode(data)
     expected_data = data[0].encode() + data[1].encode()
     self.assertEqual(result, expected_data)
Example #11
0
 def test_encode_same_set_sep_type(self):
     data = [
         tlv8.Entry(23, b'23', tlv8.DataType.BYTES),
         tlv8.Entry(23, '23', tlv8.DataType.STRING)
     ]
     result = tlv8.encode(data, 0)
     expected_data = data[0].encode() + b'\x00\x00' + data[1].encode()
     self.assertEqual(result, expected_data)
Example #12
0
 def test_encode_supported_rtp_configs(self):
     data = [tlv8.Entry(2, 0), tlv8.Entry(2, 1)]
     result = tlv8.encode(data, separator_type_id=0x00)
     expected_data = \
         b'\x02\x01\x00' + \
         b'\x00\x00' + \
         b'\x02\x01\x01'
     self.assertEqual(result, expected_data)
Example #13
0
 def test_decode_misinterpretation(self):
     """This show how data may be misinterpreted by deep_decode"""
     data = tlv8.encode([tlv8.Entry(1, 16843330), tlv8.Entry(2, b'\x01')])
     result = tlv8.deep_decode(data)
     expected_data = tlv8.EntryList([
         tlv8.Entry(1, tlv8.EntryList([tlv8.Entry(66, b'\x01\x01')])),
         tlv8.Entry(2, b'\x01')
     ])
     self.assertEqual(result, expected_data)
Example #14
0
 def test_autodetection_of_types(self):
     data = [
         tlv8.Entry(1, 3.141),
         tlv8.Entry(2, [tlv8.Entry(3, 'hello'),
                        tlv8.Entry(4, 'world')]),
         tlv8.Entry(1, 2)
     ]
     result = tlv8.encode(data)
     expected_data = b'\x01\x04%\x06I@\x02\x0e\x03\x05hello\x04\x05world\x01\x01\x02'
     self.assertEqual(result, expected_data)
Example #15
0
 def test_format_string(self):
     data = [
         tlv8.Entry(1, 3.141),
         tlv8.Entry(2, [
             tlv8.Entry(3, 'hello'),
             tlv8.Entry(4, 'world'),
         ]),
         tlv8.Entry(1, 2)
     ]
     print(tlv8.format_string(data))
Example #16
0
 def test_decode_4(self):
     input_data = b'\x01\x01\x23\x02\x03\x04\x01\x42\x01\x01\x23'
     result = tlv8.deep_decode(input_data)
     expected = tlv8.EntryList([
         tlv8.Entry(1, b'#'),
         tlv8.Entry(2, tlv8.EntryList([
             tlv8.Entry(4, b'B'),
         ])),
         tlv8.Entry(1, b'#'),
     ])
     self.assertEqual(expected, result)
Example #17
0
    def write(request, expected):
        # TODO document me
        body = tlv8.encode(request)
        logger.debug('entering write function %s',
                     tlv8.format_string(tlv8.decode(body)))
        request_tlv = tlv8.encode([
            tlv8.Entry(AdditionalParameterTypes.ParamReturnResponse,
                       bytearray(b'\x01')),
            tlv8.Entry(AdditionalParameterTypes.Value, body)
        ])
        transaction_id = random.randrange(0, 255)
        # construct a hap characteristic write request following chapter 7.3.4.4 page 94 spec R2
        data = bytearray([0x00, HapBleOpCodes.CHAR_WRITE, transaction_id])
        data.extend(characteristic_id.to_bytes(length=2, byteorder='little'))
        data.extend(len(request_tlv).to_bytes(length=2, byteorder='little'))
        data.extend(request_tlv)
        logger.debug('sent %s', bytes(data).hex())

        # write the request to the characteristic
        characteristic.write_value(value=data)

        # reading hap characteristic write response following chapter 7.3.4.5 page 95 spec R2
        data = []
        while len(data) == 0:
            time.sleep(1)
            logger.debug('reading characteristic')
            data = characteristic.read_value()
        resp_data = [b for b in data]

        expected_length = int.from_bytes(bytes(resp_data[3:5]),
                                         byteorder='little')
        logger.debug(
            'control field: {c:x}, tid: {t:x}, status: {s:x}, length: {length}'
            .format(c=resp_data[0],
                    t=resp_data[1],
                    s=resp_data[2],
                    length=expected_length))
        while len(resp_data[3:]) < expected_length:
            time.sleep(1)
            logger.debug('reading characteristic')
            data = characteristic.read_value()
            resp_data.extend([b for b in data])
            logger.debug('data %s of %s', len(resp_data[3:]), expected_length)

        logger.debug('received %s', bytes(resp_data).hex())
        logger.debug('decode %s', bytes(resp_data[5:]).hex())
        resp_tlv = tlv8.decode(
            bytes([int(a) for a in resp_data[5:]]),
            expected={AdditionalParameterTypes.Value: tlv8.DataType.BYTES})
        result = tlv8.decode(
            resp_tlv.first_by_id(AdditionalParameterTypes.Value).data,
            expected)
        logger.debug('leaving write function %s', tlv8.format_string(result))
        return result
Example #18
0
def perform_pair_setup_part1():
    """
    Performs a pair setup operation as described in chapter 4.7 page 39 ff.

    :return: a tuple of salt and server's public key
    :raises UnavailableError: if the device is already paired
    :raises MaxTriesError: if the device received more than 100 unsuccessful pairing attempts
    :raises BusyError: if a parallel pairing is ongoing
    :raises AuthenticationError: if the verification of the device's SRP proof fails
    :raises MaxPeersError: if the device cannot accept an additional pairing
    :raises IllegalData: if the verification of the accessory's data fails
    """

    #
    # Step #1 ios --> accessory (send SRP start Request) (see page 39)
    #
    logging.debug('#1 ios -> accessory: send SRP start request')
    request_tlv = [
        tlv8.Entry(TlvTypes.State, States.M1),
        tlv8.Entry(TlvTypes.Method, Methods.PairSetup)
    ]

    step2_expectations = {
        TlvTypes.State: tlv8.DataType.INTEGER,
        TlvTypes.Error: tlv8.DataType.INTEGER,
        TlvTypes.PublicKey: tlv8.DataType.BYTES,
        TlvTypes.Salt: tlv8.DataType.BYTES
    }
    response_tlv = yield (request_tlv, step2_expectations)

    #
    # Step #3 ios --> accessory (send SRP verify request) (see page 41)
    #
    logging.debug('#3 ios -> accessory: send SRP verify request')
    assert response_tlv.first_by_id(
        TlvTypes.State) and response_tlv.first_by_id(
            TlvTypes.State
        ).data == States.M2, 'perform_pair_setup: State not M2'

    # the errors here can be:
    #  * kTLVError_Unavailable: Device is paired
    #  * kTLVError_MaxTries: More than 100 unsuccessful attempts
    #  * kTLVError_Busy: There is already a pairing going on
    error = response_tlv.first_by_id(TlvTypes.Error)
    if error:
        error_handler(error.data, 'step 3')

    assert response_tlv.first_by_id(
        TlvTypes.PublicKey), 'perform_pair_setup: Not a public key'
    assert response_tlv.first_by_id(
        TlvTypes.Salt), 'perform_pair_setup: Not a salt'

    return response_tlv.first_by_id(TlvTypes.Salt).data, \
        response_tlv.first_by_id(TlvTypes.PublicKey).data
Example #19
0
 def test_decode_supported_rtp_configs(self):
     data = \
         b'\x02\x01\x00' + \
         b'\x00\x00' + \
         b'\x02\x01\x01'
     result = tlv8.decode(data, expected={2: tlv8.DataType.INTEGER})
     expected_data = tlv8.EntryList([
         tlv8.Entry(2, 0),
         tlv8.Entry(2, 1)
     ])
     self.assertEqual(result, expected_data)
Example #20
0
 def test_encode_3same(self):
     data = [
         tlv8.Entry(23, b'23', tlv8.DataType.BYTES),
         tlv8.Entry(23, '23', tlv8.DataType.STRING),
         tlv8.Entry(23, '23', tlv8.DataType.STRING)
     ]
     result = tlv8.encode(data)
     expected_data = \
         data[0].encode() + b'\xff\x00' + \
         data[1].encode() + b'\xff\x00' + \
         data[2].encode()
     self.assertEqual(result, expected_data)
Example #21
0
 def test_decode_supported_rtp_configs(self):
     data = \
         b'\x02\x01\x00' + \
         b'\x00\x00' + \
         b'\x02\x01\x01'
     result = tlv8.deep_decode(data, )
     expected_data = tlv8.EntryList([
         tlv8.Entry(2, b'\x00'),
         tlv8.Entry(0, tlv8.EntryList()),
         tlv8.Entry(2, b'\x01')
     ])
     self.assertEqual(result, expected_data)
Example #22
0
 def test_decode_example_3(self):
     input_data = b'\x01\x15\x01\x10e\xad\x8b\xe8\xb3fD\xcb\xbde#\xccc\n\xb8\xef\x02\x01\x01'
     result = tlv8.deep_decode(input_data)
     expected = tlv8.EntryList([
         tlv8.Entry(
             1,
             tlv8.EntryList([
                 tlv8.Entry(
                     1, b'e\xad\x8b\xe8\xb3fD\xcb\xbde#\xccc\n\xb8\xef'),
                 tlv8.Entry(2, b'\x01'),
             ])),
     ])
     self.assertEqual(expected, result)
Example #23
0
 def test_decode_example_2(self):
     input_data = b'\x01\x01\x00'
     result = tlv8.deep_decode(input_data)
     expected = tlv8.EntryList([
         tlv8.Entry(1, b'\x00'),
     ])
     self.assertEqual(expected, result)
Example #24
0
 def test_decode_2_entries_1_expected(self):
     input_data = b'\x02\x01\x23\x03\x01\x42'
     structure = {
         2: tlv8.DataType.INTEGER
     }
     result = tlv8.decode(input_data, structure)
     self.assertEqual(tlv8.EntryList([tlv8.Entry(2, 0x23)]), result)
Example #25
0
 def test_decode_error_4(self):
     data = b'\x01\x02Hi'
     result = tlv8.decode(data, {1: tlv8.DataType.STRING})
     expected_data = tlv8.EntryList([
         tlv8.Entry(1, 'Hi')
     ])
     self.assertEqual(result, expected_data)
Example #26
0
 def test_decode_float(self):
     input_data = b'\x01\x04' + pack('<f', 3.141)
     result = tlv8.deep_decode(input_data)
     expected = tlv8.EntryList([
         tlv8.Entry(1, b'%\x06I@'),
     ])
     self.assertEqual(expected, result)
Example #27
0
 def test_decode_int1(self):
     input_data = b'\x01\x01' + pack('<b', -123)
     result = tlv8.deep_decode(input_data)
     expected = tlv8.EntryList([
         tlv8.Entry(1, b'\x85'),
     ])
     self.assertEqual(expected, result)
Example #28
0
 def test_decode_int2(self):
     input_data = b'\x01\x02' + pack('<h', 12345)
     result = tlv8.deep_decode(input_data)
     expected = tlv8.EntryList([
         tlv8.Entry(1, b'90'),
     ])
     self.assertEqual(expected, result)
Example #29
0
 def test_bytes_257bytes(self):
     data = b''
     for i in range(0, 257):
         data += pack('<B', i % 256)
     entry = tlv8.Entry(23, data, tlv8.DataType.BYTES)
     expected_data = b'\x17\xff' + data[0:255] + b'\x17\x02' + data[255:]
     self.assertEqual(entry.encode(), expected_data)
Example #30
0
 def test_decode_int4(self):
     input_data = b'\x01\x08' + pack('<q', 4611686018427387904)
     result = tlv8.deep_decode(input_data)
     expected = tlv8.EntryList([
         tlv8.Entry(1, b'\x00\x00\x00\x00\x00\x00\x00@'),
     ])
     self.assertEqual(expected, result)