Skip to content

长效签名验证(LTV,Long term validation)

自 7.0 版本起,福昕 PDF SDK 引入了长效签名验证 (LTV) 的 API 接口,旨在解决签名过期后的验证难题。LTV 的实现依赖于两个关键要素:

  • 文档安全存储 (DSS, Document Security Store):包含签名验证所需的全部信息。
  • 文档时间戳签名 (DTS, Document Timestamp Signature):一种 time stamp 类型的签名,用于记录文档签署时的准确时间。

为支持 LTV 功能,福昕 PDF SDK 提供了以下组件:

  • 时间戳签名支持
    • 提供添加 time stamp 类型签名的 API。
    • 内置 ETSI.RFC3161 子过滤器的默认签名回调。
  • 时间戳服务器管理
    • TimeStampServerMgrTimeStampServer 类,用于配置和管理时间戳服务器。
    • 默认签名回调 ETSI.RFC3161 将自动使用默认配置的时间戳服务器。
  • LTV 验证器
    • LTVVerifier 类,提供验证签名和向文档添加 DSS 信息的功能。
    • 同时,提供 LTVVerifier 所需的基本默认吊销回调函数 RevocationCallback

长效签名验证

以下示例代码演示如何使用 SDK 默认的 sub filter:ETSI.RFC3161 签名回调及默认的 ·RevocationCallback· 进行长效签名验证。详细的信息,请参阅下载包中 \examples\simple_demo 目录下的 ltv 示例。

c++
#include "include/pdf/fs_pdfdoc.h"
#include "include/pdf/fs_pdfpage.h"
#include "include/pdf/fs_signature.h"
#include "include/pdf/fs_ltvverifier.h"
...

// Initialize time stamp server manager, add and set a default time stamp server, which will be used by default signature callback for time stamp signature.
TimeStampServerMgr::Initialize();
TimeStampServer timestamp_server = TimeStampServerMgr::AddServer(server_name, server_url, server_username, server_password);
TimeStampServerMgr::SetDefaultServer(timestamp_server);

// Assume that "signed_pdf_path" represents a signed PDF document which contains signed signature.
PDFDoc pdf_doc(signed_pdf_path);
pdf_doc.StartLoad();
{
	// Use LTVVerifier to verify and add DSS.
	LTVVerifier ltv_verifier(pdf_doc, true, true, false, LTVVerifier::e_SignatureCreationTime);
	// Set verifying mode which is necessary.
	ltv_verifier.SetVerifyMode(LTVVerifier::e_VerifyModeAcrobat);
	SignatureVerifyResultArray sig_verify_result_array = ltv_verifier.Verify();
	for (size_t i = 0; i < sig_verify_result_array.GetSize(); i++) {
		// ltv state would be e_LTVStateNotEnable here.
		SignatureVerifyResult::LTVState ltv_state =  sig_verify_result_array.GetAt(i).GetLTVState();
		if (sig_verify_result_array.GetAt(i).GetSignatureState() & Signature::e_StateVerifyValid)
			ltv_verifier.AddDSS(sig_verify_result_array.GetAt(i));
	}
}

// Add a time stamp signature as DTS and sign it. "saved_ltv_pdf_path" represents the newly saved signed PDF file.
PDFPage pdf_page = pdf_doc.GetPage(0);
// The new time stamp signature will have default filter name "Adobe.PPKLite" and default subfilter name "ETSI.RFC3161".
Signature timestamp_signature = pdf_page.AddSignature(RectF(), L"", Signature::e_SignatureTypeTimeStamp);
Progressive sign_progressive = timestamp_signature.StartSign(L"", L"", Signature::e_DigestSHA256, saved_ltv_pdf_path);
if (sign_progressive.GetRateOfProgress() != 100)
	sign_progressive.Continue();

