マイナンバーカードで PDF に署名
PLOP DS は PKCS#11 による署名に対応しており、IC カードや USB トークン等に格納されているデジタル ID を使用して PDF に署名することができます。この記事では、身近な IC カードである個人番号カード (以下マイナンバーカード) を使用して PDF に署名するまでの手順を紹介します。
なおマイナンバーカードに格納されている証明書は公的個人認証サービスでの利用を前提としており、Adobe Approved Trusted List (AATL) で信頼された認証局の証明書ではありません。そのためデモ用の証明書を使った時のように、Adobe Acrobat から信頼されない PDF になります。
マイナンバーカードで署名を行うのに必要な物
マイナンバーカードで署名を行うためには下記のようなハードウェア、ソフトウェアが必要です。
この記事では Windows 環境での使用を前提に、IC カードリーダーとして Sony PaSoRi RC-S380 を使用しています。使用可能な IC カードリーダーについては上記の参考のリンク尾をご覧ください。macOS や Linux に対応していない IC カードリーダーもあるため、あらかじめご確認ください。
マイナンバーカードと通信するまでの準備
IC カードリーダーを PC に接続したら、メーカーから提供されるドライバーソフトウェアをインストールします。RC-S380 の場合、こちらのページ から基本ソフトウェアをダウンロードしてインストールします。
また IC カード内のトークンと PLOP DS とつなぐ PKCS#11 ライブラリをインストールします。この記事では OpenSC を使用するため、Release ページ から環境に合うファイルをダウンロードしてインストールします。本記事では Windows 10 環境で OpenSC-0.21.0_win64.msi を Typical でインストールしたものとします。macOS の場合は dmg ファイルをダウンロードしてください。Linux ではパッケージマネージャーでインストールするか、ソースコードからビルドします。
ここまでの準備が完了したら、OpenSC が IC カードリーダーを認識できていることを確認します。Windows の場合、cmd.exe 等で下記のコマンドを実行し、IC カードリーダーが表示されることを確認します。
> "C:\Program Files\OpenSC Project\OpenSC\tools\opensc-tools.exe" --list-readers
# Detected readers (pcsc)
Nr. Card Features Name
0 Yes Sony Felica Port/PaSoRi 3.0 0
また、後々使用するため、ここで署名用証明書をファイルに出力します。同じく cmd.exe 等で下記のコマンドを実行して署名用パスワード (英数字6~16桁の方) を入力すると、作業フォルダに certificate.der が出力されます (表示の都合上改行していますが、実際は \ で改行せずに1行で入力します)。
> "C:\Program Files\OpenSC Project\OpenSC\tools\pkcs11-tools.exe" \
--login \
--slot-index 1 \
--read-object \
--type cert \
--label "Digital Signature Certificate" \
--output-file certificate.der
PLOP DS での署名
マイナンバーカードとの通信が可能になったら、PLOP DS から PKCS#11 ライブラリを使って署名を行います。PLOP_prepare_signature() に渡すオプションリストは下記のようになります。
String sign_opts =
"engine=pkcs#11 " + // 暗号化エンジンに PKCS#11 を指定
"digitalid={" +
"filename={./opensc-pkcs11.dll} " + // OpenSC の PKCS#11 ライブラリを指定
"threadsafe=false " + // OpenSC をシングルスレッドで使用
"slotid=1 " + // 署名用証明書が格納されているスロット 1 を指定
"signercert={./certificate.der} " + // 先ほど出力した署名用証明書を指定
"label={Digital Signature Key} " + // 署名用証明書の秘密鍵のラベルを指定
"} " +
"passwordfile={./pw.txt}"; // 署名用パスワード (英数字6~16桁) を記載したファイルを指定
- PKCS#11 ライブラリとして、Windows の場合は opensc-pkcs11.dll を指定します。これは OpenSC のインストールフォルダ (通常は C:\Program Files\OpenSC Project\OpenSC) の pkcs11 フォルダに格納されています。今回はこれを作業フォルダにコピーしていますが、直接指定することもできます。
- OpenSC はシングルスレッドで使用する必要があるため、threadsafe=false を指定します。
- マイナンバーカードには利用者証明用電子証明書と署名用電子証明書の2種類の電子証明書が含まれていますが、ここでは署名用電子証明書が格納されている slotid=1 を指定します。
- 証明書ファイルとして先ほど出力した署名用証明書を指定し、その秘密鍵をラベル名で指定します。
- pw.txt には署名用パスワード (英数字6~16桁) を記載します。ソースコードにパスワードを直接書き込むこともできますが (password={...})、オプションはトレースログにも記載されるため、外部ファイルに記載して適切な権限で保護することをお勧めします。
ソースコード全体では下記の通りです。
/* OpenSC を使用した IC カードでの署名
*
* 2020 Copyright (c) infoTek K.K. all rights reserved.
*
* 必要な製品:PLOP DS 5
*/
import java.io.*;
import com.pdflib.plop;
import com.pdflib.PLOPException;
public class sign_iccard {
public static void main (String argv[]) {
plop plop = null;
// 署名に使用する各種情報を指定
String sign_opts =
"engine=pkcs#11 " + // 暗号化エンジンに PKCS#11 を指定
"digitalid={" +
"filename={./opensc-pkcs11.dll} " + // OpenSC の PKCS#11 ライブラリを指定
"threadsafe=false " + // OpenSC をシングルスレッドで使用
"slotid=1 " + // 署名用証明書が格納されているスロット 1 を指定
"signercert={./certificate.der} " + // 先ほど出力した署名用証明書を指定
"label={Digital Signature Key} " + // 署名用証明書の秘密鍵のラベルを指定
"} " +
"passwordfile={./pw.txt}"; // 署名用パスワード (英数字6~16桁) を記載したファイルを指定
try {
// 第一引数を入力元 PDF、第二引数を出力先 PDF とする
if (argv.length < 2) {
throw new Exception("usage: sign_iccard <infile> <outfile>");
}
plop = new plop();
// infile を PLOP DS で開く。ファイルハンドルが -1 の場合はエラーメッセージを取得
int doc = plop.open_document(argv[0], "");
if(doc == -1) {
throw new Exception("Error: " + plop.get_errmsg());
}
// PLOP DS に署名情報を準備する。戻り値が -1 の場合はエラーメッセージを取得
if(plop.prepare_signature(sign_opts) == -1) {
throw new Exception("Error: " + plop.get_errmsg());
}
// 準備した署名情報で署名し、結果を outfile に出力する。戻り値が -1 の場合はエラーメッセージを取得
if(plop.create_document(argv[1], "input="+doc) == -1) {
throw new Exception("Error: " + plop.get_errmsg());
}
// infile を閉じる
plop.close_document(doc, "");
} catch (PLOPException e) {
// PLOPException の場合、エラーメッセージを出力
System.err.println("Error: " + e.get_errmsg());
} catch (Exception e) {
// PLOPException 以外の Exception はそのまま出力
System.err.println(e);
} finally {
// PLOP DS オブジェクトを生成した場合は破棄
if(plop != null) {
plop.delete();
}
}
}
}
(Dec 25, 2020 - Dec 27, 2024)