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

Standardize the key revocation list #14

Closed
brentzundel opened this issue Sep 20, 2019 · 56 comments
Closed

Standardize the key revocation list #14

brentzundel opened this issue Sep 20, 2019 · 56 comments
Assignees
Labels
pending close Issue will be closed shortly if no objections

Comments

@brentzundel
Copy link
Member

@satazor moved from CCG (w3c-ccg/did-spec#96)

@msporny msporny added the discuss Needs further discussion before a pull request can be created label Oct 1, 2019
@msporny
Copy link
Member

msporny commented Oct 8, 2019

This is assigned to @csuwildcat ... waiting for him to be added to the group.

@dhh1128
Copy link
Contributor

dhh1128 commented Oct 8, 2019

I wonder if keys are the only data in a DID doc where it is desirable to test revocation. Do endpoints have a similar need?

@csuwildcat
Copy link
Contributor

I don't feel this should be something specified in the DID spec, as it may differ greatly between methods, with some methods choosing simpler routes, like implying revocation based on key removal.

@OR13
Copy link
Contributor

OR13 commented Oct 14, 2019

Wonder if we can adopt a revocation cert approach like what has been used historically with PGP for interoperability?

Or attempt to standardize the use of serviceEndpoints for facilitating revocation lists

@decentralgabe
Copy link
Contributor

decentralgabe commented Oct 14, 2019

I think there is value in including a revokedKeys section (or adding it as a flag to the existing key), at the least. For example, it may be useful to verify issuance for a revoked key, without the need to re-issue a credential. This section could certainly define a timestamp by which the revoked key may be removed from the did doc altogether.

Additionally, there could be value in recommending a replacement key, or adding a "succeededBy" property that references another key.

It was brought up that some DID methods are sensitive of large DID Documents. In this case, resolving a service that contains revoked keys should be a possibility, as long as the structure of the inactive key is consistent.

This is not to claim that all revoked keys need to be marked as revoked, certainly there could be a use case where removing a key all-together would make sense.

EDIT: I do think it is important to list tradeoffs in the design -- more updates to the diddoc, smaller diddoc size vs external resolution (a serviceEndpoint). There are competing interests here and I would urge to consider a more flexible solution that suits a wider variety of implementations, not just those where transaction frequency and size are concerns.

@csuwildcat
Copy link
Contributor

csuwildcat commented Oct 14, 2019

I strongly believe we should not force DID Methods to retain revoked keys, and allow them the option imply revocation via removal of the key. For many of the more decentralized DID Methods, it simply isn't feasible to retain all that data on a constantly accumulating basis across tens of billions of DIDs.

One scalable way to do this would be to publish key revocation references in an off-chain Hub/datastore that has a well-known mechanism for location/retrieval. This would allow the DID controller to publish any number of key revocation entries with any amount of detail they wish, all without encumbering the scarce resources of the underlying decentralized systems the DIDs are anchored in.

@csuwildcat
Copy link
Contributor

csuwildcat commented Oct 15, 2019

To add a bit of detail: if we add a standard property/mechanism like revokedKeys that would potentially accrue a lot of data over time (or a key marking/retention convention that would do the same), I know some DID Methods could not feasibly support it at scale (and I imagine others will discover the inherent scalability issues as well).

Beyond this singular topic, I would advocate that we, as a WG, strongly push for all this sort of stuff to be handled via Service Endpoints. There are bound to be many, many things people might argue to put into the DID Document, and given this is generally backed by scarce, decentralized resources, I think it would be smart to set this precedent early.

@OR13
Copy link
Contributor

OR13 commented Oct 15, 2019

I agree. I think ideally, a publicKey entry would point to a service endpoint definition which could be used to answer questions about revocation or succession. Alternatively, this information could be embedded in the publicKey definition itself, but I'd rather see it in service endpoints section.

@selfissued
Copy link
Contributor

The obvious way to revoke keys is to remove them from the DID document. (This is analogous to the way that OpenID Connect keys are revoked by removing them from the referenced JWK Set document.)

Adding a list to the document won't scale, and so isn't an option we should consider.

@ChristopherA
Copy link
Contributor

Though I agree that for many global scale DID Methods that having revoked keys in the DID itself will not scale.

HOWEVER, some smaller scale DID methods, such as :btcr :peer :git etc. need to have some consistent way to convey that a key is not only absent or inactive, but explicitly revoked. These methods can’t use an interactive service endpoint.

— Christopher Allen

@csuwildcat
Copy link
Contributor

csuwildcat commented Oct 17, 2019 via email

@dhh1128
Copy link
Contributor

dhh1128 commented Oct 17, 2019

I agree with @ChristopherA 's comment above. The did:peer method revokes keys by adding them to a deleted list. The list is called deleted rather than revoked because it also includes other things in the DID doc that have been deleted, such as service endpoints and authorization rules. This handling is necessary to support the CRDT semantics used by peer synchronization. A service endpoints approach won't work, as it requires knowledge of the current state of a peer's world to be centralized. I believe that many peers will centralize how their state is managed, but I am unwilling to require that behavior.

I don't have a strong opinion about this issue in general--I just don't want a decision to be made that invalidates what did:peer is doing. Today, what the method does is all allowed by the spec.

@msporny
Copy link
Member

msporny commented Oct 17, 2019

The obvious way to revoke keys is to remove them from the DID document.

While this is true, I'm really concerned about doing just this.

Here are two attack models to consider:

Attack Model 1: I have two devices, each w/ a key that I can use to perform authentication. One of those devices is stolen, I use my software to "deactivate" the stolen device. This means, that the public key is removed from my DID Document. At some point in the future, I'm tricked (somehow) into "reactivating" the device, which adds the previously revoked public key back into the approved verification methods for authentication.

Attack Model 2: I'm a developer writing software that modifies DID Documents. I believe that I'm aware of all locations in a DID Document that may refer to a key. When a key is revoked, I go into all of those locations and look for the key in question and remove it. Unfortunately, this particular type of DID Document has 3 extra locations where the key might appear, and I don't clear the key from those locations resulting in a potential for compromise.

All this points to either plan 1) we accept these attack models as very real possibilities, or plan 2) we use a revocation list of some kind for cryptographic material.

