Skip to main content

C2PA manifest embedding, referencing, and hard binding for HTML documents

Project description

c2pa-html

C2PA manifest embedding, referencing, and hard binding for HTML documents.

Implements the Embedding Manifests into HTML section of the C2PA Technical Specification: a C2PA Manifest Store carried inline as the Base64 content of a <script type="application/c2pa"> element, or referenced externally by a <link rel="c2pa-manifest"> element, both in the document head.

[dependencies]
c2pa-html = "0.1"

What it does

document discover, embed, reference, and remove a manifest association
hardbinding the exact c2pa.hash.data coverage, with compute and verify

Signature verification, certificate trust, assertion validation, and resolution of an external manifest URI are out of scope.

Reference an external manifest

The specification prefers this form.

use c2pa_html::document;

let page = b"<html>\n<head>\n    <title>Example</title>\n</head>\n<body></body>\n</html>";
let out = document::embed_reference(page, "https://fabrikam.example/m.c2pa")?;

let manifest = document::extract(&out)?;
assert_eq!(manifest.href(), Some("https://fabrikam.example/m.c2pa"));
# Ok::<(), c2pa_html::Error>(())

Carry the manifest inline

use c2pa_html::document;

let page = b"<html>\n<head>\n    <title>Example</title>\n</head>\n<body></body>\n</html>";
let out = document::embed(page, b"manifest-store-bytes")?;

assert_eq!(
    document::extract(&out)?.store(),
    Some(&b"manifest-store-bytes"[..])
);
// Removing the manifest restores the document byte for byte.
assert_eq!(document::remove(&out)?, page);
# Ok::<(), c2pa_html::Error>(())

Bind the document

use c2pa_html::document;
use c2pa_html::hardbinding::{compute_data_hash, verify_data_hash, Algorithm, Sha2};

let page = b"<html>\n<head>\n    <title>Example</title>\n</head>\n<body></body>\n</html>";
let out = document::embed(page, b"manifest-store-bytes")?;

let binding = compute_data_hash(&out, Algorithm::Sha256, &Sha2)?;
assert!(verify_data_hash(&out, &binding, &Sha2).is_ok());
# Ok::<(), c2pa_html::Error>(())

Binding coverage

  • Inline — one exclusion range covering the entire script element, <script through </script> inclusive. The hash is over the document with that range removed.
  • External — no exclusion range at all. The hash is over the entire document, link element included, so the manifest URI cannot be swapped without breaking the binding.

The hash is over the bytes of the document as stored, with no normalization. Anything that re-serializes the HTML — a CMS, a CDN, a formatter that rewrites quote styles or collapses whitespace — shifts byte offsets and invalidates the binding. That is by design: re-serialization is a content modification. Embed after the final serialization step, or use an external manifest.

The inline hash can be computed before the manifest exists

Because the exclusion covers the entire script element, the covered bytes are the document with the element cut out — and embed adds no bytes outside the element, so that is the original document. Signing an inline HTML manifest needs no placeholder-reserve-then-fill dance: hash, sign, embed.

use c2pa_html::hardbinding::inline_hash_before_embed;

An external manifest has no exclusion, so the link element is inside the hash and the order reverses: insert the link first, then hash.

Discovery

Scoped to the document head, byte-oriented, and tolerant of how HTML is actually written:

  • all three attribute quoting forms — rel="x", rel='x', rel=x
  • ASCII case-insensitive tag names, attribute names, type, and rel
  • rel as a space-separated token list, per HTML
  • link matched on rel alone; type="application/c2pa" is optional
  • comments, doctypes, and the contents of other script and style elements are never mistaken for markup
  • an implied head (both tags omitted) is still searched

A document shall carry at most one association. Two script elements, two link elements, or one of each are all rejected with the specified manifest.html.multipleManifests failure — the manifests were located, and the document is rejected for carrying too many.

Finding nothing carries no status code (it is simply an unsigned document), and neither does an element that matches but yields no Manifest Store — the specification names no code for that, and the fail-safe reading is that nothing was obtained. Error::is_no_manifest_located() draws the line a caller actually needs: "carries no provenance" versus "carried provenance that was rejected".

Bytes, not text

The specification directs a validator to treat the document "as a series of bytes (vs. text)", so every entry point takes &[u8] and returns Vec<u8>. A document in a legacy ASCII-compatible encoding scans correctly, and byte offsets mean what the hard binding says they mean.

Zero dependencies, no features

Discovery, embedding, Base64, SHA-2, and the binding algorithm are all in-crate. There is nothing to enable and nothing to pull in — the dependency list is empty in every configuration.

SHA-256/384/512 are implemented against FIPS 180-4 and tested against the NIST vectors. A hash is the one primitive where writing it yourself is uncontroversial: fully specified, no key, public input, no timing side channel, and published vectors that pin every path.

What that gives up is speed — no SHA-NI, no NEON. Immaterial for an HTML document; it would not be for a multi-gigabyte asset, which is why hashing goes through the Hasher trait. A caller with that problem injects an accelerated implementation and never touches the built-in one.

Related

crate method
c2pa-structured-text structured text: ASCII-armoured manifest in a comment
c2pa-unstructured-text unstructured text: Unicode variation selectors

HTML is a file format, so its binding hashes stored bytes with no normalization. The text methods differ deliberately: structured text also hashes raw bytes but has no element to exclude, and unstructured text normalizes to NFC because clipboard-portable text may arrive in any normalization form.

License

MIT OR Apache-2.0.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

c2pa_html-0.1.0.tar.gz (43.8 kB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

c2pa_html-0.1.0-cp39-abi3-win_amd64.whl (136.3 kB view details)

Uploaded CPython 3.9+Windows x86-64

c2pa_html-0.1.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (271.9 kB view details)

Uploaded CPython 3.9+manylinux: glibc 2.17+ x86-64

c2pa_html-0.1.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (267.1 kB view details)

Uploaded CPython 3.9+manylinux: glibc 2.17+ ARM64

c2pa_html-0.1.0-cp39-abi3-macosx_11_0_arm64.whl (238.8 kB view details)

Uploaded CPython 3.9+macOS 11.0+ ARM64

c2pa_html-0.1.0-cp39-abi3-macosx_10_12_x86_64.whl (242.4 kB view details)

Uploaded CPython 3.9+macOS 10.12+ x86-64

File details

Details for the file c2pa_html-0.1.0.tar.gz.

File metadata

  • Download URL: c2pa_html-0.1.0.tar.gz
  • Upload date:
  • Size: 43.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for c2pa_html-0.1.0.tar.gz
Algorithm Hash digest
SHA256 1964afbc9d2d2899f90eb32ec71cc509b1437cd7572e0f0ee6a40088e5213284
MD5 ef6f38927ea9370e9bc366afd2fa5cc6
BLAKE2b-256 ad1681d8376660d4a73fe001baa30c05472750f3de2d8b0474193395fe7ca9e1

See more details on using hashes here.

Provenance

The following attestation bundles were made for c2pa_html-0.1.0.tar.gz:

Publisher: release.yml on writerslogic/c2pa-html

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file c2pa_html-0.1.0-cp39-abi3-win_amd64.whl.

File metadata

  • Download URL: c2pa_html-0.1.0-cp39-abi3-win_amd64.whl
  • Upload date:
  • Size: 136.3 kB
  • Tags: CPython 3.9+, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for c2pa_html-0.1.0-cp39-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 aafc0fdf773ad9096e63d24bd8d5c7102c45200d66bf87c12d6534e8d8d31bbf
MD5 1dfb3fe84dfc536da0448fd66f859247
BLAKE2b-256 d37d97aafa3314e91ca97973ce5c9fd484fba784e6f60fb8449a75fad0c7755b

See more details on using hashes here.

Provenance

The following attestation bundles were made for c2pa_html-0.1.0-cp39-abi3-win_amd64.whl:

Publisher: release.yml on writerslogic/c2pa-html

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file c2pa_html-0.1.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for c2pa_html-0.1.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 1efe08c5a06f040785d05df232b06d621b74d8964dbfd1e96c8e0f3e9c4b8ae8
MD5 ac8c3819b1d6d2b325f72dcb2d37724b
BLAKE2b-256 3918c635ad517e18d224bf48605467fb6303df434dc1eec345f0d21281447d93

See more details on using hashes here.

Provenance

The following attestation bundles were made for c2pa_html-0.1.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:

Publisher: release.yml on writerslogic/c2pa-html

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file c2pa_html-0.1.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for c2pa_html-0.1.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 191f01de351c75ce19689843611a2bceeba60c02836c170dab5e3d967d1ac3a8
MD5 97b0a21a3779e4a2e31f5ed6f76675f5
BLAKE2b-256 8e317daaaa0d58cdbdc10084e7bcac023e576c2a5286fe620fffbfe20a6da5f9

See more details on using hashes here.

Provenance

The following attestation bundles were made for c2pa_html-0.1.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl:

Publisher: release.yml on writerslogic/c2pa-html

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file c2pa_html-0.1.0-cp39-abi3-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for c2pa_html-0.1.0-cp39-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 6d6c1a7877dd3aed784c32664dce3ffba22938fa5ab8544a739bde6b16540b78
MD5 3caaed170cce7795c5206a8b5e541f60
BLAKE2b-256 82e31c432ba277f19dd0a21cd70064851fb2f15eb2e5e44975479e1598c58f48

See more details on using hashes here.

Provenance

The following attestation bundles were made for c2pa_html-0.1.0-cp39-abi3-macosx_11_0_arm64.whl:

Publisher: release.yml on writerslogic/c2pa-html

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file c2pa_html-0.1.0-cp39-abi3-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for c2pa_html-0.1.0-cp39-abi3-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 1cd41fab3641c826c14d4f39de7bedda080e7ec8a163412e74797eb7c4d5546c
MD5 0ddf609723f65dc4e23dd8910e721a60
BLAKE2b-256 cd2b0d0f9767756fb7d032296a1661aba864ceb1067f1302fc8886213c82b84c

See more details on using hashes here.

Provenance

The following attestation bundles were made for c2pa_html-0.1.0-cp39-abi3-macosx_10_12_x86_64.whl:

Publisher: release.yml on writerslogic/c2pa-html

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page