跳到內容
getnextpdf.com

Enterprise 版本

ASiC trust binding — deep reference

本頁內容尚未翻譯。

This page is the deep reference for the ASiC trust binding surface in NextPDF Enterprise. It documents the supported public API, its behavior contract, its reason codes, and its failure modes. For the workflow-level guide and worked examples, see ASiC trust binding.

The surface answers one narrow question: at a stated validation time, does the signing certificate taken from an ASiC container signature parse, fall within its own validity period, and carry a signature that verifies against at least one anchor in the supplied anchor bundle? NextPDF\Enterprise\Security\Asic\AsicTrustBinder exposes two public methods, verify() and verifyAgainstBundle(), and both assert the Enterprise capability enterprise.signatures.batch_validate. verify() takes the signer PEM, a TslDocument, and a validation time, and derives an anchor bundle from that trusted list through NextPDF\Enterprise\Security\Tsl\TslTrustAnchorProvider::buildBundle(); verifyAgainstBundle() takes the signer PEM, a pre-built EnterpriseCaTrustAnchorBundle, and a validation time. Each returns an AsicTrustBindingResult — a trusted/untrusted verdict, the anchor bundle version it decided against, and machine-readable reason codes. buildBundle() raises NextPDF\Enterprise\Security\Tsl\TslParseException when the trusted list is not fresh or its granted CA/QC set is empty.

One boundary is deliberate. This API does not parse ASiC containers: its inputs are the already-extracted signer PEM, the trusted list (or a pre-built bundle), and the validation time. Your tooling opens the container, walks its META-INF manifests, and extracts the signing certificate before calling this API.

trusted = true is a bounded statement about three checks: the signer certificate parsed, its validity period included the supplied validation time, and its signature verified against at least one anchor in the bundle when that anchor was loaded on its own as the candidate issuer. Everything else is out of scope for this call, as an observed property of the code:

  • The binder loads no intermediate certificates and assembles no certificate path — each anchor is tried singly, and a bundle with no matching anchor yields no_anchor_chain.
  • It performs no revocation lookup: there is no CRL or OCSP call in the binder or in its anchor-derivation path.
  • It does not verify the ASiC/CAdES/XAdES content signature over the container — its only cryptographic input is the signer certificate, not the signed data. Validate the signature value with Signature verification.
  • It produces no qualification or legal-effect classification of the signer: the result object carries only a trusted flag, the anchor bundle version, and reason codes.

Both public entry points, verify() and verifyAgainstBundle(), begin by asserting the Enterprise capability code enterprise.signatures.batch_validate (CapabilityCode::EnterpriseSignaturesBatchValidate); TslTrustAnchorProvider::buildBundle() asserts the same capability before deriving any anchor. The classes documented here live under the NextPDF\Enterprise\Security\Asic and NextPDF\Enterprise\Security\Tsl namespaces. Compare editions.

SymbolParametersBehaviorReturnsThrowsNotes
AsicTrustBinder::verifystring $signerCertPem, TslDocument $tsl, DateTimeInterface $validationTimeAsserts the capability and verifies the signer against an anchor bundle derived from the supplied TSL via buildBundle()AsicTrustBindingResultTslParseException when the TSL is not fresh (stale or non-canonical NextUpdate) or its granted CA/QC set is emptyThe validation time is an explicit parameter with no default
AsicTrustBinder::verifyAgainstBundlestring $signerCertPem, EnterpriseCaTrustAnchorBundle $bundle, DateTimeInterface $validationTimeAsserts the capability and verifies the signer against the supplied bundleAsicTrustBindingResultNot specified hereConstruct the bundle via TslTrustAnchorProvider::buildBundle
AsicTrustBindingResult::__constructbool $trusted, string $anchorBundleVersion, array $reasonsImmutable verdict value objectNot specified herefinal readonly; $reasons is list<non-empty-string>; all three properties are public
TslTrustAnchorProvider::buildBundleTslDocument $tsl, DateTimeImmutable $nowAsserts TSL freshness and filters to granted CA/QC services; produces a bundle versioned tsl-<territory>-seq<N>EnterpriseCaTrustAnchorBundleTslParseException (stale, non-canonical NextUpdate, or empty granted CA/QC set)Produces the anchor bundle verify() decides against
EnterpriseCaTrustAnchorBundle::__constructarray $anchorsPem, string $bundleVersion, string $bundleSha256Validates the 64-hex digest and each PEM, then hash_equals the supplied digest against the one recomputed over the canonicalised anchorsInvalidArgumentException (digest not 64-hex, a non-PEM entry, or digest mismatch)Prefer buildBundle over hand construction
EnterpriseCaTrustAnchorBundle::computeBundleSha256array $anchorsPemProduces the SHA-256 digest the bundle constructor validatesnon-empty-string (hex SHA-256)Not specified hereStatic helper
EnterpriseCaTrustAnchorBundle::containsFingerprintstring $anchorDerSha256HexReturns whether the supplied hex string equals one of the bundle’s per-anchor SHA-256 digests, each computed over that anchor’s DER bodyboolNot specified hereMembership test, not signature verification

