Simple minds think alike

より多くの可能性を

OpenSCを使ってマイナンバーカードで電子署名・検証してみた

マイナンバーカードを使って電子署名できるアプリを作ってみたくて、マイナンバーの仕様に関して調べてまとめてみました。また、実際にOpenSCというツールを使って電子署名・検証し、マイナンバーカードの内部構造の理解を深めました。

前提

  • macOS: 12.4
  • OpenSSL: LibreSSL 2.8.3
  • OpenSC: 0.22.0-rc1-74

マイナンバーカードのインタフェース

まずは、マイナンバーカードの外部からアクセスするためのインタフェースとその規格を確認し、接続に使った機器に関して説明します。

規格

マイナンバーカードは接触・非接触両方のインタフェースを持ち、それぞれ以下の規格に準拠しています。

  • 接触インターフェース
  • 接触インターフェース(NFC)
    • ISO/IEC 14443 TypeB

接触インターフェースであるNFCの代表的の規格は以下の3つであり、マイナンバーカードは2番目のType Bを採用しています。

分類 規格 特徴 使用例
Type-A ISO/IEC 14443 Type A (MIFARE) 比較的安価で低機能 taspo
Type-B ISO/IEC 14443 Type B 高セキュリティ、高処理速度 パスポート、住民基本台帳カード、免許証
Type-F NFC-F ‐ JIS X 6319-4 (FeliCa) 高セキュリティ、高処理速度 SuicaEdy、iD

使用機器・環境

今回の検証では、接触インターフェース(ISO 7816 準拠) ICカードに対応した以下のカードリーダーを使用し、電子署名・検証してみました。

PCからマイナンバーカードの裏面にあるICチップにアクセスできれば接触/非接触どちらのインタフェースでもよかったのですが、2,000円台という安価で壊れても買い直しやすそうだったのでこちらのICカードリーダーで試してみました。

Amazon.co.jp: SCM ICカードリーダー/ライター B-CAS・住基カード対応 SCR3310/v2.0 : パソコン・周辺機器

マイナンバーカードの内部構造

アプリ

総務省のマイナンナーカードの説明によるとマイナンバーカードのICチップには、券面AP・公的個人認証AP(JPKI-AP)・券面入力補助AP・住基APという4つのアプリケーションがあり、以下の概要図のようになっています。

https://www.soumu.go.jp/main_content/000379924.jpg

本記事の検証では、OpenSCというツールを使って電子署名をしたいので公的個人認証AP(JPKI-AP)の部分を使っていきます。

データ構造

また、ICチップ内部のデータ構造は公開されていませんが、ICチップの内部にアクセスして確認すると以下のようなデータ構造になっていることがわかります。

本記事では署名用のデータを使います。

電子署名・検証

いよいよOpenSCとマイナンバーカードにある署名証明書を使って電子署名を行なっていきます。

OpenSCとは

OpenSCは、クロスプラットフォームで動作するスマートカード用のライブラリ・ユーティリティ郡です。主に暗号操作をサポートするカードに対して、認証、メール暗号化、デジタル署名などをするアプリケーションを実装しやすくしてくれるものです。

OpenSCのインストール

以下から環境にあったインストーラーをダウンロードして、OpenSCをインストールします。 https://github.com/OpenSC/OpenSC/wiki/#download

インストール後、pkcs15-crypt, pkcs15-tool の両コマンドが使えるようになっていることを確認します。

$ pkcs15-crypt --version
OpenSC-0.22.0-rc1-74-gc902e199, rev: c902e199, commit-time: 2021-08-10 11:09:03 +0200
$ pkcs15-tool  --version
OpenSC-0.22.0-rc1-74-gc902e199, rev: c902e199, commit-time: 2021-08-10 11:09:03 +0200

これらのツールの用途はそれぞれ以下の通りです。

  • pksc15-creypt
    • ICカードに保存された鍵を用いて、電子署名の計算やデータの復号化などの暗号処理を実行するためのツールです。
  • pkcs15-tool
    • PIN・証明書・公開鍵など、カード内部のデータにアクセスするためのツールです。

電子署名

以下のコマンドで署名対象のファイル( plain.txt )を作成します。(RSA署名できるのは254バイトまでなので、実際には署名対象自体ではなくダイジェストに対して署名します)

$ echo "hello" > plain.txt

