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

Discussions for EIP: Add DID related methods to the JSON-RPC #2845

Closed
oed opened this issue Aug 1, 2020 · 79 comments
Closed

Discussions for EIP: Add DID related methods to the JSON-RPC #2845

oed opened this issue Aug 1, 2020 · 79 comments
Labels

Comments

@oed
Copy link
Contributor

oed commented Aug 1, 2020

https://eips.ethereum.org/EIPS/eip-2844

@oed
Copy link
Contributor Author

oed commented Aug 3, 2020

Replying to @kdenhartog from the duplicate discussion thread #2851

Original message:

My first round of feedback for this:

One of the general topics that's been discussed quite a bit is if we want to restrict the algorithms and key types supported in the JOSE registries. Often times this is done to limit the scope of code that needs to be written by various implementations which in turn should bolster interoperability. I see you've done this via recommendations, but I'd wonder if we want to restrict further usage here via explicitly not supporting certain algorithms. Is that something you think would be beneficial?

Note: This next piece of feedback is based on potentially misunderstanding the paths permission aspect. I'd like to figure out more about this and then we may not need to address the comments below. Additionally, I'd like to understand the architecture of where the operations are being performed because I'm thinking I misunder

Another point that I caught quite quickly is that this EIP is looking to use DIDs to manage discoverability of keys. I'm happy to see this approach being taken further as I think it will help quite a bit. I hope it's an approach that more DApps look to use as well. With that in mind, one of the things that I wasn't sure about was how the API would be integrated with key management to perform the sign and encrypt operations. Is your current assumption that a Key Management architecture will be used within the implementation and it's the responsibility of implementers to be handle this? In general, every JOSE implementation I've looked at has made the assumption that the private key is provided in some way and it will perform the cryptographic operation when necessary. This is slightly different from what's proposed at this point though. I think we may need to think more about what the general expectation is on the implementers and the callers in terms of who's providing which data (private key), who's performing the cryptographic operations, and who's performing the structuring of the data (e.g. creating the JWE with the signed data). From there we'll likely want to take a look at the general API design to make sure it aligns with what's generally done by wallets and other DApps that would be using this API.

I'm also interested to know more about why encrypt and verify were not included. I assume there's back history from the previous attempts that may further explain this. Have they already been added via other APIs or was there some other reason that they were left off?

In general though @oed, I like the direction that you're going with this and I'm curious to hear others opinions on this.

Personally I would be fine with restricting the alg and key types to the ones that are supported by JOSE registries (are those used by default for COSE as well?).

