アイコン 株式会社トラスト・ソフトウェア・システム
電話:03-5316-3375info@trustss.co.jp
電話:03-5316-3375info@trustss.co.jp

開発者向けPDFライブラリ - Pdftools SDK

PDF電子署名(タイムスタンプ)機能

PDF電子署名機能

PDFにさまざまな種類のデジタル署名を作成、管理、検証できます。
さまざまなローカルまたはオンラインのセキュアなプロバイダーからの電子証明書で法的および規制上の要件をサポートします。

価格見積もり

 NOTE:
この機能は「Pdftools SDK」ライブラリの一部です。
Pdftools SDKの全機能は無償で試用できます。

APIリファレンス

APIリファレンスはこちらです。(すべて英文)

PDFに電子署名 機能

電子署名は電子文書またはメッセージの信頼性と整合性を確認するために使用される技術です。
電子署名は秘密鍵を使用して文書またはメッセージを暗号化することによって実施されます。
作成された電子署名は対応する公開鍵を使用して検証します。
この公開鍵は署名を検証したい人なら誰でも使用できるように認証局によって公開されています。
電子署名は文書またはメッセージがいかなる方法でも改ざんまたは変更されていないことや、送信者と主張する人物によって送信されたことを確認するために使用されます。

Pdftools SDKは次の三種類のデジタル署名をサポートしています:

文書承認署名

文書承認署名は契約の承認や署名などのワークフローの一部としてPDFに電子署名を施します。
この電子署名は署名者のID(電子証明書)を記録し、署名の適用後に文書の内容が変更されていないことを確認できるようにします。
PDFには複数のこの文書承認署名を関連付けることができます。
たとえば、複数の当事者が契約に署名する場合、各文書承認署名にはユニークな電子署名があり、各署名は連続して適用され、署名チェーンが作成されます。

変更の検出と防止(MDP)

この署名は、文書作成者の ID を記録します。 これにより、ユーザーは署名の有効性を維持しながら、PDFに特定の変更を加えることができます。たとえば、作成者は、署名の有効性を維持しながら、ユーザーがドキュメントのフォーム に入力できるようにすることができます。
作成者が許可していない変更がドキュメントに行われた場合の署名は無効になります。

PDFには一つのMDPを含めることができ、ドキュメントに他の署名を追加する前にその署名を追加する必要があります。
MDPを含む一般的なワークフローは次のようになります:

  1. MDPがテンプレート・ドキュメントに適用され、フォームへの入力が可能になります。
  2. ユーザーはフォームのフィールドに個人情報を入力します。
  3. ドキュメントに文書承認署名が適用され、それ以上の変更ができなくなります。

ドキュメント認証署名には次の設定を使用できます:

タイムスタンプ(Time-Stamp Signature)

タイムスタンプ署名は文書が特定の時間に存在したことと、その時間以降文書の内容が変更されていないことを証明します。
多くの場合、タイムスタンプ署名は以前に署名された文書に変更がないことを確認するための「再署名」に使用されます。
タイムスタンプは独立した信頼できるタイムスタンプ機関(Time-Stamp Athority)によって提供されます。

サポートされているプロバイダー(Cryptographic Provider)

暗号化プロバイダーは、証明書と関連する秘密キーを管理し、暗号化アルゴリズムを実装します。
Pdftools SDK は以下の暗号化プロバイダーをサポートしています。

長期検証可能な電子署名(Long-term Validation)

Pdftools SDK を使用すると様々な既定に従ってPDFの承認、PDFへの電子署名と検証、およびタイムスタンプ署名と検証ができます。
署名は証明書、オンライン証明書ステータス プロトコル(OCSP)の結果や証明書失効リスト(CRL)などのソースを使用して検証できます。
これらのソースはPDFファイルに埋め込むことで長期検証を可能にします。また、ローカル マシンに保存したり、発行者からダウンロードしたりできます。
検証プロセスではすべての署名とそれに対応する詳細のリストを返すことができ、イベントを使用して特定のビジネス ロジックをトリガーすることもできます。

可視電子署名

電子署名に視覚的な外観(スタンプや印影など)を追加できます。
これは、ドキュメント承認署名、ドキュメント認証署名、タイムスタンプ署名、および既存の未署名署名への署名に適用されます。

サンプル

C#のサンプルプロジェクトではPdftools SDKライブラリ(DLL)をNuGetから自動でダウンロードします。
CのサンプルプロジェクトにはPdftools SDKライブラリ(DLL)が含まれています。

ライセンスキー無し(無償)で試用できます。ただし、結果に「透かし」が入ります。
「透かし」の削除をご希望の場合は問い合わせページまたはメールでお問い合わせください。

