w3c / did-core

W3C Decentralized Identifier Specification v1.0
https://www.w3.org/TR/did-core/
Other
404 stars 94 forks source link

Add additional note to Verification Method Revocation section #668

Closed oed closed 3 years ago

oed commented 3 years ago

After some discussion around key revocation with @OR13 he suggested that I add some additional context on how to securely verify proofs / signatures that where made in the past with a revoked key.


Preview | Diff

iherman commented 3 years ago

(Admin) the proposal is entirely located in a Note, ie, in a non-normative part of the specification. As a consequence, the contribution is non-substantive which also means that I can release the IPR contribution lock.

w3cbot commented 3 years ago

iherman marked as non substantive for IPR from ash-nazg.

dhh1128 commented 3 years ago

I don't understand the imagined significance of the "updated" and "nextUpdate" metadata. I think they are unnecessary -- I can validate something in the past based entirely on Orie's first 2 conditions. But Orie's use of "iif" (which, BTW, I think needs to be in all caps if retained) implies that he believes condition 3 is also necessary. Why?

oed commented 3 years ago

I don't understand the imagined significance of the "updated" and "nextUpdate" metadata. I think they are unnecessary -- I can validate something in the past based entirely on Orie's first 2 conditions. But Orie's use of "iif" (which, BTW, I think needs to be in all caps if retained) implies that he believes condition 3 is also necessary. Why?

I don't think you can. If you only have (1) & (2) someone who gets access to a key that was in versionId but is now revoked would be able to produce a valid proof since we have no way of knowing in what time interval the given key was valid. Condition (3) gives us the ability to check if the proof from (2) was produced within the time period which the given key was valid.

dhh1128 commented 3 years ago

I don't think you can. If you only have (1) & (2) someone who gets access to a key that was in versionId but is now revoked would be able to produce a valid proof since we have no way of knowing in what time interval the given key was valid. Condition (3) gives us the ability to check if the proof from (2) was produced within the time period which the given key was valid.

I think we are making different assumptions about starting context, and we may be understanding the semantics of versionId and versionTimestamp differently.

I am assuming that the versionId that was active at the moment of signing is recorded somewhere that the verifier considers reliable. For example, Fred is executing a legal contract on Jan 1. He affixes a digital signature, and at the same time, the parties involved record the current versionId of Fred's DID (which they know because they resolved his DID, right then). On June 1, Fred revokes the key he used to sign that contract, by removing that key from his DID doc -- but there is no question about which version of the DID's state governed the signing of the contract, because it was captured at the time the signature was captured. It doesn't matter what the time interval was when it was valid; it only matters what its state was at the moment of signing.

In such a case, it seems to me that knowing when the DID doc was updated from a previous version to the named versionId -- and knowing when the DID doc was later updated from versionId to something beyond it -- is irrelevant. If the legal contract was signed with versionId = ABCXYZ, and if that versionId was the one that was active when the signing occurred, then revocation doesn't affect it. Period. Revocation can never undo what was legally binding at the time, if we can prove (to whatever standard of confidence will satisfy a given verifier) that it was active at the time of the action. I believe this is the gist of @msporny's comment.

On the other hand, if we assume that the version of the DID doc wasn't recorded at the time of signing, then we have the vulnerability you're worried about. An attacker can sign on Aug 1 with the key that was valid in January, but claim that the signature occurred back in January -- and it may be hard to contradict that story. To do so, we would need to conduct a relative timing analysis. We'd figure out from other contextual clues what is the beginning and the end of the possible time range when the signature was created, and we'd figure out the beginning and the end of the time range when the verification method was valid (using the two metadata items from IFF condition 3 in the verbiage), and we look for an overlap of those two ranges. If there is any overlap at all, the attacker's assertion cannot be disproved; only if we can completely rule out overlap ("there's no way this signature could have been created during the timeframe when the verification method was active") can we say with confidence that the attacker is lying.

