İçeriğe geç
getnextpdf.com

Enterprise sürüm

ASiC güven bağlama

Bir ASiC konteyneri, imzalanmış dosyaları onları koruyan imzalarla bir araya getirir. Zor soru “imza hesaplanıyor mu?” değil, “imzalayanın arkasında kim duruyor?” sorusudur. NextPDF\Enterprise\Security\Asic\AsicTrustBinder tam olarak bu soruyu yanıtlar. Ona konteyner imzasından gelen imzalama sertifikasını, bir güvenilen listeyi ve bir doğrulama zamanını verirsiniz. O da bir AsicTrustBindingResult ile yanıt verir: güvenilir/güvenilmez bir karar, karar verdiği çıpa paketi sürümü ve makinece okunabilir gerekçeler. Her ret kendi nedenini adlandırır, böylece denetim kanıtı kendini yazar.

Bir sınır bilinçlidir ve baştan söylenmeye değerdir. Bu API, ASiC konteynerlerini ayrıştırmaz. Konteyneri açan ve imzalama sertifikasını çıkaran sizin araçlarınızdır; güven kararı NextPDF’e aittir.

Bu yetenek NextPDF Enterprise (nextpdf/enterprise) içinde gelir ve bir Enterprise katmanı lisans zarfı ile etkinleşir. Bu yetkilendirme olmadan bir dağıtım, yeteneğin sınıflarını yüklemez. Sürümleri karşılaştırın ve bir lisans edinin.

Terminal window
composer require nextpdf/enterprise

Etkinleştirme, Enterprise lisans zarfınızı gerektirir. Bkz. Kurulum ve kimlik doğrulama. Bu sayfadaki sınıflar NextPDF\Enterprise\Security\Asic ve NextPDF\Enterprise\Security\Tsl altında yer alır.

ASiC (Associated Signature Containers, ETSI EN 319 162-1) veri dosyalarını ve imzaları tek bir arşivde paketler. Bir baseline ASiC konteyneri yalnızca CAdES veya XAdES baseline imzaları gömer. Bir CAdES baseline imzası imzalama sertifikasını SignedData.certificates içinde taşır, bu nedenle bir doğrulayıcının, imza iyi biçimli olduğunda ve konteyner araçları tarafından destekleniyorsa bunu konteynerin imzasından çıkarması beklenir. Çıkarılan bu sertifika, bu API’nin girdisidir.

Güven kaynağı bir ETSI TS 119 612 güvenilen listesidir (TSL): güven hizmeti sağlayıcılarını ve onların hizmet sertifikalarını sıralayan, imzalanmış bir XML belgesi. NextPDF\Enterprise\Security\Tsl\TslTrustAnchorProvider, ayrıştırılmış bir TslDocument’i bir çıpa paketine dönüştürür. Yalnızca hem granted durumunda hem de CA/QC hizmet türünde olan hizmetler çıpa kümesini besler. Paket, TSL sıra numarası ve bölgeden türetilen bir sürüm dizesini artı bir SHA-256 bütünlük özetini taşır.

Herhangi bir çıpa karşılaştırmasından önce iki fail-closed geçit çalışır:

  1. TSL tazeliği. NextUpdate anı geçmiş bir güvenilen liste, süresi dolmuş olarak atılmalıdır. AsicTrustBinder::verify(), tek bir çıpa türetmeden önce, sağlanan doğrulama zamanında tazeliği doğrular. Bayat bir liste ya da açık bir UTC belirteci olmayan bir NextUpdate değeri TslParseException fırlatır.
  2. İmzalayan geçerlilik süresi. RFC 5280 yol doğrulaması, sertifika geçerlilik süresinin doğrulama zamanını içermesini gerektirir. O zamanda sertifikası süresi dolmuş ya da henüz geçerli olmayan, kriptografik açıdan sağlam bir imza, kesin bir gerekçe koduyla reddedilir.

Ancak o zaman bağlayıcı, imzalama sertifikasını her çıpaya karşı sınar. Bir eşleşme, anchor_signature_match gerekçesiyle trusted: true verir. Eşleşme olmaması, no_anchor_chain gerekçesiyle trusted: false verir.