So the JSON-RPC is used for two main things with ethereum. Interacting interacting with chain state, and requesting things from the wallet. This means that it acts as a way for an app to request signatures and account information from a wallet. So in our case here the only things needed to be done wallet side is signing and decrypting. Internally wallets are free to use whichever key management system they prefer. A caller of any of these methods won't need to provide any type of key material.
Both verifying and encryption can happen completely client side (without any wallet interaction) so there is no need to add methods for them. Instead a utility library that does this can be implemented (we're thinking about implementing these utility functions in the js-did library).

@OR13
Copy link

OR13 commented Aug 3, 2020

Things to consider...

secp256k1 supports ecdsa (ES256K JWS) and Schnorr (SS256K (not registered!)).... and UPort created ES256K-R which is similarly not registered... and it identical to ES256K with appended recovery byte...

IMO, making the header a required RPC argument, and restricting the valid values of alg is a good way of addressing this issue.

There is also detached JWS https://tools.ietf.org/html/rfc7797 ... this is really useful for when you are signing binary... not some JSON.stringify-iable data (lots of issues with canonicalization and JOSE)....

It's also the default JWS format used by Linked Data Proofs.

I'm not sure adding the did_* prefix to RPC calls is wise.... especially if what we are really doing is exposing JOSE / COSE interfaces.... I would prefer to see jose_jws_sign and jose_jws_sign_detached... and the COSE equivalents.

@oed
Copy link
Contributor Author

oed commented Aug 4, 2020

Thanks @OR13

secp256k1 supports ecdsa (ES256K JWS) and Schnorr (SS256K (not registered!)).... and UPort created ES256K-R which is similarly not registered... and it identical to ES256K with appended recovery byte...

Good point. I should probably explicitly say ES256K 👍

IMO, making the header a required RPC argument, and restricting the valid values of alg is a good way of addressing this issue.

Hm, seems like this would require the application developer to be aware of which algs the wallet supports. This would mean that there needs to be an additional rpc method for getting this information. I'd rather have the wallet decide this and append the alg that it is using.

There is also detached JWS https://tools.ietf.org/html/rfc7797

Happy to add this if others express interest.

I'm not sure adding the did_* prefix to RPC calls is wise.... especially if what we are really doing is exposing JOSE / COSE interfaces.... I would prefer to see jose_jws_sign and jose_jws_sign_detached... and the COSE equivalents.

The whole point here is to enable DID signed JOSE/COSE objects. Essentially by setting the kid to the DID (and key fragment) for the signing entity. Imo this is critical for this EIP to be successful. Using did_* for decryption also simplifies things because the combination of key discovery and decryption is key for dev UX.

@OR13
Copy link

OR13 commented Aug 4, 2020

If the developer is not required to know which signing algorithms are supported and set the header explicitly, a default header should be provided.... which defaults will be used?

+1 to using kid and making its default value of the form did:example:123#fragment

what about all the developers who want JWTs / JWSs but don't care about DIDs?... I agree that the APIs should be simple, but i question why they should start with dids... to me... dids are more of an option for setting the kid.... but I am assuming there would be APIs for retrieving JWKs.... so the entire system can be used with or without DIDs.

@oed
Copy link
Contributor Author

oed commented Aug 4, 2020

which defaults will be used?

That's up to the wallet implementer (a reccommendation is provided in the EIP)

but I am assuming there would be APIs for retrieving JWKs

What do you mean by this exactly? To me this is what you would use the DID for. Using did:ethr would be the most straight forward way for wallets to support some way of distributing JWKs, as all ethereum wallets support did:ethr already.

@OR13
Copy link

OR13 commented Aug 4, 2020

put another way...

what RPC interfaces will be provided for getting public key bytes....

possibly options:

did_resolve -> didDocument as json
jose_get_jwk_by_kid -> JWK
did_jws_verify vs jose_jws_verify

For example... Tangem cards support a "getPublicKey" NFC interface. You can then use that interface to verify signatures... the cards themselves don't support "verifying on the card".... thats similar to the concept of "verifying on the rpc server"...

I'd prefer to have a JOSE RPC interface, that happened to work with DIDs... and a DID RPC interface that supported things like:

resolution (which returns a set of keys, and their associated relationships)...

those relationships have nothing to do with JOSE... they are no mentioned in the JOSE RFCs... they were created in DID Core.

@oed
Copy link
Contributor Author

oed commented Aug 6, 2020

what RPC interfaces will be provided for getting public key bytes

This is what did_authenticate is for. With it you will get back the DID that was authenticated. To get the public key bytes you can use something like the DID Resolver which works with any DID method (provided a resolver is implemented for it).

The problem with an RPC method like did_resolve is that it's not really the responsibility of a wallet to resolve DIDs for apps. Instead Ethereum clients would need to implement this method, but then there has to be consensus among client implementers which DID methods to support (would be very hard). I also think DID resolution is more of an application on top of blockchains rather than something that should be implemented in blockchain client software.

@awoie
Copy link
Contributor

awoie commented Aug 11, 2020

did_authenticate should return a proof-of-control of the DID and should expect an aud/ domain and nonce / challenge parameter. I don't know which data format the proof should have and whether it would be allowed to support different formats but it could be either a JWS or CWS.

Updated:

You might be able to use the path as the challenge.

@awoie
Copy link
Contributor

awoie commented Aug 11, 2020

I guess did_createCWS should return a CWS, so there might be a typo in the return value.

Returns:
A CWE encoded as base64, string

^^should be rather CWS, right?

@awoie
Copy link
Contributor

awoie commented Aug 11, 2020

Is there a reason to not include an API for:

  • did_createCWE
  • did_createJWE

?

Update:

That certainly only makes sense using authcrypt -> e.g., ECDH-1PU

@awoie
Copy link
Contributor

awoie commented Aug 11, 2020

Is the did parameter needed if the kid or something similar could be used to determine the DID in the CWE/JWE?

@awoie
Copy link
Contributor

awoie commented Aug 11, 2020

Is it needed to recommend a decryption algorithm for decryption? The decryption algorithm can be determined from the CWE/JWE directly, trying to decrypt the CWE/JWE with a different algorithm, would fail anyways. In general I agree that ECDH-ES (X25519) + XChacha20Poly1305 should be recommended.

@pedrouid
Copy link
Contributor

did_authenticate should return a proof-of-control of the DID and should expect an aud/ domain and nonce / challenge parameter. I don't know which data format the proof should have and whether it would be allowed to support different formats but it could be either a JWS or CWS.
This definitely would be super useful and best practice that should be adopted by all Ethereum wallets IMO

Me and @wighawag drafted a similar proposal last year where accounts would be exposed with signatures for a given challenge.

https://ethereum-magicians.org/t/automatic-authentication-signature/2429

If this pattern would be possible with did_authenticate by default then we could replace the current eth_requestAccounts with this method instead to include proof-of-control

Same dapps currently after getting the user's accounts follow up with a personal_sign request to attest for the private key ownership or even to access the public key of the account.

I think this should just be the default behavior for all dapp and wallet interoperability

@oed
Copy link
Contributor Author

oed commented Aug 11, 2020

Adding a challenge makes sense! Thanks for suggesting @awoie and clarifying @pedrouid. Will add this when I update the draft. Might make sense to make this an actual JWT/CWT with an expiry actually. A challenge should definitely be included.
What is your thinking on aud @awoie? Is it strictly needed?

I guess did_createCWS should return a CWS, so there might be a typo in the return value.

Nice catch!

That certainly only makes sense using authcrypt -> e.g., ECDH-1PU

Would you mind expanding on this? And yeah for the suggested encryption alg you can just do the encryption client side.

Is it needed to recommend a decryption algorithm for decryption?

It's really up to the wallet to decide what to use, and state that in their DID document.

Is the did parameter needed if the kid or something similar could be used to determine the DID in the CWE/JWE?

The kid should not specified in the JWE/CWE. That would leak information about the ciphertext.

@awoie
Copy link
Contributor

awoie commented Aug 11, 2020

Adding a challenge makes sense! Thanks for suggesting @awoie and clarifying @pedrouid. Will add this when I update the draft. Might make sense to make this an actual JWT/CWT with an expiry actually. A challenge should definitely be included.

nonce has that purpose in id_token JWTs in OIDC (see IANA claims registry). If you introduce a new claim for this purpose, then registering a new claim name in the IANA should be considered.

What is your thinking on aud @awoie? Is it strictly needed?

aud can be optional and it can be any arbitrary stringOrUri. I think it would be good practice to make use of that. Everyone that receives the JWS would have to identify itself and then decide whether to reject the JWS. Not sure what is the CWS equivalent.

That certainly only makes sense using authcrypt -> e.g., ECDH-1PU

Would you mind expanding on this? And yeah for the suggested encryption alg you can just do the encryption client side.

ECDH-1PU is for example used in DIDComm-messaging to encrypt a message to a DID while enabling the receiver of the encrypted message to verify some sort of authenticity that the sender is has a certain DID (or more general keys) by avoiding the sign-JWS-then-encrypt-JWE pattern. In that case, only the wallet would be able to create such a JWE/CWE because only the wallet controls the private key.

Is the did parameter needed if the kid or something similar could be used to determine the DID in the CWE/JWE?

The kid should not specified in the JWE/CWE. That would leak information about the ciphertext.

The kid won't be in the Ciphertext of the JWE. It would be in the unprotected header field per recipient: see https://tools.ietf.org/html/rfc7516#section-4.1.6. You could use the same pattern as you described for JWS/CWS and use a DID URL.

@oed
Copy link
Contributor Author

oed commented Aug 12, 2020

nonce has that purpose in id_token JWTs in OIDC (see IANA claims registry).

Great, let's use nonce 👍

aud can be optional and it can be any arbitrary stringOrUri.

Ok, so this would be optionally set by the wallet?

ECDH-1PU is for example used in DIDComm-messaging to encrypt a message to a DID while enabling the receiver of the encrypted message to verify some sort of authenticity that the sender is has a certain DID (or more general keys) by avoiding the sign-JWS-then-encrypt-JWE pattern.

Makes sense, but seems a bit out of scope for now. Could easily be addressed in an additional EIP!
Q: Is the receiver the only party that can verify sender authenticity or can everyone do it?

The kid won't be in the Ciphertext of the JWE.

That's my point :) In some cases you might not want to leak information about whom the ciphertext is intended for.

@OR13
Copy link

OR13 commented Aug 13, 2020

kid is optional everywhere, but for JWS, its pretty critical for handling resolution of public key bytes for verification, see this list of JOSE /. DID issues:

https://github.com/decentralized-identity/did-jose-extensions/blob/master/options.md

TL;DR; I'd rather see use of kid defined consistently as pointing to a verificationMethod id... than see people keep creating 1 off spec text to handle key lookups without using JSON-LD.

@OR13
Copy link

OR13 commented Aug 13, 2020

I agree we should postpone encryption until we have signatures. can we take an inventory of the proposed RPC methods?

@awoie
Copy link
Contributor

awoie commented Aug 13, 2020

There is also detached JWS https://tools.ietf.org/html/rfc7797 ... this is really useful for when you are signing binary... not some JSON.stringify-iable data (lots of issues with canonicalization and JOSE)....

@oed @OR13 Does it make sense to also support JWS JSON serialization? What happens if a DID has more than one signature key attached to it?

@OR13
Copy link

OR13 commented Aug 13, 2020

I assume the API interface would support specifying the exact key to use for signing....

For example: https://github.com/transmute-industries/did-key.js/blob/master/packages/secp256k1/src/__fixtures__/index.ts#L58

did:example:123#fragment is a URI that identifies the public "verification side" of the private "signing side"...

I would consider a wallet API that didn't let me choose the signing key pretty broken, in all cases where there was more than 1 signing key.... its not clear to me that is the case for did:ethr or secp256k1 did:key however... since the did identifies a particular public / private key pair.

@awoie
Copy link
Contributor

awoie commented Aug 13, 2020

I assume the API interface would support specifying the exact key to use for signing....

For example: https://github.com/transmute-industries/did-key.js/blob/master/packages/secp256k1/src/__fixtures__/index.ts#L58

did:example:123#fragment is a URI that identifies the public "verification side" of the private "signing side"...

I would consider a wallet API that didn't let me choose the signing key pretty broken, in all cases where there was more than 1 signing key.... its not clear to me that is the case for did:ethr or secp256k1 did:key however... since the did identifies a particular public / private key pair.

With JSON Serialization you would be able to send multiple signatures back in case the DID controls a few signing keys. That was why I brought that up.

@OR13
Copy link

OR13 commented Aug 13, 2020

@awoie hm so the interface would be kid: array<did_uri>, payload: any, header: any=> json serialized JWS

Seems useful.

@oed
Copy link
Contributor Author

oed commented Aug 13, 2020

TL;DR; I'd rather see use of kid defined consistently as pointing to a verificationMethod id...

Makes sense. This was my intention. Maybe that was unclear?

Does it make sense to also support JWS JSON serialization? What happens if a DID has more than one signature key attached to it?

I'm agnostic as to which serialization to use. I'm curious though what the use case is for signing with multiple keys from the same DID? If you want to have two different DIDs sign the same payload you can just take two JWS with compact serialization and reserialize them using the JSON serlialization (which is trivial).

I assume the API interface would support specifying the exact key to use for signing....

Yeah exactly. You can already specify the fragment in the did param of did_createJWS.

@kdenhartog
Copy link
Contributor

take two JWS with compact serialization and reserialize them

Would this break the signatures of the two because of the non-payload data being signed (e.g. protected headers)?

If not, it would be cool to enable multi-signature supports as a separate API where a JWS can be passed in with the DID and it will de-assemble the JWS and sign the payload/header data and then that JSON serialized JWS could be passed as a form of a multi-signature to something like a smart contract or any other verifier for that matter.

@wighawag
Copy link
Contributor

Thanks for creating this proposal.

Regarding did_authenticate. From the discussion, It looks like it has multiple purpose

The current draft of this proposal specify that did_authenticate requires user permission. This seems important if authentication is used for something other than ensuring that the user indeed control the did (the private key of the ethereum address presented).

Otherwise, as @pedrouid mentions, did_authenticate could simply replace eth_requestAccounts, see in particular: https://ethereum-magicians.org/t/eip-1102-opt-in-provider-access/414/58 which would already require user to accept showing their did.

But looking at the current draft of the proposal here, it seems that did_authenticate performs more than simply checking if the user control the did being advertised.

It accept a path parameter. And then further in the proposal it is mentioned that decryption happen without user confirmation only if did_authenticate was already accepted for a particular path.

If we go with the idea that did_authenticate replace eth_requestAccount, the path should default to the application origin (like in eth_requestAccount) then the only prompt should be about accepting to reveal your did, the authentication is then done automatically so the application can be sure the user is indeed in control of that did and is not someone faking it.

Any other path would require user confirmation.

Furthermore as mentioned here and explained in Proposal 1: Non-Interactive Decryption
If we consider the default path being the application origin,
Then decryption should happen automatically for every encryption performed from that same origin. No user confirmation should be required there. For that a mechanism should be put in place so that encryption include the origin in the data.

diagram

This would allow a seamless encrypted storage for application, that can then be safely shared across devices.
Of course this is only fully under user control for application on content-addressable system like ipfs, but as mentioned in my comment and blog, an ENS or even DNS name that point to an ipfs hash should use the ipfs hash as the origin (not the ENS name).

Now if the content change (and so the uri), the user would be requested to did_authenticate the new "path"

Now, I am not very knowledgeable with JWS and I might abuse term "path" here by allowing it to represent URI. If that is the case, we could separate the 2.

Note: for traditional URI (non content-addressable) it could be up to the wallet to decide whether a user confirmation is required as there is a security risk that the application get compromised.

@oed
Copy link
Contributor Author

oed commented Aug 14, 2020

Would this break the signatures of the two because of the non-payload data being signed (e.g. protected headers)?

It wouldn't. Each signer is free to choose what to put in their protected header. For example they would need to put their own kid in there.

@oed
Copy link
Contributor Author

oed commented Aug 14, 2020

@wighawag While we could use path like that I would strongly advise against it since it would incentivize apps to silo data around their origins. Where as if you just use a path unrelated to origin this would make it easier to share data across apps.

I'm saying this mainly because I believe data should always be independent of the app that is bee used to display the data.

@wighawag
Copy link
Contributor

@oed I agree that we should not silo data. But here the proposal is to remove the need for approval for the default case.
This is better for the uers and that's why I think it should be that way.
No reason to request a confirmation when the application that request decryption was the one encrypting it.
Other application can alwasy request user to approve them for that origin. not big deal

@oed
Copy link
Contributor Author

oed commented Oct 28, 2020

Updated the EIP. Let me know if I missed something or if you have additional suggestions :)