The reason I said we may be misunderstanding the relative semantics of versionId and versionTimestamp is that I have always intended versionId to be used in the first scenario; if you know in advance that you might need to prove later that something wasn't revoked, of course you would record the versionId. Recording the versionTimestamp instead would make the analysis probabilistic and fuzzy and messy, so why do it? On the other hand, I think versionTimestamp will always be used when you have to do range analysis. So when I read the verbiage that says it's only possible to be confident IFF you know versionId and you have time boundaries, it feels surprising.

msporny commented 3 years ago

@dhh1128 wrote:

So when I read the verbiage that says it's only possible to be confident IFF you know versionId and you have time boundaries, it feels surprising.

Yes, exactly what I was attempting to get at. @dhh1128 put it far more eloquently than I did, thank you!

oed commented 3 years ago

@dhh1128 Ok, so it seems like we are making different trust assumptions here. In your first scenario you assume that there is a third party verifier that observes the versionId was active at the time the signature was made. However, if you are building a trustless protocol which should be independently verifiable by anyone at any point in the future you can't make this assumption.

On the other hand, if we assume that the version of the DID doc wasn't recorded at the time of signing, then we have the vulnerability you're worried about. An attacker can sign on Aug 1 with the key that was valid in January, but claim that the signature occurred back in January -- and it may be hard to contradict that story. To do so, we would need to conduct a relative timing analysis.

This is roughly it. I would frame it a bit differently, or at least the use case I'm considering.

The controller of the DID creates a proof which contains the versionId. This proof is anchored on-chain. Any observer at any point in the future will now be able to determine at which point in time the proof was made (because you can look at the blockchain to determine the timestamp of the block in which the proof was anchored). However, the observer has no way of knowing if this versionId was valid at that point in time. This is why updated and nextUpdate is needed.

Happy to move this to a separate note that clarifies that this only applies in a trustless setting if that makes sense?

dhh1128 commented 3 years ago

I would be happy with a clarification that this only applies in a trustless setting. But even then, I still think versionId is being used in a really odd way; wouldn't it be versionTimestamp that you'd want?

oed commented 3 years ago

@dhh1128 I suppose you mean versionTime? It's a little bit unclear what this parameter actually is. Is it the timestamp when this version of the DID document was created, or an arbitrary timestamp? If the former then you would need to use nextUpdate anyway. If the latter then you might get away without nextUpdate. Since versionTime is a bit ambiguous, and nextUpdate works in all cases (even using versionId) I prefer this path.

dhh1128 commented 3 years ago

@dhh1128 I suppose you mean versionTime?

Yes, sorry about the imprecision.

It's a little bit unclear what this parameter actually is. Is it the timestamp when this version of the DID document was created, or an arbitrary timestamp?

I assume each DID method would clarify that.

If the former then you would need to use nextUpdate anyway. If the latter then you might get away without nextUpdate. Since versionTime is a bit ambiguous, and nextUpdate works in all cases (even using versionId) I prefer this path.

I have built a system that has support for versionId and versionTime. versionTime is an arbitrary timestamp. The system is designed for the type of setting that you have called "trusted" rather than "trustless" (that is, it assumes there is independently recorded metadata available). Thus, the universal resolver's implementation of my DID method does not currently include either updated or nextUpdate in its metadata (though it could be extended to do so, since the underlying information is recorded). The way your verbiage is currently written, the standard would be saying that my system cannot be secure. I dispute this, since it does not intend to support trustless use cases. Therefore, I would like the language to be precise about when your requirements truly apply.

msporny commented 3 years ago

Hey folks, I need to merge this. We're out of time and the WG needs a static snapshot to vote on for transition to Candidate Recommendation. I have done my best to merge @TallTed and @dhh1128's suggestions along with additional language that @dhh1128 requested.

@oed -- if you disagree with any of this, you can open a new PR to fix the content. This entire section is editorial, so we can keep working on it AFTER we transition to Candidate Recommendation.

msporny commented 3 years ago

Editorial, multiple reviews, changes requested and made, no objections, merging.