I think we should do plan 2 above, which seems to be workable if we also do the following:

  1. Keep the list off the ledger.
  2. Use a hashlink to point to the list content (to ensure cryptographic security over the list such that it can't be easily compromised).

There is a downside here, in that we almost certainly need to fetch the list before doing any sort of key operation to see if the key in use has been revoked (to prevent attacks 1 and 2 above).

If we agree to that general plan, the solution space gets pretty small:

  1. Create a new property in a DID Document that points to revocation lists (possibly a status list for all things that could be revoked in a DID Document).
  2. Use a non-interactive service endpoint to provide the revocation list.

Using the service endpoint feels like the correct direction, but that may have us mandating that all DID Documents MUST provide a key revocation list service endpoint.

@csuwildcat
Copy link
Contributor

csuwildcat commented Oct 17, 2019 via email

@brentzundel
Copy link
Member Author

@csuwildcat my understanding of how a service endpoint approach centralizes revocation, is that it does so for an individual entity's domain. If the did spec requires there to be a service endpoint for a list of revoked keys (or for any other view into the internal state of a domain), then the did spec is requiring there to be a single authority for that domain's internal state, and that may not work if the entity's domain is fully decentralized.
@msporny I think having the option to use a service endpoint for such things is fine (I personally feel that most domains will probably prefer this), but I don't think it is a good idea to mandate service endpoints for revocation.

@msporny
Copy link
Member

msporny commented Oct 17, 2019

@msporny I think having the option to use a service endpoint for such things is fine (I personally feel that most domains will probably prefer this), but I don't think it is a good idea to mandate service endpoints for revocation.

Excellent point, @brentzundel -- we should definitely avoid mandating and we may even want to go as far as saying "wherever you point to, we strongly advise that it's also decentralized". The multi-instance mechanism suggested by @csuwildcat is an option (albeit, a bit complicated). An IPFS link may be another acceptable mechanism. Pointing to another "cheaper" document on a DLT could be yet another.

@brentzundel
Copy link
Member Author

To clarify, I'm saying I don't think it's a good idea to mandate the use of service endpoints for revocation. I.e., I strongly prefer "a DID Doc SHOULD use a service endpoint for revocations lists." over "a DID Doc MUST use a service endpoint for revocation lists."

@csuwildcat
Copy link
Contributor

csuwildcat commented Oct 17, 2019 via email

@csuwildcat
Copy link
Contributor

Haven't seen much activity on this thread lately, but I still feel retaining old key objects on DID Docs with properties that declare a revoked status will lead to DID Docs growing far too large for many DID Methods to support, which implicitly means devs will need to actively support at least two completely different mechanisms of revocation (in-doc retained keys and an endpoint-based mechanism). Given anything that involves the definition of complex behaviors/protocols for how to externally handle in-doc revocation properties/values is going to stray outside the scope of data format definition, isn't the most logical move to create a scalable, endpoint-based protocol/mechanism for key revocation that is unified across different DID Methods?

@msporny
Copy link
Member

msporny commented Nov 1, 2019

I still feel retaining old key objects on DID Docs with properties that declare a revoked status will lead to DID Docs growing far too large for many DID Methods to support

I think there is general consensus at Digital Bazaar that this is true (even though the Veres One ledger can support this sort of thing).

There is not consensus at our organization on what the better approach is -- 1) just removing keys w/ no key revocation list, or 2) removing keys and placing them on an external key revocation list.