@OR13
Copy link

OR13 commented Oct 28, 2020

why is version-id required? and how is its value calculated?

a signature from a specific version is similar to a signature from an issuer which never does key rotation... it will always verify.... defeating the purpose of many signatures.... however, there are cases you only care that the signature was valid at the time in the past when the keys were active, and you don't care if the signature valid for the current version.

Consider that an attacker will have "active keys for a version" if they compromise any version, so rotation no longer insulates the controller from being impersonated.

also version-id is not implemented by many did methods, so folks may be less familiar with it.

Since this is an EIP, it might be helpful to provide concrete data model examples using:

@awoie
Copy link
Contributor

awoie commented Oct 28, 2020

Interesting @kdenhartog what would the payload and header look like if we would use JWM?
Would also be interested in input from @awoie here!

@oed DIDComm v2 as it is proposed right now, won't use compact serialization.

Example JWM (JWE) that is used in DIDComm v2 -- JWS and plain-text will be also supported:

{
    "protected": "<encoded protected header from above>",
    "recipients": [
        {
            "header": {
                "alg":"ECDH-1PU", //authcrypt
                "kid": "did:ex:recipient?version=x#key_id"
                "apu":"QWxpY2U",
                "apv":"Qm9i",
                "epk": {
                    "kty":"EC",
                    "crv":"X25519",
                    "x":"gI0GAILBdu7T53akrFmMyGcsF3n5dO7MmwNBHKW5SV0",
                    "y":"SLW_xSffzlPWrHEVI30DHM_4egVwt3NQqeUD7nMFpps"
                },
                "encrypted_sender": "<encrypted({'kty':'OKP','crv':'X25519','x':'3p7bfXt9wbTTW2HC7OQ1Nz-DQ8hbeGdNrfx-FG-IK08'})>"
            },
            "encrypted_key": "<cek, encrypted to kid>"
        }
    ]
    "iv": "<generated iv>",
    "ciphertext": "<JWM encrypted with cek>",
    "tag": "<generated tag>"
}

