第３回 SmartHRのライブラリkijiを使ってe-Govを動かす（実行環境構築編）

kijiは、SmartHRに組み込まれているライブラリであり、GitHubで公開されています。このライブラリはRubyで作られたOSSであり、誰でも入手・改造・再頒布が可能です。
[SmartHR kiji](https://GitHub.com/kufu/kiji)

ここでは、kijiを呼び出して署名付きxmlを生成するドライバーを開発します。

本編以外にも、[e-Gov仕様編](https://qiita.com/itaruMatumoto/items/a4a4d74b5a1ff9ea0b8b "第１回 SmartHRのライブラリkijiを使ってe-Govを動かす（e-Gov仕様編）")、[e-Gov公開資料編](https://qiita.com/itaruMatumoto/items/019818d06e2e790dbc2c "第２回 SmartHRのライブラリkijiを使ってe-Govを動かす（e-Gov公開資料編）")、[動作確認編](https://qiita.com/itaruMatumoto/items/318c9aaa74d238b58941 "第４回 SmartHRのライブラリkijiを使ってe-Govを動かす（動作確認編）")がありますので、必要に応じて参照して下さい。

#１．kijiのフォルダ構成
GitHubからkijiをダウンロードします。フォルダ構成は次のとおりです。

```:kiji-masterフォルダ構成
kiji-master/
        ├ bin/
        ├ lib/         # 開発ソース一式
        │  └ kiji/
        └ spec/        # テスト環境一式
```

kiji-master直下にあるlibに開発ソース一式、specにテスト環境一式があります。kiji-master直下にあるkiji.gemspecを確認すると、kijiが依存する他のgemパッケージのバージョンを確認できます。

後述しますが、開発ソースを一部修正する必要が生じたため、ローカル環境でkijiをビルドしました。kiji.gemspecのspec.filesよりGitHubからファイル一覧を取得するようになっていたので、ローカルフォルダーから取得するように変更しました。

lib内の開発ソースを以下に示します。

```:libフォルダ構成
lib/
  ├ kiji.rb
  └ kiji/
       ├ access.rb
       ├ api.rb
       ├ authentication.rb
       ├ client.rb
       ├ digester.rb
       ├ signer.rb
       ├ version.rb
       └ zipper.rb
```

kiji.rbを確認すると、アプリケーションが、version.rb、client.rb、zipper.rbを直接取り込んでいる事が分かります。

```ruby:kiji.rb
require 'kiji/version.rb'
require 'kiji/client.rb'
require 'kiji/zipper.rb'
```

#２．kijiの構造について
kijiは４つのクラスと２つのモジュールから構成されます。

```:kijiの構造
module kiji
  ├ class Zipper             # zipファイルに固める  
  ├ class Client             # e-Gov外部連携APIに送信  
  ├ class Signer             # 署名付きxml作成  
  ├ class Digester           # デジタル署名作成  
  ├ module Authentication    # 認証関係のユーティリティ  
  └ module Access            # e-Gov関係のユーティリティ
```

４つのクラスの階層としては、class Zipperとclass Clientが最上位にあり、その下にclass Signer、class Digesterと続きます。クラス図で書くと次のようになります。
![kijiクラス関連図.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/659913/98033992-d132-6ddf-0b35-9c3dfecc8ec5.png)

e-Gov電子申請は、次の手順で行われます。

①署名付きxmlを作成する
②署名付きxml、添付ファイル等をzipファイルに固める
③zipファイルをBase64形式にエンコードして、送信データに格納する
④e-Gov外部連携APIのhttpリクエストボディに③を設定した上で送信する

class Zipperは①②、class Clientは③④の機能を持ちます。

今回は、class Zipperを利用して①②を行い、e-Govへの送信はcurlコマンドを利用する事にしました。これは、署名付きxmlの内容及びe-Govからのレスポンスを確認するためです。

#３．windows環境の改行コードに起因するkijiの修正
zipper.rbにて、申請書のハッシュ値を計算する際、署名対象となるxmlを読み込む箇所に問題があり、コードを修正しました。

オリジナルのコード「app_doc = File.read(app_file_path)」では、xmlをテキストモードで読み込むため、windows形式の改行コード"\r\n"を内部で自動的に"\n"に置き換えてしまい、その結果に対してハッシュ値を計算していました。そのため、改行コードの置き換えをしないバイナリモードで読み込むように修正しました。

```ruby:zipper.rb
      # 申請書のハッシュ値を求める
      app_file_paths.each do |app_file_path|
-       app_doc = File.read(app_file_path)
+       f = File.open(app_file_path, "rb")
+       app_doc = f.read
        app_file_name = File.basename(app_file_path)
        signer.digest_file!(app_doc, id: app_file_name)
      end
```

これによって、ローカルgemを作成する事になりました。kiji.gemspecのspec.filesをローカル先に変更した後、kijiをビルドして、ローカル環境にインストールしました。

```:kijiビルド
\kiji-master>rake build
kiji 0.2.2 built to pkg/kiji-0.2.2.gem.


\kiji-master>dir pkg
2020/08/21  11:42    <DIR>          .
2020/08/21  11:42    <DIR>          ..
2020/08/16  20:54            13,312 kiji-0.2.2.gem


\kiji-master>gem install pkg\kiji-0.2.2.gem
Successfully installed kiji-0.2.2
Parsing documentation for kiji-0.2.2
Installing ri documentation for kiji-0.2.2
Done installing documentation for kiji after 0 seconds
1 gem installed

```

#４．テストデータを用意する
一括申請を行う際に必要になるテストデータを用意します。テストデータとしては、標準形式及び個別ファイル署名形式があります。この際、参照すべき公開資料としては、検証環境テスト用手続に関する資料です。公開資料「APIテスト用手続一覧」には、以下の情報が掲載されています。

```:APIテスト用手続一覧
手続情報
├ 手続識別子
├ 手続名称（構成管理XMLの「手続名称タグ」に記載する名称）
├ 様式ID
├ 申請書様式名称
├ 申請書様式仕様パターン
├ 受付行政機関ID
├ 分類
├ ひな形とした手続に関する情報
│    ├ 手続識別子
│    └ 手続名
├ 手続に関する条件
│    ├ 申請種別
│    ├ 申請書（手続識別子、申請書様式バージョン）
│    ├ 署名（有無、署名最大人数）
│    ├ 添付書類（有無、必須/任意/添付不可、書類名、固定/任意、書類名、送付方法）
│    ├ 提出先（提出先識別子、提出先名称、大分類、中分類、小分類）
│    ├ 単様式/複数様式
│    ├ 取下げ方法
│    ├ 府省照会有無
│    ├ 手数料種別
│    ├ 受付期間
│    ├ 様式
│    ├ 手続削除フラグ
│    └ ステータス自動遷移対象
└ 到達以降の可能処理
     ├ 取下げ（なし、依頼、申請）
     ├ 補正（なし、部分補正、再提出、補正申請）
     ├ 公文書発出（なし、あり）
     ├ 手数料登録(後納)（なし、あり）
     ├ 手続終了（通知、取下げ済み、再提出済み、公文書取得最終）
     └ コメント通知（なし、メッセージあり、ファイルあり）
```

また、公開資料「APIテスト用手続ステータス遷移一覧」には、新規申請、取下げ依頼、取下げ申請、補正申請毎に、以下の情報が掲載されています。

```:APIテスト用手続ステータス遷移一覧
ステータス遷移一覧
├ 手続識別子
├ 手続名
├ 申請に対する操作／処理
│    ├ 取下げ
│    ├ 補正申請
│    ├ コメント通知
│    ├ 公文書発出
│    └ 納付ｽﾃｰﾀｽ変更
├ 申請ステータスとアクション
│    ├ 申請の事前状態
│    │   ├ 対象の申請
│    │   └ 申請ステータス（申請サブステータス）
│    ├ アクション
│    │   ├ 利用者側の操作
│    │   └ e-Gov側処理の有無
│    └ 申請の事後状態
│         ├ 対象の申請
│         └ 申請ステータス（申請サブステータス）
└ 備考
```

これらの資料を参考にして、目的とするテストを実施できるようにテストデータを作成します。

##４．１　標準形式
テストデータとして、手続識別子「900A010200001000」を取り上げます。この手続は「雇用保険被保険者資格取得届／電子申請」です。添付書類が必須であり、公文書の発出はありません。

必要なファイルは以下の通りです。ファイル名称については、公開資料「外部連携 API申請データ仕様 共通データ仕様書」で仕様が決められているので、その規則に従います。

| No | ファイル種別 | ファイル名称 | 備考 |
|:--:|:-------|:-------|:-------|
| 1 | 構成管理XML | kousei.xml | |
| 2 | 申請書XML | 900A01020000100001_01.xml | 様式ID（半角英数字18桁）＋「_01」固定 |
| 3 | 添付書類 | 添付ファイル.docx | |

これらのファイルは次の階層になっています。

```:ファイル階層
kousei.xml
      ├ 900A01020000100001_01.xml
      └ 添付ファイル.docx
```

構成管理XML（kousei.xml）に必要な情報は、以下のとおりです。

| No | 項目 | 内容 | 備考 |
|:--:|:-------|:-------|:-------|
| 1 | 手続識別子 | 900A010200001000 | |
| 2 | 手続名称 | ＡＰＩテスト用手続（労働保険関係手続）（通）０００１／ＡＰＩテスト用手続（労働保険関係手続）（通）０００１ | 構成管理XMLの「手続名称タグ」に記載する名称 |
| 3 | 様式ID | 900A01020000100001 | |
| 4 | 申請書様式名称 | ＡＰＩテスト用手続（労働保険関係手続）（通）０００１＿０１ | |
| 5 | 申請書様式仕様パターン | 0001 | 申請書XML構造定義【APIテスト用手続き】におけるパターン |
| 6 | 受付行政機関ID | 100900 | |

構成管理XML（kousei.xml）に記載する手続きに関する条件については、以下のとおりです。

| No | 項目 | 内容 | 備考 |
|--:|:-------|:-------|:-------|
| 1 | 申請種別 | 通常申請 | |
| 2 | 申請書-手続識別子（申請書） | 900A010200001000 | |
| 3 | 申請書-申請書様式バージョン | 0003 | |
| 4 | 署名-有無 | 署名あり（単署） | |
| 5 | 署名-署名最大人数  | 1 | |
| 6 | 添付書類-有無 | 有 | |
| 7 | 添付書類-必須/任意 | 必須 | |
| 8 | 添付書類-書類名固定/任意 | 書類名固定 | 書類名を「テスト添付書類１」とする |
| 9 | 添付書類-書類名 | テスト添付書類１ | |
| 10 | 添付書類-送付方法 | 添付 | |
| 11 | 提出先-提出先識別子 | 900API00000000001001001 | |
| 12 | 提出先-提出先名称 | 総務省,行政管理局,API | |

これらの情報を構成管理XML（kousei.xml）のタグに埋め込みます。

```:kousei.xml
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="999000000000000001.xsl" type="text/xsl"?>
<DataRoot>
  <様式ID>999000000000000001</様式ID>
  <様式バージョン>0001</様式バージョン>
  <STYLESHEET>999000000000000001.xsl</STYLESHEET>
  <構成情報 ID="構成情報">
    <管理情報>
      <手続番号>
        <受付行政機関ID>100900</受付行政機関ID>
        <手続ID>900A010200001000</手続ID>
      </手続番号>
      <手続名称>ＡＰＩテスト用手続（労働保険関係手続）（通）０００１／ＡＰＩテスト用手続（労働保険関係手続）（通）０００１</手続名称>
      <初回受付番号/>
      <申請種別>新規申請</申請種別>
      <申請者連絡先情報>
        <申請者情報>
          <氏名>ほげ　ほげ</氏名>
          <氏名フリガナ>フリ　ガナ</氏名フリガナ>
          <役職/>
          <法人団体名/>
          <法人団体名フリガナ/>
          <部門名/>
          <部門名フリガナ/>
          <郵便番号>1200001</郵便番号>
          <住所>東京都足立区大谷田</住所>
          <住所フリガナ>トウキョウトアダチクオオヤタ</住所フリガナ>
          <電話番号>12-232-1232</電話番号>
          <FAX番号/>
          <電子メールアドレス>zzz@zzz.zz</電子メールアドレス>
        </申請者情報>
        <連絡先情報>
          <氏名>漢　字</氏名>
          <氏名フリガナ>フリ　ガナ</氏名フリガナ>
          <役職/>
          <法人団体名/>
          <法人団体名フリガナ/>
          <部門名/>
          <部門名フリガナ/>
          <郵便番号>1200001</郵便番号>
          <住所>東京都足立区大谷田</住所>
          <住所フリガナ>トウキョウトアダチクオオヤタ</住所フリガナ>
          <電話番号>12-232-1232</電話番号>
          <FAX番号/>
          <電子メールアドレス>zzz@zzz.zz</電子メールアドレス>
        </連絡先情報>
        <委任登録票添付情報>
          <発行番号/>
          <委任登録票名称/>
          <委任登録票ファイル名称/>
        </委任登録票添付情報>
      </申請者連絡先情報>
    </管理情報>
    <添付書類属性情報>
      <添付種別>添付</添付種別>
      <添付書類名称>テスト添付書類１</添付書類名称>
      <添付書類ファイル名称>添付ファイル.docx</添付書類ファイル名称>
      <提出情報>1</提出情報>
    </添付書類属性情報>
    <手数料情報>
      <手数料1>
        <手数料識別子/>
        <略科目コード/>
        <略科目名/>
        <振込金額/>
      </手数料1>
      <手数料2>
        <手数料識別子/>
        <略科目コード/>
        <略科目名/>
        <振込金額/>
      </手数料2>
      <手数料3>
        <手数料識別子/>
        <略科目コード/>
        <略科目名/>
        <振込金額/>
      </手数料3>
      <手数料4>
        <手数料識別子/>
        <略科目コード/>
        <略科目名/>
        <振込金額/>
      </手数料4>
      <手数料5>
        <手数料識別子/>
        <略科目コード/>
        <略科目名/>
        <振込金額/>
      </手数料5>
      <手数料6>
        <手数料識別子/>
        <略科目コード/>
        <略科目名/>
        <振込金額/>
      </手数料6>
    </手数料情報>
    <通信欄/>
    <府省照会情報>
      <府省照会1>
        <府省照会情報ラベル/>
        <府省照会情報/>
      </府省照会1>
      <府省照会2>
        <府省照会情報ラベル/>
        <府省照会情報/>
      </府省照会2>
      <府省照会3>
        <府省照会情報ラベル/>
        <府省照会情報/>
      </府省照会3>
      <府省照会4>
        <府省照会情報ラベル/>
        <府省照会情報/>
      </府省照会4>
      <府省照会5>
        <府省照会情報ラベル/>
        <府省照会情報/>
      </府省照会5>
      <府省照会6>
        <府省照会情報ラベル/>
        <府省照会情報/>
      </府省照会6>
      <府省照会7>
        <府省照会情報ラベル/>
        <府省照会情報/>
      </府省照会7>
      <府省照会8>
        <府省照会情報ラベル/>
        <府省照会情報/>
      </府省照会8>
      <府省照会9>
        <府省照会情報ラベル/>
        <府省照会情報/>
      </府省照会9>
      <府省照会10>
        <府省照会情報ラベル/>
        <府省照会情報/>
      </府省照会10>
    </府省照会情報>
    <提出先情報>
      <提出先識別子>900API00000000001001001</提出先識別子>
      <提出先名称>総務省,行政管理局,API</提出先名称>
    </提出先情報>
  <申請書属性情報><申請書様式ID>900A01020000100001</申請書様式ID><申請書様式バージョン>0003</申請書様式バージョン>
  <申請書様式名称>ＡＰＩテスト用手続（労働保険関係手続）（通）０００１＿０１</申請書様式名称><申請書ファイル名称>900A01020000100001_01.xml</申請書ファイル名称></申請書属性情報></構成情報>
</DataRoot>
```
申請書XML（900A01020000100001_01.xml）について、次のように作成します。

```:900A01020000100001_01.xml
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="900A01020000100001.xsl" ?>
<DataRoot>
  <様式ID>900A01020000100001</様式ID>
  <様式バージョン>0003</様式バージョン>
  <STYLESHEET>900A01020000100001.xsl</STYLESHEET>
  <様式コピー情報>0</様式コピー情報>
  <Doctype>1</Doctype>
  <G00005-A-250045-001_1>
  <帳票種別>13101</帳票種別>
  <被保険者番号>
    <被保険者番号4桁></被保険者番号4桁>
    <被保険者番号6桁></被保険者番号6桁>
    <被保険者番号CD></被保険者番号CD>
  </被保険者番号>
  <取得>1</取得>
  <被保険者氏名>えーぴーあい　太郎</被保険者氏名>
  <被保険者氏名フリガナ>エーピーアイ　タロウ</被保険者氏名フリガナ>
  <変更後の氏名></変更後の氏名>
  <変更後の氏名フリガナ></変更後の氏名フリガナ>
  <性別>男</性別>
  <生年月日>
    <年号>昭和</年号>
    <年>59</年>
    <月>5</月>
    <日>23</日>
  </生年月日>
  <事業所番号>
    <事業所番号4桁>1111</事業所番号4桁>
    <事業所番号6桁>222222</事業所番号6桁>
    <事業所番号CD>3</事業所番号CD>
  </事業所番号>
  <資格取得年月日>
    <年号>平成</年号>
    <年>27</年>
    <月>4</月>
    <日>9</日>
  </資格取得年月日>
  <被保険者となったことの原因>1</被保険者となったことの原因>
  <賃金>
    <支払の態様>1</支払の態様>
    <賃金月額>500</賃金月額>
  </賃金>
  <雇用形態>7</雇用形態>
  <職種>1</職種>
  <取得時被保険者種類区分/>
  <番号複数取得チェック不要/>
  <契約期間の定め>有</契約期間の定め>
  <契約期間の定めの有無>
    <契約期間の定め有>
      <契約期間開始>
        <年号>平成</年号>
        <年>27</年>
        <月>4</月>
        <日>9</日>
      </契約期間開始>
      <契約期間終了>
        <年号>平成</年号>
        <年>28</年>
        <月>3</月>
        <日>31</日>
      </契約期間終了>
      <契約更新条項有無>有</契約更新条項有無>
    </契約期間の定め有>
  </契約期間の定めの有無>
  <一週間の所定労働時間>
    <時間>40</時間>
    <分>0</分>
  </一週間の所定労働時間>
  <事業所名称>株式会社試験</事業所名称>
  <備考欄_申請者>
    <国籍/>
    <在留資格/>
    <在留期間>
      <年/>
      <月/>
      <日/>
    </在留期間>
    <資格外活動許可の有無/>
    <派遣請負労働者/>
    <備考/>
  </備考欄_申請者>
  <事業主>
    <住所>東京都</住所>
    <氏名>テストオーナー</氏名>
    <電話番号>
      <市外局番>03</市外局番>
      <市内局番>3030</市内局番>
      <加入者番号>3333</加入者番号>
    </電話番号>
  </事業主>
  <届出年月日>
    <年号>平成</年号>
    <年>27</年>
    <月>4</月>
    <日>1</日>
  </届出年月日>
  <あて先>品川</あて先>
  <社会保険労務士記載欄>
    <作成年月日>
      <年号>平成</年号>
      <年></年>
      <月></月>
      <日></日>
    </作成年月日>
    <提出代行者事務代理者の表示></提出代行者事務代理者の表示>
    <氏名></氏名>
    <電話番号>
      <市外局番></市外局番>
      <市内局番></市内局番>
      <加入者番号></加入者番号>
    </電話番号>
    <付記欄></付記欄>
  </社会保険労務士記載欄>
  <備考欄_職員>
    <備考></備考>
    <確認通知年月日>
      <年号>平成</年号>
      <年></年>
      <月></月>
      <日></日>
    </確認通知年月日>
  </備考欄_職員>
  <Xmit>0</Xmit>
</G00005-A-250045-001_1>
</DataRoot>
```

各タグにおけるデータの省略可否、文字数、文字種別等の制約を遵守すれば、形式チェック等は問題なく通ります。テストデータであるため、架空の内容で大丈夫です。

##４．２　個別ファイル署名形式
テストデータとして、手続識別子「950A102200039000」を取り上げます。この手続は、「国民年金被保険者資格取得・種別変更・種別確認（第３号被保険者該当）届書／電子申請」です。添付書類が不要であり、公文書が発出されます。

必要なファイルは以下の通りです。

| No | ファイル種別 | ファイル名称 | 備考 |
|:--:|:-------|:-------|:-------|
| 1 | 構成管理XML | kousei.xml | |
| 2 | 申請書XML① | 950A10220003900001_01.xml | 様式ID（半角英数字18桁）＋「_01」固定 |
| 3 | 申請書に対する構成情報XML① | kousei20200716142110000.xml | ‘kousei’＋ yyyyMMddHHmmssSSS |
| 4 | 申請書XML② | 950A10220003900002_01.xml | |
| 5 | 申請書に対する構成情報XML② | kousei20200716142115000.xml | |

申請書に対する構成情報XMLにおける「yyyyMMddHHmmssSSS」 は、申請案件フォルダ内でファイル名を一意とするために付加する当該ファイルの作成日付と時刻（100 分の 1 秒単位）です。これについても、公開資料「外部連携 API申請データ仕様 共通データ仕様書」に記載されています。

これらのファイルは次のような階層になっています。

```:ファイル階層
kousei.xml
      ├ 950A10220003900001_01.xml
      ├ kousei20200716142110000.xml
      ├ 950A10220003900002_01.xml
      └ kousei20200716142115000.xml
```

具体的なxmlの内容については、[GitHub](https://github.com/itaruMatumoto/eGovSignedXmlCreationEnvironment/tree/master/zip_data/indivisual/in/950A102200039000(1) "個別ファイル署名形式")にありますので、必要に応じて参照して下さい。

#５．データ変換ツールについて
今後、テストデータを作成して動作確認を行う際、[データ変換ツール](https://hogehoge.tk/tool/)を利用します。このツールでは、ハッシュ値の計算、Base64形式エンコード又はデコード、エンコード又はデコード結果のファイルへの出力等を行う事ができます。次のケースでツールを利用します。

- 署名付きxml生成ドライバーで計算したハッシュ値を検証する
- 申請データを作成するため、Zip形式の申請データセットをBase64形式にエンコードする
- e-Govよりダウンロードした公文書をBase64形式デコードしてファイルに出力する

#６．署名付きxml生成ドライバーを作成する
今回は、ユーザ登録・認証及び一括申請のために、署名付きxml生成ドライバーをそれぞれ作成します。なお、一括申請では標準形式及び個別ファイル署名形式で署名対象ファイルが異なるため、それぞれに対応するドライバーを作成します。

なお、ドライバーの実行環境を[GitHub](https://github.com/itaruMatumoto/eGovSignedXmlCreationEnvironment "egov署名付きxml生成環境")に用意しましたので、必要に応じて参照して下さい。

##６．１　ユーザ登録・認証
ユーザ登録・認証の場合、ひな形となるxmlを使わず、kousei.xmlの\<ApplData>タグで囲まれた範囲に対して、ハッシュ値を計算し、そのハッシュ値に対して署名を行う点がポイントになります。

ツールを実行する前に、環境変数「EGOV_USER_ID」にe-Gov検証環境利用申請で指定した利用者IDを設定しておく必要があります。

署名付きxml生成ドライバーは次の通りです。

```ruby:make_register_xml.rb
require 'kiji'

egov_env = {
  "KEY" => File.expand_path("./証明書/e-GovEE01_sha2.pfx"),
  "KEY_PASSWORD" => "gpkitest",
}

user_id = ENV["EGOV_USER_ID"]

pkcs12 = OpenSSL::PKCS12.new(File.open(egov_env["KEY"], "rb"),egov_env["KEY_PASSWORD"])

# ユーザＩＤを設定する
appl_data = Nokogiri::XML::Builder.new do |xml|
  xml.DataRoot {
    xml.ApplData(Id: 'ApplData') {
      xml.UserID user_id
    }
  }
end

doc = appl_data.to_xml(save_with:  0)

signer = Kiji::Signer.new(doc) do |s|
  s.cert = pkcs12.certificate
  s.private_key = pkcs12.key
  s.digest_algorithm           = :sha256
  s.signature_digest_algorithm = :sha256
end

signer.security_node = signer.document.root

# ダイジェスト値を計算する
signer.document.xpath('/DataRoot/ApplData').each do |node|
  signer.digest!(node, id: '#ApplData')
end

# 署名する
signer.sign!(issuer_serial: true)

# xmlに書き込む
File.write("register.xml", signer.to_xml)
```

##６．２　一括申請
###（１）標準形式
標準形式では、構成管理XMLが署名付きxmlになるのがポイントです。次の手順に従って、署名を行います。

1. zipperインスタンスを生成する
2. zipperの第１引数（署名出力先）に構成管理XML、第２引数（署名対象）に申請書XML（＋添付ファイル）のファイルパスをそれぞれ渡して、署名付きの構成管理XMLを作成する
3. 署名付きの構成管理XML及び申請書XML（＋添付ファイル）をzip形式ファイルに固める
4. 手続が複数あれば、各手続毎に2を繰り返してから、最後に3を行う

作成するドライバーについては、make_zip_file_standard_format.rbとします。
ドライバの入出力については、ドライバがあるフォルダに./zip_data/standard/があり、その下にin及びoutフォルダがあります。

inフォルダの中には、900A010200001000(1)フォルダがあり、以下3ファイルがあります。
・kousei.xml
・900A01020000100001_01.xml
・添付ファイル.docx

また、証明書ファイルについては、ドライバーがあるフォルダ直下に証明書フォルダを作成し、その中にe-GovEE01_sha2.pfxを配置します。

ドライバー実行前、outフォルダの中は空です。
ドライバーを実行すると900A010200001000(1)フォルダ、apply_data.zipが作成されます。900A010200001000(1)フォルダには、inフォルダと同じファイルがあり、ここにあるkousei.xmlは、署名付きxmlです。apply_data.zipについては、900A010200001000(1)フォルダをzip形式で固めたものです。

apply_data.zipについて、[データ変換ツール](https://hogehoge.tk/tool/)を使ってBase64形式にエンコードします。エンコード結果をapply_data.xmlの\<FileData>タグに挿入すると、e-Govに送信できる申請データが完成します。

![apply_data_xml.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/659913/7770bdd9-fc98-e60b-673d-15d585229753.png)

ドライバ実行後、実行環境は次の状態になります。

```:標準形式の配置構成
実行環境/ 
     ├ make_zip_file_standard_format.rb
     ├ 証明書/
     │    └ e-GovEE01_sha2.pfx
     └ zip_data/
             └ standard/
                     ├ in/
                     │  └ 900A010200001000(1)/
                     │              ├ kousei.xml
                     │              ├ 900A01020000100001_01.xml
                     │              └ 添付ファイル.docx
                     └ out/
                         ├ 900A010200001000(1)/
                         │          ├ kousei.xml
                         │          ├ 900A01020000100001_01.xml
                         │          └ 添付ファイル.docx
                         └ apply_data.zip
```
署名付きxml生成ドライバーは次の通りです。

```ruby:make_zip_file_standard_format.rb
require 'fileutils'
require 'zip'
require "cgi"
require 'date' 
require 'kiji'

# 署名ファイル、パスワード
Key = "./証明書/e-GovEE01_sha2.pfx"
password = "gpkitest"

# 入出力先パスを定義する
input_base_path = "./zip_data/standard/in/"
output_base_path = "./zip_data/standard/out/"

# 入出力データのファイルパスを定義する
Procedure = Struct.new(:folder, :kousei_xml, :application_xml, :attachment_file)
proc = Procedure.new("900A010200001000(1)","kousei.xml","900A01020000100001_01.xml","添付ファイル.docx")

input_path = "#{input_base_path}/#{proc.folder}"
output_path = "#{output_base_path}/#{proc.folder}"

signed_xml_path = "#{input_path}/#{proc.kousei_xml}"
style_file_path = "#{input_path}/#{proc.application_xml}"
attachment_file_path = "#{input_path}/#{proc.attachment_file}"
app_files_path = ["#{style_file_path}", "#{attachment_file_path}"]

# 出力先のフォルダ、ファイル等を消す
Dir.glob("#{output_base_path}/*") do |f|
  FileUtils.rm_r(f)
end

# Zipper生成
pkcs12 = OpenSSL::PKCS12.new(File.open(Key, "rb"),password)
zipper = Kiji::Zipper.new() do |s|
  s.cert = pkcs12.certificate
  s.private_key = pkcs12.key
end

# 署名を行う
signer = zipper.sign(signed_xml_path, app_files_path)

# 申請フォルダを作成する
FileUtils.mkdir_p(output_path)

# 署名付きxmlを書き出す
File.write("#{output_path}/#{proc.kousei_xml}", signer.to_xml)

# 申請書XML、添付ファイルをコピーする
app_files_path.each do |f|
  FileUtils.cp(f, output_path)
end

# 出力先にあるフォルダをzipに固める
zipper.write_zip(output_base_path, "#{output_base_path}/apply_data.zip")
```

###（２）個別ファイル署名形式
個別ファイル署名形式では、「申請書①に対する構成情報XML」及び「申請書②に対する構成情報XML」が、それぞれ署名付きxmlになるのがポイントです（kousei.xmlは署名付きxmlになりません）。次の手順に従って、署名を行います。

1. zipperインスタンスを生成する
2. zipperの第１引数（署名出力先）に「申請書①に対する構成情報XML」、第２引数（署名対象）に「申請書②XML」のファイルパスを渡して、「申請書①に対する構成情報XML」に署名を付与する
3. zipperの第１引数（署名出力先）に「申請書②に対する構成情報XML」、第２引数（署名対象）に「申請書②XML」のファイルパスを渡して、「申請書②に対する構成情報XML」に署名を付与する
4. 構成管理XML、申請書①に対する構成情報XML、申請書①XML、申請書②に対する構成情報XML、申請書②XMLをzip形式ファイルに固める
5. 手続が複数あれば、各手続毎に2,3を繰り返し、最後に4を行う

作成するドライバーについては、make_zip_file_individual_signature_format.rbとします。
ドライバの入出力については、ドライバがあるフォルダに./zip_data/indivisual/があり、その下にin及びoutフォルダがあります。
inフォルダの中には、950A102200039000(1)フォルダがあり、以下５ファイルがあります。
・kousei.xml                     // 構成管理XML
・950A10220003900001_01.xml      // 申請書XML①
・kousei20200716142110000.xml    // 申請書XML①に対する構成情報XML
・950A10220003900002_01.xml      // 申請書XML②
・kousei20200716142115000.xml    // 申請書XML②に対する構成情報XML

また、証明書ファイルについては、ドライバーがあるフォルダ直下に証明書フォルダを作成し、その中にe-GovEE01_sha2.pfxを配置します。

ドライバー実行前、outフォルダは空です。
ドライバを実行すると950A102200039000(1)フォルダ、apply_data.zipが作成されます。
950A102200039000(1)フォルダには、inフォルダと同じファイルがあります。ただし、ここにあるkousei20200716142110000.xml及びkousei20200716142115000.xmlは、署名付きxmlです。
apply_data.zipについては、950A102200039000(1)フォルダをzip形式で固めたものです。

apply_data.zipについて、[データ変換ツール](https://hogehoge.tk/tool/)を使ってBase64形式にエンコードします。エンコード結果をapply_data.xmlの\<FileData>タグに挿入すると、e-Govに送信できる申請データが完成します。なお、apply_data.xmlの書式については、標準形式と同じです。

ドライバ実行後、実行環境は次の状態になります。

```:個別ファイル署名形式の配置構成
実行環境/
     ├ make_zip_file_individual_signature_format.rb
     ├ 証明書/
     │    └ e-GovEE01_sha2.pfx
     └ zip_data/
             └ indivisual/
                    ├ in/
                    │  └ 950A102200039000(1)/
                    │            ├ kousei.xml
                    │            ├ 950A10220003900001_01.xml
                    │            ├ kousei20200716142110000.xml
                    │            ├ 950A10220003900002_01.xml
                    │            └ kousei20200716142115000.xml
                    └ out/
                       ├ 950A102200039000(1)/
                       │         ├ kousei.xml
                       │         ├ 950A10220003900001_01.xml
                       │         ├ kousei20200716142110000.xml
                       │         ├ 950A10220003900002_01.xml
                       │         └ kousei20200716142115000.xml
                       └ apply_data.zip
```
署名付きxml生成ドライバーは次の通りです。

```ruby:make_zip_file_individual_signature_format.rb
require 'fileutils'
require 'zip'
require "cgi"
require 'date' 
require 'kiji'

# 署名ファイル、パスワードを定義する
Key = "./証明書/e-GovEE01_sha2.pfx"
password = "gpkitest"

# 入出力先パスを定義する
input_base_path = "./zip_data/indivisual/in/"
output_base_path = "./zip_data/indivisual/out/"

# 出力先のフォルダ、ファイル等を消す
Dir.glob("#{output_base_path}/*") do |f|
  FileUtils.rm_r(f)
end

# 入出力データのファイルパスを定義する
Procedure = Struct.new(:folder, :kousei_xml, 
                       :config_info_appl_xml, :application_xml, 
                       :config_info_appl_xml_2, :application_xml_2)
proc = Procedure.new("950A102200039000(1)","kousei.xml",
                     "kousei20200716142110000.xml","950A10220003900001_01.xml",
                     "kousei20200716142115000.xml","950A10220003900002_01.xml")

input_path = "#{input_base_path}/#{proc.folder}"
output_path = "#{output_base_path}/#{proc.folder}"

# 申請フォルダを作成する
FileUtils.mkdir_p(output_path)

# Zipper生成
pkcs12 = OpenSSL::PKCS12.new(File.open(Key, "rb"),password)
zipper = Kiji::Zipper.new() do |s|
  s.cert = pkcs12.certificate
  s.private_key = pkcs12.key
end

# 申請書１に対する構成情報XMLに対して署名を行う
signed_xml_path = "#{input_path}/#{proc.config_info_appl_xml}"
style_file_path = ["#{input_path}/#{proc.application_xml}"]
signer = zipper.sign(signed_xml_path, style_file_path)

# 署名付きxmlを書き出す
File.write("#{output_path}/#{proc.config_info_appl_xml}", signer.to_xml)

# 申請書２に対する構成情報XMLに対して署名を行う
signed_xml_path_2 = "#{input_path}/#{proc.config_info_appl_xml_2}"
style_file_path_2 = ["#{input_path}/#{proc.application_xml_2}"]
signer = zipper.sign(signed_xml_path_2, style_file_path_2)

# 署名付きxmlを書き出す
File.write("#{output_path}/#{proc.config_info_appl_xml_2}", signer.to_xml)

# コピーする申請書XML、添付ファイルをリスト化する
copy_files_path = ["#{input_path}/#{proc.kousei_xml}", style_file_path, style_file_path_2]

# 申請書XML、添付ファイルをコピーする
copy_files_path.each do |f|
  FileUtils.cp(f, output_path)
end

# 出力先リストをzipに固める
zipper.write_zip(output_base_path, output_base_path + "apply_data.zip")
```

次は[動作確認編](https://qiita.com/itaruMatumoto/items/318c9aaa74d238b58941 "第４回 SmartHRのライブラリkijiを使ってe-Govを動かす（動作確認編)")に続きます。