Adobe Acrobat ProをVB.NETで操作して電子署名してみる

Acrobat ProをVB.NETとAcrobat提供のJavascriptライブラリを組み合わせることで色々なことができます。
以下覚書を兼ねつらつらと。

#電子署名を打ってみる
VB.NETからAcrobat Pro操作することができますが、電子署名を打つにはさらにJavascriptの力を借りる必要があります。

動作のイメージは、VB.NETアプリケーションからAcrobat Proのjavascriptディレクトリに配置しておいた自
前のjavascriptアプリケーションを呼び出し、そのjavascriptアプリケーションで電子署名を打つイメージです。

次のURLは電子署名を打つVB.NETソリューションです。このソリューションを使うには、次のカッコ数字の手順を踏む必要があります。
[電子署名を打つVB.NETソリューション:SilverCat](https://github.com/madilloar/PRJ_Silver)

(1).Acrobat Proのインストール。
試用版の状態でも余計なダイアログは表示されますが使えます(30日縛りだったっけ)。
私はこの投稿用のソリューションをテストするのに「Adobe Acrobat XI Pro」を試用版の状態でテストしています。

(2).Acrobat Proのインストールディレクトリにあるjavascriptディレクトリに、
`C:\Program Files (x86)\Adobe\Acrobat 11.0\Acrobat\Javascripts`
次のようなJavascriptファイルを置きます。
[電子署名を打つjavascriptファイル:SetSecurity.js](https://github.com/madilloar/PRJ_Silver/blob/master/SilverCat/SilverCat/resource/SetSecurity.js)

(3).Acrobat Proを起動してセキュリティポリシーを作ります。
編集パスワードなどのセキュリティポリシーの設定を作ります。セキュリティポリシー名は"PASSWORD_ENCRYPT_POLICY"で作ります。次のURL([セキュリティポリシーの設定方法](https://github.com/madilloar/PRJ_Silver/blob/master/SilverCat/SilverCat/resource/AcrobatPro%E3%82%BB%E3%82%AD%E3%83%A5%E3%83%86%E3%82%A3%E3%83%9D%E3%83%AA%E3%82%B7%E3%83%BC%E3%81%AE%E8%A8%AD%E5%AE%9A%E6%96%B9.pdf))に従って作ります。

(4).Acrobat Proを起動して電子署名の作成と表示方法の設定を作ります。
電子署名の作成と表示方法の設定を作ります。表示方法の設定名は"AppearanceSilverCatSignature"で作ります。次のURL([電子署名の作成と表示方法の設定]
(https://github.com/madilloar/PRJ_Silver/blob/master/SilverCat/SilverCat/resource/AcrobatPro%E9%9B%BB%E5%AD%90%E7%BD%B2%E5%90%8D%E4%BD%9C%E6%88%90%E3%81%A8%E8%A1%A8%E7%A4%BA%E6%96%B9%E6%B3%95%E3%81%AE%E8%A8%AD%E5%AE%9A%E6%96%B9.pdf))に従って作ります。

(5).VB.NETソリューションを実行する。

(6).ソリューション配下のdataディレクトリに、「電子署名したPDFファイル([sample_signed.pdf](https://github.com/madilloar/PRJ_Silver/blob/master/SilverCat/SilverCat/data/sample_signed.pdf))」などができているので、これをAdobe ReaderやAcrobat Proで開いて確認します。左上隅に電子署名のフィールドが打ってあれば成功です。
※電子署名の確認ができるPDFビューワーでないと見えませんのでご注意ください。

##呼び出し側のVB.NETのコード断片

```vb:
'' 自前のSignPdf.jsの引数をJSON形式で渡したいので、それを組み立てます。
Dim signParam As Hashtable = New Hashtable
Dim jsonSignParam As String
'' PDFファイルに打つ電子署名の矩形位置座標
signParam.Add("x", 1)
signParam.Add("y", 1)
signParam.Add("width", 36)
signParam.Add("height", 36)
'' 電子証明書のファイルフルパス。javascriptが解釈できるようにパス区切りはスラッシュ
signParam.Add("digitalIdFilePath","C:/temp/my_private_key.p12")
'' 電子証明書の秘密鍵パスワード
signParam.Add("password", "password!")
'' PDFファイルに施すセキュリティポリシー名。事前にAcrobat Proに登録しておく。
signParam.Add("securityPolicyName", "PASSWORD_ENCRYPT_POLICY")
'' 電子署名の作成と表示方法の設定名。事前にAcrobat Proに登録しておく。
signParam.Add("appearanceSignature", "AppearanceSilverCatSignature")
'' PDFファイルの受信者の公開鍵で暗号化する場合は、受信者の公開鍵を指定する。
'' セキュリティポリシーで暗号化する場合は、Nothing
signParam.Add("recipientPublicCerts", Nothing)
'' JavaScriptSerializerでJSON形式の文字列に変換
jsonSignParam = (New JavaScriptSerializer).Serialize(signParam).ToString()

''～～途中省略～～

'' 電子署名自体はJavascriptで行うので、ここではJavascriptを呼び出すイメージ。
'' フィールドにjavascriptの実行メソッドがあるので、フィールドを作る。
formApp = New AFormApp()
fields = CType(formApp.Fields, Fields)

'' 呼び出すメソッド名に先に作ったJSON形式引数を当て込んで呼び出す。
Dim jsCode As New StringWriter
jsCode.Write("SignToPdf(this, ")
jsCode.Write(jsonSignParam)
jsCode.Write(");")
Dim jsRc As String = fields.ExecuteThisJavascript(jsCode.ToString())
```

##呼び出される側のjavascriptコード断片
Acrobat Proのインストールディレクトリにあるjavascriptディレクトリに、
`C:\Program Files (x86)\Adobe\Acrobat 11.0\Acrobat\Javascripts`
次のようなJavascriptファイルを置く。
[電子署名を打つjavascriptファイル:SetSecurity.js](https://github.com/madilloar/PRJ_Silver/blob/master/SilverCat/SilverCat/resource/SetSecurity.js)

```js:SetSecurity.js
/**
* セキュリティポリシーを設定します。
* @param policy セキュリティポリシー名。
*/
SetSecurityPolicy = app.trustedFunction (
  function(doc, policy) {
    try {
      app.beginPriv();

      var sh = security.getHandler(security.PPKLiteHandler, false);

      // セキュティポリシーによるセキュリティ設定：
      // Acrobat Pro XIの場合：
      // 「表示(V)」「ツール(T)」でツールパネルを表示。
      // 「保護」アコーディオン、「暗号化」アコーディオンをクリックし、
      // 「セキュリティポリシーを管理(M)...」をクリック。
      // 「セキュリティポリシーの管理」ダイアログで登録したセキュリティーポリシーの名前で
      // 登録しておいたセキュリティポリシーにより、PDFファイルにセキュリティを設定する。

      // セキュリティポリシーの検索。
      var options = { cHandler:security.StandardHandler };
      var policyArray = security.getSecurityPolicies( { oOptions: options } );
      var myPolicy = null;
      for( var i = 0; i < policyArray.length; i++) {
        if( policyArray[i].name == policy ) {
            myPolicy = policyArray[i];
            break;
        }
      }
      // セキュリティポリシーの設定。
      var res = doc.encryptUsingPolicy({ oPolicy: myPolicy , oHandler: sh, bUI: false } );
      if( res.errorCode != 0 ) {
        throw res.errorText;
      }
      app.endPriv();
    } catch (e) {
      throw e;
    }
  }
);
/**
* 電子署名フィールドに電子署名を埋め込みます。
* @param sigField 電子署名フィールド。
* @param pwd 電子証明書パスワード。
* @param did 電子証明書ファイルのフルパス。
* @param appearanceSignature 電子署名の表示の仕方。
*/
EmbedSignToPdf = app.trustedFunction (
  function(doc, sigField, pwd, did, appearanceSignature) {
    try {
      app.beginPriv();

      var sh = security.getHandler(security.PPKLiteHandler, false);
      sh.login(pwd, did);
      // この電子証明書にログインするパスワードのタイムアウトはデフォルト、ゼロ秒。
      // デフォルト値のままだと、電子署名したかのように見えて、実は空振りするようなので、
      // よくわからないがゼロ秒じゃない値、例えば30秒を指定。
      sh.setPasswordTimeout(pwd, 30); 

      // 電子署名情報の設定。
      // mdp:"allowAll":普通署名。
      //     "allowNone","default","defaultAndComments":MDP署名。
      var sigInfo = {
        mdp: "allowNone",
        appearance: appearanceSignature
      };

      // 電子署名をする。
      sigField.signatureSign({oSig: sh, oInfo: sigInfo, bUI: false});

      app.endPriv();
    } catch (e) {
      throw e;
    }
  }
);
```