Example payload (other claims might be included):

{
  "id": "<message id>",
  "type": "<message type>",
  "from": "did:ex:sender",
  
  // contains id of the first message in the thread
  "thread_id": "<thread id>",
  
  "body": { 
      // sub-protocol message according to <message type>
  }
}

@awoie
Copy link
Contributor

awoie commented Oct 28, 2020

@oed @OR13 @kdenhartog imo, the did_* API should also support JSON serialization, or if the first version does not support other serialization options than compact serialization, then i would rename the API, or introduce a place holder parameter that indicates the type and have compact as the default option. further, it would be great if we could continue the work on this to add support for JWM and more specifically JSON serialized JWE which are used in DIDComm v2.

another point that i want to make is to add an did_encryptJWE for authcrypt. it would be specifically great to get feedback on the usefulness from @kdenhartog on this.

@awoie
Copy link
Contributor

awoie commented Oct 28, 2020

@oed did_authenticate is missing the aud parameter, or will this be derived from paths?

@oed
Copy link
Contributor Author

oed commented Oct 30, 2020

@OR13

why is version-id required?

Thanks, it shouldn't be. Will change the wording.

Consider that an attacker will have "active keys for a version" if they compromise any version, so rotation no longer insulates the controller from being impersonated.

This is not always true. For example in Ceramic each update that is made is anchored in a blockchain. This makes it possible to determine if a key that signed the update was valid at the time the anchor was made.

