# `SignCore.XML.Canonicalizer`
[🔗](https://github.com/utaladriz/pkcs11ex/blob/v0.1.0/lib/sign_core/xml/canonicalizer.ex#L1)

Thin wrapper around `SignCore.XML.C14n.XmerlC14n` — our vendored
copy of `xmerl_c14n`.

The Phase 4 plan reserved the option to vendor in-tree if the
upstream package went unmaintained. The Hex 0.2.0 release crashes
on OTP 28 (unprefixed-attribute namespace field shape), so we
vendor + patch in `lib/pkcs11ex/xml/c14n/`. A future pivot to a
NIF-wrapped `bergshamra` is still a one-file replacement.

Scope of this module:

  * Canonicalise an `:xmerl` document or fragment into the byte
    sequence that `<DigestValue>` and `<SignatureValue>` are
    computed over.
  * v1 supports only **Exclusive XML Canonicalization 1.0**
    (`http://www.w3.org/2001/10/xml-exc-c14n#`) — the C14N method
    XAdES B-B mandates and the SII DTE shape uses. Inclusive C14N
    and 1.1 are out of scope until a real conformance test argues
    for them.
  * Errors surface as `{:error, {:c14n, reason}}` so the verify
    pipeline can branch on the class atom (per api.md §4.1).

# `method`

```elixir
@type method() :: :exclusive_c14n_10
```

Canonicalisation method atoms supported by this adapter.

# `xmerl_node`

```elixir
@type xmerl_node() :: tuple()
```

Anything `xmerl_c14n` accepts: a parsed `:xmerl` element record
(`{:xmlElement, ...}`) or document (`{:xmlDocument, ...}`). For
binary input use `parse/1` first.

# `canonicalize`

```elixir
@spec canonicalize(
  xmerl_node(),
  keyword()
) :: {:ok, binary()} | {:error, term()}
```

Canonicalise the given `:xmerl` element under Exclusive XML C14N 1.0.

## Options

  * `:method` — one of `[:exclusive_c14n_10]`. v1
    rejects anything else with `{:c14n, :unsupported_canonicalization}`.
  * `:inclusive_namespaces` — list of namespace prefixes that
    should NOT be excluded from the canonical form even though
    they're not visibly used. Maps to the
    `<InclusiveNamespaces PrefixList="...">` transform. The
    `xmerl_c14n` API takes this as a charlist list; we accept
    strings and convert.

# `canonicalize_subtree`

```elixir
@spec canonicalize_subtree(
  xmerl_node(),
  keyword()
) :: {:ok, binary()} | {:error, term()}
```

Canonicalises a sub-tree extracted from a host document where the
parent's default namespace would be inherited but is **not visibly
used** anywhere inside the sub-tree.

Why this is needed: exclusive C14N's W3C-spec behaviour drops
inherited default namespaces unless an element name in the
sub-tree is unprefixed (i.e., actually lives in the inherited
default namespace). Our vendored `xmerl_c14n` over-emits the
inherited default — it preserves it whenever it differs from the
outer parent — so `<ds:SignedInfo>` extracted from a SII-DTE
document picks up `xmlns="http://www.sii.cl/SiiDte"` even though
none of its descendants use that namespace.

This helper clears the parsed element's
`:xmlNamespace.default` field before delegating to
`canonicalize/2`, producing the canonical bytes a correct
exclusive-C14N implementation (`xmlsec1`, BouncyCastle) would
emit.

**Caveat:** only safe when every element in the sub-tree uses an
explicit namespace prefix (`ds:`, `xades:`, etc.). If any element
name is unprefixed, the default namespace IS visibly used and
must be preserved — use `canonicalize/2` in that case.

Used by both `SignCore.XML.sign/2` (for the
`<xades:SignedProperties>` digest) and `SignCore.XML.verify/2`
(for re-extracting `<ds:SignedInfo>` and
`<xades:SignedProperties>` from the host document).

# `parse`

```elixir
@spec parse(binary()) :: {:ok, xmerl_node()} | {:error, {:malformed_xml, term()}}
```

Parse an XML binary into an `:xmerl` element. Convenience wrapper
around `:xmerl_scan.string/2` that returns `:ok | :error` tuples
rather than crashing on malformed input.

Returns the root `:xmlElement`. `xmerl_c14n` accepts either an
element or a document wrapper, but later phases of the sign flow
need the root element to splice `<Signature>` in as a child, so
we standardise on returning the element here.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
