- thoughts, engineering, art, life
Posts About
written Nov 08 2022

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:

Thoughts on Bluesky's SSI Proposal

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.

ATP identity - requirements

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:

ATP identity - implementation

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:

  1. did-web, an existing standard for using a domain/subdomain as the account name:
  2. did-placeholder, a new proposal: did:plc:bv6ggog3tya2z3vxsub7hnal

did-web (spec) is not especially interesting - the client does an https:// WebFinger lookup to and retrieves a did-placeholder URI which is then resolved to an actual account document. If 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: '',
    service: '',
    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.

The unfortunate

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.

The good

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).

Revisiting the requirements

If I look at the requirements again, reading between the lines I think this one causes a lot of trouble:

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 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.