Not sure how blockchainAccountId is relevant here. Mind elaborating?

@awoie good point about serialization. Meant to change it to general, will make another update!

another point that i want to make is to add an did_encryptJWE for authcrypt. it would be specifically great to get feedback on the usefulness from

Can you please provide a specification for this? I don't know how that should work.

did_authenticate is missing the aud parameter, or will this be derived from paths?

Good point, will add the aud param there.

Have the updates here: https://github.com/oed/EIPs/blob/chore/additional-2844-udates/EIPS/eip-2844.md Will make a PR after some more time for feedback 👍

@OR13
Copy link

OR13 commented Oct 30, 2020

This makes it possible to determine if a key that signed the update was valid at the time the anchor was made.

right, but when that signature is the first evidence of a compromised key, and the signature remains valid forever (because its pinned to a version), this removes a lot of the value of dids and key rotation...

id_token and access_token are not signed with keys that were "once valid"... they are signed with keys that are "currently" valid... and checking that they are still valid is part of verifying them.

If you were to sign an id_token with a pinned version it would be valid forever.... even after that key was compromised.

blockchainAccountId

^ This is a generic way of representing ethereum addresses, and bitcoin addresses (and others) and its part of DID Core. ethereumAddress is not part of DID Core.

@awoie
Copy link
Contributor