次に以下のコマンドで、PKCS#15オブジェクトを全て表示し、署名用の秘密鍵のIDを確認します。

$ pkcs15-tool --dump
〜〜〜 他のPKCS#15オブジェクト 〜〜〜
Private RSA Key [Digital Signature Key]
    Object Flags   : [0x01], private
    Usage          : [0x204], sign, nonRepudiation
    Access Flags   : [0x1D], sensitive, alwaysSensitive, neverExtract, local
    Algo_refs      : 0
    ModLength      : 2048
    Key ref        : 2 (0x02)
    Native         : yes
    Auth ID        : 02
    ID             : 02
    MD:guid        : xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
〜〜〜 他のPKCS#15オブジェクト 〜〜〜

署名用の秘密鍵のIDが 2 だということがわかりました。また、コマンドの結果から、マイナンバーカード内には以下の10個のオブジェクトがあることが分かります。

  • PIN [User Authentication PIN] - 認証用PIN
  • PIN [Digital Signature PIN] - 署名用PIN
  • Private RSA Key [User Authentication Key] - 認証用秘密鍵
  • Private RSA Key [Digital Signature Key] - 署名用秘密鍵
  • Public RSA Key [User Authentication Public Key] - 認証用公開鍵
  • Public RSA Key [Digital Signature Public Key] - 署名用公開鍵
  • X.509 Certificate [User Authentication Certificate] - 認証証明書
  • X.509 Certificate [Digital Signature Certificate] - 署名証明書
  • X.509 Certificate [User Authentication Certificate CA] - 認証用CA証明書
  • X.509 Certificate [Digital Signature Certificate CA] - 署名用CA証明書

pkcs15-crypt-k オプションに署名用の秘密鍵のID 2 を指定して、作成したテキストファイルを署名します。また、署名用パスワード(英数字6-16文字)の入力が求められるので入力します。(※英字のアルファベットは大文字を入力する必要があります。)

$ pkcs15-crypt -s -k 2 --pkcs1 -R -i plain.txt -o text.signed

pkcs15-crypt はデフォルトだと入力データが正しい長さでパディングされたものと見なして扱うので --pkcs1 オプションを指定して入力データをパディングしてあげています。(参考)

パスワードを間違えてしまった場合、以下のコマンドでPINがブロックされるまでの残り回数を確認できます。PINがブロックされると役所に行ってリセットを依頼する必要があるのでご注意を。

$ pkcs15-tool --list-pins

署名済みのファイルtext.signedができました。

署名検証

次に署名証明書の公開鍵を使って、署名済みのファイルの署名検証を行います。

以下のコマンドで、署名用のPINと証明書のIDを確認します。それぞれ 2 であることが分かります。

$ pkcs15-tool --dump
PIN [Digital Signature PIN]
    Object Flags   : [0x12], modifiable
    ID             : 02
    Flags          : [0x12], local, initialized
    Length         : min_len:6, max_len:16, stored_len:0
    Pad char       : 0x00
    Reference      : 2 (0x02)
    Type           : ascii-numeric
    Tries left     : 5

X.509 Certificate [Digital Signature Certificate]
    Object Flags   : [0x01], private
    Authority      : no
    Path           : 0001
    ID             : 02
    Encoded serial : 00 00 XXXXXXXXX

pkcs15-tool--read-certificate オプションに署名証明書のID 2--auth-id オプションにPINの auth-id02 指定して、署名証明書を取得します。再度、署名用パスワードの入力が求められるので入力します。

$ pkcs15-tool --read-certificate 2 --verify-pin --auth-id 02
Using reader with a card: SCR3310 Smart Card Reader
Please enter PIN [Digital Signature PIN]:
-----BEGIN CERTIFICATE-----
xxxxx
-----END CERTIFICATE-----

出力された-----BEGIN CERTIFICATE-----から-----END CERTIFICATE-----の箇所をファイル名 sign.crt として保存します。

以下のコマンドで署名証明書(sign.crt)から公開鍵の部分を取り出して、ファイル sign.pubに保存します。

$ openssl x509 -in sign.crt -noout -pubkey > sign.pub

先ほど作成した署名済みファイル(text.signed)を公開鍵(sign.pub)で検証すると内容を確認できます。

$ openssl rsautl -verify -pubin -inkey sign.pub -in text.signed
hello

参考資料

関連記事

simple-minds-think-alike.moritamorie.com