Bỏ qua để đến nội dung

Security / Signing: CMS, dấu thời gian RFC 3161, LTV, độ tin cậy

Trang này mô tả bề mặt chữ ký trong NextPDF Core: tạo chữ ký Content Management Syntax (CMS), áp dụng dấu thời gian Request for Comments (RFC) 3161, xác thực chuỗi chứng chỉ theo RFC 5280, và kiểm tra trạng thái thu hồi qua Online Certificate Status Protocol (OCSP) cùng danh sách thu hồi chứng chỉ (CRL). Trang này chỉ mô tả hành vi. Các lớp triển khai Core là nội bộ: mã sản phẩm dùng hợp đồng SignerInterface, không dùng các kiểu cụ thể NextPDF\Security\Signature. Bộ xác minh và các trust anchor được cấu hình cho nó quyết định liệu một chữ ký đã tạo có xác minh được hay không. Kết quả đó nằm ngoài tầm kiểm soát của bên tạo chữ ký, và trang này nêu rõ điều đó ở mọi chỗ liên quan.

Terminal window
composer require nextpdf/core:^3

Core dựng cấu trúc CMS SignedData từ byte range, rồi lưu cấu trúc đó dưới dạng dữ liệu được mã hóa theo Distinguished Encoding Rules (DER) trong mục Contents của từ điển chữ ký — ISO 32000-2 §12.8.1. Cấu trúc này mang theo các thuộc tính đã ký của SignerInfo, bao gồm content-type và message-digest — RFC 5652 §5.3. Bộ xác minh tính lại digest của nội dung và so sánh với thuộc tính message-digest. Phép so sánh phải khớp thì chữ ký mới hợp lệ — RFC 5652 §5.4. SignerInfo cũng mang theo định danh thuật toán digest và khối thuộc tính đã ký — RFC 5652 §5. Core dùng phpseclib3 cho các đường ký bằng phần mềm mà nó cung cấp: RSA, RSASSA-PSS, ECDSA, và Ed25519.

Dấu thời gian RFC 3161 là một trao đổi yêu cầu-và-phản hồi với Time-Stamping Authority (TSA), trả về cấu trúc TSTInfo — RFC 3161 §2.4.1. Mỗi token mang theo một serialNumber duy nhất đối với TSA phát hành — RFC 3161 §2.4.2 — và một genTime biểu diễn theo Coordinated Universal Time (UTC), tức thời điểm token được tạo ra — RFC 3161 §2.4.2.

Việc xác thực độ tin cậy gồm hai phép kiểm tra. Xác thực đường đi lần từ chứng chỉ của bên ký đến một trust anchor, kiểm tra các ràng buộc cơ bản và các đầu vào dựng đường đi — RFC 5280 §6.1. Kiểm tra thu hồi truy vấn một bộ phản hồi OCSP hoặc đọc một CRL: một phản hồi OCSP báo cáo good, revoked, hoặc unknown — RFC 6960 §2.2 — và các trường thisUpdatenextUpdate của phản hồi giới hạn mức độ mới của trạng thái đó — RFC 6960 §4.2. Bên gọi cung cấp các trust anchor và chính sách về độ mới của thông tin thu hồi. Engine xác thực dựa trên các đầu vào đó và không đi kèm danh sách tin cậy dựng sẵn.

KiểuLoạiVai tròĐộ ổn địnhTừ phiên bản
SignerInterfaceinterface (NextPDF\Contracts)Hợp đồng ký mà các bên gọi phụ thuộc vàoổn định1.0.0
SignatureLevelenumBộ chọn cấp độ PDF Advanced Electronic Signatures (PAdES) và phép dò khả dụngổn định1.0.0
Rfc5280PathValidatorinterfaceĐiểm vào xác thực đường đi chứng chỉ (validate(...))ổn định (đóng băng 3.1.0)3.1.0
RevocationStatusenumKết quả OCSP / CRL: good, revoked, unknownổn định3.1.0
CaTrustAnchorBundletypeTập trust anchor do bên gọi cung cấpổn định3.1.0
TstInfotypeCác trường dấu thời gian RFC 3161 đã phân tíchổn định3.2.0

SignerInterface::sign() trả về một SignatureResult. Phương thức toHex() của nó tạo chuỗi hex /Contents, còn thuộc tính cmsSignedData giữ các byte DER thô. Các lớp cụ thể trong NextPDF\Security\Signature triển khai hành vi này là nội bộ (stability: internal trong manifest mô-đun). Chúng không thuộc API công khai và có thể thay đổi mà không cần tăng phiên bản lớn. Hãy phụ thuộc vào các hợp đồng và enum nêu trên.

