クマは森で用を足しますか?

アウトプットは重要です。

OmapiTest.testTransmitApdu()が期待するSIMカードの振る舞い(2)

前回は、Android Secure Element CTSのOmapiTest.testTransmitApdu()を、Pythonスクリプトで再現するところまで。今回は、それに対応するJava Cardアプレット側の実装を行います。

cheerio-the-bear.hatenablog.com

その前に「インストール」できないことに気付く

前々回、ほぼ空っぽのJava Cardアプレットを「ロード」してみましたが、その次のステップ「インストール」に失敗することに気付きました。

cheerio-the-bear.hatenablog.com

やはりSIMツールキット用のアプレットじゃないと駄目なんだろうかとか、試行錯誤していて気付きました。どうやら、モジュールAIDとインスタンスAIDが一致していないといけないようです。仕様的にはその限りではないものと理解しているのですが、一致していればインストールできるので、ひとまず気にしないで走り抜けることにします。

ということで、ちょっとしたコードの掃除と一緒に、Makefileを更新して各種AIDを変更しました。

github.com


ロード、インストールおよび削除のコマンドは、この時点ではこうです。

  • ロード
    • python shadysim.py --pcsc -l ./cardlet.cap --kic 9A665E9CDA096DAE9C04894785EB0B18 --kid 1A8DD88431450CAF8D3719F6380F0A18
  • インストール
    • python shadysim.py --pcsc -i ./cardlet.cap --module-aid A000000476416E64726F696443545331 --instance-aid A000000476416E64726F696443545331 --nonvolatile-memory-required 0100 --volatile-memory-for-install 0300 --kic 9A665E9CDA096DAE9C04894785EB0B18 --kid 1A8DD88431450CAF8D3719F6380F0A18
  • 削除
    • python shadysim.py --pcsc -d A00000047600 --kic 9A665E9CDA096DAE9C04894785EB0B18 --kid 1A8DD88431450CAF8D3719F6380F0A18

UnicodeDecodeError: 'charmap' codec can't decodeとは

このUnicodeDecodeErrorには、地味に足踏みさせられました。どうやらsmartcardのSCardGetErrorMessage()には「あるある」なエラーらしく、なんでもWindowsが日本語でエラーを返していて、それをうまくデコードできないんだとか。

$ python sects.py
...
C-APDU : 010C000001AA
Traceback (most recent call last):
  File "sects.py", line 176, in <module>
    omapi.execute_all()
  File "sects.py", line 159, in execute_all
    self.testTransmitApdu()
  File "sects.py", line 121, in testTransmitApdu
    (response, sw) = self.commandif.send_apdu(selectable_aid, apdu)
  File "sects.py", line 85, in send_apdu
    (response, sw) = self.send_apdu_on_channel(channel_number, apdu)
  File "sects.py", line 74, in send_apdu_on_channel
    (response, sw) = self.transport.send_apdu(apdu)
  File "C:\Users\cheeriotb\projects\osmocom3\osmocom-sim-tools\shadysim\pySim\transport\__init__.py", line 68, in send_apdu
    data, sw = self.send_apdu_raw(pdu)
  File "C:\Users\cheeriotb\projects\osmocom3\osmocom-sim-tools\shadysim\pySim\transport\pcsc.py", line 79, in send_apdu_raw
    data, sw1, sw2 = self._con.transmit(apdu)
  File "C:\Users\cheeriotb\AppData\Local\Programs\Python\Python37\lib\site-packages\smartcard\CardConnectionDecorator.py", line 82, in transmit
    return self.component.transmit(bytes, protocol)
  File "C:\Users\cheeriotb\AppData\Local\Programs\Python\Python37\lib\site-packages\smartcard\CardConnection.py", line 146, in transmit
    data, sw1, sw2 = self.doTransmit(bytes, protocol)
  File "C:\Users\cheeriotb\AppData\Local\Programs\Python\Python37\lib\site-packages\smartcard\pcsc\PCSCCardConnection.py", line 205, in doTransmit
    SCardGetErrorMessage(hresult))
  File "C:\Users\cheeriotb\AppData\Local\Programs\Python\Python37\lib\site-packages\smartcard\scard\scard.py", line 1278, in SCardGetErrorMessage
    return _scard.SCardGetErrorMessage(lErrCode)
  File "C:\Users\cheeriotb\AppData\Local\Programs\Python\Python37\lib\encodings\cp1250.py", line 15, in decode
    return codecs.charmap_decode(input,errors,decoding_table)
UnicodeDecodeError: 'charmap' codec can't decode byte 0x83 in position 0: character maps to <undefined>