License Agreement(利用許諾契約書)が含まれていますので必ず確認してください。

PDFの署名フィールドに可視の電子署名

指定された電子証明書でPDF文書に署名し、可視の(視覚的な)電子署名を適用します。
この署名プロセスには(未署名の)署名フィールドが既に含まれた入力PDFが必要です。署名フィールドを追加するサンプルを参照してください。
指定された電子証明書を使用して文書に署名し、既存のフィールドに署名を追加します。署名の外観はXMLまたはJSONファイルを使用して作成され、テキスト、画像、またはPDFを使用できます。
この電子署名は表示部分と非表示部分の両方で構成されます。他のアプリケーションでは、非表示部分のみを使用して、文書の署名部分の整合性を検証し、さらに電子証明書を検証します。
電子証明書は、パスワードで保護されたPKCS#12ファイル(.pfxまたは.p12)で指定します。


サンプル・プロジェクト(C#)をダウンロード
サンプル・プロジェクト(Python)をダウンロード
サンプル・プロジェクトをダウンロード
サンプル・プロジェクトの実行手順を参照してください
static void AddAppearanceSignatureField(string certificateFile, string password, string appConfigFile, string inPath, string outPath)
{
    // Create a session to the built-in cryptographic provider
    using var session = new PdfTools.Crypto.Providers.BuiltIn.Provider();

    // Create signature configuration from PFX (or P12) file
    using var pfxStr = File.OpenRead(certificateFile);
    var signature = session.CreateSignatureFromCertificate(pfxStr, password);

    // Open input document
    using var inStr = File.OpenRead(inPath);
    using var inDoc = Document.Open(inStr);

    // Choose first signature field
    foreach (var field in inDoc.SignatureFields)
    {
        if (field != null)
        {
            signature.FieldName = field.FieldName;
            break;
        }
    }

    // Create stream for output file
    using var outStr = File.Create(outPath);

    // Create appearance from either an XML or a json file
    using var appStream = File.OpenRead(appConfigFile);
    if (Path.GetExtension(appConfigFile) == ".xml")
        signature.Appearance = Appearance.CreateFromXml(appStream);
    else
        signature.Appearance = Appearance.CreateFromJson(appStream);

    signature.Appearance.CustomTextVariables.Add("company", "Daily Planet");

    // Sign the input document
    using var outDoc = new Signer().Sign(inDoc, signature, outStr);
}
サンプル・プロジェクトの実行手順を参照してください
def add_appearance_signature_field(certificate_file: str, password: str, appearance_config_file: str, input_path: str, output_path: str):
    # Create a session to the built-in cryptographic provider
    with Provider() as session:
        # Create signature configuration from PFX (or P12) file
        with io.FileIO(certificate_file, 'rb') as pfx_str:
            signature = session.create_signature_from_certificate(pfx_str, password)

            # Open input document
            with io.FileIO(input_path, 'rb') as input_pdf_stream:
                with Document.open(input_pdf_stream) as input_pdf_document:
                    # Choose first signature field
                    for field in input_pdf_document.signature_fields:
                        if field:
                            signature.field_name = field.field_name
                            break

                    # Create stream for output file
                    with io.FileIO(output_path, 'wb+') as output_stream:
                        # Create appearance configuration from either XML or JSON file
                        with io.FileIO(appearance_config_file, 'rb') as appearance_config_stream:
                            if os.path.splitext(appearance_config_file)[1].lower() == ".xml":
                                signature.appearance = Appearance.create_from_xml(appearance_config_stream)
                            else:
                                signature.appearance = Appearance.create_from_json(appearance_config_stream)

                            signature.appearance.custom_text_variables["company"] = "Daily Planet"

                            # Sign the input document
                            signer = Signer()
                            signer.sign(input_pdf_document, signature, output_stream)
# Sign the input document
add_appearance_signature_field(certificate_file, password, appearance_config_file, input_path, output_path)

PDFに署名フィールドを追加

別のアプリケーションで電子署名できる(未署名の)署名フィールドを追加します。この署名フィールドに電子署名するサンプルを参照してください。
署名フィールドは文書に電子署名が必要であることを示し、電子署名の外観が表示されるページと位置を定義します。
これは署名スペースが指定されているフォームや契約書で特に便利です。電子署名の外観は署名検証プロセスとは無関係ですがユーザーへの視覚的な手がかりとして役立ちます。


サンプル・プロジェクト(C#)をダウンロード
サンプル・プロジェクト(Python)をダウンロード
サンプル・プロジェクトをダウンロード
サンプル・プロジェクトの実行手順を参照してください
static void AddSignatureField(string inPath, string outPath)
{
    // Open input document
    using var inStr = File.OpenRead(inPath);
    using var inDoc = Document.Open(inStr);

    // Create empty field appearance that is 6cm by 3cm in size
    var appearance = Appearance.CreateFieldBoundingBox(Size.cm(6, 3));

    // Add field to last page of document
    appearance.PageNumber = inDoc.PageCount;

    // Position field
    appearance.Bottom = Length.cm(3);
    appearance.Left = Length.cm(6.5);

    // Create a signature field configuration
    var field = new SignatureFieldOptions(appearance);

    // Create stream for output file
    using var outStr = File.Create(outPath);

    // Sign the input document
    using var outDoc = new Signer().AddSignatureField(inDoc, field, outStr);
}
サンプル・プロジェクトの実行手順を参照してください
def add_signature_field(input_path: str, output_path: str):
    # Open input document
    with io.FileIO(input_path, 'rb') as in_stream:
        with Document.open(in_stream) as input_document:
            # Create empty field appearance that is 6cm by 3cm in size
            appearance = Appearance.create_field_bounding_box(Size(170.08, 85.04))

            # Add field to last page of document
            appearance.page_number = input_document.page_count

            # Position field
            appearance.bottom = 85.04
            appearance.left = 184.25

            # Create a signature field configuration
            field = SignatureFieldOptions(appearance)

            # Create stream for output file
            with io.FileIO(output_path, 'wb+') as output_stream:
                # Sign the input document
                signer = Signer()
                signer.add_signature_field(input_document, field, output_stream)
# Sign the input document
add_signature_field(input_path, output_path)

PDFにドキュメントのタイムスタンプを追加

PDFに信頼できる文書タイムスタンプを追加します。 これによって、その文書がタイムスタンプ時刻に存在しその時刻以降で改ざんされていないことを保証します。


サンプル・プロジェクト(C#)をダウンロード
サンプル・プロジェクト(Python)をダウンロード
サンプル・プロジェクトをダウンロード
サンプル・プロジェクトの実行手順を参照してください
static void AddTimestamp(Uri timeStampUrl, string inPath, string outPath)
{
    // Create a session to the built-in cryptographic provider
    using var session = new BuiltIn.Provider();
    session.TimestampUrl = timeStampUrl;

    // Create time-stamp configuration
    var timestamp = session.CreateTimestamp();

    // Open input document
    using var inStr = File.OpenRead(inPath);
    using var inDoc = Document.Open(inStr);

    // Create stream for output file
    using var outStr = File.Create(outPath);

    // Add the document time-stamp
    using var outDoc = new Signer().AddTimestamp(inDoc, timestamp, outStr);
}
サンプル・プロジェクトの実行手順を参照してください
def add_timestamp(time_stamp_url: str, input_path: str, output_path: str):
    # Create a session to the built-in cryptographic provider
    with Provider() as session:
        session.timestamp_url = time_stamp_url

        # Create time-stamp configuration
        timestamp = session.create_timestamp()

        # Open input document
        with io.FileIO(input_path, 'rb') as in_stream:
            with Document.open(in_stream) as input_document:

                # Create stream for output file
                with io.FileIO(output_path, 'wb+') as output_stream:

                    # Add the document time-stamp
                    signer = Signer()
                    signer.add_timestamp(input_document, timestamp, output_stream)
# Optional: Set your proxy configuration
# Sdk.Proxy = new Uri("http://myproxy:8080");

# Add a document time-stamp to a PDF
add_timestamp(time_stamp_url, input_path, output_path)

PDFを認証

このタイプの電子署名によりPDF作成者は署名後にどのような種類の変更が許可されるかを指定できます。
これらの署名は、変更検出および防止(MDP)署名とも呼ばれます。
電子証明書は、パスワードで保護されたPKCS#12ファイル(.pfxまたは.p12)から読み取られます。


サンプル・プロジェクト(C#)をダウンロード
サンプル・プロジェクト(Python)をダウンロード
サンプル・プロジェクトをダウンロード
サンプル・プロジェクトの実行手順を参照してください
static void Certify(string certificateFile, string password, string inPath, string outPath)
{
    // Create a session to the built-in cryptographic provider
    using var session = new BuiltIn.Provider();

    // Create signature configuration from PFX (or P12) file
    using var pfxStr = File.OpenRead(certificateFile);
    var signature = session.CreateSignatureFromCertificate(pfxStr, password);

    // Embed validation information to enable the long term validation (LTV) of the signature (default)
    signature.ValidationInformation = PdfTools.Crypto.ValidationInformation.EmbedInDocument;

    // Open input document
    using var inStr = File.OpenRead(inPath);
    using var inDoc = Document.Open(inStr);

    // Create stream for output file
    using var outStr = File.Create(outPath);

    // Add a document certification (MDP) signature
    // Optionally, the access permissions can be set.
    using var outDoc = new Signer().Certify(inDoc, signature, outStr);
}
		
サンプル・プロジェクトの実行手順を参照してください
def certify_document(certificate_file: str, password: str, input_path: str, output_path: str):
    # Create a session to the built-in cryptographic provider
    with Provider() as session:
        with io.FileIO(certificate_file, 'rb') as pfx_stream:
            # Create signature configuration from PFX (or P12) file
            signature = session.create_signature_from_certificate(pfx_stream, password)

            # Embed validation information to enable the long-term validation (LTV) of the signature
            signature.validation_information = ValidationInformation.EMBED_IN_DOCUMENT

            # Open input document
            with io.FileIO(input_path, 'rb') as in_stream:
                with Document.open(in_stream) as input_document:

                    # Create stream for output file
                    with io.FileIO(output_path, 'wb+') as output_stream:
                        # Certify the document with the MDP signature
                        signer = Signer()
                        signer.certify(input_document, signature, output_stream)
			
# Certify a PDF document
certify_document(certificate_file, password, input_path, output_path)
		

PKCS#11デバイスを使用してPDFに電子署名

ドキュメント署名(承認署名とも呼ばれます)を追加します。
この電子署名は、ドキュメントの署名部分の整合性を検証し、署名者の身元を認証します。署名の長期検証(LTV;Long Term Validation)を可能にするために、検証情報が埋め込まれています。
署名証明書は、PKCS#11ミドルウェア(ドライバー)を備えた暗号化デバイスに保存されます。


サンプル・プロジェクト(C#)をダウンロード
サンプル・プロジェクト(Python)をダウンロード
サンプル・プロジェクトをダウンロード
サンプル・プロジェクトの実行手順を参照してください
// Load the PKCS#11 driver module (middleware)
// The module can only be loaded once in the application.
using var module = Pkcs11.Module.Load(pkcs11Library);

// Create a session to the cryptographic device and log in
// with the password (pin)
// Use Devices[i] if you have more than one device installed instead of Devices.GetSingle()
using var session = module.Devices.GetSingle().CreateSession(password);

// Sign a PDF document
Sign(session, certificate, inPath, outPath);
static void Sign(Pkcs11.Session session, string certificate, string inPath, string outPath)
{
    // Create the signature configuration
    // This can be re-used to sign multiple documents
    var signature = session.CreateSignatureFromName(certificate);

    // Open input document
    using var inStr = File.OpenRead(inPath);
    using var inDoc = Document.Open(inStr);

    // Create stream for output file
    using var outStr = File.Create(outPath);

    // Sign the input document
    using var outDoc = new Signer().Sign(inDoc, signature, outStr);
}
サンプル・プロジェクトの実行手順を参照してください
def sign(session: Session, certificate: str, input_path: str, output_path: str):
    # Create the signature configuration for the certificate
    signature = session.create_signature_from_name(certificate)

    # Open input document
    with io.FileIO(input_path, 'rb') as in_stream:
        with Document.open(in_stream) as input_document:

            # Create stream for output file
            with io.FileIO(output_path, 'wb+') as output_stream:

                # Sign the input document
                signer = Signer()
                signer.sign(input_document, signature, output_stream)
# Optional: Set your proxy configuration
# Sdk.set_proxy("http://myproxy:8080")

# Load the PKCS#11 driver module (middleware)
# The module can only be loaded once in the application.
with Module.load(pkcs11_library) as module:

    # Create a session to the cryptographic device and log in with the password (pin)
    # Use devices[i] if you have more than one device installed instead of devices.get_single()
    with module.devices.get_single().create_session(password) as session:
        # Sign a PDF document
        sign(session, certificate, input_path, output_path)

PDFに可視の電子署名を追加

可視の(視覚的な外観を持つ)電子署名をPDF文書に追加します。
電子署名の外観はXML(またはjson)ファイルで指定します。この外観にはテキスト、画像、またはPDFを追加できます。
この署名は可視部分と不可視部分で構成され、不可視部分のみで文書の署名部分を検証し、署名者のIDを認証できます。
署名用の証明書はパスワードで保護されたPKCS#12ファイル(.pfxまたは.p12)で指定します。


サンプル・プロジェクト(C#)をダウンロード ReadMeを開く
サンプル・プロジェクト(Python)をダウンロード ReadMeを開く
サンプル・プロジェクトをダウンロード
サンプル・プロジェクトの実行手順を参照してください
static void Sign(string certificateFile, string password, string appConfigFile, string inPath, string outPath)
{
    // 組み込みの暗号化プロバイダへのセッションを生成
    using var session = new BuiltIn.Provider();

    // 証明書ファイルを開く
    using var pfxStr = File.OpenRead(certificateFile);

    // .pfx(または.p12)ファイルから署名設定を作成
    BuiltIn.SignatureConfiguration signature = session.CreateSignatureFromCertificate(pfxStr, password);

    // XMLまたはjsonファイルから外観を作成
    using var appStream = File.OpenRead(appConfigFile);
    if (Path.GetExtension(appConfigFile) == ".xml")
        signature.Appearance = Appearance.CreateFromXml(appStream);
    else
        signature.Appearance = Appearance.CreateFromJson(appStream);

    signature.Appearance.PageNumber = 1;
    signature.Appearance.CustomTextVariables.Add("company", "Daily Planet");

    // 入力のPDFファイルを開く
    using var inStr = File.OpenRead(inPath);
    using var inDoc = Document.Open(inStr);

    // 出力ファイルのストリームを生成
    using var outStr = File.Create(outPath);

    // 入力PDF文書に電子署名
    using var outDoc = new Signer().Sign(inDoc, signature, outStr);
}			
サンプル・プロジェクトの実行手順を参照してください
def sign(certificate_file: str, password: str, appearance_config_file: str, input_path: str, output_path: str):
    # 組み込みの暗号化プロバイダへのセッションを生成
    with Provider() as session:
        # 証明書ファイルを開く
        with io.FileIO(certificate_file, 'rb') as pfx_stream:
            # .pfx(または.p12)ファイルから署名設定を作成
            signature = session.create_signature_from_certificate(pfx_stream, password)

            # XMLまたはjsonファイルから外観を作成
            with io.FileIO(appearance_config_file, 'rb') as appearance_stream:
                if appearance_config_file.endswith(".xml"):
                    signature.appearance = Appearance.create_from_xml(appearance_stream)
                else:
                    signature.appearance = Appearance.create_from_json(appearance_stream)

            signature.appearance.page_number = 1
            signature.appearance.custom_text_variables["company"] = "Daily Planet"

            # 入力のPDFファイルを開く
            with io.FileIO(input_path, 'rb') as input_stream:
                with Document.open(input_stream) as input_document:
                    # 出力ファイルのストリームを生成
                    with io.FileIO(output_path, 'wb+') as output_stream:
                        # 入力PDF文書に電子署名
                        signer = Signer()
                        signer.sign(input_document, signature, output_stream)			
# オプションで: プロキシを指定できます
# Sdk.set_proxy("http://myproxy:8080")

# PDF文書に電子署名
sign(certificate_file, password, appearance_config_file, input_path, output_path)			

入力PDF文書に含まれる署名を検証

入力PDF文書に含まれるすべての電子署名の署名情報を抽出して検証し、結果をコンソールに出力します。


サンプル・プロジェクト(C#)をダウンロード ReadMeを開く
サンプル・プロジェクト(Python)をダウンロード ReadMeを開く
サンプル・プロジェクトをダウンロード
サンプル・プロジェクトの実行手順を参照してください
// ヘルパー関数によって署名検証の詳細を出力します。
static int Validate(string inputFile, string certDir)
{
    // 既定の検証プロファイルを使用します。
    var profile = new Default();

    // オフライン操作の場合はファイルシステムからカスタム信頼リスト(CustomTrustList)を構築し、外部失効チェックを無効にします。
    if (certDir != null && certDir.Length != 0)
    {
        Console.WriteLine("Using 'offline' validation mode with custom trust list.");
        Console.WriteLine();

        // 証明書を保持するためのカスタム信頼リストを生成
        var ctl = new CustomTrustList();

        // 証明書ディレクトリ内のファイルを反復処理し、カスタム信頼リストに証明書を追加
        if (Directory.Exists(certDir))
        {
            var directoryListing = Directory.EnumerateFiles(certDir);
            foreach (string fileName in directoryListing)
            {
                try
                {
                    using var certStr = File.OpenRead(fileName);

                    if (fileName.EndsWith(".cer") || fileName.EndsWith(".pem"))
                    {
                        ctl.AddCertificates(certStr);
                    }
                    else if (fileName.EndsWith(".p12") || fileName.EndsWith(".pfx"))
                    {
                        // パスワードが必要な場合はaddArchive(certStr, password)を使用します。
                        ctl.AddArchive(certStr);
                    }
                }
                catch (Exception e)
                {
                    Console.WriteLine("Could not add certificate '" + fileName + "' to custom trust list: " + e.Message);
                }
            }
        }
        else
        {
            // dirがディレクトリではない場合の処理
            Console.WriteLine("Directory " + certDir + " is missing. No certificates were added to the custom trust list.");
        }
        Console.WriteLine();

        // 検証プロファイルへのカスタム信頼リスト割り当て
        profile.CustomTrustList = ctl;

        // ファイルに埋め込まれた情報とカスタム信頼リストからの検証を許可
        var vo = profile.ValidationOptions;
        vo.TimeSource = TimeSource.ProofOfExistence | TimeSource.ExpiredTimeStamp | TimeSource.SignatureTime;
        vo.CertificateSources = DataSource.EmbedInSignature | DataSource.EmbedInDocument | DataSource.CustomTrustList;

        // 失効チェックを無効にします。
        profile.SigningCertTrustConstraints.RevocationCheckPolicy = RevocationCheckPolicy.NoCheck;
        profile.TimeStampTrustConstraints.RevocationCheckPolicy = RevocationCheckPolicy.NoCheck;
    }

    // 文書内のすべての署名を検証 (最新のものだけではありません。)
    var signatureSelector = SignatureSelector.All;

    // 検証オブジェクト(Validator)とイベントリスナーを作成
    var validator = new Validator();
    validator.Constraint += (s, e) =>
    {
        Console.WriteLine("  - " + e.Signature.Name + (e.DataPart.Length > 0 ? (": " + e.DataPart) : "") + ": " +
            ConstraintToString(e.Indication, e.SubIndication, e.Message));
    };

    try
    {
        using var inStr = File.OpenRead(inputFile);
        // 入力のPDFファイルを開く
        // パスワードが必要な場合は、Open(inStr, password)を使用します。
        using var document = Document.Open(inStr);

        // 文書、プロファイル、セレクタを検証メソッドに渡して実行
        Console.WriteLine("Validation Constraints");
        var results = validator.Validate(document, profile, signatureSelector);

        Console.WriteLine();
        Console.WriteLine("Signatures validated: " + results.Count);
        Console.WriteLine();

        // 結果を出力
        foreach (var result in results)
        {
            var field = result.SignatureField;
            Console.WriteLine(field.FieldName + " of " + field.Name);
            try
            {
                Console.WriteLine("  - Revision  : " + (field.Revision.IsLatest ? "latest" : "intermediate"));
            }
            catch (Exception ex)
            {
                Console.WriteLine("Unable to validate document Revision: " + ex.Message);
            }

            PrintContent(result.SignatureContent);
            Console.WriteLine();
        }

        return 0;
    }
    catch (Exception ex)
    {
        Console.WriteLine("Unable to validate file: " + ex.Message);
        return 5;
    }
}			
private static void PrintContent(SignatureContent content)
{
    if(content != null)
    {
        Console.WriteLine("  - Validity  : " + ConstraintToString(content.Validity));
        switch (content)
        {
            case UnsupportedSignatureContent:
                break;
            case CmsSignatureContent signature:
                {
                    Console.WriteLine("  - Validation: " + signature.ValidationTime + " from " + signature.ValidationTimeSource);
                    Console.WriteLine("  - Hash      : " + signature.HashAlgorithm);
                    Console.WriteLine("  - Signing Cert");
                    PrintContent(signature.SigningCertificate);
                    Console.WriteLine("  - Chain");
                    foreach (var cert in signature.CertificateChain)
                    {
                        Console.WriteLine("  - Issuer Cert " + (signature.CertificateChain.IndexOf(cert) + 1));
                        PrintContent(cert);
                    }
                    Console.WriteLine("  - Chain     : " + (signature.CertificateChain.IsComplete ? "complete" : "incomplete") + " chain");
                    Console.WriteLine("  Time-Stamp");
                    PrintContent(signature.TimeStamp);
                    break;
                }
            case TimeStampContent timeStamp:
                {
                    Console.WriteLine("  - Validation: " + timeStamp.ValidationTime + " from " + timeStamp.ValidationTimeSource);
                    Console.WriteLine("  - Hash      : " + timeStamp.HashAlgorithm);
                    Console.WriteLine("  - Time      : " + timeStamp.Date);
                    Console.WriteLine("  - Signing Cert");
                    PrintContent(timeStamp.SigningCertificate);
                    Console.WriteLine("  - Chain");
                    foreach (var cert in timeStamp.CertificateChain)
                    {
                        Console.WriteLine("  - Issuer Cert " + (timeStamp.CertificateChain.IndexOf(cert) + 1));
                        PrintContent(cert);
                    }
                    Console.WriteLine("  - Chain      : " + (timeStamp.CertificateChain.IsComplete ? "complete" : "incomplete") + " chain");
                    break;
                }
            default:
                Console.WriteLine("Unsupported signature content type " + content.GetType().Name);
                break;
        }                
    }
    else
    {
        Console.WriteLine("  - null");
    }
}			
private static void PrintContent(Certificate cert)
{
    if(cert != null)
    {
        Console.WriteLine("    - Subject    : " + cert.SubjectName);
        Console.WriteLine("    - Issuer     : " + cert.IssuerName);
        Console.WriteLine("    - Validity   : " + cert.NotBefore + " - " + cert.NotAfter);
        try
        {
            Console.WriteLine("    - Fingerprint: " + FormatSha1Digest(new BigInteger(SHA1.Create().ComputeHash(cert.RawData)).ToByteArray(), "-"));
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }
        Console.WriteLine("    - Source     : " + cert.Source);
        Console.WriteLine("    - Validity   : " + ConstraintToString(cert.Validity));
    }
    else
    {
        Console.WriteLine("    - null");
    }
}			
private static String ConstraintToString(ConstraintResult constraint)
{
    return ConstraintToString(constraint.Indication, constraint.SubIndication, constraint.Message);
}			
private static String ConstraintToString(Indication indication, SubIndication subIndication, String message)
{
    return (indication == Indication.Valid ? "" : (indication == Indication.Indeterminate ? "?" : "!")) + "" +
        subIndication + " " +
        message;
}			
// SHA-1ダイジェスト文字列を生成するヘルパー関数
private static String FormatSha1Digest(byte[] bytes, String delimiter)
{
    var result = new StringBuilder();
    foreach (byte aByte in bytes)
    {
        int number = (int)aByte & 0xff;
        String hex = number.ToString("X2");
        result.Append(hex.ToUpper() + delimiter);
    }
    return result.ToString().Substring(0, result.Length - delimiter.Length);
}			
サンプル・プロジェクトの実行手順を参照してください
def constraint_to_string(indication: Indication, sub_indication: str, message: str, is_full_revision_covered: bool = None):
    # is_full_revision_covered が指定されている場合はバイト範囲の検証を処理する
    if is_full_revision_covered is None or is_full_revision_covered:
        indication_str = (
            "" if indication == Indication.VALID else
            "?" if indication == Indication.INDETERMINATE else
            "!"
        )
        return f"{indication_str}{sub_indication} {message}"

    byte_range_invalid = "!Invalid signature byte range."
    if indication == Indication.VALID:
        return byte_range_invalid
    else:
        return f"{byte_range_invalid} {sub_indication} {message}"			
def format_sha1_digest(fingerprint: str, delimiter: str):
    return delimiter.join(fingerprint[i:i+2] for i in range(0, len(fingerprint), 2))			
def print_certificate(cert: Certificate):
    if cert is not None:
        print(f"    - Subject    : {cert.subject_name}")
        print(f"    - Issuer     : {cert.issuer_name}")
        print(f"    - Validity   : {cert.not_before} - {cert.not_after}")
        try:
            # 整数のリストをバイトに変換
            raw_data_bytes = bytes(cert.raw_data)

            # hashlibを使ってFingerprint計算
            fingerprint = hashlib.sha1(raw_data_bytes).hexdigest().upper()
            print(f"    - Fingerprint: {format_sha1_digest(fingerprint, '-')}")
        except Exception as ex:
            print(str(ex))
        # 個々のデータソース名を抽出して表示
        sources = [source.name for source in DataSource if source in cert.source]
        print(f"    - Source     : {', '.join(sources)}")
        print(f"    - Validity   : {constraint_to_string(cert.validity.indication, cert.validity.sub_indication.name, cert.validity.message)}")
    else:
        print("    - null")			
def print_signature_content(content: SignatureContent, is_full_revision_covered: bool = None):
    if content is not None:
        print(f"  - Validity  : {constraint_to_string(content.validity.indication, content.validity.sub_indication.name, content.validity.message, is_full_revision_covered)}")

        if isinstance(content, UnsupportedSignatureContent):
            pass  # サポートされていないコンテンツに対する処理はしません
        elif isinstance(content, CmsSignatureContent):
            print(f"  - Validation: {content.validation_time} from {content.validation_time_source.name}")
            print(f"  - Hash      : {content.hash_algorithm.name}")
            print("  - Signing Cert")
            print_certificate(content.signing_certificate)
            print("  - Chain")
            for index, cert in enumerate(content.certificate_chain, start=1):
                print(f"  - Issuer Cert {index}")
                print_certificate(cert)
            print(f"  - Chain     : {'complete' if content.certificate_chain.is_complete else 'incomplete'} chain")
            print("  Time-Stamp")
            print_signature_content(content.time_stamp)
        elif isinstance(content, TimeStampContent):
            print(f"  - Validation: {content.validation_time} from {content.validation_time_source.name}")
            print(f"  - Hash      : {content.hash_algorithm.name}")
            print(f"  - Time      : {content.date}")
            print("  - Signing Cert")
            print_certificate(content.signing_certificate)
            print("  - Chain")
            for index, cert in enumerate(content.certificate_chain, start=1):
                print(f"  - Issuer Cert {index}")
                print_certificate(cert)
            print(f"  - Chain     : {'complete' if content.certificate_chain.is_complete else 'incomplete'} chain")
        else:
            print(f"Unsupported signature content type {str(type(content))}")
    else:
        print("  - null")			
def on_constraint_event(message: str, indication: Indication, sub_indication: SubIndication, signature: DocumentSignature, data_part: str):
    print(f"  - {signature.name}" + (f": {data_part}" if len(data_part) > 0 else "") + ": " +
          constraint_to_string(indication, sub_indication.name, message))			
def validate(input_file: str, cert_dir: str):
    # デフォルトの検証プロファイルを使用します
    profile = Default()

    # オフライン操作の場合は、ファイルシステムからカスタム信頼リストを構築し、外部失効チェックを無効にします
    if cert_dir:
        print("Using 'offline' validation mode with custom trust list.")
        print()

        # 証明書を保持するためのCustomTrustList(カスタム信頼リスト)を作成
        ctl = CustomTrustList()

        # 証明書ディレクトリ内のファイルを反復処理し、カスタム信頼リストに証明書を追加します
        if os.path.isdir(cert_dir):
            for file_name in os.listdir(cert_dir):
                try:
                    with io.FileIO(os.path.join(cert_dir, file_name), 'rb') as cert_stream:
                        if file_name.endswith(".cer") or file_name.endswith(".pem"):
                            ctl.add_certificates(cert_stream)
                        elif file_name.endswith(".p12") or file_name.endswith(".pfx"):
                            # If a password is required, use add_archive(certStr, password).
                            ctl.add_archive(cert_stream)
                except Exception as e:
                    print(f"Could not add certificate '{file_name}' to custom trust list: {e}")
        else:
            print(f"Directory {cert_dir} is missing. No certificates were added to the custom trust list.")
        print()

        profile.custom_trust_list = ctl

        # 検証オプションを構成
        validation_options = profile.validation_options
        validation_options.time_source = TimeSource.PROOF_OF_EXISTENCE | TimeSource.EXPIRED_TIME_STAMP | TimeSource.SIGNATURE_TIME
        validation_options.certificate_sources = DataSource.EMBED_IN_SIGNATURE | DataSource.EMBED_IN_DOCUMENT | DataSource.CUSTOM_TRUST_LIST

        # 失効チェックを無効にします
        profile.signing_cert_trust_constraints.revocation_check_policy = RevocationCheckPolicy.NO_CHECK
        profile.time_stamp_trust_constraints.revocation_check_policy = RevocationCheckPolicy.NO_CHECK

    # 文書内のすべての署名を検証する(最新のものだけでなく)
    signatureSelector = SignatureSelector.ALL

    # Validatorオブジェクトとイベントリスナーを作成
    validator = Validator()
    validator.add_constraint_handler(on_constraint_event)

    try:
        with io.FileIO(input_file, 'rb') as in_stream:
            # 入力文書をオープン
            # パスワードが必要な場合は、Open(inStr, password) を使用します
            with Document.open(in_stream) as document:
                print("Validation Constraints")
                results = validator.validate(document, profile, signatureSelector)
                print()
                print(f"Signatures validated: {len(results)}")
                print()

                for result in results:
                    field = result.signature_field
                    print(f"{field.field_name} of {field.name}")
                    try:
                        print(f"  - Revision  : {'latest' if field.revision.is_latest else 'intermediate'}")
                    except Exception as ex:
                        print(f"Unable to validate document Revision: {str(ex)}")

                    print_signature_content(result.signature_content, field.is_full_revision_covered)
                    print()
    except Exception as e:
        print(f"Unable to validate file: {e}")			
# オプションで: プロキシを指定できます
# Sdk.set_proxy("http://myproxy:8080")

validate(input_file, cert_dir)			

他の機能サンプルを参照してください。

お問い合わせ、ご質問、技術サポート

質問のページからお送りいただくようお願いします。
または、メールでsupport@trustss.co.jpあてにお送りください。


ご購入前の技術的質問も無償で対応します。サポート受付ページからお願いします。

> PDF Structure (PDF構成)

> PDF Imager-LP (画像化)

> PDF Stamper (電子印鑑)

> Pdftools SDK

- サンプル・コード
- Pdftools SDKサンプルの利用手順
- Toolbox Add-on
- Toolbox Add-onサンプルの利用手順
> Pdftools SDK APIリファレンス
- その他のAPI及びコマンドラインツール
> PDF SDK オープンソースと有償ライブラリ