examples/contracts/signing-quickstart.php
<?php
declare(strict_types=1);
require_once __DIR__ . '/../../vendor/autoload.php';
use NextPDF\Contracts\SignerInterface;
/**
* Produce the CMS SignedData hex for a PDF /Contents field.
*
* @param SignerInterface $signer A Core or Premium signer.
* @param string $byteRange The PDF byte range to sign.
*
* @return string Hex-encoded CMS SignedData.
*/
function sign(SignerInterface $signer, string $byteRange): string
{
return $signer->sign($byteRange)->toHex();
}

Bên gọi phụ thuộc vào hợp đồng. Cả bộ ký bằng phần mềm của Core lẫn bộ ký Hardware Security Module (HSM) của Premium đều thỏa mãn SignerInterface, nên đoạn mã này không thay đổi giữa các phiên bản phát hành.

examples/contracts/signing-trust.php
<?php
declare(strict_types=1);
require_once __DIR__ . '/../../vendor/autoload.php';
use NextPDF\Contracts\SignerInterface;
use NextPDF\Contracts\TimestampProviderInterface;
use NextPDF\Exception\NextPdfException;
use Psr\Log\LoggerInterface;
final readonly class TimestampedSigner
{
public function __construct(
private SignerInterface $signer,
private TimestampProviderInterface $timestamps,
private LoggerInterface $logger,
) {}
/**
* Sign a byte range, then timestamp the CMS structure.
*
* The timestamp's trust still depends on the verifier accepting the
* Time-Stamping Authority; this method only produces the structure.
*
* @param string $byteRange The PDF byte range to sign.
*
* @return array{cms: string, tst: string}
*/
public function sign(string $byteRange): array
{
try {
$signature = $this->signer->sign($byteRange);
$token = $this->timestamps->getTimestamp($signature->cmsSignedData);
return ['cms' => $signature->toHex(), 'tst' => $token];
} catch (NextPdfException $e) {
$this->logger->error('Signing failed', ['error' => $e->getMessage()]);
throw $e;
}
}
}

Bộ cung cấp dấu thời gian được tiêm vào để mỗi triển khai có thể ghim Time-Stamping Authority riêng. Khối catch ghi log rồi ném lại ngoại lệ. Nó không bao giờ nuốt lỗi, nên đường ký luôn fail-closed.

Trường hợp đặc biệt & điểm cần lưu ý

Phần tiêu đề “Trường hợp đặc biệt & điểm cần lưu ý”
  • Chữ ký đã tạo không phải là chữ ký đã được xác minh. Việc xác thực đường đi và kiểm tra thu hồi diễn ra tại bộ xác minh, sử dụng các trust anchor của chính bộ xác minh đó. Bên tạo chữ ký không thể khẳng định kết quả.
  • Digest của byte range loại trừ giá trị chữ ký. Một digest bao gồm cả các octet Contents thì không thể xác minh — ISO 32000-2 §12.8.1.
  • Trạng thái thu hồi có cửa sổ độ mới. Một phản hồi OCSP chỉ còn hiện hành trong khoảng thisUpdate / nextUpdate của nó — RFC 6960 §4.2. Một phản hồi đã cũ không thể thay thế cho lần kiểm tra mới tại thời điểm xác thực.
  • Engine không đi kèm bất kỳ danh sách tin cậy dựng sẵn nào. CaTrustAnchorBundle do bên gọi cung cấp; một bundle rỗng có nghĩa là không chuỗi nào xác thực được, theo thiết kế.
  • OCSP unknown không phải là good. Hãy coi unknown là trạng thái không xác định, chứ không phải sự chấp nhận ngầm — RFC 6960 §2.2.
  • Việc lưu giữ khóa bằng HSM, ký trì hoãn và ký trên đám mây, cùng bộ tạo PAdES B-LT / B-LTA không có trong Core. Chọn các đường đó trong bản phân phối Core sẽ fail-closed kèm thông báo nêu rõ thành phần Enterprise còn thiếu.

