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

Contracts / Signing

Miền ký gồm sáu contract. Các contract này định nghĩa cách tạo chữ ký Cryptographic Message Syntax (CMS), áp dụng dấu thời gian Request for Comments (RFC) 3161, ký bằng khóa trong mô-đun bảo mật phần cứng (HSM) và bật xác thực dài hạn (LTV). Core công bố các contract; các phiên bản Pro và Enterprise cung cấp những triển khai sẵn sàng cho môi trường sản xuất.

Terminal window
composer require nextpdf/core:^3

Chữ ký số Portable Document Format (PDF) là một cấu trúc CMS SignedData được lưu trong từ điển chữ ký. Mục Contents chứa cấu trúc được mã hóa theo Distinguished Encoding Rules (DER). Mục ByteRange chỉ định các khoảng byte mà digest bao phủ. Digest bao phủ toàn bộ tệp và loại trừ chính giá trị chữ ký; xem International Organization for Standardization (ISO) 32000-2 §12.8.1. Cấu trúc CMS tuân theo RFC 5652 §5.1: phiên bản, thuật toán digest, nội dung được đóng gói và thông tin người ký.

SignerInterface là contract cốt lõi. Nó tạo CMS SignedData cho một khoảng byte, áp dụng dấu thời gian cho giá trị chữ ký và cho biết có hỗ trợ LTV hay không. Contract này mang các mức cơ sở PDF Advanced Electronic Signatures (PAdES) từ B-B đến B-LTA như được European Telecommunications Standards Institute (ETSI) EN 319 142 định nghĩa. Mỗi mức cao hơn bổ sung thêm tài liệu xác thực. B-B mang chữ ký cơ sở. B-T bổ sung dấu thời gian chữ ký. B-LT bổ sung dữ liệu thu hồi. B-LTA bổ sung dấu thời gian lưu trữ.

HsmSignerInterface ký bằng khóa được lưu trong mô-đun bảo mật phần cứng. Khóa riêng không bao giờ rời khỏi ranh giới phần cứng. Contract trả về chứng chỉ người ký và chuỗi chứng chỉ ở dạng DER để lớp CMS có thể dựng cấu trúc. DeferredSignerInterface mở rộng SignerInterface để ký bất đồng bộ. Bên gọi gửi dữ liệu, nhận mã định danh công việc, thăm dò thời điểm hoàn tất rồi lấy kết quả. Hãy dùng contract này khi một HSM từ xa hoặc dịch vụ khóa trên đám mây không trả về kết quả ngay lập tức.

TimestampProviderInterface yêu cầu token dấu thời gian RFC 3161. Giao thức là một trao đổi yêu cầu-phản hồi với Time-Stamping Authority (TSA); xem RFC 3161 §2.4. messageImprint trong token là hash của giá trị chữ ký; xem RFC 3161 §2.4.2. LtvManagerInterface bật LTV. Nó thu thập chuỗi chứng chỉ, lấy các phản hồi Online Certificate Status Protocol (OCSP) và danh sách thu hồi chứng chỉ (CRL), dựng Document Security Store (DSS), rồi thêm dấu thời gian tài liệu cho B-LTA. CryptoPolicyInterface kiểm soát các thuật toán hash, chữ ký và mã hóa được phép, cùng với độ mạnh của khóa, trước khi bất kỳ thao tác mật mã nào chạy.

LoạiKiểuThành viên chínhĐộ ổn địnhTừ
SignerInterfaceinterfacesign(string): SignatureResult, timestamp(string): string, supportsLtv(): boolstable1.0.0
HsmSignerInterfaceinterfacesign(string, string): string, getCertificateDer(), getCertificateChainDer(), getPublicKeyAlgorithm()stable1.0.0
DeferredSignerInterfaceinterfacesubmitForSigning(string): string, retrieveSignature(string), isComplete(string) (mở rộng SignerInterface)experimental3.0.0
TimestampProviderInterfaceinterfacegetTimestamp(string): stringexperimental3.0.0
LtvManagerInterfaceinterfaceenableLtv(...), addDocumentTimestamp(...)stable1.10.0
CryptoPolicyInterfaceinterfaceisHashAlgorithmAllowed(), isSignatureAlgorithmAllowed(), isEncryptionAlgorithmAllowed(), isKeyStrengthAllowed(), getPreferredHashAlgorithm(), getName()stable1.9.0

