1
# Twisted, the Framework of Your Internet
2
# Copyright (C) 2001 Matthew W. Lefkowitz
4
# This library is free software; you can redistribute it and/or
5
# modify it under the terms of version 2.1 of the GNU Lesser General Public
6
# License as published by the Free Software Foundation.
8
# This library is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11
# Lesser General Public License for more details.
13
# You should have received a copy of the GNU Lesser General Public
14
# License along with this library; if not, write to the Free Software
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
"""Pure, simple, BER encoding and decoding"""
19
# This BER library is currently aimed at supporting LDAP, thus
20
# the following restrictions from RFC2251 apply:
22
# (1) Only the definite form of length encoding will be used.
24
# (2) OCTET STRING values will be encoded in the primitive form
27
# (3) If the value of a BOOLEAN type is true, the encoding MUST have
28
# its contents octets set to hex "FF".
30
# (4) If a value of a type is its default value, it MUST be absent.
31
# Only some BOOLEAN and INTEGER types have default values in
32
# this protocol definition.
36
from twisted.python.mutablestring import MutableString
43
# | primitive (0) or structured (1)
48
CLASS_UNIVERSAL = 0x00
49
CLASS_APPLICATION = 0x40
53
STRUCTURED_MASK = 0x20
61
# 1xxxxxxx = len is stored in the next 0xxxxxxx octets
62
# indefinite form not supported
76
l=ber2int(m[1:1+ll], signed=0)
91
assert ord(le[0])&0x80==0
92
le0=chr(ord(le[0])|0x80)
97
encoded=MutableString()
98
while i>127 or i<-128:
99
encoded=chr(i%256)+encoded
101
encoded=chr(i%256)+encoded
104
def ber2int(e, signed=1):
107
if v&0x80 and signed:
109
for i in range(1, len(e)):
116
def identification(self):
119
def __init__(self, tag=None):
124
return len(str(self))
126
def __cmp__(self, other):
127
if isinstance(other, BERBase):
128
return cmp(str(self), str(other))
132
class BERStructured(BERBase):
133
def identification(self):
134
return STRUCTURED|self.tag
136
class BERException(Exception): pass
138
class BERExceptionInsufficientData(Exception): pass
143
raise BERExceptionInsufficientData, d
145
class BERInteger(BERBase):
148
def decode(self, encoded, berdecoder):
149
e2=MutableString(encoded)
151
self.tag=ber2int(e2[0], signed=0)&(CLASS_MASK|TAG_MASK)
159
self.value=ber2int(e)
161
def __init__(self, value=None, encoded=None, berdecoder=None, tag=None):
162
"""Create a new BERInteger object.
163
Either value or encoded must be given:
164
value is an integer, encoded is a MutableString.
166
BERBase.__init__(self, tag)
173
self.decode(encoded, berdecoder)
175
raise "You must give either value or encoded"
178
encoded=int2ber(self.value)
179
return chr(self.identification()) \
180
+int2berlen(len(encoded)) \
184
if self.tag==self.__class__.tag:
185
return self.__class__.__name__+"(value=%d)"%self.value
187
return self.__class__.__name__+"(value=%d, tag=%d)" \
188
%(self.value, self.tag)
190
class BEROctetString(BERBase):
193
def decode(self, encoded, berdecoder):
194
e2=MutableString(encoded)
196
self.tag=ber2int(e2[0], signed=0)&(CLASS_MASK|TAG_MASK)
206
def __init__(self, value=None, encoded=None, berdecoder=None, tag=None):
207
BERBase.__init__(self, tag)
214
self.decode(encoded, berdecoder)
216
raise "You must give either value or encoded"
219
return chr(self.identification()) \
220
+int2berlen(len(self.value)) \
224
if self.tag==self.__class__.tag:
225
return self.__class__.__name__+"(value=%s)" \
228
return self.__class__.__name__ \
229
+"(value=%s, tag=%d)" \
230
%(repr(self.value), self.tag)
232
class BERNull(BERBase):
235
def decode(self, encoded, berdecoder):
237
self.tag=ber2int(encoded[0], signed=0)&(CLASS_MASK|TAG_MASK)
238
assert encoded[1]=='\000'
241
def __init__(self, encoded=None, berdecoder=None, tag=None):
242
BERBase.__init__(self, tag)
245
self.decode(encoded, berdecoder)
248
return chr(self.identification())+chr(0)
251
if self.tag==self.__class__.tag:
252
return self.__class__.__name__+"()"
254
return self.__class__.__name__+"(tag=%d)"%self.tag
256
class BERBoolean(BERBase):
259
def decode(self, encoded, berdecoder):
260
e2=MutableString(encoded)
262
self.tag=ber2int(e2[0], signed=0)&(CLASS_MASK|TAG_MASK)
275
def __init__(self, value=None, encoded=None, berdecoder=None, tag=None):
276
"""Create a new BERInteger object.
277
Either value or encoded must be given:
278
value is an integer, encoded is a MutableString.
280
BERBase.__init__(self, tag)
289
self.decode(encoded, berdecoder)
291
raise "You must give either value or encoded"
294
assert self.value==0 or self.value==0xFF
295
return chr(self.identification()) \
300
if self.tag==self.__class__.tag:
301
return self.__class__.__name__+"(value=%d)"%self.value
303
return self.__class__.__name__+"(value=%d, tag=%d)" \
304
%(self.value, self.tag)
307
class BEREnumerated(BERInteger):
310
class BERSequence(BERStructured, UserList.UserList):
311
# TODO __getslice__ calls __init__ with no args.
314
def decode(self, encoded, berdecoder):
315
e2=MutableString(encoded)
317
self.tag=ber2int(e2[0], signed=0)&(CLASS_MASK|TAG_MASK)
326
n=ber2object(berdecoder, content)
331
def __init__(self, value=None, encoded=None, berdecoder=None, tag=None):
332
BERStructured.__init__(self, tag)
333
UserList.UserList.__init__(self)
340
self.decode(encoded, berdecoder)
342
raise "You must give either value or encoded"
345
r=string.join(map(str, self.data), '')
346
return chr(self.identification())+int2berlen(len(r))+r
349
if self.tag==self.__class__.tag:
350
return self.__class__.__name__+"(value=%s)"%repr(self.data)
352
return self.__class__.__name__+"(value=%s, tag=%d)" \
353
%(repr(self.data), self.tag)
356
class BERSequenceOf(BERSequence):
359
class BERSet(BERSequence):
365
class BERDecoderContext:
367
BERInteger.tag: BERInteger,
368
BEROctetString.tag: BEROctetString,
369
BERNull.tag: BERNull,
370
BERBoolean.tag: BERBoolean,
371
BEREnumerated.tag: BEREnumerated,
372
BERSequence.tag: BERSequence,
376
def __init__(self, fallback=None, inherit=None):
377
self.fallback=fallback
378
self.inherit_context=inherit
380
def lookup_id(self, id):
382
return self.Identities[id]
385
return self.fallback.lookup_id(id)
390
return self.inherit_context or self
393
return "<"+self.__class__.__name__ \
394
+" identities="+repr(self.Identities) \
395
+" fallback="+repr(self.fallback) \
396
+" inherit="+repr(self.inherit_context) \
399
def ber2object(context, m):
400
"""ber2object(mutablestring) -> berobject
401
Modifies mutablestring to remove decoded part.
406
i=ber2int(m[0], signed=0)&(CLASS_MASK|TAG_MASK)
407
berclass=context.lookup_id(i)
409
inh=context.inherit()
411
return berclass(encoded=m, berdecoder=inh)
413
raise "BERDecoderContext %s has no tag 0x%02x"%(context, i)
414
tag=ber2int(m[0], signed=0)
417
print "Skipped unknown tag=%d, len=%d"%(tag,l)
421
#TODO unimplemented classes are below:
423
#class BERObjectIdentifier(BERBase):
427
#class BERIA5String(BERBase):
431
#class BERPrintableString(BERBase):
435
#class BERT61String(BERBase):
439
#class BERUTCTime(BERBase):
443
#class BERBitString(BERBase):