// Then use LTVVeirfier to verify the new signed PDF file.
PDFDoc check_pdf_doc(saved_ltv_pdf_path);
check_pdf_doc.StartLoad();
{
	// Use LTVVeirfier to verify.
	LTVVerifier ltv_verifier(pdf_doc, true, true, false, LTVVerifier::e_SignatureCreationTime);
	// Set verifying mode which is necessary.
	ltv_verifier.SetVerifyMode(LTVVerifier::e_VerifyModeAcrobat);
	SignatureVerifyResultArray sig_verify_result_array = ltv_verifier.Verify();
	for (size_t i = 0; i < sig_verify_result_array.GetSize(); i++) {
		// ltv state would be e_LTVStateEnable here.
		SignatureVerifyResult::LTVState ltv_state =  sig_verify_result_array.GetAt(i).GetLTVState();
		... // User can get other information from SignatureVerifyResult.
	}
}

// Release time stamp server manager when everything is done.
TimeStampServerMgr::Release();
C
#include "include/fs_basictypes_c.h"
#include "include/fs_pdfdoc_c.h"
#include "include/fs_pdfpage_c.h"
#include "include/fs_signature_c.h"
#include "include/fs_ltvverifier_c.h"
...

// Initialize time stamp server manager, add and set a default time stamp server, which will be used by default signature callback for time stamp signature.
FSDK_TimeStampServerMgr_Initialize();
FS_TIMESTAMPSERVER_HANDLE timestamp_server;
FS_WSTR password;
password.str = NULL;
password.len = 0;
FSDK_TimeStampServerMgr_AddServer(server_name, server_url, L"", &password, &timestamp_server);
FSDK_TimeStampServerMgr_SetDefaultServer0(timestamp_server);

