Lewati ke konten
getnextpdf.com

Enterprise edisi

Pengikatan kepercayaan ASiC

Sebuah kontainer ASiC membungkus berkas-berkas yang ditandatangani beserta tanda tangan yang melindunginya. Pertanyaan yang sulit bukanlah “apakah tanda tangannya cocok dihitung?” melainkan “siapa yang berdiri di belakang penanda tangan?”. NextPDF\Enterprise\Security\Asic\AsicTrustBinder menjawab persis pertanyaan itu. Anda menyerahkan sertifikat penanda tangan dari tanda tangan kontainer, sebuah trusted list, dan sebuah waktu validasi. Ia menjawab dengan AsicTrustBindingResult: sebuah verdict trusted/untrusted, versi anchor bundle yang menjadi dasar keputusannya, dan alasan yang machine-readable. Setiap penolakan menyebutkan penyebabnya, sehingga bukti audit menulis dirinya sendiri.

Satu batas dibuat secara sengaja dan patut dinyatakan di awal. API ini tidak mem-parsing kontainer ASiC. Tooling Anda yang membuka kontainer dan mengekstrak sertifikat penanda tangan; NextPDF yang memiliki keputusan kepercayaan.

Kapabilitas ini hadir dalam NextPDF Enterprise (nextpdf/enterprise) dan aktif dengan license envelope tingkat Enterprise. Sebuah deployment tanpa entitlement tersebut tidak memuat kelas-kelas kapabilitas ini. Bandingkan edisi dan dapatkan lisensi.

Terminal window
composer require nextpdf/enterprise

Aktivasi memerlukan license envelope Enterprise Anda. Lihat Install and authenticate. Kelas-kelas pada halaman ini berada di bawah NextPDF\Enterprise\Security\Asic dan NextPDF\Enterprise\Security\Tsl.

ASiC (Associated Signature Containers, ETSI EN 319 162-1) mengemas berkas data dan tanda tangan dalam satu arsip. Sebuah kontainer ASiC baseline menyematkan hanya tanda tangan CAdES atau XAdES baseline. Sebuah tanda tangan CAdES baseline membawa sertifikat penanda tangannya di dalam SignedData.certificates, sehingga sebuah verifier diharapkan mengekstraknya ketika tanda tangan tersebut well-formed dan didukung oleh container tooling dari tanda tangan kontainer. Sertifikat yang diekstrak itulah yang menjadi input API ini.

Sumber kepercayaan adalah sebuah trusted list (TSL) ETSI TS 119 612: sebuah dokumen XML yang ditandatangani yang menyebutkan trust service provider dan sertifikat layanan mereka. NextPDF\Enterprise\Security\Tsl\TslTrustAnchorProvider mengonversi sebuah TslDocument yang telah di-parsing menjadi sebuah anchor bundle. Hanya layanan yang berstatus granted sekaligus bertipe layanan CA/QC yang menyemai anchor set. Bundle tersebut membawa string versi yang diturunkan dari nomor urut TSL dan teritori, plus sebuah digest integritas SHA-256.

Dua gate fail-closed berjalan sebelum perbandingan anchor apa pun:

  1. Freshness TSL. Sebuah trusted list yang instan NextUpdate-nya telah lewat harus dibuang sebagai kedaluwarsa. AsicTrustBinder::verify() menegaskan freshness pada waktu validasi yang diberikan sebelum menurunkan satu anchor pun. Sebuah list yang basi, atau sebuah nilai NextUpdate tanpa penanda UTC eksplisit, melempar TslParseException.
  2. Periode validitas penanda tangan. Path validation RFC 5280 mengharuskan periode validitas sertifikat mencakup waktu validasi. Sebuah tanda tangan yang secara kriptografis utuh namun sertifikatnya telah kedaluwarsa, atau belum berlaku, pada waktu itu ditolak dengan reason code yang presisi.

Baru setelah itu binder menguji sertifikat penanda tangan terhadap setiap anchor. Sebuah kecocokan menghasilkan trusted: true dengan alasan anchor_signature_match. Tanpa kecocokan menghasilkan trusted: false dengan alasan no_anchor_chain.

