Enterprise phiên bản
Ràng buộc tin cậy ASiC
Nhìn tổng quan
Phần tiêu đề “Nhìn tổng quan”Một container ASiC gói các tệp đã ký cùng với những chữ ký bảo vệ chúng. Câu hỏi khó không phải là “chữ ký có tính đúng không?” mà là “ai đứng sau người ký?”. NextPDF\Enterprise\Security\Asic\AsicTrustBinder trả lời chính xác câu hỏi đó. Bạn đưa cho nó chứng chỉ ký lấy từ chữ ký container, một trusted list, và một thời điểm xác thực. Nó trả lời bằng một AsicTrustBindingResult: một phán quyết tin cậy/không tin cậy, phiên bản anchor bundle mà nó đã căn cứ vào, và các lý do máy đọc được. Mỗi lần từ chối đều nêu tên nguyên nhân, nên bằng chứng kiểm toán tự nó được viết ra.
Có một ranh giới cố tình đặt ra, đáng nêu rõ ngay từ đầu. API này không phân tích các container ASiC. Công cụ của bạn mở container và trích xuất chứng chỉ ký; NextPDF sở hữu quyết định tin cậy.
Tình trạng sẵn có & cấp phép
Phần tiêu đề “Tình trạng sẵn có & cấp phép”Khả năng này được cung cấp trong NextPDF Enterprise (nextpdf/enterprise) và kích hoạt bằng một license envelope hạng Enterprise. Một triển khai không có quyền đó sẽ không nạp các lớp của khả năng này. So sánh các phiên bản và lấy giấy phép.
Cài đặt
Phần tiêu đề “Cài đặt”composer require nextpdf/enterpriseViệc kích hoạt yêu cầu license envelope Enterprise của bạn. Xem Cài đặt và xác thực. Các lớp trên trang này nằm dưới NextPDF\Enterprise\Security\Asic và NextPDF\Enterprise\Security\Tsl.
Tổng quan khái niệm
Phần tiêu đề “Tổng quan khái niệm”ASiC (Associated Signature Containers, ETSI EN 319 162-1) đóng gói các tệp dữ liệu và chữ ký trong một kho lưu trữ. Một container ASiC baseline chỉ nhúng chữ ký CAdES hoặc XAdES baseline. Một chữ ký CAdES baseline mang chứng chỉ ký của nó bên trong SignedData.certificates, nên bên xác minh được kỳ vọng sẽ trích xuất nó khi chữ ký đúng định dạng và được công cụ container hỗ trợ, từ chữ ký của container. Chứng chỉ được trích xuất đó là đầu vào của API này.
Nguồn tin cậy là một trusted list (TSL) ETSI TS 119 612: một tài liệu XML đã ký liệt kê các nhà cung cấp dịch vụ tin cậy và các chứng chỉ dịch vụ của họ. NextPDF\Enterprise\Security\Tsl\TslTrustAnchorProvider chuyển một TslDocument đã phân tích thành một anchor bundle. Chỉ những dịch vụ vừa ở trạng thái granted vừa thuộc loại dịch vụ CA/QC mới gieo vào tập anchor. Bundle mang một chuỗi phiên bản suy ra từ số thứ tự (sequence number) và lãnh thổ của TSL, cùng một digest toàn vẹn SHA-256.
Hai cổng fail-closed chạy trước bất kỳ so sánh anchor nào:
- Độ mới của TSL. Một trusted list có thời điểm
NextUpdateđã trôi qua phải bị loại bỏ vì đã hết hạn.AsicTrustBinder::verify()khẳng định độ mới tại thời điểm xác thực được cung cấp trước khi suy ra bất kỳ anchor nào. Một danh sách cũ, hoặc một giá trịNextUpdatekhông có ký hiệu chỉ định UTC tường minh, sẽ némTslParseException. - Khoảng hiệu lực của người ký. Xác thực đường dẫn theo RFC 5280 yêu cầu khoảng hiệu lực của chứng chỉ phải bao gồm thời điểm xác thực. Một chữ ký nguyên vẹn về mặt mật mã nhưng chứng chỉ của nó đã hết hạn, hoặc chưa có hiệu lực, tại thời điểm đó sẽ bị từ chối với một mã lý do chính xác.
Chỉ khi đó binder mới kiểm tra chứng chỉ ký so với từng anchor. Một kết quả khớp cho trusted: true với lý do anchor_signature_match. Không có kết quả khớp cho trusted: false với lý do no_anchor_chain.
Vì sao nó hoạt động theo cách này
Phần tiêu đề “Vì sao nó hoạt động theo cách này”Quyết định thiết kế chịu lực là sự tách bạch nghiêm ngặt giữa cơ chế container và quyết định tin cậy, với quyết định tin cậy buộc phải tường minh về thời gian. Các định dạng container khác nhau (ASiC-S, ASiC-E, tải trọng CAdES hoặc XAdES), nhưng câu hỏi tin cậy là một hạt nhân bất biến: chứng chỉ này có móc nối tới một anchor từ một trusted list mới tại một thời điểm được nêu hay không? Giữ hạt nhân đó tách khỏi việc phân tích ZIP và XML giữ nó đủ nhỏ để kiểm thử vét cạn và để fail-closed tại mọi cổng. Cùng lập luận đó cấm một giá trị mặc định now ngầm: thời điểm xác thực làm thay đổi phán quyết, nên bên gọi phải sở hữu nó. Độ mới được khẳng định ngay bên trong chính đường dẫn suy ra anchor, không phải trong một collaborator tùy chọn, nên không đường dẫn tạo ra nào có thể bỏ qua nó.
Bối cảnh thiết kế: Chữ ký số chứng minh ai đã ký như thế nào.
Bề mặt API
Phần tiêu đề “Bề mặt API”AsicTrustBinder
Phần tiêu đề “AsicTrustBinder”Việc khởi tạo nhận anchor provider biến các trusted list thành các anchor bundle.
public function __construct( private readonly TslTrustAnchorProvider $anchorProvider,) {}Điểm vào chính xác minh một chứng chỉ người ký so với một trusted list:
public function verify( string $signerCertPem, TslDocument $tsl, DateTimeInterface $validationTime,): AsicTrustBindingResult$signerCertPem— chuỗi PEM không rỗng: chứng chỉ ký từ chữ ký ASiC.$tsl— trusted list đã phân tích và đã xác thực.$validationTime— thời điểm mà khoảng hiệu lực của chứng chỉ người ký phải bao gồm. Không có giá trị mặc định.
Ném hoặc thất bại với: NextPDF\Enterprise\Security\Tsl\TslParseException khi TSL đã cũ (NextUpdate đã trôi qua), khi NextUpdate không phải là một giá trị UTC chuẩn tắc, hoặc khi danh sách không chứa dịch vụ CA/QC đang hoạt động nào. Người ký không tin cậy không ném; chúng trả về một kết quả với trusted: false và một mã lý do.
Đối với khối lượng công việc theo lô, hãy xác minh so với một bundle đã dựng sẵn:
public function verifyAgainstBundle( string $signerCertPem, EnterpriseCaTrustAnchorBundle $bundle, DateTimeInterface $validationTime,): AsicTrustBindingResultNém hoặc thất bại với: không có ngoại lệ của riêng nó; mọi kết cục đều là một AsicTrustBindingResult. Lấy bundle từ TslTrustAnchorProvider::buildBundle() — đừng tự tay dựng nó.
TslTrustAnchorProvider
Phần tiêu đề “TslTrustAnchorProvider”public function buildBundle(TslDocument $tsl, DateTimeImmutable $now): EnterpriseCaTrustAnchorBundleNém hoặc thất bại với: TslParseException nếu TSL đã cũ, NextUpdate của nó không phải là một giá trị UTC chuẩn tắc, hoặc nó không có dịch vụ CA/QC đang hoạt động nào.
AsicTrustBindingResult
Phần tiêu đề “AsicTrustBindingResult”public function __construct( public bool $trusted, public string $anchorBundleVersion, public array $reasons,) {}$reasons là một list<non-empty-string> gồm các mã máy đọc được. $anchorBundleVersion ghi lại tập anchor đã dùng, ở dạng tsl-<territory>-seq<N> (ví dụ tsl-eu-seq42).
| Mã lý do | Ý nghĩa |
|---|---|
anchor_signature_match | Chứng chỉ người ký xác minh được so với một anchor suy ra từ TSL. Tin cậy. |
no_anchor_chain | Không có anchor nào trong bundle xác minh được chứng chỉ người ký. Không tin cậy. |
signer_cert_expired | Thời điểm xác thực nằm sau notAfter của chứng chỉ. Không tin cậy. |
signer_cert_not_yet_valid | Thời điểm xác thực nằm trước notBefore của chứng chỉ. Không tin cậy. |
cannot_parse_signer_cert | PEM được cung cấp không phân tích được thành một chứng chỉ X.509. Không tin cậy. |
Ví dụ mã — Bắt đầu nhanh
Phần tiêu đề “Ví dụ mã — Bắt đầu nhanh”Công cụ container của bạn đã trích xuất chứng chỉ ký. Hãy ràng buộc nó với một trusted list của quốc gia thành viên mà bạn đã tải về và xác thực (xem Trusted lists).
<?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";Đầu ra kỳ vọng cho một người ký được cấp bởi một dịch vụ CA/QC có trong danh sách:
TRUSTEDAnchors: tsl-eu-seq42Reasons: anchor_signature_matchVí dụ mã — Sản xuất
Phần tiêu đề “Ví dụ mã — Sản xuất”Suy ra anchor bundle một lần cho mỗi trusted list, rồi xác minh nhiều người ký container so với nó. Một TSL cũ hoặc không dùng được làm cả lô fail-closed; các vấn đề của từng người ký được bộc lộ theo từng container.
<?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, );}Đầu ra kỳ vọng khi một chứng chỉ người ký đã hết hạn:
invoice-2026-06.asice => trusted (anchor_signature_match; anchors tsl-eu-seq42)tender-2019.asice => rejected (signer_cert_expired; anchors tsl-eu-seq42)Trường hợp biên & điểm cần lưu ý
Phần tiêu đề “Trường hợp biên & điểm cần lưu ý”- Thời điểm xác thực là bắt buộc và mang tính quyết định. Không có giá trị mặc định
nowngầm. Một chữ ký từng xác minh được vào năm 2019 báo cáosigner_cert_expiredkhi bạn xác thực tại một thời điểm năm 2026 vượt quanotAfter. Đối với tư liệu lịch sử, hãy truyền thời điểm mà bằng chứng của bạn hỗ trợ (ví dụ một thời điểm chứng minh sự tồn tại), không phải đồng hồ treo tường. - Một TSL cũ sẽ ném; nó không phải là một phán quyết “không tin cậy”.
TslParseExceptiontừverify()hoặcbuildBundle()nghĩa là nguồn tin cậy không dùng được. Hãy coi đó là một thất bại vận hành: làm mới danh sách, đừng ghi nhận nó như một lần từ chối người ký. - Các anchor được kiểm tra như những đơn vị cấp trực tiếp. Mỗi anchor được thử như chứng chỉ đã ký chứng chỉ người ký. Các TSL của quốc gia thành viên EU liệt kê các chứng chỉ dịch vụ CA/QC cấp phát, nên các chứng chỉ đủ điều kiện thực thể-cuối thường khớp trực tiếp. Một người ký được cấp bởi một CA trung gian mà bản thân nó không phải là một dịch vụ CA/QC đang hoạt động có trong danh sách sẽ cho
no_anchor_chain. - Việc suy ra anchor lọc rất chặt. Các dịch vụ đã bị rút, hoặc thuộc bất kỳ loại nào khác ngoài CA/QC, không bao giờ trở thành anchor. Một danh sách có tập CA/QC đang hoạt động rỗng sẽ ném thay vì tạo ra một bundle rỗng.
NextUpdatephải là UTC chuẩn tắc. Một giá trị không có ký hiệu chỉ địnhZtường minh hoặc độ lệch số bị từ chối fail-closed, không bao giờ được diễn giải lại theo múi giờ cục bộ của máy chủ.- Đầu vào không đúng định dạng suy giảm một cách chính xác. Một PEM không phân tích được trả về
cannot_parse_signer_cert; một chứng chỉ chưa có hiệu lực được phân biệt với một chứng chỉ đã hết hạn. - Hãy ghi lại
anchorBundleVersion. Nó nêu tên tập anchor chính xác (tsl-<territory>-seq<N>) đứng sau mỗi phán quyết, đó chính là điều mà một kiểm toán viên sẽ hỏi.
Ghi chú bảo mật
Phần tiêu đề “Ghi chú bảo mật”- Fail-closed theo thiết kế. Độ mới được khẳng định trước khi suy ra bất kỳ anchor nào. Cổng hiệu lực người ký chạy trước bất kỳ so sánh anchor nào. Vật liệu tin cậy không dùng được sẽ ném; người ký đáng ngờ bị từ chối kèm lý do. Không đường dẫn nào suy giảm thành một lần thông qua ngầm.
- Ràng buộc tin cậy là một lớp, không phải toàn bộ quá trình xác thực. API này không xác minh giá trị chữ ký CAdES trên nội dung container, không kiểm tra thu hồi (không tra cứu CRL hoặc OCSP), và không xác thực chính tài liệu TSL. Hãy xác thực danh sách qua đường ống trusted-list trước (xem Trusted lists), xác minh chữ ký về mặt mật mã bằng công cụ chữ ký của bạn, và bổ sung việc kiểm tra thu hồi theo chính sách của bạn.
- Chọn thời điểm xác thực một cách có chủ đích. Phán quyết là một hàm của thời điểm bạn truyền vào. Hãy suy ra nó từ bằng chứng đáng tin cậy (một dấu thời gian đủ điều kiện, một bản ghi lưu trữ), không phải từ một đồng hồ mà kẻ tấn công có thể tác động.
- Đầu ra bằng chứng có tính tất định.
trusted,anchorBundleVersion, vàreasonslà những giá trị ổn định, máy đọc được, phù hợp cho các nhật ký kiểm toán đã ký.
Sự tuân thủ
Phần tiêu đề “Sự tuân thủ”AsicTrustBinder hỗ trợ các luồng công việc phù hợp với ETSI EN 319 162-1 (container ASiC baseline), ETSI EN 319 122-1 (chữ ký CAdES baseline), và ETSI TS 119 612 (trusted list), và áp dụng cổng khoảng-hiệu-lực RFC 5280 tại thời điểm xác thực được cung cấp.
Hỗ trợ không phải là sự tuân thủ, và sự tuân thủ không phải là chứng nhận. NextPDF triển khai các kiểm tra mà trang này mô tả; nó chưa được bất kỳ tổ chức nào chứng nhận đối với các tiêu chuẩn này, và việc sử dụng API này tự nó không làm cho đầu ra của bạn trở nên “qualified” hay có hiệu lực pháp lý theo eIDAS hoặc bất kỳ chế độ nào khác. NextPDF không nắm giữ chứng nhận nào và không cấp chứng nhận nào. Việc một quá trình xác thực hoàn chỉnh có đáp ứng một yêu cầu pháp lý hoặc mua sắm cụ thể hay không là một xác định thuộc về các bên đánh giá của bạn.
Hành vi ở chế độ FIPS
Phần tiêu đề “Hành vi ở chế độ FIPS”Ràng buộc tin cậy thực hiện các kiểm tra chữ ký chứng chỉ X.509 trong tiến trình; nó không được định tuyến qua bộ bảo vệ runtime chế độ FIPS của Enterprise, và việc bật chế độ FIPS không làm thay đổi hành vi của nó. Nó không phải là một dịch vụ mật mã đã được kiểm định FIPS, và không có chứng nhận FIPS 140 nào được tuyên bố. Các triển khai có nghĩa vụ FIPS nên khoanh vùng phạm vi cho API này một cách phù hợp và xem Chính sách mật mã FIPS 140-2/3.
Hợp đồng hành vi
Phần tiêu đề “Hợp đồng hành vi”verify()chỉ suy ra anchor từ một TSL còn mới tại thời điểm xác thực được cung cấp; một danh sách cũ hoặc không đúng định dạng sẽ némTslParseExceptiontrước khi bất kỳ anchor nào tồn tại.- Các anchor được suy ra riêng từ những dịch vụ TSL ở trạng thái granted với loại dịch vụ CA/QC; một tập hoạt động rỗng sẽ ném.
- Khoảng hiệu lực của chứng chỉ người ký phải bao gồm thời điểm xác thực; vi phạm trả về
signer_cert_expiredhoặcsigner_cert_not_yet_valid. - Mọi kết cục đều là một
AsicTrustBindingResultmangtrusted,anchorBundleVersion, và ít nhất một mã lý do; không có phán quyết nào không có lý do. - Người ký không tin cậy được trả về, không bao giờ bị ném; vật liệu tin cậy không dùng được bị ném, không bao giờ được trả về như một phán quyết.
- Việc phân tích container không bao giờ diễn ra bên trong API này; đầu vào là PEM đã trích xuất, trusted list, và thời điểm xác thực.
Phương án dự phòng Core
Phần tiêu đề “Phương án dự phòng Core”NextPDF Core xác thực các chữ ký PDF (CMS/PAdES) so với các trust anchor mà bạn ghim tường minh qua hợp đồng CaTrustAnchorBundle của nó — xem Bảo mật Core. Core không có việc nạp trusted-list (TSL) và không có ràng buộc tin cậy dành riêng cho ASiC. Chỉ với Core, bạn có thể duy trì tập anchor của riêng mình để xác thực chữ ký PDF; việc suy ra anchor từ một trusted list ETSI TS 119 612 và ràng buộc các người ký container ASiC với chúng đòi hỏi NextPDF Enterprise.
Ranh giới xuất bản
Phần tiêu đề “Ranh giới xuất bản”Trang này chỉ ghi lại hành vi quan sát được từ bên ngoài và bề mặt API công khai được hỗ trợ. Các đường dẫn namespace nội bộ, các lớp trợ giúp, các bảng cơ chế, tên tệp runbook, và các tiền tố ticket nằm ngoài phạm vi.
Xem thêm
Phần tiêu đề “Xem thêm”- Trusted lists — tải về, xác thực, và phân tích TSL cấp dữ liệu cho anchor provider.
- Xác minh chữ ký — bề mặt xác minh Enterprise cho các chữ ký PDF.
- Chính sách mật mã FIPS 140-2/3 — tư thế chế độ FIPS của Enterprise.
- Chữ ký số chứng minh ai đã ký như thế nào — bối cảnh từ nguyên lý cơ bản.
- Xác thực dài hạn — vì sao thời điểm xác thực và bằng chứng được bảo tồn lại quan trọng.