keripy
keripy copied to clipboard
get cred events from an issuer's TEL?
This issue tracks a question from @rubelhassan, @Arsh-Sandhu , and me. We are looking for an efficient way to discover that a particular issuer has issued or revoked credentials, and what the SAIDs and approximate issuance/revocation times of those credentials is. Our assumption was that we could contact the witness that services the issuer's AID, and get a series of events from the TEL that each contain the SAID of a given credential, or similar. What we have discovered is that this doesn't work. We seem to have a way to ask the question, but the answer to the question always seems to be "this TEL has no events" -- and we are wondering if this is by design, or if we are doing something wrong.
I will append a series of messages from Discord, reproducing some conversation that has occurred in that channel.
First post on Discord, from Rubel:
I have a query regarding the retrieval of TELs. Scenario: I want to monitor credentials (iss, rev) that are issued to an AID (holder/issuer). I tried to obtain the TELs using witness endpoint but the response contained KELs only. Could anyone suggest what could be the possible ways to do that? I'd highly appreciate your insights and response.
After a few suggestions, another comment from Rubel:
As you suggested, I've tried to fetch TELs for the issuer (using issuer AID)
but got no traces of iss events or ACDC chains in the response. From the
log of keria I see that TEL events were sent to witnesses:
Sending TEL events to witnesses
url: http://127.0.0.1:5642/oobi/<aid>/witness/<wit-aid>
env: keripy (development), keria (development)
wits: [wan, wil, wes]
To which @rodolfomiranda replied:
You should see interaction events with anchors for the registry
creation and every credential issued. You wont see the TEL, but
an anchoring event.
@nkongsuwan:
I have been wondering about this question for a while as well. If a credential
is revoked, then a SAID of the revocation-TEL event will be anchored to the
KEL's interaction. How can you tell if a particular interaction event corresponds
to a revocation?
My guess is to look at i and s in the interaction event.
This should work only if there is one issuance or one revocation per one
interaction event. If a bunch of ACDC issuances and revocations are batched into
a single interaction event, then the issuer also needs a mechanism to publish the
TEL (or some sort of cryptographic proofs) so a verifier can tell if a specific ACDC
is revoked.
@rubelhassan:
I understand that TELs are not directly accessible currently, and we can get the ixn anchors from KELs that only include i, s, and d. How to look up TELs using anchor information, is there a specific function or endpoint in KERI designed for this purpose?
@pfeairheller :
You use a qry message with a route of /tels
@rubelhassan:
I think you mean something like this - httping.createCESRRequest(msg, client, dest=wit, path="/qry/tels") in that case, issuer.pre, issuer.regk, vcid are required for the query msg. But I was looking for TELs by issuer AID where only AID and wits are known to me. I'm a little bit confused, could you please explain? Sorry for my limited knowledge here.
@rubelhassan:
Hi all, I'd like to ask a scenario-based question. I've created a Keripy agent to obtain KELs and TELs from the AIDs (external). Now let's say there's an AID-x that has issued credentials to AID-Y and AID-Z. Now I want to query KELs, TELs of AID-X also creds. Here are the steps I followed to achieve this:
TL;DR: I was able to get KELs but not TELs. Sorry for posting a long query.
Resolved oobi with AID-X and agent
hby.db.oobis.pin(keys=(oobi,), val=obr)#agent's hby
Implemented a QueryDoer class to communicate with an aid's witnesses. The class is as follows:
class QueryDoer(doing.DoDoer): #full code attached in the snipped
def __init__(self, hby, rgy, alias, pre, anchor, **kwa):
self.mbd = indirecting.MailboxDirector(hby=self.hby, topics=["/replay", "/receipt", "/reply", "/credential"],
verifier=self.vry)
def queryDo(self, tymth, tock=0.0, **opts):
if anchor is not None:
doer = querying.AnchorQuerier(hby=self.hby, hab=self.hab, pre=self.pre, anchor=anchor)
# also tried WitInq telquery directly
else:
doer = querying.QueryDoer(hby=self.hby, hab=self.hab, pre=self.pre, kvy=self.mbd.kvy)
I created QueryDoer instance, which invokes queryDo after initialization.
qryDoer = QueryDoer(hby=hby, rgy=rgy, alias=alias, pre=aid, anchor=anchor)
I queried KELs by AID-X, I got KELs successfully.
hby.db.clonePreIter(pre=aid)
In this step I tried to get TELs of AID-X using anchor found in KELs, but got empty response.
tvy.reger.clonePreIter(pre=anchor['i'])
I checked ragers of wits of AID-X which contain TELs but using agent I coundn't get them.
Finally when I tried to find cred issued by AID-X, which is also empty.
cred = tvy.reger.cloneCred(anchor['i'])
I appreciate your feedback if there's anything I might have missed or if you have any suggestions for alternative
approaches.
class QueryDoer(doing.DoDoer):
def __init__(self, hby, rgy, alias, pre, anchor, **kwa):
doers = []
# init properties skipped
self.hbyDoer = habbing.HaberyDoer(habery=self.hby)
@kentbull :
So are you asking how to retrieve TELs from the LMDB database for a given Agent / keystore?
@dhh1128 :
@Rubel , I am just running down a mental checklist of things that
could explain why code in keripy works, and code you wrote does
not. One potential source of differences is the witnesses that were
used. Does your code use exactly the same witnesses that the
reference code does?
We discussed this briefly on the community call today. We got to the place described in the first post on this issue -- not sure whether we're trying to pursue a dead end.
Phil's comment seems to suggest that it should be possible, but our testing did not produce useful results...
So are you asking how to retrieve TELs from the LMDB database for a given Agent / keystore?
Yes, that is what I was asking, which is a part of, though not everything, that Rubel was asking.
All of the current code for querying for TELs assumes you have a credential so you can use the registry SAID and the credential SAID to query for the TEL events related to that credential. We do not have a use case for querying for all TEL events from an issuer or from a registry.
If you have such a use case, please propose an API change to the qry
events and we can discuss it on Tuesday and figure out who wants to address this with a PR.
After listening and reading all the discussions in the past two weeks, my summary on this is that we need an option for issuers to publish their TELs to their witnesses so that the TELs are publicly discoverable, making them public TELs.
This should not be the default option as there are privacy implications for publishing the TELs of which ACDCs are issued to natural persons.
A good example use case is in the vLEI ecosystem where Qualified vLEI Issuers (QVI) issue ACDCs to legal entities. These ACDCs only contain public information of legal entities so they can be made public. This capability would allow anyone to monitor QVIs’ activities, without relying on GLEIF’s centralized API services.
Great summary @nkongsuwan , I agree with this assessment
If we pursue this design goal, then a relevant question in my mind is: How does an AID's controller signal the intention that a TEL should be public? Is this a choice that must be made when the AID is first created? Or can it be made and unmade multiple times, over the lifecycle of an AID?
If it's made when the AID is first created, does the publicness of the TEL get declared in an inception event? Or should an AID be able to make different publicness decisions about different credential registries, and have those decisions bind to the event that announces the credential registry?
Additionally, if the creds and tels are public, will it require a new API to be implemented to query an AID's credentials?
If we pursue this design goal, then a relevant question in my mind is: How does an AID's controller signal the intention that a TEL should be public? Is this a choice that must be made when the AID is first created? Or can it be made and unmade multiple times, over the lifecycle of an AID?
I don’t think this choice should be made when the AID is first created as an AID may issue a variety of ACDCs, some public and some private. For example, a QVI may issue an ECR credential (via ECR AUTH from LE) which is private. Perhaps, this may be declared in key events that anchor registry creation. In the example of vLEI, a QVI may use different registries for different types of credentials.
By design the only thing that a KEL publicizes is key state. Key state includes current signing keys, current signing key threshold, next key threshold next key digest list and backer threshold and backer identifiers. Seals that are anchored in a KEL are by design hidden. they are just hashes and maybe a reference to someother key.
This means that the AID itself has no mechanism for publishing anything about any TELs and any data that is anchored to its key state via a seal. As it should not. The publicity state of what is being sealed is sealed item dependent. Lets call these the Seal target. I.e. the seal target’s publicity is target dependent. This means any mix of public or private target’s is possible.
So given that the KEL itself cannot publicize a Seal Target how does it get published?
The primary mechanism is by an API or service endpoint. Service endpoints are can have routes attached to them via a route path string like “/public/tels”. and in some cases a return route path string like “/process/tels” This enables two things.
- peer-to-peer asynchronous connections can be connected when query to a route includes a return route for the response that comes back asynchronously
- synchronous protocols don’t need the return route but the route maps nicely to ReST APIs as a resource path.
These endpoints are discoverable dynamically via OOBIs. The endpoint can then be self-discoverable by publishing the routes is responds to, such as OpenAPI if its rest or the equivalent of a directory of routes (say at route “/“) of routes it responds to.
The querymessages in KERI support parametrized queries to a given endpoints route so they are perfectly generalizable.
The matching reply messages can return arbitrary field map documents so they are perfectly generalizable.
Likewise for the prod and bare messages except that these two are meant only for seal targets. That does not preclude query/reply from being associated with seal targets. But the former may employ different semantics. So far we don’t have any of the former supported but because a seal target is more secure than Bada/Run it makes sense to bifurcate based on its enhanced security posture. So maybe down the road.
Now given OOBIs for endpoints and routes for what get served up by those endpoints, a given AID controller now has perfect flexibility in what and when it wants to publicise. If it decides to make something public it attaches it to a route. If later it decides ot not publicize it. then it unattaches it. Nothing changes in the KEL.
If what it wants to publicise is a TEL then all it needs to do is create a route that corresponds to one of the following:
- single TEL
- a family of TELs
- parametrized TELs
- all TELs
- Tels with restricted (i.e. permitted) access and an access authentication and authorization mechanism.
Authentication and Authorization
Basically unlike federated identity, KERI and ACDCs have simplified this proble, while also removing the security problems that make it such difficult problem.
Authorization starts with a white lists of trusted AIDs as trust anchors or root-of-trust Thes trust anchors can use a combination of ACDCs and Delegated AIDs to create delegable issuances of authority. That authority can be attenuated to certain roles.
Now authentication happens upon presentations of a delegation and then authorization against the white list of trust-anchors and whatever delegable authority is allowed. Primary authentication is by verifying signatures against the current key state of the AID controller making the presentation and against ACDCs delegating authority from white listed trust anchors.
Nobearer tokens, no ephemeral tokens, no trusted third party identity providers. Each AID controller is its own identity provider. Trust anchors are not identity providers. They are not involved in the authentication process. They issue credentials which can be verified without necessarily contacting the issuer. Dynamically revocable credentials just need to have their TELs publicized to a watcher network that a verifier can access.
One can confuse a trust anchor with an identity provide, please don’t. The security role they play is materially different. They provide reputational trust not attributional trust. An identity provider provides attributional trust as a proxy for the user. In KERI the user always provides their own attributional trust. They sometimes need a reference (letter of reference) so that they can inherit or borrow enough reputation from a trust anchor to enable access. Its a completely different trust model than federated identity.
Just a sanity check, the following sentence comes from section 6.7.1 of the vLEI OOR EGF:
GLEIF MUST monitor the QVI Transaction Event Logs (TELs) to detect the issuance
of OOR vLEI Credentials which were not reported using the vLEI Reporting API.
I remember that. I don't remember why GLEIF wanted it that way.
On Feb 21, 2024, at 10:44, Daniel Hardman @.***> wrote:
Just a sanity check, the following sentence comes from section 6.7.1 of the vLEI OOR EGF:
GLEIF MUST monitor the QVI Transaction Event Logs (TELs) to detect the issuance of OOR vLEI Credentials which were not reported using the vLEI Reporting API. — Reply to this email directly, view it on GitHub https://github.com/WebOfTrust/keripy/issues/672#issuecomment-1957481332, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAETEPLA3VLFKHRCXYSYKU3YUYXALAVCNFSM6AAAAABC77YXRKVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTSNJXGQ4DCMZTGI. You are receiving this because you commented.
I believe the solution here, that Sam is referring to is a bespoke service from witnesses that represent a discovery service for published credentials. This cleanly separates what should be a simple publication of issued public credentials from Witnesses.
I think Sam described above how that service can be designed and accessed via end roles and OOBIs.