I'm joev, a security engineer 👋 You may know me from my work at Apple or on Metasploit, or from my CVEs.
Nowadays I work on open-source security software. This site is a cryptographic experiment of sorts, and a place to store my photos.
Say hello: @joev@infosec.exchange
Recently Bluesky has put out a unique set of design documents for a decentralized social network protocol called At Protocol ("ATP"), which includes a design for self-sovereign identity ("SSI").
I think this is the closest I have seen an SSI proposal get to supporting acceptable UX and performance requirements, which is rather exciting. At the same time, I think the design leaves much to be desired from a decentralization and anti-censorship perspective. Let's dive in.
The design document for identity in ATP lays out the project's requirements. They are clear and consistent enough that I will just present them without comment:
- ID provision. Users should be able to create global IDs which are stable across services. These IDs should rarely change to ensure that links to their content are stable.
- Public key distribution. Distributed systems rely on cryptography to prove the authenticity of data and provide end-to-end privacy. The identity system must publish their public keys with strong security.
- Key rotation. Users must be able to rotate their key material without disrupting their identity.
- Service discovery. To interact with users, applications must be able to discover the services in use by a given user.
- Usability. Users should have human-readable and memorable names.
- Portability. Identities should be portable across services. Changing a provider should not cause a user to lose their identity, social graph, or content.
ATP identity uses two DID methods as its actual account identifiers. A DID is just a URI that can be resolved into a JSON document containing some loosely agreed-upon account properties. The process for resolving the URI into the document, along with any additional document properties are specified in the DID method which has a unique URI scheme prefix and is the thing you probably actually care about.
ATP proposes two possible DID methods:
did:web:alice.myhost.com
did:plc:bv6ggog3tya2z3vxsub7hnal
did-web
(spec) is not especially interesting - the client does an https://
WebFinger lookup to alice.myhost.com
and retrieves a did-placeholder
URI which is then resolved to an actual account document. If myhost.com
wants to, it can absolutely slip a backdoored did-placeholder
into this response.
did-placeholder
(spec proposal) is where things get spicy - this DID consists of the hash of an initial entry into an array document that contains a "root" public key. This array document looks something like:
// did:plc:bv6ggog3tya2z3vxsub7hnal resolves to e.g.:
[
{
type: 'create',
signingKey: 'did:key:zDnaejYFhgFiVF89LhJ4UipACLKuqo6PteZf8eKDVKeExXUPk',
recoveryKey: 'did:key:zDnaeSezF2TgCD71b5DiiFyhHQwKAfsBVqTTHRMvP597Z5Ztn',
username: 'alice.example.com',
service: 'https://example.com',
prev: null,
sig: 'vi6JAl5W4FfyViD5...4y7gOLGblWkEwfQ'
}
]
This initial document is self-authenticated via the hash in the DID URI, very similar to the DIDs in other authenticated approaches like DIF Sidetrees.
The signed document is then stored in a centralized registry currently provided by Bluesky. Note that the registry is prevented via the hash and chained-signature scheme from itself modifying the array document. This means the registry servers cannot e.g. add a backdoor key to the returned account document - however they can revert the document to an older version, or just delete the document.
Despite these useful mitigations to prevent document modification, centralizing the registry has terrible ramifications on reliability and censor-ability. This is not lost at all on the ATP devs, who write:
We cheekily titled the method "Placeholder", because we don't want it to stick around. We're actively hoping to replace it with something less centralized. We expect a method to emerge that fits the bill within the next few years, likely a permissioned DID consortium.
Sadly I just don't see a DID consortium fixing much - whoever runs this service has to deal with all account history and abuse for every possible account on the internet. This has got to be rather costly to do forever, and at some point decisions will have to be made to block access to some bad actor clients - meaning the system will have to be designed so blocking clients is possible. Email has a similar problem with blocked IP ranges that makes it highly impractical to try to run your own SMTP system today.
While the presence of a universal account history service enables some serious UX improvements to SSI, I don't think the price tag is worth it here.
Further I think it would be best to specify protocol-level alternatives for ecosystems where account resolution is not available (e.g. offline or actively-censored networks). As the design stands today, if the One True account resolution service goes down, nothing whatsoever is actually cryptographically verifiable.
Putting aside centralization and censorship concerns - the proposal for dealing with signing and recovery keys is one of the more practically usable proposals for SSI I have personally seen. The "recovery key" is your root, and is used to sign a (possibly more physically-accessible) "signing key". You can use the recovery key to rotate the signing key when needed.
In the event that your signing key was compromised, you can also use the recovery key to request that the lookup servers remove any updates from the last N hours and "revert" your account document to before the attack. This can greatly ease some recovery scenarios, although all clients must be aware of this and act accordingly, which raises implementation complexity. This is what I am referring to by "enables some serious UX improvements".
Of course, there is still a recovery key that can be lost, but for practical everyday usage there is no need to carry this around: most usage revolves around the signing keys. There does appear to be a limit of one signing key per account, which is often in practice a rather frustrating constraint when you have multiple devices (Secure Scuttlebutt suffered from this).
If I look at the requirements again, reading between the lines I think this one causes a lot of trouble:
- Portability. Identities should be portable across services. Changing a provider should not cause a user to lose their identity, social graph, or content.
The Bluesky designers clearly want to make it impossible for any misbehaving (or dead!) provider to interfere with users obtaining an updated copy of its users' accounts. As such another coordinating server is necessary to support this.
Personally I disagree and think this is too strong of a goal - I think it suffices for a user to be able to prove they have migrated to a new provider.
While I greatly dislike the centralized registry, I wish multiple device keys were supported, and I wish it included an offline mechanism for verifying attached user@domain.com
labels - overall ATP's identity layer is a strong step forward in defining what a practically usable SSI implementation looks like, and its evolution should be watched carefully by anyone looking to build SSI implementations today.