Keputusan desain yang menjadi tumpuan adalah pemisahan ketat antara mekanika kontainer dan keputusan kepercayaan, dengan keputusan kepercayaan dipaksa eksplisit soal waktu. Format kontainer bervariasi (ASiC-S, ASiC-E, payload CAdES atau XAdES), tetapi pertanyaan kepercayaan adalah satu kernel invarian: apakah sertifikat ini merantai ke sebuah anchor dari trusted list yang segar pada instan yang dinyatakan? Menjaga kernel itu bebas dari parsing ZIP dan XML membuatnya cukup kecil untuk diuji secara menyeluruh dan untuk fail closed di setiap gate. Penalaran yang sama melarang default now yang senyap: waktu validasi mengubah verdict, jadi pemanggil harus memilikinya. Freshness ditegaskan di dalam jalur penurunan anchor itu sendiri, bukan di dalam kolaborator opsional, sehingga tidak ada jalur produsen yang dapat melewatinya.

Latar belakang desain: Bagaimana tanda tangan digital membuktikan siapa yang menandatangani.

Konstruksi mengambil anchor provider yang mengubah trusted list menjadi anchor bundle.

public function __construct(
private readonly TslTrustAnchorProvider $anchorProvider,
) {}

Entry point utama memverifikasi sebuah sertifikat penanda tangan terhadap sebuah trusted list:

public function verify(
string $signerCertPem,
TslDocument $tsl,
DateTimeInterface $validationTime,
): AsicTrustBindingResult
  • $signerCertPem — string PEM non-kosong: sertifikat penanda tangan dari tanda tangan ASiC.
  • $tsl — trusted list yang telah di-parsing dan terautentikasi.
  • $validationTime — instan yang harus dicakup oleh periode validitas sertifikat penanda tangan. Tidak ada default.

Melempar atau gagal dengan: NextPDF\Enterprise\Security\Tsl\TslParseException ketika TSL basi (NextUpdate telah lewat), ketika NextUpdate bukan nilai UTC kanonis, atau ketika list tidak memuat layanan CA/QC aktif. Penanda tangan yang untrusted tidak melempar; mereka mengembalikan sebuah result dengan trusted: false dan sebuah reason code.

Untuk beban kerja batch, verifikasi terhadap bundle yang telah dibangun sebelumnya:

public function verifyAgainstBundle(
string $signerCertPem,
EnterpriseCaTrustAnchorBundle $bundle,
DateTimeInterface $validationTime,
): AsicTrustBindingResult

Melempar atau gagal dengan: tidak ada exception miliknya sendiri; setiap hasil adalah sebuah AsicTrustBindingResult. Peroleh bundle dari TslTrustAnchorProvider::buildBundle() — jangan mengonstruksinya secara manual.

public function buildBundle(TslDocument $tsl, DateTimeImmutable $now): EnterpriseCaTrustAnchorBundle

Melempar atau gagal dengan: TslParseException jika TSL basi, NextUpdate-nya bukan nilai UTC kanonis, atau tidak memiliki layanan CA/QC aktif.

public function __construct(
public bool $trusted,
public string $anchorBundleVersion,
public array $reasons,
) {}

$reasons adalah sebuah list<non-empty-string> berisi kode yang machine-readable. $anchorBundleVersion mencatat anchor set yang digunakan, dalam bentuk tsl-<territory>-seq<N> (misalnya tsl-eu-seq42).

Reason codeArti
anchor_signature_matchSertifikat penanda tangan terverifikasi terhadap sebuah anchor yang diturunkan dari TSL. Trusted.
no_anchor_chainTidak ada anchor dalam bundle yang memverifikasi sertifikat penanda tangan. Untrusted.
signer_cert_expiredWaktu validasi jatuh setelah notAfter sertifikat. Untrusted.
signer_cert_not_yet_validWaktu validasi jatuh sebelum notBefore sertifikat. Untrusted.
cannot_parse_signer_certPEM yang diberikan tidak dapat di-parsing sebagai sertifikat X.509. Untrusted.

