2015/09/19

[nrf52][nfc]NFCペアリング問題はこれで終わろう

nRF52832のNFCペアリングサンプルを動かしてUARTログを見ると、こういうアドレスを探しに行っていた。

[DM]: Searching for device 0x87 0x6B 0xE7 0xDA 0x8E 0x68.

このアドレスは、ペアリングしようとしているNexus5のアドレスではなかった。
それに、毎回変わっているのだ。
そして比較しているアドレスは、保持しているNexus5のアドレスのようなのだ。
それは探してもペアリングに失敗するわな・・・。

では、このアドレスはどこから湧いて出たものだろうか?
スニファで見ていると、これのようだった。

image

CONNECT_REQは、仕様書Core_V4.2 Vol.6 Part B 2.3.3.1 CONNECT_REQだろう。
そのInitAのアドレス値をPreview DKは探そうとしている。
しかし、Preview DKが保持しているのは、Nexus5のアドレスとNexus5で表示されている値のようだ。

こんがらがってきたので、少し整理しよう。

AdvAは、ランダムではなく、毎回同じ値だ。
InitAは、ランダムな値だ(ルール性の有無ではなく、とりあえず毎回違う値になっているように見えるという意味で)。
そして、AdvAはNexus5のアドレスと呼んでいる値とは異なる。

まず、Preview DKはどこからNexus5のアドレスを取得したのか?
CONNECT_REQにもAdvertisingにも出てこないから、どっちかだろう。

  • 初回にNexus5とPairingできたときには取得できた
  • NFC経由で取得できた

なぜなら、Advertisingのアドレス(AdvA)は固定だし、InitAはランダムだからだ(そのまんまな理由ですが・・・)。
といいつつも、後者しかないだろうな。

・・・・・えっ、NDEFのデータにはAdvAしか出てないの??
NDEFタグから読み込んだ内容を保持していると思い込んでいただけに、私としてショックだ。


「InitAってなんじゃ?」というQAがあった。
what is initiator address in CONNECT_REQ? - Nordic Developer Zone

忘れていたが、BLE(だけかどうか知らんが)のアドレスにはpublicとrandomがあるのだよ、というお話だ。
上のパケットを見ると、RxAddもTxAddも1なので、AdvertisingアドレスもInitiatorアドレスもランダムなのだ。
(今さら気づいたが、AddってアドレスのAddなのね。付加情報のaddかと思ってた。)
CONNECT_REQはMaster側のデバイスが送信するので「このAdvAアドレスに対して、私InitAアドレスが接続要求しますぞ」という意味になろう。

 

NDEFには、AdvAのアドレスしか載っていなかった(Random Address)。
Randomといっても毎回同じ値なので、staticなのだろう・・・か?
hiro99ma blog: [ble]Device Addressのpublicとrandom
下位2bitでわかるとのこと。
randomアドレスの特徴は、これ。

  • staticアドレス
    • 下位2bitが1
    • 残りのビットが全部0じゃないこと(0x000000000003はダメ)
    • 残りのビットが全部1じゃないこと(0xFFFFFFFFFFFFはダメ)
  • privateアドレス(non-resolvable)
    • 下位2bitが0
    • 残りのビットが全部0じゃないこと(0x000000000000はダメ)
    • 残りのビットが全部1じゃないこと(0xFFFFFFFFFFFCはダメ)
  • privateアドレス(resolvable)
    • 下位2bitがb10
    • 残りのビットが全部0じゃないこと(0x000000000002はダメ)
    • 残りのビットが全部1じゃないこと(0xFFFFFFFFFFFEはダメ)

AdvAは、0xCD256AB87D9Aだから・・・下位2bitは10じゃないか。
ということで、これはresolvableなprivateアドレスということになる。

なにが「resolvable」かっていうと、なんか、Local Identity Resolving Key(IRK)とかPeer Identity Resolving Key(IRK)とかいう言葉が出てきたので、Pairingとも関係しそうだ(どっちも略がIRKなのはどうなんだ、とは思うが)。
ただ単なるでたらめな数字じゃなくて、Hash式が書いてあるから、それなりに認証するときに解決できるような値なのだろう。そこが「resolvable」たるゆえんか。

難しいことはさておき、CONNECT_REQではアドレスがランダムでもよさそうなことはわかった。
でもまあ、念のため原典を当たっておこう。

Core_V4.2の[Vol 6, Part B] 2.3.3.1 CONNECT_REQだ。
InitAは、TxAddが0ならpublic、1ならrandomということだ。


念のためにAD-BTSSP v1.1を読むと、NDEFには「3.3.1 LE Bluetooth Device Address」を持つことになっている。
ここには、Randomアドレスであれば[Vol 3, Part C]10.8を参照することになっていた。

10.8に書いてあることは、上の方に書いたアドレスの種類だけでなく、bonded deviceについても少し書いてあった。
resolvable privateアドレスを使う、ということのようなので、さっきの推測は違ってなかったようだ。
が「or」で、10.3章に定義した手順で認証した、とある。

