Pixel 7 のログから逆引きして学び始める eSIM MEP
Apple は iPhone 13 から、Google は Pixel 7 から eSIM MEP (Multiple Enabled Profiles) をサポートしています。一般市民が触って遊べるようなものなのかどうかは疑問なところですが、どんな仕組みで動いているのか知っておいても良いかなと考えています。ということで、今回は ETSI TS 102 221 を読んでゆきます。
UICC が MEP をサポートしているかどうか
Pixel 7 のバグレポートを見ると、UiccSlot やその近辺のログに "..MultipleEnabledProfiles=true" といった情報を見つけることができます。
UiccSlot: mActive=true mIsEuicc=true isEuiccSupportsMultipleEnabledProfiles=true mIsRemovable=false mLastRadioState={0=1, 1=2} mIccIds={0=898130005[****], 1=} mPortIdxToPhoneId={0=1, 1=-1} mEid=[****] mCardState=CARDSTATE_PRESENT mUiccCard=com.android.internal.telephony.uicc.euicc.EuiccCard@224a7c5 UiccCard: mCardState=CARDSTATE_PRESENT mCardId=[****] mNumberOfPorts=1 mIsSupportsMultipleEnabledProfiles=true
この情報がどこから来ているんだろうとソースコードを追ってみると、AnswerToReset.java による ATR の確認結果であることがわかります。
private void checkEuiccSupportedCapabilities() { // eUICC is supported only if the b8 and b2 of the first tB after T=15 are set to 1. // MEP is supported only if the b8 and b1 of the first tB after T=15 are set to 1. for (int i = 0; i < mInterfaceBytes.size() - 1; i++) { if (mInterfaceBytes.get(i).getTD() != null && (mInterfaceBytes.get(i).getTD() & T_MASK) == T_VALUE_FOR_GLOBAL_INTERFACE && mInterfaceBytes.get(i + 1).getTB() != null) { if ((mInterfaceBytes.get(i + 1).getTB() & B8_MASK) != 0 && (mInterfaceBytes.get(i + 1).getTB() & B2_MASK) != 0) { mIsEuiccSupported = true; } if ((mInterfaceBytes.get(i + 1).getTB() & B8_MASK) != 0 && (mInterfaceBytes.get(i + 1).getTB() & B1_MASK) != 0) { mIsMultipleEnabledProfilesSupported = true; } return; } } }
TD3 の下位ニブル 'F' (Protocol T=15) の次のセットが Global Interface Bytes です。ETSI TS 102 221 によると、そのセットの TB の b8 および b1 がセットされていれば UICC が LSI (Logical SE Interface) をサポートしていることを示しているとのこと。上記のソースコードにあるコメントもそのように説明していますね。
Pixel 7 の ATR もログから拾ってきてみました。TD=3F (Protocol T=15) となっている 3 つめのセットの次のセットが Global Interface Bytes で、その TB=83 (b8/b1 ともに 1) が LSI のサポートを意味しているということですね。
D/AnswerToReset( 2191): Successfully parsed the ATR string 3B9F97C00AB1FE453FC6838031E073FE211F65D002341569810F21 into AnswerToReset:{ mConventionByte=3B, mFormatByte=9F, mInterfaceBytes={ {TA=97,TB=null,TC=null,TD=C0} {TA=null,TB=null,TC=0A,TD=B1} {TA=FE,TB=45,TC=null,TD=3F} {TA=C6,TB=83,TC=null,TD=null} }, mHistoricalBytes={80,31,E0,73,FE,21,1F,65,D0,02,34,15,69,81,0F,}, mCheckByte=21 }
LSI (Logical SE Interface) とその選択
LSI とは、ISO 7816 の物理インターフェースを複数の論理インターフェースへと多重化してアクセスする仕組みのこと。主に T = 0 プロトコルの端末の場合、MANAGE LSI コマンドを使って後続の APDU コマンドの論理インターフェースを選択したり、特定の論理インターフェースのみをリセットしたりするようです。論理インターフェースの、0 から 31 までの 32 個まで取り扱うことができますよと。
7.5 Logical secure element Interfaces
A UICC may support LSIs. If supported by the UICC, this shall be indicated in the ATR. LSIs provide a multiplexing mechanism which allows the terminal to communicate with multiple LSEs over one physical interface. LSIs supported by the UICC and the terminal shall be identified by consecutive numbers starting from zero. The maximum value for the LSI is '1F'. Management of LSIs is done via a dedicated command MANAGE LSI which allows:
各論理インターフェースを通してアクセスする LSE については、下記のように説明されています。eUICC SE の場合、eSIM プロファイル (もしくはそれが入っている箱のようなもの) がこの LSE に相当するものとして読んで不都合なさそうです。なるほど、活性化されている複数の eSIM プロファイルのうちのひとつから REFRESH コマンドを受けたとき、従来の方法で eUICC をリセットすると eUICC 全体を (=全ての eSIM プロファイルを) リセットしてしまいますもんね。複数の論理インターフェースで多重化されているときには、MANAGE LSI コマンドを使って特定の論理インターフェースをリセットしたい旨を伝える必要があるみたいです。
8.10 Logical secure elements
A UICC may support several LSEs on the same physical element. Each LSE acts and is handled by the terminal like a separate secure element. The terminal communicates with the different LSEs via LSIs. Each LSE operates logically independently from the others. As seen on the interface, each LSE has its own file system, its own applications, its own AIDs, its own independent security status, its own CAT session (which means that several of them can run interleaved in parallel on the different LSIs), and its own runtime environment.
The terminal can switch between the LSEs by sending MANAGE LSI (select LSI) commands or by selecting the LSI via the NAD byte when using T = 1. The MANAGE LSI command also allows resetting an LSE. Such a reset shall be equivalent to a warm reset of the interface for a UICC not supporting LSEs. A cold reset or a warm reset of the physical interface results in resetting all LSEs. When the terminal receives a REFRESH proactive command with mode "UICC reset" on an LSI, the terminal shall reset only the corresponding LSE via a MANAGE LSI command
先ほど MANAGE LSI コマンドによる論理インターフェース選択について「主に T = 0 プロトコルの端末の場合」と書きましたが、T = 1 プロトコルであれば MANAGE LSI コマンドではなく NAD (Node ADdress byte) バイトを使って論理インターフェースを指定することができます。NAD バイトは、T = 1 のブロック構造のプロローグフィールド内に存在します。
この NAD バイトにある DAD/SAD を使ってブロックの送受信の対象とする論理インターフェースを指定することになりますが、AT コマンドや PC/SC インターフェース経由で一般市民があれこれやれそうな気がしていないので、それについて言及するのはこのあたりまでにしておこうと思います。
端末と eUICC の LSI 利用に関する同意確認
UICC は ATR を使って LSI のサポートを端末に対して示しますが、それをただ見ているだけでは端末は LSI を利用することができません。
7.5 Logical secure element Interfaces
Terminal and UICC shall agree on using LSIs as follows:
- The UICC indicates support for LSIs in the ATR.
- If indicated by the UICC, the terminal shall indicate in PPS2 if LSIs shall be used for the card session.
- If LSIs are used for the card session, LSI 0 is selected after the PPS.
- Before sending a command on an LSI different from 0 or sending any other MANAGE LSI command, the terminal shall perform the setup of the LSI configuration by sending a MANAGE LSI (configure LSIs) APDU to the UICC.
端末側もまた、PPS2 を使って LSI を利用する能力と意思があることを UICC に対して示す必要があると説明されています。
6.4 PPS procedure
PPS2 shall only be used if the first tB i (i > 2) after T = 15 is present in the ATR. The coding for PPS2 is identical to that of the first tBi (i > 2) after T = 15. The value selected depends upon the features supported by the terminal.
MANAGE LSI コマンドの仕様
MANAGE LSI コマンドの CLA および INS は、下表のように規定されています。CLA は '8X' ではなく '80' なので、論理チャネル 0 (基本チャネル) に対してのみ送信可能なコマンドなんですね。
Command | CLA | INS |
---|---|---|
MANAGE LSI | '80' | '7C' |
MANAGE LSI コマンドについて整理するには ETSI TS 102 221 から複数の表を引用する必要がありますので、あらためて別の投稿でそれを行うことにしようと思います。
eSIM.me を Windows 11 の LPA で使用する
このページに来られた方々は既にいろいろとご存じのことだと思われますので、まずは結論から。ふたつあります。
- 「MBIM モードで接続可能な eSIM 対応通信モジュール」を増設すれば、着脱可能なカード型 eUICC である "eSIM.me" を Windows PC 上で制御できるようになります。
- 「MBIM モードで接続可能な eSIM 内蔵通信モジュール」を増設すれば、Windows PC を eSIM 対応機にすることができます。
増設と書きましたが、M.2 通信モジュールを変換アダプタに載せて Windows PC の USB ポートに挿してみただけです。
Windows に入っている LPA および設定アプリを用いて "eSIM.me" に対してそれらの操作を行うことができることを確認しました。もし仮に TelcoVillage GmbH が "eSIM.me" のサービスを継続しないような事態になっても、これで安心ですね(そうなのか)。
実際に確認してみたこと
もろもろ試す前の Windows の設定画面がこちらです。セルラー通信モジュールなんて載せていないデスクトップ PC ですので、セルラー関係の表示がありません。
そして、こちらが上述の通信モジュールを増設した後の Windows の設定画面です。セルラーの設定メニューが登場していますね。"TelcoVillege1" と表示されていますが、おそらく空の状態の "eSIM.me" のブートプロファイルが見えているものと思われます。
その後、Ubigi の eSIM をダウンロードしてみました。特に問題なくダウンロードの手続きは成功し、ダウンロード後の eSIM が普通に表示されています。
今回使用したもの
Dell PC 用のこちらの通信モジュールを購入して試しました。商品の説明に "only for e-SIM Card" などと書かれていてちょっとあやしいですが、「eSIM 対応」と読んで問題なさそうです。
eSIM 対応は SIM2 カードスロットだけなのではと想像していましたが、SIM1 カードスロットに "eSIM.me" を装着しても問題なく使用できています。また、SIM2 カードスロットに "eSIM.me" を装着する必要があるものと考えていたのですが、なんと SIM2 として eSIM がこのモジュールに内蔵されていました。つまり、この通信モジュールさえ増設できれば、"eSIM.me" を持っていなくても Windows PC を eSIM 対応機にすることができます。
M.2 通信モジュールを USB 機器化するアダプタですが、SIM カードスロットがふたつ付いている下記のものを使用しました。上記の通り SIM2 カードスロットの利用が必要になるものと考えての選択でしたが、結局のところ SIM カードスロットがひとつの変換アダプタでも全然問題なかったということになります。
そしておなじみのカード型 eUICC、"eSIM.me" がこちらです。
通信モジュールを選ぶのは何故か(未解決)
期待通りに Windows の LPA を起動させられたのは、これまでのところ上記の通信モジュールひとつだけです。カード型 eUICC (eSIM.me) を認識できるもの、また AT+CSIM コマンドを用いて ISD-R を選択できるものも幾つか見つけたのですが、それらでは Windows の設定画面に eSIM 関連オプションを表示させることができません。モバイルブロードバンド関係のログをさらっと見る限りでは、Windows に ATR を提供できるかどうかがひとつポイントになってそうな感じはあります。
下記のログは上記の通信モジュールを使用時に取得したもので、"GetAtrInfo Succeeded" になっていることが確認できます。その他の通信モジュールで試したときには、これが軒並み "GetAtrInfo Failed" になっていました。
[Microsoft-Windows-wmbclass]Solicited response received with the following parameters: Caller Request Id: 0x182 Driver Request Id: 0 Service Id: {0000004a-588e-c2f6-37f0-c94b8665f4d4} Command Name: Kミ堵UICC_CID_ATR Command Id: 1 Device Status: 0(MBB_STATUS_SUCCESS) Ndis Status: 0x0(NT=STATUS_SUCCESS) Payload Length: 32 Payload: 0x17000000080000003B9F96803FC7828031E073FE211B57AA8660F0010011EE00 ... [Microsoft-Windows-WwanProtDim]INDICATION RECEIVED [Microsoft-Windows-WwanProtDim] StatusCode : NDIS_STATUS_WWAN_ATR_INFO (0x40041034) [Microsoft-Windows-WwanProtDim] RequestId : 0x182 [Microsoft-Windows-WwanProtDim] DataLength : 0x30 ... [Microsoft-Windows-WWAN-SVC-EVENTS]WWAN Service event: [Info] WwanNhTraceMsmNotification: [NH] Dispatch WwanNotificationSourceMsm\WwanMsmEventTypeAtrInfo AtrLength=23 Interface: {{c39392e1-770f-4d88-aa4b-d9d9aabc10f6}} ... [Microsoft-Windows-WWAN-SVC-EVENTS]WWAN Service event: [Info] CWwanUicc::onAtr: IsESIM 1 IsEnterpriseESIM 0 ReadyState 1 Interface: {{c39392e1-770f-4d88-aa4b-d9d9aabc10f6}} ... [Microsoft-Windows-WWAN-SVC-EVENTS][M:0][E:0][Req:0] ExecutorType(4(WWAN_INTF_TYPE_MBIM_1)) GetAtrInfo Succeeded
ちゃんと調べるためには MBIM の仕様書を読まないといけなさそうですので、それはまた暇になったときのための宿題にしようと思います。
過去の関連記事
本ブログにて最初に "eSIM.me" を取り上げたのは、下記の記事でした。
cheerio-the-bear.hatenablog.com
着脱可能なカード型 eUICC としては、ソフトバンク系の通信事業者で商用化されているものもおすすめです。こちらはいつまでサービスされるのかかなり疑問ですので、レア度が高くなるものと思われます。
ワイモバイルのeSIMカード (Removable eUICC) はいい感じです
ソフトバンクおよびワイモバイルでは「eSIMプロファイルのダウンロードに使える物理的なeSIMカード」が2022年3月から提供されているようですが、あまり市場に出回っていないのか(そんな気はする)、それらのeSIMカードについて書かれたブログやツイートを見かけることがほとんどありません。今後もそのような物理的なeSIMカードが提供され続けるかというと、そんなことにはならないように思います。いまこのeSIMカードで充分に遊んでおかないと、後になって後悔するかもしれません。
ということで調達しました、ワイモバイルのYM5G-eUICCnano(n162)カードがこちらです。見た目は普通のSIMカードですが、カード型のeUICCになっています。サービス開始時期的におそらくほぼ同じ仕様だと思われますので、ソフトバンクの方の調達は見送りました(誰かお願いします)。
ちなみに、商用のeUICCカードを取り扱うのは今回で三度目になります。ドコモeSIMカードVer.1およびeSIM.meについては、それぞれ下記の記事をご覧ください。個人的には、eSIM.meがおすすめです。
cheerio-the-bear.hatenablog.com
cheerio-the-bear.hatenablog.com
では、ワイモバイルのYM5G-eUICCnano(n162)カードについて書いてゆきます。
他の通信事業者のeSIMも入れられます
eSIM関係の掲示板を見ると「どうせ他の通信事業者のeSIMは入らないんでしょ?」みたいなコメントも書かれていましたが、いいえちゃんと入るんです。実際にpovoのeSIMを入れてみたときのスクリーンショットがこちらです。
ワイモバイル以外のeSIMの有効化・無効化の操作も問題ありません。また、いずれかのeSIMが有効化された状態のeSIMカードは従来のSIMカードと互換性がありますので、それを他のeSIM非対応端末に装着して使用することも可能です。
GoogleのPixel端末などには「SIMマネージャー」アプリがインストールされていますが、このeSIMカードに対応している端末にはその代わりに「eSIMカード情報設定」アプリが入っています。利用規約を見る限りでは、ソフトバンク内製のアプリのようです。
ES10c: GetProfilesInfo
YM5G-eUICCnano(n162)カードには、2種類のeSIMがインストールされていました。ひとつめは、テスト用プロファイルです。GSMA TS.48に準拠しているもののようで、こちらは通常モードにおいては端末上に表示されることはありません。
serviceProviderName | TS.48 |
---|---|
profileClass | Test (0) |
もうひとつがワイモバイルのeSIMプロファイルということになるのですが、何故かプロビジョニング用プロファイルとしてインストールされています。また、PPR2が設定されていることがわかります。
serviceProviderName | Y!mobile |
---|---|
profileClass | Provisioning (1) |
profilePolicyRules | ppr2 |
PPR1/PPR2の説明のため、GSMA SGP.22から下記の記述を引用します。まだ実際に試してはいないのですが、このeSIMはユーザーの操作によって削除することはできないようになっているようです。
PprIds ::= BIT STRING {-- Definition of Profile Policy Rules identifiers pprUpdateControl(0), -- defines how to update PPRs via ES6 ppr1(1), -- Indicator for PPR1 'Disabling of this Profile is not allowed' ppr2(2) -- Indicator for PPR2 'Deletion of this Profile is not allowed' }
ショップ店頭でのeSIMの開通手続きの様子を見ていないので定かではありませんが、YM5G-eUICCnano(n162)カードの製造時点でこの2種類のeSIMがインストールされていたのではと想像しています。
ES10b: GetRAT
YM5G-eUICCnano(n162)カードのRAT (Rules Authorisation Table)には、特別な仕掛けはありません。MCC/MNC 'EEEEEE'はオールマイティですので、どの通信事業者にも同じルールが適用されます。また、PPRが設定されたeSIMをインストールする際には、ユーザーの同意を求めることになります。
pprIds | ppr1, ppr2 |
---|---|
allowedOperators | mccMnc:EEEEEE, gid1:null, gid2:null |
pprFlags | consentRequired |
そういえば、以前確認したドコモeSIMカード(Ver.1)には、下表のルールも記述されていました。例えば、ドコモのeSIMにPPR2が設定されていたとしても、そのインストールの際にユーザーの同意を求める必要はない、ということになるようです。
pprIds | ppr1, ppr2 |
---|---|
allowedOperators | mccMnc:44F001, gid1:00FFFF, gid2:FFFFFF |
pprFlags | N/A |
ES10b: GetEUICCInfo
さすがに最近の標準仕様バージョンに準拠しているようですが、気になるところがふたつありました。ひとつめは、rspCapabilityの値。
profileVersion | 2.3.1 |
---|---|
svn | 2.2.2 |
uiccCapability | BIT STRING '077F36CB80' |
ts102241Version | 9.2.0 |
globalplatformVersion | 2.3.0 |
rspCapability | BIT STRING '0192' |
euiccCiPKIdListForVerification | '81370F5125D0B1D408D4C3B232E6D25E795BEBFB' |
euiccCiPKIdListForSigning | '81370F5125D0B1D408D4C3B232E6D25E795BEBFB' |
forbiddenProfilePolicyRules | pprUpdateControl, ppr1 |
ppVersion | 0.0.1 |
sasAcreditationNumber | GE-NG-UP-0621 |
GSMA SGP.22 v2.4では、rspCapabilityの各ビットについて下記のように説明されています。additionalProfileとtestProfileSupportに加えて(6)の位置の機能をサポートしているようですが、これを書いている時点で最新のv2.4仕様書にはその説明がまだありません。
RspCapability ::= BIT STRING { additionalProfile(0), -- at least one more Profile can be installed crlSupport(1), -- CRL rpmSupport(2), -- Remote Profile Management testProfileSupport (3), -- support for test profile deviceInfoExtensibilitySupport (4), -- support for ASN.1 extensibility in the Device Info serviceSpecificDataSupport (5) -- support for Service Specific Data in the Profile Metadata }
もうひとつは、sasAcreditationNumberとして表示されている"GE-NG-UP-0621"です。"GD-NG-UP-0621"ならSAS-UP認証済み施設として検索にも引っかかってくるのですが、これは誤記なんでしょうか。
参考までに、ドコモeSIMカード(Ver.1)の同情報も再掲します。こちらは証明書が残念でしたね。
profileVersion | 2.0.0 |
---|---|
svn | 2.0.0 |
uiccCapability | BIT STRING '067F36C0' |
ts102241Version | 9.2.0 |
globalplatformVersion | 2.2.1 |
rspCapability | BIT STRING '0490' |
euiccCiPKIdListForVerification | '137BD996CB67F5AAB8EDBD9850D651AACB952F0F' |
euiccCiPKIdListForSigning | '137BD996CB67F5AAB8EDBD9850D651AACB952F0F' |
forbiddenProfilePolicyRules | pprUpdateControl, ppr1 |
ppVersion | 0.0.1 |
sasAcreditationNumber | GD-NG-0617 |
eSIM.me は商用かつ汎用の Removable eUICC カード
抜き差しできる eUICC カード、あります
世の中の SIM/UICC 好きの皆さま、取り外し可能なカード型の eUICC をお探しではないですか?先日ついにこの eSIM.me を見つけて、脊髄反射でポチっとやりました。ご覧ください、こちらが eSIM.me の eUICC カードです。1FF の半分のサイズのカードが、2FF/3FF/4FF 用にマルチカットされています。
ソフトバンクも同様のカードを三月中旬以降に提供とのことですが、対象機種が AQUOS R6 と BALMUDA Phone では手を出しづらいです。Android の eUICC フレームワークに準拠したかたちで LPA を搭載するのではと思っていますが、意外とこの eSIM.me と同じソリューションだったりするのかもです。
これで、趣味の eSIM が(何それ)捗ります。
eSIM.me とは
SIM カードスロットを有する Android 端末を、eSIM 対応端末にすることができる商品です。eSIM.me より届けられる eUICC カードを Android 端末に装着し、eUICC を制御する LPA の役割を担う eSIM.me アプリを Google Play ストア経由でインストールすれば、セットアップ完了です。同アプリを使って QR コードをスキャンする等すれば、eSIM をダウンロード・インストールすることができるようになります。
SIM カードスロットが eUICC に置き換わるようなものなので、カードスロットが 2 つあるデュアル SIM 端末に eSIM.me カードを 2 枚させば、両方のスロットを eSIM に対応させることが可能です。また、近年の Google Pixel 端末のように元々 eSIM に対応している端末においても、SIM カードスロットにこの eSIM.me カードを装着して利用することができます。
こちらの eSIM.me サイトからオーダーし、およそ 10 日で自宅に届きました。
何らかの方法で(アカウント情報と EID を使ってとか?)使用可能なメーカーや機種の縛りをかけているようで、商品の種類は不自然な程に多いです。今回は、最も汎用的に使用可能な "eSIM.me Card for Android" を選択しています。予備としてもう一枚購入しておくかどうか迷います。だって、このビジネスを何年も続けてくれそうになくないですか?
IIJ の eSIM のダウンロードに成功した
以前 Android GSI をフラッシュした Google Pixel 4 がそのままほこりを被っていたので、それに eSIM.me アプリをプッシュして動作を確認しました。アクティベーションコードの入力については、QR コードのスキャンとマニュアル入力に対応しています。SM-DS は .. どうでしょうね。SM-DS で運用している eSIM 事業者があれば試してみたいところです。
ダウンロード中の表示がテストアプリ・サンプルアプリのそれのようで少し気になりますが、IIJ の eSIM を問題なくダウンロード・インストールできました。eSIM の ON/OFF 制御についても特に問題はないようです。
楽天モバイルの eSIM のダウンロードに失敗した (2022/04/13 追記)
一方、楽天モバイルの eSIM のダウンロードには失敗しています。プロファイルパッケージデータの端末へのダウンロード自体は滞りなく完了していたようですので、実際のところは「インストールに失敗した」という表現が正しそうです。
eSIM.me の eUICC カードから返ってきたエラー情報がそのまま表示されているようで、原因は installFailedDueToPEProcessingError (12) とされています。楽天モバイルのプロファイルパッケージと eSIM.me の eUICC カードの間で、何らかの互換性の問題、仕様解釈の不一致のようなものが起きていることが予想されます。eSIM.me のサイト上でチケットを作成し、このエラーの発生について eSIM.me にレポート済みです。
2022/04/13 追記 : 次のバージョンのファームウェアで、この問題は解決されるそうです。市場投入は本年六月前後になるだろう、とのことでした。
Android OMAPI を利用して eUICC カードにアクセス
eUICC フレームワークに沿うかたちで LPA を実装することを Android は想定していると思いますが、eSIM.me アプリ (= LPA) は Android OMAPI (Secure Element API) を通して UICC SE (この場合 eUICC カード) へのアクセスを実現しています。下記のログで、ISD-R の AID (a0000005591010ffffffff8900000100) を指定して論理チャネルを開いている様子を確認できます。
I/esim.me ( 5121): AndroidOmapiApi. Check isReaderAvailable : SIM1 I/SecureElement-Terminal-SIM1( 2133): ATR : 3b9f96803fc7828031e073fe211b57aa8660f0010004fb I/SecureElementService( 2133): openLogicalChannel() AID = a0000005591010ffffffff8900000100, P2 = 0 W/SecureElement-Terminal-SIM1( 2133): Enable access control on logical channel for esim.me I/SecureElement-AccessControlEnforcer( 2133): checkCommand() : Access = ALLOWED APDU Access = ALLOWED Reason = Unspecified I/SecureElement-Terminal-SIM1( 2133): Sent : 81cadf2000 I/SecureElement-Terminal-SIM1( 2133): Received : df20082618f36467f9a02d9000 I/SecureElement-AraController( 2133): Refresh tag unchanged. Using access rules from cache. I/SecureElement-AccessControlEnforcer( 2133): getAccessRule() appCert = 8d48ecfaf44c5752145ee28b3eb7429cc6627e98 I/SecureElement-AccessControlEnforcer( 2133): getAccessRule() appCert = a2afbbf5681bb26e40c8d69da6c72dd3a62cda7dbd74c5c2f26e7ff1fa819905 I/SecureElement-AccessRuleCache( 2133): findAccessRule() Case C REF_DO: AID_REF_DO: 4f00 Hash_REF_DO: c1148d48ecfaf44c5752145ee28b3eb7429cc6627e98 , com.android.se.security.ChannelAccess I/SecureElement-AccessRuleCache( 2133): [mPackageName=esim.me, mAccess=ALLOWED, mApduAccess=ALLOWED, mUseApduFilter=false, mApduFilter=null, mCallingPid=0, mReason=, mNFCEventAllowed=ALLOWED, mPrivilegeAccess=UNDEFINED] I/SecureElementService( 2133): openLogicalChannel() Success. Channel: 1
許可されていないアプリからのアクセス要求には Android OMAPI が拒否の応答を行うはずですが、なるほど eSIM.me アプリ(を含む)からのアクセス要求を受け付けるようにアクセスルールが設定されています。下記のログから、eSIM.me の ARA-M に設定されているアクセスルールの詳細を確認することができます。上のログにあった eSIM.me アプリの署名のハッシュ値 (SHA1 : 8d48ecfaf44c5752145ee28b3eb7429cc6627e98) が、ふたつ目のルールで全許可 (AID_REF_DO: 4f00) に設定されていますね。
I/SecureElement-Terminal-SIM1( 2108): Sent : 81caff4000 I/SecureElement-Terminal-SIM1( 2108): Received : ff4081b4e222e1184f00c114a4ec39717cecd7f1e84e913b22b0555fe7dfdd8ae306d00101d10101e222e1184f00c1148d48ecfaf44c5752145ee28b3eb7429cc6627e98e306d00101d10101e222e1184f00c11446bcaf2247253f695f19d60eece158099fe52c62e306d00101d10101e222e1184f00c114fa4abb42827a0fbceb891ddc0d34f658c21ff88ce306d00101d10101e222e1184f00c11435cc639bb5826fde0d0ef088b0f20cb69f0c49ade306d00101d101019000 I/SecureElement-AccessRuleCache( 2108): Add Access Rule: REF_DO: AID_REF_DO: 4f00 Hash_REF_DO: c114a4ec39717cecd7f1e84e913b22b0555fe7dfdd8a , com.android.se.security.ChannelAccess I/SecureElement-AccessRuleCache( 2108): [mPackageName=, mAccess=ALLOWED, mApduAccess=ALLOWED, mUseApduFilter=false, mApduFilter=null, mCallingPid=0, mReason=, mNFCEventAllowed=ALLOWED, mPrivilegeAccess=UNDEFINED] I/SecureElement-AccessRuleCache( 2108): Add Access Rule: REF_DO: AID_REF_DO: 4f00 Hash_REF_DO: c1148d48ecfaf44c5752145ee28b3eb7429cc6627e98 , com.android.se.security.ChannelAccess I/SecureElement-AccessRuleCache( 2108): [mPackageName=, mAccess=ALLOWED, mApduAccess=ALLOWED, mUseApduFilter=false, mApduFilter=null, mCallingPid=0, mReason=, mNFCEventAllowed=ALLOWED, mPrivilegeAccess=UNDEFINED] I/SecureElement-AccessRuleCache( 2108): Add Access Rule: REF_DO: AID_REF_DO: 4f00 Hash_REF_DO: c11446bcaf2247253f695f19d60eece158099fe52c62 , com.android.se.security.ChannelAccess I/SecureElement-AccessRuleCache( 2108): [mPackageName=, mAccess=ALLOWED, mApduAccess=ALLOWED, mUseApduFilter=false, mApduFilter=null, mCallingPid=0, mReason=, mNFCEventAllowed=ALLOWED, mPrivilegeAccess=UNDEFINED] I/SecureElement-AccessRuleCache( 2108): Add Access Rule: REF_DO: AID_REF_DO: 4f00 Hash_REF_DO: c114fa4abb42827a0fbceb891ddc0d34f658c21ff88c , com.android.se.security.ChannelAccess I/SecureElement-AccessRuleCache( 2108): [mPackageName=, mAccess=ALLOWED, mApduAccess=ALLOWED, mUseApduFilter=false, mApduFilter=null, mCallingPid=0, mReason=, mNFCEventAllowed=ALLOWED, mPrivilegeAccess=UNDEFINED] I/SecureElement-AccessRuleCache( 2108): Add Access Rule: REF_DO: AID_REF_DO: 4f00 Hash_REF_DO: c11435cc639bb5826fde0d0ef088b0f20cb69f0c49ad , com.android.se.security.ChannelAccess I/SecureElement-AccessRuleCache( 2108): [mPackageName=, mAccess=ALLOWED, mApduAccess=ALLOWED, mUseApduFilter=false, mApduFilter=null, mCallingPid=0, mReason=, mNFCEventAllowed=ALLOWED, mPrivilegeAccess=UNDEFINED]
デフォルトファイルシステム
eSIM をダウンロードする前の eUICC でも、必要最低限のファイルシステムを端末側に見せる必要があります。GSMA SGP.22 の規定では MF と極少数の EF を設ければ良いことになっていますが、eSIM.me カードのデフォルトファイルシステムには DIR や ICCID、IMSI、MSISDN 等も存在します。デフォルトファイルシステムというか、それをひとつのデフォルトプロファイルとして実装しているようです。空の状態でプロファイルのリストを要求すると、以下のログのようにプロファイルがひとつ返ってきます。
I/esim.me ( 5121): AndroidOmapiApi. execute APDU command :81E2910003BF2D00 I/SecureElement-AccessControlEnforcer( 2133): checkCommand() : Access = ALLOWED APDU Access = ALLOWED Reason = Unspecified I/SecureElement-Terminal-SIM1( 2133): Sent : 81e2910003bf2d00 I/SecureElement-Terminal-SIM1( 2133): Received : 613e I/SecureElement-Terminal-SIM1( 2133): Sent : 81c000003e I/SecureElement-Terminal-SIM1( 2133): Received : bf2d3ba039e3375a0aXXXXXXXXXXXXXXXXXXXX4f10a0000005591010ffffffff89000012009f70010191076553494d2e6d6592076553494d2e6d659501019000 I/esim.me ( 5121): AndroidOmapiApi. received APDU response :BF2D3BA039E3375A0AXXXXXXXXXXXXXXXXXXXX4F10A0000005591010FFFFFFFF89000012009F70010191076553494D2E6D6592076553494D2E6D659501019000 I/esim.me ( 5121): Profile list object: profileInfoListOk: { I/esim.me ( 5121): { I/esim.me ( 5121): iccid: XXXXXXXXXXXXXXXXXXXX, I/esim.me ( 5121): isdpAid: A0000005591010FFFFFFFF8900001200, I/esim.me ( 5121): profileState: 1, I/esim.me ( 5121): serviceProviderName: eSIM.me, I/esim.me ( 5121): profileName: eSIM.me, I/esim.me ( 5121): profileClass: 1 I/esim.me ( 5121): } I/esim.me ( 5121): }
MCC/MNC のペアは 262/24 でした。
eUICC カードに関する情報
参考までに、EuiccInfo2 を読みだしているログもここに貼ります。
I/esim.me ( 5121): AndroidOmapiApi. execute APDU command :81E2910003BF2200 I/SecureElement-AccessControlEnforcer( 2133): checkCommand() : Access = ALLOWED APDU Access = ALLOWED Reason = Unspecified I/SecureElement-Terminal-SIM1( 2133): Sent : 81e2910003bf2200 I/SecureElement-Terminal-SIM1( 2133): Received : 617b I/SecureElement-Terminal-SIM1( 2133): Sent : 81c000007b I/SecureElement-Terminal-SIM1( 2133): Received : bf2278810302010282030202008303040200840d81010082040007701e830239b68503017f3a8603090200870302030088020490a916041481370f5125d0b1d408d4c3b232e6d25e795bebfbaa16041481370f5125d0b1d408d4c3b232e6d25e795bebfb8b010004030100000c0d45442d5a492d55502d303832329000 I/esim.me ( 5121): AndroidOmapiApi. received APDU response :BF2278810302010282030202008303040200840D81010082040007701E830239B68503017F3A8603090200870302030088020490A916041481370F5125D0B1D408D4C3B232E6D25E795BEBFBAA16041481370F5125D0B1D408D4C3B232E6D25E795BEBFB8B010004030100000C0D45442D5A492D55502D303832329000 I/esim.me ( 5121): - EUICC info 2 is: { I/esim.me ( 5121): profileVersion: 020102, I/esim.me ( 5121): svn: 020200, I/esim.me ( 5121): euiccFirmwareVer: 040200, I/esim.me ( 5121): extCardResource: 81010082040007701E830239B6, I/esim.me ( 5121): uiccCapability: 011111110011101, I/esim.me ( 5121): javacardVersion: 090200, I/esim.me ( 5121): globalplatformVersion: 020300, I/esim.me ( 5121): rspCapability: 1001, I/esim.me ( 5121): euiccCiPKIdListForVerification: { I/esim.me ( 5121): 81370F5125D0B1D408D4C3B232E6D25E795BEBFB I/esim.me ( 5121): }, I/esim.me ( 5121): euiccCiPKIdListForSigning: { I/esim.me ( 5121): 81370F5125D0B1D408D4C3B232E6D25E795BEBFB I/esim.me ( 5121): }, I/esim.me ( 5121): euiccCategory: 0, I/esim.me ( 5121): ppVersion: 010000, I/esim.me ( 5121): sasAcreditationNumber: ED-ZI-UP-0822 I/esim.me ( 5121): }
SAS-UP の認定番号が ED-ZI-UP-0822 とのことで、中国の "Eastcompeace" というスマートカードベンダによって製造されているカードのようです。
iPhone 13のデュアルeSIMはもっと取り上げられてよい
ネットメディアの反応
iPhone 13では新たに「デュアルeSIM」がサポートされ、eSIMだけで(物理的なSIMカードを装着することなく)2回線を同時に利用できるようになりました。思ったよりも数は多くないという印象ですが、ネットメディアの記事でも「デュアルeSIM」が取り上げられ、概ね好意的に受け入れられているようです。日本でも大手の通信事業者からeSIMが提供されるようになりましたし、SIMカードからeSIMへの移行をほんの少し加速させるのではないでしょうか。
残念なのは、eSIMプロファイルを2つだけダウンロード・インストールして満足している記事が多く見受けられることです。「デュアルeSIM」なんだから、eSIMだけで2回線を同時に利用できることを確認すれば良いだろう。そう考えてのことだと思われますが、iPhone 13が実現した「デュアルeSIM」の注目すべきポイントは、(マニアの観点では)そこではありません。
今回Appleは、GSMA SGP.21で規定されている下記の要件によるプロファイル数の上限設定を、何らかの方法を使って飛び越えています。
EUICC6 | At a maximum, only one Profile SHALL be enabled at any point in time. |
「有効なプロファイルはひとつまで」の制限からの解放
検証のため、下記の4種類のeSIMプロファイルを契約してiPhone 13にダウンロードしてみました。ダウンロード手続きそのものに特筆すべきものは無く、また「どちらのeUICCにダウンロードしますか?」といったようなユーザーへの確認を求められることもありませんでした。「デュアルeSIM」だからといって、iPhone 13がeUICCを複数持っているとは考えにくいです。
この4種類のeSIMプロファイルの中から「デュアルeSIM」に利用する2つを選択する場合、その組み合わせは6通りあります。実際にその6通りを試してみましたが、下のスクリーンショットの在圏表示を見てわかるように、全ての組み合わせを問題なく選択することが可能です。試せてはいないですが、プロファイルの数を更に増やしたとしても、同じ結果になることが予想されます。
eUICCひとつあたり「同時に有効化できるプロファイルの数はひとつまで」という制限に縛られていては、(もしeUICCを4つ載せているならその限りではありませんが)これを実現することはできません。例えば、RakutenとIIJのプロファイルが同一のeUICCにダウンロードされている場合、従来の(というか現行の通常の)eUICCではその2つを同時に使用することはできません。「デュアルeSIM」だからといって、eUICCを2つ搭載すれば良いというわけではないということです。
GSMA SGP.21の現行仕様では実現できない機能を実装し、業界に先駆けてそれを商用化しているものと思われます。SIMカードレスに向かう流れはきっと進行してゆくことでしょうし、さすがはAppleといった感じです。
ドコモeSIMカードVer.1にはがっかりです
ドコモeSIMカードに他キャリアのeSIMプロファイルもダウンロードできたらいいな、なんて思っちゃいますよね。ドコモeSIMカード対応製品はここ三年近く発売されていないので、ちょっと古くなってしまったタブレットdtab Compact d-02Kを調達して確認することにしました。
こちらが、ドコモeSIMカードの表面・裏面の写真です。表面には、32桁のEIDがびっしりとプリントされています。
もしこのカードを使って楽天モバイルやIIJのeSIMプロファイルをダウンロードできるなら、少し前に下記のエントリで書いたようにGoogle Pixelに実装されているeSIMを無理やり使う必要はなくなります。しかし、残念ながらそんなうまい話はないようです。
cheerio-the-bear.hatenablog.com
ドコモeSIMカードからEUICCInfo1やEUICCInfo2を取得してみると、CI Public Key IdentifiersがGSMAのルートCIの証明書に対応するデータを含んでいません。そのEUICCInfo1を使ってドコモ以外のキャリアのSM-DP+にES9+: InitiateAuthenticationを送信すると、下記のようにエラーが返ってきます。これでは、eSIMプロファイルを提供するキャリアをユーザーが選択することができず、解除することが許されないSIMロックを設定されているようなものです。
{ "header" : { "functionExecutionStatus" : { "status" : "Failed", "statusCodeData" : { "subjectCode" : "8.8.2", "reasonCode" : "3.1", "message" : "None of the proposed Public Key Identifiers is supported by the SM-DP+" } } } }
ドコモeSIMカードに設定されているデフォルトSM-DP+はというと、GSMAのルートCIの証明書を求めてはいないようです。
うまくいくと思って調べ始めたわけではないですが、がっかりです。GSMAのルートCI証明書に対応したeSIMカードは、商用製品としては世の中に出回っていないんでしょうか。eSIMカード探しの旅は、しばらく終わりそうにありません。
Function(ES10a): GetEuiccConfiguredAddresses (BF3C)
デフォルトSM-DP+アドレスが入っていますね。プロファイルのダウンロード手続きの際にユーザーに入力させるのはEIDの一部だけですので、SM-DP+のアドレスはこれから得ているんでしょう。
defaultDpAddress | usmdp-001-prod-muc1-eb.venyonservices.com |
---|---|
rootDsAddress | (空) |
Function (ES10b): GetEUICCInfo (EUICCInfo1 - BF20)
数年前に発売された製品に同梱されていたドコモeSIMカードですので、GSMA SGP.22のバージョンはv2.0と少し前のものになります。Google Pixel等に実装されているeSIMとは異なり、CI Public Key IdentifiersがGSMAルート証明書のものを含んでいないようです。
svn | 020000 |
---|---|
euiccCiPKIdListForVerification | 137BD996CB67F5AAB8EDBD9850D651AACB952F0F |
euiccCiPKIdListForSigning | 137BD996CB67F5AAB8EDBD9850D651AACB952F0F |
Function (ES10b): GetEUICCInfo (EUICCInfo2 - BF22)
sasAcreditationNumberはGD-NG-0617ですので、Giesecke+Devrient社の中国南昌市で作られたものだということになりますか。
profileVersion | 020000 |
---|---|
svn | 020000 |
euiccFirmwareVer | 040200 |
extCardResource | 810100820400077D72830400000FC6 |
uiccCapability | 067F36C0 (No contactlessSupport/eapClient) |
ts102241Version | 090200 |
globalplatformVersion | 020201 |
rspCapability | 0490 (testProfileSupport + additionalProfile) |
euiccCiPKIdListForVerification | 137BD996CB67F5AAB8EDBD9850D651AACB952F0F |
euiccCiPKIdListForSigning | 137BD996CB67F5AAB8EDBD9850D651AACB952F0F |
forbiddenProfilePolicyRules | 06C0 (ppr1 + pprUpdateControl) |
ppVersion | 000001 |
sasAcreditationNumber | GD-NG-0617 |
Function (ES10c): GetProfilesInfo (BF2D)
プロビジョニングプロファイルが入っていたので、その情報の一部をご紹介します。アイコンもPNG形式で入っているようですので、いつかまた時間のあるときに読んでみようと思います。
serviceProviderName | NTT DOCOMO |
---|---|
profileName | NTT DOCOMO PP |
iconType | 1 (png) |
profileClass | 1 (provisioning) |
operatorId | 440/10 (no gid1/gid2) |
16 進文字列とバイト配列を変換する関数を C 言語で書く
下記エントリで Kotlin でやったやつを、C 言語でもやってみました。やってみましたというか、必要に迫られて手早く書きました。またいつか必要になりそうですので、ここに貼っておこうと思います。
cheerio-the-bear.hatenablog.com
C 言語もここのところずっと遠ざかっていましたので、まだ勘を取り戻すにはもう少し時間がかかりそうです。「あっ!unsigned char とかあったんだ!」みたいな感じになってます。慣れてくると、もっとスマートに書けたりするんでしょうねぇ。
16進数の文字列からバイト配列への変換
unsigned char *util_hex_string_to_byte_array( const char *string, size_t length ) { unsigned char *array; int index; unsigned char octet; char nibble; if ((array = (unsigned char *) malloc(length / 2)) == NULL) { return NULL; } for (index = 0; index < length; index++) { nibble = string[index]; if (('0' <= nibble) && (nibble <= '9')) { nibble = nibble - '0'; } else if (('a' <= nibble) && (nibble <= 'f')) { nibble = 0x0A + (nibble - 'a'); } else if (('A' <= nibble) && (nibble <= 'F')) { nibble = 0x0A + (nibble - 'A'); } else { free(array); return NULL; } if ((index % 2) == 0) { octet = nibble; } else { array[index / 2] = (octet << 4) + nibble; } } return array; }
バイト配列から16進数の文字列への変換
static const char *UTIL_CONVERT_TO_HEX_CHAR = "0123456789ABCDEF"; char *util_byte_array_to_hex_string( const unsigned char *array, size_t length ) { char *string; char *destination; int index; unsigned char octet; if (length == 0) { return NULL; } if ((string = destination = (char *) malloc(length * 2 + 1)) == NULL) { return NULL; } for (index = 0; index < length; index++) { octet = array[index]; *destination++ = UTIL_CONVERT_TO_HEX_CHAR[octet / 0x10]; *destination++ = UTIL_CONVERT_TO_HEX_CHAR[octet % 0x10]; } *destination = '\0'; return string; }
使い方
それぞれ、下記のコード例のように使用します。どちらの関数でも内部で malloc() したヒープメモリを返しますので、使い終わったら使用者側で free() を呼んで解放する必要があります。
const char *data = "00017F8081FEFF"; unsigned char *array; char *string; array = util_hex_string_to_byte_array(data, strlen(data)); assert(array[0] == 0x00); assert(array[1] == 0x01); assert(array[2] == 0x7F); assert(array[3] == 0x80); assert(array[4] == 0x81); assert(array[5] == 0xFE); assert(array[6] == 0xFF); string = util_byte_array_to_hex_string(array, strlen(data) / 2); assert(strcmp(data, string) == 0); free(array); free(string);