ちゃんとコードで言語設定を合わせる方法があるんじゃないかとしばらく探していたのですが、そもそも本筋ではないところに長く時間を費やすのは得策ではなく。ひとまず、PCの言語設定を英語にして回避。カードへのデータの送信に問題があったことがわかりました。

$ python sects.py
...
C-APDU : 010C000001AA00
Traceback (most recent call last):
  File "sects.py", line 175, in <module>
    omapi.execute_all()
  File "sects.py", line 158, in execute_all
    self.testTransmitApdu()
  File "sects.py", line 149, in testTransmitApdu
    (response, sw) = self.commandif.send_apdu(selectable_aid, apdu)
  File "sects.py", line 85, in send_apdu
    (response, sw) = self.send_apdu_on_channel(channel_number, apdu)
  File "sects.py", line 74, in send_apdu_on_channel
    (response, sw) = self.transport.send_apdu(apdu)
  File "C:\Users\cheeriotb\projects\osmocom3\osmocom-sim-tools\shadysim\pySim\transport\__init__.py", line 68, in send_apdu
    data, sw = self.send_apdu_raw(pdu)
  File "C:\Users\cheeriotb\projects\osmocom3\osmocom-sim-tools\shadysim\pySim\transport\pcsc.py", line 79, in send_apdu_raw
    data, sw1, sw2 = self._con.transmit(apdu)
  File "C:\Users\cheeriotb\AppData\Local\Programs\Python\Python37\lib\site-packages\smartcard\CardConnectionDecorator.py", line 82, in transmit
    return self.component.transmit(bytes, protocol)
  File "C:\Users\cheeriotb\AppData\Local\Programs\Python\Python37\lib\site-packages\smartcard\CardConnection.py", line 146, in transmit
    data, sw1, sw2 = self.doTransmit(bytes, protocol)
  File "C:\Users\cheeriotb\AppData\Local\Programs\Python\Python37\lib\site-packages\smartcard\pcsc\PCSCCardConnection.py", line 205, in doTransmit
    SCardGetErrorMessage(hresult))
smartcard.Exceptions.CardConnectionException: Failed to transmit with protocol T0. A communications error with the smart card has been detected. Retry the operation.

CardConnectionException: Failed to transmit with protocol T0の原因

カードへのデータ送信に問題があったのは、単純にJava Cardアプレット側が未完成だったためです。APDU.setOutgoing()のAPI仕様には、下記のようにノートが付けられていました。なるほど、確かにそのときにはまだsetIncomingAndReceive()を呼んでいませんでしたし、カードがデータを受信する前に送信しようとするコードになっていましたので、このエラーには納得です。

Notes.
On a case 4 command, the setIncomingAndReceive() must be invoked prior to calling this method. Otherwise, erroneous behavior may result in T=0 protocol.

ということで、Java Card側の実装を追加してOmapiTest.testTransmitApdu()に耐えられるようになりました。

github.com


テストを実行した際の、APDUコマンドのやり取りがこれです。それらしく動作しています。

