1
2
3
4 """Classes for reading/writing binary data (such as TLS records)."""
5
6 from __future__ import division
7
8
11 self.bytes = bytearray(0)
12
13 - def add(self, x, length):
14 self.bytes += bytearray(length)
15 newIndex = len(self.bytes) - 1
16 for count in range(length):
17 self.bytes[newIndex] = x & 0xFF
18 x >>= 8
19 newIndex -= 1
20 if x != 0:
21 raise ValueError("Can't represent value in specified length")
22
24 for e in seq:
25 self.add(e, length)
26
27 - def addVarSeq(self, seq, length, lengthLength):
28 self.add(len(seq)*length, lengthLength)
29 for e in seq:
30 self.add(e, length)
31
33 """
34 Add a variable length list of same-sized element tuples.
35
36 Note that all tuples must have the same size.
37
38 Inverse of Parser.getVarTupleList()
39
40 @type seq: enumerable
41 @param seq: list of tuples
42
43 @type length: int
44 @param length: length of single element in tuple
45
46 @type lengthLength: int
47 @param lengthLength: length in bytes of overall length field
48 """
49 if len(seq) == 0:
50 self.add(0, lengthLength)
51 else:
52 tupleSize = len(seq[0])
53 tupleLength = tupleSize*length
54 self.add(len(seq)*tupleLength, lengthLength)
55 for elemTuple in seq:
56 if len(elemTuple) != tupleSize:
57 raise ValueError("Tuples of different sizes")
58 for elem in elemTuple:
59 self.add(elem, length)
60
62 """
63 Parser for TLV and LV byte-based encodings.
64
65 Parser that can handle arbitrary byte-based encodings usually employed in
66 Type-Length-Value or Length-Value binary encoding protocols like ASN.1
67 or TLS
68
69 Note: if the raw bytes don't match expected values (like trying to
70 read a 4-byte integer from a 2-byte buffer), most methods will raise a
71 SyntaxError exception.
72
73 TODO: don't use an exception used by language parser to indicate errors
74 in application code.
75
76 @type bytes: bytearray
77 @ivar bytes: data to be interpreted (buffer)
78
79 @type index: int
80 @ivar index: current position in the buffer
81
82 @type lengthCheck: int
83 @ivar lengthCheck: size of struct being parsed
84
85 @type indexCheck: int
86 @ivar indexCheck: position at which the structure begins in buffer
87 """
88
90 """
91 Bind raw bytes with parser.
92
93 @type bytes: bytearray
94 @param bytes: bytes to be parsed/interpreted
95 """
96 self.bytes = bytes
97 self.index = 0
98 self.indexCheck = 0
99 self.lengthCheck = 0
100
101 - def get(self, length):
102 """
103 Read a single big-endian integer value encoded in 'length' bytes.
104
105 @type length: int
106 @param length: number of bytes in which the value is encoded in
107
108 @rtype: int
109 """
110 if self.index + length > len(self.bytes):
111 raise SyntaxError()
112 x = 0
113 for _ in range(length):
114 x <<= 8
115 x |= self.bytes[self.index]
116 self.index += 1
117 return x
118
120 """
121 Read a string of bytes encoded in 'lengthBytes' bytes.
122
123 @type lengthBytes: int
124 @param lengthBytes: number of bytes to return
125
126 @rtype: bytearray
127 """
128 if self.index + lengthBytes > len(self.bytes):
129 raise SyntaxError()
130 bytes = self.bytes[self.index : self.index+lengthBytes]
131 self.index += lengthBytes
132 return bytes
133
135 """
136 Read a variable length string with a fixed length.
137
138 @type lengthLength: int
139 @param lengthLength: number of bytes in which the length of the string
140 is encoded in
141
142 @rtype: bytearray
143 """
144 lengthBytes = self.get(lengthLength)
145 return self.getFixBytes(lengthBytes)
146
148 """
149 Read a list of static length with same-sized ints.
150
151 @type length: int
152 @param length: size in bytes of a single element in list
153
154 @type lengthList: int
155 @param lengthList: number of elements in list
156
157 @rtype: list of int
158 """
159 l = [0] * lengthList
160 for x in range(lengthList):
161 l[x] = self.get(length)
162 return l
163
165 """
166 Read a variable length list of same-sized integers.
167
168 @type length: int
169 @param length: size in bytes of a single element
170
171 @type lengthLength: int
172 @param lengthLength: size of the encoded length of the list
173
174 @rtype: list of int
175 """
176 lengthList = self.get(lengthLength)
177 if lengthList % length != 0:
178 raise SyntaxError()
179 lengthList = lengthList // length
180 l = [0] * lengthList
181 for x in range(lengthList):
182 l[x] = self.get(length)
183 return l
184
186 """
187 Read a variable length list of same sized tuples.
188
189 @type elemLength: int
190 @param elemLength: length in bytes of single tuple element
191
192 @type elemNum: int
193 @param elemNum: number of elements in tuple
194
195 @type lengthLength: int
196 @param lengthLength: length in bytes of the list length variable
197
198 @rtype: list of tuple of int
199 """
200 lengthList = self.get(lengthLength)
201 if lengthList % (elemLength * elemNum) != 0:
202 raise SyntaxError()
203 tupleCount = lengthList // (elemLength * elemNum)
204 tupleList = []
205 for _ in range(tupleCount):
206 currentTuple = []
207 for _ in range(elemNum):
208 currentTuple.append(self.get(elemLength))
209 tupleList.append(tuple(currentTuple))
210 return tupleList
211
213 """
214 Read length of struct and start a length check for parsing.
215
216 @type lengthLength: int
217 @param lengthLength: number of bytes in which the length is encoded
218 """
219 self.lengthCheck = self.get(lengthLength)
220 self.indexCheck = self.index
221
223 """
224 Set length of struct and start a length check for parsing.
225
226 @type length: int
227 @param length: expected size of parsed struct in bytes
228 """
229 self.lengthCheck = length
230 self.indexCheck = self.index
231
233 """
234 Stop struct parsing, verify that no under- or overflow occurred.
235
236 In case the expected length was mismatched with actual length of
237 processed data, raises an exception.
238 """
239 if (self.index - self.indexCheck) != self.lengthCheck:
240 raise SyntaxError()
241
243 """
244 Check if there is data in structure left for parsing.
245
246 Returns True if the whole structure was parsed, False if there is
247 some data left.
248
249 Will raise an exception if overflow occured (amount of data read was
250 greater than expected size)
251 """
252 if (self.index - self.indexCheck) < self.lengthCheck:
253 return False
254 elif (self.index - self.indexCheck) == self.lengthCheck:
255 return True
256 else:
257 raise SyntaxError()
258
260 """Return amount of data remaining in struct being parsed."""
261 return len(self.bytes) - self.index
262