With 1, there is concern that this won't work for DID Registries that are not capable of doing historical querying (like did:web). With 2, there is concern about having yet another place you have to go before you can see if a signature is valid for a particular DID.

@dhh1128
Copy link
Contributor

dhh1128 commented Nov 1, 2019 via email

@selfissued
Copy link
Contributor

I don't believe it would be useful to define an attribute that is sometimes meaningful and sometimes ignored, and whose behavior is undefined. That's not the way that interoperable standards are constructed. I believe we should close this issue with no action, on that basis.

@csuwildcat
Copy link
Contributor

csuwildcat commented Nov 1, 2019 via email

@csuwildcat
Copy link
Contributor

To dig in a bit on the issue of certain Methods actively blocking this behavior/property from being used, would this mean we need to specify a standard parse error/directive Method implementer must emit when throwing on the unsupported/blocked inclusion of this sort of revocation metadata in their DID ops? I just want to know how we would deal with the downstream consequences.

@OR13
Copy link
Contributor

OR13 commented Nov 6, 2019

Related thought, some method like did:key can't actually support revocation, since the did document is a deterministic function of public key in multibase format.

If we can't formalize revocation beyond the concept of removal from a DID Document at the interop level, I worry about the implications for key life...

Time is the enemy, revocation and rotation in a gentle manner seem to be useful, especially if you want short lived keys, that issue credentials which still need to be verified, or which need to be reissued.

I'm in favor of MUST language for revocations using service endpoints IF revocation is implemented in any way other than remove from the DID Document.

@ChristopherA
Copy link
Contributor

If the proposed resolution here is that we DO NOT pursue a standard/scheme for retaining keys and marking them as revoked in some way, then I wholeheartedly AGREE, and support the resolution.

I've dug so many holes only to find fool's gold in my search for scalable revocation approaches since my SSL/TLS days, I'm hoping we can avoid falling into them as well.

@csuwildcat
Copy link
Contributor

@jandrieu "Resolving a DID reveals the latest, authoritative DID Document. If a key is no longer in the DID Document, it is either revoked or was never valid." - you noted on the other Issue that I was incorrect in my understanding of this statement. Can you clarify, because it seemed like you were saying a key no longer in the DID Document authoritatively means it has been revoked. I agree with this, and my agreement above reflects that. I have no issue with leaving the spec open for people/Methods to attempt to retain keys for random reasons, but large DID Docs will be a nonstarter for any Method that seeks robust decentralization + globally indexable resolution of its DIDs (highly desirable features).

If folks take out their calculator and enter whatever they believe the average number/size of state change ops a DID from a Big Doc DID Method will generate over its lifetime, then multiply that by, say, 100 billion, the number that appears on the screen should be nothing short of frightening. Some methods are taking this into account, and have protocol limitations on the size of ops, ways to reduce/prune past state, and other optimizations that are all designed to ensure you can run them without requiring a datacenter to operate a single node. The issues that will plague 'Big Doc DID Methods' (at least those that try to scale beyond cottage usage and small time POCs) are some of the same issues Craig Wright and his merry band of Bitcoin SV folks will face if they proceed with their giant block sizes.

@jandrieu
Copy link
Contributor

@csuwildcat your last comment is what I read as different from the sense of the other thread:

If the proposed resolution here is that we DO NOT pursue a standard/scheme for retaining keys and marking them as revoked in some way, then I wholeheartedly AGREE, and support the resolution.

The resolution is in fact, that we DO pursue a standard/scheme for OPTIONALLY retaining keys and marketing them as revoked.

So, I think we may be on the same page but talking past each other.

it seemed like you were saying a key no longer in the DID Document authoritatively means it has been revoked

That is right. To my view, if a key isn't in the DID Document, it is not valid. Whether because it is an old key revoked or because it was never there. That's the "80%" use case in the Pareto principle here.

I just want to be sure we leave the door open for the case where the controller sees value in retaining "revoked" keys with some meta-data about why and what that means.

Because, yeah, I agree with you. Storing old keys by default will face scaling problems.

@msporny
Copy link
Member

msporny commented Apr 14, 2020

What we may want to do at this point is state something like this:

With respect to keys that are revoked, DID Methods may choose express those keys or lists of keys in a method specific way. This specification, by design, does not specify a mechanism for doing so.

@OR13
Copy link
Contributor

OR13 commented Apr 14, 2020

Not helpful for developers... We should be helpful and explicit not vague.... either define it or don't allow it.

@lrosenthol
Copy link

I agree with @msporny that you need to leave the details of key revocation handling outside of the spec, and to each DID method/provider accordingly. Some may wish to use a CRL-like approach while others may prefer an OCSP-like approach. Both are valid and should be supported.
I will also point out that in many cases the certificates themselves may be issued by governments or other organizations that utilize systems such as the EUTL which need to be supported.

@OR13
Copy link
Contributor

OR13 commented Apr 14, 2020

IMO, a DPKI spec, that does not define revocation explicitly is pretty broken... even GPG has support for this... and look at all the issues with key servers that we have been able to learn from....

Leaving this up to DID Methods creates exponential switch statements regarding "verification" and opens the door to numerous security issues....

@OR13
Copy link
Contributor

OR13 commented Apr 14, 2020

If your software wants to allow for an expired key to still show up... why don't you augment your DID Document after resolution to support that, and take full responsibility for all the security issues that creates? There is nothing stopping people from using custom resolvers that inject expired / revoked keys into did documents, and hard coding against those interfaces.... just don't ask other developers to support that kind of thing in their implementations.

@dlongley
Copy link
Contributor

+1 that this cannot be left to individual DID methods -- I think that's a total failure to achieve interop. One of the main goals of the did-core spec is to make it so that my application can fetch a DID Document (using some DID method-specific resolver) and then my application knows whether or not, for example, the verification methods found therein are still valid for whatever purpose they are listed under (verification relationship). The application doesn't have to care about any DID-method specific details; those were handled by the resolver and the application can get on with its own business (clean separation of concerns).

This is the common form of operation and where we need interop. The simplest way to handle this is to say that any verification method that is expressed in a current DID Document is valid for the purpose it is listed under (verification relationship). If it's not there, it's not.

Now, there may be other forms of operation that are not common. For these, I do think it's acceptable for DID methods to provide a way to search through the history of changes to a DID Document and individual applications may have clever ways for relying on that information safely. These I'm happy to leave these as special cases with DID-method specific solutions -- where there may be some level of interop based on DID parameters like "version".

@dlongley
Copy link
Contributor