$ python sects.py
...
started: testTransmitApdu
C-APDU : 0070000001
R-APDU + SW : 019000
C-APDU : 01A4040010A000000476416E64726F69644354533100
R-APDU + SW : 9f0c
C-APDU : 01c000000c
R-APDU + SW : 6f0a640353010162038501019000
C-APDU : 01060000
R-APDU + SW : 9000
C-APDU : 00708001
R-APDU + SW : 9000
C-APDU : 0070000001
R-APDU + SW : 019000
C-APDU : 01A4040010A000000476416E64726F69644354533100
R-APDU + SW : 9f0c
C-APDU : 01c000000c
R-APDU + SW : 6f0a640353010162038501019000
C-APDU : 81060000
R-APDU + SW : 9000
C-APDU : 00708001
R-APDU + SW : 9000
C-APDU : 0070000001
R-APDU + SW : 019000
C-APDU : 01A4040010A000000476416E64726F69644354533100
R-APDU + SW : 9f0c
C-APDU : 01c000000c
R-APDU + SW : 6f0a640353010162038501019000
C-APDU : A1060000
R-APDU + SW : 9000
C-APDU : 00708001
R-APDU + SW : 9000
C-APDU : 0070000001
R-APDU + SW : 019000
C-APDU : 01A4040010A000000476416E64726F69644354533100
R-APDU + SW : 9f0c
C-APDU : 01c000000c
R-APDU + SW : 6f0a640353010162038501019000
C-APDU : 95060000
R-APDU + SW : 9000
C-APDU : 00708001
R-APDU + SW : 9000
C-APDU : 0070000001
R-APDU + SW : 019000
C-APDU : 01A4040010A000000476416E64726F69644354533100
R-APDU + SW : 9f0c
C-APDU : 01c000000c
R-APDU + SW : 6f0a640353010162038501019000
C-APDU : 010A000001AA
R-APDU + SW : 9000
C-APDU : 00708001
R-APDU + SW : 9000
C-APDU : 0070000001
R-APDU + SW : 019000
C-APDU : 01A4040010A000000476416E64726F69644354533100
R-APDU + SW : 9f0c
C-APDU : 01c000000c
R-APDU + SW : 6f0a640353010162038501019000
C-APDU : 810A000001AA
R-APDU + SW : 9000
C-APDU : 00708001
R-APDU + SW : 9000
C-APDU : 0070000001
R-APDU + SW : 019000
C-APDU : 01A4040010A000000476416E64726F69644354533100
R-APDU + SW : 9f0c
C-APDU : 01c000000c
R-APDU + SW : 6f0a640353010162038501019000
C-APDU : A10A000001AA
R-APDU + SW : 9000
C-APDU : 00708001
R-APDU + SW : 9000
C-APDU : 0070000001
R-APDU + SW : 019000
C-APDU : 01A4040010A000000476416E64726F69644354533100
R-APDU + SW : 9f0c
C-APDU : 01c000000c
R-APDU + SW : 6f0a640353010162038501019000
C-APDU : 950A000001AA
R-APDU + SW : 9000
C-APDU : 00708001
R-APDU + SW : 9000
C-APDU : 0070000001
R-APDU + SW : 019000
C-APDU : 01A4040010A000000476416E64726F69644354533100
R-APDU + SW : 9f0c
C-APDU : 01c000000c
R-APDU + SW : 6f0a640353010162038501019000
C-APDU : 0108000000
R-APDU + SW : 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009000
C-APDU : 00708001
R-APDU + SW : 9000
C-APDU : 0070000001
R-APDU + SW : 019000
C-APDU : 01A4040010A000000476416E64726F69644354533100
R-APDU + SW : 9f0c
C-APDU : 01c000000c
R-APDU + SW : 6f0a640353010162038501019000
C-APDU : 8108000000
R-APDU + SW : 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009000
C-APDU : 00708001
R-APDU + SW : 9000
C-APDU : 0070000001
R-APDU + SW : 019000
C-APDU : 01A4040010A000000476416E64726F69644354533100
R-APDU + SW : 9f0c
C-APDU : 01c000000c
R-APDU + SW : 6f0a640353010162038501019000
C-APDU : A108000000
R-APDU + SW : 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009000
C-APDU : 00708001
R-APDU + SW : 9000
C-APDU : 0070000001
R-APDU + SW : 019000
C-APDU : 01A4040010A000000476416E64726F69644354533100
R-APDU + SW : 9f0c
C-APDU : 01c000000c
R-APDU + SW : 6f0a640353010162038501019000
C-APDU : 9508000000
R-APDU + SW : 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009000
C-APDU : 00708001
R-APDU + SW : 9000
C-APDU : 0070000001
R-APDU + SW : 019000
C-APDU : 01A4040010A000000476416E64726F69644354533100
R-APDU + SW : 9f0c
C-APDU : 01c000000c
R-APDU + SW : 6f0a640353010162038501019000
C-APDU : 010C000001AA00
R-APDU + SW : 9f00
C-APDU : 01c0000000
R-APDU + SW : 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009000
C-APDU : 00708001
R-APDU + SW : 9000
C-APDU : 0070000001
R-APDU + SW : 019000
C-APDU : 01A4040010A000000476416E64726F69644354533100
R-APDU + SW : 9f0c
C-APDU : 01c000000c
R-APDU + SW : 6f0a640353010162038501019000
C-APDU : 810C000001AA00
R-APDU + SW : 9f00
C-APDU : 81c0000000
R-APDU + SW : 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009000
C-APDU : 00708001
R-APDU + SW : 9000
C-APDU : 0070000001
R-APDU + SW : 019000
C-APDU : 01A4040010A000000476416E64726F69644354533100
R-APDU + SW : 9f0c
C-APDU : 01c000000c
R-APDU + SW : 6f0a640353010162038501019000
C-APDU : A10C000001AA00
R-APDU + SW : 9f00
C-APDU : A1c0000000
R-APDU + SW : 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009000
C-APDU : 00708001
R-APDU + SW : 9000
C-APDU : 0070000001
R-APDU + SW : 019000
C-APDU : 01A4040010A000000476416E64726F69644354533100
R-APDU + SW : 9f0c
C-APDU : 01c000000c
R-APDU + SW : 6f0a640353010162038501019000
C-APDU : 950C000001AA00
R-APDU + SW : 9f00
C-APDU : 95c0000000
R-APDU + SW : 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009000
C-APDU : 00708001
R-APDU + SW : 9000
finished: testTransmitApdu

いい感じです。次のテストに取り掛かってみましょう。