Container tooling Anda telah mengekstrak sertifikat penanda tangan. Ikat ke sebuah trusted list negara anggota yang telah Anda ambil dan autentikasi (lihat Trusted lists).

asic-trust-binding-quickstart.php
<?php
declare(strict_types=1);
require __DIR__ . '/vendor/autoload.php';
use NextPDF\Enterprise\Security\Asic\AsicTrustBinder;
use NextPDF\Enterprise\Security\Tsl\TslParseException;
use NextPDF\Enterprise\Security\Tsl\TslTrustAnchorProvider;
use NextPDF\Enterprise\Security\Tsl\TslXmlParser;
// Extracted by YOUR tooling from META-INF/signature.p7s or signatures.xml.
$signerCertPem = (string) file_get_contents(__DIR__ . '/asic-signer.pem');
// A trusted list you have already fetched and authenticated.
$tslXml = (string) file_get_contents(__DIR__ . '/member-state-tsl.xml');
$binder = new AsicTrustBinder(new TslTrustAnchorProvider());
try {
$tsl = (new TslXmlParser())->parse($tslXml);
$result = $binder->verify(
signerCertPem: $signerCertPem,
tsl: $tsl,
validationTime: new DateTimeImmutable('2026-07-03T12:00:00Z'),
);
} catch (TslParseException $e) {
// Fail closed: stale TSL, malformed NextUpdate, or no active CA/QC services.
fwrite(STDERR, 'Trusted list rejected: ' . $e->getMessage() . PHP_EOL);
exit(1);
}
echo $result->trusted ? "TRUSTED\n" : "NOT TRUSTED\n";
echo 'Anchors: ' . $result->anchorBundleVersion . "\n";
echo 'Reasons: ' . implode(', ', $result->reasons) . "\n";

Output yang diharapkan untuk sebuah penanda tangan yang diterbitkan oleh sebuah layanan CA/QC yang terdaftar:

TRUSTED
Anchors: tsl-eu-seq42
Reasons: anchor_signature_match

Turunkan anchor bundle sekali per trusted list, lalu verifikasi banyak penanda tangan kontainer terhadapnya. Satu TSL yang basi atau tak dapat dipakai membuat seluruh batch fail closed; masalah penanda tangan individual muncul per kontainer.

asic-trust-binding-batch.php
<?php
declare(strict_types=1);
require __DIR__ . '/vendor/autoload.php';
use NextPDF\Enterprise\Security\Asic\AsicTrustBinder;
use NextPDF\Enterprise\Security\Asic\AsicTrustBindingResult;
use NextPDF\Enterprise\Security\Tsl\TslDocument;
use NextPDF\Enterprise\Security\Tsl\TslParseException;
use NextPDF\Enterprise\Security\Tsl\TslTrustAnchorProvider;
use NextPDF\Enterprise\Security\Tsl\TslXmlParser;
/**
* @param array<string, non-empty-string> $signerPemsByContainer PEM per container path.
* @return array<string, AsicTrustBindingResult>
* @throws TslParseException When no anchor set can be derived from the TSL.
*/
function bindBatch(
TslDocument $tsl,
array $signerPemsByContainer,
DateTimeImmutable $validationTime,
): array {
$provider = new TslTrustAnchorProvider();
// Derive the anchor set ONCE; a throw here means the trusted list itself
// is unusable at this validation time.
$bundle = $provider->buildBundle($tsl, $validationTime);
$binder = new AsicTrustBinder($provider);
$results = [];
foreach ($signerPemsByContainer as $container => $signerPem) {
$results[$container] = $binder->verifyAgainstBundle(
signerCertPem: $signerPem,
bundle: $bundle,
validationTime: $validationTime,
);
}
return $results;
}
$tsl = (new TslXmlParser())->parse(
(string) file_get_contents(__DIR__ . '/member-state-tsl.xml'),
);
$signerPems = [
'invoice-2026-06.asice' => (string) file_get_contents(__DIR__ . '/signer-a.pem'),
'tender-2019.asice' => (string) file_get_contents(__DIR__ . '/signer-b.pem'),
];
try {
$results = bindBatch(
tsl: $tsl,
signerPemsByContainer: $signerPems,
validationTime: new DateTimeImmutable('now', new DateTimeZone('UTC')),
);
} catch (TslParseException $e) {
// Fail closed for the WHOLE batch: no trustworthy anchor set exists.
fwrite(STDERR, 'Anchor derivation failed: ' . $e->getMessage() . PHP_EOL);
exit(1);
}
foreach ($results as $container => $result) {
printf(
"%s => %s (%s; anchors %s)\n",
$container,
$result->trusted ? 'trusted' : 'rejected',
implode(',', $result->reasons),
$result->anchorBundleVersion,
);
}

Output yang diharapkan ketika satu sertifikat penanda tangan telah kedaluwarsa:

invoice-2026-06.asice => trusted (anchor_signature_match; anchors tsl-eu-seq42)
tender-2019.asice => rejected (signer_cert_expired; anchors tsl-eu-seq42)
  • Waktu validasi bersifat wajib dan menentukan. Tidak ada default now yang senyap. Sebuah tanda tangan yang terverifikasi pada 2019 melaporkan signer_cert_expired ketika Anda memvalidasi pada instan 2026 yang melewati notAfter. Untuk material historis, berikan waktu yang didukung bukti Anda (misalnya sebuah waktu proof-of-existence), bukan jam dinding.
  • Sebuah TSL basi melempar; itu bukan verdict “untrusted”. TslParseException dari verify() atau buildBundle() berarti sumber kepercayaan tak dapat dipakai. Perlakukan sebagai kegagalan operasional: segarkan list, jangan mencatatnya sebagai penolakan penanda tangan.
  • Anchor diuji sebagai issuer langsung. Setiap anchor dicoba sebagai sertifikat yang menandatangani sertifikat penanda tangan. TSL negara anggota EU mendaftarkan sertifikat layanan CA/QC penerbit, sehingga sertifikat qualified end-entity umumnya cocok secara langsung. Sebuah penanda tangan yang diterbitkan oleh CA perantara yang bukan sebuah layanan CA/QC aktif yang terdaftar menghasilkan no_anchor_chain.
  • Penurunan anchor menyaring dengan ketat. Layanan yang ditarik (withdrawn), atau bertipe apa pun selain CA/QC, tidak pernah menjadi anchor. Sebuah list yang set CA/QC aktifnya kosong melempar, alih-alih menghasilkan bundle kosong.
  • NextUpdate harus UTC kanonis. Sebuah nilai tanpa penanda Z eksplisit atau offset numerik ditolak fail-closed, tidak pernah ditafsirkan ulang dalam zona waktu lokal server.
  • Input yang malformed terdegradasi secara presisi. Sebuah PEM yang tidak dapat di-parsing mengembalikan cannot_parse_signer_cert; sebuah sertifikat yang belum berlaku dibedakan dari yang telah kedaluwarsa.
  • Catat anchorBundleVersion. Ia menyebutkan anchor set persis (tsl-<territory>-seq<N>) di balik setiap verdict, yang merupakan hal yang akan ditanyakan seorang auditor.
  • Fail-closed secara konstruksi. Freshness ditegaskan sebelum anchor apa pun diturunkan. Gate validitas penanda tangan berjalan sebelum perbandingan anchor apa pun. Material kepercayaan yang tak dapat dipakai melempar; penanda tangan yang meragukan ditolak dengan alasan. Tidak ada jalur yang terdegradasi menjadi lolos senyap.
  • Pengikatan kepercayaan adalah satu lapisan, bukan keseluruhan validasi. API ini tidak memverifikasi nilai tanda tangan CAdES atas konten kontainer, tidak memeriksa revocation (tidak ada lookup CRL atau OCSP), dan tidak mengautentikasi dokumen TSL itu sendiri. Autentikasi list melalui pipeline trusted-list terlebih dahulu (lihat Trusted lists), verifikasi tanda tangan secara kriptografis dengan signature tooling Anda, dan tambahkan pemeriksaan revocation sesuai kebijakan Anda.
  • Pilih waktu validasi secara sengaja. Verdict adalah fungsi dari waktu yang Anda berikan. Turunkan dari bukti yang tepercaya (sebuah qualified timestamp, sebuah catatan arsip), bukan dari jam yang dapat dipengaruhi penyerang.
  • Output bukti bersifat deterministik. trusted, anchorBundleVersion, dan reasons adalah nilai yang stabil dan machine-readable, cocok untuk log audit yang ditandatangani.

