Now that RFC 9421 has been published and is no longer a draft, I think it would be a good idea to write a FEP (or other document) with implementation recommendations, to ensure interoperability between AP servers. The RFC describes how to create and verify signatures, but it’s still up to us to define things like the required fields to be signed, which algorithms are likely to work, and how to discover servers that support it.
I believe HTTP signatures are still useful even with FEP-8b32 object signing, because they prove the authenticity of the origin server. That can be used to implement federation policies on private networks (not connected to the wider “fediverse”), or as a basis of trust before even parsing the AP object body. FEP-8b32 proofs validate the activity object itself and remain with the object as it traverses the network; HTTP signatures validate each link at the transport layer.
Also, I think it’s fine & good for the popular servers (mastodon, misskey, gotosocial, …) to wait for smaller servers to shake out interoperability first. It’s easier for the small servers to iterate and debug. Once we have something working, the more popular servers can implement our consensus requirements with a higher confidence it will “just work”.
It would be cool to do a revised report, or a new report, for supporting the published version of HTTP Signature and especially for smooth transition from draft-cavage-11.
Yeah, I saw that yesterday, but it appears to be about documenting the current “standard” (the old cavage draft)… which is definitely worth doing!
I’d like to start a conversation about how we migrate to the RFC, and what it looks like when we’re done. I think we have a pretty good start from other threads here but want to consolidate them here.
I’ve recently started working through this in my own project. Here are some quick thoughts:
I think it would be a good idea to write a FEP (or other document)
I’d suggest an update to the report Evan linked to. Having just one document seems less prone to confusion.
I believe HTTP signatures are still useful even with FEP-8b32 object signing
Agreed, because FEP-8b32 is only useful for POSTs. It can’t be used to sign GET requests.
advertise support using FEP-844e on the server actor
RFC9421 defines its own mechanism for this using the Accept-Signature header field. For Fediverse purposes this would appear in the response to a POST request, and apply to subsequent POSTs to the same inbox. I haven’t seen anyone talk about using this on the Fediverse; perhaps this is because it’s only applicable to HTTP signatures and doesn’t cover any other features that people might want to advertise.
required signed fields: @method, @target-uri
if a query is present, require: @query
Isn’t the @query part already covered by @target-uri?
for POST, also require: content-type, content-digest
+1 for requiring the Content-Type. I did this at first, and was a bit puzzled to find that there are projects out there that don’t sign this header.
I also sign Accept if it’s present (eg in a GET request). I don’t know if it should be required, but I’d lean towards “better safe than sorry”.
signatures must use public keys from FEP-521a (“assertionMethod”)
Right now I allow the publicKey to be used if the algorithm is rsa-v1_5_sha256 - maybe this will offer an easier migration path for projects that don’t want to implement ED25519 yet?
You can also do HEAD on the inbox and discover links whose relation is http://www.w3.org/ns/ldp#constrainedBy per Linked Data Notifications – one of those might give you more information about what particular constraints an inbox is assuming.
The Accept-Signature header can also be exposed by doing OPTIONS on the inbox. LDN uses a similar Accept-Post header to indicate the Content-Type that a POST must have. You don’t have to try a POST first then potentially have it fail.
Does the value of the Content-Type have any security implications? Are there perceived attacks where the Content-Type might be varied after signing the other headers? I am guessing the concern would be something like “The signature was on application/ld+json content but the Content-Type was later set to application/vc”, which doesn’t really make sense for fedi’s current usage. Signing the Content-Digest of a POST makes sense and is what Mastodon currently enforces.
These should be separate concerns. Using publicKey implies nothing about which specific purposes the key may be used for. It is equivalent to having a verificationMethod only in the newer VC work. You still have no information about whether a specific key is allowed to be used for authenticating or asserting or other purposes. Right now in fedi, everyone assumes keys used to sign HTTP messages are implicitly fulfilling some purpose – perhaps they take a Signature to mean that the sec:owner or sec:controller of the keyId is either authenticating the delivery, or asserting the statements made in the content, or both, or something else.
This is an ambiguity that is generally bad for security, and things like git forges have moved to differentiate “authentication keys” for SSH access from “signing keys” for GPG commits. Using the same key for both means that if someone compromises your SSH authentication key, they will also be able to sign commits using your GPG identity. Using a different key means that they will be able to access repos as you, but commits will fail GPG validation.
In the case of fedi, an HTTP message being signed by a key for the purpose of sec:authentication means that “This is who is sending the HTTP message”. But an HTTP message being signed by a key for the purpose of sec:assertionMethod means that “This is who is making the claims in the content”. These might not be the same entity. An HTTP POST might be delivered by a proxy actor for every user on the domain, and the content might be asserted by a specific user’s actor.
+1 for writing a FEP, I would contribute to that effort
require ed25519, recommend rsa-v1_5_sha256
I think it should be the other way around: require rsa-v1_5_sha256, recommend ed25519. Since RSA is already used, implementers can start with RFC-9421 and add support for ed25519 later.
As far as I know, Mastodon and WordPress implemented RFC-9421 but not ed25519.
tootik
It's developed by @dimkr (he's on a tootik instance, you can test your implementation there)
It looks like it could be in the response to both 202 Accepted and 401 Unauthorized, so I like this idea as another way to find out that a server supports RFC signatures.
Oh hey, you’re right… I even have a comment to that effect in my code, I just didn’t remember that when writing my notes. Okay, so @query doesn’t need to be required, just @method & @target-uri.
I think using RSA at all was a mistake, and this is a good opportunity to push people into migrating. In my experience it will be difficult or impossible to enforce better algorithms later if we have bad ones in our “required” list.
In the languages I use (ts/python/rust), it’s been easier to find ed25519 support than RSA, but I don’t use ruby – is it hard to find a good ed25519 implementation there, and is that the reason mastodon & friends used it at first?
is that the reason mastodon & friends used it at first?
Ed25519 is a newer crypto, EdDSA was first mentioned in draft-cavage-http-signatures-11, 2019. As far as I know, ActivityPub servers were already using RSA at that time.