If we need a way to retain revoked verification methods, then we should allow for individual verification methods to define how they can be marked as revoked. For example, their specifications can indicate that if they have a revoked property (with some value), then they must be considered revoked. This should be expressed/handled at the verification method layer -- as an application will either understand a particular verification method (including any details about how it may be marked as revoked) or it should not be used by that application anyway. I think this continues to fit in with an appropriate separation of concerns.

@csuwildcat
Copy link
Contributor

csuwildcat commented Apr 14, 2020

After consideration, I'm rescinding my previous support for adding vague language that encourages unclear in-Document revocation mechanisms, and going to stick by the position that the endeavor to retain revoked keys in the Doc is fraught with security and scalability issues I just can't support. The spec should not specify a mechanism for this, because it is likely to lead to bad outcomes (as Chris/others have noted), and divergence in Method support that will harm the ecosystem.

@lrosenthol
Copy link

lrosenthol commented Apr 14, 2020

@OR13 wrote:

IMO, a DPKI spec

I think that's the problem here. AFAICT, we are not writing a DPKI spec. We are writing a spec about Decentralized Identity. Says so right in the first two sentences of the Abstract:

Decentralized identifiers (DIDs) are a new type of identifier that enables verifiable, decentralized digital identity. A DID identifies any subject (e.g., a person, organization, thing, data model, abstract entity, etc.) that the controller of the DID decides that it identifies.

Identity may contain certificates, it may not. Even if I have certificates, they may be connected to some existing certificate store/model that is based on an existing revocation model (eg. CRL/OCSP).

If you are trying to turn both the entire Identity and entire PKI world on their respective heads with this single spec - I think you are shooting for the moon.

Why not simply try to solve problems that you can solve?

@decentralgabe
Copy link
Contributor

Is there a middle ground between revoked and in use? A key that needs to be around for historical purposes but is no longer used to sign new documents?

A fine answer to this, and the need for some to retain historical keys, could be to expose a serviceEndpoint in the document that contains these keys.

@dhh1128
Copy link
Contributor

dhh1128 commented Apr 14, 2020

@glcohen : I believe what I am about to say is aligned with the thinking of others on this ticket, but I am not sure. So this will be an interesting test of whether we all share the same mental model.

My answer: Revocation isn't retroactive; it doesn't undo the status of a key (e.g., the validity of its signatures) in the past. In other words, there is no way to say, "I revoke this key from point-in-time T looking forward, and also from T looking backward." Revocation just covers the forward-looking part. Now, combine that with the fact that you can resolve a DID not just for the present, but for any arbitrary point in time in the past, and you already have the middle ground you're imagining, without exposing a serviceEndpoint to contain old stuff. If key X is revoked at time T, then a resolution of the DID against any time >= T will not contain X, and times < T will contain it (at least as far back as it had valid privileges).

@lrosenthol
Copy link

lrosenthol commented Apr 14, 2020

combine that with the fact that you can resolve a DID not just for the present, but for any arbitrary point in time in the past

Is that a requirement of a DID method/resolver? I can see a number of cases where it would not be possible to resolve a DID for any arbitrary time T - but only for present.

(but that aside, I agree with your description of revocation)

@decentralgabe
Copy link
Contributor

@dhh1128 we've been thinking through the case of key compromise where revocation does mean old signatures are now invalid. Perhaps there's another way to express this?

And yes, our DID method presently only allows you to view the current state, not history so what you describe is impossible. I am curious if there is a requirement for DID methods to retain all histories.

@dhh1128
Copy link
Contributor

dhh1128 commented Apr 14, 2020

@glcohen : I believe the idea of invaliding a key backward in time (as opposed to from this point forward) is not generally described with the word "revoke" but rather "decry." What you are saying to someone is, "Yes, at the time this was signed, the key was considered valid. But we now disclaim its authority. It was actually compromised, and its previous actions are also now suspect." Support for decrying something is not something you can impose on others; all you can do is ask them to consider your assertion that the key was not in your control when it was exercised. If you set up the key to take legally binding actions on your behalf, you might still have to live with the consequences; there's not a simple "undo my signature" feature. But I think decry might be useful (e.g., in a case where a child grabs a parent's cell phone and does something foolish with it).

Re. the question that both you and @lrosenthol asked: no, I don't think DID methods are required to support resolution at an arbitrary point in time. However, many do, for exactly this reason. And timestamp and version-of-DID-doc are both standard matrix parameters that are supposed to be defined for all resolvers (even if they aren't supported). @peacekeeper will know more.

@csuwildcat
Copy link
Contributor

csuwildcat commented Apr 14, 2020

And yes, our DID method presently only allows you to view the current state, not history so what you describe is impossible. I am curious if there is a requirement for DID methods to retain all histories.

@lrosenthol and @glcohen, you both touched on great points related to history retention, and this specific topic is but one of many that revolve around the same core issue: resolving past DID states over long periods of time (or perpetually). The most significant objective problem is the comically massive amount of resources doing so would implicitly require, for example:

  1. Let's assume there are 7 billion people and businesses on earth who, in addition to their peer-private DIDs, have at least 1 globally known persona identifier (e.g. an ID you would purposefully want correlated to you - think networking apps, public posts, etc.)
  2. To start with a rough basis for analysis, let's assume the average DID requires 1k in net data storage for a DID that utilizes a common set of 'features' (a few public keys, an endpoint or two, etc.). For 7 billions people, that's 7 terabytes alone based on a single DID create operation.
  3. Users may have multiple keys associated with their current DID state, and businesses may have many more than users do. So let's assume just one key roll and service configuration change to their DID state every year totals 500 bytes - no biggie, just toss another 3-4 terabytes per year on the heap.
  4. But what if your DID method wasn't just serving humans and business who have one such ID? What about users with multiple public IDs, and IDs for devices, and apps, and bears, oh my! If you assume more than one public persona ID per person/business, or add in other entity types that may want to utilize ever-growing historical retention features, it's going to get really ugly, really quick.
  5. Because physics is likely to be disagreeable and unwavering (darn you, physics!), implementations will likely make one of three choices:
    1. The implementer was never intending their system to be an open, permissionless, globally addressable DID implementation from the start, so they don't worry about these scale/viability issues. This could be fine for artisanal Methods that hand-craft limited edition DIDs for a select audience, or Methods that are only meant for consumption by a consortium of companies, for example.
    2. For some reason the implementer chooses to allow these unbounded conditions, resulting in an implementation that is very centralized, as it grows so massive basically no one except major corporations and governments can run the nodes (or they bank on the future discovery of some alien technology that radically advances transmission and storage systems).
    3. The implementer adds aggressively minimized data structures, data compression techniques, and protocol-level pruning features that are designed to mitigate the aforementioned issues.

How it relates to this feature: my suggestion would be for the community to orthogonally codify some sort of Service Endpoint-based protocol to allow for detailed, historical key/revocation info, among other things (which can still be chain-anchored/provable). I say this because my calculator tells me ever-growing lists of data in DID Documents are going to require folks to make some tough choices - so in the words of the Grail Knight from Indiana Jones and the Last Crusade, I hope we all "Choose wisely".

@OR13
Copy link
Contributor

OR13 commented Apr 15, 2020

This could be fine for artisanal Methods that hand-craft limited edition DIDs for a select audience, or Methods that are only meant for consumption by a consortium of companies, for example.

This is one of the best things I have ever read from this wg.

@dlongley
Copy link
Contributor

dlongley commented Jun 2, 2020

Related to #279 which has been merged. Unfortunately, it did not include my suggestions.

@msporny msporny removed the ready for pr Issue is ready for a PR label Jun 2, 2020
@OR13
Copy link
Contributor

OR13 commented Jun 2, 2020

@dlongley Please open a PR and tag people for review.

@dlongley
Copy link
Contributor

dlongley commented Jun 2, 2020

@OR13 Done, see #308.

@msporny
Copy link
Member

msporny commented Jun 23, 2020

This is done, marking pending close and waiting 7 days to see if there are objections.

@msporny msporny added the pending close Issue will be closed shortly if no objections label Jun 23, 2020
@brentzundel
Copy link
Member Author

No comments since marked pending close, closing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
pending close Issue will be closed shortly if no objections
Projects
None yet
Development

No branches or pull requests