// Assume that "signed_pdf_path" represents a signed PDF document which contains signed signature.
FS_PDFDOC_HANDLE pdf_doc;
FSDK_PDFDoc_Create0(signed_pdf_path, &pdf_doc);
FS_PROGRESSIVE_HANDLE progressive;
FSDK_PDFDoc_StartLoad(pdf_doc, NULL, true, NULL, &progressive);
{
	// Use LTVVerifier to verify and add DSS.
	FS_LTVVERIFIER_HANDLE  ltv_verifier;
	FSDK_LTVVerifier_Create(pdf_doc, true, true, false, e_FSSignatureCreationTime, &ltv_verifier);
	// Set verifying mode which is necessary.
	FSDK_LTVVerifier_SetVerifyMode(ltv_verifier, e_FSVerifyModeAcrobat);
	FS_UINT32 length;
	FSDK_LTVVerifier_Verify(ltv_verifier, NULL, &length);
	FS_SIGNATUREVERIFYRESULT_HANDLE*sig_verify_result_array= malloc( length * sizeof(FS_SIGNATUREVERIFYRESULT_HANDLE);
	FSDK_LTVVerifier_Verify(ltv_verifier, sig_verify_result_array, &length);
	for (size_t i = 0; i < length; i++) {
		// ltv state would be e_LTVStateNotEnable here.
		FS_SIGNATUREVERIFYRESULT_HANDLE sig_verify_result = sig_verify_result_array[i];
		FSLTVState ltv_state;
		FSDK_SignatureVerifyResult_GetLTVState(sig_verify_result, &ltv_state);
		FS_UINT32 sig_state;
		FSDK_SignatureVerifyResult_GetSignatureState(sig_verify_result, &sig_state);
		if (sig_state & e_FSStateVerifyValid)
			FSDK_LTVVerifier_AddDSS(ltv_verifier, sig_verify_result_array[i]);
	}
	free(sig_verify_result_array);
}

// Add a time stamp signature as DTS and sign it. "saved_ltv_pdf_path" represents the newly saved signed PDF file.
FS_PDFPAGE_HANDLE pdf_page;
FSDK_PDFDoc_GetPage(pdf_doc, 0, &pdf_page);;
// The new time stamp signature will have default filter name "Adobe.PPKLite" and default subfilter name "ETSI.RFC3161".
FS_SIGNATURE_HANDLE timestamp_signature;
FSRectF rect;
FSDK_PDFPage_AddSignature1(pdf_page, rect, L"", e_FSSignatureTypeTimeStamp, true, &timestamp_signature);
FS_PROGRESSIVE_HANDLE sign_progressive;
FSDK_Signature_StartSign(timestamp_signature, L"", L"", e_FSDigestSHA256, saved_ltv_pdf_path, NULL, NULL, &sign_progressive);
int rate;
FSDK_Progressive_GetRateOfProgress(sign_progressive, &rate);
if (rate != 100){
	FSState state;
	FSDK_Progressive_Continue(sign_progressive, &state);
}
// Then use LTVVeirfier to verify the new signed PDF file.
FS_PDFDOC_HANDLE check_pdf_doc;
FSDK_PDFDoc_Create0(saved_ltv_pdf_path, &check_pdf_doc);
FS_PROGRESSIVE_HANDLE progressive1;
FSDK_PDFDoc_StartLoad(check_pdf_doc, NULL, true, NULL, &progressive1);
{
	// Use LTVVeirfier to verify.
	FS_LTVVERIFIER_HANDLE ltv_verifier;
	FSDK_LTVVerifier_Create(pdf_doc, true, true, false, e_FSSignatureCreationTime, &ltv_verifier);
	// Set verifying mode which is necessary.
	FSDK_LTVVerifier_SetVerifyMode(ltv_verifier, e_FSVerifyModeAcrobat);
	FS_UINT32 length;
	FSDK_LTVVerifier_Verify(ltv_verifier, NULL, &length);
	FS_SIGNATUREVERIFYRESULT_HANDLE*sig_verify_result_array= malloc (length *  sizeof(FS_SIGNATUREVERIFYRESULT_HANDLE));
	FSDK_LTVVerifier_Verify(ltv_verifier, sig_verify_result_array, &length);
	for (size_t i = 0; i < length; i++) {
		// ltv state would be e_LTVStateEnable here.
		FS_SIGNATUREVERIFYRESULT_HANDLE sig_verify_result = sig_verify_result_array[i];
		FSLTVState ltv_state;
		FSDK_SignatureVerifyResult_GetLTVState(sig_verify_result, &ltv_state);
		... // User can get other information from SignatureVerifyResult.
	}
	free(sig_verify_result_array);
}

// Release time stamp server manager when everything is done.
FSDK_TimeStampServerMgr_Release();
java
// Initialize time stamp server manager, add and set a default time stamp server, which will be used by default signature callback for time stamp signature.
TimeStampServerMgr.initialize();
TimeStampServer timestamp_server = TimeStampServerMgr.addServer(server_name, server_url, server_username, server_password);
TimeStampServerMgr.setDefaultServer(timestamp_server);
		 
// Assume that "signed_pdf_path" represents a signed PDF document which contains signed signature.
PDFDoc pdf_doc = new PDFDoc(signed_pdf_path);
pdf_doc.startLoad(null, false, null);
{
   // Use LTVVerifier to verify and add DSS.
   LTVVerifier ltv_verifier = new LTVVerifier(pdf_doc, true, true, false, LTVVerifier.e_SignatureCreationTime);
   // Set verifying mode which is necessary.
   ltv_verifier.setVerifyMode(LTVVerifier.e_VerifyModeAcrobat);
   SignatureVerifyResultArray sig_verify_result_array = ltv_verifier.verify();
   for (long i = 0; i < sig_verify_result_array.getSize(); i++) {
	// ltv state would be e_LTVStateNotEnable here.
	int ltv_state =  sig_verify_result_array.getAt(i).getLTVState();
	if ((sig_verify_result_array.getAt(i).getSignatureState() & Signature.e_StateVerifyValid) == Signature.e_StateVerifyValid)
	    ltv_verifier.addDSS(sig_verify_result_array.getAt(i));
	}
   }		 
		 
// Add a time stamp signature as DTS and sign it. "saved_ltv_pdf_path" represents the newly saved signed PDF file.
PDFPage pdf_page = pdf_doc.getPage(0);
// The new time stamp signature will have default filter name "Adobe.PPKLite" and default subfilter name "ETSI.RFC3161".
Signature timestamp_signature = pdf_page.addSignature(new RectF(), "", Signature.e_SignatureTypeTimeStamp, true);
Progressive sign_progressive = timestamp_signature.startSign("", empty_str.getBytes(), Signature.e_DigestSHA256, saved_ltv_pdf_path, null, null);
if (sign_progressive.getRateOfProgress() != 100)
   sign_progressive.resume();
		 
// Then use LTVVeirfier to verify the new signed PDF file.
PDFDoc check_pdf_doc = new PDFDoc(saved_ltv_pdf_path);
check_pdf_doc.startLoad(null, false, null);
{
   // Use LTVVeirfier to verify.
   LTVVerifier ltv_verifier = new LTVVerifier(pdf_doc, true, true, false, LTVVerifier.e_SignatureCreationTime);
   // Set verifying mode which is necessary.
   ltv_verifier.setVerifyMode(LTVVerifier.e_VerifyModeAcrobat);
   SignatureVerifyResultArray sig_verify_result_array = ltv_verifier.verify();
   for (long i = 0; i < sig_verify_result_array.getSize(); i++) {
	// ltv state would be e_LTVStateEnable here.
	int ltv_state =  sig_verify_result_array.getAt(i).getLTVState();
	... // User can get other information from SignatureVerifyResult.
   }
}
		 
// Release time stamp server manager when everything is done.
TimeStampServerMgr::Release();
py
import sys
import site

if sys.version_info.major == 2:
    _PYTHON2_ = True
else:
    _PYTHON2_ = False

if _PYTHON2_:
    #replace with the python2 lib path
    site.addsitedir('../../../')
    from FoxitPDFSDKPython2 import *
else:
from FoxitPDFSDKPython3 import *

# Implementation of pdf.SignatureCallback
class SignatureCallbackImpl(SignatureCallback):

    def __init__(self, *args):
        if _PYTHON2_:
            super(SignatureCallbackImpl, self).__init__()
        else:
            super().__init__()
        self.digest_context_ = None
        self.sub_filter_ = args[0]

    def __del__(self):
        self.__disown__()

    def Release(self):
        pass

    def GetTextFromFile(self, *args):
        file_buffer = None
        if self.digest_context_ is None or not self.digest_context_.GetFileReadCallback(
        ):
            return False, None
        file_read = self.digest_context_.GetFileReadCallback()
        val, buffer = file_read.ReadBlock(
            (self.digest_context_.GetByteRangeElement(0),
             self.digest_context_.GetByteRangeElement(1)))
        file_buffer = buffer
        val, buffer = file_read.ReadBlock(
            (self.digest_context_.GetByteRangeElement(2),
             self.digest_context_.GetByteRangeElement(3)))
        file_buffer += buffer
        return True, file_buffer

    def StartCalcDigest(self, *args):
        file = args[0]
        byte_range_array = args[1]
        size_of_array = len(args[1])
        signature = args[2]
        client_data = args[3]
        self.digest_context_ = DigestContext(file, byte_range_array,
                                             size_of_array)
        return self.digest_context_.HashInit()

    def ContinueCalcDigest(self, *args):
        try:
            if self.digest_context_ is None:
                return Progressive.e_Error

            ret, file_buffer = self.GetTextFromFile()
            if not ret:
                return Progressive.e_Error
            self.digest_context_.HashUpdate(file_buffer)
            return Progressive.e_Finished
        except Exception as ex:
            print(ex.GetMessage())
        return Progressive.e_Error

    def GetDigest(self, *args):
        try:
            if self.digest_context_ is None:
                return ""
            digest = self.digest_context_.HashDigest()
            return digest
        except Exception as ex:
            print(ex.GetMessage())
        return ""

    def Sign(self, *args):
        try:
            digest = args[0][0]
            digest_length = args[0][1]
            cert_path = args[1]
            password = args[2]
            digest_algorithm = args[3]
            client_data = args[4]

            if self.digest_context_ is None:
                return ""
            plain_text = ""
            if "adbe.pkcs7.sha1" == self.sub_filter_:
                plain_text = digest

            pk12 = crypto.load_pkcs12(open(cert_path, 'rb').read(), password)
            pkey = pk12.get_privatekey()
            signcert = pk12.get_certificate()

            PKCS7_NOSIGS = 0x4

            bio_in = crypto._new_mem_buf(plain_text)
            pkcs7 = crypto._lib.PKCS7_sign(signcert._x509, pkey._pkey,
                                           crypto._ffi.NULL, bio_in,
                                           PKCS7_NOSIGS)
            bio_out = crypto._new_mem_buf()
            crypto._lib.i2d_PKCS7_bio(bio_out, pkcs7)
            signed_data = crypto._bio_to_string(bio_out)
            return signed_data
        except Exception as ex:
            print(ex.GetMessage())

        return ""

    def VerifySigState(self, *args):
        # Usually, the content of a signature field is contain the certification of signer.
        # But we can't judge this certification is trusted.
        # For this example, the signer is ourself. So when using api PKCS7_verify to verify,
        # we pass NULL to it's parameter <i>certs</i>.
        # Meanwhile, if application should specify the certificates, we suggest pass flag PKCS7_NOINTERN to
        # api PKCS7_verify.
        if self.digest_context_ is None:
            return Signature.e_StateVerifyErrorData
        plain_text = ""

        digest = args[0][0]
        digest_length = args[0][1]
        signed_data = args[1][0]
        signed_data_len = args[1][1]
        client_data = args[2]

        if "adbe.pkcs7.sha1" != self.sub_filter_:
            return Signature.e_StateUnknown

        p7 = crypto.load_pkcs7_data(crypto.FILETYPE_ASN1, signed_data)
        PKCS7_NOVERIFY = 0x20
        p7bio = crypto._new_mem_buf(digest)
        res = crypto._lib.PKCS7_verify(p7._pkcs7, crypto._ffi.NULL,
                                       crypto._ffi.NULL, p7bio,
                                       crypto._ffi.NULL, PKCS7_NOVERIFY)

        if res:
            return Signature.e_StateVerifyNoChange
        else:
            return Signature.e_StateVerifyChange

    def IsNeedPadData(self, *args):
        return False

    def CheckCertificateValidity(self, *args):
        # User can check the validity of input certificate here.
        # If no need to check, just return e_CertValid.
        return SignatureCallback.e_CertValid
objc
#include "FSPDFObjC.h"

// Initialize time stamp server manager, add and set a default time stamp server, which will be used by default signature callback for time stamp signature.
[FSTimeStampServerMgr initialize];
FSTimeStampServer* timestamp_server = [FSTimeStampServerMgr addServer:server_name server_url:server_url user_name:user_name password:password];
[FSTimeStampServerMgr setDefaultServer:timestamp_server];

// Assume that "signed_pdf_path" represents a signed PDF document which contains signed signature.
FSPDFDoc *pdf_doc = [[FSPDFDoc alloc] initWithPath:signed_pdf_path];
[pdf_doc startLoad:nil is_cache_stream:NO pause:nil];
{
    // Use LTVVerifier to verify and add DSS.
    FSLTVVerifier* ltv_verifier = [[FSLTVVerifier alloc] initWithDocument:pdf_doc is_verify_signature:YES use_expired_tst:YES ignore_doc_info:NO time_type:FSLTVVerifierSignatureCreationTime];
    // Set verifying mode which is necessary.
    [ltv_verifier setVerifyMode:FSLTVVerifierVerifyModeAcrobat];
    FSSignatureVerifyResultArray* sig_verify_result_array = [ltv_verifier verify];
    unsigned long array_size = [sig_verify_result_array getSize];
    for (size_t i = 0; i < array_size; i++) {
        FSSignatureVerifyResult* sig_verify_result = [sig_verify_result_array getAt:i];
        // ltv state would be FSSignatureVerifyResultLTVStateNotEnable here.
        FSSignatureVerifyResultLTVState ltv_state = [sig_verify_result getLTVState];
        if (([sig_verify_result getSignatureState] & FSSignatureStateVerifyValid) == FSSignatureStateVerifyValid)
            [ltv_verifier addDSS:sig_verify_result];
    }
}

// Add a time stamp signature as DTS and sign it. "saved_ltv_pdf_path" represents the newly saved signed PDF file.
FSPDFPage *pdf_page = [pdf_doc getPage:0];
// The new time stamp signature will have default filter name "Adobe.PPKLite" and default subfilter name "ETSI.RFC3161".
FSRectF* empty_rect = [[FSRectF alloc] init];
FSSignature* timestamp_signature = [pdf_page addSignatureWithSignatureType:empty_rect field_name:@""
signature_type:FSSignatureSignatureTypeTimeStamp to_check_permission:YES];
[timestamp_signature startSign:@"" cert_password:@"" digest_algorithm:FSSignatureDigestSHA1 save_path:saved_ltv_pdf_path client_data:nil pause:nil];

// Then use LTVVeirfier to verify the new signed PDF file.
FSPDFDoc *check_pdf_doc = [[FSPDFDoc alloc] initWithPath:saved_ltv_pdf_path];
[check_pdf_doc startLoad:nil is_cache_stream:NO pause:nil];
{
    // Use LTVVerifier to verify
    FSLTVVerifier* ltv_verifier = [[FSLTVVerifier alloc] initWithDocument:pdf_doc is_verify_signature:YES use_expired_tst:YES ignore_doc_info:NO time_type:FSLTVVerifierSignatureCreationTime];
    // Set verifying mode which is necessary.
    [ltv_verifier setVerifyMode:FSLTVVerifierVerifyModeAcrobat];
    FSSignatureVerifyResultArray* sig_verify_result_array = [ltv_verifier verify];
    unsigned long array_size = [sig_verify_result_array getSize];
    for (size_t i = 0; i < array_size; i++) {
        FSSignatureVerifyResult* sig_verify_result = [sig_verify_result_array getAt:i];
        // ltv state would be FSSignatureVerifyResultLTVStateEnable here.
        FSSignatureVerifyResultLTVState ltv_state = [sig_verify_result getLTVState];
        ... // User can get other information from FSSignatureVerifyResult.
    }
}

// Destroy time stamp server manager when everything is done.
[FSTimeStampServerMgr destroy];
js
const FSDK = require("@foxitsoftware/foxit-pdf-sdk-node");

let filter = "Adobe.PPKLite";
let sub_filter = "adbe.pkcs7.detached";
console.log("Use signature callback object for filter \"%s\" and sub-filter \"%s\"", filter, sub_filter);
let pdf_page = pdf_doc.GetPage(0);
// Add a new signature to first page.
let new_signature = AddSiganture(pdf_page, sub_filter);
// Set filter and subfilter for the new signature.
new_signature.SetFilter(filter);
new_signature.SetSubFilter(sub_filter);
let is_signed = new_signature.IsSigned();
let sig_state = new_signature.GetState();
console.log("[Before signing] Signed?:%s\t State:%s",is_signed? "true" : "false",
TransformSignatureStateToString(sig_state));
// Sign the new signature.
let signed_pdf_path = output_directory + "signed_newsignature_default_handler.pdf";

let cert_file_path = input_path + "foxit_all.pfx";
let cert_file_password = "123456";
// Cert file path will be passed back to application through callback function FSSignatureCallback::Sign().
// In this demo, the cert file path will be used for signing in callback function FSSignatureCallback::Sign().
new_signature.StartSign(cert_file_path, cert_file_password,
                            FSDK.Signature.e_DigestSHA1, signed_pdf_path, null, null);
console.log("[Sign] Finished!");
is_signed = new_signature.IsSigned();
sig_state = new_signature.GetState();
console.log("[After signing] Signed?:%s\tState:%s",is_signed? "true" : "false",
TransformSignatureStateToString(sig_state));
  
// Open the signed document and verify the newly added signature (which is the last one).
console.log("Signed PDF file: %s", signed_pdf_path);
let signed_pdf_doc = new FSDK.PDFDoc(signed_pdf_path);
error_code = signed_pdf_doc.Load("");
if (FSDK.e_ErrSuccess !=error_code ) {
    console.log("Fail to open the signed PDF file.");
    return;
}
// Get the last signature which is just added and signed.
let sig_count = signed_pdf_doc.GetSignatureCount();
let signed_signature = signed_pdf_doc.GetSignature(sig_count-1);
// Verify the intergrity of signature.
signed_signature.StartVerify(Buffer.alloc(0), null);
console.log("[Verify] Finished!");
is_signed = signed_signature.IsSigned();
sig_state = signed_signature.GetState();
console.log("[After verifying] Signed?:%s\tState:%s", is_signed? "true" : "false",
TransformSignatureStateToString(sig_state));
csharp
using System;

using foxit.common;
using foxit.pdf;
using foxit;
using foxit.common.fxcrt;

// Initialize time stamp server manager, add and set a default time stamp server, which will be used by default signature callback for time stamp signature.
TimeStampServerMgr.Initialize();
using (TimeStampServer timestamp_server = TimeStampServerMgr.AddServer(server_name, server_url, server_username, server_password))
{
  TimeStampServerMgr.SetDefaultServer(timestamp_server);
  // Assume that "signed_pdf_path" represents a signed PDF document which contains signed signature.
  using (PDFDoc pdf_doc = new PDFDoc(signed_pdf_path))
  {
    pdf_doc.StartLoad(null, true, null);
    // Use LTVVerifier to verify and add DSS.
    using (LTVVerifier ltv_verifier = new LTVVerifier(pdf_doc, true, true, false, LTVVerifier.TimeType.e_SignatureCreationTime))
    {
      // Set verifying mode which is necessary.
      ltv_verifier.SetVerifyMode(LTVVerifier.VerifyMode.e_VerifyModeAcrobat);
      SignatureVerifyResultArray sig_verify_result_array = ltv_verifier.Verify();
      for (uint i = 0; i < sig_verify_result_array.GetSize(); i++)
      {
        // ltv state would be e_LTVStateNotEnable here.
        SignatureVerifyResult.LTVState ltv_state = sig_verify_result_array.GetAt(i).GetLTVState();
        if ((sig_verify_result_array.GetAt(i).GetSignatureState() & Convert.ToUInt32(Signature.States.e_StateVerifyValid)) > 0)
          ltv_verifier.AddDSS(sig_verify_result_array.GetAt(i));
      }
      // Add a time stamp signature as DTS and sign it. "saved_ltv_pdf_path" represents the newly saved signed PDF file.
      using (PDFPage pdf_page = pdf_doc.GetPage(0))
      {
        // The new time stamp signature will have default filter name "Adobe.PPKLite" and default subfilter name "ETSI.RFC3161".
        Signature timestamp_signature = pdf_page.AddSignature(new RectF(), "", Signature.SignatureType.e_SignatureTypeTimeStamp, true);
        byte[] empty_byte = Encoding.ASCII.GetBytes("");
        Progressive sign_progressive = timestamp_signature.StartSign("", empty_byte, Signature.DigestAlgorithm.e_DigestSHA256,
          saved_ltv_pdf_path, IntPtr.Zero, null);
        if (sign_progressive.GetRateOfProgress() != 100)
          sign_progressive.Continue();
 
        // Then use LTVVeirfier to verify the new signed PDF file.
        using (PDFDoc check_pdf_doc = new PDFDoc(saved_ltv_pdf_path))
        {
          check_pdf_doc.StartLoad(null, true, null);
          // Use LTVVeirfier to verify.
          using (LTVVerifier ltv_verifier = new LTVVerifier(pdf_doc, true, true, false, LTVVerifier.TimeType.e_SignatureCreationTime))
          {
            // Set verifying mode which is necessary.
            ltv_verifier.SetVerifyMode(LTVVerifier.VerifyMode.e_VerifyModeAcrobat);
            SignatureVerifyResultArray sig_verify_result_array = ltv_verifier.Verify();
            for (uint i = 0; i < sig_verify_result_array.GetSize(); i++)
            {
              // ltv state would be e_LTVStateEnable here.
              SignatureVerifyResult.LTVState ltv_state = sig_verify_result_array.GetAt(i).GetLTVState();
              ... // User can get other information from SignatureVerifyResult.
            }           
          }
        }
      }
    }
  }
}
// Release time stamp server manager when everything is done.
TimeStampServerMgr.Release();