Example #1
0
    async def load_cache_for_verification(self, archive: bool = False) -> int:
        """
        Load schema, cred def, revocation caches; optionally archive enough to go
        offline and be able to verify proof on content marked of interest in configuration.

        Return timestamp (epoch seconds) of cache load event, also used as subdirectory
        for cache archives.

        :param archive: True to archive now or False to demur (subclasses may still
            need to augment archivable caches further)
        :return: cache load event timestamp (epoch seconds)
        """

        LOGGER.debug('Verifier.load_cache_for_verification >>> archive: %s',
                     archive)

        rv = int(time())
        for s_id in self.config.get('archive-verifier-caches-on-close',
                                    {}).get('schema_id', {}):
            if ok_schema_id(s_id):
                with SCHEMA_CACHE.lock:
                    await self.get_schema(s_id)
            else:
                LOGGER.info('Not archiving schema for specified bad id %s',
                            s_id)
        for cd_id in self.config.get('archive-verifier-caches-on-close',
                                     {}).get('cred_def_id', {}):
            if ok_cred_def_id(cd_id):
                with CRED_DEF_CACHE.lock:
                    await self.get_cred_def(cd_id)
            else:
                LOGGER.info('Not archiving cred def for specified bad id %s',
                            cd_id)
        for rr_id in self.config.get('archive-verifier-caches-on-close',
                                     {}).get('rev_reg_id', {}):
            if ok_rev_reg_id(rr_id):
                await self.get_rev_reg_def(rr_id)
                with REVO_CACHE.lock:
                    revo_cache_entry = REVO_CACHE.get(rr_id, None)
                    if revo_cache_entry:
                        try:
                            await revo_cache_entry.get_state_json(
                                self._build_rr_state_json, rv, rv)
                        except ClosedPool:
                            LOGGER.warning(
                                'Verifier %s is offline from pool %s, cannot update revo cache reg state for %s to %s',
                                self.name, self.pool.name, rr_id, rv)
                        except AbsentPool:
                            LOGGER.warning(
                                'Verifier %s has no pool, cannot update revo cache reg state for %s to %s',
                                self.name, rr_id, rv)
            else:
                LOGGER.info('Not archiving rev reg for specified bad id %s',
                            rr_id)

        if archive:
            ArchivableCaches.archive(self.dir_cache)
        LOGGER.debug('Verifier.load_cache_for_verification <<< %s', rv)
        return rv
Example #2
0
 async def _set_timestamp(rr_id: str, timestamp: int) -> None:
     nonlocal rr_id2rr
     with REVO_CACHE.lock:
         revo_cache_entry = REVO_CACHE.get(rr_id, None)
         (rr_json, _) = await revo_cache_entry.get_state_json(self._build_rr_state_json, timestamp, timestamp)
         if rr_id not in rr_id2rr:
             rr_id2rr[rr_id] = {}
         rr_id2rr[rr_id][timestamp] = json.loads(rr_json)
Example #3
0
    async def _get_rev_reg_def(self, rr_id: str) -> str:
        """
        Get revocation registry definition from ledger by its identifier. Raise AbsentRevReg
        for no such revocation registry, logging any error condition and raising BadLedgerTxn
        on bad request.

        Retrieve the revocation registry definition from the anchor's revocation cache if it has it;
        cache it en passant if it does not (and such a revocation registry definition exists on the ledger).

        :param rr_id: (revocation registry) identifier string, of the format
            '<issuer-did>:4:<issuer-did>:3:CL:<schema-seq-no>:<tag>:CL_ACCUM:<tag>'
        :return: revocation registry definition json as retrieved from ledger
        """

        LOGGER.debug('_BaseAnchor._get_rev_reg_def >>> rr_id: %s', rr_id)

        if not ok_rev_reg_id(rr_id):
            LOGGER.debug('_BaseAnchor._get_rev_reg_def <!< Bad rev reg id %s',
                         rr_id)
            raise BadIdentifier('Bad rev reg id {}'.format(rr_id))

        rv_json = json.dumps({})

        with REVO_CACHE.lock:
            revo_cache_entry = REVO_CACHE.get(rr_id, None)
            rr_def = revo_cache_entry.rev_reg_def if revo_cache_entry else None
            if rr_def:
                LOGGER.info(
                    '_BaseAnchor._get_rev_reg_def: rev reg def for %s from cache',
                    rr_id)
                rv_json = json.dumps(rr_def)
            else:
                get_rrd_req_json = await ledger.build_get_revoc_reg_def_request(
                    self.did, rr_id)
                resp_json = await self._submit(get_rrd_req_json)
                try:
                    (_,
                     rv_json) = await ledger.parse_get_revoc_reg_def_response(
                         resp_json)
                    rr_def = json.loads(rv_json)
                except IndyError:  # ledger replied, but there is no such rev reg
                    LOGGER.debug(
                        '_BaseAnchor._get_rev_reg_def: <!< no rev reg exists on %s',
                        rr_id)
                    raise AbsentRevReg('No rev reg exists on {}'.format(rr_id))

                if revo_cache_entry is None:
                    REVO_CACHE[rr_id] = RevoCacheEntry(rr_def, None)
                else:
                    REVO_CACHE[rr_id].rev_reg_def = rr_def

        LOGGER.debug('_BaseAnchor._get_rev_reg_def <<< %s', rv_json)
        return rv_json
