Exemple #1
0
    def _issue_revocation(self, if_id, chain):
        """
        Store a RevocationObject in ZK and send a revocation to all ERs.

        :param if_id: The interface that needs to be revoked.
        :type if_id: int
        :param chain: The hash chain corresponding to if_id.
        :type chain: :class:`lib.crypto.hash_chain.HashChain`
        """
        # Only the master BS issues revocations.
        if not self.zk.have_lock():
            return
        rev_info = RevocationInfo.from_values(chain.next_element())
        logging.info("Storing revocation in ZK.")
        rev_obj = RevocationObject.from_values(if_id, chain.current_index(),
                                               chain.next_element())
        entry_name = "%s:%s" % (chain.start_element(hex_=True),
                                chain.next_element(hex_=True))
        self.revobjs_cache.store(entry_name, rev_obj.pack())
        logging.info("Issuing revocation for IF %d.", if_id)
        # Issue revocation to all ERs.
        info = IFStateInfo.from_values(if_id, False, chain.next_element())
        pld = IFStatePayload.from_values([info])
        state_pkt = self._build_packet()
        for er in self.topology.get_all_edge_routers():
            state_pkt.addrs.dst.host = er.addr
            state_pkt.set_payload(pld.copy())
            self.send(state_pkt, er.addr)
        self._process_revocation(rev_info, if_id)
Exemple #2
0
    def process_revocation(self, spkt, from_local_as):
        pld = spkt.get_payload()
        logging.info("Processing revocation: %s", pld.info)
        # First, forward the packet as appropriate.
        self.handle_data(spkt, from_local_as)
        if from_local_as:
            return
        # Forward to local path and beacon services if we haven't recently.
        rev_info = RevocationInfo.from_raw(pld.info.rev_info)
        if rev_info in self.revocations:
            return
        snames = []
        # Fork revocation to local BS and PS if router is downstream of the
        # failed interface.
        if (spkt.addrs.src.isd_as[0] == self.addr.isd_as[0] and
                self._is_downstream_router()):
            snames.append(BEACON_SERVICE)
            if self.topology.path_servers:
                snames.append(PATH_SERVICE)
        # Fork revocation to local PS if router is in the AS of the source.
        elif (spkt.addrs.dst.isd_as == self.addr.isd_as and
                self.topology.path_servers):
            snames.append(PATH_SERVICE)

        self.revocations[rev_info] = True
        for sname in snames:
            try:
                addr, port = self.dns_query_topo(sname)[0]
            except SCIONServiceLookupError:
                logging.error("Unable to find %s to forward revocation to.",
                              sname)
                continue
            pkt = self._build_packet(addr, dst_port=port,
                                     payload=rev_info.copy())
            self.send(pkt, addr, SCION_UDP_EH_DATA_PORT)
Exemple #3
0
 def _parse(self, raw):
     """
     Parses raw bytes and populates the fields.
     """
     data = Raw(raw, self.NAME)
     self.if_id, self.hash_chain_idx = struct.unpack("!II", data.pop(8))
     self.rev_info = RevocationInfo.from_raw(data.pop())
Exemple #4
0
    def get_proof(self, if_id, epoch, prev_root, next_root):
        """
        Obtain the proof for revoking a given interface at a given epoch.

        :param int if_id: ID of the interface to be revoked.
        :param int epoch: epoch for which the interface is to be revoked.
        :param bytes prev_root: hash of the previous root.
        :param bytes next_root: hash of the next root.
        """
        assert if_id in self._if2idx.keys(), "if_id not found in AS"
        relative_epoch = epoch % HASHTREE_N_EPOCHS
        # Obtain the nonce for the (if_id, epoch) pair using the seed.
        raw_nonce = self._seed + struct.pack("!qq", if_id, relative_epoch)
        nonce = self._hash_func(raw_nonce)

        # Obtain the sibling hashes along with their left/right position info.
        siblings = []
        idx = self._if2idx[if_id] + relative_epoch
        while idx > 0:
            if idx % 2 == 0:
                siblings.append((True, self._nodes[idx - 1]))
            else:
                siblings.append((False, self._nodes[idx + 1]))
            idx = (idx - 1) // 2

        # Using the above fields, construct a RevInfo capnp as the proof.
        return RevocationInfo.from_values(
            self._isd_as, if_id, epoch, nonce, siblings, prev_root, next_root,
            self._hash_type)
