PadesLevels.cs
//
// このコードは、DioDocs for PDF のサンプルの一部として提供されています。
// © MESCIUS inc. All rights reserved.
//
using System;
using System.IO;
using System.Drawing;
using System.Text;
using System.Linq;
using System.Collections.Generic;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using GrapeCity.Documents.Pdf;
using GrapeCity.Documents.Pdf.Security;
using GrapeCity.Documents.Pdf.AcroForms;
using GrapeCity.Documents.Text;
namespace DsPdfWeb.Demos
{
// このサンプルでは、空の署名フィールドを含む既存の PDF ファイルに、
// PAdES(PDF 長期署名、PDF Advanced Electronic Signatures)標準の
// 様々な署名レベルに準拠した署名を行う方法を紹介しています。
// なお、オンラインで実行した場合、このサンプルは空の署名フィールドを含む
// 未署名の PDF を生成するだけになります。実際に PDF に署名するには、
// 有効な .pfx ファイル(「JohnDoe.pfx」を参照を用意する必要があります。
// サンプルには、様々な PAdES レベルにて PDF に署名するために使用できる
// 5つの方法が含まれており、最後の3つの方法を連鎖的に使用することで、
// 署名の強度を段階的に上げることができます。
// 署名のコンプライアンスを確認するには、Acrobat Reader で署名されたPDFを開き、
// 署名のプロパティを調べてください。
//
// 重要! このサンプルに含まれるコードは、DsPdf に有効な
// ライセンスキーが適用されていないと正しく動作しません。
public class PadesLevels
{
// 認証局が発行した証明書を設定します。検証に使用します。
static X509Certificate2 s_caCertRoot = new X509Certificate2(Path.Combine("Resources", "Misc", "CACertRoot.crt"));
// 注:実際の証明書に置き換えてください。
static X509Certificate2 s_cert = new X509Certificate2(Path.Combine("Resources", "Misc", "JohnDoe.pfx"), "secret");
static PadesLevels()
{
// 注:署名が有効なまま PDF を保存するには、ライセンスキーが適用されている必要があります。
// 適用されていない場合、PDF を保存する際に追加されるウォーターマークにより、
// 増分更新が無効になります。
// GcPdfDocument.SetLicenseKey("ライセンスキー");
}
public void CreatePDF(Stream stream, int paramsIdx = 0)
{
CreatePDF(stream, GetSampleParamsList()[paramsIdx]);
}
// このサンプルには、実際に署名やタイムスタンプを追加するコードが含まれていますが、
// そのコードはオンラインデモでは実行されません。そのため、オンラインサンプルでは、
// 選択された PAdES レベルに関する情報を含む PDF を生成するだけですが、
// 有効な証明書を使用すれば、実際に署名やタイムスタンプを追加できるようになります。
// 対応するコードをコピーして、アプリケーションで使用することもできます。
public void CreatePDF(Stream stream, string[] sampleParams)
{
// 注:署名/タイムスタンプを追加するコードを実際に実行するには、true に変更します。
bool doSigning = false;
// 空の署名フィールドを含む未署名の PDF を指定します。
var fn = Path.Combine("Resources", "PDFs", sampleParams[3]);
if (doSigning)
{
//このコードを実行すると、PAdES レベルが上がっていく5つのPDFが作成されます。
// PAdES B-B
Do_B_B(fn);
// PAdES B-T
Do_B_T(fn);
// なお、次の3つのステップでは、前のステップで作成されたPDFを使用して、
// 検証情報を段階的に追加していきます。
// PAdES B-LT
Do_B_LT("B-T.pdf");
// PAdES B-LTA
Do_B_LTA("B-LT.pdf");
// LTV(長期検証、Long-Term Validation) が可能
Do_B_LTA_LTV("B-LTA.pdf");
}
// デモ用の結果を出力するために、
// 出力ストリームに元となる PDF をコピーします。
using var fs = File.OpenRead(fn);
fs.CopyTo(stream);
}
// PAdES B-B レベルの署名にて PDF に署名します。
void Do_B_B(string fn)
{
using FileStream fs = File.OpenRead(fn);
var doc = new GcPdfDocument();
doc.Load(fs);
var signField = doc.AcroForm.Fields.FirstOrDefault(f_ => f_ is SignatureField);
if (signField == null)
throw new Exception("署名フィールドが見つかりませんでした。");
var sp = new SignatureProperties()
{
SignatureField = signField,
SignatureBuilder = new Pkcs7SignatureBuilder(s_cert)
{
Format = Pkcs7SignatureBuilder.SignatureFormat.ETSI_CAdES_detached,
},
};
// 署名して、PDF をファイルに保存します。
doc.Sign(sp, "B-B.pdf");
}
// PAdES B-T レベルの署名にて PDF に署名します。
void Do_B_T(string fn)
{
using FileStream fs = File.OpenRead(fn);
var doc = new GcPdfDocument();
doc.Load(fs);
var signField = doc.AcroForm.Fields.FirstOrDefault(f_ => f_ is SignatureField);
if (signField == null)
throw new Exception("署名フィールドが見つかりませんでした。");
var sp = new SignatureProperties()
{
SignatureField = signField,
SignatureBuilder = new Pkcs7SignatureBuilder(s_cert)
{
Format = Pkcs7SignatureBuilder.SignatureFormat.ETSI_CAdES_detached,
},
TimeStamp = new TimeStamp(@"http://ts.ssl.com"),
};
// 署名して、PDF をファイルに保存します。
doc.Sign(sp, "B-T.pdf");
}
// PAdES B-T レベルの署名(例:上記の Do_B_T メソッドで作成されたもの)に LTV 情報を追加し、
// PAdES B-LT レベルに準拠した署名にします。
void Do_B_LT(string fn)
{
using FileStream fs = File.OpenRead(fn);
var doc = new GcPdfDocument();
doc.Load(fs);
var signField = doc.AcroForm.Fields.FirstOrDefault(f_ => f_ is SignatureField);
if (signField == null)
throw new Exception("署名フィールドが見つかりませんでした。");
// 署名を取得し、その署名に対する検証情報を追加します。
var sig = (Signature)signField.Value;
var vp = new DocumentSecurityStore.VerificationParams();
vp.Certificates = new X509Certificate2[] { s_caCertRoot };
if (!doc.SecurityStore.AddVerification(sig, vp))
throw new Exception($"{sig.Name} に対する検証を追加できませんでした。");
// 署名が有効なままになるように、増分更新で PDF をファイルに保存します。
doc.Save("B-LT.pdf", SaveMode.IncrementalUpdate);
}
// 署名された PDF(例:上記の Do_B_LT メソッドで作成されたもの)にタイムスタンプを追加し、
// PAdES B-LTA レベルに準拠したドキュメントにします。
void Do_B_LTA(string fn)
{
using FileStream fs = File.OpenRead(fn);
var doc = new GcPdfDocument();
doc.Load(fs);
var ts = new TimeStampProperties()
{
TimeStamp = new TimeStamp(@"http://ts.ssl.com"),
};
// PDF にタイムスタンプを追加してファイルに保存します。
doc.TimeStamp(ts, "B-LTA.pdf");
}
// PDF のタイムスタンプ(例:上記の Do_B_LTA メソッドで作成されたもの)に対して
// 検証情報を追加し、LTV が可能な署名にします。
void Do_B_LTA_LTV(string fn)
{
using FileStream fs = File.OpenRead(fn);
var doc = new GcPdfDocument();
doc.Load(fs);
var signField = doc.AcroForm.Fields.FirstOrDefault(f_ => f_ is SignatureField);
if (signField == null)
throw new Exception("署名フィールドが見つかりませんでした。");
// 署名を取得し、その署名に対する検証情報を追加します。
var sig = (Signature)signField.Value;
if (!doc.SecurityStore.AddVerification(sig))
throw new Exception($"{sig.Name} に対する検証を追加できませんでした。");
// 署名が有効なままになるように、増分更新で PDF をファイルに保存します。
doc.Save("B-LTA_LTV.pdf", SaveMode.IncrementalUpdate);
}
public static List<string[]> GetSampleParamsList()
{
// このリストでは、サンプルの名前、説明、情報、読み込む PDF ファイルを保持しています。
return new List<string[]>()
{
new string[] { "@b-sign/PAdES B-B レベル", "PDF へ PAdES の B-B レベルに準拠した署名を行う", "",
"PAdES-B-B.pdf" },
new string[] { "@b-sign/PAdES B-T レベル", "PDF へ PAdES の B-T レベルに準拠した署名を行う", "",
"PAdES-B-T.pdf" },
new string[] { "@b-sign/PAdES B-LT レベル", "署名に長期検証情報を追加する", "",
"PAdES-B-LT.pdf" },
new string[] { "@b-sign/PAdES B-LTA レベル", "署名された PDF にタイムスタンプを追加する", "",
"PAdES-B-LTA.pdf" },
new string[] { "@b-sign/長期検証可能な署名", "長期検証が可能な署名を作成する", "",
"PAdES-B-LTA-LTV.pdf" },
};
}
}
}