跳到內容

已簽署合約的工作流程

Spec: ETSI EN 319 142-2, §5.1 Spec: ISO 32000-2:2020, §12.8 Evidence: Mixed evidence

已簽署的合約不只是「上面有簽章的 PDF」。它是一份經過準備,讓簽章保護正確位元組的文件;它以符合義務的層級簽署,並以能在簽署憑證過期後仍可驗證的方式封裝。本頁會帶你走完整個情境,從空白文件到長期有效的合約,也會坦白說明引擎目前已連線哪些步驟,哪些仍以凍結介面的形式公開。

一份簽署當天可驗證、卻在三年後爭議中失效的合約,比完全沒有簽章更糟,因為已經有人據此信賴它。失敗原因很少出在密碼學本身;通常是缺少時間戳記或撤銷證據,而且往往到簽署者早已離開後才被裁定。

事先選定簽章義務,並在簽署當下產出該義務所需的證據,正是一份能站得住腳的合約,與一份悄悄失效的合約之間的差別。這件事應該在工作流程中一次決定,而不是每次發生爭議時才又發現。

  • 先準備,再簽署。 簽章只涵蓋它據以計算的那段位元組範圍。要在簽署「之前」就確認文件已是最終版本,包括任何稍後附加的修訂;不要等到簽署之後才決定。
  • 為義務挑選層級,而不是反過來。 PAdES 定義了一個遞進:基本簽章、加上時間戳記的簽章、嵌入驗證材料的簽章,以及為無限期封存有效性而重新蓋戳的簽章(ETSI EN 319 142-2 §5.1)。
  • 長期有效性是一種結構,而非一項屬性。 它是寫入檔案中的文件安全儲存區,加上一個文件時間戳記(ISO 32000-2:2020 §12.8)。
  • 對接縫要精準。 NextPDF 的高階 Document::setSignature() 凍結了公開 API,但會快速失敗,不會輸出一份未簽署的檔案。已連線的路徑是較低階的協調器。本頁不會假裝情況不是這樣。

NextPDF 將決策機制分開。決策是義務需要哪一個 PAdES 層級;機制是位元組如何被簽署, 以及驗證材料如何被攜帶。把兩者混為一談, 正是團隊最後得到一個有效卻不持久簽章的原因。

這個情境分成四個階段。

  1. Prepare the document Compose the agreement and treat it as final. The signature will protect this exact byte range and nothing added outside it without a new revision.
  2. Choose the obligation B-B proves who. B-T adds trusted time. B-LT embeds the material to validate later. B-LTA re-stamps for indefinite validity.
  3. Sign A CMS signature is embedded in the signature dictionary over the byte range; a timestamp is requested from a TSA if the level needs one.
  4. Preserve For long-term levels, the Document Security Store and a document timestamp are written so the signature outlives its certificate.
從頭到尾的已簽署合約情境:每個階段都增添一項保證,而你在第二階段所選的層級,決定了第三與第四階段必須產出多少證據。

這個層級列舉是真實存在的,也誠實地編碼了義務。B-B 證明簽署者的身分。B-T 加上一個受信任的時間戳記,讓「何時」和「是誰」一樣明確。B-LT 嵌入在簽署憑證過期後驗證簽章所需的憑證與撤銷回應。 B-LTA 再加上文件時間戳記,讓信任鏈能在每張時間戳記憑證失效前重新蓋戳, 持續延伸以維持無限期有效性。這個列舉知道哪些層級需要時間戳記、哪些需要嵌入的驗證材料,因此引擎可以拒絕不可能的組合, 而不是產出一份誤導性標示為「已簽署」的檔案。

這個遞進有標準支持 Evidence: Standard-backed Spec: ETSI EN 319 142-2, §5.1 描述了 PAdES 層級: 它層疊於 EN 319 142-1 的構件之上,從基本的嵌入式簽章向上遞進。長期結構則由以下規範固定 Spec: ISO 32000-2:2020, §12.8 :長期驗證建立於文件安全儲存區與文件時間戳記字典之上, 並寫入檔案之中。

這個層級模型也有程式碼支持 Evidence: Code-backed 這個 SignatureLevel 列舉具備四個 PAdES 案例(B-BB-TB-LTB-LTA),並附帶用於判定「需要時間戳記」、「需要嵌入驗證材料」與「需要文件時間戳記」的方法。高階的 Document::setSignature() 連到快速失敗防護; 它會引發一個阻擋性、可採取行動的診斷訊息,而非輸出一份未簽署的文件——這是一個可驗證的行為,而非一項聲稱。

長期維護行為記錄在 Premium 級別的能力層級:封存介面會寫入 DSS 與各別簽章的 VRI,透過健康檢查檢視封存完整性,並在時間戳記憑證過期前以文件時間戳記重新蓋戳。文件也明確指出,最終仍由驗證者裁定。

這裡展示的是決策,也就是使用真實列舉來選擇義務。已連線的簽署路徑是較低階的協調器;高階呼叫只用來讓快速失敗行為更明確。

