diff --git a/scapy/asn1/asn1.py b/scapy/asn1/asn1.py index 841ed901e7f51c084e922481500f2e426ac584bd..624a5e32434de8a6cba2cbea8778267370b0392e 100644 --- a/scapy/asn1/asn1.py +++ b/scapy/asn1/asn1.py @@ -1,6 +1,7 @@ ## This file is part of Scapy ## See http://www.secdev.org/projects/scapy for more informations ## Copyright (C) Philippe Biondi <phil@secdev.org> +## Modified by Maxence Tury <maxence.tury@ssi.gouv.fr> ## This program is published under a GPLv2 license """ @@ -8,10 +9,11 @@ ASN.1 (Abstract Syntax Notation One) """ import random +from datetime import datetime from scapy.config import conf -from scapy.error import Scapy_Exception,warning +from scapy.error import Scapy_Exception, warning from scapy.volatile import RandField -from scapy.utils import Enum_metaclass, EnumElement +from scapy.utils import Enum_metaclass, EnumElement, binrepr class RandASN1Object(RandField): def __init__(self, objlist=None): @@ -153,27 +155,25 @@ class ASN1_Class_UNIVERSAL(ASN1_Class): EMBEDDED_PDF = 11 UTF8_STRING = 12 RELATIVE_OID = 13 - SEQUENCE = 0x30#XXX 16 ?? - SET = 0x31 #XXX 17 ?? + SEQUENCE = 16|0x20 # constructed encoding + SET = 17|0x20 # constructed encoding NUMERIC_STRING = 18 PRINTABLE_STRING = 19 - T61_STRING = 20 + T61_STRING = 20 # aka TELETEX_STRING VIDEOTEX_STRING = 21 IA5_STRING = 22 UTC_TIME = 23 GENERALIZED_TIME = 24 GRAPHIC_STRING = 25 - ISO646_STRING = 26 + ISO646_STRING = 26 # aka VISIBLE_STRING GENERAL_STRING = 27 UNIVERSAL_STRING = 28 CHAR_STRING = 29 BMP_STRING = 30 - IPADDRESS = 0x40 - COUNTER32 = 0x41 - GAUGE32 = 0x42 - TIME_TICKS = 0x43 - COUNTER64 = 0x46 - SEP = 0x80 + IPADDRESS = 0|0x40 # application-specific encoding + COUNTER32 = 1|0x40 # application-specific encoding + TIME_TICKS = 3|0x40 # application-specific encoding + class ASN1_Object_metaclass(type): def __new__(cls, name, bases, dct): @@ -184,7 +184,6 @@ class ASN1_Object_metaclass(type): warning("Error registering %r for %r" % (c.tag, c.codec)) return c - class ASN1_Object: __metaclass__ = ASN1_Object_metaclass tag = ASN1_Class_UNIVERSAL.ANY @@ -205,6 +204,13 @@ class ASN1_Object: def __cmp__(self, other): return cmp(self.val, other) + +####################### +#### ASN1 objects #### +####################### + +# on the whole, we order the classes by ASN1_Class_UNIVERSAL tag value + class ASN1_DECODING_ERROR(ASN1_Object): tag = ASN1_Class_UNIVERSAL.ERROR def __init__(self, val, exc=None): @@ -230,61 +236,124 @@ class ASN1_BADTAG(ASN1_force): class ASN1_INTEGER(ASN1_Object): tag = ASN1_Class_UNIVERSAL.INTEGER + def __repr__(self): + h = hex(self.val) + if h[-1] == "L": + h = h[:-1] + # cut at 22 because with leading '0x', x509 serials should be < 23 + if len(h) > 22: + h = h[:12] + "..." + h[-10:] + r = repr(self.val) + if len(r) > 20: + r = r[:10] + "..." + r[-10:] + return h + " <%s[%s]>" % (self.__dict__.get("name", self.__class__.__name__), r) + +class ASN1_BOOLEAN(ASN1_INTEGER): + tag = ASN1_Class_UNIVERSAL.BOOLEAN + # BER: 0 means False, anything else means True + def __repr__(self): + return str((not (self.val==0))) + " " + ASN1_Object.__repr__(self) + +class ASN1_BIT_STRING(ASN1_Object): + """ + /!\ ASN1_BIT_STRING values are bit strings like "011101". + /!\ A zero-bit padded readable string is provided nonetheless. + """ + 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 + else: + if len(val) % 8 == 0: + self.unused_bits = 0 + 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) + 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 "") + else: + s = self.val_readable + if len(s) > 20: + s = s[:10] + "..." + s[-10:] + return "<%s[%r] (%d unused bit%s)>" % (self.__dict__.get("name", self.__class__.__name__), s, self.unused_bits, "s" if self.unused_bits>1 else "") class ASN1_STRING(ASN1_Object): tag = ASN1_Class_UNIVERSAL.STRING -class ASN1_BIT_STRING(ASN1_STRING): - tag = ASN1_Class_UNIVERSAL.BIT_STRING +class ASN1_NULL(ASN1_Object): + tag = ASN1_Class_UNIVERSAL.NULL + def __repr__(self): + return ASN1_Object.__repr__(self) -class ASN1_PRINTABLE_STRING(ASN1_STRING): - tag = ASN1_Class_UNIVERSAL.PRINTABLE_STRING +class ASN1_OID(ASN1_Object): + tag = ASN1_Class_UNIVERSAL.OID + def __init__(self, val): + val = conf.mib._oid(val) + ASN1_Object.__init__(self, val) + self.oidname = conf.mib._oidname(val) + def __repr__(self): + return "<%s[%r]>" % (self.__dict__.get("name", self.__class__.__name__), self.oidname) -class ASN1_T61_STRING(ASN1_STRING): - tag = ASN1_Class_UNIVERSAL.T61_STRING +class ASN1_ENUMERATED(ASN1_INTEGER): + tag = ASN1_Class_UNIVERSAL.ENUMERATED -class ASN1_IA5_STRING(ASN1_STRING): - tag = ASN1_Class_UNIVERSAL.IA5_STRING +class ASN1_UTF8_STRING(ASN1_STRING): + tag = ASN1_Class_UNIVERSAL.UTF8_STRING class ASN1_NUMERIC_STRING(ASN1_STRING): tag = ASN1_Class_UNIVERSAL.NUMERIC_STRING +class ASN1_PRINTABLE_STRING(ASN1_STRING): + tag = ASN1_Class_UNIVERSAL.PRINTABLE_STRING + +class ASN1_T61_STRING(ASN1_STRING): + tag = ASN1_Class_UNIVERSAL.T61_STRING + class ASN1_VIDEOTEX_STRING(ASN1_STRING): tag = ASN1_Class_UNIVERSAL.VIDEOTEX_STRING -class ASN1_IPADDRESS(ASN1_STRING): - tag = ASN1_Class_UNIVERSAL.IPADDRESS +class ASN1_IA5_STRING(ASN1_STRING): + tag = ASN1_Class_UNIVERSAL.IA5_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) + def __repr__(self): + return 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) + def __repr__(self): + return self.pretty_time + " " + ASN1_STRING.__repr__(self) -class ASN1_TIME_TICKS(ASN1_INTEGER): - tag = ASN1_Class_UNIVERSAL.TIME_TICKS +class ASN1_ISO646_STRING(ASN1_STRING): + tag = ASN1_Class_UNIVERSAL.ISO646_STRING -class ASN1_BOOLEAN(ASN1_INTEGER): - tag = ASN1_Class_UNIVERSAL.BOOLEAN +class ASN1_UNIVERSAL_STRING(ASN1_STRING): + tag = ASN1_Class_UNIVERSAL.UNIVERSAL_STRING -class ASN1_ENUMERATED(ASN1_INTEGER): - tag = ASN1_Class_UNIVERSAL.ENUMERATED - -class ASN1_NULL(ASN1_INTEGER): - tag = ASN1_Class_UNIVERSAL.NULL +class ASN1_BMP_STRING(ASN1_STRING): + tag = ASN1_Class_UNIVERSAL.BMP_STRING -class ASN1_SEP(ASN1_NULL): - tag = ASN1_Class_UNIVERSAL.SEP - -class ASN1_GAUGE32(ASN1_INTEGER): - tag = ASN1_Class_UNIVERSAL.GAUGE32 - -class ASN1_COUNTER32(ASN1_INTEGER): - tag = ASN1_Class_UNIVERSAL.COUNTER32 - -class ASN1_COUNTER64(ASN1_INTEGER): - tag = ASN1_Class_UNIVERSAL.COUNTER64 - class ASN1_SEQUENCE(ASN1_Object): tag = ASN1_Class_UNIVERSAL.SEQUENCE def strshow(self, lvl=0): @@ -295,17 +364,15 @@ class ASN1_SEQUENCE(ASN1_Object): class ASN1_SET(ASN1_SEQUENCE): tag = ASN1_Class_UNIVERSAL.SET - -class ASN1_OID(ASN1_Object): - tag = ASN1_Class_UNIVERSAL.OID - def __init__(self, val): - val = conf.mib._oid(val) - ASN1_Object.__init__(self, val) - def __repr__(self): - return "<%s[%r]>" % (self.__dict__.get("name", self.__class__.__name__), conf.mib._oidname(self.val)) - def __oidname__(self): - return '%s'%conf.mib._oidname(self.val) - +class ASN1_IPADDRESS(ASN1_STRING): + tag = ASN1_Class_UNIVERSAL.IPADDRESS + +class ASN1_COUNTER32(ASN1_INTEGER): + tag = ASN1_Class_UNIVERSAL.COUNTER32 + +class ASN1_TIME_TICKS(ASN1_INTEGER): + tag = ASN1_Class_UNIVERSAL.TIME_TICKS + conf.ASN1_default_codec = ASN1_Codecs.BER diff --git a/scapy/asn1/ber.py b/scapy/asn1/ber.py index fe180e1cc2f517350f381c667807b35c3f080fb1..499cda61fe43bc2b59600413de70741bfe0cf51f 100644 --- a/scapy/asn1/ber.py +++ b/scapy/asn1/ber.py @@ -1,6 +1,8 @@ ## This file is part of Scapy ## See http://www.secdev.org/projects/scapy for more informations ## Copyright (C) Philippe Biondi <phil@secdev.org> +## Modified by Maxence Tury <maxence.tury@ssi.gouv.fr> +## Acknowledgment: Ralph Broenink ## This program is published under a GPLv2 license """ @@ -8,7 +10,7 @@ Basic Encoding Rules (BER) for ASN.1 """ from scapy.error import warning -from scapy.utils import inet_aton,inet_ntoa +from scapy.utils import binrepr,inet_aton,inet_ntoa from asn1 import ASN1_Decoding_Error,ASN1_Encoding_Error,ASN1_BadTag_Decoding_Error,ASN1_Codecs,ASN1_Class_UNIVERSAL,ASN1_Error,ASN1_DECODING_ERROR,ASN1_BADTAG ################## @@ -87,8 +89,7 @@ def BER_num_enc(l, size=1): l >>= 7 size -= 1 return "".join([chr(k) for k in x]) -def BER_num_dec(s): - x = 0 +def BER_num_dec(s, x=0): for i, c in enumerate(s): c = ord(c) x <<= 7 @@ -99,6 +100,43 @@ def BER_num_dec(s): raise BER_Decoding_Error("BER_num_dec: unfinished number description", remaining=s) return x, s[i+1:] +# The function below provides low-tag and high-tag identifier partial support. +# Class and primitive/constructed bit decoding is not supported yet. +# For now Scapy considers this information to always be part of the identifier +# e.g. we need BER_id_dec("\x30") to be 0x30 so that Scapy calls a SEQUENCE, +# even though the real id is 0x10 once bit 6 (constructed) has been removed. +def BER_id_dec(s): + x = ord(s[0]) + if x & 0x1f != 0x1f: + return x,s[1:] + return BER_num_dec(s[1:], x&0xe0) + +# The functions below provide implicit and explicit tagging support. +def BER_tagging_dec(s, hidden_tag=None, implicit_tag=None, + explicit_tag=None, safe=False): + if len(s) > 0: + err_msg = "BER_tagging_dec: observed tag does not match expected tag" + if implicit_tag is not None: + ber_id,s = BER_id_dec(s) + if ber_id != implicit_tag: + if not safe: + raise BER_Decoding_Error(err_msg, remaining=s) + s = chr(hidden_tag) + s + elif explicit_tag is not None: + ber_id,s = BER_id_dec(s) + if ber_id != explicit_tag: + if not safe: + raise BER_Decoding_Error(err_msg, remaining=s) + l,s = BER_len_dec(s) + return s +def BER_tagging_enc(s, implicit_tag=None, explicit_tag=None): + if len(s) > 0: + if implicit_tag is not None: + s = chr(implicit_tag) + s[1:] + elif explicit_tag is not None: + s = chr(explicit_tag) + BER_len_enc(len(s)) + s + return s + #####[ BER classes ]##### class BERcodec_metaclass(type): @@ -128,10 +166,11 @@ class BERcodec_Object: @classmethod def check_type(cls, s): cls.check_string(s) - if cls.tag != ord(s[0]): + tag, remainder = BER_id_dec(s) + if cls.tag != tag: raise BER_BadTag_Decoding_Error("%s: Got tag [%i/%#x] while expecting %r" % - (cls.__name__, ord(s[0]), ord(s[0]),cls.tag), remaining=s) - return s[1:] + (cls.__name__, tag, tag, cls.tag), remaining=s) + return remainder @classmethod def check_type_get_len(cls, s): s2 = cls.check_type(s) @@ -152,7 +191,7 @@ class BERcodec_Object: if context is None: context = cls.tag.context cls.check_string(s) - p = ord(s[0]) + p,_ = BER_id_dec(s) if p not in context: t = s if len(t) > 18: @@ -187,11 +226,13 @@ class BERcodec_Object: else: return BERcodec_INTEGER.enc(int(s)) - - ASN1_Codecs.BER.register_stem(BERcodec_Object) +########################## +#### BERcodec objects #### +########################## + class BERcodec_INTEGER(BERcodec_Object): tag = ASN1_Class_UNIVERSAL.INTEGER @classmethod @@ -223,12 +264,46 @@ class BERcodec_INTEGER(BERcodec_Object): x |= ord(c) return cls.asn1_object(x),t - class BERcodec_BOOLEAN(BERcodec_INTEGER): tag = ASN1_Class_UNIVERSAL.BOOLEAN -class BERcodec_ENUMERATED(BERcodec_INTEGER): - tag = ASN1_Class_UNIVERSAL.ENUMERATED +class BERcodec_BIT_STRING(BERcodec_Object): + tag = ASN1_Class_UNIVERSAL.BIT_STRING + @classmethod + def do_dec(cls, s, context=None, safe=False): + # /!\ the unused_bits information is lost after this decoding + l,s,t = cls.check_type_check_len(s) + if len(s) > 0: + unused_bits = ord(s[0]) + if safe and unused_bits > 7: + raise BER_Decoding_Error("BERcodec_BIT_STRING: too many unused_bits advertised", remaining=s) + s = "".join(binrepr(ord(x)).zfill(8) for x in s[1:]) + if unused_bits > 0: + s = s[:-unused_bits] + return cls.tag.asn1_object(s),t + else: + raise BER_Decoding_Error("BERcodec_BIT_STRING found no content (not even unused_bits byte)", remaining=s) + @classmethod + def enc(cls,s): + # /!\ this is DER encoding (bit strings are only zero-bit padded) + if len(s) % 8 == 0: + unused_bits = 0 + else: + unused_bits = 8 - len(s)%8 + s += "0"*unused_bits + s = "".join(chr(int("".join(x),2)) for x in zip(*[iter(s)]*8)) + s = chr(unused_bits) + s + return chr(cls.tag)+BER_len_enc(len(s))+s + +class BERcodec_STRING(BERcodec_Object): + tag = ASN1_Class_UNIVERSAL.STRING + @classmethod + def enc(cls,s): + return chr(cls.tag)+BER_len_enc(len(s))+s + @classmethod + def do_dec(cls, s, context=None, safe=False): + l,s,t = cls.check_type_check_len(s) + return cls.tag.asn1_object(s),t class BERcodec_NULL(BERcodec_INTEGER): tag = ASN1_Class_UNIVERSAL.NULL @@ -237,23 +312,35 @@ class BERcodec_NULL(BERcodec_INTEGER): if i == 0: return chr(cls.tag)+"\0" else: - return BERcodec_INTEGER.enc(i) - -class BERcodec_SEP(BERcodec_NULL): - tag = ASN1_Class_UNIVERSAL.SEP + return super(cls,cls).enc(i) -class BERcodec_STRING(BERcodec_Object): - tag = ASN1_Class_UNIVERSAL.STRING +class BERcodec_OID(BERcodec_Object): + tag = ASN1_Class_UNIVERSAL.OID @classmethod - def enc(cls,s): + def enc(cls, oid): + lst = [int(x) for x in oid.strip(".").split(".")] + if len(lst) >= 2: + lst[1] += 40*lst[0] + del(lst[0]) + s = "".join([BER_num_enc(k) for k in lst]) return chr(cls.tag)+BER_len_enc(len(s))+s @classmethod def do_dec(cls, s, context=None, safe=False): l,s,t = cls.check_type_check_len(s) - return cls.tag.asn1_object(s),t + lst = [] + while s: + l,s = BER_num_dec(s) + lst.append(l) + if (len(lst) > 0): + lst.insert(0,lst[0]/40) + lst[1] %= 40 + return cls.asn1_object(".".join([str(k) for k in lst])), t -class BERcodec_BIT_STRING(BERcodec_STRING): - tag = ASN1_Class_UNIVERSAL.BIT_STRING +class BERcodec_ENUMERATED(BERcodec_INTEGER): + tag = ASN1_Class_UNIVERSAL.ENUMERATED + +class BERcodec_UTF8_STRING(BERcodec_STRING): + tag = ASN1_Class_UNIVERSAL.UTF8_STRING class BERcodec_PRINTABLE_STRING(BERcodec_STRING): tag = ASN1_Class_UNIVERSAL.PRINTABLE_STRING @@ -264,49 +351,20 @@ class BERcodec_T61_STRING (BERcodec_STRING): class BERcodec_IA5_STRING(BERcodec_STRING): tag = ASN1_Class_UNIVERSAL.IA5_STRING -class BERcodec_NUMERIC_STRING(BERcodec_STRING): - tag = ASN1_Class_UNIVERSAL.NUMERIC_STRING - -class BERcodec_VIDEOTEX_STRING(BERcodec_STRING): - tag = ASN1_Class_UNIVERSAL.VIDEOTEX_STRING - -class BERcodec_IPADDRESS(BERcodec_STRING): - tag = ASN1_Class_UNIVERSAL.IPADDRESS - - @classmethod - def enc(cls, ipaddr_ascii): - try: - s = inet_aton(ipaddr_ascii) - except Exception: - raise BER_Encoding_Error("IPv4 address could not be encoded") - return chr(cls.tag)+BER_len_enc(len(s))+s - - @classmethod - def do_dec(cls, s, context=None, safe=False): - l,s,t = cls.check_type_check_len(s) - try: - ipaddr_ascii = inet_ntoa(s) - except Exception: - raise BER_Decoding_Error("IP address could not be decoded", decoded=obj) - return cls.asn1_object(ipaddr_ascii), t - class BERcodec_UTC_TIME(BERcodec_STRING): tag = ASN1_Class_UNIVERSAL.UTC_TIME class BERcodec_GENERALIZED_TIME(BERcodec_STRING): tag = ASN1_Class_UNIVERSAL.GENERALIZED_TIME -class BERcodec_TIME_TICKS(BERcodec_INTEGER): - tag = ASN1_Class_UNIVERSAL.TIME_TICKS +class BERcodec_ISO646_STRING(BERcodec_STRING): + tag = ASN1_Class_UNIVERSAL.ISO646_STRING -class BERcodec_GAUGE32(BERcodec_INTEGER): - tag = ASN1_Class_UNIVERSAL.GAUGE32 +class BERcodec_UNIVERSAL_STRING(BERcodec_STRING): + tag = ASN1_Class_UNIVERSAL.UNIVERSAL_STRING -class BERcodec_COUNTER32(BERcodec_INTEGER): - tag = ASN1_Class_UNIVERSAL.COUNTER32 - -class BERcodec_COUNTER64(BERcodec_INTEGER): - tag = ASN1_Class_UNIVERSAL.COUNTER64 +class BERcodec_BMP_STRING (BERcodec_STRING): + tag = ASN1_Class_UNIVERSAL.BMP_STRING class BERcodec_SEQUENCE(BERcodec_Object): tag = ASN1_Class_UNIVERSAL.SEQUENCE @@ -339,28 +397,29 @@ class BERcodec_SEQUENCE(BERcodec_Object): class BERcodec_SET(BERcodec_SEQUENCE): tag = ASN1_Class_UNIVERSAL.SET - -class BERcodec_OID(BERcodec_Object): - tag = ASN1_Class_UNIVERSAL.OID - +class BERcodec_IPADDRESS(BERcodec_STRING): + tag = ASN1_Class_UNIVERSAL.IPADDRESS @classmethod - def enc(cls, oid): - lst = [int(x) for x in oid.strip(".").split(".")] - if len(lst) >= 2: - lst[1] += 40*lst[0] - del(lst[0]) - s = "".join([BER_num_enc(k) for k in lst]) + def enc(cls, ipaddr_ascii): + try: + s = inet_aton(ipaddr_ascii) + except Exception: + raise BER_Encoding_Error("IPv4 address could not be encoded") return chr(cls.tag)+BER_len_enc(len(s))+s @classmethod def do_dec(cls, s, context=None, safe=False): l,s,t = cls.check_type_check_len(s) - lst = [] - while s: - l,s = BER_num_dec(s) - lst.append(l) - if (len(lst) > 0): - lst.insert(0,lst[0]/40) - lst[1] %= 40 - return cls.asn1_object(".".join([str(k) for k in lst])), t + try: + ipaddr_ascii = inet_ntoa(s) + except Exception: + raise BER_Decoding_Error("IP address could not be decoded", decoded=obj) + return cls.asn1_object(ipaddr_ascii), t + +class BERcodec_COUNTER32(BERcodec_INTEGER): + tag = ASN1_Class_UNIVERSAL.COUNTER32 + +class BERcodec_TIME_TICKS(BERcodec_INTEGER): + tag = ASN1_Class_UNIVERSAL.TIME_TICKS + diff --git a/scapy/asn1/mib.py b/scapy/asn1/mib.py index cd0fa65ea1a287f5c23ebab81c90ea0b820de28d..c8065f00d62efb3493658fff38bbc32db8a765f3 100644 --- a/scapy/asn1/mib.py +++ b/scapy/asn1/mib.py @@ -1,6 +1,7 @@ ## This file is part of Scapy ## See http://www.secdev.org/projects/scapy for more informations ## Copyright (C) Philippe Biondi <phil@secdev.org> +## Modified by Maxence Tury <maxence.tury@ssi.gouv.fr> ## This program is published under a GPLv2 license """ @@ -143,5 +144,424 @@ def load_mib(filenames): conf.mib=newmib +#################### +## OID references ## +#################### -conf.mib = MIBDict(_name="MIB") +####### pkcs1 ####### + +pkcs1_oids = { + "rsaEncryption" : "1.2.840.113549.1.1.1", + "md2WithRSAEncryption" : "1.2.840.113549.1.1.2", + "md4WithRSAEncryption" : "1.2.840.113549.1.1.3", + "md5WithRSAEncryption" : "1.2.840.113549.1.1.4", + "sha1-with-rsa-signature" : "1.2.840.113549.1.1.5", + "rsaOAEPEncryptionSET" : "1.2.840.113549.1.1.6", + "id-RSAES-OAEP" : "1.2.840.113549.1.1.7", + "id-mgf1" : "1.2.840.113549.1.1.8", + "id-pSpecified" : "1.2.840.113549.1.1.9", + "rsassa-pss" : "1.2.840.113549.1.1.10", + "sha256WithRSAEncryption" : "1.2.840.113549.1.1.11", + "sha384WithRSAEncryption" : "1.2.840.113549.1.1.12", + "sha512WithRSAEncryption" : "1.2.840.113549.1.1.13", + "sha224WithRSAEncryption" : "1.2.840.113549.1.1.14" + } + +####### pkcs9 ####### + +pkcs9_oids = { + "modules" : "1.2.840.113549.1.9.0", + "emailAddress" : "1.2.840.113549.1.9.1", + "unstructuredName" : "1.2.840.113549.1.9.2", + "contentType" : "1.2.840.113549.1.9.3", + "messageDigest" : "1.2.840.113549.1.9.4", + "signing-time" : "1.2.840.113549.1.9.5", + "countersignature" : "1.2.840.113549.1.9.6", + "challengePassword" : "1.2.840.113549.1.9.7", + "unstructuredAddress" : "1.2.840.113549.1.9.8", + "extendedCertificateAttributes" : "1.2.840.113549.1.9.9", + "signingDescription" : "1.2.840.113549.1.9.13", + "extensionRequest" : "1.2.840.113549.1.9.14", + "smimeCapabilities" : "1.2.840.113549.1.9.15", + "smime" : "1.2.840.113549.1.9.16", + "pgpKeyID" : "1.2.840.113549.1.9.17", + "friendlyName" : "1.2.840.113549.1.9.20", + "localKeyID" : "1.2.840.113549.1.9.21", + "certTypes" : "1.2.840.113549.1.9.22", + "crlTypes" : "1.2.840.113549.1.9.23", + "pkcs-9-oc" : "1.2.840.113549.1.9.24", + "pkcs-9-at" : "1.2.840.113549.1.9.25", + "pkcs-9-sx" : "1.2.840.113549.1.9.26", + "pkcs-9-mr" : "1.2.840.113549.1.9.27", + "id-aa-CMSAlgorithmProtection" : "1.2.840.113549.1.9.52" + } + +####### x509 ####### + +attributeType_oids = { + "objectClass" : "2.5.4.0", + "aliasedEntryName" : "2.5.4.1", + "knowledgeInformation" : "2.5.4.2", + "commonName" : "2.5.4.3", + "surname" : "2.5.4.4", + "serialNumber" : "2.5.4.5", + "countryName" : "2.5.4.6", + "localityName" : "2.5.4.7", + "stateOrProvinceName" : "2.5.4.8", + "streetAddress" : "2.5.4.9", + "organizationName" : "2.5.4.10", + "organizationUnitName" : "2.5.4.11", + "title" : "2.5.4.12", + "description" : "2.5.4.13", + "searchGuide" : "2.5.4.14", + "businessCategory" : "2.5.4.15", + "postalAddress" : "2.5.4.16", + "postalCode" : "2.5.4.17", + "postOfficeBox" : "2.5.4.18", + "physicalDeliveryOfficeName" : "2.5.4.19", + "telephoneNumber" : "2.5.4.20", + "telexNumber" : "2.5.4.21", + "teletexTerminalIdentifier" : "2.5.4.22", + "facsimileTelephoneNumber" : "2.5.4.23", + "x121Address" : "2.5.4.24", + "internationalISDNNumber" : "2.5.4.25", + "registeredAddress" : "2.5.4.26", + "destinationIndicator" : "2.5.4.27", + "preferredDeliveryMethod" : "2.5.4.28", + "presentationAddress" : "2.5.4.29", + "supportedApplicationContext" : "2.5.4.30", + "member" : "2.5.4.31", + "owner" : "2.5.4.32", + "roleOccupant" : "2.5.4.33", + "seeAlso" : "2.5.4.34", + "userPassword" : "2.5.4.35", + "userCertificate" : "2.5.4.36", + "cACertificate" : "2.5.4.37", + "authorityRevocationList" : "2.5.4.38", + "certificateRevocationList" : "2.5.4.39", + "crossCertificatePair" : "2.5.4.40", + "name" : "2.5.4.41", + "givenName" : "2.5.4.42", + "initials" : "2.5.4.43", + "generationQualifier" : "2.5.4.44", + "uniqueIdentifier" : "2.5.4.45", + "dnQualifier" : "2.5.4.46", + "enhancedSearchGuide" : "2.5.4.47", + "protocolInformation" : "2.5.4.48", + "distinguishedName" : "2.5.4.49", + "uniqueMember" : "2.5.4.50", + "houseIdentifier" : "2.5.4.51", + "supportedAlgorithms" : "2.5.4.52", + "deltaRevocationList" : "2.5.4.53", + "dmdName" : "2.5.4.54", + "clearance" : "2.5.4.55", + "defaultDirQop" : "2.5.4.56", + "attributeIntegrityInfo" : "2.5.4.57", + "attributeCertificate" : "2.5.4.58", + "attributeCertificateRevocationList": "2.5.4.59", + "confKeyInfo" : "2.5.4.60", + "aACertificate" : "2.5.4.61", + "attributeDescriptorCertificate" : "2.5.4.62", + "attributeAuthorityRevocationList" : "2.5.4.63", + "family-information" : "2.5.4.64", + "pseudonym" : "2.5.4.65", + "communicationsService" : "2.5.4.66", + "communicationsNetwork" : "2.5.4.67", + "certificationPracticeStmt" : "2.5.4.68", + "certificatePolicy" : "2.5.4.69", + "pkiPath" : "2.5.4.70", + "privPolicy" : "2.5.4.71", + "role" : "2.5.4.72", + "delegationPath" : "2.5.4.73", + "protPrivPolicy" : "2.5.4.74", + "xMLPrivilegeInfo" : "2.5.4.75", + "xmlPrivPolicy" : "2.5.4.76", + "uuidpair" : "2.5.4.77", + "tagOid" : "2.5.4.78", + "uiiFormat" : "2.5.4.79", + "uiiInUrh" : "2.5.4.80", + "contentUrl" : "2.5.4.81", + "permission" : "2.5.4.82", + "uri" : "2.5.4.83", + "pwdAttribute" : "2.5.4.84", + "userPwd" : "2.5.4.85", + "urn" : "2.5.4.86", + "url" : "2.5.4.87", + "utmCoordinates" : "2.5.4.88", + "urnC" : "2.5.4.89", + "uii" : "2.5.4.90", + "epc" : "2.5.4.91", + "tagAfi" : "2.5.4.92", + "epcFormat" : "2.5.4.93", + "epcInUrn" : "2.5.4.94", + "ldapUrl" : "2.5.4.95", + "ldapUrl" : "2.5.4.96", + "organizationIdentifier" : "2.5.4.97" + } + +certificateExtension_oids = { + "authorityKeyIdentifier" : "2.5.29.1", + "keyAttributes" : "2.5.29.2", + "certificatePolicies" : "2.5.29.3", + "keyUsageRestriction" : "2.5.29.4", + "policyMapping" : "2.5.29.5", + "subtreesConstraint" : "2.5.29.6", + "subjectAltName" : "2.5.29.7", + "issuerAltName" : "2.5.29.8", + "subjectDirectoryAttributes" : "2.5.29.9", + "basicConstraints" : "2.5.29.10", + "subjectKeyIdentifier" : "2.5.29.14", + "keyUsage" : "2.5.29.15", + "privateKeyUsagePeriod" : "2.5.29.16", + "subjectAltName" : "2.5.29.17", + "issuerAltName" : "2.5.29.18", + "basicConstraints" : "2.5.29.19", + "cRLNumber" : "2.5.29.20", + "reasonCode" : "2.5.29.21", + "expirationDate" : "2.5.29.22", + "instructionCode" : "2.5.29.23", + "invalidityDate" : "2.5.29.24", + "cRLDistributionPoints" : "2.5.29.25", + "issuingDistributionPoint" : "2.5.29.26", + "deltaCRLIndicator" : "2.5.29.27", + "issuingDistributionPoint" : "2.5.29.28", + "certificateIssuer" : "2.5.29.29", + "nameConstraints" : "2.5.29.30", + "cRLDistributionPoints" : "2.5.29.31", + "certificatePolicies" : "2.5.29.32", + "policyMappings" : "2.5.29.33", + "policyConstraints" : "2.5.29.34", + "authorityKeyIdentifier" : "2.5.29.35", + "policyConstraints" : "2.5.29.36", + "extKeyUsage" : "2.5.29.37", + "authorityAttributeIdentifier" : "2.5.29.38", + "roleSpecCertIdentifier" : "2.5.29.39", + "cRLStreamIdentifier" : "2.5.29.40", + "basicAttConstraints" : "2.5.29.41", + "delegatedNameConstraints" : "2.5.29.42", + "timeSpecification" : "2.5.29.43", + "cRLScope" : "2.5.29.44", + "statusReferrals" : "2.5.29.45", + "freshestCRL" : "2.5.29.46", + "orderedList" : "2.5.29.47", + "attributeDescriptor" : "2.5.29.48", + "userNotice" : "2.5.29.49", + "sOAIdentifier" : "2.5.29.50", + "baseUpdateTime" : "2.5.29.51", + "acceptableCertPolicies" : "2.5.29.52", + "deltaInfo" : "2.5.29.53", + "inhibitAnyPolicy" : "2.5.29.54", + "targetInformation" : "2.5.29.55", + "noRevAvail" : "2.5.29.56", + "acceptablePrivilegePolicies" : "2.5.29.57", + "id-ce-toBeRevoked" : "2.5.29.58", + "id-ce-RevokedGroups" : "2.5.29.59", + "id-ce-expiredCertsOnCRL" : "2.5.29.60", + "indirectIssuer" : "2.5.29.61", + "id-ce-noAssertion" : "2.5.29.62", + "id-ce-aAissuingDistributionPoint" : "2.5.29.63", + "id-ce-issuedOnBehaIFOF" : "2.5.29.64", + "id-ce-singleUse" : "2.5.29.65", + "id-ce-groupAC" : "2.5.29.66", + "id-ce-allowedAttAss" : "2.5.29.67", + "id-ce-attributeMappings" : "2.5.29.68", + "id-ce-holderNameConstraints" : "2.5.29.69" + } + +certExt_oids = { + "cert-type" : "2.16.840.1.113730.1.1", + "base-url" : "2.16.840.1.113730.1.2", + "revocation-url" : "2.16.840.1.113730.1.3", + "ca-revocation-url" : "2.16.840.1.113730.1.4", + "ca-crl-url" : "2.16.840.1.113730.1.5", + "ca-cert-url" : "2.16.840.1.113730.1.6", + "renewal-url" : "2.16.840.1.113730.1.7", + "ca-policy-url" : "2.16.840.1.113730.1.8", + "homepage-url" : "2.16.840.1.113730.1.9", + "entity-logo" : "2.16.840.1.113730.1.10", + "user-picture" : "2.16.840.1.113730.1.11", + "ssl-server-name" : "2.16.840.1.113730.1.12", + "comment" : "2.16.840.1.113730.1.13", + "lost-password-url" : "2.16.840.1.113730.1.14", + "cert-renewal-time" : "2.16.840.1.113730.1.15", + "aia" : "2.16.840.1.113730.1.16", + "cert-scope-of-use" : "2.16.840.1.113730.1.17", + } + +certPkixPe_oids = { + "authorityInfoAccess" : "1.3.6.1.5.5.7.1.1", + "biometricInfo" : "1.3.6.1.5.5.7.1.2", + "qcStatements" : "1.3.6.1.5.5.7.1.3", + "auditIdentity" : "1.3.6.1.5.5.7.1.4", + "aaControls" : "1.3.6.1.5.5.7.1.6", + "proxying" : "1.3.6.1.5.5.7.1.10", + "subjectInfoAccess" : "1.3.6.1.5.5.7.1.11" + } + +certPkixQt_oids = { + "cps" : "1.3.6.1.5.5.7.2.1", + "unotice" : "1.3.6.1.5.5.7.2.2" + } + +certPkixKp_oids = { + "serverAuth" : "1.3.6.1.5.5.7.3.1", + "clientAuth" : "1.3.6.1.5.5.7.3.2", + "codeSigning" : "1.3.6.1.5.5.7.3.3", + "emailProtection" : "1.3.6.1.5.5.7.3.4", + "ipsecEndSystem" : "1.3.6.1.5.5.7.3.5", + "ipsecTunnel" : "1.3.6.1.5.5.7.3.6", + "ipsecUser" : "1.3.6.1.5.5.7.3.7", + "timeStamping" : "1.3.6.1.5.5.7.3.8", + "ocspSigning" : "1.3.6.1.5.5.7.3.9", + "dvcs" : "1.3.6.1.5.5.7.3.10", + "secureShellClient" : "1.3.6.1.5.5.7.3.21", + "secureShellServer" : "1.3.6.1.5.5.7.3.22" + } + +certPkixAd_oids = { + "ocsp" : "1.3.6.1.5.5.7.48.1", + "caIssuers" : "1.3.6.1.5.5.7.48.2", + "timestamping" : "1.3.6.1.5.5.7.48.3", + "id-ad-dvcs" : "1.3.6.1.5.5.7.48.4", + "id-ad-caRepository" : "1.3.6.1.5.5.7.48.5", + "id-pkix-ocsp-archive-cutoff" : "1.3.6.1.5.5.7.48.6", + "id-pkix-ocsp-service-locator" : "1.3.6.1.5.5.7.48.7", + "id-ad-cmc" : "1.3.6.1.5.5.7.48.12" + } + +####### ansi-x962 ####### + +x962KeyType_oids = { + "prime-field" : "1.2.840.10045.1.1", + "characteristic-two-field" : "1.2.840.10045.1.2", + "ecPublicKey" : "1.2.840.10045.2.1", + } + +x962Signature_oids = { + "ecdsa-with-SHA1" : "1.2.840.10045.4.1", + "ecdsa-with-Recommended" : "1.2.840.10045.4.2", + "ecdsa-with-SHA224" : "1.2.840.10045.4.3.1", + "ecdsa-with-SHA256" : "1.2.840.10045.4.3.2", + "ecdsa-with-SHA384" : "1.2.840.10045.4.3.3", + "ecdsa-with-SHA512" : "1.2.840.10045.4.3.4" + } + +####### elliptic curves ####### + +certicomCurve_oids = { + "ansit163k1" : "1.3.132.0.1", + "ansit163r1" : "1.3.132.0.2", + "ansit239k1" : "1.3.132.0.3", + "sect113r1" : "1.3.132.0.4", + "sect113r2" : "1.3.132.0.5", + "secp112r1" : "1.3.132.0.6", + "secp112r2" : "1.3.132.0.7", + "ansip160r1" : "1.3.132.0.8", + "ansip160k1" : "1.3.132.0.9", + "ansip256k1" : "1.3.132.0.10", + "ansit163r2" : "1.3.132.0.15", + "ansit283k1" : "1.3.132.0.16", + "ansit283r1" : "1.3.132.0.17", + "sect131r1" : "1.3.132.0.22", + "ansit193r1" : "1.3.132.0.24", + "ansit193r2" : "1.3.132.0.25", + "ansit233k1" : "1.3.132.0.26", + "ansit233r1" : "1.3.132.0.27", + "secp128r1" : "1.3.132.0.28", + "secp128r2" : "1.3.132.0.29", + "ansip160r2" : "1.3.132.0.30", + "ansip192k1" : "1.3.132.0.31", + "ansip224k1" : "1.3.132.0.32", + "ansip224r1" : "1.3.132.0.33", + "ansip384r1" : "1.3.132.0.34", + "ansip521r1" : "1.3.132.0.35", + "ansit409k1" : "1.3.132.0.36", + "ansit409r1" : "1.3.132.0.37", + "ansit571k1" : "1.3.132.0.38", + "ansit571r1" : "1.3.132.0.39" + } + +####### policies ####### + +certPolicy_oids = { + "anyPolicy" : "2.5.29.32.0" + } + +# from Chromium source code (ev_root_ca_metadata.cc) +evPolicy_oids = { + "EV AC Camerfirma S.A. Chambers of Commerce Root - 2008" : "1.3.6.1.4.1.17326.10.14.2.1.2", + "EV AC Camerfirma S.A. Chambers of Commerce Root - 2008" : "1.3.6.1.4.1.17326.10.14.2.2.2", + "EV AC Camerfirma S.A. Global Chambersign Root - 2008" : "1.3.6.1.4.1.17326.10.8.12.1.2", + "EV AC Camerfirma S.A. Global Chambersign Root - 2008" : "1.3.6.1.4.1.17326.10.8.12.2.2", + "EV AddTrust/Comodo/USERTrust" : "1.3.6.1.4.1.6449.1.2.1.5.1", + "EV AddTrust External CA Root" : "1.3.6.1.4.1.782.1.2.1.8.1", + "EV Actualis Authentication Root CA" : "1.3.159.1.17.1", + "EV AffirmTrust Commercial" : "1.3.6.1.4.1.34697.2.1", + "EV AffirmTrust Networking" : "1.3.6.1.4.1.34697.2.2", + "EV AffirmTrust Premium" : "1.3.6.1.4.1.34697.2.3", + "EV AffirmTrust Premium ECC" : "1.3.6.1.4.1.34697.2.4", + "EV Autoridad de Certificacion Firmaprofesional CIF A62634068" : "1.3.6.1.4.1.13177.10.1.3.10", + "EV Baltimore CyberTrust Root" : "1.3.6.1.4.1.6334.1.100.1", + "EV Buypass Class 3" : "2.16.578.1.26.1.3.3", + "EV Certificate Authority of WoSign" : "1.3.6.1.4.1.36305.2", + "EV CertPlus Class 2 Primary CA (KEYNECTIS)" : "1.3.6.1.4.1.22234.2.5.2.3.1", + "EV Certum Trusted Network CA" : "1.2.616.1.113527.2.5.1.1", + "EV China Internet Network Information Center EV Certificates Root" : "1.3.6.1.4.1.29836.1.10", + "EV Cybertrust Global Root" : "1.3.6.1.4.1.6334.1.100.1", + "EV DigiCert High Assurance EV Root CA" : "2.16.840.1.114412.2.1", + "EV D-TRUST Root Class 3 CA 2 EV 2009" : "1.3.6.1.4.1.4788.2.202.1", + "EV Entrust Certification Authority" : "2.16.840.1.114028.10.1.2", + "EV Equifax Secure Certificate Authority (GeoTrust)" : "1.3.6.1.4.1.14370.1.6", + "EV E-Tugra Certification Authority" : "2.16.792.3.0.4.1.1.4", + "EV GeoTrust Primary Certification Authority" : "1.3.6.1.4.1.14370.1.6", + "EV GlobalSign Root CAs" : "1.3.6.1.4.1.4146.1.1", + "EV Go Daddy Certification Authority" : "2.16.840.1.114413.1.7.23.3", + "EV Izenpe.com roots Business" : "1.3.6.1.4.1.14777.6.1.1", + "EV Izenpe.com roots Government" : "1.3.6.1.4.1.14777.6.1.2", + "EV Network Solutions Certificate Authority" : "1.3.6.1.4.1.781.1.2.1.8.1", + "EV QuoVadis Roots" : "1.3.6.1.4.1.8024.0.2.100.1.2", + "EV SecureTrust Corporation Roots" : "2.16.840.1.114404.1.1.2.4.1", + "EV Security Communication RootCA1" : "1.2.392.200091.100.721.1", + "EV Staat der Nederlanden EV Root CA" : "2.16.528.1.1003.1.2.7", + "EV StartCom Certification Authority" : "1.3.6.1.4.1.23223.1.1.1", + "EV Starfield Certificate Authority" : "2.16.840.1.114414.1.7.23.3", + "EV Starfield Service Certificate Authority" : "2.16.840.1.114414.1.7.24.3", + "EV SwissSign Gold CA - G2" : "2.16.756.1.89.1.2.1.1", + "EV Swisscom Root EV CA 2" : "2.16.756.1.83.21.0", + "EV thawte CAs" : "2.16.840.1.113733.1.7.48.1", + "EV TWCA Roots" : "1.3.6.1.4.1.40869.1.1.22.3", + "EV T-Telessec GlobalRoot Class 3" : "1.3.6.1.4.1.7879.13.24.1", + "EV USERTrust Certification Authorities" : "1.3.6.1.4.1.6449.1.2.1.5.1", + "EV ValiCert Class 2 Policy Validation Authority" : "2.16.840.1.114413.1.7.23.3", + "EV VeriSign Certification Authorities" : "2.16.840.1.113733.1.7.23.6", + "EV Wells Fargo WellsSecure Public Root Certification Authority" : "2.16.840.1.114171.500.9", + "EV XRamp Global Certification Authority" : "2.16.840.1.114404.1.1.2.4.1", + "jurisdictionOfIncorporationLocalityName" : "1.3.6.1.4.1.311.60.2.1.1", + "jurisdictionOfIncorporationStateOrProvinceName" : "1.3.6.1.4.1.311.60.2.1.2", + "jurisdictionOfIncorporationCountryName" : "1.3.6.1.4.1.311.60.2.1.3" + } + + +x509_oids_sets = [ + pkcs1_oids, + pkcs9_oids, + attributeType_oids, + certificateExtension_oids, + certExt_oids, + certPkixPe_oids, + certPkixQt_oids, + certPkixKp_oids, + certPkixAd_oids, + certPolicy_oids, + evPolicy_oids, + x962KeyType_oids, + x962Signature_oids, + certicomCurve_oids + ] + +x509_oids = {} + +for oids_set in x509_oids_sets: + x509_oids.update(oids_set) + +conf.mib = MIBDict(_name="MIB", **x509_oids) diff --git a/scapy/asn1fields.py b/scapy/asn1fields.py index 1a59bd50d757db44e254a9ff7c8d3b74d5b62aff..0994e4a9afcd870cbf1856e31d980ac72f5e5294 100644 --- a/scapy/asn1fields.py +++ b/scapy/asn1fields.py @@ -1,6 +1,7 @@ ## This file is part of Scapy ## See http://www.secdev.org/projects/scapy for more informations ## Copyright (C) Philippe Biondi <phil@secdev.org> +## Enhanced by Maxence Tury <maxence.tury@ssi.gouv.fr> ## This program is published under a GPLv2 license """ @@ -9,51 +10,48 @@ Classes that implement ASN.1 data structures. from asn1.asn1 import * from asn1.ber import * +from asn1.mib import * from volatile import * from base_classes import BasePacket +from utils import binrepr - -##################### -#### ASN1 Fields #### -##################### +FLEXIBLE_TAGS = False class ASN1F_badsequence(Exception): pass -class ASN1F_element: +class ASN1F_element(object): pass -class ASN1F_optionnal(ASN1F_element): - def __init__(self, field): - self._field=field - def __getattr__(self, attr): - return getattr(self._field,attr) - def dissect(self,pkt,s): - try: - return self._field.dissect(pkt,s) - except ASN1F_badsequence: - self._field.set_val(pkt,None) - return s - except BER_Decoding_Error: - self._field.set_val(pkt,None) - return s - def build(self, pkt): - if self._field.is_empty(pkt): - return "" - return self._field.build(pkt) -class ASN1F_field(ASN1F_element): - holds_packets=0 - islist=0 +########################## +#### Basic ASN1 Field #### +########################## +class ASN1F_field(ASN1F_element): + holds_packets = 0 + islist = 0 ASN1_tag = ASN1_Class_UNIVERSAL.ANY - context=ASN1_Class_UNIVERSAL + context = ASN1_Class_UNIVERSAL - def __init__(self, name, default, context=None): - if context is not None: - self.context = context + def __init__(self, name, default, context=None, + implicit_tag=None, explicit_tag=None): + self.context = context self.name = name - self.default = default + if default is None: + self.default = None + elif type(default) is ASN1_NULL: + self.default = default + else: + self.default = self.ASN1_tag.asn1_object(default) + self.flexible_tag = False or FLEXIBLE_TAGS + if (implicit_tag is not None) and (explicit_tag is not None): + err_msg = "field cannot be both implicitly and explicitly tagged" + raise ASN1_Error(err_msg) + self.implicit_tag = implicit_tag + self.explicit_tag = explicit_tag + # network_tag gets useful for ASN1F_CHOICE + self.network_tag = implicit_tag or explicit_tag or self.ASN1_tag def i2repr(self, pkt, x): return repr(x) @@ -61,20 +59,65 @@ class ASN1F_field(ASN1F_element): return x def any2i(self, pkt, x): return x - def m2i(self, pkt, x): - return self.ASN1_tag.get_codec(pkt.ASN1_codec).safedec(x, context=self.context) + def m2i(self, pkt, s): + """ + The good thing about safedec is that it may still decode ASN1 + even if there is a mismatch between the expected tag (self.ASN1_tag) + and the actual tag; the decoded ASN1 object will simply be put + into an ASN1_BADTAG object. However, safedec prevents the raising of + exceptions needed for ASN1F_optional processing. + Thus we use 'flexible_tag', which should be False with ASN1F_optional. + + Regarding other fields, we might need to know whether encoding went + as expected or not. Noticeably, input methods from cert.py expect + certain exceptions to be raised. Hence default flexible_tag is False, + but we provide a FLEXIBLE_TAGS switch for debugging purposes. + """ + s = BER_tagging_dec(s, hidden_tag=self.ASN1_tag, + implicit_tag=self.implicit_tag, + explicit_tag=self.explicit_tag, + safe=self.flexible_tag) + codec = self.ASN1_tag.get_codec(pkt.ASN1_codec) + if self.flexible_tag: + return codec.safedec(s, context=self.context) + else: + return codec.dec(s, context=self.context) def i2m(self, pkt, x): if x is None: - x = 0 + return "" if isinstance(x, ASN1_Object): if ( self.ASN1_tag == ASN1_Class_UNIVERSAL.ANY or x.tag == ASN1_Class_UNIVERSAL.RAW or x.tag == ASN1_Class_UNIVERSAL.ERROR or self.ASN1_tag == x.tag ): - return x.enc(pkt.ASN1_codec) + s = x.enc(pkt.ASN1_codec) else: raise ASN1_Error("Encoding Error: got %r instead of an %r for field [%s]" % (x, self.ASN1_tag, self.name)) - return self.ASN1_tag.get_codec(pkt.ASN1_codec).enc(x) + else: + s = self.ASN1_tag.get_codec(pkt.ASN1_codec).enc(x) + return BER_tagging_enc(s, implicit_tag=self.implicit_tag, + explicit_tag=self.explicit_tag) + def extract_packet(self, cls, s): + if len(s) > 0: + try: + c = cls(s) + except ASN1F_badsequence: + c = packet.Raw(s) + cpad = c.getlayer(packet.Raw) + s = "" + if cpad is not None: + s = cpad.load + del(cpad.underlayer.payload) + return c,s + else: + return None,s + + def build(self, pkt): + return self.i2m(pkt, getattr(pkt, self.name)) + def dissect(self, pkt, s): + v,s = self.m2i(pkt, s) + self.set_val(pkt, v) + return s def do_copy(self, x): if hasattr(x, "copy"): @@ -85,54 +128,41 @@ class ASN1F_field(ASN1F_element): if isinstance(x[i], BasePacket): x[i] = x[i].copy() return x - - def build(self, pkt): - return self.i2m(pkt, getattr(pkt, self.name)) - def set_val(self, pkt, val): setattr(pkt, self.name, val) def is_empty(self, pkt): - return getattr(pkt,self.name) is None - - def dissect(self, pkt, s): - v,s = self.m2i(pkt, s) - self.set_val(pkt, v) - return s - + return getattr(pkt, self.name) is None def get_fields_list(self): return [self] - + def __hash__(self): return hash(self.name) def __str__(self): - return self.name - def __eq__(self, other): - return self.name == other - def __repr__(self): - return self.name + return repr(self) def randval(self): return RandInt() -class ASN1F_INTEGER(ASN1F_field): - ASN1_tag= ASN1_Class_UNIVERSAL.INTEGER - def randval(self): - return RandNum(-2**64, 2**64-1) +############################ +#### Simple ASN1 Fields #### +############################ class ASN1F_BOOLEAN(ASN1F_field): - ASN1_tag= ASN1_Class_UNIVERSAL.BOOLEAN + ASN1_tag = ASN1_Class_UNIVERSAL.BOOLEAN def randval(self): - return RandChoice(True,False) + return RandChoice(True, False) -class ASN1F_NULL(ASN1F_INTEGER): - ASN1_tag= ASN1_Class_UNIVERSAL.NULL - -class ASN1F_SEP(ASN1F_NULL): - ASN1_tag= ASN1_Class_UNIVERSAL.SEP +class ASN1F_INTEGER(ASN1F_field): + ASN1_tag = ASN1_Class_UNIVERSAL.INTEGER + def randval(self): + return RandNum(-2**64, 2**64-1) class ASN1F_enum_INTEGER(ASN1F_INTEGER): - def __init__(self, name, default, enum): - ASN1F_INTEGER.__init__(self, name, default) + def __init__(self, name, default, enum, context=None, + implicit_tag=None, explicit_tag=None): + ASN1F_INTEGER.__init__(self, name, default, context=context, + implicit_tag=implicit_tag, + explicit_tag=explicit_tag) i2s = self.i2s = {} s2i = self.s2i = {} if type(enum) is list: @@ -148,62 +178,96 @@ class ASN1F_enum_INTEGER(ASN1F_INTEGER): if type(x) is str: x = self.s2i[x] return x - def i2repr_one(self, pkt, x): - return self.i2s.get(x, repr(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) + 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 i2repr(self, pkt, x): if type(x) is list: - return map(lambda z,pkt=pkt:self.i2repr_one(pkt,z), x) + return map(lambda z,pkt=pkt:self.i2repr_one(pkt, z), x) else: - return self.i2repr_one(pkt,x) - -class ASN1F_ENUMERATED(ASN1F_enum_INTEGER): - ASN1_tag = ASN1_Class_UNIVERSAL.ENUMERATED + return self.i2repr_one(pkt, x) +class ASN1F_BIT_STRING(ASN1F_field): + ASN1_tag = ASN1_Class_UNIVERSAL.BIT_STRING + def __init__(self, name, default, default_readable=True, context=None, + implicit_tag=None, explicit_tag=None): + if default is not None and default_readable: + default = "".join(binrepr(ord(x)).zfill(8) for x in default) + ASN1F_field.__init__(self, name, default, context=context, + implicit_tag=implicit_tag, + explicit_tag=explicit_tag) + def randval(self): + return RandString(RandNum(0, 1000)) + class ASN1F_STRING(ASN1F_field): ASN1_tag = ASN1_Class_UNIVERSAL.STRING def randval(self): return RandString(RandNum(0, 1000)) +class ASN1F_NULL(ASN1F_INTEGER): + ASN1_tag = ASN1_Class_UNIVERSAL.NULL + +class ASN1F_OID(ASN1F_field): + ASN1_tag = ASN1_Class_UNIVERSAL.OID + def randval(self): + return RandOID() + +class ASN1F_ENUMERATED(ASN1F_enum_INTEGER): + ASN1_tag = ASN1_Class_UNIVERSAL.ENUMERATED + +class ASN1F_UTF8_STRING(ASN1F_STRING): + ASN1_tag = ASN1_Class_UNIVERSAL.UTF8_STRING + class ASN1F_PRINTABLE_STRING(ASN1F_STRING): ASN1_tag = ASN1_Class_UNIVERSAL.PRINTABLE_STRING -class ASN1F_BIT_STRING(ASN1F_STRING): - ASN1_tag = ASN1_Class_UNIVERSAL.BIT_STRING - -class ASN1F_IPADDRESS(ASN1F_STRING): - ASN1_tag = ASN1_Class_UNIVERSAL.IPADDRESS - -class ASN1F_TIME_TICKS(ASN1F_INTEGER): - ASN1_tag = ASN1_Class_UNIVERSAL.TIME_TICKS +class ASN1F_T61_STRING(ASN1F_STRING): + ASN1_tag = ASN1_Class_UNIVERSAL.T61_STRING +class ASN1F_IA5_STRING(ASN1F_STRING): + ASN1_tag = ASN1_Class_UNIVERSAL.IA5_STRING + class ASN1F_UTC_TIME(ASN1F_STRING): ASN1_tag = ASN1_Class_UNIVERSAL.UTC_TIME class ASN1F_GENERALIZED_TIME(ASN1F_STRING): ASN1_tag = ASN1_Class_UNIVERSAL.GENERALIZED_TIME -class ASN1F_OID(ASN1F_field): - ASN1_tag = ASN1_Class_UNIVERSAL.OID - def randval(self): - return RandOID() +class ASN1F_ISO646_STRING(ASN1F_STRING): + ASN1_tag = ASN1_Class_UNIVERSAL.ISO646_STRING +class ASN1F_UNIVERSAL_STRING(ASN1F_STRING): + ASN1_tag = ASN1_Class_UNIVERSAL.UNIVERSAL_STRING + +class ASN1F_BMP_STRING(ASN1F_STRING): + ASN1_tag = ASN1_Class_UNIVERSAL.BMP_STRING + class ASN1F_SEQUENCE(ASN1F_field): ASN1_tag = ASN1_Class_UNIVERSAL.SEQUENCE - def __init__(self, *seq, **kargs): - if "ASN1_tag" in kargs: - self.ASN1_tag = kargs["ASN1_tag"] + holds_packets = 1 + def __init__(self, *seq, **kwargs): + name = "dummy_seq_name" + default = [field.default for field in seq] + for kwarg in ["context", "implicit_tag", "explicit_tag"]: + if kwarg in kwargs: + setattr(self, kwarg, kwargs[kwarg]) + else: + setattr(self, kwarg, None) + ASN1F_field.__init__(self, name, default, context=self.context, + implicit_tag=self.implicit_tag, + explicit_tag=self.explicit_tag) self.seq = seq + self.islist = len(seq) > 1 def __repr__(self): - return "<%s%r>" % (self.__class__.__name__,self.seq,) - def set_val(self, pkt, val): - for f in self.seq: - f.set_val(pkt,val) + return "<%s%r>" % (self.__class__.__name__, self.seq) def is_empty(self, pkt): for f in self.seq: if not f.is_empty(pkt): @@ -211,120 +275,280 @@ class ASN1F_SEQUENCE(ASN1F_field): return True def get_fields_list(self): return reduce(lambda x,y: x+y.get_fields_list(), self.seq, []) + def m2i(self, pkt, s): + """ + ASN1F_SEQUENCE behaves transparently, with nested ASN1_objects being + dissected one by one. Because we use obj.dissect (see loop below) + instead of obj.m2i (as we trust dissect to do the appropriate set_vals) + we do not directly retrieve the list of nested objects. + Thus m2i returns an empty list (along with the proper remainder). + It is discarded by dissect() and should not be missed elsewhere. + """ + s = BER_tagging_dec(s, hidden_tag=self.ASN1_tag, + implicit_tag=self.implicit_tag, + explicit_tag=self.explicit_tag, + safe=self.flexible_tag) + codec = self.ASN1_tag.get_codec(pkt.ASN1_codec) + i,s,remain = codec.check_type_check_len(s) + if len(s) == 0: + for obj in self.seq: + obj.set_val(pkt, None) + else: + for obj in self.seq: + try: + s = obj.dissect(pkt, s) + except ASN1F_badsequence,e: + break + if len(s) > 0: + raise BER_Decoding_Error("unexpected remainder", remaining=s) + return [], remain + def dissect(self, pkt, s): + _,x = self.m2i(pkt, s) + return x def build(self, pkt): s = reduce(lambda x,y: x+y.build(pkt), self.seq, "") return self.i2m(pkt, s) - def dissect(self, pkt, s): - codec = self.ASN1_tag.get_codec(pkt.ASN1_codec) - try: - i,s,remain = codec.check_type_check_len(s) - for obj in self.seq: - s = obj.dissect(pkt,s) - if s: - warning("Too many bytes to decode sequence: [%r]" % s) # XXX not reversible! - return remain - except ASN1_Error,e: - raise ASN1F_badsequence(e) class ASN1F_SET(ASN1F_SEQUENCE): ASN1_tag = ASN1_Class_UNIVERSAL.SET -class ASN1F_SEQUENCE_OF(ASN1F_SEQUENCE): +class ASN1F_SEQUENCE_OF(ASN1F_field): + ASN1_tag = ASN1_Class_UNIVERSAL.SEQUENCE holds_packets = 1 islist = 1 - def __init__(self, name, default, asn1pkt, ASN1_tag=0x30): - self.asn1pkt = asn1pkt - self.tag = chr(ASN1_tag) - self.name = name + def __init__(self, name, default, cls, context=None, + implicit_tag=None, explicit_tag=None): + self.cls = cls + ASN1F_field.__init__(self, name, None, context=context, + implicit_tag=implicit_tag, explicit_tag=explicit_tag) self.default = default - def i2repr(self, pkt, i): - if i is None: - return [] - return i - def get_fields_list(self): - return [self] - def set_val(self, pkt, val): - ASN1F_field.set_val(self, pkt, val) def is_empty(self, pkt): return ASN1F_field.is_empty(self, pkt) + def m2i(self, pkt, s): + s = BER_tagging_dec(s, hidden_tag=self.ASN1_tag, + implicit_tag=self.implicit_tag, + explicit_tag=self.explicit_tag, + safe=self.flexible_tag) + codec = self.ASN1_tag.get_codec(pkt.ASN1_codec) + i,s,remain = codec.check_type_check_len(s) + lst = [] + while s: + c,s = self.extract_packet(self.cls, s) + lst.append(c) + if len(s) > 0: + raise BER_Decoding_Error("unexpected remainder", remaining=s) + return lst, remain def build(self, pkt): val = getattr(pkt, self.name) - if isinstance(val, ASN1_Object) and val.tag == ASN1_Class_UNIVERSAL.RAW: + if isinstance(val, ASN1_Object) and val.tag==ASN1_Class_UNIVERSAL.RAW: s = val elif val is None: s = "" else: - s = "".join(map(str, val )) + s = "".join(map(str, val)) return self.i2m(pkt, s) - def dissect(self, pkt, s): - codec = self.ASN1_tag.get_codec(pkt.ASN1_codec) - i,s1,remain = codec.check_type_check_len(s) - lst = [] - while s1: - try: - p = self.asn1pkt(s1) - except ASN1F_badsequence,e: - lst.append(conf.raw_layer(s1)) - break - lst.append(p) - if conf.raw_layer in p: - s1 = p[conf.raw_layer].load - del(p[conf.raw_layer].underlayer.payload) - else: - break - self.set_val(pkt, lst) - return remain + def randval(self): return fuzz(self.asn1pkt()) def __repr__(self): - return "<%s %s>" % (self.__class__.__name__,self.name) + return "<%s %s>" % (self.__class__.__name__, self.name) + +class ASN1F_SET_OF(ASN1F_SEQUENCE_OF): + ASN1_tag = ASN1_Class_UNIVERSAL.SET + +class ASN1F_IPADDRESS(ASN1F_STRING): + ASN1_tag = ASN1_Class_UNIVERSAL.IPADDRESS + +class ASN1F_TIME_TICKS(ASN1F_INTEGER): + ASN1_tag = ASN1_Class_UNIVERSAL.TIME_TICKS + + +############################# +#### Complex ASN1 Fields #### +############################# + +class ASN1F_optional(ASN1F_element): + def __init__(self, field, by_default=False): + field.flexible_tag = False + self._field = field + def __getattr__(self, attr): + return getattr(self._field, attr) + def m2i(self, pkt, s): + try: + return self._field.m2i(pkt, s) + except (ASN1_Error, ASN1F_badsequence, BER_Decoding_Error): + # ASN1_Error may be raised by ASN1F_CHOICE + return None, s + def dissect(self, pkt, s): + try: + return self._field.dissect(pkt, s) + except (ASN1_Error, ASN1F_badsequence, BER_Decoding_Error): + self._field.set_val(pkt, None) + return s + def build(self, pkt): + if self._field.is_empty(pkt): + return "" + return self._field.build(pkt) + def any2i(self, pkt, x): + return self._field.any2i(pkt, x) + def i2repr(self, pkt, x): + return self._field.i2repr(pkt, x) + +class ASN1F_CHOICE(ASN1F_field): + """ + Multiple types are allowed: ASN1_Packet, ASN1F_field and ASN1F_PACKET(), + See layers/x509.py for examples. + Other ASN1F_field instances than ASN1F_PACKET instances must not be used. + """ + holds_packets = 1 + ASN1_tag = ASN1_Class_UNIVERSAL.ANY + def __init__(self, name, default, *args, **kwargs): + if "implicit_tag" in kwargs: + err_msg = "ASN1F_CHOICE has been called with an implicit_tag" + raise ASN1_Error(err_msg) + self.implicit_tag = None + for kwarg in ["context", "explicit_tag"]: + if kwarg in kwargs: + setattr(self, kwarg, kwargs[kwarg]) + else: + setattr(self, kwarg, None) + ASN1F_field.__init__(self, name, None, context=self.context, + explicit_tag=self.explicit_tag) + self.default = default + self.current_choice = None + self.choices = {} + self.pktchoices = {} + for p in args: + if hasattr(p, "ASN1_root"): # should be ASN1_Packet + if hasattr(p.ASN1_root, "choices"): + for k,v in p.ASN1_root.choices.iteritems(): + self.choices[k] = v # ASN1F_CHOICE recursion + else: + self.choices[p.ASN1_root.network_tag] = p + elif hasattr(p, "ASN1_tag"): + if type(p) is type: # should be ASN1F_field class + self.choices[p.ASN1_tag] = p + else: # should be ASN1F_PACKET instance + self.choices[p.network_tag] = p + self.pktchoices[hash(p.cls)] = (p.implicit_tag, p.explicit_tag) + else: + raise ASN1_Error("ASN1F_CHOICE: no tag found for one field") + def m2i(self, pkt, s): + """ + First we have to retrieve the appropriate choice. + Then we extract the field/packet, according to this choice. + """ + if len(s) == 0: + raise ASN1_Error("ASN1F_CHOICE: got empty string") + s = BER_tagging_dec(s, hidden_tag=self.ASN1_tag, + explicit_tag=self.explicit_tag, + safe=self.flexible_tag) + tag,_ = BER_id_dec(s) + if tag not in self.choices: + if self.flexible_tag: + choice = ASN1F_field + else: + raise ASN1_Error("ASN1F_CHOICE: unexpected field") + else: + choice = self.choices[tag] + if hasattr(choice, "ASN1_root"): + return self.extract_packet(choice, 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) + 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) + return BER_tagging_enc(s, explicit_tag=self.explicit_tag) + def randval(self): + return RandChoice(*map(lambda x:fuzz(x()), self.choice.values())) class ASN1F_PACKET(ASN1F_field): holds_packets = 1 - def __init__(self, name, default, cls): - ASN1F_field.__init__(self, name, default) + def __init__(self, name, default, cls, context=None, + implicit_tag=None, explicit_tag=None): self.cls = cls + ASN1F_field.__init__(self, name, None, context=context, + implicit_tag=implicit_tag, explicit_tag=explicit_tag) + if cls.ASN1_root.ASN1_tag == ASN1_Class_UNIVERSAL.SEQUENCE: + if implicit_tag is None and explicit_tag is None: + self.network_tag = 16|0x20 + self.default = default + def m2i(self, pkt, s): + s = BER_tagging_dec(s, hidden_tag=self.cls.ASN1_root.ASN1_tag, + implicit_tag=self.implicit_tag, + explicit_tag=self.explicit_tag, + safe=self.flexible_tag) + p,s = self.extract_packet(self.cls, s) + return p,s def i2m(self, pkt, x): if x is None: - x = "" - return str(x) - def extract_packet(self, cls, x): - try: - c = cls(x) - except ASN1F_badsequence: - c = conf.raw_layer(x) - cpad = c.getlayer(conf.padding_layer) - x = "" - if cpad is not None: - x = cpad.load - del(cpad.underlayer.payload) - return c,x - def m2i(self, pkt, x): - return self.extract_packet(self.cls, x) - - -class ASN1F_CHOICE(ASN1F_PACKET): - ASN1_tag = ASN1_Class_UNIVERSAL.NONE - def __init__(self, name, default, *args): - self.name=name - self.choice = {} - for p in args: - self.choice[p.ASN1_root.ASN1_tag] = p -# self.context=context - self.default=default - def m2i(self, pkt, x): - if len(x) == 0: - return conf.raw_layer(),"" - raise ASN1_Error("ASN1F_CHOICE: got empty string") - if ord(x[0]) not in self.choice: - return conf.raw_layer(x),"" # XXX return RawASN1 packet ? Raise error - raise ASN1_Error("Decoding Error: choice [%i] not found in %r" % (ord(x[0]), self.choice.keys())) + s = "" + else: + s = str(x) + return BER_tagging_enc(s, implicit_tag=self.implicit_tag, + explicit_tag=self.explicit_tag) + +class ASN1F_BIT_STRING_ENCAPS(ASN1F_BIT_STRING): + """ + We may emulate simple string encapsulation with explicit_tag=0x04, + but we need a specific class for bit strings because of unused bits, etc. + """ + holds_packets = 1 + def __init__(self, name, default, cls, context=None, + implicit_tag=None, explicit_tag=None): + self.cls = cls + ASN1F_BIT_STRING.__init__(self, name, None, context=context, + implicit_tag=implicit_tag, + explicit_tag=explicit_tag) + self.default = default + def m2i(self, pkt, s): + bit_string, remain = ASN1F_BIT_STRING.m2i(self, pkt, s) + if len(bit_string.val) % 8 != 0: + raise BER_Decoding_Error("wrong bit string", remaining=s) + p,s = self.extract_packet(self.cls, bit_string.val_readable) + if len(s) > 0: + raise BER_Decoding_Error("unexpected remainder", remaining=s) + return p, remain + def i2m(self, pkt, x): + if x is None: + s = "" + else: + s = str(x) + s = "".join(binrepr(ord(x)).zfill(8) for x in s) + return ASN1F_BIT_STRING.i2m(self, pkt, s) + +class ASN1F_FLAGS(ASN1F_BIT_STRING): + def __init__(self, name, default, mapping, context=None, + implicit_tag=None, explicit_tag=None): + self.mapping = mapping + ASN1F_BIT_STRING.__init__(self, name, default, + default_readable=False, + context=context, + implicit_tag=implicit_tag, + explicit_tag=explicit_tag) + def get_flags(self, pkt): + fbytes = getattr(pkt, self.name).val + flags = [] + for i, positional in enumerate(fbytes): + if positional == '1' and i < len(self.mapping): + flags.append(self.mapping[i]) + return flags + def i2repr(self, pkt, x): + if x is not None: + pretty_s = ", ".join(self.get_flags(pkt)) + return pretty_s + " " + repr(x) + return repr(x) - z = ASN1F_PACKET.extract_packet(self, self.choice[ord(x[0])], x) - return z - def randval(self): - return RandChoice(*map(lambda x:fuzz(x()), self.choice.values())) - - -# This import must come in last to avoid problems with cyclic dependencies + +# This import must come last to avoid problems with cyclic dependencies import packet diff --git a/scapy/contrib/HomePlugAV.py b/scapy/contrib/HomePlugAV.py index a3fb670c882bface713f954692b60e1b24e3acb8..1717f442ab53f1ed6141b35285ba666f901995d5 100644 --- a/scapy/contrib/HomePlugAV.py +++ b/scapy/contrib/HomePlugAV.py @@ -451,7 +451,6 @@ class ReadModuleDataConfirmation(Packet): ] def post_build(self, p, pay): - import binascii if self.DataLen is None: _len = len(self.ModuleData) p = p[:6] + struct.pack('h', _len) + p[8:] @@ -475,7 +474,6 @@ class WriteModuleDataRequest(Packet): ] def post_build(self, p, pay): - import binascii if self.DataLen is None: _len = len(self.ModuleData) p = p[:2] + struct.pack('h', _len) + p[4:] diff --git a/scapy/contrib/openflow.py b/scapy/contrib/openflow.py index beab1f13158b812e9e43897728c99703c03679b4..3e5fcf73281471fa8dde592b43091e5342285129 100755 --- a/scapy/contrib/openflow.py +++ b/scapy/contrib/openflow.py @@ -11,9 +11,9 @@ # scapy.contrib.description = openflow v1.0 # scapy.contrib.status = loads -import binascii import struct from scapy.all import * +from scapy.utils import binrepr ### If prereq_autocomplete is True then match prerequisites will be ### automatically handled. See OFPMatch class. @@ -129,58 +129,58 @@ class OFPMatch(Packet): ### with post_build we create the wildcards field bit by bit def post_build(self, p, pay): # first 10 bits of an ofp_match are always set to 0 - l = ["0"*10] + l = "0"*10 # when one field has not been declared, it is assumed to be wildcarded if self.wildcards1 is None: - if self.nw_tos is None: l.append("1") - else: l.append("0") - if self.dl_vlan_pcp is None: l.append("1") - else: l.append("0") + if self.nw_tos is None: l+="1" + else: l+="0" + if self.dl_vlan_pcp is None: l+="1" + else: l+="0" else: - w1 = bin(self.wildcards1)[2:] - l.append("0"*(2-len(w1))) - l.append(w1) + w1 = binrepr(self.wildcards1) + l+="0"*(2-len(w1)) + l+=w1 # ip masks use 6 bits each if self.nw_dst_mask is None: - if self.nw_dst is "0": l.append("111111") + if self.nw_dst is "0": l+="111111" # 0x100000 would be ok too (32-bit IP mask) - else: l.append("0"*6) + else: l+="0"*6 else: - m1 = bin(self.nw_dst_mask)[2:] - l.append("0"*(6-len(m1))) - l.append(m1) + m1 = binrepr(self.nw_dst_mask) + l+="0"*(6-len(m1)) + l+=m1 if self.nw_src_mask is None: - if self.nw_src is "0": l.append("111111") - else: l.append("0"*6) + if self.nw_src is "0": l+="111111" + else: l+="0"*6 else: - m2 = bin(self.nw_src_mask)[2:] - l.append("0"*(6-len(m2))) - l.append(m2) + m2 = binrepr(self.nw_src_mask) + l+="0"*(6-len(m2)) + l+=m2 # wildcards2 works the same way as wildcards1 if self.wildcards2 is None: - if self.tp_dst is None: l.append("1") - else: l.append("0") - if self.tp_src is None: l.append("1") - else: l.append("0") - if self.nw_proto is None: l.append("1") - else: l.append("0") - if self.dl_type is None: l.append("1") - else: l.append("0") - if self.dl_dst is None: l.append("1") - else: l.append("0") - if self.dl_src is None: l.append("1") - else: l.append("0") - if self.dl_vlan is None: l.append("1") - else: l.append("0") - if self.in_port is None: l.append("1") - else: l.append("0") + if self.tp_dst is None: l+="1" + else: l+="0" + if self.tp_src is None: l+="1" + else: l+="0" + if self.nw_proto is None: l+="1" + else: l+="0" + if self.dl_type is None: l+="1" + else: l+="0" + if self.dl_dst is None: l+="1" + else: l+="0" + if self.dl_src is None: l+="1" + else: l+="0" + if self.dl_vlan is None: l+="1" + else: l+="0" + if self.in_port is None: l+="1" + else: l+="0" else: - w2 = bin(self.wildcards2)[2:] - l.append("0"*(8-len(w2))) - l.append(w2) + w2 = binrepr(self.wildcards2) + l+="0"*(8-len(w2)) + l+=w2 ### In order to write OFPMatch compliant with the specifications, ### if prereq_autocomplete has been set to True @@ -189,21 +189,15 @@ class OFPMatch(Packet): if self.dl_type is None: if self.nw_src is not "0" or self.nw_dst is not "0" or self.nw_proto is not None or self.nw_tos is not None: p = p[:22] + struct.pack("!H", 0x0800) + p[24:] - l[-5] = "0" + l = l[:-5] + "0" + l[-4:] if self.nw_proto is None: if self.tp_src is not None or self.tp_dst is not None: p = p[:22] + struct.pack("!H", 0x0800) + p[24:] - l[-5] = "0" + l = l[:-5] + "0" + l[-4:] p = p[:25] + struct.pack("!B", 0x06) + p[26:] - l[-6] = "0" - - wild = "".join(l) - pad = "" - i = 0 - while i < 32 and wild[i:i+4] == "0000": - pad += "0" - i += 4 - ins = binascii.unhexlify(pad + "%x" % int(wild, 2)) + l = l[:-6] + "0" + l[-5:] + + ins = "".join(chr(int("".join(x),2)) for x in zip(*[iter(l)]*8)) p = ins + p[4:] return p + pay diff --git a/scapy/layers/x509.py b/scapy/layers/x509.py index 18aaa5e3391d401bdf95150cf1f8305c67f87a85..fa0389a555621e2a51b55f569abcc16093790605 100644 --- a/scapy/layers/x509.py +++ b/scapy/layers/x509.py @@ -1,6 +1,7 @@ ## This file is part of Scapy ## See http://www.secdev.org/projects/scapy for more informations ## Copyright (C) Philippe Biondi <phil@secdev.org> +## Enhanced by Maxence Tury <maxence.tury@ssi.gouv.fr> ## This program is published under a GPLv2 license """ @@ -10,99 +11,969 @@ X.509 certificates. from scapy.asn1packet import * from scapy.asn1fields import * -########## -## X509 ## -########## - -######[ ASN1 class ]###### - -class ASN1_Class_X509(ASN1_Class_UNIVERSAL): - name="X509" - CONT0 = 0xa0 - CONT1 = 0xa1 - CONT2 = 0xa2 - CONT3 = 0xa3 - -class ASN1_X509_CONT0(ASN1_SEQUENCE): - tag = ASN1_Class_X509.CONT0 - -class ASN1_X509_CONT1(ASN1_SEQUENCE): - tag = ASN1_Class_X509.CONT1 - -class ASN1_X509_CONT2(ASN1_SEQUENCE): - tag = ASN1_Class_X509.CONT2 - -class ASN1_X509_CONT3(ASN1_SEQUENCE): - tag = ASN1_Class_X509.CONT3 - -######[ BER codecs ]####### - -class BERcodec_X509_CONT0(BERcodec_SEQUENCE): - tag = ASN1_Class_X509.CONT0 - -class BERcodec_X509_CONT1(BERcodec_SEQUENCE): - tag = ASN1_Class_X509.CONT1 - -class BERcodec_X509_CONT2(BERcodec_SEQUENCE): - tag = ASN1_Class_X509.CONT2 - -class BERcodec_X509_CONT3(BERcodec_SEQUENCE): - tag = ASN1_Class_X509.CONT3 - -######[ ASN1 fields ]###### - -class ASN1F_X509_CONT0(ASN1F_SEQUENCE): - ASN1_tag = ASN1_Class_X509.CONT0 - -class ASN1F_X509_CONT1(ASN1F_SEQUENCE): - ASN1_tag = ASN1_Class_X509.CONT1 - -class ASN1F_X509_CONT2(ASN1F_SEQUENCE): - ASN1_tag = ASN1_Class_X509.CONT2 - -class ASN1F_X509_CONT3(ASN1F_SEQUENCE): - ASN1_tag = ASN1_Class_X509.CONT3 - -######[ X509 packets ]###### - -class X509RDN(ASN1_Packet): - ASN1_codec = ASN1_Codecs.BER - ASN1_root = ASN1F_SET( - ASN1F_SEQUENCE( ASN1F_OID("oid","2.5.4.6"), - ASN1F_PRINTABLE_STRING("value","") - ) - ) - -class X509v3Ext(ASN1_Packet): - ASN1_codec = ASN1_Codecs.BER - ASN1_root = ASN1F_field("val",ASN1_NULL(0)) - - -class X509Cert(ASN1_Packet): - ASN1_codec = ASN1_Codecs.BER - ASN1_root = ASN1F_SEQUENCE( - ASN1F_SEQUENCE( - ASN1F_optionnal(ASN1F_X509_CONT0(ASN1F_INTEGER("version",3))), - ASN1F_INTEGER("sn",1), - ASN1F_SEQUENCE(ASN1F_OID("sign_algo","1.2.840.113549.1.1.5"), - ASN1F_field("sa_value",ASN1_NULL(0))), - ASN1F_SEQUENCE_OF("issuer",[],X509RDN), - ASN1F_SEQUENCE(ASN1F_UTC_TIME("not_before",ZuluTime(-600)), # ten minutes ago - ASN1F_UTC_TIME("not_after",ZuluTime(+86400))), # for 24h - ASN1F_SEQUENCE_OF("subject",[],X509RDN), - ASN1F_SEQUENCE( - ASN1F_SEQUENCE(ASN1F_OID("pubkey_algo","1.2.840.113549.1.1.1"), - ASN1F_field("pk_value",ASN1_NULL(0))), - ASN1F_BIT_STRING("pubkey","") - ), - ASN1F_optionnal(ASN1F_X509_CONT3(ASN1F_SEQUENCE_OF("x509v3ext",[],X509v3Ext))), - - ), - ASN1F_SEQUENCE(ASN1F_OID("sign_algo2","1.2.840.113549.1.1.5"), - ASN1F_field("sa2_value",ASN1_NULL(0))), - ASN1F_BIT_STRING("signature","") - ) +class ASN1P_OID(ASN1_Packet): + ASN1_codec = ASN1_Codecs.BER + ASN1_root = ASN1F_OID("oid", "0") + +class ASN1P_INTEGER(ASN1_Packet): + ASN1_codec = ASN1_Codecs.BER + ASN1_root = ASN1F_INTEGER("number", 0) + + +####################### +##### RSA packets ##### +####################### +##### based on RFC 3447 + +# It could be interesting to use os.urandom and try to generate +# a new modulus each time RSAPublicKey is called with default values. +# (We might have to dig into scapy field initialization mechanisms...) +# NEVER rely on the key below, which is provided only for debugging purposes. +class RSAPublicKey(ASN1_Packet): + ASN1_codec = ASN1_Codecs.BER + ASN1_root = ASN1F_SEQUENCE( + ASN1F_INTEGER("modulus", 10), + ASN1F_INTEGER("publicExponent", 3)) + +class RSAOtherPrimeInfo(ASN1_Packet): + ASN1_codec = ASN1_Codecs.DER + ASN1_root = ASN1F_SEQUENCE( + ASN1F_INTEGER("prime", 0), + ASN1F_INTEGER("exponent", 0), + ASN1F_INTEGER("coefficient", 0)) + +class RSAPrivateKey(ASN1_Packet): + ASN1_codec = ASN1_Codecs.BER + ASN1_root = ASN1F_SEQUENCE( + ASN1F_enum_INTEGER("version", 0, ["two-prime", "multi"]), + ASN1F_INTEGER("modulus", 10), + ASN1F_INTEGER("publicExponent", 3), + ASN1F_INTEGER("privateExponent", 3), + ASN1F_INTEGER("prime1", 2), + ASN1F_INTEGER("prime2", 5), + ASN1F_INTEGER("exponent1", 0), + ASN1F_INTEGER("exponent2", 3), + ASN1F_INTEGER("coefficient", 1), + ASN1F_optional( + ASN1F_SEQUENCE_OF("otherPrimeInfos", None, + RSAOtherPrimeInfo))) + +#################################### +########## ECDSA packets ########### +#################################### +#### based on RFC 3279 & 5480 & 5915 + +class ECFieldID(ASN1_Packet): +# No characteristic-two-field support for now. + ASN1_codec = ASN1_Codecs.BER + ASN1_root = ASN1F_SEQUENCE( + ASN1F_OID("fieldType", "prime-field"), + ASN1F_INTEGER("prime", 0)) + +class ECCurve(ASN1_Packet): + ASN1_codec = ASN1_Codecs.BER + ASN1_root = ASN1F_SEQUENCE( + ASN1F_STRING("a", ""), + ASN1F_STRING("b", ""), + ASN1F_optional( + ASN1F_BIT_STRING("seed", None))) + +class ECSpecifiedDomain(ASN1_Packet): + ASN1_codec = ASN1_Codecs.BER + ASN1_root = ASN1F_SEQUENCE( + ASN1F_enum_INTEGER("version", 1, {1: "ecpVer1"}), + ASN1F_PACKET("fieldID", ECFieldID(), ECFieldID), + ASN1F_PACKET("curve", ECCurve(), ECCurve), + ASN1F_STRING("base", ""), + ASN1F_INTEGER("order", 0), + ASN1F_optional( + ASN1F_INTEGER("cofactor", None))) + +class ECParameters(ASN1_Packet): + ASN1_codec = ASN1_Codecs.BER + ASN1_root = ASN1F_CHOICE("curve", ASN1_OID("ansip384r1"), + ASN1F_OID, # for named curves + ASN1F_NULL, # for implicit curves + ECSpecifiedDomain) + +class ECDSAPublicKey(ASN1_Packet): + ASN1_codec = ASN1_Codecs.BER + ASN1_root = ASN1F_BIT_STRING("ecPoint", "") + +class ECDSAPrivateKey(ASN1_Packet): + ASN1_codec = ASN1_Codecs.BER + ASN1_root = ASN1F_SEQUENCE( + ASN1F_enum_INTEGER("version", 1, {1: "ecPrivkeyVer1"}), + ASN1F_STRING("privateKey", ""), + ASN1F_optional( + ASN1F_PACKET("parameters", None, ECParameters, + explicit_tag=0xa0)), + ASN1F_optional( + ASN1F_PACKET("publicKey", None, + ECDSAPublicKey, + explicit_tag=0xa1))) + +class ECDSASignature(ASN1_Packet): + ASN1_codec = ASN1_Codecs.BER + ASN1_root = ASN1F_SEQUENCE( + ASN1F_INTEGER("r", 0), + ASN1F_INTEGER("s", 0)) + + +###################### +#### X509 packets #### +###################### +#### based on RFC 5280 + + +####### Names ####### + +class ASN1F_X509_DirectoryString(ASN1F_CHOICE): +# we include ASN1 bit strings for rare instances of x500 addresses + def __init__(self, name, default, **kwargs): + ASN1F_CHOICE.__init__(self, name, default, + ASN1F_PRINTABLE_STRING, ASN1F_UTF8_STRING, + ASN1F_IA5_STRING, ASN1F_T61_STRING, + ASN1F_UNIVERSAL_STRING, ASN1F_BIT_STRING, + **kwargs) + +class X509_AttributeValue(ASN1_Packet): + ASN1_codec = ASN1_Codecs.BER + ASN1_root = ASN1F_CHOICE("value", ASN1_PRINTABLE_STRING("FR"), + ASN1F_PRINTABLE_STRING, ASN1F_UTF8_STRING, + ASN1F_IA5_STRING, ASN1F_T61_STRING, + ASN1F_UNIVERSAL_STRING) + +class X509_Attribute(ASN1_Packet): + ASN1_codec = ASN1_Codecs.BER + ASN1_root = ASN1F_SEQUENCE( + ASN1F_OID("type", "2.5.4.6"), + ASN1F_SET_OF("values", + [X509_AttributeValue()], + X509_AttributeValue)) +class X509_AttributeTypeAndValue(ASN1_Packet): + ASN1_codec = ASN1_Codecs.BER + ASN1_root = ASN1F_SEQUENCE( + ASN1F_OID("type", "2.5.4.6"), + ASN1F_X509_DirectoryString("value", + ASN1_PRINTABLE_STRING("FR"))) + +class X509_RDN(ASN1_Packet): + ASN1_codec = ASN1_Codecs.BER + ASN1_root = ASN1F_SET_OF("rdn", [X509_AttributeTypeAndValue()], + X509_AttributeTypeAndValue) +class X509_OtherName(ASN1_Packet): + ASN1_codec = ASN1_Codecs.BER + ASN1_root = ASN1F_SEQUENCE( + ASN1F_OID("type_id", "0"), + ASN1F_CHOICE("value", None, + ASN1F_IA5_STRING, ASN1F_ISO646_STRING, + ASN1F_BMP_STRING, ASN1F_UTF8_STRING, + explicit_tag=0xa0)) + +class X509_RFC822Name(ASN1_Packet): + ASN1_codec = ASN1_Codecs.BER + ASN1_root = ASN1F_IA5_STRING("rfc822Name", "") + +class X509_DNSName(ASN1_Packet): + ASN1_codec = ASN1_Codecs.BER + ASN1_root = ASN1F_IA5_STRING("dNSName", "") + +#XXX write me +class X509_X400Address(ASN1_Packet): + ASN1_codec = ASN1_Codecs.BER + ASN1_root = ASN1F_field("x400Address", "") + +default_directoryName = [ + X509_RDN(), + X509_RDN( + rdn=[X509_AttributeTypeAndValue( + type="2.5.4.10", + value=ASN1_PRINTABLE_STRING("Scapy, Inc."))]), + X509_RDN( + rdn=[X509_AttributeTypeAndValue( + type="2.5.4.3", + value=ASN1_PRINTABLE_STRING("Scapy Default Name"))]) + ] + +class X509_DirectoryName(ASN1_Packet): + ASN1_codec = ASN1_Codecs.BER + ASN1_root = ASN1F_SEQUENCE_OF("directoryName", default_directoryName, + X509_RDN) + +class X509_EDIPartyName(ASN1_Packet): + ASN1_codec = ASN1_Codecs.BER + ASN1_root = ASN1F_SEQUENCE( + ASN1F_optional( + ASN1F_X509_DirectoryString("nameAssigner", None, + explicit_tag=0xa0)), + ASN1F_X509_DirectoryString("partyName", None, + explicit_tag=0xa1)) + +class X509_URI(ASN1_Packet): + ASN1_codec = ASN1_Codecs.BER + ASN1_root = ASN1F_IA5_STRING("uniformResourceIdentifier", "") + +class X509_IPAddress(ASN1_Packet): + ASN1_codec = ASN1_Codecs.BER + ASN1_root = ASN1F_STRING("iPAddress", "") + +class X509_RegisteredID(ASN1_Packet): + ASN1_codec = ASN1_Codecs.BER + ASN1_root = ASN1F_OID("registeredID", "") + +class X509_GeneralName(ASN1_Packet): + ASN1_codec = ASN1_Codecs.BER + ASN1_root = ASN1F_CHOICE("generalName", X509_DirectoryName(), + ASN1F_PACKET("otherName", None, X509_OtherName, + implicit_tag=0xa0), + ASN1F_PACKET("rfc822Name", None, X509_RFC822Name, + implicit_tag=0x81), + ASN1F_PACKET("dNSName", None, X509_DNSName, + implicit_tag=0x82), + ASN1F_PACKET("x400Address", None, X509_X400Address, + explicit_tag=0xa3), + ASN1F_PACKET("directoryName", None, X509_DirectoryName, + explicit_tag=0xa4), + ASN1F_PACKET("ediPartyName", None, X509_EDIPartyName, + explicit_tag=0xa5), + ASN1F_PACKET("uniformResourceIdentifier", None, X509_URI, + implicit_tag=0x86), + ASN1F_PACKET("ipAddress", None, X509_IPAddress, + implicit_tag=0x87), + ASN1F_PACKET("registeredID", None, X509_RegisteredID, + implicit_tag=0x88)) + + +####### Extensions ####### + +class X509_ExtAuthorityKeyIdentifier(ASN1_Packet): + ASN1_codec = ASN1_Codecs.BER + ASN1_root = ASN1F_SEQUENCE( + ASN1F_optional( + ASN1F_STRING("keyIdentifier", "\xff"*20, + implicit_tag=0x80)), + ASN1F_optional( + ASN1F_SEQUENCE_OF("authorityCertIssuer", None, + X509_GeneralName, + implicit_tag=0xa1)), + ASN1F_optional( + ASN1F_INTEGER("authorityCertSerialNumber", None, + implicit_tag=0x82))) + +class X509_ExtSubjectDirectoryAttributes(ASN1_Packet): + ASN1_codec = ASN1_Codecs.BER + ASN1_root = ASN1F_SEQUENCE_OF("subjectDirectoryAttributes", + [X509_Attribute()], + X509_Attribute) + +class X509_ExtSubjectKeyIdentifier(ASN1_Packet): + ASN1_codec = ASN1_Codecs.BER + ASN1_root = ASN1F_STRING("keyIdentifier", "xff"*20) + +class X509_ExtFullName(ASN1_Packet): + ASN1_codec = ASN1_Codecs.BER + ASN1_root = ASN1F_SEQUENCE_OF("fullName", [X509_GeneralName()], + X509_GeneralName, implicit_tag=0xa0) + +class X509_ExtNameRelativeToCRLIssuer(ASN1_Packet): + ASN1_codec = ASN1_Codecs.BER + ASN1_root = ASN1F_PACKET("nameRelativeToCRLIssuer", X509_RDN(), X509_RDN, + implicit_tag=0xa1) + +class X509_ExtDistributionPointName(ASN1_Packet): + ASN1_codec = ASN1_Codecs.BER + ASN1_root = ASN1F_CHOICE("distributionPointName", None, + X509_ExtFullName, X509_ExtNameRelativeToCRLIssuer) + +reasons_mapping = ["unused", + "keyCompromise", + "cACompromise", + "affiliationChanged", + "superseded", + "cessationOfOperation", + "certificateHold", + "privilegeWithdrawn", + "aACompromise"] + +class X509_ExtDistributionPoint(ASN1_Packet): + ASN1_codec = ASN1_Codecs.BER + ASN1_root = ASN1F_SEQUENCE( + ASN1F_optional( + ASN1F_PACKET("distributionPoint", + X509_ExtDistributionPointName(), + X509_ExtDistributionPointName, + explicit_tag=0xa0)), + ASN1F_optional( + ASN1F_FLAGS("reasons", None, reasons_mapping, + implicit_tag=0x81)), + ASN1F_optional( + ASN1F_SEQUENCE_OF("cRLIssuer", None, + X509_GeneralName, + implicit_tag=0xa2))) + +ku_mapping = ["digitalSignature", + "nonRepudiation", + "keyEncipherment", + "dataEncipherment", + "keyAgreement", + "keyCertSign", + "cRLSign", + "encipherOnly", + "decipherOnly"] + +class X509_ExtKeyUsage(ASN1_Packet): + ASN1_codec = ASN1_Codecs.BER + ASN1_root = ASN1F_FLAGS("keyUsage", "101", ku_mapping) + def get_keyUsage(self): + return self.ASN1_root.get_flags(self) + +class X509_ExtPrivateKeyUsagePeriod(ASN1_Packet): + ASN1_codec = ASN1_Codecs.BER + ASN1_root = ASN1F_SEQUENCE( + ASN1F_optional( + ASN1F_GENERALIZED_TIME("notBefore", + str(GeneralizedTime(-600)), + implicit_tag=0x80)), + ASN1F_optional( + ASN1F_GENERALIZED_TIME("notAfter", + str(GeneralizedTime(+86400)), + implicit_tag=0x81))) + +class X509_PolicyMapping(ASN1_Packet): + ASN1_codec = ASN1_Codecs.BER + ASN1_root = ASN1F_SEQUENCE( + ASN1F_OID("issuerDomainPolicy", None), + ASN1F_OID("subjectDomainPolicy", None)) + +class X509_ExtPolicyMappings(ASN1_Packet): + ASN1_codec = ASN1_Codecs.BER + ASN1_root = ASN1F_SEQUENCE_OF("policyMappings", [], X509_PolicyMapping) + +class X509_ExtBasicConstraints(ASN1_Packet): +# The cA field should not be optional, but some certs omit it for False. + ASN1_codec = ASN1_Codecs.BER + ASN1_root = ASN1F_SEQUENCE( + ASN1F_optional( + ASN1F_BOOLEAN("cA", False)), + ASN1F_optional( + ASN1F_INTEGER("pathLenConstraint", None))) + +class X509_ExtCRLNumber(ASN1_Packet): + ASN1_codec = ASN1_Codecs.BER + ASN1_root = ASN1F_INTEGER("cRLNumber", 0) +cRL_reasons = ["unspecified", + "keyCompromise", + "cACompromise", + "affiliationChanged", + "superseded", + "cessationOfOperation", + "certificateHold", + "unused_reasonCode", + "removeFromCRL", + "privilegeWithdrawn", + "aACompromise"] + +class X509_ExtReasonCode(ASN1_Packet): + ASN1_codec = ASN1_Codecs.BER + ASN1_root = ASN1F_ENUMERATED("cRLReason", 0, cRL_reasons) + +class X509_ExtDeltaCRLIndicator(ASN1_Packet): + ASN1_codec = ASN1_Codecs.BER + ASN1_root = ASN1F_INTEGER("deltaCRLIndicator", 0) + +class X509_ExtIssuingDistributionPoint(ASN1_Packet): + ASN1_codec = ASN1_Codecs.BER + ASN1_root = ASN1F_SEQUENCE( + ASN1F_optional( + ASN1F_PACKET("distributionPoint", + X509_ExtDistributionPointName(), + X509_ExtDistributionPointName, + explicit_tag=0xa0)), + ASN1F_BOOLEAN("onlyContainsUserCerts", False, + implicit_tag=0x81), + ASN1F_BOOLEAN("onlyContainsCACerts", False, + implicit_tag=0x82), + ASN1F_optional( + ASN1F_FLAGS("onlySomeReasons", None, + reasons_mapping, + implicit_tag=0x83)), + ASN1F_BOOLEAN("indirectCRL", False, + implicit_tag=0x84), + ASN1F_BOOLEAN("onlyContainsAttributeCerts", False, + implicit_tag=0x85)) + +class X509_ExtCertificateIssuer(ASN1_Packet): + ASN1_codec = ASN1_Codecs.BER + ASN1_root = ASN1F_SEQUENCE_OF("certificateIssuer", [], X509_GeneralName) + +class X509_ExtInvalidityDate(ASN1_Packet): + ASN1_codec = ASN1_Codecs.BER + ASN1_root = ASN1F_GENERALIZED_TIME("invalidityDate", str(ZuluTime(+86400))) + +class X509_ExtSubjectAltName(ASN1_Packet): + ASN1_codec = ASN1_Codecs.BER + ASN1_root = ASN1F_SEQUENCE_OF("subjectAltName", [], X509_GeneralName) + +class X509_ExtIssuerAltName(ASN1_Packet): + ASN1_codec = ASN1_Codecs.BER + ASN1_root = ASN1F_SEQUENCE_OF("issuerAltName", [], X509_GeneralName) + +class X509_ExtGeneralSubtree(ASN1_Packet): +# 'minimum' is not optional in RFC 5280, yet it is in some implementations. + ASN1_codec = ASN1_Codecs.BER + ASN1_root = ASN1F_SEQUENCE( + ASN1F_PACKET("base", X509_GeneralName(), X509_GeneralName), + ASN1F_optional( + ASN1F_INTEGER("minimum", None, implicit_tag=0x80)), + ASN1F_optional( + ASN1F_INTEGER("maximum", None, implicit_tag=0x81))) + +class X509_ExtNameConstraints(ASN1_Packet): + ASN1_codec = ASN1_Codecs.BER + ASN1_root = ASN1F_SEQUENCE( + ASN1F_optional( + ASN1F_SEQUENCE_OF("permittedSubtrees", None, + X509_ExtGeneralSubtree, + implicit_tag=0xa0)), + ASN1F_optional( + ASN1F_SEQUENCE_OF("excludedSubtrees", None, + X509_ExtGeneralSubtree, + implicit_tag=0xa1))) + +class X509_ExtPolicyConstraints(ASN1_Packet): + ASN1_codec = ASN1_Codecs.BER + ASN1_root = ASN1F_SEQUENCE( + ASN1F_optional( + ASN1F_INTEGER("requireExplicitPolicy", None, + implicit_tag=0x80)), + ASN1F_optional( + ASN1F_INTEGER("inhibitPolicyMapping", None, + implicit_tag=0x81))) + +class X509_ExtExtendedKeyUsage(ASN1_Packet): + ASN1_codec = ASN1_Codecs.BER + ASN1_root = ASN1F_SEQUENCE_OF("extendedKeyUsage", [], ASN1P_OID) + def get_extendedKeyUsage(self): + eku_array = self.extendedKeyUsage + return [eku.oid.oidname for eku in eku_array] + +class X509_ExtNoticeReference(ASN1_Packet): + ASN1_codec = ASN1_Codecs.BER + ASN1_root = ASN1F_SEQUENCE( + ASN1F_CHOICE("organization", + ASN1_UTF8_STRING("Dummy Organization"), + ASN1F_IA5_STRING, ASN1F_ISO646_STRING, + ASN1F_BMP_STRING, ASN1F_UTF8_STRING), + ASN1F_SEQUENCE_OF("noticeNumbers", [], ASN1P_INTEGER)) + +class X509_ExtUserNotice(ASN1_Packet): + ASN1_codec = ASN1_Codecs.BER + ASN1_root = ASN1F_SEQUENCE( + ASN1F_optional( + ASN1F_PACKET("noticeRef", None, + X509_ExtNoticeReference)), + ASN1F_optional( + ASN1F_CHOICE("explicitText", + ASN1_UTF8_STRING("Dummy ExplicitText"), + ASN1F_IA5_STRING, ASN1F_ISO646_STRING, + ASN1F_BMP_STRING, ASN1F_UTF8_STRING))) + +class X509_ExtPolicyQualifierInfo(ASN1_Packet): + ASN1_codec = ASN1_Codecs.BER + ASN1_root = ASN1F_SEQUENCE( + ASN1F_OID("policyQualifierId", "1.3.6.1.5.5.7.2.1"), + ASN1F_CHOICE("qualifier", ASN1_IA5_STRING("cps_str"), + ASN1F_IA5_STRING, X509_ExtUserNotice)) + +class X509_ExtPolicyInformation(ASN1_Packet): + ASN1_codec = ASN1_Codecs.BER + ASN1_root = ASN1F_SEQUENCE( + ASN1F_OID("policyIdentifier", "2.5.29.32.0"), + ASN1F_optional( + ASN1F_SEQUENCE_OF("policyQualifiers", None, + X509_ExtPolicyQualifierInfo))) + +class X509_ExtCertificatePolicies(ASN1_Packet): + ASN1_codec = ASN1_Codecs.BER + ASN1_root = ASN1F_SEQUENCE_OF("certificatePolicies", + [X509_ExtPolicyInformation()], + X509_ExtPolicyInformation) + +class X509_ExtCRLDistributionPoints(ASN1_Packet): + ASN1_codec = ASN1_Codecs.BER + ASN1_root = ASN1F_SEQUENCE_OF("cRLDistributionPoints", + [X509_ExtDistributionPoint()], + X509_ExtDistributionPoint) + +class X509_ExtInhibitAnyPolicy(ASN1_Packet): + ASN1_codec = ASN1_Codecs.BER + ASN1_root = ASN1F_INTEGER("skipCerts", 0) + +class X509_ExtFreshestCRL(ASN1_Packet): + ASN1_codec = ASN1_Codecs.BER + ASN1_root = ASN1F_SEQUENCE_OF("cRLDistributionPoints", + [X509_ExtDistributionPoint()], + X509_ExtDistributionPoint) + +class X509_AccessDescription(ASN1_Packet): + ASN1_codec = ASN1_Codecs.BER + ASN1_root = ASN1F_SEQUENCE( + ASN1F_OID("accessMethod", "0"), + ASN1F_PACKET("accessLocation", X509_GeneralName(), + X509_GeneralName)) + +class X509_ExtAuthInfoAccess(ASN1_Packet): + ASN1_codec = ASN1_Codecs.BER + ASN1_root = ASN1F_SEQUENCE_OF("authorityInfoAccess", + [X509_AccessDescription()], + X509_AccessDescription) + +class X509_ExtQcStatement(ASN1_Packet): + ASN1_codec = ASN1_Codecs.BER + ASN1_root = ASN1F_SEQUENCE( + ASN1F_OID("statementId", "0.4.0.1862.1.1"), + ASN1F_optional( + ASN1F_field("statementInfo", None))) + +class X509_ExtQcStatements(ASN1_Packet): + ASN1_codec = ASN1_Codecs.BER + ASN1_root = ASN1F_SEQUENCE_OF("qcStatements", + [X509_ExtQcStatement()], + X509_ExtQcStatement) + +class X509_ExtSubjInfoAccess(ASN1_Packet): + ASN1_codec = ASN1_Codecs.BER + ASN1_root = ASN1F_SEQUENCE_OF("subjectInfoAccess", + [X509_AccessDescription()], + X509_AccessDescription) + +class X509_ExtNetscapeCertType(ASN1_Packet): + ASN1_codec = ASN1_Codecs.BER + ASN1_root = ASN1F_BIT_STRING("netscapeCertType", "") + +class X509_ExtComment(ASN1_Packet): + ASN1_codec = ASN1_Codecs.BER + ASN1_root = ASN1F_CHOICE("comment", + ASN1_UTF8_STRING("Dummy comment."), + ASN1F_IA5_STRING, ASN1F_ISO646_STRING, + ASN1F_BMP_STRING, ASN1F_UTF8_STRING) + +class X509_ExtDefault(ASN1_Packet): + ASN1_codec = ASN1_Codecs.BER + ASN1_root = ASN1F_field("value", None) + +# oid-info.com shows that some extensions share multiple OIDs. +# Here we only reproduce those written in RFC5280. +ext_mapping = { + "2.5.29.9" : X509_ExtSubjectDirectoryAttributes, + "2.5.29.14" : X509_ExtSubjectKeyIdentifier, + "2.5.29.15" : X509_ExtKeyUsage, + "2.5.29.16" : X509_ExtPrivateKeyUsagePeriod, + "2.5.29.17" : X509_ExtSubjectAltName, + "2.5.29.18" : X509_ExtIssuerAltName, + "2.5.29.19" : X509_ExtBasicConstraints, + "2.5.29.20" : X509_ExtCRLNumber, + "2.5.29.21" : X509_ExtReasonCode, + "2.5.29.24" : X509_ExtInvalidityDate, + "2.5.29.27" : X509_ExtDeltaCRLIndicator, + "2.5.29.28" : X509_ExtIssuingDistributionPoint, + "2.5.29.29" : X509_ExtCertificateIssuer, + "2.5.29.30" : X509_ExtNameConstraints, + "2.5.29.31" : X509_ExtCRLDistributionPoints, + "2.5.29.32" : X509_ExtCertificatePolicies, + "2.5.29.33" : X509_ExtPolicyMappings, + "2.5.29.35" : X509_ExtAuthorityKeyIdentifier, + "2.5.29.36" : X509_ExtPolicyConstraints, + "2.5.29.37" : X509_ExtExtendedKeyUsage, + "2.5.29.46" : X509_ExtFreshestCRL, + "2.5.29.54" : X509_ExtInhibitAnyPolicy, + "2.16.840.1.113730.1.1" : X509_ExtNetscapeCertType, + "2.16.840.1.113730.1.13" : X509_ExtComment, + "1.3.6.1.5.5.7.1.1" : X509_ExtAuthInfoAccess, + "1.3.6.1.5.5.7.1.3" : X509_ExtQcStatements, + "1.3.6.1.5.5.7.1.11" : X509_ExtSubjInfoAccess + } + +class ASN1F_EXT_SEQUENCE(ASN1F_SEQUENCE): +# We use explicit_tag=0x04 with extnValue as STRING encapsulation. + def __init__(self, **kargs): + seq = [ASN1F_OID("extnID", "2.5.29.19"), + ASN1F_optional( + ASN1F_BOOLEAN("critical", False)), + ASN1F_PACKET("extnValue", + X509_ExtBasicConstraints(), + X509_ExtBasicConstraints, + explicit_tag=0x04)] + ASN1F_SEQUENCE.__init__(self, *seq, **kargs) + def dissect(self, pkt, s): + s = BER_tagging_dec(s, implicit_tag=self.implicit_tag, + explicit_tag=self.explicit_tag, + safe=self.flexible_tag) + codec = self.ASN1_tag.get_codec(pkt.ASN1_codec) + i,s,remain = codec.check_type_check_len(s) + extnID = self.seq[0] + critical = self.seq[1] + try: + oid,s = extnID.m2i(pkt, s) + extnID.set_val(pkt, oid) + s = critical.dissect(pkt, s) + encapsed = X509_ExtDefault + if oid.val in ext_mapping: + encapsed = ext_mapping[oid.val] + self.seq[2].cls = encapsed + self.seq[2].cls.ASN1_root.flexible_tag = True + # there are too many private extensions not to be flexible here + self.seq[2].default = encapsed() + s = self.seq[2].dissect(pkt, s) + if not self.flexible_tag and len(s) > 0: + err_msg = "extension sequence length issue" + raise BER_Decoding_Error(err_msg, remaining=s) + except ASN1F_badsequence,e: + raise Exception("could not parse extensions") + return remain + +class X509_Extension(ASN1_Packet): + ASN1_codec = ASN1_Codecs.BER + ASN1_root = ASN1F_EXT_SEQUENCE() + + +####### Public key wrapper ####### + +class X509_AlgorithmIdentifier(ASN1_Packet): + ASN1_codec = ASN1_Codecs.BER + ASN1_root = ASN1F_SEQUENCE( + ASN1F_OID("algorithm", "1.2.840.113549.1.1.11"), + ASN1F_optional( + ASN1F_CHOICE("parameters", ASN1_NULL(0), + ASN1F_NULL, ECParameters))) + +class ASN1F_X509_SubjectPublicKeyInfoRSA(ASN1F_SEQUENCE): + def __init__(self, **kargs): + seq = [ASN1F_PACKET("signatureAlgorithm", + X509_AlgorithmIdentifier(), + X509_AlgorithmIdentifier), + ASN1F_BIT_STRING_ENCAPS("subjectPublicKey", + RSAPublicKey(), + RSAPublicKey)] + ASN1F_SEQUENCE.__init__(self, *seq, **kargs) + +class ASN1F_X509_SubjectPublicKeyInfo(ASN1F_SEQUENCE): + def __init__(self, **kargs): + seq = [ASN1F_PACKET("signatureAlgorithm", + X509_AlgorithmIdentifier(), + X509_AlgorithmIdentifier), + ASN1F_BIT_STRING("subjectPublicKey", None)] + ASN1F_SEQUENCE.__init__(self, *seq, **kargs) + def m2i(self, pkt, x): + c,s = ASN1F_SEQUENCE.m2i(self, pkt, x) + keytype = pkt.fields["signatureAlgorithm"].algorithm.oidname + if "rsa" in keytype.lower(): + return ASN1F_X509_SubjectPublicKeyInfoRSA().m2i(pkt, x) + elif keytype == "ecPublicKey": + return c,s + else: + raise Exception("could not parse subjectPublicKeyInfo") + def dissect(self, pkt, s): + c,x = self.m2i(pkt, s) + return x + def build(self, pkt): + if "signatureAlgorithm" in pkt.fields: + ktype = pkt.fields['signatureAlgorithm'].algorithm.oidname + else: + ktype = pkt.default_fields["signatureAlgorithm"].algorithm.oidname + if "rsa" in ktype.lower(): + pkt.default_fields["subjectPublicKey"] = RSAPublicKey() + return ASN1F_X509_SubjectPublicKeyInfoRSA().build(pkt) + elif ktype == "ecPublicKey": + return ASN1F_SEQUENCE.build(self, pkt) + else: + raise Exception("could not build subjectPublicKeyInfo") + +class X509_SubjectPublicKeyInfo(ASN1_Packet): + ASN1_codec = ASN1_Codecs.BER + ASN1_root = ASN1F_X509_SubjectPublicKeyInfo() + + +####### TBSCertificate & Certificate ####### + +default_issuer = [ + X509_RDN(), + X509_RDN( + rdn=[X509_AttributeTypeAndValue( + type="2.5.4.10", + value=ASN1_PRINTABLE_STRING("Scapy, Inc."))]), + X509_RDN( + rdn=[X509_AttributeTypeAndValue( + type="2.5.4.3", + value=ASN1_PRINTABLE_STRING("Scapy Default Issuer"))]) + ] + +default_subject = [ + X509_RDN(), + X509_RDN( + rdn=[X509_AttributeTypeAndValue( + type="2.5.4.10", + value=ASN1_PRINTABLE_STRING("Scapy, Inc."))]), + X509_RDN( + rdn=[X509_AttributeTypeAndValue( + type="2.5.4.3", + value=ASN1_PRINTABLE_STRING("Scapy Default Subject"))]) + ] + +class X509_Validity(ASN1_Packet): + ASN1_codec = ASN1_Codecs.BER + ASN1_root = ASN1F_SEQUENCE( + ASN1F_CHOICE("not_before", + ASN1_UTC_TIME(str(ZuluTime(-600))), + ASN1F_UTC_TIME, ASN1F_GENERALIZED_TIME), + ASN1F_CHOICE("not_after", + ASN1_UTC_TIME(str(ZuluTime(+86400))), + ASN1F_UTC_TIME, ASN1F_GENERALIZED_TIME)) + +attrName_mapping = [ + ("countryName" , "C"), + ("stateOrProvinceName" , "ST"), + ("localityName" , "L"), + ("organizationName" , "O"), + ("organizationUnitName" , "OU"), + ("commonName" , "CN") + ] +attrName_specials = [name for name, symbol in attrName_mapping] + +class X509_TBSCertificate(ASN1_Packet): + ASN1_codec = ASN1_Codecs.BER + ASN1_root = ASN1F_SEQUENCE( + ASN1F_optional( + ASN1F_enum_INTEGER("version", 0x2, ["v1", "v2", "v3"], + explicit_tag=0xa0)), + ASN1F_INTEGER("serialNumber", 1), + ASN1F_PACKET("signature", + X509_AlgorithmIdentifier(), + X509_AlgorithmIdentifier), + ASN1F_SEQUENCE_OF("issuer", default_issuer, X509_RDN), + ASN1F_PACKET("validity", + X509_Validity(), + X509_Validity), + ASN1F_SEQUENCE_OF("subject", default_subject, X509_RDN), + ASN1F_PACKET("subjectPublicKeyInfo", + X509_SubjectPublicKeyInfo(), + X509_SubjectPublicKeyInfo), + ASN1F_optional( + ASN1F_BIT_STRING("issuerUniqueID", None, + implicit_tag=0x81)), + ASN1F_optional( + ASN1F_BIT_STRING("subjectUniqueID", None, + implicit_tag=0x82)), + ASN1F_optional( + ASN1F_SEQUENCE_OF("extensions", + [X509_Extension()], + X509_Extension, + explicit_tag=0xa3))) + def get_issuer(self): + attrs = self.issuer + attrsDict = {} + for attr in attrs: + # we assume there is only one name in each rdn ASN1_SET + attrsDict[attr.rdn[0].type.oidname] = attr.rdn[0].value.val + return attrsDict + def get_issuer_str(self): + """ + Returns a one-line string containing every type/value + in a rather specific order. sorted() built-in ensures unicity. + """ + name_str = "" + attrsDict = self.get_issuer() + for attrType, attrSymbol in attrName_mapping: + if attrType in attrsDict: + name_str += "/" + attrSymbol + "=" + name_str += attrsDict[attrType] + for attrType in sorted(attrsDict): + if attrType not in attrName_specials: + name_str += "/" + attrType + "=" + name_str += attrsDict[attrType] + return name_str + def get_subject(self): + attrs = self.subject + attrsDict = {} + for attr in attrs: + # we assume there is only one name in each rdn ASN1_SET + attrsDict[attr.rdn[0].type.oidname] = attr.rdn[0].value.val + return attrsDict + def get_subject_str(self): + name_str = "" + attrsDict = self.get_subject() + for attrType, attrSymbol in attrName_mapping: + if attrType in attrsDict: + name_str += "/" + attrSymbol + "=" + name_str += attrsDict[attrType] + for attrType in sorted(attrsDict): + if attrType not in attrName_specials: + name_str += "/" + attrType + "=" + name_str += attrsDict[attrType] + return name_str + +class ASN1F_X509_CertECDSA(ASN1F_SEQUENCE): + def __init__(self, **kargs): + seq = [ASN1F_PACKET("tbsCertificate", + X509_TBSCertificate(), + X509_TBSCertificate), + ASN1F_PACKET("signatureAlgorithm", + X509_AlgorithmIdentifier(), + X509_AlgorithmIdentifier), + ASN1F_BIT_STRING_ENCAPS("signatureValue", + ECDSASignature(), + ECDSASignature)] + ASN1F_SEQUENCE.__init__(self, *seq, **kargs) + +class ASN1F_X509_Cert(ASN1F_SEQUENCE): + def __init__(self, **kargs): + seq = [ASN1F_PACKET("tbsCertificate", + X509_TBSCertificate(), + X509_TBSCertificate), + ASN1F_PACKET("signatureAlgorithm", + X509_AlgorithmIdentifier(), + X509_AlgorithmIdentifier), + ASN1F_BIT_STRING("signatureValue", + "defaultsignature"*2)] + ASN1F_SEQUENCE.__init__(self, *seq, **kargs) + def m2i(self, pkt, x): + c,s = ASN1F_SEQUENCE.m2i(self, pkt, x) + sigtype = pkt.fields["signatureAlgorithm"].algorithm.oidname + if "rsa" in sigtype.lower(): + return c,s + elif "ecdsa" in sigtype.lower(): + return ASN1F_X509_CertECDSA().m2i(pkt, x) + else: + raise Exception("could not parse certificate") + def dissect(self, pkt, s): + c,x = self.m2i(pkt, s) + return x + def build(self, pkt): + if "signatureAlgorithm" in pkt.fields: + sigtype = pkt.fields['signatureAlgorithm'].algorithm.oidname + else: + sigtype = pkt.default_fields["signatureAlgorithm"].algorithm.oidname + if "rsa" in sigtype.lower(): + return ASN1F_SEQUENCE.build(self, pkt) + elif "ecdsa" in sigtype.lower(): + pkt.default_fields["signatureValue"] = ECDSASignature() + return ASN1F_X509_CertECDSA().build(pkt) + else: + raise Exception("could not build certificate") + +class X509_Cert(ASN1_Packet): + ASN1_codec = ASN1_Codecs.BER + ASN1_root = ASN1F_X509_Cert() + + +####### TBSCertList & CRL ####### + +class X509_RevokedCertificate(ASN1_Packet): + ASN1_codec = ASN1_Codecs.BER + ASN1_root = ASN1F_SEQUENCE(ASN1F_INTEGER("serialNumber", 1), + ASN1F_UTC_TIME("revocationDate", + str(ZuluTime(+86400))), + ASN1F_optional( + ASN1F_SEQUENCE_OF("crlEntryExtensions", + None, X509_Extension))) + +class X509_TBSCertList(ASN1_Packet): + ASN1_codec = ASN1_Codecs.BER + ASN1_root = ASN1F_SEQUENCE( + ASN1F_optional( + ASN1F_enum_INTEGER("version", 1, ["v1", "v2"])), + ASN1F_PACKET("signature", + X509_AlgorithmIdentifier(), + X509_AlgorithmIdentifier), + ASN1F_SEQUENCE_OF("issuer", default_issuer, X509_RDN), + ASN1F_UTC_TIME("this_update", str(ZuluTime(-1))), + ASN1F_optional( + ASN1F_UTC_TIME("next_update", None)), + ASN1F_optional( + ASN1F_SEQUENCE_OF("revokedCertificates", None, + X509_RevokedCertificate)), + ASN1F_optional( + ASN1F_SEQUENCE_OF("crlExtensions", None, + X509_Extension, + explicit_tag=0xa0))) + def get_issuer(self): + attrs = self.issuer + attrsDict = {} + for attr in attrs: + # we assume there is only one name in each rdn ASN1_SET + attrsDict[attr.rdn[0].type.oidname] = attr.rdn[0].value.val + return attrsDict + def get_issuer_str(self): + """ + Returns a one-line string containing every type/value + in a rather specific order. sorted() built-in ensures unicity. + """ + name_str = "" + attrsDict = self.get_issuer() + for attrType, attrSymbol in attrName_mapping: + if attrType in attrsDict: + name_str += "/" + attrSymbol + "=" + name_str += attrsDict[attrType] + for attrType in sorted(attrsDict): + if attrType not in attrName_specials: + name_str += "/" + attrType + "=" + name_str += attrsDict[attrType] + return name_str + +class ASN1F_X509_CRLECDSA(ASN1F_SEQUENCE): + def __init__(self, **kargs): + seq = [ASN1F_PACKET("tbsCertList", + X509_TBSCertList(), + X509_TBSCertList), + ASN1F_PACKET("signatureAlgorithm", + X509_AlgorithmIdentifier(), + X509_AlgorithmIdentifier), + ASN1F_BIT_STRING_ENCAPS("signatureValue", + ECDSASignature(), + ECDSASignature)] + ASN1F_SEQUENCE.__init__(self, *seq, **kargs) + +class ASN1F_X509_CRL(ASN1F_SEQUENCE): + def __init__(self, **kargs): + seq = [ASN1F_PACKET("tbsCertList", + X509_TBSCertList(), + X509_TBSCertList), + ASN1F_PACKET("signatureAlgorithm", + X509_AlgorithmIdentifier(), + X509_AlgorithmIdentifier), + ASN1F_BIT_STRING("signatureValue", + "defaultsignature"*2)] + ASN1F_SEQUENCE.__init__(self, *seq, **kargs) + def m2i(self, pkt, x): + c,s = ASN1F_SEQUENCE.m2i(self, pkt, x) + sigtype = pkt.fields["signatureAlgorithm"].algorithm.oidname + if "rsa" in sigtype.lower(): + return c,s + elif "ecdsa" in sigtype.lower(): + return ASN1F_X509_CRLECDSA().m2i(pkt, x) + else: + raise Exception("could not parse certificate") + def dissect(self, pkt, s): + c,x = self.m2i(pkt, s) + return x + def build(self, pkt): + if "signatureAlgorithm" in pkt.fields: + sigtype = pkt.fields['signatureAlgorithm'].algorithm.oidname + else: + sigtype = pkt.default_fields["signatureAlgorithm"].algorithm.oidname + if "rsa" in sigtype.lower(): + return ASN1F_SEQUENCE.build(self, pkt) + elif "ecdsa" in sigtype.lower(): + pkt.default_fields["signatureValue"] = ECDSASignature() + return ASN1F_X509_CRLECDSA().build(pkt) + else: + raise Exception("could not build certificate") + +class X509_CRL(ASN1_Packet): + ASN1_codec = ASN1_Codecs.BER + ASN1_root = ASN1F_X509_CRL() diff --git a/scapy/volatile.py b/scapy/volatile.py index 8d8d4ad76c75e53fa1693a4be4f69fc9ffffebf9..1a1f00024a80f8f14f1c423094113883f3bbe25f 100644 --- a/scapy/volatile.py +++ b/scapy/volatile.py @@ -642,10 +642,19 @@ class IntAutoTime(AutoTime): class ZuluTime(AutoTime): - def __init__(self, diff=None): - self.diff=diff + def __init__(self, diff=0): + self.diff = diff def _fix(self): - return time.strftime("%y%m%d%H%M%SZ",time.gmtime(time.time()+self.diff)) + return time.strftime("%y%m%d%H%M%SZ", + time.gmtime(time.time() + self.diff)) + + +class GeneralizedTime(AutoTime): + def __init__(self, diff=0): + self.diff = diff + def _fix(self): + return time.strftime("%Y%m%d%H%M%SZ", + time.gmtime(time.time() + self.diff)) class DelayedEval(VolatileValue): diff --git a/test/regression.uts b/test/regression.uts index af22f521ec7d1f3942fb1d629f4e5909ac03cbcf..3cf4b298e4a57fda22d9f9297ac961509f19bedf 100644 --- a/test/regression.uts +++ b/test/regression.uts @@ -540,103 +540,6 @@ assert(x.PDU.varbindlist[0].value == "172.31.19.2") assert(x.PDU.varbindlist[2].oid == "1.3.6.1.4.1.253.8.64.4.2.1.5.10.14130400") assert(x.PDU.varbindlist[2].value == 1) -############ -############ -+ X509 tests - -= X509 certificate assembling -~ X509 ASN1 -c=X509Cert( pubkey='\x00'+str(ASN1_SEQUENCE([ASN1_INTEGER(1),ASN1_INTEGER(2)])), signature="xxxxxx") -c.show() -str(c) == str(X509Cert(str(c))) - -= Small X509 certificate disassembling -~ X509 ASN1 -* This cert has neither the version field nor X509v3 extensions -small="""MIIB+jCCAWMCAgGjMA0GCSqGSIb3DQEBBAUAMEUxCzAJBgNVBAYTAlVTMRgw -FgYDVQQKEw9HVEUgQ29ycG9yYXRpb24xHDAaBgNVBAMTE0dURSBDeWJlclRy -dXN0IFJvb3QwHhcNOTYwMjIzMjMwMTAwWhcNMDYwMjIzMjM1OTAwWjBFMQsw -CQYDVQQGEwJVUzEYMBYGA1UEChMPR1RFIENvcnBvcmF0aW9uMRwwGgYDVQQD -ExNHVEUgQ3liZXJUcnVzdCBSb290MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCB -iQKBgQC45k+625h8cXyvRLfTD0bZZOWTwUKOx7pJjTUteueLveUFMVnGsS8K -DPufpz+iCWaEVh43KRuH6X4MypqfpX/1FZSj1aJGgthoTNE3FQZor734sLPw -KfWVWgkWYXcKIiXUT0Wqx73llt/51KiOQswkwB6RJ0q1bQaAYznEol44AwID -AQABMA0GCSqGSIb3DQEBBAUAA4GBABKzdcZfHeFhVYAA1IFLezEPI2PnPfMD - +fQ2qLvZ46WXTeorKeDWanOB5sCJo9Px4KWlIjeaY8JIILTbcuPI9tl8vrGv -U9oUtCG41tWW4/5ODFlitppK+ULdjG+BqXH/9ApybW1EDp3zdHSo1TRJ6V6e -6bR64eVaH4QwnNOfpSXY """.decode("base64") -c = X509Cert(small) -c.show() -assert( str(c) == small ) -assert( c.version == None ) -assert( c.sn == 419 ) -assert( "/".join(rdn.value.val for rdn in c.issuer) == "US/GTE Corporation/GTE CyberTrust Root") -assert( c.not_after == '060223235900Z' ) -assert( c.x509v3ext == None ) -assert( c.signature == '\x00\x12\xb3u\xc6_\x1d\xe1aU\x80\x00\xd4\x81K{1\x0f#c\xe7=\xf3\x03\xf9\xf46\xa8\xbb\xd9\xe3\xa5\x97M\xea+)\xe0\xd6js\x81\xe6\xc0\x89\xa3\xd3\xf1\xe0\xa5\xa5"7\x9ac\xc2H \xb4\xdbr\xe3\xc8\xf6\xd9|\xbe\xb1\xafS\xda\x14\xb4!\xb8\xd6\xd5\x96\xe3\xfeN\x0cYb\xb6\x9aJ\xf9B\xdd\x8co\x81\xa9q\xff\xf4\nrmmD\x0e\x9d\xf3tt\xa8\xd54I\xe9^\x9e\xe9\xb4z\xe1\xe5Z\x1f\x840\x9c\xd3\x9f\xa5%\xd8' ) - - -= Big X509 certificate disassembling -~ X509 ASN1 -small="""MIIIODCCB6GgAwIBAgIBADANBgkqhkiG9w0BAQUFADCCAR4xCzAJBgNVBAYT -AkVTMRIwEAYDVQQIEwlCYXJjZWxvbmExEjAQBgNVBAcTCUJhcmNlbG9uYTEu -MCwGA1UEChMlSVBTIEludGVybmV0IHB1Ymxpc2hpbmcgU2VydmljZXMgcy5s -LjErMCkGA1UEChQiaXBzQG1haWwuaXBzLmVzIEMuSS5GLiAgQi02MDkyOTQ1 -MjE0MDIGA1UECxMrSVBTIENBIFRpbWVzdGFtcGluZyBDZXJ0aWZpY2F0aW9u -IEF1dGhvcml0eTE0MDIGA1UEAxMrSVBTIENBIFRpbWVzdGFtcGluZyBDZXJ0 -aWZpY2F0aW9uIEF1dGhvcml0eTEeMBwGCSqGSIb3DQEJARYPaXBzQG1haWwu -aXBzLmVzMB4XDTAxMTIyOTAxMTAxOFoXDTI1MTIyNzAxMTAxOFowggEeMQsw -CQYDVQQGEwJFUzESMBAGA1UECBMJQmFyY2Vsb25hMRIwEAYDVQQHEwlCYXJj -ZWxvbmExLjAsBgNVBAoTJUlQUyBJbnRlcm5ldCBwdWJsaXNoaW5nIFNlcnZp -Y2VzIHMubC4xKzApBgNVBAoUImlwc0BtYWlsLmlwcy5lcyBDLkkuRi4gIEIt -NjA5Mjk0NTIxNDAyBgNVBAsTK0lQUyBDQSBUaW1lc3RhbXBpbmcgQ2VydGlm -aWNhdGlvbiBBdXRob3JpdHkxNDAyBgNVBAMTK0lQUyBDQSBUaW1lc3RhbXBp -bmcgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxHjAcBgkqhkiG9w0BCQEWD2lw -c0BtYWlsLmlwcy5lczCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAvLju -VqWajOY2ycJioGaBjRrVetJznw6EZLqVtJCneK/K/lRhW86yIFcBrkSSQxA4 -Efdo/BdApWgnMjvEp+ZCccWZ73b/K5Uk9UmSGGjKALWkWi9uy9YbLA1UZ2t6 -KaFYq6JaANZbuxjC3/YeE1Z2m6Vo4pjOxgOKNNtMg0GmqaMCAwEAAaOCBIAw -ggR8MB0GA1UdDgQWBBSL0BBQCYHynQnVDmB4AyKiP8jKZjCCAVAGA1UdIwSC -AUcwggFDgBSL0BBQCYHynQnVDmB4AyKiP8jKZqGCASakggEiMIIBHjELMAkG -A1UEBhMCRVMxEjAQBgNVBAgTCUJhcmNlbG9uYTESMBAGA1UEBxMJQmFyY2Vs -b25hMS4wLAYDVQQKEyVJUFMgSW50ZXJuZXQgcHVibGlzaGluZyBTZXJ2aWNl -cyBzLmwuMSswKQYDVQQKFCJpcHNAbWFpbC5pcHMuZXMgQy5JLkYuICBCLTYw -OTI5NDUyMTQwMgYDVQQLEytJUFMgQ0EgVGltZXN0YW1waW5nIENlcnRpZmlj -YXRpb24gQXV0aG9yaXR5MTQwMgYDVQQDEytJUFMgQ0EgVGltZXN0YW1waW5n -IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MR4wHAYJKoZIhvcNAQkBFg9pcHNA -bWFpbC5pcHMuZXOCAQAwDAYDVR0TBAUwAwEB/zAMBgNVHQ8EBQMDB/+AMGsG -A1UdJQRkMGIGCCsGAQUFBwMBBggrBgEFBQcDAgYIKwYBBQUHAwMGCCsGAQUF -BwMEBggrBgEFBQcDCAYKKwYBBAGCNwIBFQYKKwYBBAGCNwIBFgYKKwYBBAGC -NwoDAQYKKwYBBAGCNwoDBDARBglghkgBhvhCAQEEBAMCAAcwGgYDVR0RBBMw -EYEPaXBzQG1haWwuaXBzLmVzMBoGA1UdEgQTMBGBD2lwc0BtYWlsLmlwcy5l -czBHBglghkgBhvhCAQ0EOhY4VGltZXN0YW1waW5nIENBIENlcnRpZmljYXRl -IGlzc3VlZCBieSBodHRwOi8vd3d3Lmlwcy5lcy8wKQYJYIZIAYb4QgECBBwW -Gmh0dHA6Ly93d3cuaXBzLmVzL2lwczIwMDIvMEAGCWCGSAGG+EIBBAQzFjFo -dHRwOi8vd3d3Lmlwcy5lcy9pcHMyMDAyL2lwczIwMDJUaW1lc3RhbXBpbmcu -Y3JsMEUGCWCGSAGG+EIBAwQ4FjZodHRwOi8vd3d3Lmlwcy5lcy9pcHMyMDAy -L3Jldm9jYXRpb25UaW1lc3RhbXBpbmcuaHRtbD8wQgYJYIZIAYb4QgEHBDUW -M2h0dHA6Ly93d3cuaXBzLmVzL2lwczIwMDIvcmVuZXdhbFRpbWVzdGFtcGlu -Zy5odG1sPzBABglghkgBhvhCAQgEMxYxaHR0cDovL3d3dy5pcHMuZXMvaXBz -MjAwMi9wb2xpY3lUaW1lc3RhbXBpbmcuaHRtbDB/BgNVHR8EeDB2MDegNaAz -hjFodHRwOi8vd3d3Lmlwcy5lcy9pcHMyMDAyL2lwczIwMDJUaW1lc3RhbXBp -bmcuY3JsMDugOaA3hjVodHRwOi8vd3d3YmFjay5pcHMuZXMvaXBzMjAwMi9p -cHMyMDAyVGltZXN0YW1waW5nLmNybDAvBggrBgEFBQcBAQQjMCEwHwYIKwYB -BQUHMAGGE2h0dHA6Ly9vY3NwLmlwcy5lcy8wDQYJKoZIhvcNAQEFBQADgYEA -ZbrBzAAalZHK6Ww6vzoeFAh8+4Pua2JR0zORtWB5fgTYXXk36MNbsMRnLWha -sl8OCvrNPzpFoeo2zyYepxEoxZSPhExTCMWTs/zif/WN87GphV+I3pGW7hdb -rqXqcGV4LCFkAZXOzkw+UPS2Wctjjba9GNSHSl/c7+lW8AoM6HU= """.decode("base64") -c = X509Cert(small) -c.show() -assert( str(c) == small ) -assert( c.version == 2 ) -assert( c.sn == ASN1_NULL(0) ) -assert( "/".join(rdn.value.val for rdn in c.issuer if isinstance(rdn.value,ASN1_PRINTABLE_STRING)) == "ES/Barcelona/Barcelona/IPS Internet publishing Services s.l./IPS CA Timestamping Certification Authority/IPS CA Timestamping Certification Authority") -assert( c.not_after == '251227011018Z' ) -assert( len(c.x509v3ext) == 16 ) -assert( c.signature == '\x00e\xba\xc1\xcc\x00\x1a\x95\x91\xca\xe9l:\xbf:\x1e\x14\x08|\xfb\x83\xeekbQ\xd33\x91\xb5`y~\x04\xd8]y7\xe8\xc3[\xb0\xc4g-hZ\xb2_\x0e\n\xfa\xcd?:E\xa1\xea6\xcf&\x1e\xa7\x11(\xc5\x94\x8f\x84LS\x08\xc5\x93\xb3\xfc\xe2\x7f\xf5\x8d\xf3\xb1\xa9\x85_\x88\xde\x91\x96\xee\x17[\xae\xa5\xeapex,!d\x01\x95\xce\xceL>P\xf4\xb6Y\xcbc\x8d\xb6\xbd\x18\xd4\x87J_\xdc\xef\xe9V\xf0\n\x0c\xe8u' ) - - - ############ ############ @@ -658,7 +561,6 @@ dns_ans = sr1(IP(dst="resolver1.opendns.com")/UDP()/DNS(rd=1,qd=DNSQR(qname="www DNS in dns_ans - ############ ############ + More complex tests diff --git a/test/x509.uts b/test/x509.uts new file mode 100644 index 0000000000000000000000000000000000000000..3505c10d99a0487795b51f2128b27e307474b0e5 --- /dev/null +++ b/test/x509.uts @@ -0,0 +1,183 @@ +% Tests for X.509 objects +# +# Launch me with: +# sudo bash test/run_tests -t test/x509.uts -F + +########### Key class ############################################### + ++ Private RSA & ECDSA keys class tests += Key class : Importing DER encoded RSA private key +k='MIIEowIBAAKCAQEAmFdqP+nTEZukS0lLP+yj1gNImsEIf7P2ySTunceYxwkm4VE5QReDbb2L5/HL\nA9pPmIeQLSq/BgO1meOcbOSJ2YVHQ28MQ56+8Crb6n28iycX4hp0H3AxRAjh0edX+q3yilvYJ4W9\n/NnIb/wAZwS0oJif/tTkVF77HybAfJde5Eqbp+bCKIvMWnambh9DRUyjrBBZo5dA1o32zpuFBrJd\nI8dmUpw9gtf0F0Ba8lGZm8Uqc0GyXeXOJUE2u7CiMu3M77BM6ZLLTcow5+bQImkmTL1SGhzwfinM\nE1e6p3Hm//pDjuJvFaY22k05LgLuyqc59vFiB3Toldz8+AbMNjvzAwIDAQABAoIBAH3KeJZL2hhI\n/1GXNMaU/PfDgFkgmYbxMA8JKusnm/SFjxAwBGnGI6UjBXpBgpQs2Nqm3ZseF9u8hmCKvGiCEX2G\nesCo2mSfmSQxD6RBrMTuQ99UXpxzBIscFnM/Zrs8lPBARGzmF2nI3qPxXtex4ABX5o0Cd4NfZlZj\npj96skUoO8+bd3I4OPUFYFFFuv81LoSQ6Hew0a8xtJXtKkDp9h1jTGGUOc189WACNoBLH0MGeVoS\nUfc1++RcC3cypUZ8fNP1OO6GBfv06f5oXES4ZbxGYpa+nCfNwb6V2gWbkvaYm7aFn0KWGNZXS1P3\nOcWv6IWdOmg2CI7MMBLJ0LyWVCECgYEAyMJYw195mvHl8VyxJ3HkxeQaaozWL4qhNQ0Kaw+mzD+j\nYdkbHb3aBYghsgEDZjnyOVblC7I+4smvAZJLWJaf6sZ5HAw3zmj1ibCkXx7deoRc/QVcOikl3dE/\nymO0KGJNiGzJZmxbRS3hTokmVPuxSWW4p5oSiMupFHKa18Uv8DECgYEAwkJ7iTOUL6b4e3lQuHQn\nJbsiQpd+P/bsIPP7kaaHObewfHpfOOtIdtN4asxVFf/PgW5uWmBllqAHZYR14DEYIdL+hdLrdvk5\nnYQ3YfhOnp+haHUPCdEiXrRZuGXjmMA4V0hL3HPF5ZM8H80fLnN8Pgn2rIC7CZQ46y4PnoV1nXMC\ngYBBwCUCF8rkDEWa/ximKo8aoNJmAypC98xEa7j1x3KBgnYoHcrbusok9ajTe7F5UZEbZnItmnsu\nG4/Nm/RBV1OYuNgBb573YzjHl6q93IX9EkzCMXc7NS7JrzaNOopOj6OFAtwTR3m89oHMDu8W9jfi\nKgaIHdXkJ4+AuugrstE4gQKBgFK0d1/8g7SeA+Cdz84YNaqMt5NeaDPXbsTA23QxUBU0rYDxoKTd\nFybv9a6SfA83sCLM31K/A8FTNJL2CDGA9WNBL3fOSs2GYg88AVBGpUJHeDK+0748OcPUSPaG+pVI\nETSn5RRgffq16r0nWYUvSdAn8cuTqw3y+yC1pZS6AU8dAoGBAL5QCi0dTWKN3kf3cXaCAnYiWe4Q\ng2S+SgLE+F1U4Xws2rqAuSvIiuT5i5+Mqk9ZCGdoReVbAovJFoRqe7Fj9yWM+b1awGjL0bOTtnqx\n0iljob6uFyhpl1xgW3a3ICJ/ZYLvkgb4IBEteOwWpp37fX57vzhW8EmUV2UX7ve1uNRI'.decode('base64') +x=RSAPrivateKey(k) + += Key class : key version +x.version == ASN1_INTEGER(0L) + += Key class : key modulus +x.modulus == ASN1_INTEGER(19231328316532061413420367242571475005688288081144416166988378525696075445024135424022026378563116068168327239354659928492979285632474448448624869172454076124150405352043642781483254546569202103296262513098482624188672299255268092629150366527784294463900039290024710152521604731213565912934889752122898104556895316819303096201441834849255370122572613047779766933573375974464479123135292080801384304131606933504677232323037116557327478512106367095125103346134248056463878553619525193565824925835325216545121044922690971718737998420984924512388011040969150550056783451476150234324593710633552558175109683813482739004163L) + += Key class : key public exponent +x.publicExponent == ASN1_INTEGER(65537L) + += Key class : key private exponent +x.privateExponent == ASN1_INTEGER(15879630313397508329451198152673380989865598204237760057319927734227125481903063742175442230739018051313441697936698689753842471306305671266572085925009572141819112648211571007521954312641597446020984266846581125287547514750428503480880603089110687015181510081018160579576523796170439894692640171752302225125980423560965987469457505107324833137678663960560798216976668670722016960863268272661588745006387723814962668678285659376534048525020951633874488845649968990679414325096323920666486328886913648207836459784281744709948801682209478580185160477801656666089536527545026197569990716720623647770979759861119273292833L) + += Key class : key prime1 +x.prime1 == ASN1_INTEGER(140977881300857803928857666115326329496639762170623218602431133528876162476487960230341078724702018316260690172014674492782486113504117653531825010840338251572887403113276393351318549036549656895326851872473595350667293402676143426484331639796163189182788306480699144107905869179435145810212051656274284113969L) + += Key class : key prime2 +x.prime2 == ASN1_INTEGER(136413798668820291889092636919077529673097927884427227010121877374504825870002258140616512268521246045642663981036167305976907058413796938050224182519965099316625879807962173794483933183111515251808827349718943344770056106787713032506379905031673992574818291891535689493330517205396872699985860522390496583027L) + += Key class : key exponent1 +x.exponent1 == ASN1_INTEGER(46171616708754015342920807261537213121074749458020000367465429453038710215532257783908950878847126373502288079285334594398328912526548076894076506899568491565992572446455658740752572386903609191774044411412991906964352741123956581870694330173563737928488765282233340389888026245745090096745219902501964298369L) + += Key class : key exponent2 +x.exponent2 == ASN1_INTEGER(58077388505079936284685944662039782610415160654764308528562806086690474868010482729442634318267235411531220690585030443434512729356878742778542733733189895801341155353491318998637269079682889033003797865508917973141494201620317820971253064836562060222814287812344611566640341960495346782352037479526674026269L) + += Key class : key coefficient +x.coefficient == ASN1_INTEGER(133642091354977099805228515340626956943759840737228695249787077343495440064451558090846230978708992851702164116059746794777336918772240719297253693109788134358485382183551757562334253896010728509892421673776502933574360356472723011839127418477652997263867089539752161307227878233961465798519818890416647361608L) + + +########### Cert class ############################################## + ++ X509_Cert class tests += Cert class : Importing DER encoded X.509 Certificate with RSA public key +c='MIIFEjCCA/qgAwIBAgIJALRecEPnCQtxMA0GCSqGSIb3DQEBBQUAMIG2MQswCQYDVQQGEwJGUjEO\nMAwGA1UECBMFUGFyaXMxDjAMBgNVBAcTBVBhcmlzMRcwFQYDVQQKEw5NdXNocm9vbSBDb3JwLjEe\nMBwGA1UECxMVTXVzaHJvb20gVlBOIFNlcnZpY2VzMSUwIwYDVQQDExxJS0V2MiBYLjUwOSBUZXN0\nIGNlcnRpZmljYXRlMScwJQYJKoZIhvcNAQkBFhhpa2V2Mi10ZXN0QG11c2hyb29tLmNvcnAwHhcN\nMDYwNzEzMDczODU5WhcNMjYwMzMwMDczODU5WjCBtjELMAkGA1UEBhMCRlIxDjAMBgNVBAgTBVBh\ncmlzMQ4wDAYDVQQHEwVQYXJpczEXMBUGA1UEChMOTXVzaHJvb20gQ29ycC4xHjAcBgNVBAsTFU11\nc2hyb29tIFZQTiBTZXJ2aWNlczElMCMGA1UEAxMcSUtFdjIgWC41MDkgVGVzdCBjZXJ0aWZpY2F0\nZTEnMCUGCSqGSIb3DQEJARYYaWtldjItdGVzdEBtdXNocm9vbS5jb3JwMIIBIjANBgkqhkiG9w0B\nAQEFAAOCAQ8AMIIBCgKCAQEAmFdqP+nTEZukS0lLP+yj1gNImsEIf7P2ySTunceYxwkm4VE5QReD\nbb2L5/HLA9pPmIeQLSq/BgO1meOcbOSJ2YVHQ28MQ56+8Crb6n28iycX4hp0H3AxRAjh0edX+q3y\nilvYJ4W9/NnIb/wAZwS0oJif/tTkVF77HybAfJde5Eqbp+bCKIvMWnambh9DRUyjrBBZo5dA1o32\nzpuFBrJdI8dmUpw9gtf0F0Ba8lGZm8Uqc0GyXeXOJUE2u7CiMu3M77BM6ZLLTcow5+bQImkmTL1S\nGhzwfinME1e6p3Hm//pDjuJvFaY22k05LgLuyqc59vFiB3Toldz8+AbMNjvzAwIDAQABo4IBHzCC\nARswHQYDVR0OBBYEFPPYTt6Q9+Zd0s4zzVxWjG+XFDFLMIHrBgNVHSMEgeMwgeCAFPPYTt6Q9+Zd\n0s4zzVxWjG+XFDFLoYG8pIG5MIG2MQswCQYDVQQGEwJGUjEOMAwGA1UECBMFUGFyaXMxDjAMBgNV\nBAcTBVBhcmlzMRcwFQYDVQQKEw5NdXNocm9vbSBDb3JwLjEeMBwGA1UECxMVTXVzaHJvb20gVlBO\nIFNlcnZpY2VzMSUwIwYDVQQDExxJS0V2MiBYLjUwOSBUZXN0IGNlcnRpZmljYXRlMScwJQYJKoZI\nhvcNAQkBFhhpa2V2Mi10ZXN0QG11c2hyb29tLmNvcnCCCQC0XnBD5wkLcTAMBgNVHRMEBTADAQH/\nMA0GCSqGSIb3DQEBBQUAA4IBAQA2zt0BvXofiVvHMWlftZCstQaawej1SmxrAfDB4NUM24NsG+UZ\nI88XA5XM6QolmfyKnNromMLC1+6CaFxjq3jC/qdS7ifalFLQVo7ik/te0z6Olo0RkBNgyagWPX2L\nR5kHe9RvSDuoPIsbSHMmJA98AZwatbvEhmzMINJNUoHVzhPeHZnIaBgUBg02XULk/ElidO51Rf3g\nh8dR/kgFQSQT687vs1x9TWD00z0Q2bs2UF3Ob3+NYkEGEo5F9RePQm0mY94CT2xs6WpHo060Fo7f\nVpAFktMWx1vpu+wsEbQAhgGqV0fCR2QwKDIbTrPW/p9HJtJDYVjYdAFxr3s7V77y'.decode('base64') +x=X509_Cert(c) + += Cert class : Rebuild certificate +str(x) == c + += Cert class : Version +tbs = x.tbsCertificate +tbs.version == ASN1_INTEGER(2L) + += Cert class : Serial +tbs.serialNumber == ASN1_INTEGER(0xb45e7043e7090b71) + += Cert class : Signature algorithm (as advertised by TBSCertificate) +assert(type(tbs.signature) is X509_AlgorithmIdentifier) +tbs.signature.algorithm == ASN1_OID("sha1-with-rsa-signature") + += Cert class : Issuer structure +assert(type(tbs.issuer) is list) +assert(len(tbs.issuer) == 7) +assert(type(tbs.issuer[0]) is X509_RDN) +assert(type(tbs.issuer[0].rdn) is list) +assert(type(tbs.issuer[0].rdn[0]) is X509_AttributeTypeAndValue) + += Cert class : Issuer first attribute +tbs.issuer[0].rdn[0].type == ASN1_OID("countryName") and tbs.issuer[0].rdn[0].value == ASN1_PRINTABLE_STRING("FR") + += Cert class : Issuer string +tbs.get_issuer_str() == '/C=FR/ST=Paris/L=Paris/O=Mushroom Corp./OU=Mushroom VPN Services/CN=IKEv2 X.509 Test certificate/emailAddress=ikev2-test@mushroom.corp' + += Cert class : Validity +assert(type(tbs.validity) is X509_Validity) +tbs.validity.not_before == ASN1_UTC_TIME("060713073859Z") and tbs.validity.not_after == ASN1_UTC_TIME("260330073859Z") + += Cert class : Subject structure +assert(type(tbs.subject) is list) +assert(len(tbs.subject) == 7) +assert(type(tbs.subject[0]) is X509_RDN) +assert(type(tbs.subject[0].rdn) is list) +assert(type(tbs.subject[0].rdn[0]) is X509_AttributeTypeAndValue) + += Cert class : Subject last attribute +tbs.issuer[6].rdn[0].type == ASN1_OID("emailAddress") and tbs.issuer[6].rdn[0].value == ASN1_IA5_STRING("ikev2-test@mushroom.corp") + += Cert class : Subject string +tbs.get_subject_str() == '/C=FR/ST=Paris/L=Paris/O=Mushroom Corp./OU=Mushroom VPN Services/CN=IKEv2 X.509 Test certificate/emailAddress=ikev2-test@mushroom.corp' + += Cert class : SubjectPublicKey algorithm +assert(type(tbs.subjectPublicKeyInfo) is X509_SubjectPublicKeyInfo) +spki = tbs.subjectPublicKeyInfo +spki.signatureAlgorithm.algorithm == ASN1_OID("rsaEncryption") + += Cert class : SubjectPublicKey value +assert(type(spki.subjectPublicKey) is RSAPublicKey) +spki.subjectPublicKey.modulus == ASN1_INTEGER(19231328316532061413420367242571475005688288081144416166988378525696075445024135424022026378563116068168327239354659928492979285632474448448624869172454076124150405352043642781483254546569202103296262513098482624188672299255268092629150366527784294463900039290024710152521604731213565912934889752122898104556895316819303096201441834849255370122572613047779766933573375974464479123135292080801384304131606933504677232323037116557327478512106367095125103346134248056463878553619525193565824925835325216545121044922690971718737998420984924512388011040969150550056783451476150234324593710633552558175109683813482739004163L) and spki.subjectPublicKey.publicExponent == ASN1_INTEGER(65537L) + += Cert class : Extensions structure +ext = tbs.extensions +assert(type(ext) is list) +assert(len(ext) == 3) + += Cert class : Subject key identifier extension info +assert(type(ext[0]) is X509_Extension) +ext[0].extnID == ASN1_OID("subjectKeyIdentifier") and ext[0].critical == None + += Cert class : Subject key identifier extension value +assert(type(ext[0].extnValue) is X509_ExtSubjectKeyIdentifier) +ext[0].extnValue.keyIdentifier == ASN1_STRING('\xf3\xd8N\xde\x90\xf7\xe6]\xd2\xce3\xcd\\V\x8co\x97\x141K') + += Cert class : Signature algorithm +assert(type(x.signatureAlgorithm) is X509_AlgorithmIdentifier) +x.signatureAlgorithm.algorithm == ASN1_OID("sha1-with-rsa-signature") + += Cert class : Signature value +x.signatureValue == ASN1_BIT_STRING("6\xce\xdd\x01\xbdz\x1f\x89[\xc71i_\xb5\x90\xac\xb5\x06\x9a\xc1\xe8\xf5Jlk\x01\xf0\xc1\xe0\xd5\x0c\xdb\x83l\x1b\xe5\x19#\xcf\x17\x03\x95\xcc\xe9\n%\x99\xfc\x8a\x9c\xda\xe8\x98\xc2\xc2\xd7\xee\x82h\\c\xabx\xc2\xfe\xa7R\xee'\xda\x94R\xd0V\x8e\xe2\x93\xfb^\xd3>\x8e\x96\x8d\x11\x90\x13`\xc9\xa8\x16=}\x8bG\x99\x07{\xd4oH;\xa8<\x8b\x1bHs&$\x0f|\x01\x9c\x1a\xb5\xbb\xc4\x86l\xcc \xd2MR\x81\xd5\xce\x13\xde\x1d\x99\xc8h\x18\x14\x06\r6]B\xe4\xfcIbt\xeeuE\xfd\xe0\x87\xc7Q\xfeH\x05A$\x13\xeb\xce\xef\xb3\\}M`\xf4\xd3=\x10\xd9\xbb6P]\xceo\x7f\x8dbA\x06\x12\x8eE\xf5\x17\x8fBm&c\xde\x02Oll\xe9jG\xa3N\xb4\x16\x8e\xdfV\x90\x05\x92\xd3\x16\xc7[\xe9\xbb\xec,\x11\xb4\x00\x86\x01\xaaWG\xc2Gd0(2\x1bN\xb3\xd6\xfe\x9fG&\xd2CaX\xd8t\x01q\xaf{;W\xbe\xf2", readable=True) + += Cert class : Default X509_Cert from scratch +str(X509_Cert(str(X509_Cert()))) == str(X509_Cert()) + + +############ CRL class ############################################### + ++ X509_CRL class tests += CRL class : Importing DER encoded X.509 CRL +c='MIICHjCCAYcwDQYJKoZIhvcNAQEFBQAwXzELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWdu\nLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAxIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0\naG9yaXR5Fw0wNjExMDIwMDAwMDBaFw0wNzAyMTcyMzU5NTlaMIH2MCECECzSS2LEl6QXzW6jyJx6\nLcgXDTA0MDQwMTE3NTYxNVowIQIQOkXeVssCzdzcTndjIhvU1RcNMDEwNTA4MTkyMjM0WjAhAhBB\nXYg2gRUg1YCDRqhZkngsFw0wMTA3MDYxNjU3MjNaMCECEEc5gf/9hIHxlfnrGMJ8DfEXDTAzMDEw\nOTE4MDYxMlowIQIQcFR+auK62HZ/R6mZEEFeZxcNMDIwOTIzMTcwMDA4WjAhAhB+C13eGPI5ZoKm\nj2UiOCPIFw0wMTA1MDgxOTA4MjFaMCICEQDQVEhgGGfTrTXKLw1KJ5VeFw0wMTEyMTExODI2MjFa\nMA0GCSqGSIb3DQEBBQUAA4GBACLJ9rsdoaU9JMf/sCIRs3AGW8VV3TN2oJgiCGNEac9PRyV3mRKE\n0hmuIJTKLFSaa4HSAzimWpWNKuJhztsZzXUnWSZ8VuHkgHEaSbKqzUlb2g+o/848CvzJrcbeyEBk\nDCYJI5C3nLlQA49LGJ+w4GUPYBwaZ+WFxCX1C8kzglLm'.decode('base64') +x=X509_CRL(c) + += CRL class : Rebuild crl +str(x) == c + += CRL class : Version +tbs = x.tbsCertList +tbs.version == None + += CRL class : Signature algorithm (as advertised by TBSCRLificate) +assert(type(tbs.signature) is X509_AlgorithmIdentifier) +tbs.signature.algorithm == ASN1_OID("sha1-with-rsa-signature") + += CRL class : Issuer structure +assert(type(tbs.issuer) is list) +assert(len(tbs.issuer) == 3) +assert(type(tbs.issuer[0]) is X509_RDN) +assert(type(tbs.issuer[0].rdn) is list) +assert(type(tbs.issuer[0].rdn[0]) is X509_AttributeTypeAndValue) + += CRL class : Issuer first attribute +tbs.issuer[0].rdn[0].type == ASN1_OID("countryName") and tbs.issuer[0].rdn[0].value == ASN1_PRINTABLE_STRING("US") + += CRL class : Issuer string +tbs.get_issuer_str() == '/C=US/O=VeriSign, Inc./OU=Class 1 Public Primary Certification Authority' + += CRL class : This update +tbs.this_update == ASN1_UTC_TIME("061102000000Z") + += CRL class : Optional next update +tbs.next_update == ASN1_UTC_TIME("070217235959Z") + += CRL class : Optional revoked_certificates structure +assert(type(tbs.revokedCertificates) is list) +assert(len(tbs.revokedCertificates) == 7) +assert(type(tbs.revokedCertificates[0]) is X509_RevokedCertificate) + += CRL class : Revoked_certificates first attribute +tbs.revokedCertificates[0].serialNumber == ASN1_INTEGER(59577943160751197113872490992424857032L) and tbs.revokedCertificates[0].revocationDate == ASN1_UTC_TIME("040401175615Z") + += CRL class : Extensions structure +tbs.crlExtensions == None + += CRL class : Signature algorithm +assert(type(x.signatureAlgorithm) is X509_AlgorithmIdentifier) +x.signatureAlgorithm.algorithm == ASN1_OID("sha1-with-rsa-signature") + += CRL class : Signature value +x.signatureValue == ASN1_BIT_STRING('"\xc9\xf6\xbb\x1d\xa1\xa5=$\xc7\xff\xb0"\x11\xb3p\x06[\xc5U\xdd3v\xa0\x98"\x08cDi\xcfOG%w\x99\x12\x84\xd2\x19\xae \x94\xca,T\x9ak\x81\xd2\x038\xa6Z\x95\x8d*\xe2a\xce\xdb\x19\xcdu\'Y&|V\xe1\xe4\x80q\x1aI\xb2\xaa\xcdI[\xda\x0f\xa8\xff\xce<\n\xfc\xc9\xad\xc6\xde\xc8@d\x0c&\t#\x90\xb7\x9c\xb9P\x03\x8fK\x18\x9f\xb0\xe0e\x0f`\x1c\x1ag\xe5\x85\xc4%\xf5\x0b\xc93\x82R\xe6', readable=True) + += CRL class : Default X509_CRL from scratch +str(X509_CRL(str(X509_CRL()))) == str(X509_CRL()) + +