Example #4
0
    async def _sync_revoc_for_issue(self,
                                    rr_id: str,
                                    rr_size: int = None) -> None:
        """
        Create revocation registry if need be for input revocation registry identifier;
        open and cache tails file reader.

        :param rr_id: revocation registry identifier
        :param rr_size: if new revocation registry necessary, its size (default as per RevRegBuilder.create_rev_reg())
        """

        LOGGER.debug('Issuer._sync_revoc_for_issue >>> rr_id: %s, rr_size: %s',
                     rr_id, rr_size)

        if not ok_rev_reg_id(rr_id):
            LOGGER.debug('Issuer._sync_revoc_for_issue <!< Bad rev reg id %s',
                         rr_id)
            raise BadIdentifier('Bad rev reg id {}'.format(rr_id))

        (cd_id, tag) = rev_reg_id2cred_def_id_tag(rr_id)

        try:
            await self.get_cred_def(cd_id)
        except AbsentCredDef:
            LOGGER.debug(
                'Issuer._sync_revoc_for_issue <!< tails tree %s may be for another ledger; no cred def found on %s',
                self.dir_tails, cd_id)
            raise AbsentCredDef(
                'Tails tree {} may be for another ledger; no cred def found on {}'
                .format(self.dir_tails, cd_id))

        with REVO_CACHE.lock:
            revo_cache_entry = REVO_CACHE.get(rr_id, None)
            tails = None if revo_cache_entry is None else revo_cache_entry.tails
            if tails is None:  #  it's a new revocation registry, or not yet set in cache
                try:
                    tails = await Tails(self.dir_tails, cd_id, tag).open()
                except AbsentTails:  # it's a new revocation registry
                    if self.rrbx:
                        await self._set_rev_reg(rr_id, rr_size)
                    else:
                        await self.rrb.create_rev_reg(rr_id, rr_size)
                        await self._send_rev_reg_def(rr_id)
                    tails = await Tails(self.dir_tails, cd_id,
                                        tag).open()  # symlink should exist now

                if revo_cache_entry is None:
                    REVO_CACHE[rr_id] = RevoCacheEntry(None, tails)
                else:
                    REVO_CACHE[rr_id].tails = tails

        LOGGER.debug('Issuer._sync_revoc_for_issue <<<')
Example #5
0
    async def verify_proof(self, proof_req: dict, proof: dict) -> str:
        """
        Verify proof as Verifier. Raise AbsentRevReg if a proof cites a revocation registry
        that does not exist on the distributed ledger.

        :param proof_req: proof request as Verifier creates, as per proof_req_json above
        :param proof: proof as HolderProver creates
        :return: json encoded True if proof is valid; False if not
        """

        LOGGER.debug('Verifier.verify_proof >>> proof_req: %s, proof: %s',
                     proof_req, proof)

        s_id2schema = {}
        cd_id2cred_def = {}
        rr_id2rr_def = {}
        rr_id2rr = {}
        proof_ids = proof['identifiers']

        for proof_id in proof_ids:
            # schema
            s_id = proof_id['schema_id']
            if not ok_schema_id(s_id):
                LOGGER.debug('Verifier.verify_proof: <!< Bad schema id %s',
                             s_id)
                raise BadIdentifier('Bad schema id {}'.format(s_id))

            if s_id not in s_id2schema:
                schema = json.loads(
                    await self.get_schema(s_id))  # add to cache en passant
                if not schema:
                    LOGGER.debug(
                        'Verifier.verify_proof: <!< absent schema %s, proof req may be for another ledger',
                        s_id)
                    raise AbsentSchema(
                        'Absent schema {}, proof req may be for another ledger'
                        .format(s_id))
                s_id2schema[s_id] = schema

            # cred def
            cd_id = proof_id['cred_def_id']
            if not ok_cred_def_id(cd_id):
                LOGGER.debug('Verifier.verify_proof: <!< Bad cred def id %s',
                             cd_id)
                raise BadIdentifier('Bad cred def id {}'.format(cd_id))

            if cd_id not in cd_id2cred_def:
                cred_def = json.loads(
                    await self.get_cred_def(cd_id))  # add to cache en passant
                cd_id2cred_def[cd_id] = cred_def

            # rev reg def
            rr_id = proof_id['rev_reg_id']
            if not rr_id:
                continue
            if not ok_rev_reg_id(rr_id):
                LOGGER.debug('Verifier.verify_proof: <!< Bad rev reg id %s',
                             rr_id)
                raise BadIdentifier('Bad rev reg id {}'.format(rr_id))

            rr_def_json = await self._get_rev_reg_def(rr_id)
            rr_id2rr_def[rr_id] = json.loads(rr_def_json)

            # timestamp
            timestamp = proof_id['timestamp']
            with REVO_CACHE.lock:
                revo_cache_entry = REVO_CACHE.get(rr_id, None)
                (rr_json, _) = await revo_cache_entry.get_state_json(
                    self._build_rr_state_json, timestamp, timestamp)
                if rr_id not in rr_id2rr:
                    rr_id2rr[rr_id] = {}
                rr_id2rr[rr_id][timestamp] = json.loads(rr_json)

        rv = json.dumps(await anoncreds.verifier_verify_proof(
            json.dumps(proof_req), json.dumps(proof), json.dumps(s_id2schema),
            json.dumps(cd_id2cred_def), json.dumps(rr_id2rr_def),
            json.dumps(rr_id2rr)))

        LOGGER.debug('Verifier.verify_proof <<< %s', rv)
        return rv