Package tlslite :: Package utils :: Module codec
[hide private]
[frames] | no frames]

Source Code for Module tlslite.utils.codec

  1  # Author: Trevor Perrin 
  2  # See the LICENSE file for legal information regarding use of this file. 
  3   
  4  """Classes for reading/writing binary data (such as TLS records).""" 
  5   
  6  from __future__ import division 
  7   
  8   
9 -class Writer(object):
10 - def __init__(self):
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
23 - def addFixSeq(self, seq, length):
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
32 - def addVarTupleSeq(self, seq, length, lengthLength):
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
61 -class Parser(object):
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
89 - def __init__(self, bytes):
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
119 - def getFixBytes(self, lengthBytes):
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
134 - def getVarBytes(self, lengthLength):
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
147 - def getFixList(self, length, lengthList):
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
164 - def getVarList(self, length, lengthLength):
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
185 - def getVarTupleList(self, elemLength, elemNum, lengthLength):
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
212 - def startLengthCheck(self, lengthLength):
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
222 - def setLengthCheck(self, length):
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
232 - def stopLengthCheck(self):
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
242 - def atLengthCheck(self):
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
259 - def getRemainingLength(self):
260 """Return amount of data remaining in struct being parsed.""" 261 return len(self.bytes) - self.index
262