mirror of https://github.com/secdev/scapy.git
ASN.1 enhancements
This commit is contained in:
parent
870770bc0f
commit
36bbb8ff44
|
@ -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)
|
||||
if r:
|
||||
return r + " " + repr(x)
|
||||
return repr(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 type(x) is list:
|
||||
return map(lambda z,pkt=pkt:self.i2repr_one(pkt, z), x)
|
||||
else:
|
||||
return self.i2repr_one(pkt, x)
|
||||
if x is not None and isinstance(x, ASN1_INTEGER):
|
||||
r = self.i2s.get(x.val)
|
||||
if r:
|
||||
return "'%s' %s" % (r, repr(x))
|
||||
return repr(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()))
|
||||
|
|
Loading…
Reference in New Issue