AsicTrustBinder mendukung alur kerja yang selaras dengan ETSI EN 319 162-1 (kontainer ASiC baseline), ETSI EN 319 122-1 (tanda tangan CAdES baseline), dan ETSI TS 119 612 (trusted list), serta menerapkan gate periode validitas RFC 5280 pada waktu validasi yang diberikan.

Dukungan bukanlah konformansi, dan konformansi bukanlah sertifikasi. NextPDF mengimplementasikan pemeriksaan yang dijelaskan halaman ini; ia belum disertifikasi terhadap standar-standar ini oleh badan mana pun, dan menggunakan API ini tidak dengan sendirinya membuat output Anda “qualified” atau sah secara hukum di bawah eIDAS atau rezim lain mana pun. NextPDF tidak memegang sertifikasi dan tidak memberikan satu pun. Apakah sebuah proses validasi lengkap memenuhi suatu persyaratan hukum atau pengadaan tertentu adalah penetapan bagi para assessor Anda.

Pengikatan kepercayaan melakukan pemeriksaan tanda tangan sertifikat X.509 secara in-process; ia tidak dialirkan melalui runtime guard mode-FIPS Enterprise, dan mengaktifkan mode FIPS tidak mengubah perilakunya. Ia bukan layanan kriptografi yang FIPS-validated, dan tidak ada sertifikasi FIPS 140 yang diklaim. Deployment dengan kewajiban FIPS sebaiknya membatasi cakupan API ini sesuai kebutuhan dan melihat FIPS 140-2/3 cryptographic policy.

  • verify() menurunkan anchor hanya dari sebuah TSL yang segar pada waktu validasi yang diberikan; sebuah list yang basi atau malformed melempar TslParseException sebelum anchor apa pun ada.
  • Anchor diturunkan secara eksklusif dari layanan TSL berstatus granted dengan tipe layanan CA/QC; sebuah set aktif yang kosong melempar.
  • Periode validitas sertifikat penanda tangan harus mencakup waktu validasi; pelanggaran mengembalikan signer_cert_expired atau signer_cert_not_yet_valid.
  • Setiap hasil adalah sebuah AsicTrustBindingResult yang membawa trusted, anchorBundleVersion, dan setidaknya satu reason code; tidak ada verdict tanpa alasan.
  • Penanda tangan yang untrusted dikembalikan, tidak pernah dilempar; material kepercayaan yang tak dapat dipakai dilempar, tidak pernah dikembalikan sebagai verdict.
  • Parsing kontainer tidak pernah terjadi di dalam API ini; input adalah PEM yang diekstrak, trusted list, dan waktu validasi.

NextPDF Core memvalidasi tanda tangan PDF (CMS/PAdES) terhadap trust anchor yang Anda pin secara eksplisit melalui kontrak CaTrustAnchorBundle-nya — lihat Core security. Core tidak memiliki ingesti trusted-list (TSL) dan tidak memiliki pengikatan kepercayaan spesifik-ASiC. Dengan Core saja, Anda dapat memelihara anchor set Anda sendiri untuk validasi tanda tangan PDF; menurunkan anchor dari sebuah trusted list ETSI TS 119 612 dan mengikat penanda tangan kontainer ASiC ke anchor tersebut memerlukan NextPDF Enterprise.

Halaman ini mendokumentasikan perilaku yang dapat diamati secara eksternal dan permukaan API publik yang didukung saja. Jalur namespace internal, kelas helper, tabel mekanisme, nama berkas runbook, dan prefiks tiket berada di luar cakupan.