The Throws column records exception paths visible in the source and is not exhaustive: Not specified here means this page does not enumerate an exception for that row; it is not a no-throw guarantee. For example, the capability assertion at each entry point can reject an unlicensed caller.

public function verify(
string $signerCertPem,
TslDocument $tsl,
DateTimeInterface $validationTime,
): AsicTrustBindingResult
public function verifyAgainstBundle(
string $signerCertPem,
EnterpriseCaTrustAnchorBundle $bundle,
DateTimeInterface $validationTime,
): AsicTrustBindingResult
final readonly class AsicTrustBindingResult
{
public function __construct(
public bool $trusted,
public string $anchorBundleVersion,
public array $reasons,
) {}
}
public function buildBundle(
TslDocument $tsl,
DateTimeImmutable $now,
): EnterpriseCaTrustAnchorBundle

AsicTrustBindingResult::$reasons is a list<non-empty-string> of machine-readable codes.

Reason codeVerdictMeaning
anchor_signature_matchtrustedThe signer certificate verifies against an anchor in the supplied bundle.
no_anchor_chainuntrustedNo anchor in the bundle verifies the signer certificate.
signer_cert_expireduntrustedThe validation time falls after the certificate’s notAfter.
signer_cert_not_yet_validuntrustedThe validation time falls before the certificate’s notBefore.
cannot_parse_signer_certuntrustedThe supplied PEM does not load as an X.509 certificate.

$anchorBundleVersion records the bundle version label used for the decision; the binder copies it from the bundle it decided against. For a bundle produced by TslTrustAnchorProvider::buildBundle(), this label has the form tsl-<territory>-seq<N> (for example tsl-eu-seq42); for a bundle you construct directly, it is the bundleVersion string passed to the constructor.

  • Capability. Both verify() and verifyAgainstBundle() assert the enterprise.signatures.batch_validate capability.
  • TSL freshness. verify() derives its anchor bundle from the supplied trusted list through buildBundle(), which asserts the list is fresh. A list whose NextUpdate has passed, or whose NextUpdate is not a canonical UTC value, raises TslParseException.
  • Anchor derivation. buildBundle() filters the trusted list to services that are both in granted status (STATUS_GRANTED) and of the CA/QC service type (TYPE_CA_QC). A list whose granted CA/QC set is empty raises TslParseException rather than yielding an empty bundle.
  • Bundle version and integrity. A bundle produced by buildBundle() is versioned tsl-<territory>-seq<N>. The constructor recomputes a SHA-256 over the canonicalised anchor PEMs and hash_equals it against the supplied bundleSha256, throwing InvalidArgumentException on a mismatch; EnterpriseCaTrustAnchorBundle::computeBundleSha256() produces exactly the digest that check validates.
  • Signer parsing. The signer PEM is parsed once with phpseclib’s X.509 parser. A PEM that does not load yields cannot_parse_signer_cert.
  • Validity check. The signer certificate’s validity period must include the validation time; validateDate distinguishes a not-yet-valid signer (signer_cert_not_yet_valid) from an expired one (signer_cert_expired).
  • Anchor verification. Each anchor in the bundle is loaded on its own as a fresh candidate CA (loadCA) and the signer certificate’s signature is checked against it (validateSignature); a matching anchor yields anchor_signature_match, and a bundle with no matching anchor yields no_anchor_chain. The binder loads no intermediate certificates and assembles no multi-certificate path.
  • Exceptions and verdicts. A signer problem is reported as an AsicTrustBindingResult carrying a reason code, not by throwing. Two exception paths are visible in the source: TslParseException from buildBundle() (a non-fresh list, a non-canonical NextUpdate, or an empty granted CA/QC set) and InvalidArgumentException from the EnterpriseCaTrustAnchorBundle constructor (a digest that is not 64-hex, a non-PEM entry, or a digest that does not match the anchor set). This list is not exhaustive — the capability assertion, for instance, can reject an unlicensed caller.
  • Container parsing. The inputs are the extracted signer PEM, the trusted list (or a pre-built bundle), and the validation time; container parsing is the caller’s responsibility. A CAdES baseline generator places the signing certificate in SignedData.certificates, so your container tooling can extract it.
  • Validation time is mandatory. There is no silent now default; the caller passes the validation time, and validateDate compares the signer certificate’s validity period against it. A signer that passed at one instant reports signer_cert_expired when validated at a later instant past notAfter, and signer_cert_not_yet_valid before notBefore.
  • A stale TSL raises TslParseException. TslParseException from verify() or buildBundle() signals that the trust source is unusable. Treat it as an operational failure — refresh the list — not as a signer rejection.
  • NextUpdate must be canonical UTC. A non-canonical value raises TslParseException.
  • Empty granted CA/QC set. A list whose granted CA/QC services are all filtered out raises TslParseException rather than producing an empty bundle.
  • Malformed signer input. A PEM that does not parse returns cannot_parse_signer_cert; a not-yet-valid certificate is distinguished from an expired one.
  • Hand-built bundles. Constructing EnterpriseCaTrustAnchorBundle directly with a digest that is not 64-hex, a non-PEM entry, or a digest that does not match the anchor set raises InvalidArgumentException. Prefer buildBundle(), which computes a matching digest for the anchors it extracts.
  • A fresh, validated TSL is a precondition. Pass a trusted list that has already been validated through the trusted-list pipeline (see Trusted lists).
  • This is one layer, not the whole validation. The binder performs no revocation lookup (no CRL or OCSP call) and does not verify the CAdES/XAdES signature value over the container content. Verify the signature cryptographically with your signature tooling and add revocation checking per your policy.