SignerInterface::sign() trả về một NextPDF\Security\Signature\SignatureResult. Thuộc tính công khai $cmsSignedData chứa CMS được mã hóa DER. Thuộc tính công khai $digestHex chứa digest SHA-256. Thuộc tính công khai $timestampToken chứa token TSA tùy chọn. Các accessor là toHex() / toHexPadded(int) / getSize() / hasTimestamp(). HsmSignerInterface::sign() trả về các byte được mã hóa DER cho Rivest-Shamir-Adleman (RSA) và các byte r‖s thô cho Elliptic Curve Digital Signature Algorithm (ECDSA). Đối số thuật toán dùng định danh OpenSSL.

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

SignerInterface::sign() trả về một SignatureResult. toHex() tạo chuỗi hex để trình ghi đặt vào trường /Contents; các byte DER thô có sẵn trên thuộc tính công khai $cmsSignedData. Hàm này phụ thuộc vào contract, không phụ thuộc vào một lớp cụ thể. Cả test signer của core lẫn HSM signer của Premium đều đáp ứng contract này.

examples/contracts/signing-production.php
<?php
declare(strict_types=1);
require_once __DIR__ . '/../../vendor/autoload.php';
use NextPDF\Contracts\CryptoPolicyInterface;
use NextPDF\Contracts\SignerInterface;
use NextPDF\Contracts\TimestampProviderInterface;
use NextPDF\Exception\NextPdfException;
use Psr\Log\LoggerInterface;
final readonly class TimestampedSigningService
{
public function __construct(
private SignerInterface $signer,
private TimestampProviderInterface $timestamps,
private CryptoPolicyInterface $policy,
private LoggerInterface $logger,
) {}
/**
* Sign a byte range, then timestamp the CMS structure.
*
* @param string $byteRange The PDF byte range to sign.
*
* @return array{cms: string, digest: string, tst: string}
*/
public function sign(string $byteRange): array
{
if (!$this->policy->isHashAlgorithmAllowed($this->policy->getPreferredHashAlgorithm())) {
throw new \LogicException('Preferred hash rejected by crypto policy.');
}
try {
$signature = $this->signer->sign($byteRange);
$token = $this->timestamps->getTimestamp($signature->cmsSignedData);
return [
'cms' => $signature->toHex(),
'digest' => $signature->digestHex,
'tst' => $token,
];
} catch (NextPdfException $e) {
$this->logger->error('Signing failed', [
'policy' => $this->policy->getName(),
'error' => $e->getMessage(),
]);
throw $e;
}
}
}

Dịch vụ này tiêm ba contract. Nó kiểm tra chính sách mật mã trước khi ký. SignatureResult cung cấp các byte CMS qua thuộc tính công khai $cmsSignedData, digest SHA-256 qua $digestHex, và chuỗi hex /Contents thông qua toHex(). Nhà cung cấp dấu thời gian nhận các byte CMS và trả về token được mã hóa DER. Khối catch ghi lại tên chính sách rồi ném lại ngoại lệ. Nó không bao giờ nuốt lỗi.

  • Digest khoảng byte phải loại trừ giá trị chữ ký. Digest bao phủ mục Contents sẽ tạo ra chữ ký không bao giờ có thể xác minh được; xem ISO 32000-2 §12.8.1.
  • SignerInterface::supportsLtv() báo cáo khả năng, không phải trạng thái. Một signer có thể hỗ trợ LTV nhưng vẫn tạo chữ ký B-B khi chưa cấu hình dịch vụ dấu thời gian nào.
  • DeferredSignerInterface::retrieveSignature() trả về null cho đến khi công việc hoàn tất. Hãy thăm dò isComplete() trước để bạn không truyền payload trong mỗi lần kiểm tra. Việc lấy kết quả là idempotent sau khi đã có kết quả.
  • LtvManagerInterface::addDocumentTimestamp() phải chạy sau khi Document Security Store đã được ghi. Gọi trước thời điểm đó sẽ tạo ra cấu trúc B-LTA không hợp lệ.
  • CryptoPolicyInterface trả về true cho mọi thuật toán khi không có chính sách nào được thiết lập. Trong môi trường được quản lý chặt, hãy thiết lập một chính sách rõ ràng; đừng dựa vào giá trị mặc định mở.
  • HsmSignerInterface::getCertificateChainDer() loại trừ chứng chỉ người ký. Hãy dùng getCertificateDer() cho chứng chỉ lá của người ký và dùng phương thức chuỗi cho các chứng chỉ trung gian.

