hyperledger / aries-rfcs

Hyperledger Aries is infrastructure for blockchain-rooted, peer-to-peer interactions
https://hyperledger.github.io/aries-rfcs/
Apache License 2.0
324 stars 218 forks source link

RFC 0023: Can we accept inline peer did without a signature? #717

Closed jakubkoci closed 9 months ago

jakubkoci commented 2 years ago

DID Exchange request message attributes contain the following specification for DID Document:

  • The did_doc~attach (optional), contains the DIDDoc associated with the did, if required.
    • If the did is resolvable (either an inline peer:did or a publicly resolvable DID), the did_doc~attach attribute should not be included.
    • If the DID is a did:peer DID, the DIDDoc must be as outlined in RFC 0627 Static Peer DIDs.

Also, as I understood from the rest of the DID Exchange specification, when the did_doc~attach is present, it should contain a signature which we need to validate.

If the did is resolvable public DID. We can still trust that the sender (owner of that public DID) controls private keys because it's written to a ledger therefore we don't need to validate signatures. However, if the did is inline peer:did, there are no signatures present. Can we still accept such peer:did?

TelegramSam commented 2 years ago

Signatures were never needed in the Requests, and were added by mistake by... me. Does this address your confusion?

TimoGlastra commented 1 year ago

This is still an issue, and is surfaced again by the move to did:peer:2.

In this case there's no diddoc to put the signed attachment on (same with public dids).

For the request I think it's fine to nit require a signature, as long as the didcomm message used to send the request is authenticated using one of the keys from the diddocument.

However the response signature it's required when you rotate the key used from the invitation in the response. We should have an alternative. I think signing the did from the invitation (as base 64) should suffice in this case.

Can we make a modification to the protocol to allow: 1) the request message not to be signed. For did:peer:1 dids it's still required to not break interop, but for all resolvable dids, the signed attachment SHOULD NOT be present 2) do not require the response message to be signed. For did:peer:1 dids it's still required to not break interop, and if the did from the invitation is rotated, it must also be signed by the invitation did. for all resolvable dids, the signed attachment SHOULD NOT be present. If a resolvable did is used, and the key/did from the invitation is rotated in the response, a new property should be added to the response (e.g. "invitation_did~attach") that contains the did from the invitation that is being rotated base64 encoded, and signs it with a key from the invitation did. This authenticated the did rotation from invitation to response (and is important to keep for multi-use invitations with public dids that rotate to peer dids)