<?php
declare(strict_types=1);
use NextPDF\Security\Signature\SignatureLevel;
/**
* Map a business obligation to a PAdES level.
*
* The obligation drives the level, not the reverse — choosing B-B for a
* 10-year contract is a decision you do not want to make implicitly.
*/
function levelForObligation(string $obligation): SignatureLevel
{
return match ($obligation) {
// Internal sign-off, short retention, signer identity is enough.
'internal_approval' => SignatureLevel::PAdES_B_B,
// Counterparty agreement: prove the moment of signing.
'counterparty_agreement' => SignatureLevel::PAdES_B_T,
// Regulated contract that must verify after cert expiry.
'regulated_contract' => SignatureLevel::PAdES_B_LT,
// Long-lived legal record: indefinite, re-stampable validity.
'long_term_legal_record' => SignatureLevel::PAdES_B_LTA,
default => throw new \InvalidArgumentException(
"Unknown obligation: {$obligation}",
),
};
}
$level = levelForObligation('regulated_contract');
// The enum carries the obligation's implications with it.
$needsTsa = $level->requiresTimestamp(); // true for B-T+
$needsDss = $level->requiresDss(); // true for B-LT+
$needsArchive = $level->requiresDocumentTimestamp(); // true only for B-LTA

層級物件不是標籤;它回答義務蘊含什麼,因此下游連線不必重新推導。

反覆出現的誤解是:「簽章有效,所以我們完成了。」 當下有效是必要條件,卻不充分。簽章是針對一段位元組範圍計算而成;任何稍後修訂中附加在該範圍之外的內容,都不在它的涵蓋內,這就是準備必須先於簽署的原因。而一個現在可驗證的簽章,在憑證過期後可能失效,除非驗證材料已在簽署當下嵌入。「有效」與「持久」是不同保證,只有義務能告訴你實際需要哪一種。

此引擎還有一個特定陷阱:不要假設高階的 setSignature() 目前會產出一份已簽署的檔案。它不會;它會快速失敗。 這是刻意設計。請把這個診斷訊息視為契約。

  • Document::setSignature() 是凍結的公開介面,而非已連線的簽署器。 它會以阻擋性的診斷訊息快速失敗。它絕不會以一份未簽署的 PDF 取代一份已簽署的 PDF。已連線的路徑是較低階的兩階段協調器。
  • 長期驗證維護(DSS/VRI、健康檢查、封存時間戳記迴圈)是 Premium 級別的能力。 Core 並不提供封存迴圈。請參見下方的邊界。
  • 簽章只保護它自己的位元組範圍。 稍後附加的修訂是分開的。引擎不會回溯性地擴展涵蓋範圍。
  • NextPDF 產生並維護這些結構;它並不裁定。 一個簽章是否受信任,取決於驗證者的信任錨點與政策,而這些都在引擎之外。
  • B-LTA 本身並不會讓一個簽章永恆有效。 唯有當重新蓋戳的迴圈在每張時間戳記憑證過期前按時執行,它才能實現無限期有效性。
  • 本頁對 Premium 封存介面的說明停留在行為層級;它並未主張任何特定法院或機關會接受。
PAdES signing and long-term validity — edition availability
Edition Availability
Core

Core 公開 SignatureLevel 列舉以及凍結的 Document::setSignature() 介面(快速失敗)。 已連線的較低階協調器涵蓋基線簽署。長期封存維護則不在 Core 之中。

Pro

透過協調器提供 PAdES 基線簽署(B-B / B-T)。

Enterprise

加上 B-LT / B-LTA、文件安全儲存區與各別簽章的 VRI 維護、LTV 健康檢查,以及用於無限期有效性的文件時間戳記封存迴圈。

  • PAdES 基線設定檔——以遞進方式說明 B-BB-TB-LTB-LTA,以及如何選擇。
  • 長期驗證——為何今日可驗證的簽章在十年後可能失效,以及 LTV 如何嵌入證據。
  • 整合決策指南——哪一個生態系套件適合簽署工作流程,包括 NextPDF Connect 中的人工核准接縫。
  • PAdES — PDF Advanced Electronic Signatures(PDF 進階電子簽章):定義進階電子簽章如何承載於 PDF 中的 ETSI 設定檔家族。
  • Byte range(位元組範圍) — 簽章據以計算的那段連續檔案位元組;範圍外的內容不受該簽章保護。
  • 簽章層級(B-B / B-T / B-LT / B-LTAPAdES 遞進:誰簽署、何時簽署、附帶嵌入的驗證材料,以及可重新蓋戳以維持無限期封存有效性。
  • TSA — Time-Stamping Authority(時間戳記機構):一項 RFC 3161 服務,用來主張某個文件狀態曾在指定 UTC 時刻存在。
  • DSS(Document Security Store,文件安全儲存區) — 檔案內的儲存區,存放在憑證過期後驗證簽章所需的憑證、OCSP 回應與 CRL。
  • LTV(Long-Term Validation,長期驗證) — 透過嵌入驗證證據並重新蓋戳,讓簽章隨時間推移仍可驗證。
  • Fail-fast(快速失敗) — 拒絕產出具誤導性的產物,改為引發可採取行動的錯誤,而不是悄悄輸出錯誤的檔案。