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
:xmerldocument 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).
Summary
Types
Canonicalisation method atoms supported by this adapter.
Anything xmerl_c14n accepts: a parsed :xmerl element record
({:xmlElement, ...}) or document ({:xmlDocument, ...}). For
binary input use parse/1 first.
Functions
Canonicalise the given :xmerl element under Exclusive XML C14N 1.0.
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.
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.
Types
Functions
@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. Thexmerl_c14nAPI takes this as a charlist list; we accept strings and convert.
@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).
@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.