Exemple #5
0
 def _handle_scmp_revocation(self, pld, meta):
     rev_info = RevocationInfo.from_raw(pld.info.rev_info)
     try:
         rev_info.validate()
     except SCIONBaseError as e:
         logging.warning("Failed to validate SCMP RevInfo from %s: %s\n%s",
                         meta, e, rev_info.short_desc())
         return
     self._handle_revocation(CtrlPayload(PathMgmt(rev_info)), meta)
Exemple #6
0
 def test_revoked(self):
     pcb = self._mk_pcb()
     inst = Mock()
     rev_info = RevocationInfo.from_values(ISD_AS("1-ff00:0:300"), 1, LinkType.PARENT, 1)
     srev_info = SignedRevInfo.from_values(rev_info.copy().pack(),
                                           ProtoSignType.ED25519, "src".encode())
     rev_cache = Mock()
     rev_cache.get.return_value = srev_info
     inst.check_revoked_interface = SCIONElement.check_revoked_interface
     ntools.eq_(inst.check_revoked_interface(inst, pcb, rev_cache), False)
Exemple #7
0
 def _rev_entries_handler(self, raw_entries):
     for raw in raw_entries:
         rev_info = RevocationInfo.from_raw(raw)
         try:
             rev_info.validate()
         except SCIONBaseError as e:
             logging.warning("Failed to validate RevInfo from zk: %s\n%s",
                             e, rev_info.short_desc())
             continue
         self._remove_revoked_segments(rev_info)
Exemple #8
0
 def _handle_scmp_revocation(self, pld, meta):
     rev_info = RevocationInfo.from_raw(pld.info.rev_info)
     logging.debug("Received revocation via SCMP: %s (from %s)",
                   rev_info.short_desc(), meta)
     try:
         rev_info.validate()
     except SCIONBaseError as e:
         logging.warning("Failed to validate SCMP RevInfo from %s: %s\n%s",
                         meta, e, rev_info.short_desc())
         return
     self._process_revocation(rev_info)
Exemple #9
0
 def process_rev_objects(self, rev_infos):
     """
     Processes revocation infos stored in Zookeeper.
     """
     with self._rev_seg_lock:
         for raw in rev_infos:
             try:
                 rev_info = RevocationInfo.from_raw(raw)
             except SCIONParseError as e:
                 logging.error(
                     "Error processing revocation info from ZK: %s", e)
                 continue
             self.local_rev_cache[rev_info] = rev_info.copy()
Exemple #10
0
 def _handle_scmp(self, spkt):
     scmp_hdr = spkt.l4_hdr
     spkt.parse_payload()
     if (scmp_hdr.class_ == SCMPClass.PATH
             and scmp_hdr.type == SCMPPathClass.REVOKED_IF):
         scmp_pld = spkt.get_payload()
         rev_info = RevocationInfo.from_raw(scmp_pld.info.rev_info)
         logging.info("Received revocation for IF %d." % rev_info.p.ifID)
         self.sd.handle_revocation(rev_info, None)
         return ResponseRV.RETRY
     else:
         logging.error("Received SCMP error:\n%s", spkt)
         return ResponseRV.FAILURE
Exemple #11
0
    def from_values(cls, if_id, index, rev_token):
        """
        Returns a RevocationInfo object with the specified values.

        :param int if_id: The interface id of the corresponding interface.
        :param int index: The index of the rev_token in the hash chain.
        :param bytes rev_token: revocation token of interface
        """
        inst = cls()
        inst.if_id = if_id
        inst.hash_chain_idx = index
        inst.rev_info = RevocationInfo.from_values(rev_token)
        return inst
 def _handle_scmp(self, spkt):
     scmp_hdr = spkt.l4_hdr
     spkt.parse_payload()
     if (scmp_hdr.class_ == SCMPClass.PATH
             and scmp_hdr.type == SCMPPathClass.REVOKED_IF):
         scmp_pld = spkt.get_payload()
         rev_info = RevocationInfo.from_raw(scmp_pld.info.rev_info)
         logging.info("Received revocation for IF %d." % rev_info.p.ifID)
         rev_not = SCIONDRevNotification.from_values(rev_info)
         self.api_socket().send(rev_not.pack_full())
         return ResponseRV.RETRY
     else:
         logging.error("Received SCMP error:\n%s", spkt)
         return ResponseRV.FAILURE
