class ASN1_Object(six.with_metaclass(ASN1_Object_metaclass)): tag = ASN1_Class_UNIVERSAL.ANY def __init__(self, val): self.val = val def enc(self, codec): return self.tag.get_codec(codec).enc(self.val) def __repr__(self): return "<%s[%r]>" % (self.__dict__.get("name", self.__class__.__name__), self.val) # noqa: E501 def __str__(self): return self.enc(conf.ASN1_default_codec) def __bytes__(self): return self.enc(conf.ASN1_default_codec) def strshow(self, lvl=0): return (" " * lvl) + repr(self) + "\n" def show(self, lvl=0): print(self.strshow(lvl)) def __eq__(self, other): return self.val == other def __lt__(self, other): return self.val < other def __le__(self, other): return self.val <= other def __gt__(self, other): return self.val > other def __ge__(self, other): return self.val >= other def __ne__(self, other): return self.val != other
class PrivKey(six.with_metaclass(_PrivKeyFactory, object)): """ Parent class for both PrivKeyRSA and PrivKeyECDSA. Provides common signTBSCert() and resignCert() methods. """ def signTBSCert(self, tbsCert, h="sha256"): """ Note that this will always copy the signature field from the tbsCertificate into the signatureAlgorithm field of the result, regardless of the coherence between its contents (which might indicate ecdsa-with-SHA512) and the result (e.g. RSA signing MD2). There is a small inheritance trick for the computation of sigVal below: in order to use a sign() method which would apply to both PrivKeyRSA and PrivKeyECDSA, the sign() methods of the subclasses accept any argument, be it from the RSA or ECDSA world, and then they keep the ones they're interested in. Here, t will be passed eventually to pkcs1._DecryptAndSignRSA.sign(). """ sigAlg = tbsCert.signature h = h or hash_by_oid[sigAlg.algorithm.val] sigVal = self.sign(raw(tbsCert), h=h, t='pkcs') c = X509_Cert() c.tbsCertificate = tbsCert c.signatureAlgorithm = sigAlg c.signatureValue = ASN1_BIT_STRING(sigVal, readable=True) return c def resignCert(self, cert): """ Rewrite the signature of either a Cert or an X509_Cert. """ return self.signTBSCert(cert.tbsCertificate) def verifyCert(self, cert): """ Verifies either a Cert or an X509_Cert. """ tbsCert = cert.tbsCertificate sigAlg = tbsCert.signature h = hash_by_oid[sigAlg.algorithm.val] sigVal = raw(cert.signatureValue) return self.verify(raw(tbsCert), sigVal, h=h, t='pkcs')
class _GenericHMAC(six.with_metaclass(_GenericHMACMetaclass, object)): def __init__(self, key=None): self.key = key def digest(self, tbd): if self.key is None: raise HMACError return hmac.new(self.key, tbd, self.hash_alg.hash_cls).digest() def digest_sslv3(self, tbd): if self.key is None: raise HMACError h = self.hash_alg() if h.name == "SHA": pad1 = SSLv3_PAD1_SHA1 pad2 = SSLv3_PAD2_SHA1 elif h.name == "MD5": pad1 = SSLv3_PAD1_MD5 pad2 = SSLv3_PAD2_MD5 else: raise HMACError("Provided hash does not work with SSLv3.") return h.digest(self.key + pad2 + h.digest(self.key + pad1 + tbd))
class _GenericKX(six.with_metaclass(_GenericKXMetaclass)): pass
class _FFDHParams(six.with_metaclass(_FFDHParamsMetaclass)): pass
class BERcodec_Object(six.with_metaclass(BERcodec_metaclass)): codec = ASN1_Codecs.BER tag = ASN1_Class_UNIVERSAL.ANY @classmethod def asn1_object(cls, val): return cls.tag.asn1_object(val) @classmethod def check_string(cls, s): if not s: raise BER_Decoding_Error( "%s: Got empty object while expecting tag %r" % (cls.__name__, cls.tag), remaining=s ) @classmethod def check_type(cls, s): cls.check_string(s) tag, remainder = BER_id_dec(s) if not isinstance(tag, int) or cls.tag != tag: raise BER_BadTag_Decoding_Error( "%s: Got tag [%i/%#x] while expecting %r" % (cls.__name__, tag, tag, cls.tag), remaining=s ) return remainder @classmethod def check_type_get_len(cls, s): s2 = cls.check_type(s) if not s2: raise BER_Decoding_Error("%s: No bytes while expecting a length" % cls.__name__, remaining=s) return BER_len_dec(s2) @classmethod def check_type_check_len(cls, s): l, s3 = cls.check_type_get_len(s) if len(s3) < l: raise BER_Decoding_Error("%s: Got %i bytes while expecting %i" % (cls.__name__, len(s3), l), remaining=s) return l, s3[:l], s3[l:] @classmethod def do_dec(cls, s, context=None, safe=False): if context is None: context = cls.tag.context cls.check_string(s) p, remainder = BER_id_dec(s) if p not in context: t = s if len(t) > 18: t = t[:15] + b"..." raise BER_Decoding_Error("Unknown prefix [%02x] for [%r]" % (p, t), remaining=s) codec = context[p].get_codec(ASN1_Codecs.BER) if codec == BERcodec_Object: # Value type defined as Unknown l, s = BER_num_dec(remainder) return ASN1_BADTAG(s[:l]), s[l:] return codec.dec(s, context, safe) @classmethod def dec(cls, s, context=None, safe=False): if not safe: return cls.do_dec(s, context, safe) try: return cls.do_dec(s, context, safe) except BER_BadTag_Decoding_Error as e: o, remain = BERcodec_Object.dec(e.remaining, context, safe) return ASN1_BADTAG(o), remain except BER_Decoding_Error as e: return ASN1_DECODING_ERROR(s, exc=e), "" except ASN1_Error as e: return ASN1_DECODING_ERROR(s, exc=e), "" @classmethod def safedec(cls, s, context=None): return cls.dec(s, context, safe=True) @classmethod def enc(cls, s): if isinstance(s, six.string_types + (bytes,)): return BERcodec_STRING.enc(s) else: return BERcodec_INTEGER.enc(int(s))
class ASN1_Class(six.with_metaclass(ASN1_Class_metaclass)): pass
class SuperSocket(six.with_metaclass(_SuperSocket_metaclass)): desc = None closed = 0 nonblocking_socket = False read_allowed_exceptions = () def __init__(self, family=socket.AF_INET, type=socket.SOCK_STREAM, proto=0): # noqa: E501 self.ins = socket.socket(family, type, proto) self.outs = self.ins self.promisc = None def send(self, x): sx = raw(x) try: x.sent_time = time.time() except AttributeError: pass return self.outs.send(sx) if six.PY2: def _recv_raw(self, sock, x): """Internal function to receive a Packet""" pkt, sa_ll = sock.recvfrom(x) return pkt, sa_ll, None else: def _recv_raw(self, sock, x): """Internal function to receive a Packet, and process ancillary data. """ flags_len = socket.CMSG_LEN(4096) timestamp = None pkt, ancdata, flags, sa_ll = sock.recvmsg(x, flags_len) if not pkt: return pkt, sa_ll for cmsg_lvl, cmsg_type, cmsg_data in ancdata: # Check available ancillary data if (cmsg_lvl == SOL_PACKET and cmsg_type == PACKET_AUXDATA): # Parse AUXDATA auxdata = tpacket_auxdata.from_buffer_copy(cmsg_data) if auxdata.tp_vlan_tci != 0 or \ auxdata.tp_status & TP_STATUS_VLAN_VALID: # Insert VLAN tag tag = struct.pack("!HH", ETH_P_8021Q, auxdata.tp_vlan_tci) pkt = pkt[:12] + tag + pkt[12:] elif cmsg_lvl == socket.SOL_SOCKET and \ cmsg_type == SO_TIMESTAMPNS: length = len(cmsg_data) if length == 16: # __kernel_timespec tmp = struct.unpack("ll", cmsg_data) elif length == 8: # timespec tmp = struct.unpack("ii", cmsg_data) else: log_runtime.warning("Unknown timespec format.. ?!") continue timestamp = tmp[0] + tmp[1] * 1e-9 return pkt, sa_ll, timestamp def recv_raw(self, x=MTU): """Returns a tuple containing (cls, pkt_data, time)""" return conf.raw_layer, self.ins.recv(x), None def recv(self, x=MTU): cls, val, ts = self.recv_raw(x) if not val or not cls: return try: pkt = cls(val) except KeyboardInterrupt: raise except Exception: if conf.debug_dissector: from scapy.sendrecv import debug debug.crashed_on = (cls, val) raise pkt = conf.raw_layer(val) if ts: pkt.time = ts return pkt def fileno(self): return self.ins.fileno() def close(self): if self.closed: return self.closed = True if getattr(self, "outs", None): if getattr(self, "ins", None) != self.outs: if WINDOWS or self.outs.fileno() != -1: self.outs.close() if getattr(self, "ins", None): if WINDOWS or self.ins.fileno() != -1: self.ins.close() def sr(self, *args, **kargs): from scapy import sendrecv return sendrecv.sndrcv(self, *args, **kargs) def sr1(self, *args, **kargs): from scapy import sendrecv a, b = sendrecv.sndrcv(self, *args, **kargs) if len(a) > 0: return a[0][1] else: return None def sniff(self, *args, **kargs): from scapy import sendrecv return sendrecv.sniff(opened_socket=self, *args, **kargs) def tshark(self, *args, **kargs): from scapy import sendrecv return sendrecv.tshark(opened_socket=self, *args, **kargs) @staticmethod def select(sockets, remain=conf.recv_poll_rate): """This function is called during sendrecv() routine to select the available sockets. :param sockets: an array of sockets that need to be selected :returns: an array of sockets that were selected and the function to be called next to get the packets (i.g. recv) """ try: inp, _, _ = select(sockets, [], [], remain) except (IOError, select_error) as exc: # select.error has no .errno attribute if exc.args[0] != errno.EINTR: raise return inp, None def __del__(self): """Close the socket""" self.close() def __enter__(self): return self def __exit__(self, exc_type, exc_value, traceback): """Close the socket""" self.close()
class Automaton(six.with_metaclass(Automaton_metaclass)): def parse_args(self, debug=0, store=1, **kargs): self.debug_level = debug self.socket_kargs = kargs self.store_packets = store def master_filter(self, pkt): return True def my_send(self, pkt): self.send_sock.send(pkt) ## Utility classes and exceptions class _IO_fdwrapper(SelectableObject): def __init__(self, rd, wr): if WINDOWS: # rd will be used for reading and sending if isinstance(rd, ObjectPipe): self.rd = rd else: raise OSError( "On windows, only instances of ObjectPipe are externally available" ) else: if rd is not None and not isinstance(rd, int): rd = rd.fileno() if wr is not None and not isinstance(wr, int): wr = wr.fileno() self.rd = rd self.wr = wr def fileno(self): return self.rd def check_recv(self): return self.rd.check_recv() def read(self, n=65535): if WINDOWS: return self.rd.recv(n) return os.read(self.rd, n) def write(self, msg): if WINDOWS: self.rd.send(msg) return self.call_release() return os.write(self.wr, msg) def recv(self, n=65535): return self.read(n) def send(self, msg): return self.write(msg) class _IO_mixer(SelectableObject): def __init__(self, rd, wr): self.rd = rd self.wr = wr def fileno(self): if isinstance(self.rd, int): return self.rd return self.rd.fileno() def check_recv(self): return self.rd.check_recv() def recv(self, n=None): return self.rd.recv(n) def read(self, n=None): return self.recv(n) def send(self, msg): self.wr.send(msg) return self.call_release() def write(self, msg): return self.send(msg) class AutomatonException(Exception): def __init__(self, msg, state=None, result=None): Exception.__init__(self, msg) self.state = state self.result = result class AutomatonError(AutomatonException): pass class ErrorState(AutomatonException): pass class Stuck(AutomatonException): pass class AutomatonStopped(AutomatonException): pass class Breakpoint(AutomatonStopped): pass class Singlestep(AutomatonStopped): pass class InterceptionPoint(AutomatonStopped): def __init__(self, msg, state=None, result=None, packet=None): Automaton.AutomatonStopped.__init__(self, msg, state=state, result=result) self.packet = packet class CommandMessage(AutomatonException): pass ## Services def debug(self, lvl, msg): if self.debug_level >= lvl: log_interactive.debug(msg) def send(self, pkt): if self.state.state in self.interception_points: self.debug(3, "INTERCEPT: packet intercepted: %s" % pkt.summary()) self.intercepted_packet = pkt cmd = Message(type=_ATMT_Command.INTERCEPT, state=self.state, pkt=pkt) self.cmdout.send(cmd) cmd = self.cmdin.recv() self.intercepted_packet = None if cmd.type == _ATMT_Command.REJECT: self.debug(3, "INTERCEPT: packet rejected") return elif cmd.type == _ATMT_Command.REPLACE: pkt = cmd.pkt self.debug(3, "INTERCEPT: packet replaced by: %s" % pkt.summary()) elif cmd.type == _ATMT_Command.ACCEPT: self.debug(3, "INTERCEPT: packet accepted") else: raise self.AutomatonError("INTERCEPT: unkown verdict: %r" % cmd.type) self.my_send(pkt) self.debug(3, "SENT : %s" % pkt.summary()) if self.store_packets: self.packets.append(pkt.copy()) ## Internals def __init__(self, *args, **kargs): external_fd = kargs.pop("external_fd", {}) self.send_sock_class = kargs.pop("ll", conf.L3socket) self.recv_sock_class = kargs.pop("recvsock", conf.L2listen) self.started = threading.Lock() self.threadid = None self.breakpointed = None self.breakpoints = set() self.interception_points = set() self.intercepted_packet = None self.debug_level = 0 self.init_args = args self.init_kargs = kargs self.io = type.__new__(type, "IOnamespace", (), {}) self.oi = type.__new__(type, "IOnamespace", (), {}) self.cmdin = ObjectPipe() self.cmdout = ObjectPipe() self.ioin = {} self.ioout = {} for n in self.ionames: extfd = external_fd.get(n) if not isinstance(extfd, tuple): extfd = (extfd, extfd) elif WINDOWS: raise OSError( "Tuples are not allowed as external_fd on windows") ioin, ioout = extfd if ioin is None: ioin = ObjectPipe() elif not isinstance(ioin, types.InstanceType): ioin = self._IO_fdwrapper(ioin, None) if ioout is None: ioout = ioin if WINDOWS else ObjectPipe() elif not isinstance(ioout, types.InstanceType): ioout = self._IO_fdwrapper(None, ioout) self.ioin[n] = ioin self.ioout[n] = ioout ioin.ioname = n ioout.ioname = n setattr(self.io, n, self._IO_mixer(ioout, ioin)) setattr(self.oi, n, self._IO_mixer(ioin, ioout)) for stname in self.states: setattr(self, stname, _instance_state(getattr(self, stname))) self.parse_args(*args, **kargs) self.start() def __iter__(self): return self def __del__(self): self.stop() def _run_condition(self, cond, *args, **kargs): try: self.debug(5, "Trying %s [%s]" % (cond.atmt_type, cond.atmt_condname)) cond(self, *args, **kargs) except ATMT.NewStateRequested as state_req: self.debug( 2, "%s [%s] taken to state [%s]" % (cond.atmt_type, cond.atmt_condname, state_req.state)) if cond.atmt_type == ATMT.RECV: if self.store_packets: self.packets.append(args[0]) for action in self.actions[cond.atmt_condname]: self.debug(2, " + Running action [%s]" % action.__name__) action(self, *state_req.action_args, **state_req.action_kargs) raise except Exception as e: self.debug( 2, "%s [%s] raised exception [%s]" % (cond.atmt_type, cond.atmt_condname, e)) raise else: self.debug( 2, "%s [%s] not taken" % (cond.atmt_type, cond.atmt_condname)) def _do_start(self, *args, **kargs): ready = threading.Event() threading.Thread(target=self._do_control, args=(ready, ) + (args), kwargs=kargs).start() ready.wait() def _do_control(self, ready, *args, **kargs): with self.started: self.threadid = threading.currentThread().ident # Update default parameters a = args + self.init_args[len(args):] k = self.init_kargs.copy() k.update(kargs) self.parse_args(*a, **k) # Start the automaton self.state = self.initial_states[0](self) self.send_sock = self.send_sock_class() self.listen_sock = self.recv_sock_class(**self.socket_kargs) self.packets = PacketList(name="session[%s]" % self.__class__.__name__) singlestep = True iterator = self._do_iter() self.debug(3, "Starting control thread [tid=%i]" % self.threadid) # Sync threads ready.set() try: while True: c = self.cmdin.recv() self.debug(5, "Received command %s" % c.type) if c.type == _ATMT_Command.RUN: singlestep = False elif c.type == _ATMT_Command.NEXT: singlestep = True elif c.type == _ATMT_Command.FREEZE: continue elif c.type == _ATMT_Command.STOP: break while True: state = next(iterator) if isinstance(state, self.CommandMessage): break elif isinstance(state, self.Breakpoint): c = Message(type=_ATMT_Command.BREAKPOINT, state=state) self.cmdout.send(c) break if singlestep: c = Message(type=_ATMT_Command.SINGLESTEP, state=state) self.cmdout.send(c) break except StopIteration as e: c = Message(type=_ATMT_Command.END, result=e.args[0]) self.cmdout.send(c) except Exception as e: exc_info = sys.exc_info() self.debug( 3, "Transfering exception from tid=%i:\n%s" % (self.threadid, traceback.format_exc(exc_info))) m = Message(type=_ATMT_Command.EXCEPTION, exception=e, exc_info=exc_info) self.cmdout.send(m) self.debug(3, "Stopping control thread (tid=%i)" % self.threadid) self.threadid = None def _do_iter(self): while True: try: self.debug(1, "## state=[%s]" % self.state.state) # Entering a new state. First, call new state function if self.state.state in self.breakpoints and self.state.state != self.breakpointed: self.breakpointed = self.state.state yield self.Breakpoint("breakpoint triggered on state %s" % self.state.state, state=self.state.state) self.breakpointed = None state_output = self.state.run() if self.state.error: raise self.ErrorState("Reached %s: [%r]" % (self.state.state, state_output), result=state_output, state=self.state.state) if self.state.final: raise StopIteration(state_output) if state_output is None: state_output = () elif not isinstance(state_output, list): state_output = state_output, # Then check immediate conditions for cond in self.conditions[self.state.state]: self._run_condition(cond, *state_output) # If still there and no conditions left, we are stuck! if (len(self.recv_conditions[self.state.state]) == 0 and len(self.ioevents[self.state.state]) == 0 and len(self.timeout[self.state.state]) == 1): raise self.Stuck("stuck in [%s]" % self.state.state, state=self.state.state, result=state_output) # Finally listen and pay attention to timeouts expirations = iter(self.timeout[self.state.state]) next_timeout, timeout_func = next(expirations) t0 = time.time() fds = [self.cmdin] if len(self.recv_conditions[self.state.state]) > 0: fds.append(self.listen_sock) for ioev in self.ioevents[self.state.state]: fds.append(self.ioin[ioev.atmt_ioname]) while True: t = time.time() - t0 if next_timeout is not None: if next_timeout <= t: self._run_condition(timeout_func, *state_output) next_timeout, timeout_func = next(expirations) if next_timeout is None: remain = None else: remain = next_timeout - t self.debug(5, "Select on %r" % fds) r = select_objects(fds, remain) self.debug(5, "Selected %r" % r) for fd in r: self.debug(5, "Looking at %r" % fd) if fd == self.cmdin: yield self.CommandMessage( "Received command message") elif fd == self.listen_sock: pkt = self.listen_sock.recv(MTU) if pkt is not None: if self.master_filter(pkt): self.debug(3, "RECVD: %s" % pkt.summary()) for rcvcond in self.recv_conditions[ self.state.state]: self._run_condition( rcvcond, pkt, *state_output) else: self.debug(4, "FILTR: %s" % pkt.summary()) else: self.debug(3, "IOEVENT on %s" % fd.ioname) for ioevt in self.ioevents[self.state.state]: if ioevt.atmt_ioname == fd.ioname: self._run_condition( ioevt, fd, *state_output) except ATMT.NewStateRequested as state_req: self.debug( 2, "switching from [%s] to [%s]" % (self.state.state, state_req.state)) self.state = state_req yield state_req ## Public API def add_interception_points(self, *ipts): for ipt in ipts: if hasattr(ipt, "atmt_state"): ipt = ipt.atmt_state self.interception_points.add(ipt) def remove_interception_points(self, *ipts): for ipt in ipts: if hasattr(ipt, "atmt_state"): ipt = ipt.atmt_state self.interception_points.discard(ipt) def add_breakpoints(self, *bps): for bp in bps: if hasattr(bp, "atmt_state"): bp = bp.atmt_state self.breakpoints.add(bp) def remove_breakpoints(self, *bps): for bp in bps: if hasattr(bp, "atmt_state"): bp = bp.atmt_state self.breakpoints.discard(bp) def start(self, *args, **kargs): if not self.started.locked(): self._do_start(*args, **kargs) def run(self, resume=None, wait=True): if resume is None: resume = Message(type=_ATMT_Command.RUN) self.cmdin.send(resume) if wait: try: c = self.cmdout.recv() except KeyboardInterrupt: self.cmdin.send(Message(type=_ATMT_Command.FREEZE)) return if c.type == _ATMT_Command.END: return c.result elif c.type == _ATMT_Command.INTERCEPT: raise self.InterceptionPoint("packet intercepted", state=c.state.state, packet=c.pkt) elif c.type == _ATMT_Command.SINGLESTEP: raise self.Singlestep("singlestep state=[%s]" % c.state.state, state=c.state.state) elif c.type == _ATMT_Command.BREAKPOINT: raise self.Breakpoint("breakpoint triggered on state [%s]" % c.state.state, state=c.state.state) elif c.type == _ATMT_Command.EXCEPTION: six.reraise(c.exc_info[0], c.exc_info[1], c.exc_info[2]) def runbg(self, resume=None, wait=False): self.run(resume, wait) def next(self): return self.run(resume=Message(type=_ATMT_Command.NEXT)) __next__ = next def stop(self): self.cmdin.send(Message(type=_ATMT_Command.STOP)) with self.started: # Flush command pipes while True: r = select_objects([self.cmdin, self.cmdout], 0) if not r: break for fd in r: fd.recv() def restart(self, *args, **kargs): self.stop() self.start(*args, **kargs) def accept_packet(self, pkt=None, wait=False): rsm = Message() if pkt is None: rsm.type = _ATMT_Command.ACCEPT else: rsm.type = _ATMT_Command.REPLACE rsm.pkt = pkt return self.run(resume=rsm, wait=wait) def reject_packet(self, wait=False): rsm = Message(type=_ATMT_Command.REJECT) return self.run(resume=rsm, wait=wait)
class _AEADCipher_TLS13(six.with_metaclass(_AEADCipherMetaclass, object)): """ The hasattr(self, "pc_cls") enable support for the legacy implementation of GCM in the cryptography library. They should not be used, and might eventually be removed, with cryptography v2.0. XXX """ type = "aead" def __init__(self, key=None, fixed_iv=None, nonce_explicit=None): """ 'key' and 'fixed_iv' are to be provided as strings. This IV never changes: it is either the client_write_IV or server_write_IV. Note that 'nonce_explicit' is never used. It is only a safeguard for a call in session.py to the TLS 1.2/ChaCha20Poly1305 case (see RFC 7905). """ self.ready = {"key": True, "fixed_iv": True} if key is None: self.ready["key"] = False key = b"\0" * self.key_len if fixed_iv is None: self.ready["fixed_iv"] = False fixed_iv = b"\0" * self.fixed_iv_len # we use super() in order to avoid any deadlock with __setattr__ super(_AEADCipher_TLS13, self).__setattr__("key", key) super(_AEADCipher_TLS13, self).__setattr__("fixed_iv", fixed_iv) if hasattr(self, "pc_cls"): self._cipher = Cipher(self.pc_cls(key), self.pc_cls_mode(fixed_iv), backend=default_backend()) else: self._cipher = self.cipher_cls(key) def __setattr__(self, name, val): if name == "key": if self._cipher is not None: if hasattr(self, "pc_cls"): self._cipher.algorithm.key = val else: self._cipher._key = val self.ready["key"] = True elif name == "fixed_iv": self.ready["fixed_iv"] = True super(_AEADCipher_TLS13, self).__setattr__(name, val) def _get_nonce(self, seq_num): padlen = self.fixed_iv_len - len(seq_num) padded_seq_num = b"\x00" * padlen + seq_num return strxor(padded_seq_num, self.fixed_iv) def auth_encrypt(self, P, A, seq_num): """ Encrypt the data, and append the computed authentication code. TLS 1.3 does not use additional data, but we leave this option to the user nonetheless. Note that the cipher's authentication tag must be None when encrypting. """ if False in six.itervalues(self.ready): raise CipherError(P, A) if hasattr(self, "pc_cls"): self._cipher.mode._tag = None self._cipher.mode._initialization_vector = self._get_nonce(seq_num) encryptor = self._cipher.encryptor() encryptor.authenticate_additional_data(A) res = encryptor.update(P) + encryptor.finalize() res += encryptor.tag else: if (conf.crypto_valid_advanced and isinstance(self._cipher, AESCCM)): res = self._cipher.encrypt(self._get_nonce(seq_num), P, A, tag_length=self.tag_len) else: res = self._cipher.encrypt(self._get_nonce(seq_num), P, A) return res def auth_decrypt(self, A, C, seq_num): """ Decrypt the data and verify the authentication code (in this order). Note that TLS 1.3 is not supposed to use any additional data A. If the verification fails, an AEADTagError is raised. It is the user's responsibility to catch it if deemed useful. If we lack the key, we raise a CipherError which contains the encrypted input. """ C, mac = C[:-self.tag_len], C[-self.tag_len:] if False in six.itervalues(self.ready): raise CipherError(C, mac) if hasattr(self, "pc_cls"): self._cipher.mode._initialization_vector = self._get_nonce(seq_num) self._cipher.mode._tag = mac decryptor = self._cipher.decryptor() decryptor.authenticate_additional_data(A) P = decryptor.update(C) try: decryptor.finalize() except InvalidTag: raise AEADTagError(P, mac) else: try: if (conf.crypto_valid_advanced and isinstance(self._cipher, AESCCM)): P = self._cipher.decrypt(self._get_nonce(seq_num), C + mac, A, tag_length=self.tag_len) else: if (conf.crypto_valid_advanced and isinstance(self, Cipher_CHACHA20_POLY1305)): A += struct.pack("!H", len(C)) P = self._cipher.decrypt(self._get_nonce(seq_num), C + mac, A) except InvalidTag: raise AEADTagError("<unauthenticated data>", mac) return P, mac def snapshot(self): c = self.__class__(self.key, self.fixed_iv) c.ready = self.ready.copy() return c
class _StreamCipher(six.with_metaclass(_StreamCipherMetaclass, object)): type = "stream" def __init__(self, key=None): """ Note that we have to keep the encryption/decryption state in unique encryptor and decryptor objects. This differs from _BlockCipher. In order to do connection state snapshots, we need to be able to recreate past cipher contexts. This is why we feed _enc_updated_with and _dec_updated_with every time encrypt() or decrypt() is called. """ self.ready = {"key": True} if key is None: self.ready["key"] = False if hasattr(self, "expanded_key_len"): l = self.expanded_key_len else: l = self.key_len key = b"\0" * l # we use super() in order to avoid any deadlock with __setattr__ super(_StreamCipher, self).__setattr__("key", key) self._cipher = Cipher(self.pc_cls(key), mode=None, backend=default_backend()) self.encryptor = self._cipher.encryptor() self.decryptor = self._cipher.decryptor() self._enc_updated_with = b"" self._dec_updated_with = b"" def __setattr__(self, name, val): """ We have to keep the encryptor/decryptor for a long time, however they have to be updated every time the key is changed. """ if name == "key": if self._cipher is not None: self._cipher.algorithm.key = val self.encryptor = self._cipher.encryptor() self.decryptor = self._cipher.decryptor() self.ready["key"] = True super(_StreamCipher, self).__setattr__(name, val) def encrypt(self, data): if False in six.itervalues(self.ready): raise CipherError(data) self._enc_updated_with += data return self.encryptor.update(data) def decrypt(self, data): if False in six.itervalues(self.ready): raise CipherError(data) self._dec_updated_with += data return self.decryptor.update(data) def snapshot(self): c = self.__class__(self.key) c.ready = self.ready.copy() c.encryptor.update(self._enc_updated_with) c.decryptor.update(self._dec_updated_with) c._enc_updated_with = self._enc_updated_with c._dec_updated_with = self._dec_updated_with return c
class _BlockCipher(six.with_metaclass(_BlockCipherMetaclass, object)): type = "block" def __init__(self, key=None, iv=None): self.ready = {"key": True, "iv": True} if key is None: self.ready["key"] = False if hasattr(self, "expanded_key_len"): l = self.expanded_key_len else: l = self.key_len key = b"\0" * l if iv is None or iv == "": self.ready["iv"] = False iv = b"\0" * self.block_size # we use super() in order to avoid any deadlock with __setattr__ super(_BlockCipher, self).__setattr__("key", key) super(_BlockCipher, self).__setattr__("iv", iv) self._cipher = Cipher(self.pc_cls(key), self.pc_cls_mode(iv), backend=backend) def __setattr__(self, name, val): if name == "key": if self._cipher is not None: self._cipher.algorithm.key = val self.ready["key"] = True elif name == "iv": if self._cipher is not None: self._cipher.mode._initialization_vector = val self.ready["iv"] = True super(_BlockCipher, self).__setattr__(name, val) def encrypt(self, data): """ Encrypt the data. Also, update the cipher iv. This is needed for SSLv3 and TLS 1.0. For TLS 1.1/1.2, it is overwritten in TLS.post_build(). """ if False in six.itervalues(self.ready): raise CipherError(data) encryptor = self._cipher.encryptor() tmp = encryptor.update(data) + encryptor.finalize() self.iv = tmp[-self.block_size:] return tmp def decrypt(self, data): """ Decrypt the data. Also, update the cipher iv. This is needed for SSLv3 and TLS 1.0. For TLS 1.1/1.2, it is overwritten in TLS.pre_dissect(). If we lack the key, we raise a CipherError which contains the input. """ if False in six.itervalues(self.ready): raise CipherError(data) decryptor = self._cipher.decryptor() tmp = decryptor.update(data) + decryptor.finalize() self.iv = data[-self.block_size:] return tmp def snapshot(self): c = self.__class__(self.key, self.iv) c.ready = self.ready.copy() return c
class _GenericComp(six.with_metaclass(_GenericCompMetaclass, object)): pass
class SuperSocket(six.with_metaclass(_SuperSocket_metaclass)): desc = None closed = 0 def __init__(self, family=socket.AF_INET, type=socket.SOCK_STREAM, proto=0): # noqa: E501 self.ins = socket.socket(family, type, proto) self.outs = self.ins self.promisc = None def send(self, x): sx = raw(x) if hasattr(x, "sent_time"): x.sent_time = time.time() return self.outs.send(sx) def recv_raw(self, x=MTU): """Returns a tuple containing (cls, pkt_data, time)""" return conf.raw_layer, self.ins.recv(x), None def recv(self, x=MTU): cls, val, ts = self.recv_raw(x) if not val or not cls: return try: pkt = cls(val) except KeyboardInterrupt: raise except Exception: if conf.debug_dissector: raise pkt = conf.raw_layer(val) pkt.time = ts return pkt def fileno(self): return self.ins.fileno() def close(self): if self.closed: return self.closed = True if hasattr(self, "outs"): if not hasattr(self, "ins") or self.ins != self.outs: if self.outs and self.outs.fileno() != -1: self.outs.close() if hasattr(self, "ins"): if self.ins and self.ins.fileno() != -1: self.ins.close() def sr(self, *args, **kargs): from scapy import sendrecv return sendrecv.sndrcv(self, *args, **kargs) def sr1(self, *args, **kargs): from scapy import sendrecv a, b = sendrecv.sndrcv(self, *args, **kargs) if len(a) > 0: return a[0][1] else: return None def sniff(self, *args, **kargs): from scapy import sendrecv return sendrecv.sniff(opened_socket=self, *args, **kargs)
class SuperSocket(six.with_metaclass(_SuperSocket_metaclass)): desc = None closed = 0 nonblocking_socket = False read_allowed_exceptions = () auxdata_available = False def __init__(self, family=socket.AF_INET, type=socket.SOCK_STREAM, proto=0): # noqa: E501 self.ins = socket.socket(family, type, proto) self.outs = self.ins self.promisc = None def send(self, x): sx = raw(x) try: x.sent_time = time.time() except AttributeError: pass return self.outs.send(sx) if six.PY2: def _recv_raw(self, sock, x): """Internal function to receive a Packet""" pkt, sa_ll = sock.recvfrom(x) return pkt, sa_ll, None else: def _recv_raw(self, sock, x): """Internal function to receive a Packet, and process ancillary data. """ timestamp = None if not self.auxdata_available: pkt, _, _, sa_ll = sock.recvmsg(x) return pkt, sa_ll, timestamp flags_len = socket.CMSG_LEN(4096) pkt, ancdata, flags, sa_ll = sock.recvmsg(x, flags_len) if not pkt: return pkt, sa_ll, timestamp for cmsg_lvl, cmsg_type, cmsg_data in ancdata: # Check available ancillary data if (cmsg_lvl == SOL_PACKET and cmsg_type == PACKET_AUXDATA): # Parse AUXDATA try: auxdata = tpacket_auxdata.from_buffer_copy(cmsg_data) except ValueError: # Note: according to Python documentation, recvmsg() # can return a truncated message. A ValueError # exception likely indicates that Auxiliary # Data is not supported by the Linux kernel. return pkt, sa_ll, timestamp if auxdata.tp_vlan_tci != 0 or \ auxdata.tp_status & TP_STATUS_VLAN_VALID: # Insert VLAN tag tag = struct.pack( "!HH", ETH_P_8021Q, auxdata.tp_vlan_tci ) pkt = pkt[:12] + tag + pkt[12:] elif cmsg_lvl == socket.SOL_SOCKET and \ cmsg_type == SO_TIMESTAMPNS: length = len(cmsg_data) if length == 16: # __kernel_timespec tmp = struct.unpack("ll", cmsg_data) elif length == 8: # timespec tmp = struct.unpack("ii", cmsg_data) else: log_runtime.warning("Unknown timespec format.. ?!") continue timestamp = tmp[0] + tmp[1] * 1e-9 return pkt, sa_ll, timestamp def recv_raw(self, x=MTU): """Returns a tuple containing (cls, pkt_data, time)""" return conf.raw_layer, self.ins.recv(x), None def recv(self, x=MTU): cls, val, ts = self.recv_raw(x) if not val or not cls: return try: pkt = cls(val) except KeyboardInterrupt: raise except Exception: if conf.debug_dissector: from scapy.sendrecv import debug debug.crashed_on = (cls, val) raise pkt = conf.raw_layer(val) if ts: pkt.time = ts return pkt def fileno(self): return self.ins.fileno() def close(self): if self.closed: return self.closed = True if getattr(self, "outs", None): if getattr(self, "ins", None) != self.outs: if WINDOWS or self.outs.fileno() != -1: self.outs.close() if getattr(self, "ins", None): if WINDOWS or self.ins.fileno() != -1: self.ins.close() def sr(self, *args, **kargs): from scapy import sendrecv return sendrecv.sndrcv(self, *args, **kargs) def sr1(self, *args, **kargs): from scapy import sendrecv a, b = sendrecv.sndrcv(self, *args, **kargs) if len(a) > 0: return a[0][1] else: return None def sniff(self, *args, **kargs): from scapy import sendrecv return sendrecv.sniff(opened_socket=self, *args, **kargs) def tshark(self, *args, **kargs): from scapy import sendrecv return sendrecv.tshark(opened_socket=self, *args, **kargs) def _command(self, ctor_params): """Internal helper function for implementing the command() method. :param ctor_params: a dict with all parameters passed to the constructor of the class, where a key is the name of the parameter in the constructor and the value is its value """ nv = [] for name, value in six.iteritems(ctor_params): if value is None: continue elif hasattr(value, "__iter__"): try: empty = len(value) == 0 except TypeError: empty = False if empty: continue if name == "basecls": value = ( value.__name__ if hasattr(value, "__name__") else value.__class__.__name__ ) elif hasattr(value, "command"): value = value.command() else: value = repr(value) nv.append("%s=%s" % (name, value)) return "%s(%s)" % (type(self).__name__, ", ".join(nv)) def command(self): """Returns a string representing the command you have to type to obtain the same socket. """ raise NotImplementedError() @staticmethod def select(sockets, remain=conf.recv_poll_rate): """This function is called during sendrecv() routine to select the available sockets. :param sockets: an array of sockets that need to be selected :returns: an array of sockets that were selected and the function to be called next to get the packets (i.g. recv) """ try: inp, _, _ = select(sockets, [], [], remain) except (IOError, select_error) as exc: # select.error has no .errno attribute if not exc.args or exc.args[0] != errno.EINTR: raise return inp, None def __del__(self): """Close the socket""" self.close() def __enter__(self): return self def __exit__(self, exc_type, exc_value, traceback): """Close the socket""" self.close()
class AnsweringMachine(six.with_metaclass(ReferenceAM, object)): function_name = "" filter = None sniff_options = {"store": 0} sniff_options_list = [ "store", "iface", "count", "promisc", "filter", "type", "prn", "stop_filter" ] send_options = {"verbose": 0} send_options_list = ["iface", "inter", "loop", "verbose"] send_function = staticmethod(send) def __init__(self, **kargs): self.mode = 0 if self.filter: kargs.setdefault("filter", self.filter) kargs.setdefault("prn", self.reply) self.optam1 = {} self.optam2 = {} self.optam0 = {} doptsend, doptsniff = self.parse_all_options(1, kargs) self.defoptsend = self.send_options.copy() self.defoptsend.update(doptsend) self.defoptsniff = self.sniff_options.copy() self.defoptsniff.update(doptsniff) self.optsend, self.optsniff = [{}, {}] def __getattr__(self, attr): for d in [self.optam2, self.optam1]: if attr in d: return d[attr] raise AttributeError(attr) def __setattr__(self, attr, val): mode = self.__dict__.get("mode", 0) if mode == 0: self.__dict__[attr] = val else: [self.optam1, self.optam2][mode - 1][attr] = val def parse_options(self): pass def parse_all_options(self, mode, kargs): sniffopt = {} sendopt = {} for k in list(kargs): # use list(): kargs is modified in the loop if k in self.sniff_options_list: sniffopt[k] = kargs[k] if k in self.send_options_list: sendopt[k] = kargs[k] if k in self.sniff_options_list + self.send_options_list: del kargs[k] if mode != 2 or kargs: if mode == 1: self.optam0 = kargs elif mode == 2 and kargs: k = self.optam0.copy() k.update(kargs) self.parse_options(**k) kargs = k omode = self.__dict__.get("mode", 0) self.__dict__["mode"] = mode self.parse_options(**kargs) self.__dict__["mode"] = omode return sendopt, sniffopt def is_request(self, req): return 1 def make_reply(self, req): return req def send_reply(self, reply): self.send_function(reply, **self.optsend) def print_reply(self, req, reply): print("%s ==> %s" % (req.summary(), reply.summary())) def reply(self, pkt): if not self.is_request(pkt): return reply = self.make_reply(pkt) self.send_reply(reply) if conf.verb >= 0: self.print_reply(pkt, reply) def run(self, *args, **kargs): log_interactive.warning( "run() method deprecated. The instance is now callable") self(*args, **kargs) def __call__(self, *args, **kargs): optsend, optsniff = self.parse_all_options(2, kargs) self.optsend = self.defoptsend.copy() self.optsend.update(optsend) self.optsniff = self.defoptsniff.copy() self.optsniff.update(optsniff) try: self.sniff() except KeyboardInterrupt: print("Interrupted by user") def sniff(self): sniff(**self.optsniff)
class Pipe(six.with_metaclass(_PipeMeta, _ConnectorLogic)): def __init__(self, name=None): _ConnectorLogic.__init__(self) if name is None: name = "%s" % (self.__class__.__name__) self.name = name def _send(self, msg): for s in self.sinks: s.push(msg) def _high_send(self, msg): for s in self.high_sinks: s.high_push(msg) def _trigger(self, msg=None): for s in self.trigger_sinks: s.on_trigger(msg) def __repr__(self): ct = conf.color_theme s = "%s%s" % (ct.punct("<"), ct.layer_name(self.name)) if self.sources or self.sinks: s += " %s" % ct.punct("[") if self.sources: s += "%s%s" % ( ct.punct(",").join( ct.field_name(s.name) for s in self.sources), # noqa: E501 ct.field_value(">")) s += ct.layer_name("#") if self.sinks: s += "%s%s" % (ct.field_value(">"), ct.punct(",").join( ct.field_name(s.name) for s in self.sinks)) # noqa: E501 s += ct.punct("]") if self.high_sources or self.high_sinks: s += " %s" % ct.punct("[") if self.high_sources: s += "%s%s" % ( ct.punct(",").join( ct.field_name(s.name) for s in self.high_sources), # noqa: E501 ct.field_value(">>")) s += ct.layer_name("#") if self.high_sinks: s += "%s%s" % (ct.field_value(">>"), ct.punct(",").join( ct.field_name(s.name) for s in self.high_sinks)) # noqa: E501 s += ct.punct("]") if self.trigger_sources or self.trigger_sinks: s += " %s" % ct.punct("[") if self.trigger_sources: s += "%s%s" % ( ct.punct(",").join( ct.field_name(s.name) for s in self.trigger_sources), # noqa: E501 ct.field_value("^")) s += ct.layer_name("#") if self.trigger_sinks: s += "%s%s" % (ct.field_value("^"), ct.punct(",").join( ct.field_name(s.name) for s in self.trigger_sinks)) # noqa: E501 s += ct.punct("]") s += ct.punct(">") return s
class RawPcapReader(six.with_metaclass(PcapReader_metaclass)): """A stateful pcap reader. Each packet is returned as a string""" def __init__(self, filename, fdesc, magic): self.filename = filename self.f = fdesc if magic == b"\xa1\xb2\xc3\xd4": # big endian self.endian = ">" self.nano = False elif magic == b"\xd4\xc3\xb2\xa1": # little endian self.endian = "<" self.nano = False elif magic == b"\xa1\xb2\x3c\x4d": # big endian, nanosecond-precision self.endian = ">" self.nano = True elif magic == b"\x4d\x3c\xb2\xa1": # little endian, nanosecond-precision self.endian = "<" self.nano = True else: raise Scapy_Exception( "Not a pcap capture file (bad magic: %r)" % magic ) hdr = self.f.read(20) if len(hdr)<20: raise Scapy_Exception("Invalid pcap file (too short)") vermaj, vermin, tz, sig, snaplen, linktype = struct.unpack( self.endian + "HHIIII", hdr ) self.linktype = linktype def __iter__(self): return self def next(self): """implement the iterator protocol on a set of packets in a pcap file""" pkt = self.read_packet() if pkt == None: raise StopIteration return pkt __next__ = next def read_packet(self, size=MTU): """return a single packet read from the file returns None when no more packets are available """ hdr = self.f.read(16) if len(hdr) < 16: return None sec,usec,caplen,wirelen = struct.unpack(self.endian+"IIII", hdr) s = self.f.read(caplen)[:size] return s,(sec,usec,wirelen) # caplen = len(s) def dispatch(self, callback): """call the specified callback routine for each packet read This is just a convenience function for the main loop that allows for easy launching of packet processing in a thread. """ for p in self: callback(p) def read_all(self,count=-1): """return a list of all packets in the pcap file """ res=[] while count != 0: count -= 1 p = self.read_packet() if p is None: break res.append(p) return res def recv(self, size=MTU): """ Emulate a socket """ return self.read_packet(size=size)[0] def fileno(self): return self.f.fileno() def close(self): return self.f.close() def __enter__(self): return self def __exit__(self, exc_type, exc_value, tracback): self.close()
class Cert(six.with_metaclass(_CertMaker, object)): """ Wrapper for the X509_Cert from layers/x509.py. Use the 'x509Cert' attribute to access original object. """ def import_from_asn1pkt(self, cert): error_msg = "Unable to import certificate" self.x509Cert = cert tbsCert = cert.tbsCertificate self.tbsCertificate = tbsCert if tbsCert.version: self.version = tbsCert.version.val + 1 else: self.version = 1 self.serial = tbsCert.serialNumber.val self.sigAlg = tbsCert.signature.algorithm.oidname self.issuer = tbsCert.get_issuer() self.issuer_str = tbsCert.get_issuer_str() self.issuer_hash = hash(self.issuer_str) self.subject = tbsCert.get_subject() self.subject_str = tbsCert.get_subject_str() self.subject_hash = hash(self.subject_str) self.authorityKeyID = None self.notBefore_str = tbsCert.validity.not_before.pretty_time notBefore = tbsCert.validity.not_before.val if notBefore[-1] == "Z": notBefore = notBefore[:-1] try: self.notBefore = time.strptime(notBefore, "%y%m%d%H%M%S") except: raise Exception(error_msg) self.notBefore_str_simple = time.strftime("%x", self.notBefore) self.notAfter_str = tbsCert.validity.not_after.pretty_time notAfter = tbsCert.validity.not_after.val if notAfter[-1] == "Z": notAfter = notAfter[:-1] try: self.notAfter = time.strptime(notAfter, "%y%m%d%H%M%S") except: raise Exception(error_msg) self.notAfter_str_simple = time.strftime("%x", self.notAfter) self.pubKey = PubKey(raw(tbsCert.subjectPublicKeyInfo)) if tbsCert.extensions: for extn in tbsCert.extensions: if extn.extnID.oidname == "basicConstraints": self.cA = False if extn.extnValue.cA: self.cA = not (extn.extnValue.cA.val == 0) elif extn.extnID.oidname == "keyUsage": self.keyUsage = extn.extnValue.get_keyUsage() elif extn.extnID.oidname == "extKeyUsage": self.extKeyUsage = extn.extnValue.get_extendedKeyUsage() elif extn.extnID.oidname == "authorityKeyIdentifier": self.authorityKeyID = extn.extnValue.keyIdentifier.val self.signatureValue = raw(cert.signatureValue) self.signatureLen = len(self.signatureValue) def isIssuerCert(self, other): """ True if 'other' issued 'self', i.e.: - self.issuer == other.subject - self is signed by other """ if self.issuer_hash != other.subject_hash: return False return other.pubKey.verifyCert(self) def isSelfSigned(self): """ Return True if the certificate is self-signed: - issuer and subject are the same - the signature of the certificate is valid. """ if self.issuer_hash == self.subject_hash: return self.isIssuerCert(self) return False def encrypt(self, msg, t="pkcs", h="sha256", mgf=None, L=None): # no ECDSA *encryption* support, hence only RSA specific keywords here return self.pubKey.encrypt(msg, t, h, mgf, L) def verify(self, msg, sig, t="pkcs", h="sha256", mgf=None, L=None): return self.pubKey.verify(msg, sig, t, h, mgf, L) def remainingDays(self, now=None): """ Based on the value of notAfter field, returns the number of days the certificate will still be valid. The date used for the comparison is the current and local date, as returned by time.localtime(), except if 'now' argument is provided another one. 'now' argument can be given as either a time tuple or a string representing the date. Accepted format for the string version are: - '%b %d %H:%M:%S %Y %Z' e.g. 'Jan 30 07:38:59 2008 GMT' - '%m/%d/%y' e.g. '01/30/08' (less precise) If the certificate is no more valid at the date considered, then a negative value is returned representing the number of days since it has expired. The number of days is returned as a float to deal with the unlikely case of certificates that are still just valid. """ if now is None: now = time.localtime() elif isinstance(now, str): try: if '/' in now: now = time.strptime(now, '%m/%d/%y') else: now = time.strptime(now, '%b %d %H:%M:%S %Y %Z') except: warning("Bad time string provided, will use localtime() instead.") now = time.localtime() now = time.mktime(now) nft = time.mktime(self.notAfter) diff = (nft - now)/(24.*3600) return diff def isRevoked(self, crl_list): """ Given a list of trusted CRL (their signature has already been verified with trusted anchors), this function returns True if the certificate is marked as revoked by one of those CRL. Note that if the Certificate was on hold in a previous CRL and is now valid again in a new CRL and bot are in the list, it will be considered revoked: this is because _all_ CRLs are checked (not only the freshest) and revocation status is not handled. Also note that the check on the issuer is performed on the Authority Key Identifier if available in _both_ the CRL and the Cert. Otherwise, the issuers are simply compared. """ for c in crl_list: if (self.authorityKeyID is not None and c.authorityKeyID is not None and self.authorityKeyID == c.authorityKeyID): return self.serial in (x[0] for x in c.revoked_cert_serials) elif self.issuer == c.issuer: return self.serial in (x[0] for x in c.revoked_cert_serials) return False def export(self, filename, fmt="DER"): """ Export certificate in 'fmt' format (DER or PEM) to file 'filename' """ f = open(filename, "wb") if fmt == "DER": f.write(self.der) elif fmt == "PEM": f.write(self.pem) f.close() def show(self): print("Serial: %s" % self.serial) print("Issuer: " + self.issuer_str) print("Subject: " + self.subject_str) print("Validity: %s to %s" % (self.notBefore_str, self.notAfter_str)) def __repr__(self): return "[X.509 Cert. Subject:%s, Issuer:%s]" % (self.subject_str, self.issuer_str)
class _AEADCipher(six.with_metaclass(_AEADCipherMetaclass, object)): """ The hasattr(self, "pc_cls") tests correspond to the legacy API of the crypto library. With cryptography v2.0, both CCM and GCM should follow the else case. Note that the "fixed_iv" in TLS RFCs is called "salt" in the AEAD RFC 5116. """ type = "aead" fixed_iv_len = 4 nonce_explicit_len = 8 def __init__(self, key=None, fixed_iv=None, nonce_explicit=None): """ 'key' and 'fixed_iv' are to be provided as strings, whereas the internal 'nonce_explicit' is an integer (it is simpler for incrementation). /!\ The whole 'nonce' may be called IV in certain RFCs. """ self.ready = {"key": True, "fixed_iv": True, "nonce_explicit": True} if key is None: self.ready["key"] = False key = b"\0" * self.key_len if fixed_iv is None: self.ready["fixed_iv"] = False fixed_iv = b"\0" * self.fixed_iv_len if nonce_explicit is None: self.ready["nonce_explicit"] = False nonce_explicit = 0 if isinstance(nonce_explicit, str): nonce_explicit = pkcs_os2ip(nonce_explicit) # we use super() in order to avoid any deadlock with __setattr__ super(_AEADCipher, self).__setattr__("key", key) super(_AEADCipher, self).__setattr__("fixed_iv", fixed_iv) super(_AEADCipher, self).__setattr__("nonce_explicit", nonce_explicit) if hasattr(self, "pc_cls"): self._cipher = Cipher(self.pc_cls(key), self.pc_cls_mode(self._get_nonce()), backend=default_backend()) else: self._cipher = self.cipher_cls(key) def __setattr__(self, name, val): if name == "key": if self._cipher is not None: if hasattr(self, "pc_cls"): self._cipher.algorithm.key = val else: self._cipher._key = val self.ready["key"] = True elif name == "fixed_iv": self.ready["fixed_iv"] = True elif name == "nonce_explicit": if isinstance(val, str): val = pkcs_os2ip(val) self.ready["nonce_explicit"] = True super(_AEADCipher, self).__setattr__(name, val) def _get_nonce(self): return (self.fixed_iv + pkcs_i2osp(self.nonce_explicit, self.nonce_explicit_len)) def _update_nonce_explicit(self): """ Increment the explicit nonce while avoiding any overflow. """ ne = self.nonce_explicit + 1 self.nonce_explicit = ne % 2**(self.nonce_explicit_len * 8) def auth_encrypt(self, P, A, seq_num=None): """ Encrypt the data then prepend the explicit part of the nonce. The authentication tag is directly appended with the most recent crypto API. Additional data may be authenticated without encryption (as A). The 'seq_num' should never be used here, it is only a safeguard needed because one cipher (ChaCha20Poly1305) using TLS 1.2 logic in record.py actually is a _AEADCipher_TLS13 (even though others are not). """ if False in six.itervalues(self.ready): raise CipherError(P, A) if hasattr(self, "pc_cls"): self._cipher.mode._initialization_vector = self._get_nonce() self._cipher.mode._tag = None encryptor = self._cipher.encryptor() encryptor.authenticate_additional_data(A) res = encryptor.update(P) + encryptor.finalize() res += encryptor.tag else: if isinstance(self._cipher, AESCCM): res = self._cipher.encrypt(self._get_nonce(), P, A, tag_length=self.tag_len) else: res = self._cipher.encrypt(self._get_nonce(), P, A) nonce_explicit = pkcs_i2osp(self.nonce_explicit, self.nonce_explicit_len) self._update_nonce_explicit() return nonce_explicit + res def auth_decrypt(self, A, C, seq_num=None, add_length=True): """ Decrypt the data and authenticate the associated data (i.e. A). If the verification fails, an AEADTagError is raised. It is the user's responsibility to catch it if deemed useful. If we lack the key, we raise a CipherError which contains the encrypted input. Note that we add the TLSCiphertext length to A although we're supposed to add the TLSCompressed length. Fortunately, they are the same, but the specifications actually messed up here. :'( The 'add_length' switch should always be True for TLS, but we provide it anyway (mostly for test cases, hum). The 'seq_num' should never be used here, it is only a safeguard needed because one cipher (ChaCha20Poly1305) using TLS 1.2 logic in record.py actually is a _AEADCipher_TLS13 (even though others are not). """ nonce_explicit_str, C, mac = (C[:self.nonce_explicit_len], C[self.nonce_explicit_len:-self.tag_len], C[-self.tag_len:]) if False in six.itervalues(self.ready): raise CipherError(nonce_explicit_str, C, mac) self.nonce_explicit = pkcs_os2ip(nonce_explicit_str) if add_length: A += struct.pack("!H", len(C)) if hasattr(self, "pc_cls"): self._cipher.mode._initialization_vector = self._get_nonce() self._cipher.mode._tag = mac decryptor = self._cipher.decryptor() decryptor.authenticate_additional_data(A) P = decryptor.update(C) try: decryptor.finalize() except InvalidTag: raise AEADTagError(nonce_explicit_str, P, mac) else: try: if isinstance(self._cipher, AESCCM): P = self._cipher.decrypt(self._get_nonce(), C + mac, A, tag_length=self.tag_len) else: P = self._cipher.decrypt(self._get_nonce(), C + mac, A) except InvalidTag: raise AEADTagError(nonce_explicit_str, "<unauthenticated data>", mac) return nonce_explicit_str, P, mac def snapshot(self): c = self.__class__(self.key, self.fixed_iv, self.nonce_explicit) c.ready = self.ready.copy() return c
class _AEADCipher(six.with_metaclass(_AEADCipherMetaclass, object)): type = "aead" def __init__(self, key=None, salt=None, nonce_explicit=None): """ 'key' and 'salt' are to be provided as strings, whereas the internal 'nonce_explicit' is an integer (it is simpler for incrementation). """ self.ready = {"key": True, "salt": True, "nonce_explicit": True} if key is None: self.ready["key"] = False key = b"\0" * self.key_len if salt is None: self.ready["salt"] = False salt = b"\0" * self.salt_len if nonce_explicit is None: self.ready["nonce_explicit"] = False nonce_explicit = 0 if isinstance(nonce_explicit, str): nonce_explicit = pkcs_os2ip(nonce_explicit) # we use super() in order to avoid any deadlock with __setattr__ super(_AEADCipher, self).__setattr__("key", key) super(_AEADCipher, self).__setattr__("salt", salt) super(_AEADCipher, self).__setattr__("nonce_explicit", nonce_explicit) iv = salt + pkcs_i2osp(nonce_explicit, self.nonce_explicit_len) self._cipher = Cipher(self.pc_cls(key), self.pc_cls_mode(iv), backend=default_backend()) def __setattr__(self, name, val): if name == "key": if self._cipher is not None: self._cipher.algorithm.key = val self.ready["key"] = True elif name == "salt": iv = val + pkcs_i2osp(self.nonce_explicit, self.nonce_explicit_len) if self._cipher is not None: self._cipher.mode._initialization_vector = iv self.ready["salt"] = True elif name == "nonce_explicit": if isinstance(val, str): val = pkcs_os2ip(val) iv = self.salt + pkcs_i2osp(val, self.nonce_explicit_len) if self._cipher is not None: self._cipher.mode._initialization_vector = iv self.ready["nonce_explicit"] = True super(_AEADCipher, self).__setattr__(name, val) def _update_nonce(self): """ Increment the explicit nonce while avoiding any overflow. """ ne = self.nonce_explicit + 1 self.nonce_explicit = ne % 2**(self.nonce_explicit_len * 8) def auth_encrypt(self, P, A): """ Encrypt the data, prepend the explicit part of the nonce, and append the computed authentication code. Additional data may be authenticated without encryption (as A). Note that the cipher's authentication tag must be None when encrypting. """ if False in six.itervalues(self.ready): raise CipherError, (P, A) self._cipher.mode._tag = None encryptor = self._cipher.encryptor() encryptor.authenticate_additional_data(A) res = encryptor.update(P) + encryptor.finalize() res += encryptor.tag nonce_explicit = pkcs_i2osp(self.nonce_explicit, self.nonce_explicit_len) self._update_nonce() return nonce_explicit + res def auth_decrypt(self, A, C, add_length=True): """ Decrypt the data and verify the authentication code (in this order). When additional data was authenticated, it has to be passed (as A). If the verification fails, an AEADTagError is raised. It is the user's responsibility to catch it if deemed useful. If we lack the key, we raise a CipherError which contains the encrypted input. Note that we add the TLSCiphertext length to A although we're supposed to add the TLSCompressed length. Fortunately, they are the same, but the specifications actually messed up here. :'( The 'add_length' switch should always be True for TLS, but we provide it anyway (mostly for test cases, hum). """ nonce_explicit_str, C, mac = (C[:self.nonce_explicit_len], C[self.nonce_explicit_len:-self.tag_len], C[-self.tag_len:]) if False in six.itervalues(self.ready): raise CipherError, (nonce_explicit_str, C, mac) self.nonce_explicit = pkcs_os2ip(nonce_explicit_str) self._cipher.mode._tag = mac decryptor = self._cipher.decryptor() if add_length: A += struct.pack("!H", len(C)) decryptor.authenticate_additional_data(A) P = decryptor.update(C) try: decryptor.finalize() except InvalidTag: raise AEADTagError, (nonce_explicit_str, P, mac) return nonce_explicit_str, P, mac
class SuperSocket(six.with_metaclass(_SuperSocket_metaclass)): desc = None closed = 0 nonblocking_socket = False read_allowed_exceptions = () def __init__(self, family=socket.AF_INET, type=socket.SOCK_STREAM, proto=0): # noqa: E501 self.ins = socket.socket(family, type, proto) self.outs = self.ins self.promisc = None def send(self, x): sx = raw(x) try: x.sent_time = time.time() except AttributeError: pass return self.outs.send(sx) def recv_raw(self, x=MTU): """Returns a tuple containing (cls, pkt_data, time)""" return conf.raw_layer, self.ins.recv(x), None def recv(self, x=MTU): cls, val, ts = self.recv_raw(x) if not val or not cls: return try: pkt = cls(val) except KeyboardInterrupt: raise except Exception: if conf.debug_dissector: from scapy.sendrecv import debug debug.crashed_on = (cls, val) raise pkt = conf.raw_layer(val) if ts: pkt.time = ts return pkt def fileno(self): return self.ins.fileno() def close(self): if self.closed: return self.closed = True if getattr(self, "outs", None): if getattr(self, "ins", None) != self.outs: if WINDOWS or self.outs.fileno() != -1: self.outs.close() if getattr(self, "ins", None): if WINDOWS or self.ins.fileno() != -1: self.ins.close() def sr(self, *args, **kargs): from scapy import sendrecv return sendrecv.sndrcv(self, *args, **kargs) def sr1(self, *args, **kargs): from scapy import sendrecv a, b = sendrecv.sndrcv(self, *args, **kargs) if len(a) > 0: return a[0][1] else: return None def sniff(self, *args, **kargs): from scapy import sendrecv return sendrecv.sniff(opened_socket=self, *args, **kargs) def tshark(self, *args, **kargs): from scapy import sendrecv return sendrecv.tshark(opened_socket=self, *args, **kargs) @staticmethod def select(sockets, remain=conf.recv_poll_rate): """This function is called during sendrecv() routine to select the available sockets. :param sockets: an array of sockets that need to be selected :returns: an array of sockets that were selected and the function to be called next to get the packets (i.g. recv) """ try: inp, _, _ = select(sockets, [], [], remain) except (IOError, select_error) as exc: # select.error has no .errno attribute if exc.args[0] != errno.EINTR: raise return inp, None def __del__(self): """Close the socket""" self.close() def __enter__(self): return self def __exit__(self, exc_type, exc_value, traceback): """Close the socket""" self.close()
class _GenericHash(six.with_metaclass(_GenericHashMetaclass, object)): def digest(self, tbd): return self.hash_cls(tbd).digest()
class CRL(six.with_metaclass(_CRLMaker, object)): """ Wrapper for the X509_CRL from layers/x509.py. Use the 'x509CRL' attribute to access original object. """ def import_from_asn1pkt(self, crl): error_msg = "Unable to import CRL" self.x509CRL = crl tbsCertList = crl.tbsCertList self.tbsCertList = raw(tbsCertList) if tbsCertList.version: self.version = tbsCertList.version.val + 1 else: self.version = 1 self.sigAlg = tbsCertList.signature.algorithm.oidname self.issuer = tbsCertList.get_issuer() self.issuer_str = tbsCertList.get_issuer_str() self.issuer_hash = hash(self.issuer_str) self.lastUpdate_str = tbsCertList.this_update.pretty_time lastUpdate = tbsCertList.this_update.val if lastUpdate[-1] == "Z": lastUpdate = lastUpdate[:-1] try: self.lastUpdate = time.strptime(lastUpdate, "%y%m%d%H%M%S") except: raise Exception(error_msg) self.lastUpdate_str_simple = time.strftime("%x", self.lastUpdate) self.nextUpdate = None self.nextUpdate_str_simple = None if tbsCertList.next_update: self.nextUpdate_str = tbsCertList.next_update.pretty_time nextUpdate = tbsCertList.next_update.val if nextUpdate[-1] == "Z": nextUpdate = nextUpdate[:-1] try: self.nextUpdate = time.strptime(nextUpdate, "%y%m%d%H%M%S") except: raise Exception(error_msg) self.nextUpdate_str_simple = time.strftime("%x", self.nextUpdate) if tbsCertList.crlExtensions: for extension in tbsCertList.crlExtensions: if extension.extnID.oidname == "cRLNumber": self.number = extension.extnValue.cRLNumber.val revoked = [] if tbsCertList.revokedCertificates: for cert in tbsCertList.revokedCertificates: serial = cert.serialNumber.val date = cert.revocationDate.val if date[-1] == "Z": date = date[:-1] try: revocationDate = time.strptime(date, "%y%m%d%H%M%S") except: raise Exception(error_msg) revoked.append((serial, date)) self.revoked_cert_serials = revoked self.signatureValue = raw(crl.signatureValue) self.signatureLen = len(self.signatureValue) def isIssuerCert(self, other): # This is exactly the same thing as in Cert method. if self.issuer_hash != other.subject_hash: return False return other.pubKey.verifyCert(self) def verify(self, anchors): # Return True iff the CRL is signed by one of the provided anchors. return any(self.isIssuerCert(a) for a in anchors) def show(self): print("Version: %d" % self.version) print("sigAlg: " + self.sigAlg) print("Issuer: " + self.issuer_str) print("lastUpdate: %s" % self.lastUpdate_str) print("nextUpdate: %s" % self.nextUpdate_str)
class Field(six.with_metaclass(Field_metaclass, object)): """For more informations on how this work, please refer to http://www.secdev.org/projects/scapy/files/scapydoc.pdf chapter ``Adding a New Field''""" __slots__ = ["name", "fmt", "default", "sz", "owners"] islist = 0 ismutable = False holds_packets = 0 def __init__(self, name, default, fmt="H"): self.name = name if fmt[0] in "@=<>!": self.fmt = fmt else: self.fmt = "!" + fmt self.default = self.any2i(None, default) self.sz = struct.calcsize(self.fmt) self.owners = [] def register_owner(self, cls): self.owners.append(cls) def i2len(self, pkt, x): """Convert internal value to a length usable by a FieldLenField""" return self.sz def i2count(self, pkt, x): """Convert internal value to a number of elements usable by a FieldLenField. Always 1 except for list fields""" return 1 def h2i(self, pkt, x): """Convert human value to internal value""" return x def i2h(self, pkt, x): """Convert internal value to human value""" return x def m2i(self, pkt, x): """Convert machine value to internal value""" return x def i2m(self, pkt, x): """Convert internal value to machine value""" if x is None: x = 0 return x def any2i(self, pkt, x): """Try to understand the most input values possible and make an internal value from them""" return self.h2i(pkt, x) def i2repr(self, pkt, x): """Convert internal value to a nice representation""" return repr(self.i2h(pkt, x)) def addfield(self, pkt, s, val): """Add an internal value to a string""" return s + struct.pack(self.fmt, self.i2m(pkt, val)) def getfield(self, pkt, s): """Extract an internal value from a string""" return s[self.sz:], self.m2i(pkt, struct.unpack(self.fmt, s[:self.sz])[0]) def do_copy(self, x): if hasattr(x, "copy"): return x.copy() if isinstance(x, list): x = x[:] for i in range(len(x)): if isinstance(x[i], BasePacket): x[i] = x[i].copy() return x def __repr__(self): return "<Field (%s).%s>" % (",".join(x.__name__ for x in self.owners), self.name) def copy(self): return copy.deepcopy(self) def randval(self): """Return a volatile object whose value is both random and suitable for this field""" fmtt = self.fmt[-1] if fmtt in "BHIQ": return { "B": RandByte, "H": RandShort, "I": RandInt, "Q": RandLong }[fmtt]() elif fmtt == "s": if self.fmt[0] in "0123456789": l = int(self.fmt[:-1]) else: l = int(self.fmt[1:-1]) return RandBin(l) else: warning("no random class for [%s] (fmt=%s)." % (self.name, self.fmt))