はじめに
証明書ファイル(PFXファイル)を用いて、VBAからAdobe Acrobatを制御してPDFファイルのデジタル署名をしましたので、その方法について整理しました。
環境
・Windows 10 Pro
・Microsoft 365 (Excel)
・Adobe Acrobat Pro
署名方法
事前設定
Acrobatを起動して「メニュ」の「編集」→「環境設定」→分類で「セキュリティ(拡張)」を選択後、「サンドボックスによる保護」の「起動時に保護モードを有効にする」のチェックを外す必要があります。
VBAからAcrobatを制御するためには
VBAの参照設定でAcrobatのライブラリーを参照することで、PDFファイルを開くなど、一部のAcrobat機能を制御することはできますが、ほとんどの機能を制御することはまだできません。
より多くの機能を制御するため(デジタル証明するため)には、「JSObject」というオブジェクトを呼び出す必要があります。
JSObjectを使うと、Acrobat JavaScriptの機能を使うことができます。
(しかし、VBAからはJavaScriptで使うオブジェクト形式などを作ることができないので、使えられる機能もあります。)
レファレンスは以下のURLで確認できます。
処理の流れ
- PDFファイルを開く
- JSObjectを呼び出す
- 証明書ログインする
- PDFファイルに署名フィールドを生成する
- 署名フィールドに署名を追加してファイルを出力する
- 証明書ログアウトする
- PDFファイルを閉じる
コードの例
Public Sub CreateSignaturePdf()
Dim acroPdObj As New Acrobat.AcroPDDoc
Dim acroAvObj As New Acrobat.AcroAVDoc
Dim jsObj As Object
Dim objSign As Object
Dim signatureCoords() As Variant
Dim signField As Object
Dim bottomLeftX As Long
Dim bottomLeftY As Long
Dim signWidth As Long
Dim signHeight As Long
Dim targetFilePath As String
Dim certFilePath As String
Dim certPassword As String
Dim outputFilePath As String
targetFilePath = "C:\SignTest\Input\TargetPdf.pdf"
certFilePath = "C:\SignTest\Certificate\Certificate.pfx"
certPassword = "password"
outputFilePath = "C:\SignTest\Output\SignedPdf.pdf"
' 署名を表示する場合、適切に値を設定します
bottomLeftX = 200
bottomLeftY = 100
signWidth = 200
signHeight = 100
' PDFファイルを開く
If acroPdObj.Open(targetFilePath) Then
Set acroAvObj = acroPdObj.OpenAVDoc(targetFilePath)
' JSObjectを定義する
Set jsObj = acroPdObj.GetJSObject
' SecurityHandlerを生成
' https://opensource.adobe.com/dc-acrobat-sdk-docs/library/jsapiref/JS_API_AcroJS.html#gethandler
Set objSign = jsObj.security.getHandler("Adobe.PPKLite")
' 証明書ログイン
' https://opensource.adobe.com/dc-acrobat-sdk-docs/library/jsapiref/JS_API_AcroJS.html#login
Call objSign.login(certPassword, certFilePath)
' パスワードのタイムアウトを設定
' https://opensource.adobe.com/dc-acrobat-sdk-docs/library/jsapiref/JS_API_AcroJS.html#setpasswordtimeout
Call objSign.setPasswordTimeout(certPassword, 30)
' 署名を付ける座標を設定する
signatureCoords = Array(bottomLeftX, bottomLeftY + signHeight, bottomLeftX + signWidth, bottomLeftY)
' 署名フィールドを生成
' https://opensource.adobe.com/dc-acrobat-sdk-docs/library/jsapiref/doc.html#addfield
Set signField = jsObj.addField("MySignatureField", "signature", 0, signatureCoords)
' デジタル署名する
' https://opensource.adobe.com/dc-acrobat-sdk-docs/library/jsapiref/JS_API_AcroJS.html#id652
Call signField.signatureSign(objSign, Array(), outputFilePath, False)
' 証明書ログアウト
Call objSign.logout
' PDFファイルを閉じる
Call acroAvObj.Close(1)
Call acroPdObj.Close
End If
Set acroPdObj = Nothing
Set jsObj = Nothing
Set objSign = Nothing
End Sub
コード例の説明
Dim acroPdObj As New Acrobat.AcroPDDoc
Dim acroAvObj As New Acrobat.AcroAVDoc
...
' PDFファイルを開く
If acroPdObj.Open(targetFilePath) Then
Set acroAvObj = acroPdObj.OpenAVDoc(targetFilePath)
PDFファイルを開きます。
Acrobat.AcroPDDocでPDFを開いたら、バックグラウンドでAcrobatが起動しますが、デジタル署名は、Acrobatがバックグラウンドの状態ではうまく動作できない場合があります。
そのため、Acrobat.AcroAVDocでファイルを開くようにして、Acrobatが画面上で表示するようにします。
' JSObjectを定義する
Set jsObj = acroPdObj.GetJSObject
JSObjectを取得します。
JSObjectは、Acrobat.AcroPDDocから取得できます。
' SecurityHandlerを生成
' https://opensource.adobe.com/dc-acrobat-sdk-docs/library/jsapiref/JS_API_AcroJS.html#gethandler
Set objSign = jsObj.security.getHandler("Adobe.PPKLite")
' 証明書ログイン
' https://opensource.adobe.com/dc-acrobat-sdk-docs/library/jsapiref/JS_API_AcroJS.html#login
Call objSign.login(certPassword, certFilePath)
' パスワードのタイムアウトを設定
' https://opensource.adobe.com/dc-acrobat-sdk-docs/library/jsapiref/JS_API_AcroJS.html#setpasswordtimeout
Call objSign.setPasswordTimeout(certPassword, 30)
証明書を使うため、SecurityHandlerを生成します。
Handlerは、例の「Adobe.PPKLite」以外にも、下記のURLの方法で使用できるものを確認することができます。
その後、証明書ファイルにログインします。
また、パスワードのタイムアウトを設定します。
(タイムアウト時間をデフォルト値(0)にすると、正しく署名処理ができない場合があります。)
' 署名を表示する場合、適切に値を設定します
bottomLeftX = 200
bottomLeftY = 100
signWidth = 200
signHeight = 100
...
' 署名を付ける座標を設定する
signatureCoords = Array(bottomLeftX, bottomLeftY + signHeight, bottomLeftX + signWidth, bottomLeftY)
' 署名フィールドを生成
' https://opensource.adobe.com/dc-acrobat-sdk-docs/library/jsapiref/doc.html#addfield
Set signField = jsObj.addField("MySignatureField", "signature", 0, signatureCoords)
署名を表示する位置を指定して、PDFファイルに署名を付けるFieldを追加します。
署名位置は、(x1, y1, x2, y2)であり、「x1 = x2」かつ「y1 = y2」の場合、非表示で署名を付けます。
' bottomLeftX = 200
' bottomLeftY = 100
' signWidth = 0
' signHeight = 0
signatureCoords = Array(200, 100, 200, 100)
「addField」は、以下のように構成されます。
パラメーター | 説明 | 例 |
---|---|---|
cName | フィールド名 自由に設定 |
"MySignatureField" |
cFieldType | フィールドタイプ 「signature」に固定 |
"signature" |
nPageNum | ページ番号 0から始める |
0 |
oCoords | 署名表示の座標 配列 |
Array(200, 100, 400, 200) |
詳細は以下のレファレンスを確認してください。
' デジタル署名する
' https://opensource.adobe.com/dc-acrobat-sdk-docs/library/jsapiref/JS_API_AcroJS.html#id652
Call signField.signatureSign(objSign, Array(), outputFilePath, False)
指定したフィールドにデジタル署名を付けて、ファイルを出力します。
「signatureSign」は、以下のように構成されます。
パラメーター | 説明 | 例 |
---|---|---|
oSig | SecurityHandlerのオブジェクト | objSign |
oInfo | SignatureInfoのオブジェクト VBAからは作成できない形式 |
Array() |
cDIPath | 出力ファイルパス | "C:\SignTest\Output\SignedPdf.pdf" |
bUI | 署名のためのユーザインタフェース表示 「True」の場合、署名ダイアログから署名 「False」(デフォルト)の場合、ユーザインタフェースなしで署名 |
False |
' 証明書ログアウト
Call objSign.logout
' PDFファイルを閉じる
Call acroAvObj.Close(1)
Call acroPdObj.Close
End If
証明書ログアウトして、PDFファイルを閉じます。
参考