1""" 2Unit tests for the stem.client.cell. 3""" 4 5import datetime 6import hashlib 7import os 8import unittest 9 10from stem.client.datatype import ZERO, CertType, CloseReason, Address, Certificate 11from test.unit.client import test_data 12 13from stem.client.cell import ( 14 FIXED_PAYLOAD_LEN, 15 Cell, 16 PaddingCell, 17 RelayCell, 18 DestroyCell, 19 CreateFastCell, 20 CreatedFastCell, 21 VersionsCell, 22 NetinfoCell, 23 VPaddingCell, 24 CertsCell, 25 AuthChallengeCell, 26) 27 28RANDOM_PAYLOAD = os.urandom(FIXED_PAYLOAD_LEN) 29CHALLENGE = b'\x89Y\t\x99\xb2\x1e\xd9*V\xb6\x1bn\n\x05\xd8/\xe3QH\x85\x13Z\x17\xfc\x1c\x00{\xa9\xae\x83^K' 30 31PADDING_CELLS = { 32 b'\x00\x00\x00' + RANDOM_PAYLOAD: (RANDOM_PAYLOAD, 2), 33} 34 35RELAY_CELLS = { 36 b'\x00\x01\x03\r\x00\x00\x00\x01!\xa3?\xec\x00\x00' + ZERO * 498: ('RELAY_BEGIN_DIR', 13, 1, 1, b'', 564346860, ZERO * 498, 2), 37 b'\x00\x01\x03\x02\x00\x00\x00\x01\x15:m\xe0\x00&GET /tor/server/authority HTTP/1.0\r\n\r\n' + ZERO * 460: ('RELAY_DATA', 2, 1, 1, b'GET /tor/server/authority HTTP/1.0\r\n\r\n', 356150752, ZERO * 460, 2), 38 b'\x00\x01\x03\x02\x00\x00\x00\x01\x15:m\xe0\x00&GET /tor/server/authority HTTP/1.0\r\n\r\n' + b'\x01' + ZERO * 459: ('RELAY_DATA', 2, 1, 1, b'GET /tor/server/authority HTTP/1.0\r\n\r\n', 356150752, b'\x01' + ZERO * 459, 2), 39} 40 41DESTROY_CELLS = { 42 b'\x80\x00\x00\x00\x04\x00' + ZERO * 508: (2147483648, CloseReason.NONE, 0, ZERO * 508, 5), 43 b'\x80\x00\x00\x00\x04\x03' + ZERO * 508: (2147483648, CloseReason.REQUESTED, 3, ZERO * 508, 5), 44 b'\x80\x00\x00\x00\x04\x01' + b'\x01' + ZERO * 507: (2147483648, CloseReason.PROTOCOL, 1, b'\x01' + ZERO * 507, 5), 45} 46 47CREATE_FAST_CELLS = { 48 (b'\x80\x00\x00\x00\x05\x92O\x0c\xcb\xa8\xac\xfb\xc9\x7f\xd0\rz\x1a\x03u\x91\xceas\xce' + ZERO * 489): (2147483648, b'\x92O\x0c\xcb\xa8\xac\xfb\xc9\x7f\xd0\rz\x1a\x03u\x91\xceas\xce', ZERO * 489, 5), 49 (b'\x80\x00\x00\x00\x05\x92O\x0c\xcb\xa8\xac\xfb\xc9\x7f\xd0\rz\x1a\x03u\x91\xceas\x00' + ZERO * 489): (2147483648, b'\x92O\x0c\xcb\xa8\xac\xfb\xc9\x7f\xd0\rz\x1a\x03u\x91\xceas\x00', ZERO * 489, 5), 50 (b'\x80\x00\x00\x00\x05\x92O\x0c\xcb\xa8\xac\xfb\xc9\x7f\xd0\rz\x1a\x03u\x91\xceas\x00' + b'\x01' + ZERO * 488): (2147483648, b'\x92O\x0c\xcb\xa8\xac\xfb\xc9\x7f\xd0\rz\x1a\x03u\x91\xceas\x00', b'\x01' + ZERO * 488, 5), 51} 52 53CREATED_FAST_CELLS = { 54 (b'\x80\x00\x00\x00\x06\x92O\x0c\xcb\xa8\xac\xfb\xc9\x7f\xd0\rz\x1a\x03u\x91\xceas\xce\x13Z\x99\xb2\x1e\xb6\x05\x85\x17\xfc\x1c\x00{\xa9\xae\x83^K\x99\xb2' + ZERO * 469): (2147483648, b'\x92O\x0c\xcb\xa8\xac\xfb\xc9\x7f\xd0\rz\x1a\x03u\x91\xceas\xce', b'\x13Z\x99\xb2\x1e\xb6\x05\x85\x17\xfc\x1c\x00{\xa9\xae\x83^K\x99\xb2', ZERO * 469, 5), 55 (b'\x80\x00\x00\x00\x06\x92O\x0c\xcb\xa8\xac\xfb\xc9\x7f\xd0\rz\x1a\x03u\x91\xceas\xce\x13Z\x99\xb2\x1e\xb6\x05\x85\x17\xfc\x1c\x00{\xa9\xae\x83^K\x99\x00' + ZERO * 469): (2147483648, b'\x92O\x0c\xcb\xa8\xac\xfb\xc9\x7f\xd0\rz\x1a\x03u\x91\xceas\xce', b'\x13Z\x99\xb2\x1e\xb6\x05\x85\x17\xfc\x1c\x00{\xa9\xae\x83^K\x99\x00', ZERO * 469, 5), 56 (b'\x80\x00\x00\x00\x06\x92O\x0c\xcb\xa8\xac\xfb\xc9\x7f\xd0\rz\x1a\x03u\x91\xceas\xce\x13Z\x99\xb2\x1e\xb6\x05\x85\x17\xfc\x1c\x00{\xa9\xae\x83^K\x99\x00' + b'\x01' + ZERO * 468): (2147483648, b'\x92O\x0c\xcb\xa8\xac\xfb\xc9\x7f\xd0\rz\x1a\x03u\x91\xceas\xce', b'\x13Z\x99\xb2\x1e\xb6\x05\x85\x17\xfc\x1c\x00{\xa9\xae\x83^K\x99\x00', b'\x01' + ZERO * 468, 5), 57} 58 59VERSIONS_CELLS = { 60 b'\x00\x00\x07\x00\x00': ([], 2), 61 b'\x00\x00\x07\x00\x02\x00\x01': ([1], 2), 62 b'\x00\x00\x07\x00\x06\x00\x01\x00\x02\x00\x03': ([1, 2, 3], 2), 63 b'\x00\x00\x00\x00\x07\x00\x08\x00\x01\x00\x02\x00\x03\x00\x04': ([1, 2, 3, 4], 4), 64} 65 66NETINFO_CELLS = { 67 b'\x00\x00\x08ZZ\xb6\x90\x04\x04\x7f\x00\x00\x01\x01\x04\x04aq\x0f\x02' + ZERO * (FIXED_PAYLOAD_LEN - 17): (datetime.datetime(2018, 1, 14, 1, 46, 56), Address('127.0.0.1'), [Address('97.113.15.2')], ZERO * 492, 2), 68 b'\x00\x00\x08ZZ\xb6\x90\x04\x04\x7f\x00\x00\x01\x01\x04\x04aq\x0f\x02' + b'\x01' + ZERO * (FIXED_PAYLOAD_LEN - 18): (datetime.datetime(2018, 1, 14, 1, 46, 56), Address('127.0.0.1'), [Address('97.113.15.2')], b'\x01' + ZERO * 491, 2), 69} 70 71VPADDING_CELL_EMPTY_PACKED = b'\x00\x00\x80\x00\x00' 72 73VPADDING_CELLS = { 74 VPADDING_CELL_EMPTY_PACKED: (b'', 2), 75 b'\x00\x00\x80\x00\x01\x08': (b'\x08', 2), 76 b'\x00\x00\x80\x00\x02\x08\x11': (b'\x08\x11', 2), 77 b'\x00\x00\x80\x01\xfd' + RANDOM_PAYLOAD: (RANDOM_PAYLOAD, 2), 78} 79 80CERTS_CELLS = { 81 b'\x00\x00\x81\x00\x01\x00': ([], b'', 2), 82 b'\x00\x00\x81\x00\x04\x01\x01\x00\x00': ([Certificate(1, b'')], b'', 2), 83 b'\x00\x00\x81\x00\x05\x01\x01\x00\x01\x08': ([Certificate(1, b'\x08')], b'', 2), 84 b'\x00\x00\x81\x00\x07\x01\x01\x00\x01\x08' + b'\x06\x04': ([Certificate(1, b'\x08')], b'\x06\x04', 2), 85} 86 87AUTH_CHALLENGE_CELLS = { 88 b'\x00\x00\x82\x00\x26' + CHALLENGE + b'\x00\x02\x00\x01\x00\x03': (CHALLENGE, [1, 3], b'', 2), 89 b'\x00\x00\x82\x00\x28' + CHALLENGE + b'\x00\x02\x00\x01\x00\x03' + b'\x01\x02': (CHALLENGE, [1, 3], b'\x01\x02', 2), 90} 91 92 93class TestCell(unittest.TestCase): 94 def test_by_name(self): 95 cls = Cell.by_name('NETINFO') 96 self.assertEqual('NETINFO', cls.NAME) 97 self.assertEqual(8, cls.VALUE) 98 self.assertEqual(True, cls.IS_FIXED_SIZE) 99 100 self.assertRaises(ValueError, Cell.by_name, 'NOPE') 101 self.assertRaises(ValueError, Cell.by_name, 85) 102 self.assertRaises(ValueError, Cell.by_name, None) 103 104 def test_by_value(self): 105 cls = Cell.by_value(8) 106 self.assertEqual('NETINFO', cls.NAME) 107 self.assertEqual(8, cls.VALUE) 108 self.assertEqual(True, cls.IS_FIXED_SIZE) 109 110 self.assertRaises(ValueError, Cell.by_value, 'NOPE') 111 self.assertRaises(ValueError, Cell.by_value, 85) 112 self.assertRaises(ValueError, Cell.by_value, None) 113 114 def test_unimplemented_cell_methods(self): 115 cell_instance = Cell() 116 117 self.assertRaisesWith(NotImplementedError, 'Packing not yet implemented for UNKNOWN cells', cell_instance.pack, 2) 118 self.assertRaisesWith(NotImplementedError, 'Unpacking not yet implemented for UNKNOWN cells', cell_instance._unpack, b'dummy', 0, 2) 119 120 def test_payload_too_large(self): 121 class OversizedCell(Cell): 122 NAME = 'OVERSIZED' 123 VALUE = 127 # currently nonsense, but potentially will be allocated in the distant future 124 IS_FIXED_SIZE = True 125 126 def pack(self, link_protocol): 127 return OversizedCell._pack(link_protocol, ZERO * (FIXED_PAYLOAD_LEN + 1)) 128 129 instance = OversizedCell() 130 131 expected_message = 'Cell of type OVERSIZED is too large (%i bytes), must not be more than %i. Check payload size (was %i bytes)' % (FIXED_PAYLOAD_LEN + 4, FIXED_PAYLOAD_LEN + 3, FIXED_PAYLOAD_LEN + 1) 132 self.assertRaisesWith(ValueError, expected_message, instance.pack, 2) 133 134 def test_circuit_id_validation(self): 135 # only CircuitCell subclasses should provide a circ_id 136 137 self.assertRaisesWith(ValueError, 'PADDING cells should not specify a circuit identifier', PaddingCell._pack, 5, b'', circ_id = 12) 138 139 # CircuitCell should validate its circ_id 140 141 self.assertRaisesWith(ValueError, 'RELAY cells require a circuit identifier', RelayCell._pack, 5, b'', circ_id = None) 142 143 for circ_id in (0, -1, -50): 144 expected_msg = 'Circuit identifiers must a positive integer, not %s' % circ_id 145 self.assertRaisesWith(ValueError, expected_msg, RelayCell._pack, 5, b'', circ_id = circ_id) 146 147 def test_unpack_for_new_link(self): 148 expected_certs = ( 149 (CertType.LINK, 1, b'0\x82\x02F0\x82\x01\xaf'), 150 (CertType.IDENTITY, 2, b'0\x82\x01\xc90\x82\x012'), 151 (CertType.ED25519_SIGNING, 4, b'\x01\x04\x00\x06m\x1f'), 152 (CertType.LINK_CERT, 5, b'\x01\x05\x00\x06m\n\x01'), 153 (CertType.ED25519_IDENTITY, 7, b'\x1a\xa5\xb3\xbd\x88\xb1C'), 154 ) 155 156 content = test_data('new_link_cells') 157 158 version_cell, content = Cell.pop(content, 2) 159 self.assertEqual(VersionsCell([3, 4, 5]), version_cell) 160 161 certs_cell, content = Cell.pop(content, 2) 162 self.assertEqual(CertsCell, type(certs_cell)) 163 self.assertEqual(len(expected_certs), len(certs_cell.certificates)) 164 165 for i, (cert_type, cert_type_int, cert_prefix) in enumerate(expected_certs): 166 self.assertEqual(cert_type, certs_cell.certificates[i].type) 167 self.assertEqual(cert_type_int, certs_cell.certificates[i].type_int) 168 self.assertTrue(certs_cell.certificates[i].value.startswith(cert_prefix)) 169 170 auth_challenge_cell, content = Cell.pop(content, 2) 171 self.assertEqual(AuthChallengeCell([1, 3], b'\x89Y\t\x99\xb2\x1e\xd9*V\xb6\x1bn\n\x05\xd8/\xe3QH\x85\x13Z\x17\xfc\x1c\x00{\xa9\xae\x83^K'), auth_challenge_cell) 172 173 netinfo_cell, content = Cell.pop(content, 2) 174 self.assertEqual(NetinfoCell, type(netinfo_cell)) 175 self.assertEqual(datetime.datetime(2018, 1, 14, 1, 46, 56), netinfo_cell.timestamp) 176 self.assertEqual(Address('127.0.0.1'), netinfo_cell.receiver_address) 177 self.assertEqual([Address('97.113.15.2')], netinfo_cell.sender_addresses) 178 self.assertEqual(ZERO * 492, netinfo_cell.unused) 179 180 self.assertEqual(b'', content) # check that we've consumed all of the bytes 181 182 def test_padding_cell(self): 183 for cell_bytes, (payload, link_protocol) in PADDING_CELLS.items(): 184 self.assertEqual(cell_bytes, PaddingCell(payload).pack(link_protocol)) 185 186 cell = Cell.pop(cell_bytes, link_protocol)[0] 187 self.assertEqual(payload, cell.payload) 188 self.assertEqual(b'', cell.unused) # always empty 189 self.assertEqual(cell_bytes, cell.pack(link_protocol)) 190 191 def test_relay_cell(self): 192 for cell_bytes, (command, command_int, circ_id, stream_id, data, digest, unused, link_protocol) in RELAY_CELLS.items(): 193 if not unused.strip(ZERO): 194 self.assertEqual(cell_bytes, RelayCell(circ_id, command, data, digest, stream_id).pack(link_protocol)) 195 self.assertEqual(cell_bytes, RelayCell(circ_id, command_int, data, digest, stream_id).pack(link_protocol)) 196 else: 197 self.assertEqual(cell_bytes, RelayCell(circ_id, command, data, digest, stream_id, unused = unused).pack(link_protocol)) 198 self.assertEqual(cell_bytes, RelayCell(circ_id, command_int, data, digest, stream_id, unused = unused).pack(link_protocol)) 199 200 cell = Cell.pop(cell_bytes, link_protocol)[0] 201 self.assertEqual(circ_id, cell.circ_id) 202 self.assertEqual(command, cell.command) 203 self.assertEqual(command_int, cell.command_int) 204 self.assertEqual(data, cell.data) 205 self.assertEqual(digest, cell.digest) 206 self.assertEqual(stream_id, cell.stream_id) 207 self.assertEqual(unused, cell.unused) 208 209 self.assertEqual(cell_bytes, cell.pack(link_protocol)) 210 211 digest = hashlib.sha1(b'hi') 212 self.assertEqual(3257622417, RelayCell(5, 'RELAY_BEGIN_DIR', '', digest, 564346860).digest) 213 self.assertEqual(3257622417, RelayCell(5, 'RELAY_BEGIN_DIR', '', digest.digest(), 564346860).digest) 214 self.assertEqual(3257622417, RelayCell(5, 'RELAY_BEGIN_DIR', '', 3257622417, 564346860).digest) 215 self.assertRaisesWith(ValueError, 'RELAY cell digest must be a hash, string, or int but was a list', RelayCell, 5, 'RELAY_BEGIN_DIR', '', [], 564346860) 216 self.assertRaisesRegexp(ValueError, "Invalid enumeration 'NO_SUCH_COMMAND', options are RELAY_BEGIN, RELAY_DATA", RelayCell, 5, 'NO_SUCH_COMMAND', '', 5, 564346860) 217 218 mismatched_data_length_bytes = b''.join(( 219 b'\x00\x01', # circ ID 220 b'\x03', # command 221 b'\x02', # relay command 222 b'\x00\x00', # 'recognized' 223 b'\x00\x01', # stream ID 224 b'\x15:m\xe0', # digest 225 b'\xFF\xFF', # data len (65535, clearly invalid) 226 ZERO * 498, # data 227 )) 228 229 self.assertRaisesWith(ValueError, 'RELAY cell said it had 65535 bytes of data, but only had 498', Cell.pop, mismatched_data_length_bytes, 2) 230 231 def test_destroy_cell(self): 232 for cell_bytes, (circ_id, reason, reason_int, unused, link_protocol) in DESTROY_CELLS.items(): 233 if not unused.strip(ZERO): 234 self.assertEqual(cell_bytes, DestroyCell(circ_id, reason).pack(link_protocol)) 235 self.assertEqual(cell_bytes, DestroyCell(circ_id, reason_int).pack(link_protocol)) 236 else: 237 self.assertEqual(cell_bytes, DestroyCell(circ_id, reason, unused = unused).pack(link_protocol)) 238 self.assertEqual(cell_bytes, DestroyCell(circ_id, reason_int, unused = unused).pack(link_protocol)) 239 240 cell = Cell.pop(cell_bytes, link_protocol)[0] 241 self.assertEqual(circ_id, cell.circ_id) 242 self.assertEqual(reason, cell.reason) 243 self.assertEqual(reason_int, cell.reason_int) 244 self.assertEqual(unused, cell.unused) 245 self.assertEqual(cell_bytes, cell.pack(link_protocol)) 246 247 def test_create_fast_cell(self): 248 for cell_bytes, (circ_id, key_material, unused, link_protocol) in CREATE_FAST_CELLS.items(): 249 if not unused.strip(ZERO): 250 self.assertEqual(cell_bytes, CreateFastCell(circ_id, key_material).pack(link_protocol)) 251 else: 252 self.assertEqual(cell_bytes, CreateFastCell(circ_id, key_material, unused = unused).pack(link_protocol)) 253 254 cell = Cell.pop(cell_bytes, link_protocol)[0] 255 self.assertEqual(circ_id, cell.circ_id) 256 self.assertEqual(key_material, cell.key_material) 257 self.assertEqual(unused, cell.unused) 258 self.assertEqual(cell_bytes, cell.pack(link_protocol)) 259 260 self.assertRaisesWith(ValueError, 'Key material should be 20 bytes, but was 3', CreateFastCell, 5, 'boo') 261 262 def test_created_fast_cell(self): 263 for cell_bytes, (circ_id, key_material, derivative_key, unused, link_protocol) in CREATED_FAST_CELLS.items(): 264 if not unused.strip(ZERO): 265 self.assertEqual(cell_bytes, CreatedFastCell(circ_id, derivative_key, key_material).pack(link_protocol)) 266 else: 267 self.assertEqual(cell_bytes, CreatedFastCell(circ_id, derivative_key, key_material, unused = unused).pack(link_protocol)) 268 269 cell = Cell.pop(cell_bytes, link_protocol)[0] 270 self.assertEqual(circ_id, cell.circ_id) 271 self.assertEqual(key_material, cell.key_material) 272 self.assertEqual(derivative_key, cell.derivative_key) 273 self.assertEqual(unused, cell.unused) 274 self.assertEqual(cell_bytes, cell.pack(link_protocol)) 275 276 self.assertRaisesWith(ValueError, 'Key material should be 20 bytes, but was 3', CreateFastCell, 5, 'boo') 277 278 def test_versions_cell(self): 279 for cell_bytes, (versions, link_protocol) in VERSIONS_CELLS.items(): 280 self.assertEqual(cell_bytes, VersionsCell(versions).pack(link_protocol)) 281 282 cell = Cell.pop(cell_bytes, link_protocol)[0] 283 self.assertEqual(versions, cell.versions) 284 self.assertEqual(b'', cell.unused) # always empty 285 self.assertEqual(cell_bytes, cell.pack(link_protocol)) 286 287 def test_netinfo_cell(self): 288 for cell_bytes, (timestamp, receiver_address, sender_addresses, unused, link_protocol) in NETINFO_CELLS.items(): 289 if not unused.strip(ZERO): 290 self.assertEqual(cell_bytes, NetinfoCell(receiver_address, sender_addresses, timestamp).pack(link_protocol)) 291 else: 292 self.assertEqual(cell_bytes, NetinfoCell(receiver_address, sender_addresses, timestamp, unused = unused).pack(link_protocol)) 293 294 cell = Cell.pop(cell_bytes, link_protocol)[0] 295 self.assertEqual(timestamp, cell.timestamp) 296 self.assertEqual(receiver_address, cell.receiver_address) 297 self.assertEqual(sender_addresses, cell.sender_addresses) 298 self.assertEqual(unused, cell.unused) 299 self.assertEqual(cell_bytes, cell.pack(link_protocol)) 300 301 def test_vpadding_cell(self): 302 for cell_bytes, (payload, link_protocol) in VPADDING_CELLS.items(): 303 self.assertEqual(cell_bytes, VPaddingCell(payload = payload).pack(link_protocol)) 304 305 cell = Cell.pop(cell_bytes, link_protocol)[0] 306 self.assertEqual(payload, cell.payload) 307 self.assertEqual(b'', cell.unused) # always empty 308 self.assertEqual(cell_bytes, cell.pack(link_protocol)) 309 310 empty_constructed_cell = VPaddingCell(size = 0) 311 self.assertEqual(VPADDING_CELL_EMPTY_PACKED, empty_constructed_cell.pack(2)) 312 self.assertEqual(b'', empty_constructed_cell.payload) 313 314 self.assertRaisesWith(ValueError, 'VPaddingCell constructor specified both a size of 5 bytes and payload of 1 bytes', VPaddingCell, 5, '\x02') 315 self.assertRaisesWith(ValueError, 'VPaddingCell size (-15) cannot be negative', VPaddingCell, -15) 316 self.assertRaisesWith(ValueError, 'VPaddingCell constructor must specify payload or size', VPaddingCell) 317 318 def test_certs_cell(self): 319 for cell_bytes, (certs, unused, link_protocol) in CERTS_CELLS.items(): 320 if not unused.strip(ZERO): 321 self.assertEqual(cell_bytes, CertsCell(certs).pack(link_protocol)) 322 else: 323 self.assertEqual(cell_bytes, CertsCell(certs, unused = unused).pack(link_protocol)) 324 325 cell = Cell.pop(cell_bytes, link_protocol)[0] 326 self.assertEqual(certs, cell.certificates) 327 self.assertEqual(unused, cell.unused) 328 self.assertEqual(cell_bytes, cell.pack(link_protocol)) 329 330 # truncated or missing certificates should error 331 332 self.assertRaisesWith(ValueError, 'CERTS cell should have a certificate with 3 bytes, but only had 1 remaining', Cell.pop, b'\x00\x00\x81\x00\x05\x01\x01\x00\x03\x08', 2) 333 self.assertRaisesWith(ValueError, 'CERTS cell indicates it should have 2 certificates, but only contained 1', Cell.pop, b'\x00\x00\x81\x00\x05\x02\x01\x00\x01\x08', 2) 334 335 def test_auth_challenge_cell(self): 336 for cell_bytes, (challenge, methods, unused, link_protocol) in AUTH_CHALLENGE_CELLS.items(): 337 if not unused.strip(ZERO): 338 self.assertEqual(cell_bytes, AuthChallengeCell(methods, challenge).pack(link_protocol)) 339 else: 340 self.assertEqual(cell_bytes, AuthChallengeCell(methods, challenge, unused = unused).pack(link_protocol)) 341 342 cell = Cell.pop(cell_bytes, link_protocol)[0] 343 self.assertEqual(challenge, cell.challenge) 344 self.assertEqual(methods, cell.methods) 345 self.assertEqual(unused, cell.unused) 346 self.assertEqual(cell_bytes, cell.pack(link_protocol)) 347 348 self.assertRaisesWith(ValueError, 'AUTH_CHALLENGE cell should have a payload of 38 bytes, but only had 16', Cell.pop, b'\x00\x00\x82\x00&' + CHALLENGE[:10] + b'\x00\x02\x00\x01\x00\x03', 2) 349 self.assertRaisesWith(ValueError, 'AUTH_CHALLENGE should have 3 methods, but only had 4 bytes for it', Cell.pop, b'\x00\x00\x82\x00&' + CHALLENGE + b'\x00\x03\x00\x01\x00\x03', 2) 350