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

XML-DSig + XAdES B-B format adapter.

## Sign

    SignCore.XML.sign(xml_bytes,
      module: pkcs11_module,
      slot_id: slot_id,
      pin: "1234",
      key_label: "platform-signing-key",
      alg: :PS256,
      x5c: [leaf_der, intermediate_der]
    )

Returns the original XML with an enveloped `<ds:Signature>`
element spliced in before the root's closing tag. The output is a
XAdES B-B signature with `<xades:SigningCertificateV2>`,
`<xades:SigningTime>`, and the canonical
`Exclusive XML Canonicalization 1.0` C14N method on every
`<ds:Reference>` and the `<ds:SignedInfo>` element itself.

Pipeline:

  1. Parse the input XML (xmerl).
  2. Generate fresh `signature_id` and `signed_properties_id`.
  3. Build the XAdES `<xades:QualifyingProperties>` block via
     `SignCore.XML.XAdES`. SHA-256 the leaf cert into
     `<xades:CertDigest>`; DER-encode the RFC 5035 IssuerSerial
     into `<xades:IssuerSerialV2>`.
  4. Canonicalise `<xades:SignedProperties>` (subtree only) with
     exc-c14n → SHA-256 → second `<ds:Reference>` digest.
  5. Canonicalise the input document with exc-c14n → SHA-256 →
     data `<ds:Reference>` digest. The enveloped-signature
     transform is conceptually applied; at sign time there is no
     Signature in the document yet so the transform is a no-op,
     leaving the canonical form unchanged.
  6. Build `<ds:SignedInfo>` with both references.
  7. Canonicalise `<ds:SignedInfo>` with exc-c14n. Those bytes
     are the to-be-signed input.
  8. Sign via `Pkcs11ex.sign_bytes/2` (PKCS#11 → HSM).
     **Software signing never enters the path.**
  9. Build the full `<ds:Signature>` element and splice it into
     the source XML before the root's closing tag.

## v1 limitations

  * Enveloped signatures only. Detached and enveloping XML-DSig
    modes are post-v1.
  * `:PS256` and `:RS256`. PS256 emits the
    `sha256-rsa-MGF1` signature method URI per RFC 4051;
    receivers should use SHA-256 / MGF1-SHA-256 / sLen=32 to
    match the HSM-produced signature.
  * Single `<ds:Reference>` URI is empty (whole-document). The
    `:reference_uri` opt is reserved for a future fragment-signing
    mode.
  * `verify/2` lands in step 4b.1.6.

## Architectural invariants

  * x5c is **untrusted input** until verify runs the
    configured `SignCore.Policy` (allowlist gate).
  * Signature math always runs in the HSM via
    `Pkcs11ex.sign_bytes/2`. Software signing is never invoked.

# `sign_result`

```elixir
@type sign_result() :: {:ok, binary()} | {:error, term()}
```

# `verify_result`

```elixir
@type verify_result() :: {:ok, subject_id :: term()} | {:error, term()}
```

# `sign`

```elixir
@spec sign(
  binary() | iodata(),
  keyword()
) :: sign_result()
```

Sign an XML document with XML-DSig + XAdES B-B.

# `verify`

```elixir
@spec verify(
  binary() | iodata(),
  keyword()
) :: verify_result()
```

Verify a XAdES B-B-signed XML document.

Returns `{:ok, subject_id}` where `subject_id` is whatever the
configured `SignCore.Policy.validate/3` returned. The verify
pipeline runs in this order — every step is a checkpoint that
can refuse the signature with the documented error class:

  1. Parse the signed XML. Locate the (single) `<ds:Signature>`
     element. v1 refuses multi-signature documents.
  2. Extract the embedded `<ds:KeyInfo>` x5c chain.
  3. **Allowlist gate (architectural invariant).** Synthesise a
     JOSE-style header and route it through the configured
     `SignCore.Policy` — `resolve/2` then `validate/3`. The
     chain is **untrusted input** until both succeed. No
     cryptographic check has happened yet.
  4. Verify the XAdES `<xades:SigningCertificateV2>` actually
     binds the leaf cert from `<ds:KeyInfo>`:
     `SHA-256(leaf_der)` must match `<xades:CertDigest>`, and
     `<xades:IssuerSerialV2>` must match the leaf's issuer +
     serial.
  5. Recompute the data `<ds:Reference>` digest: apply the
     enveloped-signature transform (remove `<Signature>` from
     the doc), exc-c14n the result, SHA-256.
  6. Recompute the SignedProperties `<ds:Reference>` digest:
     canonicalise the `<xades:SignedProperties>` subtree,
     SHA-256.
  7. Canonicalise `<ds:SignedInfo>` (subtree extraction with
     inherited-default-namespace clear) and verify the math
     against the leaf's SPKI.

Failures from step 3 short-circuit before any signature math, so
callers cannot use `verify/2` as a CPU-bound oracle on
attacker-supplied certificates.

---

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