Skip to content

FEP-8b32: Object Integrity Proofs

Authors Status Type Date received Tracking issue Discussions Repository
silverpill @silverpill@mitra.social DRAFT implementation 2022-11-12 #29 Discussions codeberg

Summary

This proposal describes how ActivityPub servers and clients could create self-authenticating activities and objects.

HTTP signatures are often used for authentication during server-to-server interactions. However, this ties authentication to activity delivery, and limits the flexibility of the protocol.

Integrity proofs are sets of attributes that represent digital signatures and parameters required to verify them. These proofs can be added to any activity or object, allowing recipients to verify the identity of the actor and integrity of the data. That decouples authentication from the transport, and enables various protocol improvements such as offline verification and client-side signing.

History

Mastodon supports Linked Data signatures since 2017, and a number of other platforms added support for them later. These signatures are similar to integrity proofs, but are based on outdated Linked Data Signatures 1.0 specification, which has been superseded by other standards.

Requirements

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC-2119.

Integrity proofs

The proposed authentication mechanism is based on Data Integrity specification.

Proof generation

The proof MUST be created according to the Data Integrity specification, section 4.2 Add Proof.

The process of proof generation consists of the following steps:

  • Canonicalization is a transformation of a JSON object into the form suitable for hashing, according to some deterministic algorithm.
  • Hashing is a process that calculates an identifier for the transformed data using a cryptographic hash function.
  • Signature generation is a process that calculates a value that protects the integrity of the input data from modification.

The resulting proof is added to the original JSON object under the key proof.

The list of attributes used in integrity proof is defined in Data Integrity specification, section 2.1 Proofs. The proof type MUST be DataIntegrityProof, as specified in section 3.1 DataIntegrityProof. The value of proofPurpose attribute MUST be assertionMethod.

The value of the verificationMethod attribute of the proof can be an HTTP(S) URI or a DID URL.

The controlled identifier document where the verification method is expressed MUST be an actor object or a DID document that is provably associated with an ActivityPub actor (e.g. using a mechanism described in FEP-c390 or FEP-ef61). The verification method MUST be associated with the assertionMethod property of the controlled identifier document. If controlled identifier document is an actor object, implementers SHOULD use assertionMethod property as described in FEP-521a.

Objects identified using fragment identifiers SHOULD NOT contain integrity proofs.

Objects SHOULD NOT contain more than one integrity proof.

Proof verification

Recipients of an object SHOULD perform proof verification if it contains integrity proofs.

Verification process MUST follow the Data Integrity specification, section 4.4 Verify Proof. It starts with the removal of the proof value from the JSON object. Then verification method is retrieved from the controlled identifier document as described in Controlled Identifiers specification, section 3.3 Retrieve Verification Method. Then the object is canonicalized, hashed and signature verification is performed according to the parameters specified in the proof.

The subject of the controlled identifier document where the verification method is expressed MUST be the owner of the signed object, or a DID that is provably associated with that actor (e.g. using a mechanism described in FEP-c390 or FEP-ef61).

If a verifier encounters an integrity proof that uses a verification method that it can't resolve, or uses a cryptosuite that is not supported, or the proof has expired (as indicated by the expires property), the verifier SHOULD ignore the proof and try other authentication methods.

When verifying a delivered activity, the top-level integrity proof MUST take precedence over the HTTP signature if both are present. The HTTP signature MAY be dismissed.

Algorithms

Implementers are expected to pursue broad interoperability when choosing algorithms for integrity proofs.

eddsa-jcs-2022 cryptosuite is RECOMMENDED:

  • Canonicalization: JCS
  • Hashing: SHA-256
  • Signatures: EdDSA

Backward compatibility

Integrity proofs and linked data signatures can be used together, as they rely on different properties (proof and signature, respectively).

If compatibility with legacy systems is desired, the integrity proof MUST be created and inserted before the generation of the linked data signature.

If both proof and signature are present in a received object, the linked data signature MUST be removed before the verification of the integrity proof.

Security considerations

