Skip to content
Snippets Groups Projects
Commit 36bbb8ff authored by mtu's avatar mtu
Browse files

ASN.1 enhancements

parent 870770bc
No related branches found
No related tags found
No related merge requests found
......@@ -262,19 +262,42 @@ class ASN1_BIT_STRING(ASN1_Object):
"""
tag = ASN1_Class_UNIVERSAL.BIT_STRING
def __init__(self, val, readable=False):
if readable:
self.val_readable = val
val = "".join(binrepr(ord(x)).zfill(8) for x in val)
self.unused_bits = 0
if not readable:
self.val = val
else:
if len(val) % 8 == 0:
self.unused_bits = 0
self.val_readable = val
def __setattr__(self, name, value):
if name == "val_readable":
if isinstance(value, str):
val = "".join(binrepr(ord(x)).zfill(8) for x in value)
else:
self.unused_bits = 8 - len(val)%8
padded_val = val + "0"*self.unused_bits
bytes_arr = zip(*[iter(padded_val)]*8)
self.val_readable = "".join(chr(int("".join(x),2)) for x in bytes_arr)
ASN1_Object.__init__(self, val)
val = "<invalid val_readable>"
super(ASN1_Object, self).__setattr__("val", val)
super(ASN1_Object, self).__setattr__(name, value)
super(ASN1_Object, self).__setattr__("unused_bits", 0)
elif name == "val":
if isinstance(value, str):
if len([c for c in value if c not in ["0", "1"]]) > 0:
print "Invalid operation: 'val' is not a valid bit string."
return
else:
if len(value) % 8 == 0:
unused_bits = 0
else:
unused_bits = 8 - (len(value) % 8)
padded_value = value + ("0" * unused_bits)
bytes_arr = zip(*[iter(padded_value)]*8)
val_readable = "".join(chr(int("".join(x),2)) for x in bytes_arr)
else:
val_readable = "<invalid val>"
unused_bits = 0
super(ASN1_Object, self).__setattr__("val_readable", val_readable)
super(ASN1_Object, self).__setattr__(name, value)
super(ASN1_Object, self).__setattr__("unused_bits", unused_bits)
elif name == "unused_bits":
print "Invalid operation: unused_bits rewriting is not supported."
else:
super(ASN1_Object, self).__setattr__(name, value)
def __repr__(self):
if len(self.val) <= 16:
return "<%s[%r] (%d unused bit%s)>" % (self.__dict__.get("name", self.__class__.__name__), self.val, self.unused_bits, "s" if self.unused_bits>1 else "")
......@@ -327,26 +350,46 @@ class ASN1_IA5_STRING(ASN1_STRING):
class ASN1_UTC_TIME(ASN1_STRING):
tag = ASN1_Class_UNIVERSAL.UTC_TIME
def __init__(self, val):
pretty_time = ""
if len(val) == 13 and val[-1] == "Z":
dt = datetime.strptime(val[:-1], "%y%m%d%H%M%S")
pretty_time = dt.strftime("%b %d %H:%M:%S %Y GMT")
self.pretty_time = pretty_time
ASN1_STRING.__init__(self, val)
super(ASN1_UTC_TIME, self).__init__(val)
def __setattr__(self, name, value):
if name == "val":
pretty_time = None
if (isinstance(value, str) and
len(value) == 13 and value[-1] == "Z"):
dt = datetime.strptime(value[:-1], "%y%m%d%H%M%S")
pretty_time = dt.strftime("%b %d %H:%M:%S %Y GMT")
else:
pretty_time = "%s [invalid utc_time]" % value
super(ASN1_UTC_TIME, self).__setattr__("pretty_time", pretty_time)
super(ASN1_UTC_TIME, self).__setattr__(name, value)
elif name == "pretty_time":
print "Invalid operation: pretty_time rewriting is not supported."
else:
super(ASN1_UTC_TIME, self).__setattr__(name, value)
def __repr__(self):
return self.pretty_time + " " + ASN1_STRING.__repr__(self)
return "%s %s" % (self.pretty_time, ASN1_STRING.__repr__(self))
class ASN1_GENERALIZED_TIME(ASN1_STRING):
tag = ASN1_Class_UNIVERSAL.GENERALIZED_TIME
def __init__(self, val):
pretty_time = ""
if len(val) == 15 and val[-1] == "Z":
dt = datetime.strptime(val[:-1], "%Y%m%d%H%M%S")
pretty_time = dt.strftime("%b %d %H:%M:%S %Y GMT")
self.pretty_time = pretty_time
ASN1_STRING.__init__(self, val)
super(ASN1_GENERALIZED_TIME, self).__init__(val)
def __setattr__(self, name, value):
if name == "val":
pretty_time = None
if (isinstance(value, str) and
len(value) == 15 and value[-1] == "Z"):
dt = datetime.strptime(value[:-1], "%Y%m%d%H%M%S")
pretty_time = dt.strftime("%b %d %H:%M:%S %Y GMT")
else:
pretty_time = "%s [invalid generalized_time]" % value
super(ASN1_GENERALIZED_TIME, self).__setattr__("pretty_time", pretty_time)
super(ASN1_GENERALIZED_TIME, self).__setattr__(name, value)
elif name == "pretty_time":
print "Invalid operation: pretty_time rewriting is not supported."
else:
super(ASN1_GENERALIZED_TIME, self).__setattr__(name, value)
def __repr__(self):
return self.pretty_time + " " + ASN1_STRING.__repr__(self)
return "%s %s" % (self.pretty_time, ASN1_STRING.__repr__(self))
class ASN1_ISO646_STRING(ASN1_STRING):
tag = ASN1_Class_UNIVERSAL.ISO646_STRING
......
......@@ -105,13 +105,15 @@ def BER_id_dec(s):
# This returns the tag ALONG WITH THE PADDED CLASS+CONSTRUCTIVE INFO.
# Let's recall that bits 8-7 from the first byte of the tag encode
# the class information, while bit 6 means primitive or constructive.
#
# For instance, with low-tag-number '\x81', class would be 0b10
# ('context-specific') and tag 0x01, but we return 0x81 as a whole.
# For '\xff\x02', class would be 0b11 ('private'), constructed, then
# padding, then tag 0x02, but we return (0xff>>5)*128^1 + 0x02*128^0.
# For '\xff\x22', class would be 0b11 ('private'), constructed, then
# padding, then tag 0x22, but we return (0xff>>5)*128^1 + 0x22*128^0.
# Why the 5-bit-shifting? Because it provides an unequivocal encoding
# on base 128 (note that 0xff would equal 1*128^1 + 127*128^0...),
# as we know that bits 5 to 1 are fixed to 1 anyway.
#
# As long as there is no class differentiation, we have to keep this info
# encoded in scapy's tag in order to reuse it for packet building.
# Note that tags thus may have to be hard-coded with their extended
......@@ -394,7 +396,7 @@ class BERcodec_ISO646_STRING(BERcodec_STRING):
class BERcodec_UNIVERSAL_STRING(BERcodec_STRING):
tag = ASN1_Class_UNIVERSAL.UNIVERSAL_STRING
class BERcodec_BMP_STRING (BERcodec_STRING):
class BERcodec_BMP_STRING(BERcodec_STRING):
tag = ASN1_Class_UNIVERSAL.BMP_STRING
class BERcodec_SEQUENCE(BERcodec_Object):
......
......@@ -179,26 +179,16 @@ class ASN1F_enum_INTEGER(ASN1F_INTEGER):
for k in keys:
i2s[k] = enum[k]
s2i[enum[k]] = k
def any2i_one(self, pkt, x):
if type(x) is str:
x = self.s2i[x]
return x
def any2i(self, pkt, x):
if type(x) is list:
return map(lambda z,pkt=pkt:self.any2i_one(pkt,z), x)
else:
return self.any2i_one(pkt, x)
def i2repr_one(self, pkt, x):
if x is not None:
r = self.i2s.get(x)
def i2m(self, pkt, s):
if isinstance(s, str):
s = self.s2i.get(s)
return super(ASN1F_INTEGER, self).i2m(pkt, s)
def i2repr(self, pkt, x):
if x is not None and isinstance(x, ASN1_INTEGER):
r = self.i2s.get(x.val)
if r:
return r + " " + repr(x)
return "'%s' %s" % (r, repr(x))
return repr(x)
def i2repr(self, pkt, x):
if type(x) is list:
return map(lambda z,pkt=pkt:self.i2repr_one(pkt, z), x)
else:
return self.i2repr_one(pkt, x)
class ASN1F_BIT_STRING(ASN1F_field):
ASN1_tag = ASN1_Class_UNIVERSAL.BIT_STRING
......@@ -479,22 +469,23 @@ class ASN1F_CHOICE(ASN1F_field):
else:
choice = self.choices[tag]
if hasattr(choice, "ASN1_root"):
# we don't want to import ASN1_Packet in this module...
return self.extract_packet(choice, s)
elif type(choice) is type:
#XXX find a way not to instantiate the ASN1F_field
return choice(self.name, "").m2i(pkt, s)
else:
if type(choice) is type:
return choice(self.name, "").m2i(pkt, s)
else:
# choice must be an ASN1F_PACKET instance here
return choice.m2i(pkt, s)
#XXX check properly if this is an ASN1F_PACKET
return choice.m2i(pkt, s)
def i2m(self, pkt, x):
if x is None:
s = ""
else:
s = str(x)
if hash(type(x)) in self.pktchoices:
imp, exp = self.pktchoices[hash(type(x))]
s = BER_tagging_enc(s, implicit_tag=imp,
explicit_tag=exp)
if hash(type(x)) in self.pktchoices:
imp, exp = self.pktchoices[hash(type(x))]
s = BER_tagging_enc(s, implicit_tag=imp,
explicit_tag=exp)
return BER_tagging_enc(s, explicit_tag=self.explicit_tag)
def randval(self):
return RandChoice(*(packet.fuzz(x()) for x in self.choices.itervalues()))
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment