SignCore.XML.XAdES (sign_core v0.1.0)

Copy Markdown View Source

Builds the XAdES B-B <xades:QualifyingProperties> block.

Produces the canonical shape ETSI EN 319 132-1 prescribes for B-B:

<xades:QualifyingProperties Target="#Signature-{id}"
    xmlns:xades="http://uri.etsi.org/01903/v1.3.2#"
    xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
  <xades:SignedProperties Id="xades-{id}">
    <xades:SignedSignatureProperties>
      <xades:SigningTime>2026-05-06T14:05:30Z</xades:SigningTime>
      <xades:SigningCertificateV2>
        <xades:Cert>
          <xades:CertDigest>
            <ds:DigestMethod Algorithm=".../sha256"/>
            <ds:DigestValue>...</ds:DigestValue>
          </xades:CertDigest>
          <xades:IssuerSerialV2>...</xades:IssuerSerialV2>
        </xades:Cert>
      </xades:SigningCertificateV2>
    </xades:SignedSignatureProperties>
  </xades:SignedProperties>
</xades:QualifyingProperties>

The <xades:SignedProperties> element is what the second <ds:Reference> in the signature points at. The verifier recomputes its exc-c14n digest and matches it against the reference's <ds:DigestValue> — that's how the signature binds the claimed signing certificate, signing time, and any other signed properties to the rest of the signed data.

v1 scope

  • SigningCertificateV2 with IssuerSerialV2 (XAdES EN 319 132-1). The older SigningCertificate / IssuerSerial (TS 101 903 v1.3.2) form is post-v1.
  • Only the leaf cert is digested into SigningCertificateV2. Including intermediates is allowed by spec but not required for B-B; each cert in the chain would otherwise become its own <xades:Cert> element.
  • SigningTime is the only signed-signature-property emitted besides SigningCertificateV2. SignaturePolicyIdentifier, SignatureProductionPlaceV2, and SignerRoleV2 are post-v1.

Summary

Functions

Builds the DER-encoded IssuerSerial (RFC 5035 §4) octets for a <xades:IssuerSerialV2> element. Returns the raw DER — the caller base64-encodes it for the XML element body.

Builds the full <xades:QualifyingProperties> block ready for splicing into the <ds:Object> element of a <ds:Signature>.

Splices an <xades:UnsignedProperties> block into the <xades:QualifyingProperties> produced by qualifying_properties/1. Inserts immediately before the </xades:QualifyingProperties> closing tag.

Builds the <xades:UnsignedProperties> block carrying a <xades:SignatureTimeStamp> (XAdES B-T per ETSI EN 319 132-1 §5.4.1). The TST is embedded base64-encoded as <xades:EncapsulatedTimeStamp>.

Functions

build_issuer_serial_v2_der(x509)

@spec build_issuer_serial_v2_der(SignCore.X509.t()) ::
  {:ok, binary()} | {:error, term()}

Builds the DER-encoded IssuerSerial (RFC 5035 §4) octets for a <xades:IssuerSerialV2> element. Returns the raw DER — the caller base64-encodes it for the XML element body.

ASN.1 shape

IssuerSerial ::= SEQUENCE {
    issuer       GeneralNames,
    serialNumber CertificateSerialNumber
}
GeneralNames  ::= SEQUENCE OF GeneralName
GeneralName   ::= CHOICE { ..., directoryName [4] Name, ... }

Single-element GeneralNames containing a single [4] EXPLICIT Name is the canonical encoding for an X.509 issuer.

qualifying_properties(opts)

@spec qualifying_properties(keyword()) :: {:ok, String.t()} | {:error, term()}

Builds the full <xades:QualifyingProperties> block ready for splicing into the <ds:Object> element of a <ds:Signature>.

Required:

  • :signature_id — the Id of the parent <ds:Signature>. Used as the Target attribute (`). *:signed_properties_id— theIdfor<xades:SignedProperties>. The data Reference's URI in the<ds:SignedInfo>block must point at#. *:leaf_certSignCore.X509.t()for the signing cert. Optional: *:signing_timeDateTime.t(). DefaultDateTime.utc_now/0`.

splice_unsigned_properties(qp_xml, up_block)

@spec splice_unsigned_properties(String.t(), String.t()) ::
  {:ok, String.t()} | {:error, term()}

Splices an <xades:UnsignedProperties> block into the <xades:QualifyingProperties> produced by qualifying_properties/1. Inserts immediately before the </xades:QualifyingProperties> closing tag.

unsigned_signature_timestamp(opts)

@spec unsigned_signature_timestamp(keyword()) :: {:ok, String.t()} | {:error, term()}

Builds the <xades:UnsignedProperties> block carrying a <xades:SignatureTimeStamp> (XAdES B-T per ETSI EN 319 132-1 §5.4.1). The TST is embedded base64-encoded as <xades:EncapsulatedTimeStamp>.

<xades:UnsignedProperties>
  <xades:UnsignedSignatureProperties>
    <xades:SignatureTimeStamp Id="...">
      <ds:CanonicalizationMethod Algorithm="...exc-c14n#"/>
      <xades:EncapsulatedTimeStamp>...</xades:EncapsulatedTimeStamp>
    </xades:SignatureTimeStamp>
  </xades:UnsignedSignatureProperties>
</xades:UnsignedProperties>

Note: this returns just the <xades:UnsignedProperties> block. Splice it inside the parent <xades:QualifyingProperties> after <xades:SignedProperties>.

Required opts:

  • :tst_der — RFC 3161 TimeStampToken DER (the Pkcs11ex.Audit.Anchor.RFC3161.extract_token/1 output).
  • :timestamp_idId attribute on the <xades:SignatureTimeStamp> element.