Chi phí ký chủ yếu đến từ thao tác mật mã và mọi lượt trao đổi qua mạng, không phải từ contract. Một chữ ký phần mềm cục bộ thường mất vài mili giây. Chữ ký HSM cần thêm một lượt trao đổi với thiết bị. Dấu thời gian cần thêm một lượt trao đổi qua mạng với Time-Stamping Authority. Xác thực dài hạn cần thêm một lần lấy OCSP hoặc CRL cho mỗi chứng chỉ trong chuỗi. performance_budget 1500 ms wall bao phủ một chữ ký có dấu thời gian đơn lẻ với một TSA từ xa trên kết nối đã sẵn sàng. Xác thực dài hạn với điểm cuối thu hồi chậm sẽ vượt quá ngưỡng đó và nên chạy ngoài đường xử lý yêu cầu. Hồ sơ khả năng tái lập là structural, không phải bitwise. Dấu thời gian nhúng thời điểm ký, nên hai lần chạy sẽ 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.

Các contract ký 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õ. Quản lý khóa là mối quan tâm đầu tiên: HsmSignerInterface giữ khóa riêng bên trong ranh giới phần cứng, và contract không bao giờ để lộ vật liệu khóa. Hạ cấp thuật toán là mối quan tâm thứ hai: CryptoPolicyInterface chặn các hash yếu và khóa ngắn trước khi thao tác chạy, cho phép một bản triển khai áp đặt hồ sơ Federal Information Processing Standards (FIPS) 140-3 hoặc định danh điện tử, xác thực và dịch vụ tin cậy (eIDAS) mà không cần fork engine. Niềm tin vào dấu thời gian là mối quan tâm thứ ba: token RFC 3161 chỉ đáng tin cậy ngang với Time-Stamping Authority phát hành nó, nên contract nhà cung cấp có thể được tiêm vào và bản triển khai có thể ghim cơ quan của riêng mình. Xác thực dài hạn là mối quan tâm thứ tư: tài liệu thu hồi được lấy tại thời điểm ký và lưu trong Document Security Store để việc xác minh vẫn còn hiệu lực sau khi chứng chỉ hết hạn. Hãy coi mọi đầu vào của signer là không đáng tin cậy. Engine tính toán khoảng byte; không bao giờ được chấp nhận khoảng byte từ bên gọi. Trang này được đánh dấu export_control_class: legal-review-required vì các contract chi phối việc ký mật mã. Phần văn xuôi diễn giải lại tất cả các nguồn quy phạm và không trích dẫn nguồn nào, theo nguyên tắc vệ sinh trích dẫn.

Tuyên bốTiêu chuẩnĐiều khoảnBằng chứng
Mục Contents của từ điển chữ ký lưu giá trị chữ ký dưới dạng CMS SignedData được mã hóa DER hoặc TimeStampToken.ISO 32000-2§12.8.1
Digest được tính trên khoảng byte do mảng ByteRange định nghĩa và loại trừ giá trị chữ ký.ISO 32000-2§12.8.1,
Document Security Store mang tài liệu xác thực dài hạn với thông tin liên quan đến xác thực (VRI), các mục OCSP, CRL và chứng chỉ.ISO 32000-2§12.8.4.3,
Xác thực dài hạn PAdES đặt dữ liệu xác thực trong các từ điển DSS và VRI.ETSI EN 319 142-2§6.3,
Token dấu thời gian RFC 3161 ràng buộc hash của giá trị chữ ký thông qua messageImprint trong trao đổi yêu cầu-phản hồi TSA.RFC 3161§2.4.2, §2.4,
Chuỗi CMS SignedData mang phiên bản, các thuật toán digest, nội dung được đóng gói và thông tin người ký.RFC 5652§5.1

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

Core công bố và đóng băng các contract ký. Các phiên bản Pro và Enterprise cung cấp những triển khai dùng cho sản xuất phía sau HsmSignerInterface, LtvManagerInterface, và signer trì hoãn, bao gồm tích hợp phần cứng Public-Key Cryptography Standards #11 (PKCS#11) và PAdES B-LT cùng B-LTA. Core phân giải các triển khai này tại thời điểm chạy bằng class_exists() rồi ép kiểu chúng về contract, nên engine mã nguồn mở không mang phụ thuộc thương mại nào và API không thay đổi khi nâng cấp.