Exemple #13
0
 def _handle_scmp(self, spkt):
     scmp_hdr = spkt.l4_hdr
     spkt.parse_payload()
     if (scmp_hdr.class_ == SCMPClass.PATH and
             scmp_hdr.type == SCMPPathClass.REVOKED_IF):
         scmp_pld = spkt.get_payload()
         rev_info = RevocationInfo.from_raw(scmp_pld.info.rev_info)
         logging.info("Received revocation: %s (from %s)", rev_info.short_desc(), spkt.addrs.src)
         lib_sciond.send_rev_notification(
             rev_info, connector=self._connector)
         return ResponseRV.RETRY
     else:
         logging.error("Received SCMP error:\n%s", spkt)
         return ResponseRV.FAILURE
Exemple #14
0
    def _issue_revocations(self, revoked_ifs):
        """
        Store a RevocationInfo in ZK and send a revocation to all BRs.

        :param list revoked_ifs: A list of interfaces that needs to be revoked.
        """
        # Only the master BS issues revocations.
        if not self.zk.have_lock():
            return
        # Process revoked interfaces.
        infos = []
        for if_id in revoked_ifs:
            br = self.ifid2br[if_id]
            rev_info = RevocationInfo.from_values(
                self.addr.isd_as, if_id, br.interfaces[if_id].link_type,
                int(time.time()), self.REVOCATION_TTL)
            logging.info("Issuing revocation: %s", rev_info.short_desc())
            if self._labels:
                REVOCATIONS_ISSUED.labels(**self._labels).inc()
            chain = self._get_my_cert()
            _, cert_ver = chain.get_leaf_isd_as_ver()
            src = DefaultSignSrc.from_values(
                rev_info.isd_as(), cert_ver,
                self._get_my_trc().version).pack()
            srev_info = SignedRevInfo.from_values(rev_info.copy().pack(),
                                                  ProtoSignType.ED25519, src)
            srev_info.sign(self.signing_key)
            # Add to revocation cache
            self.if_revocations[if_id] = srev_info
            self._process_revocation(srev_info)
            infos.append(IFStateInfo.from_values(if_id, False, srev_info))
        border_metas = []
        # Add all BRs.
        for br in self.topology.border_routers:
            br_addr, br_port = br.int_addrs.public[0]
            border_metas.append(
                UDPMetadata.from_values(host=br_addr, port=br_port))
        # Add local path server.
        ps_meta = []
        if self.topology.path_servers:
            try:
                addr, port = self.dns_query_topo(ServiceType.PS)[0]
            except SCIONServiceLookupError:
                addr, port = None, None
            # Create a meta if there is a local path service
            if addr:
                ps_meta.append(UDPMetadata.from_values(host=addr, port=port))
        self._send_ifstate_update(infos, border_metas, ps_meta)
Exemple #15
0
 def process_rev_objects(self, rev_infos):
     """
     Processes revocation infos stored in Zookeeper.
     """
     with self._rev_seg_lock:
         for raw in rev_infos:
             try:
                 rev_info = RevocationInfo.from_raw(raw)
             except SCIONParseError as e:
                 logging.error("Error parsing revocation info from ZK: %s",
                               e)
                 continue
             try:
                 rev_info.validate()
             except SCIONBaseError as e:
                 logging.warning(
                     "Failed to validate RevInfo from zk: %s\n%s", e,
                     rev_info.short_desc())
                 continue
             self.local_rev_cache[rev_info] = rev_info.copy()
Exemple #16
0
 def rev_info(self, idx):
     return RevocationInfo(self.p.exts.revInfos[idx])
Exemple #17
0
 def _handle_scmp_revocation(self, pld, meta):
     rev_info = RevocationInfo.from_raw(pld.info.rev_info)
     self._handle_revocation(rev_info, meta)
Exemple #18
0
 def _rev_entries_handler(self, raw_entries):
     for raw in raw_entries:
         rev_info = RevocationInfo.from_raw(raw)
         self._remove_revoked_segments(rev_info)
Exemple #19
0
 def _handle_scmp_revocation(self, pld, meta):
     rev_info = RevocationInfo.from_raw(pld.info.rev_info)
     logging.debug("Received revocation via SCMP: %s (from %s)",
                   rev_info.short_desc(), meta)
     self._process_revocation(rev_info)
Exemple #20
0
 def rev_info(self):
     if not self._rev_info:
         self._rev_info = RevocationInfo(self.p.revInfo)
     return self._rev_info
Exemple #21
0
 def rev_info(self):
     if self.p.revInfo:
         return RevocationInfo(self.p.revInfo)
     return None
Exemple #22
0
 def handle_scmp_revocation(self, pld, meta):
     rev_info = RevocationInfo.from_raw(pld.info.rev_info)
     self.handle_revocation(CtrlPayload(PathMgmt(rev_info)), meta)