1
2
3
4 """Classes for reading/writing binary data (such as TLS records)."""
5
6 from __future__ import division
7
8 import sys
9 import struct
10 from struct import pack
11
12
14 """Serialisation helper for complex byte-based structures."""
15
17 """Initialise the serializer with no data."""
18 self.bytes = bytearray(0)
19
21 """Add a single-byte wide element to buffer, see add()."""
22 self.bytes.append(val)
23
24 if sys.version_info < (2, 7):
25
26
28 """Add a double-byte wide element to buffer, see add()."""
29 if not 0 <= val <= 0xffff:
30 raise ValueError("Can't represent value in specified length")
31 self.bytes += pack('>H', val)
32
34 """Add a three-byte wide element to buffer, see add()."""
35 if not 0 <= val <= 0xffffff:
36 raise ValueError("Can't represent value in specified length")
37 self.bytes += pack('>BH', val >> 16, val & 0xffff)
38
40 """Add a four-byte wide element to buffer, see add()."""
41 if not 0 <= val <= 0xffffffff:
42 raise ValueError("Can't represent value in specified length")
43 self.bytes += pack('>I', val)
44 else:
46 """Add a double-byte wide element to buffer, see add()."""
47 try:
48 self.bytes += pack('>H', val)
49 except struct.error:
50 raise ValueError("Can't represent value in specified length")
51
53 """Add a three-byte wide element to buffer, see add()."""
54 try:
55 self.bytes += pack('>BH', val >> 16, val & 0xffff)
56 except struct.error:
57 raise ValueError("Can't represent value in specified length")
58
60 """Add a four-byte wide element to buffer, see add()."""
61 try:
62 self.bytes += pack('>I', val)
63 except struct.error:
64 raise ValueError("Can't represent value in specified length")
65
66 if sys.version_info >= (3, 0):
67
68
69 - def add(self, x, length):
70 """
71 Add a single positive integer value x, encode it in length bytes
72
73 Encode positive integer x in big-endian format using length bytes,
74 add to the internal buffer.
75
76 @type x: int
77 @param x: value to encode
78
79 @type length: int
80 @param length: number of bytes to use for encoding the value
81 """
82 try:
83 self.bytes += x.to_bytes(length, 'big')
84 except OverflowError:
85 raise ValueError("Can't represent value in specified length")
86 else:
87 _addMethods = {1: addOne, 2: addTwo, 3: addThree, 4: addFour}
88
89 - def add(self, x, length):
90 """
91 Add a single positive integer value x, encode it in length bytes
92
93 Encode positive iteger x in big-endian format using length bytes,
94 add to the internal buffer.
95
96 @type x: int
97 @param x: value to encode
98
99 @type length: int
100 @param length: number of bytes to use for encoding the value
101 """
102 try:
103 self._addMethods[length](self, x)
104 except KeyError:
105 self.bytes += bytearray(length)
106 newIndex = len(self.bytes) - 1
107 for i in range(newIndex, newIndex - length, -1):
108 self.bytes[i] = x & 0xFF
109 x >>= 8
110 if x != 0:
111 raise ValueError("Can't represent value in specified "
112 "length")
113
115 """
116 Add a list of items, encode every item in length bytes
117
118 Uses the unbounded iterable seq to produce items, each of
119 which is then encoded to length bytes
120
121 @type seq: iterable of int
122 @param seq: list of positive integers to encode
123
124 @type length: int
125 @param length: number of bytes to which encode every element
126 """
127 for e in seq:
128 self.add(e, length)
129
130 if sys.version_info < (2, 7):
131
132
134 """Helper method for addVarSeq"""
135 if not all(0 <= i <= 0xffff for i in seq):
136 raise ValueError("Can't represent value in specified "
137 "length")
138 self.bytes += pack('>' + 'H' * len(seq), *seq)
139
140 - def addVarSeq(self, seq, length, lengthLength):
141 """
142 Add a bounded list of same-sized values
143
144 Create a list of specific length with all items being of the same
145 size
146
147 @type seq: list of int
148 @param seq: list of positive integers to encode
149
150 @type length: int
151 @param length: amount of bytes in which to encode every item
152
153 @type lengthLength: int
154 @param lengthLength: amount of bytes in which to encode the overall
155 length of the array
156 """
157 self.add(len(seq)*length, lengthLength)
158 if length == 1:
159 self.bytes.extend(seq)
160 elif length == 2:
161 self._addVarSeqTwo(seq)
162 else:
163 for i in seq:
164 self.add(i, length)
165 else:
166 - def addVarSeq(self, seq, length, lengthLength):
167 """
168 Add a bounded list of same-sized values
169
170 Create a list of specific length with all items being of the same
171 size
172
173 @type seq: list of int
174 @param seq: list of positive integers to encode
175
176 @type length: int
177 @param length: amount of bytes in which to encode every item
178
179 @type lengthLength: int
180 @param lengthLength: amount of bytes in which to encode the overall
181 length of the array
182 """
183 seqLen = len(seq)
184 self.add(seqLen*length, lengthLength)
185 if length == 1:
186 self.bytes.extend(seq)
187 elif length == 2:
188 try:
189 self.bytes += pack('>' + 'H' * seqLen, *seq)
190 except struct.error:
191 raise ValueError("Can't represent value in specified "
192 "length")
193 else:
194 for i in seq:
195 self.add(i, length)
196
198 """
199 Add a variable length list of same-sized element tuples.
200
201 Note that all tuples must have the same size.
202
203 Inverse of Parser.getVarTupleList()
204
205 @type seq: enumerable
206 @param seq: list of tuples
207
208 @type length: int
209 @param length: length of single element in tuple
210
211 @type lengthLength: int
212 @param lengthLength: length in bytes of overall length field
213 """
214 if not seq:
215 self.add(0, lengthLength)
216 else:
217 startPos = len(self.bytes)
218 dataLength = len(seq) * len(seq[0]) * length
219 self.add(dataLength, lengthLength)
220
221
222
223 if length == 1:
224 for elemTuple in seq:
225 self.bytes.extend(elemTuple)
226 else:
227 for elemTuple in seq:
228 self.addFixSeq(elemTuple, length)
229 if startPos + dataLength + lengthLength != len(self.bytes):
230 raise ValueError("Tuples of different lengths")
231
232
234 """
235 Parser for TLV and LV byte-based encodings.
236
237 Parser that can handle arbitrary byte-based encodings usually employed in
238 Type-Length-Value or Length-Value binary encoding protocols like ASN.1
239 or TLS
240
241 Note: if the raw bytes don't match expected values (like trying to
242 read a 4-byte integer from a 2-byte buffer), most methods will raise a
243 SyntaxError exception.
244
245 TODO: don't use an exception used by language parser to indicate errors
246 in application code.
247
248 @type bytes: bytearray
249 @ivar bytes: data to be interpreted (buffer)
250
251 @type index: int
252 @ivar index: current position in the buffer
253
254 @type lengthCheck: int
255 @ivar lengthCheck: size of struct being parsed
256
257 @type indexCheck: int
258 @ivar indexCheck: position at which the structure begins in buffer
259 """
260
262 """
263 Bind raw bytes with parser.
264
265 @type bytes: bytearray
266 @param bytes: bytes to be parsed/interpreted
267 """
268 self.bytes = bytes
269 self.index = 0
270 self.indexCheck = 0
271 self.lengthCheck = 0
272
273 - def get(self, length):
274 """
275 Read a single big-endian integer value encoded in 'length' bytes.
276
277 @type length: int
278 @param length: number of bytes in which the value is encoded in
279
280 @rtype: int
281 """
282 if self.index + length > len(self.bytes):
283 raise SyntaxError()
284 x = 0
285 for _ in range(length):
286 x <<= 8
287 x |= self.bytes[self.index]
288 self.index += 1
289 return x
290
292 """
293 Read a string of bytes encoded in 'lengthBytes' bytes.
294
295 @type lengthBytes: int
296 @param lengthBytes: number of bytes to return
297
298 @rtype: bytearray
299 """
300 if self.index + lengthBytes > len(self.bytes):
301 raise SyntaxError()
302 bytes = self.bytes[self.index : self.index+lengthBytes]
303 self.index += lengthBytes
304 return bytes
305
307 """
308 Read a variable length string with a fixed length.
309
310 @type lengthLength: int
311 @param lengthLength: number of bytes in which the length of the string
312 is encoded in
313
314 @rtype: bytearray
315 """
316 lengthBytes = self.get(lengthLength)
317 return self.getFixBytes(lengthBytes)
318
320 """
321 Read a list of static length with same-sized ints.
322
323 @type length: int
324 @param length: size in bytes of a single element in list
325
326 @type lengthList: int
327 @param lengthList: number of elements in list
328
329 @rtype: list of int
330 """
331 l = [0] * lengthList
332 for x in range(lengthList):
333 l[x] = self.get(length)
334 return l
335
337 """
338 Read a variable length list of same-sized integers.
339
340 @type length: int
341 @param length: size in bytes of a single element
342
343 @type lengthLength: int
344 @param lengthLength: size of the encoded length of the list
345
346 @rtype: list of int
347 """
348 lengthList = self.get(lengthLength)
349 if lengthList % length != 0:
350 raise SyntaxError()
351 lengthList = lengthList // length
352 l = [0] * lengthList
353 for x in range(lengthList):
354 l[x] = self.get(length)
355 return l
356
358 """
359 Read a variable length list of same sized tuples.
360
361 @type elemLength: int
362 @param elemLength: length in bytes of single tuple element
363
364 @type elemNum: int
365 @param elemNum: number of elements in tuple
366
367 @type lengthLength: int
368 @param lengthLength: length in bytes of the list length variable
369
370 @rtype: list of tuple of int
371 """
372 lengthList = self.get(lengthLength)
373 if lengthList % (elemLength * elemNum) != 0:
374 raise SyntaxError()
375 tupleCount = lengthList // (elemLength * elemNum)
376 tupleList = []
377 for _ in range(tupleCount):
378 currentTuple = []
379 for _ in range(elemNum):
380 currentTuple.append(self.get(elemLength))
381 tupleList.append(tuple(currentTuple))
382 return tupleList
383
385 """
386 Read length of struct and start a length check for parsing.
387
388 @type lengthLength: int
389 @param lengthLength: number of bytes in which the length is encoded
390 """
391 self.lengthCheck = self.get(lengthLength)
392 self.indexCheck = self.index
393
395 """
396 Set length of struct and start a length check for parsing.
397
398 @type length: int
399 @param length: expected size of parsed struct in bytes
400 """
401 self.lengthCheck = length
402 self.indexCheck = self.index
403
405 """
406 Stop struct parsing, verify that no under- or overflow occurred.
407
408 In case the expected length was mismatched with actual length of
409 processed data, raises an exception.
410 """
411 if (self.index - self.indexCheck) != self.lengthCheck:
412 raise SyntaxError()
413
415 """
416 Check if there is data in structure left for parsing.
417
418 Returns True if the whole structure was parsed, False if there is
419 some data left.
420
421 Will raise an exception if overflow occured (amount of data read was
422 greater than expected size)
423 """
424 if (self.index - self.indexCheck) < self.lengthCheck:
425 return False
426 elif (self.index - self.indexCheck) == self.lengthCheck:
427 return True
428 else:
429 raise SyntaxError()
430
432 """Return amount of data remaining in struct being parsed."""
433 return len(self.bytes) - self.index
434