Yük taşıyan tasarım kararı, konteyner mekaniği ile güven kararı arasında sıkı bir ayrımdır ve güven kararı zaman konusunda açık olmaya zorlanır. Konteyner biçimleri değişir (ASiC-S, ASiC-E, CAdES veya XAdES yükleri), ama güven sorusu tek bir değişmez çekirdektir: bu sertifika, belirtilen bir anda taze bir güvenilen listeden gelen bir çıpaya zincirleniyor mu? Bu çekirdeği ZIP ve XML ayrıştırmasından uzak tutmak, onu kapsamlı biçimde test edilebilecek ve her geçitte fail-closed olacak kadar küçük tutar. Aynı mantık sessiz bir now varsayılanını yasaklar: doğrulama zamanı kararı değiştirir, bu yüzden çağıran ona sahip olmalıdır. Tazelik, isteğe bağlı bir işbirlikçide değil, çıpa türetme yolunun kendi içinde doğrulanır, böylece hiçbir üretici yol onu atlayamaz.

Tasarım arka planı: Dijital imza imzalayanın kim olduğunu nasıl kanıtlar.

Yapı, güvenilen listeleri çıpa paketlerine dönüştüren çıpa sağlayıcısını alır.

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

Birincil giriş noktası, bir imzalayan sertifikasını bir güvenilen listeye karşı doğrular:

public function verify(
string $signerCertPem,
TslDocument $tsl,
DateTimeInterface $validationTime,
): AsicTrustBindingResult
  • $signerCertPem — boş olmayan PEM dizesi: ASiC imzasından gelen imzalama sertifikası.
  • $tsl — ayrıştırılmış, kimliği kanıtlanmış güvenilen liste.
  • $validationTime — imzalayan sertifikasının geçerlilik süresinin içermesi gereken an. Varsayılan yoktur.

Şununla fırlatır ya da başarısız olur: TSL bayat olduğunda (NextUpdate geçmiş), NextUpdate kanonik bir UTC değeri olmadığında ya da liste hiç etkin CA/QC hizmeti içermediğinde NextPDF\Enterprise\Security\Tsl\TslParseException. Güvenilmez imzalayanlar fırlatmaz; trusted: false ve bir gerekçe kodu ile bir sonuç döndürürler.

Toplu iş yükleri için, önceden oluşturulmuş bir pakete karşı doğrulayın:

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

Şununla fırlatır ya da başarısız olur: kendine ait bir istisna yok; her sonuç bir AsicTrustBindingResult’tur. Paketi TslTrustAnchorProvider::buildBundle()’dan edinin — onu elle oluşturmayın.

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

Şununla fırlatır ya da başarısız olur: TSL bayatsa, NextUpdate değeri kanonik bir UTC değeri değilse ya da hiç etkin CA/QC hizmeti yoksa TslParseException.

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

$reasons, makinece okunabilir kodların bir list<non-empty-string>’idir. $anchorBundleVersion, kullanılan çıpa kümesini tsl-<territory>-seq<N> biçiminde kaydeder (örneğin tsl-eu-seq42).

Gerekçe koduAnlamı
anchor_signature_matchİmzalayan sertifikası, TSL türevli bir çıpaya karşı doğrulanır. Güvenilir.
no_anchor_chainPakette imzalayan sertifikasını doğrulayan hiçbir çıpa yok. Güvenilmez.
signer_cert_expiredDoğrulama zamanı sertifikanın notAfter değerinden sonraya düşer. Güvenilmez.
signer_cert_not_yet_validDoğrulama zamanı sertifikanın notBefore değerinden önceye düşer. Güvenilmez.
cannot_parse_signer_certSağlanan PEM, X.509 sertifikası olarak ayrıştırılamıyor. Güvenilmez.

Konteyner araçlarınız imzalama sertifikasını zaten çıkardı. Onu, getirip kimliğini kanıtladığınız bir üye devlet güvenilen listesine bağlayın (bkz. Güvenilen listeler).

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";

