マイナンバーカードの仕組みはどうなっている?
国立豊田高専を中退し、2021年4月にゆめみに入社した池口直希氏。サーバーサイドエンジニアでPHP、TypeScript、C#、Go、Rustといった言語のほか、AWS、Terraform、Dockerなどを使う。「なんでも屋なので、フロントエンドにも手を出したりもしています」と池口氏。
池口氏が所属するゆめみでは興味深い制度がいくつもある。まず、ぱくぱくスタディ制度。社内の勉強会で1人1回あたり1500円(税抜)まで、お菓子や飲み物を会社が補助する。この制度にかけて、「お菓子などを食べながら気軽に聴いてほしい」と呼びかけた。また池口氏は副業も行っている。 副業し放題制度では副業を許可するだけではなく、営業時間内の副業も許可する。ゆめみが社員に副業として社内発注したり、社内で副業についての相談をしたりすることも可能だ(ゆめみでの労働時間としてはカウントされないが)。多様な制度で、社員の心理的安全性を高めることを重視している。
本題に入ろう。今回のテーマはマイナンバーカード。裏面からはICチップの接触端子が見えるほか、NFC規格に準ずる非接触通信にも対応している。カード発行時には、カードOSを基盤として4つのAP(アプリケーション)が搭載されている[※1]。それらが公的個人認証AP(JPKI AP)、券面事項確認AP、券面事項入力補助AP、住基APだ。
[※1] 西村,小野津,志賀 (2017) 『マイナンバーカードの技術仕様と利活用方式』 富士通株式会社。
なお、ここでいうJPKIとは地方公共団体情報システム機構の提供する公開鍵認証基盤(Public Key Infrastracture)のこと。このJPKIを用いて発行され、マイナンバーカードに記録された秘密鍵を利用して書類に電子署名をつけることが可能となっている。
マイナンバーカードには署名用と利用者証明用、2つのキーペアが入っている[※2]。どう使い分けるかというと、例えば前者はe-Taxで書類に署名を添付する時、後者はマイナポータルへのログイン時に使う。それぞれデジタル技術で公的なアイデンティティーを証明できるようになっている。
Rustでマイナンバーカードを操作するAndroidアプリを作る
マイナンバーカードでデジタル署名ができることを知り、池口氏は作ってみたいスマホアプリの着想を得た。シンプルなAndroidアプリで、署名したいメッセージと利用者証明用鍵の暗証番号を入力し、マイナンバーカードをスマホにかざして署名したり、署名を確認したりできるというものだ。池口氏は「せっかくなら流行の技術を採り入れたい。このイベントはU30であることからも 、若い技術を使いたい。そこでRustを使うことにしました」と言う。
ちなみに今回のアプリ開発はゆめみの10%ルールにて行った。同社では業務時間の10%を研究開発やOSS貢献に利用していいという制度になっている(2022年1月現在、Rustについてはさらに拡張され20%ルールの対象となった)。池口氏は「正社員としてフルタイムで働きつつ、副業もしているので、なかなか時間がないという状況です。でもゆめみなら10%ルールがあるので気軽にこのようなことができるのです」と話す。10%ルールは複数のメンバーで取り組むことも可能だ。
今回は言語としてRustを選択したものの、Androidアプリでは基本的にJavaやKotlinを使うことが多い。そのためRustを機械語にコンパイルした上で、FFI(Foreign Function Interface)を用いて外部から呼び出す必要があった。
一方、マイナンバーカードとの通信にはAPDU(Application Protocol Data Unit)プロトコル[※3]を使うことができる。Android NDKがあってもRustのライブラリから直接デバイスのNFC通信にアクセスできないため委譲する形でAndroidアプリから処理する。
[※3] 財団法人ニューメディア開発協会(1998)『ISO/IEC 10536 準拠非接触 IC カード 実装規約書』。
FFIでの初期化時に、特定の関数ポインタをRustライブラリへ渡しておく。例えばRustライブラリで「署名してください」と命令を送った時に、「このAPDUコマンドを送信してください」という処理がAndroidアプリに返る。そしてAndroidアプリからNFCのAPIを用いて、コマンドを送信することで返ってきたものを送信し、再びRustライブラリに返すという流れになる。
「こうすることで、とても柔軟にRustライブラリを使い回すことができて、他環境にも対応できます。モバイルではiOS、ひいてはWindows、macOS、Linuxなどのパソコン環境にも対応できるのがいいところです」(池口氏)
実装については時間の都合でポイントのみの紹介に留めたが、GitHubに全て公開されているので詳しくは下記を参照してほしい。jpki-rsはコアの実装部分となり、マイナンバーカードのJPKIで署名する時のコマンドや処理がRustで記述されている。easy-jpkiはアプリのUIと署名の命令をライブラリ側へ送るところをKotlinで記述している。
- siketyan/jpki-rs:コアのRust実装部分とAndroidとのアダプタ部分
- siketyan/easy-jpki:AndroidアプリとしてのKotlin実装部分
実際にポイントとなるコードを見てみよう。NFCカードとの接続やUIを省くと、下記のものとなる。ここが「こういうコマンドを送って」と委譲された部分の処理となる。4行目の「isoDep.・・・」で、コマンドをマイナンバーカードへ送る流れとなる。
デジタル署名するボタンを押した時の処理は下記となる。1行目で現在のNFC通信をもとにライブラリの初期化処理を行い、2行目でデジタル署名する。ここでは暗証番号と署名するメッセージをバイト列で渡す。池口氏が「Rustのライブラリへ切り出すことによって、これだけで済ますことができる」と言う通り、確かにとてもシンプルだ。
マイナンバーカードが持つ技術的な意義とは?
実際のアプリの動きを池口氏は披露した。アプリを開いて暗証番号とメッセージを入力し「Sign」ボタンを押すと、まず署名の出力先となるファイルを選択する画面が表示される。ここでファイルを選択するとカード待機画面となり、ユーザーは端末にマイナンバーカードをかざす。端末がカードを読み取ると、署名が行われる。
次は署名を検証する機能を試す。今度はメッセージのみを入力して「Verify」ボタンを押し、検証したい署名を選択すると、先ほど同様にカード待機画面となり、ユーザーは端末にマイナンバーカードをかざす。カードが読み取られ、検証処理が走り、その結果が表示される。
最後に池口氏はこのアプリの意義について説明した。マイナンバーカードは健康保険証や運転免許証の代替として使えることがメリットとしてうたわれているが、そこは大して重要ではないと池口氏は考えている。「マイナンバーカードを作る最大のメリットは日本の公的な公開鍵基盤が発行した証明書が手に入ることなのです」(池口氏)
鍵そのものはいくらでも発行可能だ。ただしそれが実在する人物に紐付けられた鍵かどうかは分からない。しかしマイナンバーカードについては公的機関が鍵を発行しているため、ユーザーの公的な情報と紐付けられた鍵となる。
「マイナンバーの通知カードの状態ではNFCの機能は使えませんし、証明書も入っていない状態です。まだ通知カードだけでマイナンバーカードを作っていない人はマイナンバーカードを作って自分の公的な証明書を手に入れていただければと思います」(池口氏)
最後にRust言語に関しては「あまりコードを出せなかったものの、柔軟な言語なのでいろんなことに活用されると期待しています」と評価した。