ClaimStandardClause
An ASiC-E container associates data files with signature files, each carrying CAdES or XAdES signatures over its own file set.ETSI EN 319 162-1§4.4.1
A validation application identifies the signature reference file from each ASiCManifest; container parsing precedes this API.ETSI EN 319 162-1§4.4.4.2
A CAdES baseline generator includes the signing certificate in SignedData.certificates, so a verifier can extract it.ETSI EN 319 122-1Clause 6
A trusted list whose Next update instant has passed is expired and is discarded.ETSI TS 119 612§5.3.15
The CA/QC service-type URI identifies trust services issuing qualified certificates; only these seed the anchor set.ETSI TS 119 612§5.5.9.1
Signature validation validates the signing certificate at the validation time, which is an explicit input.ETSI EN 319 102-1§5.2.6.1
Whether the validation time falls within the signing certificate’s validity period is a distinct validation step.ETSI EN 319 102-1§5.2.6.2
Path validation requires the certificate validity period to include the time being tested.RFC 5280§6.1.3
The validity period runs from notBefore through notAfter inclusive, distinguishing not-yet-valid from expired.RFC 5280§4.1.2.5

All clauses are paraphrased; NextPDF does not reproduce normative text. Support is not conformance, and conformance is not certification. NextPDF implements the checks this page describes; using this API does not by itself make your output “qualified” or legally effective under eIDAS or any other regime. Whether a complete validation process meets a given legal or procurement requirement is a determination for your assessors.

  • AsicTrustBindingResult is a final readonly value object. Construct results directly in unit tests; build bundles through buildBundle() or derive their digest with the static EnterpriseCaTrustAnchorBundle::computeBundleSha256() helper so the digest is consistent.
  • verify() derives an anchor bundle from the TSL it is given via buildBundle(); verifyAgainstBundle() takes an already-built bundle instead.
  • Recommended boundary tests: a signer issued by a listed anchor (trusted), a signer under an unlisted issuer (no_anchor_chain), a malformed signer PEM (cannot_parse_signer_cert), a validation time past notAfter (signer_cert_expired) and before notBefore (signer_cert_not_yet_valid), and a stale trusted list (TslParseException).
  • The caller supplies the validation time; validateDate compares the signer certificate’s validity period against that time. The binder does not determine whether a timestamp is qualified or otherwise trustworthy — that determination is the caller’s responsibility.

This page documents externally observable behavior and the supported public API surface only. Internal namespace paths beyond the published entry points, helper classes, mechanism tables, runbook filenames, and ticket prefixes are out of scope.