Implementers using integrity proofs as an authentication mechanism are advised to follow the recommendations given in FEP-fe34: Origin-based security model.

Privacy considerations

If a private object is signed, its authenticity can be proven if it is distributed beyond the intended recipients. This risk can be mitigated by encrypting private content.

Integrity proofs can be repudiated by rotating the verification method.

Examples

Signed object

{
  "@context": [
    "https://www.w3.org/ns/activitystreams",
    "https://w3id.org/security/data-integrity/v2"
  ],
  "id": "https://server.example/objects/1",
  "type": "Note",
  "attributedTo": "https://server.example/users/alice",
  "content": "Hello world",
  "proof": {
    "@context": [
      "https://www.w3.org/ns/activitystreams",
      "https://w3id.org/security/data-integrity/v2"
    ],
    "type": "DataIntegrityProof",
    "cryptosuite": "eddsa-jcs-2022",
    "verificationMethod": "https://server.example/users/alice#ed25519-key",
    "proofPurpose": "assertionMethod",
    "proofValue": "...",
    "created": "2023-02-24T23:36:38Z"
  }
}

Signed activity

{
  "@context": [
    "https://www.w3.org/ns/activitystreams",
    "https://w3id.org/security/data-integrity/v2"
  ],
  "id": "https://server.example/activities/1",
  "type": "Create",
  "actor": "https://server.example/users/alice",
  "object": {
    "id": "https://server.example/objects/1",
    "type": "Note",
    "attributedTo": "https://server.example/users/alice",
    "content": "Hello world"
  },
  "proof": {
    "@context": [
      "https://www.w3.org/ns/activitystreams",
      "https://w3id.org/security/data-integrity/v2"
    ],
    "type": "DataIntegrityProof",
    "cryptosuite": "eddsa-jcs-2022",
    "verificationMethod": "https://server.example/users/alice#ed25519-key",
    "proofPurpose": "assertionMethod",
    "proofValue": "...",
    "created": "2023-02-24T23:36:38Z"
  }
}

Signed activity with embedded signed object

{
  "@context": [
    "https://www.w3.org/ns/activitystreams",
    "https://w3id.org/security/data-integrity/v2"
  ],
  "id": "https://server.example/activities/1",
  "type": "Create",
  "actor": "https://server.example/users/alice",
  "object": {
    "@context": [
      "https://www.w3.org/ns/activitystreams",
      "https://w3id.org/security/data-integrity/v2"
    ],
    "id": "https://server.example/objects/1",
    "type": "Note",
    "attributedTo": "https://server.example/users/alice",
    "content": "Hello world",
    "proof": {
      "@context": [
        "https://www.w3.org/ns/activitystreams",
        "https://w3id.org/security/data-integrity/v2"
      ],
      "type": "DataIntegrityProof",
      "cryptosuite": "eddsa-jcs-2022",
      "verificationMethod": "https://server.example/users/alice#ed25519-key",
      "proofPurpose": "assertionMethod",
      "proofValue": "...",
      "created": "2023-02-24T23:36:38Z"
    }
  },
  "proof": {
    "@context": [
      "https://www.w3.org/ns/activitystreams",
      "https://w3id.org/security/data-integrity/v2"
    ],
    "type": "DataIntegrityProof",
    "cryptosuite": "eddsa-jcs-2022",
    "verificationMethod": "https://server.example/users/alice#ed25519-key",
    "proofPurpose": "assertionMethod",
    "proofValue": "...",
    "created": "2023-02-24T23:36:38Z"
  }
}

Test vectors

Implementations

Future work

Use cases

Quantum-resistant cryptosuites

This document recommends the eddsa-jcs-2022 cryptosuite, which is not secure against attacks by quantum computers. At the time of writing, the cryptosuites for quantum-resistant integrity proofs are being standardized in Quantum-Resistant Cryptosuites v1.0 specification.

References

CC0 1.0 Universal (CC0 1.0) Public Domain Dedication

To the extent possible under law, the authors of this Fediverse Enhancement Proposal have waived all copyright and related or neighboring rights to this work.