Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Spike: Investigate/document how to use OOB Connection Reuse with did:peer #2703

Closed
swcurran opened this issue Jan 9, 2024 · 24 comments
Closed
Assignees
Labels
documentation Improvements or additions to documentation

Comments

@swcurran
Copy link
Member

swcurran commented Jan 9, 2024

Now that we have did:peer:2/4 support in ACA-Py, we should be able to support connection reuse with:

  • OOB multi-use invitations
  • using did:peer:2/4

This task is to investigate this use of connections to determine how a Bifold Wallet might be able to use this.

@swcurran
Copy link
Member Author

swcurran commented Jan 9, 2024

@ianco, could you please take a look at this one? I think it should be easy to try out with the demo and the Swagger API.

@PatStLouis
Copy link
Contributor

I can look if IDLab can provide a web tool to conveniently and repeatedly generate an OOB credential offer QR code. Would this be useful @ianco ?

@ianco
Copy link
Member

ianco commented Jan 12, 2024

Just started to look at this today. I'm assuming this will use the /out-of-band/create-invitation endpoint?

How do you setup the payload to specify did:peer:2/4 (or is it an internal coding change)?

{
  "accept": [
    "didcomm/aip1",
    "didcomm/aip2;env=rfc19"
  ],
  "alias": "Barry",
  "attachments": [
    {
      "id": "attachment-0",
      "type": "present-proof"
    }
  ],
  "goal": "To issue a Faber College Graduate credential",
  "goal_code": "issue-vc",
  "handshake_protocols": [
    "did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/didexchange/1.0"
  ],
  "mediation_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "metadata": {},
  "my_label": "Invitation to Barry",
  "protocol_version": "1.1",
  "use_public_did": false
}

(above is the sample body on the swagger page)

@swcurran
Copy link
Member Author

There is a on option for triggering emitting a DID peer 2 in these scenarios —emit-did-peer-2. Integration test using did-peer-2 can be found here:

I think that is what you need to use. The trick I’m wondering about is being able to establish a connection, and then being being able to use reuse when establishing a second connection (so you only have one connection…).

@swcurran
Copy link
Member Author

My hope is that it works out of the box, and we just need to describe how to do it. But if it doesn’t work out of the box, what does happen and how do we fix it?

@ianco
Copy link
Member

ianco commented Jan 15, 2024

See PR #2713 ... I created an integration test to issue a credential and send a proof request and it fails :-(

(I think due to an overly aggressive DID validation)

Faber.agent | 2024-01-15 19:51:13,533 aries_cloudagent.messaging.models.base ERROR V20CredRequest message validation error:
Faber.agent | Traceback (most recent call last):
Faber.agent |   File "/home/aries/aries_cloudagent/messaging/models/base.py", line 200, in deserialize
Faber.agent |     schema.loads(obj) if isinstance(obj, str) else schema.load(obj),
Faber.agent |   File "/home/aries/.local/lib/python3.9/site-packages/marshmallow/schema.py", line 723, in load
Faber.agent |     return self._do_load(
Faber.agent |   File "/home/aries/.local/lib/python3.9/site-packages/marshmallow/schema.py", line 910, in _do_load
Faber.agent |     raise exc
Faber.agent | marshmallow.exceptions.ValidationError: {'prover_did': ['Value did:peer:2.Vz6MkupZQ2wUQxARjfCQfXEZksrenDvuv2erBN66MxR9tZ3cQ.SeyJpZCI6IiNkaWRjb21tLTAiLCJ0IjoiZGlkLWNvbW11bmljYXRpb24iLCJwcmlvcml0eSI6MCwicmVjaXBpZW50S2V5cyI6WyIja2V5LTEiXSwiciI6W10sInMiOiJodHRwOi8vaG9zdC5kb2NrZXIuaW50ZXJuYWw6ODA0MCJ9 is not an indy decentralized identifier (DID)']}

Both askar and askar-anoncreds fail, but with different errors

@swcurran
Copy link
Member Author

@Jsyro FYI ^^^^

@swcurran
Copy link
Member Author

@ianco — can you write up the reuse part what you did to enable reuse? How does it work — what does the invitee do, and what does the invited do to make this work? I think I see some complications, so am wondering about it.

Ignore the issue with the integration test. It’s a trivial fix, I’m pretty sure.

@ianco
Copy link
Member

ianco commented Jan 18, 2024

@ianco — can you write up the reuse part what you did to enable reuse?

On the demo I just added the --reuse-connections parameter - for example in https://github.com/hyperledger/aries-cloudagent-python/blob/main/demo/features/0160-connection.feature:

      @GHA @UnqualifiedDids
      Examples:
         | Acme_capabilities           | Acme_extra        | Bob_capabilities | Bob_extra        |
         | --public-did --did-exchange --reuse-connections | --emit-did-peer-2 | --did-exchange   |--emit-did-peer-4 |

this sets up the appropriate aca-py flags (I don't recall offhand, maybe just --public-invites?) and then the invite uses the /out-of-band endpoints with the reuse flag.

I can write this up in more detail, where should I put the docs?

@swcurran
Copy link
Member Author

Some questions about all the complications I can think of around this:

  • Just to confirm — you established two connections, and on the second, the invitee replied with the “reuse” message and everything worked?
  • So the trick is —public-did —emit-did-peer-2 and set multi-use on the invite?
  • Does the multi-use invitation use a DID Peer 2? Or does it use the invitee’s public DID that is on a ledger (presumably, a did:sov)?
  • When the connection is actually established, does the inviter’s DID have the same DID peer 2 as the invite, or does it create a new one when it sends the response message.

Thanks!

@ianco
Copy link
Member

ianco commented Jan 18, 2024

  • Just to confirm — you established two connections, and on the second, the invitee replied with the “reuse” message and everything worked?

Correct - I manually checked that the same connection was being reused

  • So the trick is —public-did —emit-did-peer-2 and set multi-use on the invite?

Yes

  • Does the multi-use invitation use a DID Peer 2? Or does it use the invitee’s public DID that is on a ledger (presumably, a did:sov)?

I believe it uses the agent's public DID (presumably a did:sov), is it possible to setup a DID using a different format?

  • When the connection is actually established, does the inviter’s DID have the same DID peer 2 as the invite, or does it create a new one when it sends the response message.

I'll need to check this ...

@Jsyro
Copy link
Contributor

Jsyro commented Jan 18, 2024

V20CredRequest

https://github.com/hyperledger/aries-cloudagent-python/blob/main/aries_cloudagent/indy/models/cred_request.py#L53

Looks like this is the class that is likely inherited by V20CredRequest that defines the prover_did regex. this needs to be updated to handle a wider range of dids. I'd probably make a new validator that imports and use the regex defined in pydid, assuming we are still leveraging that library.

https://github.com/Indicio-tech/pydid/blob/main/pydid/did.py

Let me know if i need to do this, and how we build tests for this usually in the future.

@swcurran
Copy link
Member Author

Sorry @Jsyro — I thought the comments got onto this. The correction needed is covered here, along with the explanation #2714. We need to remove the checking entirely. @ianco has that issue. It’s a trivial change (I could make it almost!) except for I want to make sure the testing is appropriately updated.

@ianco
Copy link
Member

ianco commented Feb 1, 2024

@swcurran is there any work outstanding on this issue or can we close it?

@swcurran swcurran assigned swcurran and unassigned ianco Feb 1, 2024
@swcurran
Copy link
Member Author

swcurran commented Feb 1, 2024

I can take this. Need to summarize and get it back to BC Wallet team. Thanks!

@swcurran
Copy link
Member Author

@ianco -- a couple of things in this:

  1. In step 7 of the demo, there is an error generated in the Faber log. Works fine when I do step 5 (paste in the same invitation a second time).
ERROR:asyncio:Task exception was never retrieved
future: <Task finished name='Task-60' coro=<AriesAgent.handle_connections() done, defined at /home/aries/demo/runners/agent_container.py:132> exception=KeyError('rfc23_state')>
Traceback (most recent call last):
  File "/home/aries/demo/runners/agent_container.py", line 149, in handle_connections
    if message["rfc23_state"] in ["completed", "response-sent"]:
KeyError: 'rfc23_state'

The process actually works, but the error should probably be cleaned up. Do you want me to create a new issue for that?

  1. Also, this task was intended to be that we use a did:peer:2 (or 4) as the DID in the invitation, and that we use the same did:peer:2 (or 4) in every invitation. The demo implementation instead uses the existing did:sov for the invitation. Could you do a run through (using Swagger) where you use a did:peer:2 in the invitations just to make sure that works? Once you have done, perhaps you could update the --reuse-connection implementation in Faber to use a did:peer:2 (or 4). If that is done, we have to make sure to use the SAME DID on every invitation.

If this needs clarification, or I have it wrong, lets discuss.

Thanks!

@swcurran swcurran assigned ianco and unassigned swcurran Feb 15, 2024
@ianco
Copy link
Member

ianco commented Feb 15, 2024

The connection reuse logic in the demo is a bit messed up, hence the error. I'm looking into it ...

@swcurran
Copy link
Member Author

Is there anything in ACA-Py for reuse? IMHO — the reuse should be happening in ACA-Py automagically.

@ianco
Copy link
Member

ianco commented Feb 15, 2024

I think aca-py is ok but the demo needs to respond to the webhooks etc. It looks like the demo is making some assumptions about when it should expect a new (vs existing) connection.

@ianco
Copy link
Member

ianco commented Feb 23, 2024

Opened a PR to fix some issues with the demo (PR #2813) however there are now issues with did:peer.

When running the demo using did:peer and connection reuse, alice gets the following error when accepting the connection:

Alice      | 2024-02-23 18:42:17,990 aries_cloudagent.core.conductor ERROR Exception in message handler:
Alice      | Traceback (most recent call last):
Alice      |   File "/usr/local/lib/python3.9/asyncio/tasks.py", line 256, in __step
Alice      |     result = coro.send(None)
Alice      |   File "/home/aries/aries_cloudagent/core/dispatcher.py", line 253, in handle_message
Alice      |     await handler(context, responder)
Alice      |   File "/home/aries/aries_cloudagent/protocols/didexchange/v1_0/handlers/response_handler.py", line 29, in handle
Alice      |     conn_rec = await mgr.accept_response(
Alice      |   File "/home/aries/aries_cloudagent/protocols/didexchange/v1_0/manager.py", line 845, in accept_response
Alice      |     await self.record_did(response.did)
...
Alice      |   File "/home/aries/.local/lib/python3.9/site-packages/pydid/verification_method.py", line 52, in __init__
Alice      |     super().__init__(**data)
Alice      |   File "pydantic/main.py", line 341, in pydantic.main.BaseModel.__init__
Alice      | pydantic.error_wrappers.ValidationError: 1 validation error for Ed25519VerificationKey2018
Alice      | publicKeyBase58
Alice      |   none is not an allowed value (type=type_error.none.not_allowed)

Also it looks like the DID in the invitation isn't a did:peer.

@swcurran would appreciate some guidance here, should the connection automatically use a did:peer or does the controller need to create one explicitly? (This also doesn't work right now, when to create a wallet DID and specify did:peer:2 it raises an error, and it looks like did:peer:4 isn't supported?)

@swcurran swcurran self-assigned this Feb 23, 2024
@swcurran
Copy link
Member Author

I think the goals are:

  • we likely want to have a default flow that uses a did:peer:2 or did:peer:4 (based on the emit… setting) for OOB invitations.
    • did:4… if no setting
  • the same DID is used for all invitations to enable reuse.
    • perhaps an override could be given on generating an invitation. But if not already there, don’t bother.
  • the DID should be automatically created if it doesn’t exist when creating an invitation (e.g., the first one)
    • If that is not in the existing flow, perhaps we don’t need that? E.g. if the controller already has to do it explicitly.
    • the Controller could create their own "invitation" DID for use as “the DID” for invitations before the first. That would allow them to, for example, create/use a did:sov DID for invitations if they really want to.

What does the current flow look like?

Thanks

@ianco
Copy link
Member

ianco commented Feb 26, 2024

I think the goals are:

  • we likely want to have a default flow that uses a did:peer:2 or did:peer:4 (based on the emit… setting) for OOB invitations.
    • did:4… if no setting

I don't think this is a big deal, we just need to generate a did:peer:* DID for the invitation

  • the same DID is used for all invitations to enable reuse.

You mean for all invitations? Or just for re-use? I'm not sure the best way to do this, other than checking (when they create a new multi-use invitation) to see if there is already an existing multi-use invitation (and then re-using it). Otherwise we need to create a special DID in the wallet and tag it somehow.

  • perhaps an override could be given on generating an invitation. But if not already there, don’t bother.
  • the DID should be automatically created if it doesn’t exist when creating an invitation (e.g., the first one)

    • If that is not in the existing flow, perhaps we don’t need that? E.g. if the controller already has to do it explicitly.
    • the Controller could create their own "invitation" DID for use as “the DID” for invitations before the first. That would allow them to, for example, create/use a did:sov DID for invitations if they really want to.

The "create DID" API currently doesn't work for did:peer:* DID's ...

What does the current flow look like?

I'll put some more details in another comment.

@swcurran
Copy link
Member Author

Reuse should work for all invitations by default, single- and multi-use. All agents should want to support reuse, so we want to make that path easy, and an agent can go out of their way to not support reuse. I don’t know of a use case where they don’t want to support reuse.

Otherwise we need to create a special DID in the wallet and tag it somehow.

Yes — I think that is what we need to do.

I was kind of worried we didn’t support this, especially with did:peer:2/4, hence this ticket :-). So it is not just a clarify, but real work...

@ianco
Copy link
Member

ianco commented Feb 26, 2024

  1. Add support for creating did:peer:2 and did:peer:4 to the POST /wallet/did/create endpoint. Also add an optional tag to specify the did's "role" (for now the only possible role is to make the did the default for use in invitations).
  2. For the OOB invitation, by default use the tagged did when creating an invitation (unless "public did" is selected). If there is no existing did already tagged for use in invitations, then create one. Provide an optional flag - "use unique did" - for any use cases where the inviter wants to issue a unique did per invitation (for example they don't want the invitee to reuse connections, possibly for privacy purposes).
  3. When creating a did for invitations (when it has to be done automatically), use the overall aca-py setting (--emit-did-peer-2, --emit-did-peer-4, or by default use a did:key)
  4. The invitee should always check if the invitation contains an existing did (i.e. already used to make a connection) in which case it should reuse the existing connection.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
documentation Improvements or additions to documentation
Projects
None yet
Development

No branches or pull requests

4 participants