この「or」が英文のどこにかかるのかがすぐわからない・・・。
間違っていても訳さないことには進まないので、解釈してみよう。

bonded deviceは、10.8.2.3章に定義したresolvable private addressか、connectionを確立して10.3章に定義した認証手順で処理を進める。
resolvable private addressを使うdeviceは、常に配信要求を以下のように行う。

  • 両側ともbond可能な場合:[Vol 3, Part H]3.6.4章で定義したIRK値
  • 上記以外:あらかじめ配信用の鍵を用意しておく

IRK値配信要求が失敗した場合、10.3章で定義する手順で再接続・認証するか、現在の接続を切断する。

うーん・・・。
まずは、わからないものを調べていこう。

10.8.2.3章: Resolvable Private Address Resolution Procedure
Resolvable Private Addressの解決手順は[Vol.6 Part B]1.3.2.3章に書いてありますよ、という章。
Hostは、対向デバイスから取得したIRK値か、ローカルデバイスのIRK値を使ってresolvable private addressを解決できますよ、ということらしい。

10.3章: Authentication Procedure
認証手順、だろう。
フローチャートにParingとか出てくるので、読んでおいて損はないのだろうけど、ちょっと気力が・・・。

[Vol 3, Part H]3.6.4章: Identity Information
Identity情報。
128bit(16 oct)のIRK。
この情報は「Transport Specific Key Distribution」フェーズで使われる。

あまりわからなかったが、とにかくIRKを使えばResolvable Private Addressを解決できる、ということがわかっていればよいんじゃないかな。


この辺を手がかりにネットで検索していこう。

What mechanism randomizes the BLE address that gets hashed with the IRK? - Nordic Developer Zone
S110のv7.0.0 alphaまではResolvable Private Addressに対応していない、ということのようだ。
念のためBLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLEで検索すると、device_manager_peripheral.cでは何箇所か使っていた。
何に使っているかはわからないが、書いてあるということは使っていると思っててよいんじゃないか。

bluetooth - Can you uniquely identify a BLE MAC address in Android 5.0? - Stack Overflow
Android5.0からは、static addressが使えなくなった、とある。
これは何か関係しているかもしれない。
nRF52 SDK v0.9.1のNFCペアリングは、Galaxy S6でしかやってない、とリリースノートに書かれている。
ただ、ネットで見ると、今年の5月くらいに5.1.1配信が海外で行われた、という記事があったので、同じバージョンかもしれん。
Nordicさんも、端末じゃなくてOSバージョンまで特定してくれないと困るなあ。

Bluetooth Low Energy SMP Pairing | Freescale Community
ここはシンプルにまとまっている。
まとまっているのだけど、私がTKとかSTKとか出てくるたびに拒否反応を起こしてしまい、読みたくない。。。

 

よし、私が実データ派だということを思いだしたので、もう一度nRF52のFLASHを消去してペアリングし直そう。


初回は、CONNECT_REQ後、SM_Pairing_Req/Rsp、SM_Pairing_Confirm、SM_Pairing_Randomが走るようだ。
2回目も同じ。
同じなのだけど、コンソールログがちょっと違う。
初回はFLASHに値を保持していないので、アドレスが0xFFFFFFFFFFFFになっているのだが、2回目はNexus5のアドレスが入っていた。

スニファのデータを眺めた感じでは、Nexus5のアドレスを直接やりとりしているようには見えない。
ということは、InitAで渡しているアドレス値を変換するとNexus5のアドレスになるっていうことかい?
それが「Resolvable」という意味なのだろうか??

ならば、こういう仮説が立てられそうだ。

  • 1回ペアリングが成功すると、何か相手の情報を保持する。アドレスと、暗号化の鍵か何かのようなもの(IRK?)。
  • それ以降は、鍵の交換を省略し、保持している鍵でInitAのアドレスを解決し、保持している相手のアドレスを比較し、一致したら接続する。
  • Nexus5側でペアリング情報を削除すると、その鍵情報がnRF52側と変わってしまうのだが、nRF52側はそれを知らない。
    • なので、nRF52は不一致と判断して接続をやめてしまう

ここの最初で「検索しに行こうとしているアドレスが違う」と書いたが、コンソールに出力しているのはInitAそのもので、まだ解決する前のアドレス値だ。
だから、そこは心配しなくてもいいんだろう。

 

ひとまず、NFCペアリングできなかった件は、これで終わりにしよう。
仮説を検証するのが筋なのだろうけど、そこは私の手に余るし、もうちょっとお遊びで使いたいのだ。
FLASHを消せばペアリングもそこそこうまくいくようなので(Android側は、LocalNameじゃなくてAdvAアドレスが表示されるような中途半端なペアリングになっているが)、DeviceManagerからデータを消すルートさえ用意しておけばいいんじゃなかろうかね。

おっと、サンプルのmain()を見ると、ボタン2を押しながら起動するとBondingデータをクリアするようになっていた。
やるな、Nordic。

0 件のコメント:

コメントを投稿

コメントありがとうございます。
スパムかもしれない、と私が思ったら、
申し訳ないですが勝手に削除することもあります。