awoie commented Oct 30, 2020

If you were to sign an id_token with a pinned version it would be valid forever.... even after that key was compromised.

I would disagree with that. The id_token would remain valid until it has expired indicated by the exp claim.

@awoie
Copy link
Contributor

awoie commented Oct 30, 2020

This makes it possible to determine if a key that signed the update was valid at the time the anchor was made.

right, but when that signature is the first evidence of a compromised key, and the signature remains valid forever (because its pinned to a version), this removes a lot of the value of dids and key rotation...

IMO, a mix might be desired. For example, if you look at the SSI use case. An issuer provides a VC to a subject/holder. The VC could contain the DID of the issuer + version property. If think it is desirable to being able to verify that the VC was valid at least once. In case the issuer key got compromised, then I would expect that the issuer would revoke the credential through the revocation method of their choice (e.g., through some onchain accumulator). The VC would need to contain a credentialStatus property of course. On the other hand, in case we are dealing with subject DIDs, then it probably makes no sense to specify a dedicated version as the verifier is interested in verifying proof of control (or the domain proof) at the time the holder provides the W3C VP.

Update:
Another approach would be to include separate version field in the proof property of the VC instead of using the version parameter directly in the DID URL. That version shows which version of the DID was used to cover the case mentioned above.

@OR13
Copy link

OR13 commented Oct 30, 2020

If you were to sign an id_token with a pinned version it would be valid forever.... even after that key was compromised.

