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

Key pair for every actor vs single instance-wide key pair #57

Open
SorteKanin opened this issue Aug 15, 2024 · 9 comments
Open

Key pair for every actor vs single instance-wide key pair #57

SorteKanin opened this issue Aug 15, 2024 · 9 comments

Comments

@SorteKanin
Copy link

I posted this question on socialhub.activitypub.rocks but I thought I'd also try here to see if anyone knows.

Is there any specific reason to have separate public/private keys for every single actor, rather than just using a single instance-wide public/private key pair?

I was checking out this document here and it kinda implies that there is no need for every actor to have their own key. The procedure (as I understand it) should work even if all actors use the same key.

The server is in control of all the keys anyway. So why create a new key pair for every actor? It seems redundant/unnecessary. Is it mostly for future compatibility, for instance for a possible future with end-to-end encryption? Or is it that if a private key got leaked or broken, it’s at least only for one actor and not all actors?

Are there any implementations that assume that every actor has their own key pair and wouldn’t work with a single key pair?

@nightpool
Copy link
Collaborator

nightpool commented Aug 15, 2024 via email

@snarfed
Copy link
Collaborator

snarfed commented Aug 15, 2024

@nightpool is definitely right about the fediverse as it exists in the wild today. Users, their keys, and all of their activities/objects are usually tightly coupled to their server and accessible to their admins.

Having said that, it's worth noting that ActivityPub itself is much looser and doesn't specify those couplings nearly so tightly. There are also experimental FEPs like fep-ae97 for client signing, along with portable signatures like LD Sigs, fep-c390 identity proofs, and fep-ef61 portable objects, that decouple them even more aggressively.

@SorteKanin
Copy link
Author

SorteKanin commented Aug 21, 2024

reduces the amount of validation/the footgun potential of processing user's activities as the sending server

@nightpool If it's not too much to ask, could you expand on this? What kind of footguns might appear due to using only a single key?

Users, their keys, and all of their activities/objects are usually tightly coupled to their server and accessible to their admins.

@snarfed I'm not sure what this has to do with coupling, but maybe I am misunderstanding your comment. I'm definitely still assuming that the server is in control of the singular key and all the users, so in that sense there is the same coupling as when each user has their own key.

@snarfed
Copy link
Collaborator

snarfed commented Aug 21, 2024

I'm definitely still assuming that the server is in control of the singular key and all the users, so in that sense there is the same coupling as when each user has their own key.

Right, that is the key assumption. It's broadly true on the fediverse today, but not universally, and it's not required. You can build a server that doesn't control or have access to user private keys and still fully implements AP. Users can generate their own keypairs, give their server their public keys, and sign all of their activities locally, in their client. fep-ae97 describes this and links to two implementations. It's obviously unusual, and there are open questions - and most other servers would have trouble interoperating, since eg LD Signature support is mixed at best, much less FEP-8b32 integrity proofs - but still.

@nightpool
Copy link
Collaborator

You can build a server that doesn't control or have access to user private keys and still fully implements AP

You cannot do this without exposing every user on your server to URI exhaustion or confused deputy attacks where you can trick remote servers into thinking users "liked"/"boosted" different statuses then they actually did.

For example, imagine the following scenario:

  1. User [email protected] posts "I like coffee!" with the URI https://a.com/post/123
  2. User [email protected] boosts it.
  3. User [email protected] generates a new Create { Note } activity with the URI https://a.com/post/123 that says "I hate coffee!"
  4. Alex signs this locally and sends this to c.com, where they have followers. Then, they send bob's signed boost.
  5. Users on c.com sees that Bob hates coffee instead of loving it.

Additionally, there's a similar trivial DOS attack where Alex signs Notes with all of the same URIs as Alice's notes and races to send them to all of Alice's followers before she can.

I've posted this scenario many times before on the mailing list when this discussion has come up. It was a CVE that we fixed very early in Mastodon's life cycle.

There's no way to fix this without 1) throwing away message signing entirely (by e.g. validating every URI you get sent with a lookup, meaning that message signing provides no value) or 2) a new extension property restricting an actor's keys to only be valid for some subset of URIs.

@snarfed
Copy link
Collaborator

snarfed commented Aug 21, 2024

Great point! Chalk up yet another open question. Nothing's ever easy 😆 😢

@SorteKanin
Copy link
Author

@nightpool shouldn't the server at a.com just return an error when [email protected] tries to create the activity with a URI that already exists? Isn't this just a bug in the a.com server? Why is Alex allowed to create that activity?

@nightpool
Copy link
Collaborator

@SorteKanin Because in the system @snarfed proposes, [email protected] is custodial of their keys, so the server at a.com is not involved. They sign the request and deliver it to b.com directly. This cannot happen unless you use separate keys per actor and then also give [email protected] access to them

@SorteKanin
Copy link
Author

But if a.com is never made aware of the activity because it is sent directly to b.com, how can Alex set an ID? I mean whatever Alex sets the ID to, that URL will not exist (or it will point to something else) since a.com never even saw the activity. I don't see how it makes sense to send an activity directly to a remote server like that without having the activity on your own server as well.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants