Is Provenance Rediscovering XML Signature?
Here is a puzzle that comes up in every content provenance project eventually. An article is signed. A reader quotes two paragraphs of it in a newsletter. What should a verifier say about those two paragraphs?
The honest answer, in most provenance systems shipping today, is “invalid.” Not because anything dishonest happened, but because a C2PA hard binding is a hash over an exact byte sequence, and two paragraphs are not the article. The signature is doing precisely what a signature does. The problem is that quoting is not tampering, and a system that reports failure on ordinary, legitimate use teaches people to ignore it.
That puzzle has a name and a solution, and both are about twenty-five years old.
The inheritance nobody mentions
C2PA signs with COSE. COSE is the CBOR-encoded sibling of JOSE. And JOSE was specified, in large part, as a deliberate reaction against XML Signature.
The reaction was thorough. JOSE has no canonicalization. No reference lists. No transforms. No countersignatures. A JWS covers one exact byte sequence and makes no claim about anything else. Every one of those omissions was a considered decision, and the omissions are the direct cause of the structural limits provenance now runs into.
So the shape of the field today is a signing format that can say only “these exact bytes, signed by this key,” carrying a use case — provenance across editing, excerpting, composition, and multi-party review — that needs nearly everything the format left out.
What the previous generation built
XML Signature and the WS-Security stack around it were built for a problem that looks unfamiliar in the media world and is structurally identical: documents that pass through intermediaries, get wrapped and re-serialized, get partially signed by different actors, and have to remain verifiable at the far end.
Signing content with no stable byte sequence. XMLDSig never signed the bytes. Canonicalization produced a normalized form — whitespace, attribute order, namespace declarations — and the signature covered the canonical form. The modern complaint that “free-form text has no stable byte representation” is a request for a canonical form, and canonical forms are a solved problem.
Signing a fragment that moves. Exclusive canonicalization exists because a signed subtree inherits namespace declarations from its ancestors. Move the subtree into a different document and the signature either breaks or, worse, silently changes meaning. The excerpt problem — a paragraph lifted into an aggregator, a search result, a retrieval chunk — is the moved-subtree problem wearing different clothes.
Binding without a container. Enveloped, enveloping, and detached signatures, with URI references naming what is covered, were all present from the start. C2PA has enveloped signatures, because media files have containers to put a manifest in, and is now working out detached signing one format at a time.
Per-component coverage. A single XMLDSig signature carries many references, each with its own URI and its own transform chain. Granular, per-component coverage under one signature was the ordinary case rather than an extension. An article with independently hashed media components is a multi-reference signature by another name.
Selective disclosure. XPath filter transforms selected which parts of a document a signature covered. The decrypt transform let a signature cover content that remains encrypted to the verifier. Both are the problem every newsroom provenance project eventually hits: prove the whole while withholding a part.
Multi-party with intermediaries. WS-Security let several actors sign different parts of a message as it moved through intermediaries, each adding signed material without invalidating what came before. Reporter, editor, fact-checker, and publisher is the same graph with different labels.
Why all of it was thrown away
This is the half that matters, and the half most often missing when someone rediscovers the first list.
XMLDSig’s expressiveness was a catastrophe in production. Signature wrapping was the worst of it: the combination of reference URIs and a flexible document model let an attacker relocate the signed element and place attacker-controlled content where the application would actually read it, while the signature still verified perfectly. The root cause was a gap between what the signature covered and what the application consumed. That gap broke SAML deployments, WS-Security stacks, and cloud control planes for the better part of a decade.
Transforms were an execution surface. A transform chain is code the verifier runs on attacker-supplied input. XSLT transforms were remote code execution as a design feature. XPath transforms were denial of service.
Canonicalization was too subtle. Several algorithms with slightly different namespace behavior produced interoperability failures, and worse, security-relevant disagreements between implementations about what had actually been signed.
JOSE looked at all of that and concluded that a signature should cover a byte string, full stop. The conclusion was correct. It is also why the format cannot express the things provenance needs.
The rule that comes out of knowing both halves
Adopt the primitive. Refuse the flexibility.
Every capability in the first list is genuinely required by content provenance. Every general-purpose mechanism for expressing those capabilities is dangerous. The engineering discipline that follows is specific:
Coverage must be explicit, enumerable, and computed by the verifier — never inferred from where content happens to sit in a document. The verifier reads what is covered from the signed structure itself and then confirms that what the application consumes is exactly that. Closing the covered-versus-consumed gap is the entire signature-wrapping lesson in one sentence.
One canonicalization, named in the signed payload, with no negotiation and no algorithm agility at verification time.
No attacker-influenced selection. If transforms exist at all, they come from a fixed vocabulary the implementer chose, not from an expression language supplied inside the document being verified.
Append-only for multi-party. A later actor adds a signature. A later actor never re-serializes what an earlier actor signed.
Where the risk actually sits now
Worth saying plainly, because the current specifications are better than the reputation of their ancestors: C2PA and the Creator Assertions Working Group specify no JSON-LD canonicalization and require no context resolution. A CAWG identity claims aggregation credential is secured with an enveloping COSE signature, and the specification is explicit that the unsecured credential is the unencoded COSE payload — the raw bytes. The @context property is required to contain particular values, and those values are checked as strings inside signed bytes. Nothing is fetched. The specifications kept the JOSE discipline honestly.
Which moves the risk somewhere less obvious. Byte-exact verification is safe. Deciding what the verified bytes mean is not covered by the signature at all. Any consumer that expands a credential’s JSON-LD in order to interpret it — to render an author, resolve an affiliation, evaluate a policy — reintroduces a runtime dependency on the meaning of content that was already verified. What you verified and what you act on drift apart.
That is the covered-versus-consumed gap arriving by a different road. The fix is the same as it was in 2005: pin the context by value or by digest, never dereference anything during verification or rendering, and drive interpretation only from terms present in the signed bytes.
The primitives are coming back because the problem requires them. The attacks will come back too, unless the people rebuilding them go and read what happened the first time.