Open peacekeeper opened 6 years ago
I think it would be better to be explicit between "DID does not exist" and "DID has been revoked". In fact, I think it would be beneficial to specify what should be required in a DID Document for a DID that has been revoked and provide an example. (Sorry if I missed that in the spec.)
@ChristopherA responded to the above email thread with how BTCR handles this, which highlights the three (really two) revocation scenarios we should describe. I formatted it for clarity.
With BTCR, the resolver always can construct a DID document. But it must check to see if the “tip” bitcoin address has been spent — if it has, the DID document has been revoked (or rotated) as of the date of the address being spent. The tip transaction can contain:
- no information (default revoke)
- revocation information (revoke with details why)
- link to updated DID document (rotation)
+1 I also agree it makes sense to distinguish between a DID that has been revoked, and one that doesn't exist. (At least if a method supports this, I could also imagine methods where a revoked DID is actually completely deleted everywhere - I think this should also be allowed).
As for locating the "latest version", yes I am certain that in a simple "resolve" request, the latest DID document must be returned. That's the meaning of "update" - it updates what the latest version is. So I think a BTCR resolver must follow all the tip transactions to the end in order to locate the latest version.
Returning earlier versions of a DID document could be an additional optional feature, if both the DID method and the resolver implementation support it.
@peacekeeper, regarding:
(... I could also imagine methods where a revoked DID is actually completely deleted everywhere - I think this should also be allowed)
I think this question deserves a little more discussion. Could allowing this inadvertently create a situation where compromised private keys might be reused?
Regarding the versioning issue, if we don't plan on formally requiring a "request version history" on a DID (I don't think we should), we could loosely agree to add it as meta information to the DID Document in the same way.
Good points, I agree with both. We can have a warning in the spec about security implications of "revoked" vs "deleted", and we could add versioning information to the DID document in a similar way as revocation information.
(But resolver implementations should also try as much as possible to protect developers from accidentally using a revoked/outdated DID document).
there was another discussion on m/l that a DID that was valid on a given date needs to be continue to be valid on that date to allow validation of signature. I feel strongly that a subject should not be permitted to revoke a commitment made (ie a signature) at a earlier date. That capability would invalidate the entire chain, including key rolling and even the revocation itself. That means that requests to the resolver need to allow the request to include the date on which the DID is being queried. In general it would be most useful for the resolver to always included status, which could be (for example) that this DID was revoked on this date. Anyway, that is how i am constructing a resolver. If a method does not support that, i would simply ignore the method.
Good points, versioning (and the ability to resolve earlier versions of a DID Document) is definitely one of the features that needs to be addressed in the DID Resolution spec. I just created an issue for this: https://github.com/w3c-ccg/did-resolution/issues/12
I'm concerned about revocation vs. spending for a prescription. A prescription can be coded as a Verifiable Credential and it's subject to revocation and spending. (1) Does the prescription itself have a DID or is the VC being revoked or spent? (2) Revocation can be done only by the issuer. Spending must be done by the subject and verifier together. How?
@peacekeeper Resurrecting this thread since the DID-Linked Resources use case might signal that this question should be treated in a different fashion than it is currently...
My view is that a deactivated DID can still be read and should be resolved. It’s up to the client app/API request sender to then decide what to do with this. For example:
I’m going with the spirit of what DID Core’s production specification implies:
If a DID has been deactivated, DID document metadata MUST include this property with the boolean value
true
. If a DID has not been deactivated, this property is OPTIONAL, but if included, MUST have the boolean valuefalse
.
This does not state a DID production shouldn't be made. If it was the case, this would be entirely unique out of all the other DIDDoc metadata in the effect that it has on production. Also, since it's optional/may be set to false
, the opposite scenario implies an answer should be returned with the value set to true
.
Based on the above, I'd suggest that deactivated DIDDocs should return a resolution response. The change I'd make is to set didResolutionMetadata
to return a different value instead:
If the input DID has been deactivated, return the following result:
didResolutionMetadata
: «[ ]»didDocument
: nulldidDocumentMetadata
: «[ "deactivated" → true ]»
didResolutionMetadata
: "didDeactivated"didDocument
: didDocumentMetadata
: «[ "deactivated" → true ]»DIDs may be deactivated with a replacement DID created, or without a replacement DID created. If the DID method supports it (perhaps via the alsoKnownAs
property, perhaps the DID subject could also specify the new replacement DID. In this case, the resolution specification could also support:
didResolutionMetadata
: "didDeactivatedAndReplaced" (?)didDocument
: didDocumentMetadata
: «[ "deactivated" → true ]»The current HTTP status code of 410 implies "Gone", so returning an actual response is syntactically weird. I propose that status codes should be:
@ankurdotb Thanks for sharing detailed thoughts on this! Personally I don't have a strong opinion here and could live with either approach. I think DID Core supports your arguments, since it says that if the resolution was successful, a didDocument must be returned. At some point in the past, "deactivated" was an error code, but then we changed that, since a deactivated DID isn't really an error, so we just made it another metadata property (see https://github.com/w3c/did-core/pull/691). And you're right that it would be unique as a metadata property if the didDocument was null. It also feels strange to return DID document metadata without returning a DID document :)
Having said that, let me present some arguments for the current approach:
Here are two potential ideas for a middle ground:
What do you think? In any case, it feels like we have to clarify more what deactivating a DID actually means.
The change I'd make is to set
didResolutionMetadata
to return a different value instead.
didResolutionMetadata
: "didDeactivated"
I don't really understand what you mean here. According to DID Core, didResolutionMetadata
must be a map, we can't change it to a single string. Maybe I misunderstood.
Also pinging @fabianekc since he also had some thoughts about DID rotation, forwarding, redirecting.
The change I'd make is to set
didResolutionMetadata
to return a different value instead.
didResolutionMetadata
: "didDeactivated"I don't really understand what you mean here. According to DID Core,
didResolutionMetadata
must be a map, we can't change it to a single string. Maybe I misunderstood.
I don't mean the DID Document Metadata, which is defined in DID Core specification, but the values returned under DID Resolution Metadata - which as far as I understand is purely in the DID Resolution specification and not in DID Core. For example, the other values mentioned here are notFound
, invalidDidUrl
etc. Am I correct that these are purely in DID Resolution?
The argument for calling it "deactivate" was mostly a technical one, since many DID methods were and are based on blockchain/ledger technology where you can't really delete anything.
I agree with you that non-ledger VDRs such as did:key
, did:dns
etc could certainly actually delete rather than deactivate. Personally, I wouldn't assume whether underling VDR had a way of deactivating the information or actually deleting it. (I would also argue that if we get really philosophical, even ledger-based VDRs could stop existing given a long-enough time horizon, which is technically a delete operation. E.g., if did:terra
was an actual DID method, it would have stopped existing in mid-2022, even though some people may have retained archival copies.)
The university should rotate the keys in its DID document, not rotate its DID. If an entity is aquired by another entity, both DIDs should continue to exist (not deactivated), and they could point to each other using the alsoKnownAs property.
While I do agree that in an ideal scenario either replacements should be created or new as well as legacy kept alive, in reality, I suspect that this will be hard to achieve. Sometimes, companies/entities just straight up go bankrupt and not acquired, or just plain not interested in maintaining "legacy" technology. I would consider verifying a credential linked to a deactivated DID as being interpreted as "It is a cryptographically verifiable fact that this credential is untampered, but it's issued by a defunct entity". E.g., think of a KYC credential issued by Silicon Valley Bank or FTX, utility bill credentials issued by a bankrupt energy provider in the UK etc. More importantly, with paper/plastic credentials issued by defunct entities, or in defunct formats, I can still use them and are considered valid documents. (My birth certificate is on paper filled in with pen, which is no longer a valid format where I was born, but that doesn't make it any less of a "genuine" document although whoever I may show it to could ask me to show other documents stating my birthplace since they don't trust this legacy format as much.)
Also, I suspect legacy/un-maintained service endpoints are only truly critical in some DID methods, but perhaps not all. A JWT VC is pretty standalone.
I'm a bit worried that if "deactivated" is merely metadata, many implementations will simply ignore it, and all VCs, service endpoints, Linked Resources, etc. will just continue to work normally even though the DID has been deactivated by the controller.
I do agree strongly with you on this point. Logically, I think this is how it should work but I suspect a lot of people wouldn't, and this could become a real issue if this best practice isn't followed.
...we could introduce a resolution option "resolveDeactivated=true" (or similar) that would return the actual deactivated DID document...
I really like this idea and I think this is the ideal answer. By asking the requester to explicitly acknowledge and re-send the request a deactivated DID, it's more likely that they'll understand and account for it in their logic. It's like a dialog prompt going "Are you REALLY sure?" before continuing. Also, if an underlying VDR like did:web
or did:dns
which could actually delete isn't able to provide an answer, this could also be gracefully handled with something in the response that then returns an error status/code. More likely they'll just return a 404 rather than a 410 because unless they are separately tracking all deactivated or historical DIDs, it'll be very hard for those VDRs to distinguish between a "not found" vs a "gone".
So maybe the steps could be:
did:dns
would be a fantastic example of this.) In this scenario, it returns a 404 not found.deactivated: true
. I worry that this solution is a bit too clever for real-world usage.What do you think?
Should DID resolution distinguish between a "DID that does not exist because it has never been created" and a "DID that has been revoked"? What results should be returned in each case by a DID resolver?
Yes. First, DIDs and DID keys are part of a decentralised PKI. Second, DID keys are used for e-signing/e-sealing, and authentication. DID keys can essentially have three states
The deactivated state can be due to
In most VDR, DID keys are self-managed, meaning that the keys can be self-suspended or self-revoked. Suspension and revocation of keys by 3rd parties are usually done using VCs + using a credential status framework.
Depending on the use case, deactivation may require to signal
All this is independent of whether the DID R. supports the resolution of historical information or not.
Why is the distinction between non-existent and deactivated important? There's a difference between whether a key has been revoked/suspended or does not belong to the DID controller. First signals that a given DID issues the VC, but the DID has been revoked/suspended for some reason, second signals that the VC has not been issued by the DID, which is an attack.
Why is the distinction between non-existent and deactivated important? There's a difference between whether a key has been revoked/suspended or does not belong to the DID controller. First signals that a given DID issues the VC, but the DID has been revoked/suspended for some reason, second signals that the VC has not been issued by the DID, which is an attack.
Glad you agree @alenhorvat! (BTW, everything that follows is me agreeing with you, rather than disputing any of your points.)
This is the reason why I think there should be some way of resolving deactivated DIDs vs DIDs that never existed/don't exist, even if it's by using an additional query parameter to make the client app developer 'opt-in' if necessary to make sure they truly understand what they're doing.
The deactivated state can be due to
key expiration suspension (temporary deactivated) revocation key rolling (registering a new key + revoking an existing key) - we're using key rolling instead of key rotation since key rotation definition is very ambiguous
The scenarios you've mentioned are excellent examples of intentional DID/key deactivation. I also add the following scenarios for why a DID/key may be in deactivated state, as unintentional or non-recoverable scenarios:
did:web
or did:dns
could very easily allow some form of break-glass access to deactivate the entry in case they've lost control of the key without needing the operation to be signed by controller keys.did:ethr
) is entirely sunset because the network/VDR cannot be run any more (due to economic challenges, legal challenges, sunsetting legacy products etc). The developers of this VDR are the ones who set the rules for what's allowed to authorise a transaction, and could choose, using a software update to mark all DIDs as deactivated (and perhaps available only in a read-only format/archive).These non-recoverable scenarios, IMO, should not cause a holder to lose the ability to use their credentials entirely.
See this thread: https://lists.w3.org/Archives/Public/public-credentials/2018Jun/0078.html
Should DID resolution distinguish between a "DID that does not exist because it has never been created" and a "DID that has been revoked"? What results should be returned in each case by a DID resolver?