Skip to content

Handle mismatched id values in standalone key documents #963

Description

@dahlia

When resolveFetchedKey in packages/fedify/src/sig/key.ts fetches the document at a keyId URL and parses it as a standalone CryptographicKey or Multikey, it does not check whether the object's id matches the requested URL:

let key: T | null = null;
if (object instanceof cls) key = object;
else if (isActor(object)) {
  // …iterates keys and matches k.id?.href === keyId
}

The actor branch compares each candidate with k.id?.href === keyId before accepting it. The standalone branch skips that check. A document served at one URL can therefore declare a different id and still be cached under the requested URL.

This came from a security report, but we closed the report because the mismatch does not provide a way to impersonate another actor. The verification path does not use the key document's id to establish the actor's identity. It checks the key's owner or controller against the activity's actor.

The current behavior is nevertheless confusing: key.id may differ from the keyId used for the lookup and cache entry. For a standalone key with a present but mismatched id, we could reject the document or emit a warning.

The actor branch intentionally allows one related case. When the requested keyId has no fragment and the actor exposes exactly one key, it accepts that key without an exact id match:

const keyIdUrl = new URL(keyId);
if (key == null && keyIdUrl.hash === "" && length === 1) {
  key = lastKey;
}

A change to the standalone path should account for this existing tolerance rather than making the result depend unexpectedly on whether the response is an actor or a key document. I am not yet sure whether a mismatch should be an error. Logging it is less likely to break interoperability, but rejecting it keeps the fetched key's identity aligned with its cache key.

Acceptance criteria:

  • A standalone key document with a present id that differs from the requested keyId is rejected or handled according to a documented and tested rule.
  • The fragmentless single-key tolerance in the actor branch continues to work.
  • A regression test covers a standalone key document with a mismatched id.

Metadata

Metadata

Assignees

Type

Fields

Priority

Low

Effort

Low

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions