Open trwnh opened 5 days ago
@trwnh — Your suggested algorithm (including the sub-steps) would be better as an ordered list, than as the current unordered, as bullets should be executable in any order, which is not usually the case for an algorithm.
This is great, thank you for the details @trwnh! And @TallTed, true, but @trwnh's algorithm is pretty clearly intended to be ordered in spirit, I think we can give them the benefit of the doubt here.
I'm all for resolving ambiguities here. Fragment handling is a good example, I can definitely change the language to clarify that you keep it for comparing against ids like in step 7.
I am a bit reluctant to make it quite this detailed and in the weeds though. This new algorithm reads more like pseudocode than prose, and I don't know if I want to go quite that far. It is an algorithm, agreed, but it's not a normative standard, and it leans heavily on existing standards and other established patterns like caching, array vs object handling, fetching objects by id if they're not inlined, etc.
Regardless, I'll take another pass at it and incorporate a lot of this. Thank you!
yeah, the list is intended to be ordered but while typing it on my phone it was too inconvenient to use numbers. (also my pronouns are they/them :x)
re: taking another pass and incorporating stuff, i think the important bits are:
keyId="http://actor.example/#not-the-real-key"
and land on "publicKey": {"id": "#the-real-key"}
and never detect the error
publicKey.id
to keyId
publicKey.id
didn't match the keyId
, then call this out as a "key not matching" error. if no suitable publicKey
is present (i.e. it is missing publicKeyPem
or otherwise missing entirely), then call this out as a "key not found" error.
https://swicg.github.io/activitypub-http-signature/#how-to-obtain-a-signature-s-public-key
the way it's written, handling a key document in step 5 has you jumping back to step 2 with an actor id, and then step 4 skips ahead to step 7
what you want to be doing is verifying that the actor's
publicKey
includes an id matching the http-sig'skeyId
you started with, not to throw away the key in the interimstep 7 should make it clear that the key in
publicKey
may be referenced by id, and that you should either a) have this key in-memory while this algorithm is processing, or b) that you need to refetch it from cache (step 2) or from network (step 3, but you should already have it from your first pass of the algorithm...)i understand what the intent is with the "go back and run this algorithm with an actor" bit, but as written it's inefficient.
there is also an implication in step 1 that you should be discarding url fragments, despite this being unnecessary and also needing the url fragment later on in step 7.
furthermore the
id
==keyId
comparison needs to make sure that thepublicKey.id
is converted to an absolute URI first, since it could be relative or absolutea more correct algorithm should be:
KEY_ID
,DOCUMENT
,PUBLIC_KEY
,ACTOR_ID
.KEY_ID
to the value of thekeyId
parameter of the HTTP Signature.KEY_ID
using an HTTP GET. Caching may be used. Store the result in memory asDOCUMENT
.PUBLIC_KEY
to the value of thepublicKeyPem
property inDOCUMENT
, if present.ACTOR_ID
to the id of thecontroller
orowner
property inDOCUMENT
, if present.PUBLIC_KEY
has not been set: SetPUBLIC_KEY
to the value of thepublicKey
property inDOCUMENT
, if present.PUBLIC_KEY
is an array: Filter the array for an item whose absolutizedid
matchesKEY_ID
.PUBLIC_KEY
is an object:ACTOR_ID
has not been set: SetACTOR_ID
to the id of thecontroller
orowner
property of that object, if present.PUBLIC_KEY
to the value of thepublicKeyPem
property of that object, if present. Otherwise, unsetPUBLIC_KEY
.ACTOR_ID
has not been set: SetACTOR_ID
to the value ofKEY_ID
, removing the URL fragment if any.ACTOR_ID
using an HTTP GET. Caching may be used. Store the result in memory asDOCUMENT
.PUBLIC_KEY
to the value of thepublicKey
property inDOCUMENT
, if present.PUBLIC_KEY
is an array: Filter the array for an item whose absolutizedid
matchesKEY_ID
.PUBLIC_KEY
is an object:id
of that object does not matchKEY_ID
, abort processing with a KeyNotMatchingError.PUBLIC_KEY
to the value of thepublicKeyPem
property of that object, if present. Otherwise, unsetPUBLIC_KEY
.PUBLIC_KEY
is not set, abort processing with a KeyNotFoundError.PUBLIC_KEY
and return this PEM-decoded value along withACTOR_ID
.