Listelenmiş bir CA/QC hizmeti tarafından verilen bir imzalayan için beklenen çıktı:

TRUSTED
Anchors: tsl-eu-seq42
Reasons: anchor_signature_match

Çıpa paketini güvenilen liste başına bir kez türetin, sonra birçok konteyner imzalayanını ona karşı doğrulayın. Bayat ya da kullanılamaz tek bir TSL, tüm partiyi fail-closed başarısız kılar; bireysel imzalayan sorunları konteyner başına ortaya çıkar.

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,
);
}

Bir imzalayan sertifikasının süresi dolmuş olduğunda beklenen çıktı:

invoice-2026-06.asice => trusted (anchor_signature_match; anchors tsl-eu-seq42)
tender-2019.asice => rejected (signer_cert_expired; anchors tsl-eu-seq42)
  • Doğrulama zamanı zorunludur ve belirleyicidir. Sessiz bir now varsayılanı yoktur. 2019’da doğrulanan bir imza, notAfter değerini geçmiş bir 2026 anında doğruladığınızda signer_cert_expired bildirir. Tarihsel materyaller için, duvar saatini değil, kanıtınızın desteklediği zamanı (örneğin bir varlık-kanıtı zamanını) geçirin.
  • Bayat bir TSL fırlatır; o bir “güvenilmez” kararı değildir. verify() ya da buildBundle()’dan gelen TslParseException, güven kaynağının kullanılamaz olduğu anlamına gelir. Bunu bir işletimsel başarısızlık olarak ele alın: listeyi yenileyin, onu bir imzalayan reddi olarak kaydetmeyin.
  • Çıpalar doğrudan verici olarak sınanır. Her çıpa, imzalayan sertifikasını imzalayan sertifika olarak denenir. AB üye devlet TSL’leri verici CA/QC hizmet sertifikalarını listeler, bu nedenle son varlık nitelikli sertifikaları tipik olarak doğrudan eşleşir. Kendisi listelenmiş etkin bir CA/QC hizmeti olmayan bir ara CA tarafından verilen bir imzalayan, no_anchor_chain verir.
  • Çıpa türetme sert filtreler. Geri çekilmiş ya da CA/QC dışında herhangi bir türde olan hizmetler asla çıpa olmaz. Etkin CA/QC kümesi boş olan bir liste, boş bir paket üretmek yerine fırlatır.
  • NextUpdate kanonik UTC olmalıdır. Açık bir Z ya da sayısal ofset belirteci olmayan bir değer, sunucunun yerel saat diliminde asla yeniden yorumlanmadan fail-closed reddedilir.
  • Hatalı biçimli girdi kesin biçimde azalır. Ayrıştırılamayan bir PEM cannot_parse_signer_cert döndürür; henüz geçerli olmayan bir sertifika, süresi dolmuş olandan ayırt edilir.
  • anchorBundleVersion’ı kaydedin. O, her kararın arkasındaki tam çıpa kümesini (tsl-<territory>-seq<N>) adlandırır ki bir denetçinin isteyeceği şey budur.
  • Yapı gereği fail-closed. Tazelik, herhangi bir çıpa türetilmeden önce doğrulanır. İmzalayan geçerlilik geçidi, herhangi bir çıpa karşılaştırmasından önce çalışır. Kullanılamaz güven materyali fırlatır; şüpheli imzalayanlar gerekçelerle reddedilir. Hiçbir yol sessiz bir geçişe indirgenmez.
  • Güven bağlama tek bir katmandır, tüm doğrulama değildir. Bu API, CAdES imza değerini konteyner içeriği üzerinden doğrulamaz, iptali kontrol etmez (CRL ya da OCSP araması yok) ve TSL belgesinin kendisinin kimliğini kanıtlamaz. Listeyi önce güvenilen liste ardışık düzeni aracılığıyla kimliğini kanıtlayın (bkz. Güvenilen listeler), imzayı kriptografik olarak imza araçlarınızla doğrulayın ve politikanıza göre iptal kontrolü ekleyin.
  • Doğrulama zamanını bilinçli seçin. Karar, geçirdiğiniz zamanın bir fonksiyonudur. Onu, saldırganın etkileyebileceği bir saatten değil, güvenilir kanıttan (nitelikli bir zaman damgası, arşivsel bir kayıt) türetin.
  • Kanıt çıktıları deterministiktir. trusted, anchorBundleVersion ve reasons, imzalı denetim günlükleri için uygun, kararlı, makinece okunabilir değerlerdir.

