def sign(self,data, dad=False, nonce=None): """sign the data with RSA signature option, adds timestamp, nonce, etc. Data must be a valid NS, NA, RS, RA or ICMPv6 redirect packet""" ndp_msg = IPv6(data) if dad and ndp_msg[IPv6].src != "::" : raise AddressException("tried to sign a DAD message with the null address") elif not dad and ndp_msg[IPv6].src != self.__address: raise AddressException("tried to sign a message with an incorrect source address") if not ndp_msg.haslayer(ICMPv6ND_RS) \ and not ndp_msg.haslayer(ICMPv6ND_RA) \ and not ndp_msg.haslayer(ICMPv6ND_NS) \ and not ndp_msg.haslayer(ICMPv6ND_NA) \ and not ndp_msg.haslayer(ICMPv6ND_Redirect) : raise AddressException("tried to sign a packet that is not a NDP message") # TODO: # for now, we only take the first algorithm of the list, # latter, we will implement a round-robin mechanism nc = NeighCache() ( sign, verif ) = nc.get_ssao(ndp_msg.dst) neigh_sigalg = (sign + verif) sigtypeID = self.sign_doable(neigh_sigalg) if sigtypeID == None: if NDprotector.ECCsupport and isinstance(self.__key,ECCkey): sigtypeID = self.__key.get_sigtypeID()[0] warn("No matching Signature Algorithm to sign the message, using %s\n" \ % SigTypeID[sigtypeID]) else: warn("No matching Signature Algorithm to sign the message, using RSA/SHA-1\n") sigtypeID = 0 cgapds = CGAParams(modifier = pkcs_i2osp(self.__modifier, 16), \ prefix = self.__prefix, \ ccount = self.__collcount, \ pubkey = self.__pubkey, \ ext = self.__ext) # in some case, we may not really want to add a nonce value if nonce is None: # no nonce value are joined with this message ndp_msg /= ICMPv6NDOptCGA(cgaparams = cgapds) / \ ICMPv6NDOptTimestamp() else: # add the different options to a message ndp_msg /= ICMPv6NDOptCGA(cgaparams = cgapds) / \ ICMPv6NDOptTimestamp() / \ ICMPv6NDOptNonce(nonce=nonce) # compute the available Signature Algorithms sigalgs = SigAlgList_compute(sigtypeID, NDprotector.SignatureAlgorithms) ndp_msg /= ICMPv6NDOptSSA(sigalgs=sigalgs) # dirty hack: force the update of the payload length extra_payload_len = len(str(ndp_msg.getlayer(ICMPv6NDOptCGA))) ndp_msg[IPv6].plen += extra_payload_len # dirty hack: force to recompute the (ICMP) checksum del(ndp_msg[IPv6].payload.cksum) # freezing data inside the new option fields ndp_msg = IPv6(str(ndp_msg)) # need to bind the key hash with address' PubKey pubkey = load_pkey(self.__key, NDprotector.ECCsupport) keyh = get_public_key_hash(pubkey, sigtypeID=sigtypeID) # adding the signature ndp_msg /= ICMPv6NDOptUSSig(key=self.__key, pos = self.__keypos, keyh = keyh, sigtypeID=sigtypeID) # dirty hack: force the update of the payload length extra_payload_len = len(str(ndp_msg.getlayer(ICMPv6NDOptUSSig))) ndp_msg[IPv6].plen += extra_payload_len # dirty hack: force to recompute the (ICMP) checksum (once again) del(ndp_msg[IPv6].payload.cksum) return ndp_msg
def __init__(self,interface=None,\ address=None,prefix=None,\ key=None,modifier=None,sec=None,\ collcount=0, ext=None, keypos=0,\ publickey=None,\ autoconf=False, dad=True,\ ** extrap): """if no interface name is given, we'll use scapy6send to determine a working one and use it""" self.__interface = None self.__address = None self.__prefix = None self.__key = None self.__pubkey = None self.__modifier = 0 self.__collcount = 0 self.__sec = 0 self.__ext = [] self.__keypos = keypos self.__autoconf = autoconf # we can't put ext=[] as a default argument because of its "mutable" nature if ext == None: ext = [] self.__ext = ext plugins = get_plugins_by_capability("Address") for plugin in plugins: plugin.init_address(self,extrap) # time at the beginning of the function beginning = time.time() if not address and not prefix: raise Exception("can not configure an address without at least a prefix") if address and (not key or (not modifier and modifier !=0 )): raise Exception("can not use an address without at least the key and the modifier") if interface == None: warn("no interface name given, using %s\n" % conf.iface) self.__interface = conf.iface else: if interface in get_if_list(): self.__interface = interface else: raise AddressException("No such interface for the address: %s", interface) if collcount >= 0 and collcount <= 3: self.__collcount = collcount else: raise AddressException("The collision counter must be between 0 and 3") if modifier == None: self.__modifier= random.randint(0,2**128 -1) else: self.__modifier= modifier if sec != None: self.__sec=sec else: self.__sec=NDprotector.default_sec_value if prefix: # prefix length is /64 if socket.inet_pton(socket.AF_INET6,prefix)[8:] == \ '\x00'*8 : self.__prefix == prefix else: raise AddressException("prefix %s is not valid" % prefix) # generate a key or use a default one when none is passed if key is None and NDprotector.default_publickey: self.__key = load_key(NDprotector.default_publickey, NDprotector.ECCsupport) self.__pubkey = load_pkey(NDprotector.default_publickey, NDprotector.ECCsupport) elif key is None and not NDprotector.default_publickey: warn("Computing an RSA key pair\n") k = Popen( [ OpenSSL , "genrsa", str(NDprotector.rsa_key_size)], stdout=PIPE, stderr=PIPE) key = k.stdout.read() if not "BEGIN RSA PRIVATE KEY" in key: raise AddressException("unable to compute the RSA public Key") self.__key = Key(key) self.__pubkey = self.__key.toPubKey() # a key was passed else: self.__key = load_key(key, NDprotector.ECCsupport) self.__pubkey = load_pkey(key, NDprotector.ECCsupport) # set the Public Key that will be store in the CGA PDS # in the Public Key field if publickey: self.__pubkey = load_pkey(NDprotector.default_publickey, NDprotector.ECCsupport) if address == None: self.__prefix = prefix warn("Generating CGA\n") if type(modifier) == int: modifier = pkcs_i2osp(modifier,16) res = CGAgen(prefix, self.__pubkey, self.__sec, modifier = modifier, ext=ext, do_dad=False) if type(res) is tuple: (self.__address,param) = res self.__modifier = pkcs_os2ip(param.modifier) else: raise AddressException("failed to create an address, perhaps you should investage on the public key files") else: # we use the address passed in parameter self.__address = address # weak TODO: find something cleaner to extract the prefix from the address self.__prefix = socket.inet_ntop(socket.AF_INET6, \ socket.inet_pton(socket.AF_INET6,address)[:8]+"\x00"*8) modifier = pkcs_i2osp(self.__modifier,16) self.__sec = ord(socket.inet_pton(\ socket.AF_INET6,self.__address)[8]) >> 5 print "About to invoke CGAverify in Address.py, check 1" # jochoi: debug if not CGAverify(self.__address, CGAParams(modifier=modifier, prefix=self.__prefix, \ ccount = self.__collcount, pubkey = self.__pubkey, \ ext = ext)): raise AddressException("Address %s is not a valid CGA" % self.__address) if NDprotector.assign_addresses: self.assign(dad=dad) end = time.time() warn("CGA address %s computed and assigned in %f seconds\n" %\ (self.__address, end - beginning))
def __init__(self,interface=None,\ address=None,prefix=None,\ key=None,modifier=None,sec=None,\ collcount=0, ext=None, keypos=0,\ publickey=None,\ autoconf=False, dad=True,\ ** extrap): """if no interface name is given, we'll use scapy6send to determine a working one and use it""" self.__interface = None self.__address = None self.__prefix = None self.__key = None self.__pubkey = None self.__modifier = 0 self.__collcount = 0 self.__sec = 0 self.__ext = [] self.__keypos = keypos self.__autoconf = autoconf # we can't put ext=[] as a default argument because of its "mutable" nature if ext == None: ext = [] self.__ext = ext plugins = get_plugins_by_capability("Address") for plugin in plugins: plugin.init_address(self,extrap) # time at the beginning of the function beginning = time.time() if not address and not prefix: raise Exception("can not configure an address without at least a prefix") if address and (not key or (not modifier and modifier !=0 )): raise Exception("can not use an address without at least the key and the modifier") if interface == None: warn("no interface name given, using %s\n" % conf.iface) self.__interface = conf.iface else: if interface in get_if_list(): self.__interface = interface else: raise AddressException("No such interface for the address: %s", interface) if collcount >= 0 and collcount <= 3: self.__collcount = collcount else: raise AddressException("The collision counter must be between 0 and 3") if modifier == None: self.__modifier= random.randint(0,2**128 -1) else: self.__modifier= modifier if sec != None: self.__sec=sec else: self.__sec=NDprotector.default_sec_value if prefix: # prefix length is /64 if socket.inet_pton(socket.AF_INET6,prefix)[8:] == \ '\x00'*8 : self.__prefix == prefix else: raise AddressException("prefix %s is not valid" % prefix) # generate a key or use a default one when none is passed if key is None and NDprotector.default_publickey: self.__key = load_key(NDprotector.default_publickey, NDprotector.ECCsupport) self.__pubkey = load_pkey(NDprotector.default_publickey, NDprotector.ECCsupport) elif key is None and not NDprotector.default_publickey: warn("Computing an RSA key pair\n") k = Popen( [ OpenSSL , "genrsa", str(NDprotector.rsa_key_size)], stdout=PIPE, stderr=PIPE) key = k.stdout.read() if not "BEGIN RSA PRIVATE KEY" in key: raise AddressException("unable to compute the RSA public Key") self.__key = Key(key) self.__pubkey = self.__key.toPubKey() # a key was passed else: self.__key = load_key(key, NDprotector.ECCsupport) self.__pubkey = load_pkey(key, NDprotector.ECCsupport) # set the Public Key that will be store in the CGA PDS # in the Public Key field if publickey: self.__pubkey = load_pkey(NDprotector.default_publickey, NDprotector.ECCsupport) if address == None: self.__prefix = prefix warn("Generating CGA\n") if type(modifier) == int: modifier = pkcs_i2osp(modifier,16) res = CGAgen(prefix, self.__pubkey, self.__sec, modifier = modifier, ext=ext, do_dad=False) if type(res) is tuple: (self.__address,param) = res self.__modifier = pkcs_os2ip(param.modifier) else: raise AddressException("failed to create an address, perhaps you should investage on the public key files") else: # we use the address passed in parameter self.__address = address # weak TODO: find something cleaner to extract the prefix from the address self.__prefix = socket.inet_ntop(socket.AF_INET6, \ socket.inet_pton(socket.AF_INET6,address)[:8]+"\x00"*8) modifier = pkcs_i2osp(self.__modifier,16) self.__sec = ord(socket.inet_pton(\ socket.AF_INET6,self.__address)[8]) >> 5 if not CGAverify(self.__address, CGAParams(modifier=modifier, prefix=self.__prefix, \ ccount = self.__collcount, pubkey = self.__pubkey, \ ext = ext)): raise AddressException("Address %s is not a valid CGA" % self.__address) if NDprotector.assign_addresses: self.assign(dad=dad) end = time.time() warn("CGA address %s computed and assigned in %f seconds\n" %\ (self.__address, end - beginning))