superseriousbusiness / gotosocial

Fast, fun, small ActivityPub server.
https://docs.gotosocial.org
GNU Affero General Public License v3.0
3.57k stars 300 forks source link

[bug] Oddities with signing #1181

Closed driusan closed 1 year ago

driusan commented 1 year ago

Describe the bug with a clear and concise description of what the bug is.

The actor object returned by main-key is missing the inbox/outbox/algorithm, the url for the actor object itself does not return the ActivityPub actor object.

What's your GoToSocial Version?

Unknown

GoToSocial Arch

Unknown

Browser version

hget

What happened?

I'm trying to validate an incoming request that @ftrvxmtrx says came from her gotosocial install, but it has some issues that make it difficult for other fediverse to validate the http signature.

The HTTP signature says it came from keyId="$domainname/users/$username/main-key",algorithm="hs2019" (where $domainname and $username is the actual domain/user). Retrieving $domainname/users/$username/main-key results in the ActivityStreams/ActivityPub actor object. It claims to have an id of https://$domainname/users/$username (without the /main-key path component) On the other hand, retrieving the actual id of https://$domainname/users/$username url with an Accept header of either application/ld+json;profile="https://www.w3.org/ns/activitystreams" or application/activity+json does not return the actor object.

The actor object returned also looks like it's missing the inbox and outbox fields (mandatory according to the ActivityPub spec) and doesn't have any field to determine what the "real" algorithm used for signing was since the algorithm in the header was the pseudo-algorithm hs2019. (I think Mastodon gets around this by just assuming everything is rsa-sha256, but that seems even less secure to me than just specifying the algorithm in the header..)

I'm not sure what version of GoToSocial it is since it's not my install, but I suspect it's the latest development head..

What you expected to happen?

  1. The actor object would be returned when requested with an Accept header of either application/ld+json;profile="https://www.w3.org/ns/activitystreams" (mandatory according to the ActivityPub spec) or application/activity+json (optional according to the spec)
  2. There would be an inbox and outbox field in the actor object returned.
  3. The actor object would include the algorithm used if the HTTP header is hs2019

How to reproduce it?

  1. curl the actor id URL with an Accept header set to one of the Content-Types required by the ActivityPub spec and/or the actor-id with /main-key (not #main-key like most other software seems to use) and look at the results
  2. Look at the Signature added to outgoing messages, try to manually validate and figure out the actor's inbox (or outbox.)

Anything else we need to know?

No response

tsmethurst commented 1 year ago

Heya, thanks for opening this.

Indeed there's a few irregularities with the way we serve public keys.

Mastodon and others serve the public key as a fragment part of the Actor (#main-key), which results in having to serve the entire Actor model (with potentially sensitive fields) for a simple public key request. Rather naively, I figured early on that GtS could serve just a stub of an Actor with only those fields necessary for the public key, with an ID pointing towards the actual Actor ID which could be dereferenced with a signed request.

Most softwares handle this OK: they extract the public key from whatever is served at the public key URI, and then use the owner field of the publicKey on the Actor to dereference the owner with a signed request. But some softwares, understandably, don't handle this OK because it's something of a hack. The Akkoma devs had to insert some code specific to GtS to get federation working, and it's likely that a few others did as well.

I think in future we'll try to figure out a way to change this behavior, because it's honestly a bit mental and I wish someone had told me at the time 'that's a bad idea', but it was just me working on it then :P

tsmethurst commented 1 year ago

sort of related https://github.com/superseriousbusiness/gotosocial/issues/894 btw

driusan commented 1 year ago

Thanks for the info. It's more of the fact that the id URL wasn't returning anything that was causing problems than the fact that the key is at a separate URL instead of a fragment that was throwing me off. Now that I know you require the messages to be signed to get the real actor object (which is also kind of idiosyncratic, most other implementations seem to only require signing for sensitive requests where the id of the requestor needs to be verified like POST requests while the profile is publicly accessible) I'll give that a try when I get a chance and see if that helps.

tsmethurst commented 1 year ago

which is also kind of idiosyncratic, most other implementations seem to only require signing for sensitive requests where the id of the requestor needs to be verified like POST requests while the profile is publicly accessible

GtS basically has the equivalent of mastodon's 'secure mode' always on, so that we can quickly and easily apply ACLs for posts against domain blocks and stuff :)

tsmethurst commented 1 year ago

I'm gonna close this now since it seems like you've implemented a fix on your side :) We have https://github.com/superseriousbusiness/gotosocial/issues/1186 open now so we can track the http signature irregularities. Feel free to open this again if you still wanna discuss!