Simpler solutions welcome, but this would be straightforward to implement i think, and somewhat non-breaking (as there's no implementations AFAIK not using did:peer:1 atm). Alternative solution is to still attach the resolved did document for resolvable did documents, but we can't enforce that the did documents should match in that case as different resolver implementations returns different structures. We could require for semantic equalness but that would require a complex implementation. So basically it would mean you can use any document in the signed attachment, as the did document would not be stored (as it's resolvable)

swcurran commented 1 year ago

@TimoGlastra — can you join the Aries Working Group meeting on Wednesday so that we can go over this and discuss. A presentation of the before and after would be helpful.

FYI - @TelegramSam

genaris commented 1 year ago

@mirgee @Jsyro @dbluhm what do you think about the approach proposed by @TimoGlastra ? I think that now we are all working on the implementation for did:peer:2 in Aries VCX, ACA-Py and AFJ it is a very good moment to reach consensus on this and move forward with the implementations, so we can start running some tests in the AATH.

swcurran commented 1 year ago

I could use a presentation (with pictures! :-) ) and a discussion about this to better understand the proposal and its impact.

AFAIK, only AFJ is using did:peer:1, and there is no plan for others to use it. We want to go to did:peer:2/3, or to go to a new proposal from @dbluhm and @TelegramSam of did:peer:4 (see this issue to the peer-did-spec).

I’ve also put in a proposal to eliminate much of the asperational wording in the did:peer:spec — things like updates to the DIDDoc (key rotation), which are just not going to happen, IMHO. See this PR.

The sooner we eliminate all but did:peer:4 (or did:peer:2/3), the better.

genaris commented 1 year ago

did:peer:4 already? What a moment to be alive! 🤯

TelegramSam commented 1 year ago

The signature was in theory to verify that the other party held the associated private key, and is therefore authorized to rotate to a new DID.

As long as the request message is sent encrypted to the key present in the invitation, the only way the message can be processed is by possessing the private key. The receipt of the provided DID in the request message and subsequent response message will ONLY arrive if the private key could be used to decrypt the request message. Therefore, the signature in the response message is unnecessary to gain confidence that the party has access to the private key associated with the public key in the invitation.

Notably, the RFC says nothing about signature requirements, and is only present in the examples. No signatures are required, with non loss of confidence.

TimoGlastra commented 1 year ago

I think that would at least warrant a big disclaimer. This means that the publicKey + threadId is now the basis of trust in an exchange. While before we had cryptographic assurance.

A hacker wouldn't even have to steal the private key of the inviter to steal the connection, 'stealing' the public key of the requester + the thread id is enough to be able to send a response message. Sure this is not a flow that is easily exploited. But there's definitely some security implications here over signing off on using another key in the response than was used in the invitation.

warren-gallagher commented 1 year ago

The signature was in theory to verify that the other party held the associated private key, and is therefore authorized to rotate to a new DID.

As long as the request message is sent encrypted to the key present in the invitation, the only way the message can be processed is by possessing the private key. The receipt of the provided DID in the request message and subsequent response message will ONLY arrive if the private key could be used to decrypt the request message. Therefore, the signature in the response message is unnecessary to gain confidence that the party has access to the private key associated with the public key in the invitation.

Notably, the RFC says nothing about signature requirements, and is only present in the examples. No signatures are required, with non loss of confidence.

The spec does not speak to how thread ids are generated, nor whether it is expected that new DIDs are being generated for most/all did exchanges. If we assume that thread Ids are random and that DIDs are generally not reused across relationships, then I agree that the the signature is not necessary.

TelegramSam commented 1 year ago

Let me expand a little bit for clarity and out loud thinking.

In order to send a response message, you need to know the requester's selected request message/threadid (same thing) and DID (key and endpoint). These are encrypted in the request message.

RFC 0008 specifies that Message IDs must be sufficiently unique, with a UUID recommended.

It is also not required to send a unique DID in the request message of the DID Exchange protocol.

Given the lack of MUST style requirements, the spec insufficiently guarantees sufficient randomness. In practice, I believe that UUIDs are used for thread IDs.

This means that after further discussion/thought, I think @TimoGlastra is right:

But there's definitely some security implications here over signing off on using another key in the response than was used in the invitation.

That leaves two options:

Option 1: Add a huge disclaimer to the DID Exchange Protocol (which should have been there since the beginning for non-peer DIDs) that highlights the necessity of UUIDs/sufficiently random for message IDs, and the danger of reusing a DID in the request message. This is likely enough, but is (as discussed above) not immune from poor execution.

Option 2: Add an optional attachment in the response message where the response method's DID is signed with the key used in the invitation. We specify in the Community Coordinated Update that this is required. This option results in no loss of cryptographic confidence.

Thoughts?

jakubkoci commented 1 year ago

It seems we should use some mechanism of signing with DID from invitation. I'm not sure if we should rely on the security of thread ID and public key. To me, it adds a burden on implementers. They have to understand what's the problem, the attack vector, and how to mitigate it. If I implement the did-exchange protocol, should I care how the security of thread IDs and public keys is preserved? It might not even be in my hands because I'm just adding one particular protocol to a library that takes care of threading and public key management.

Maybe, we can rely on DIDComm authcrypt. Require in specification that the response message must be sent via authcrypt, using the DID from the invitation. But that's, again, something outside of the protocol itself.

JamesKEbert commented 2 months ago

I realize this is slightly old news now, but I'm trying to understand the motivating reason behind the addition of the did_rotate~attach.

Am I correct in understanding that the issue here is that we cannot rely on the DIDComm authcrypt due to the response message being packed using the new keys presented within the response message itself? Therefore, if a malicious actor could intercept a request message, they could respond with a response message (packed with the new keys) and successfully steal that peer-to-peer relationship.
RFC 0023 states in regards to the response transmission:

The message should be packaged in the encrypted envelope format, using the keys from the request, and the new keys presented in the internal did doc.

If in theory, the RFC was adjusted to use authcrypt using the keys used in the invitation, how could a malicious actor send a response message without having access to the private keys? In this case I'd assume the signature in the response would just be duplicative assurance. But I am potentially missing something here, and would love to be enlightened to it.