I would disagree with that. The id_token would remain valid until it has expired indicated by the exp claim.

sure, but what about VCs that have no exp?

Rotating keys is a weapon of last resort for credential revocation...

@oed
Copy link
Contributor Author

oed commented Oct 31, 2020

sure, but what about VCs that have no exp?

Imo this should not be limited to VCs. Maybe it makes sense to add an option to the createJWS to request use of the version-id param?

For example in ceramic all previous documents would be invalidated if you rotate keys for whatever reason, which is definitely not desired. New keys can always invalidate changes made by old keys.

@kdenhartog
Copy link
Contributor

another point that i want to make is to add an did_encryptJWE for authcrypt. it would be specifically great to get feedback on the usefulness from

Can you please provide a specification for this? I don't know how that should work.

Authcrypt is effectively ECDH-1PU

@oed
Copy link
Contributor Author

oed commented Nov 2, 2020

Thanks @kdenhartog I meant more if someone could provide a description of how the json-rpc method for it would work :)

@awoie
Copy link
Contributor

awoie commented Nov 4, 2020

Thanks @kdenhartog I meant more if someone could provide a description of how the json-rpc method for it would work :)

There is an early version of a JWM implementation that uses authcrypt:
https://github.com/TelegramSam/jose/pull/1/files

JWM.encrypt(attributes, recipients, key[, options])`

Serializes and encrypts the attributes as JWM using the provided private or symmetrical key. The Algorithm
that will be used to sign with is either provided as part of the 'options.algorithm',
'options.header.alg' or inferred from the provided `<JWK.Key>` instance.

It further says:

<JWK.Key> instances are recommended for performance purposes when re-using the same key for
every operation. When used, JWM will be authcrypted from the key to the recipients. When omitted, the JWM will be anoncrypted to the recipients.

@oed
Copy link
Contributor Author

oed commented Nov 5, 2020

@awoie Do you have an opinion on how the json-rpc method should look like? I don't have enough insight to design it.

@awoie
Copy link
Contributor

awoie commented Mar 23, 2021

@oed I will provide an example this week.

@awoie
Copy link
Contributor

awoie commented Apr 6, 2021

@oed This is the proposal to update eip2844 to support authcrypt but I'm wondering if @kdenhartog also thinks this is useful.

AuthcryptJWE

Encrypts a message using ECDH-1PU to an array of recipients. Authenticated encryption provides only authenticity and not the stronger security properties of non-repudiation or third-party verifiability. This can be an advantage in applications where privacy, anonymity, or plausible deniability are goals.

For content encryption of the message, the following algorithm MUST be used:

Algorithm(JWA) Description
XC20P XChaCha20Poly1305

Method:
did_authcryptJWE

Params:

  • payload - the payload to encrypt, json object or base64url encoded string.
  • did - the DID or DID URI that should authenticate the message. If a DID is used, it MUST contain a keyAgreement section in the DID Document that contains a X25519 key. If multiple key agreement keys are contained in the DID Document, the first key will be used to authenticate the message. If a DID URI is used the DID URI MUST point to a key that is directly or indirectly referenced in the keyAgreement section of the DID Document.
  • recipients - A json array of type string. Every entry refers to a public key of one recipient of the JWE. Each public key MUST be encoded as base58 multibase.

Returns:

  • A JWE with JSON general serialization, string. The kid MUST be the DID URI that is expected to decrypt the message.

@oed
Copy link
Contributor Author

oed commented Apr 6, 2021

Looks nice overall @awoie. Some thoughts:

the payload to encrypt, json object or base64url encoded string.

Can we be more opinionated here please? I would prefer just one option, probably base64url.

did - the DID or DID URI that should authenticate the message.

So if I understand correctly this did would be used as the skid in the JWE header? The one thing I would add here is to have an optional parameter that adds a versionId or a versionTime query param in the resulting skid. The reason for this is that you need to be able to resolve the correct version of the DID document if the key that was used was revoked.

The kid MUST be the DID URI that is expected to decrypt the message.

Where would the kid come from here? Seems like the wallet side would not have access to this information? Also I assume that there would be a kid in the unprotected header of each recipient?

@awoie
Copy link
Contributor

awoie commented Apr 6, 2021

@oed right, I will provide an update, we should also talk about cty, apu and apv.

@oed
Copy link
Contributor Author

oed commented Apr 6, 2021

@awoie Can you remind me what cty is?

apu and apv are not strictly required by the JWE spec afaik.

@kdenhartog
Copy link
Contributor

@oed This is the proposal to update eip2844 to support authcrypt but I'm wondering if @kdenhartog also thinks this is useful.

AuthcryptJWE

Encrypts a message using ECDH-1PU to an array of recipients. Authenticated encryption provides only authenticity and not the stronger security properties of non-repudiation or third-party verifiability. This can be an advantage in applications where privacy, anonymity, or plausible deniability are goals.

For content encryption of the message, the following algorithm MUST be used:
Algorithm(JWA) Description
XC20P XChaCha20Poly1305

Method:
did_authcryptJWE

Params:

* `payload` - the payload to encrypt, json object or base64url encoded string.

* `did` - the DID or DID URI that should authenticate the message. If a DID is used, it MUST contain a `keyAgreement` section in the DID Document that contains a X25519 key. If multiple key agreement keys are contained in the DID Document, the first key will be used to authenticate the message. If a DID URI is used the DID URI MUST point to a key that is directly or indirectly referenced in the `keyAgreement` section of the DID Document.

* `recipients` - A json array of type string. Every entry refers to a public key of one recipient of the JWE. Each public key MUST be encoded as base58 multibase.

Returns:

* A JWE with JSON general serialization, string. The `kid` MUST be the DID URI that is expected to decrypt the message.

Yeah that would be really useful in my opinion. That's effectively merging everyone on the envelope of DIDCommV2 which would be amazing.

@kdenhartog
Copy link
Contributor

kdenhartog commented Apr 8, 2021

@awoie Can you remind me what cty is?

apu and apv are not strictly required by the JWE spec afaik.

cty is going to be used to determine which version of payload we're using. Keep an eye on this RFC: https://github.com/hyperledger/aries-rfcs/blob/82ace6001f97552f05d3da5472bcf9dbf7726a05/features/0587-encryption-envelope-v2/README.md#media-type

As for apu / apv that's correct that they're not strictly for a generic JWE, but for the 1PU they appear to be required for the HKDF function parameters PartyUInfo and PartyVInfo. We could decide that we want these values to be static or match another property (thinking maybe the did keyId which is passed in the kid property) so that we don't need to explicitly include those properties and save a bit of space.

@D4nte
Copy link

D4nte commented Sep 13, 2021

I think I had a similar thought to #2845 (comment).

For did_decryptJWE, we propose to bypass the user permission:

If the paths property is present in the decrypted data it should contain an array of string paths. If one of the these path prefixes matches with one of the path prefixes the user has already granted permission for then decryption should happen automatically without any user confirmation.

Would it makes to apply the same logic for did_createJWS?

Imagine a chat application where a signature is attached to each message, a similar logic would enable this use case without having to ask the user for signature authorization every time.

Or am I missing the point of the did_createJWS API?

@kdenhartog
Copy link
Contributor

kdenhartog commented Sep 13, 2021

Thinking about this more after coming back to look at this a few months later, I get the feeling we're conflating a few different layers here and if we decompose these things a bit more it would make the DID functionality all the more usable.

1st, I think we should add a DID management layer for normal CRUD ops so that the DID can be managed independent of it's usage.

2nd, I think we need to look at the JOSE layer as one of many usage layers which depends on the state of DIDs under management. This is a bad assumption because the RPC is intended to be stateless

3rd, I think the conflation of a ABAC authz model built into the usage layer is going to inherently couple things in weird ways that probably aren't correct. I need to understand the different trust boundaries a bit more on the RPC to get a better understanding and see if it makes sense to have the authz model combined with the usage or if it makes sense to separate it. When I get some time in the next week or two I'll do some research on this and see if my thinking here is heading in the right direction or if I'm off basis.

@github-actions
Copy link

There has been no activity on this issue for two months. It will be closed in a week if no further activity occurs. If you would like to move this EIP forward, please respond to any outstanding feedback or add a comment indicating that you have addressed all required feedback and are ready for a review.

@github-actions github-actions bot added the stale label Mar 12, 2022
@github-actions
Copy link

This issue was closed due to inactivity. If you are still pursuing it, feel free to reopen it and respond to any feedback or request a review in a comment.

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

No branches or pull requests

10 participants