Một chữ ký bằng phần mềm mất cỡ vài mili-giây. Một dấu thời gian thêm một lượt đi-về mạng tới TSA. Việc xác thực đường đi là cục bộ sau khi các chứng chỉ đã ở trong bộ nhớ; việc kiểm tra thu hồi thêm một lần tải OCSP hoặc CRL cho mỗi chứng chỉ trong chuỗi. Ngân sách 1500 ms thời gian thực bao phủ một chữ ký có dấu thời gian với một TSA ở xa trên một kết nối đã khởi động. Việc kiểm tra thu hồi với một endpoint chậm vượt quá ngân sách đó và nên nằm ngoài đường xử lý request. Hồ sơ khả năng tái lập là structural: dấu thời gian nhúng thời điểm ký, nên hai lần chạy khác nhau ở các byte dấu thời gian trong khi cấu trúc tài liệu vẫn giống hệt nhau.

Đây là ranh giới mật mã chính của engine, nên mô hình mối đe dọa được nêu rõ. Engine tự tính byte range và không bao giờ nhận nó từ bên gọi. Đường ký là fail-closed: lỗi nguyên thủy hoặc khoảng trống về khả năng sẽ ném ngoại lệ có kiểu và không bao giờ âm thầm hạ cấp xuống thuật toán yếu hơn. Ở cấp độ yêu cầu dấu thời gian (B-T, B-LT, B-LTA), việc Time-Stamping Authority trả về token rỗng là lỗi chí mạng: chữ ký bị từ chối, chứ không được phát ra ở trạng thái âm thầm không đóng dấu, bị hạ cấp, trừ khi có một bộ xử lý lỗi được nối để cho phép sự suy giảm đã được ghi tài liệu. Độ tin cậy do bên gọi kiểm soát theo thiết kế: các anchor và chính sách thu hồi là đầu vào, chứ không phải giá trị mặc định của engine, vì bên tạo chữ ký khẳng định độ tin cậy của chính mình là đang khẳng định một sự thật mà chỉ bộ xác minh mới có thể thiết lập. Độ tin cậy của dấu thời gian quy về độ tin cậy đối với Time-Stamping Authority, vốn có thể tiêm vào để mỗi triển khai ghim được Time-Stamping Authority riêng. Trang này được đánh dấu export_control_class: legal-review-required vì liên quan đến ký mật mã; mọi nguồn quy chuẩn đều được diễn giải lại và không nguồn nào được tái tạo nguyên văn, theo nguyên tắc trích dẫn.

Tuyên bốTiêu chuẩnĐiều khoảnBằng chứng
Chữ ký CMS được lưu dưới dạng mã hóa DER trong mục Contents của từ điển chữ ký.ISO 32000-2§12.8.1
SignerInfo mang theo các thuộc tính đã ký content-type và message-digest.RFC 5652§5.3
Bộ xác minh tính lại digest của nội dung và so sánh với thuộc tính message-digest.RFC 5652§5.4
Một token dấu thời gian do một RFC 3161 TSA tạo ra và mang theo một serialNumber duy nhất cùng một genTime theo UTC.RFC 3161§2.4.1, §2.4.2,,
Việc xác thực đường dẫn chứng chỉ kiểm tra các ràng buộc cơ bản và các đầu vào đường đi từ bên ký đến một trust anchor.RFC 5280§6.1,
OCSP báo cáo certStatus là good, revoked, hoặc unknown, được giới hạn bởi thisUpdate / nextUpdate.RFC 6960§2.2, §4.2,

Tất cả các điều khoản đều được diễn giải lại. NextPDF không tái tạo nguyên văn văn bản quy chuẩn. Hãy tham khảo các tiêu chuẩn đã xuất bản để biết ngôn ngữ có thẩm quyền.

Core cung cấp bộ ký CMS bằng phần mềm (RSA, RSASSA-PSS, ECDSA, Ed25519), việc tiêu thụ dấu thời gian RFC 3161, xác thực đường đi RFC 5280, và kiểm tra thu hồi qua OCSP / CRL. Việc lưu giữ khóa bằng HSM và Public-Key Cryptography Standards #11 (PKCS#11), ký trì hoãn và ký trên đám mây, bộ tạo PAdES B-LT và B-LTA, cùng hồ sơ chính sách mật mã Federal Information Processing Standards (FIPS) 140-3 được cung cấp trong các phiên bản Pro và Enterprise. Core phân giải những thành phần này tại thời điểm chạy dựa trên hợp đồng, nên engine mã nguồn mở không mang theo phụ thuộc thương mại nào, và API không thay đổi khi nâng cấp.