AsicTrustBinder, ETSI EN 319 162-1 (ASiC baseline konteynerleri), ETSI EN 319 122-1 (CAdES baseline imzaları) ve ETSI TS 119 612 (güvenilen listeler) ile hizalanmış iş akışlarını destekler ve sağlanan doğrulama zamanında RFC 5280 geçerlilik süresi geçidini uygular.

Destek uygunluk değildir ve uygunluk sertifikasyon değildir. NextPDF, bu sayfanın açıkladığı kontrolleri uygular; herhangi bir kuruluş tarafından bu standartlara karşı sertifikalandırılmamıştır ve bu API’yi kullanmak tek başına çıktınızı eIDAS ya da başka bir rejim altında “nitelikli” veya yasal olarak etkili kılmaz. NextPDF hiçbir sertifikasyona sahip değildir ve hiçbirini vermez. Tam bir doğrulama sürecinin belirli bir yasal ya da tedarik gereksinimini karşılayıp karşılamadığı, değerlendiricileriniz için bir belirlemedir.

Güven bağlama, X.509 sertifika imzası kontrollerini süreç içinde gerçekleştirir; Enterprise FIPS modu çalışma zamanı korumasından geçirilmez ve FIPS modunu etkinleştirmek onun davranışını değiştirmez. O bir FIPS doğrulamalı kriptografik hizmet değildir ve hiçbir FIPS 140 sertifikasyonu iddia edilmez. FIPS yükümlülükleri olan dağıtımlar bu API’yi buna göre kapsamlandırmalı ve FIPS 140-2/3 kriptografik politikası’na bakmalıdır.

  • verify(), çıpaları yalnızca sağlanan doğrulama zamanında taze olan bir TSL’den türetir; bayat ya da hatalı biçimli bir liste, herhangi bir çıpa var olmadan önce TslParseException fırlatır.
  • Çıpalar yalnızca granted durumunda ve CA/QC hizmet türündeki TSL hizmetlerinden türetilir; boş bir etkin küme fırlatır.
  • İmzalayan sertifikasının geçerlilik süresi doğrulama zamanını içermelidir; ihlaller signer_cert_expired ya da signer_cert_not_yet_valid döndürür.
  • Her sonuç, trusted, anchorBundleVersion ve en az bir gerekçe kodu taşıyan bir AsicTrustBindingResult’tur; gerekçesiz karar yoktur.
  • Güvenilmez imzalayanlar döndürülür, asla fırlatılmaz; kullanılamaz güven materyali fırlatılır, asla bir karar olarak döndürülmez.
  • Konteyner ayrıştırma bu API’nin içinde asla gerçekleşmez; girdiler çıkarılan PEM, güvenilen liste ve doğrulama zamanıdır.

NextPDF Core, PDF (CMS/PAdES) imzalarını, CaTrustAnchorBundle sözleşmesi aracılığıyla açıkça sabitlediğiniz güven çıpalarına karşı doğrular — bkz. Core güvenlik. Core’da güvenilen liste (TSL) alımı ve ASiC’ye özgü güven bağlama yoktur. Yalnızca Core ile, PDF imza doğrulaması için kendi çıpa kümenizi tutabilirsiniz; çıpaları bir ETSI TS 119 612 güvenilen listesinden türetmek ve ASiC konteyner imzalayanlarını onlara bağlamak NextPDF Enterprise gerektirir.

Bu sayfa yalnızca dışarıdan gözlemlenebilir davranışı ve desteklenen genel API yüzeyini belgeler. Dahili ad alanı yolları, yardımcı sınıflar, mekanizma tabloları, runbook dosya adları ve bilet önekleri kapsam dışıdır.