iMessageの内部構造の解説
(jjtech.dev)- iMessageは APNs を単なる通知チャネルではなく双方向転送基盤として使い、IDS を通じて公開鍵の登録・照会とメッセージ配信の準備をまとめて処理する
- デバイスはAPNs接続後に push token を受け取り、iMessageのtopicである
com.apple.madridをフィルタリングして受信するメッセージ範囲を決める - IDS登録にはApple ID認証トークン、長期証明書、公開暗号化鍵・署名鍵のアップロード、validation data の提出が必要で、非Appleデバイスでの利用が難しいように設計されている
- メッセージ暗号化は旧式の
pairと新式のpair-ecに分かれ、pair-ecはSignalに似た pre-key ベースの forward secrecy を提供する - 送信者は受信者ごとの暗号化ペイロードを個別に送ることも、まとめて送ることもできるが、最新デバイスで復号するにはAES鍵に HMACタグ が含まれている必要がある
APNsが担うiMessageの転送基盤
- iMessageの基礎レイヤーの1つは Apple Push Notification Service(APNs)
- APNsは、App Storeアプリが閉じているときでもリアルタイム通知や更新を受け取るために使われるサービスと同じレイヤー
- iMessageではAPNsは通知受信だけでなく、メッセージ転送 にも使われる双方向サービスとして動作する
- デバイスがAPNsに接続すると push token を受け取る
- このトークンは特定のデバイスに通知をルーティングするために使われる
application:didRegisterForRemoteNotificationsWithDeviceToken:APIで受け取るトークンとは技術的に異なる- このAPIのトークンはアプリごとのスコープで、アプリケーションのbundle IDで要求されるが、目的は似ている
- デバイスにpush notificationを送るときは、メッセージの topic も指定する必要がある
- topicは通常Bundle IDのように見える
- iMessageのtopicは
com.apple.madrid
- デバイスがAPNsに接続すると、どのメッセージを受け取るかをサーバーに伝える filter message を送信する
- APNsサーバーはAPNs Courierとも呼ばれる
- filter messageには状態ごとのtopic一覧を含められる
- topicの状態は
enabled,opertunistic,paused,disabledのいずれかになる
APNs上で動作するIDSクエリ
- APNsはiMessageの実際のメッセージ配信にだけ使われるわけではない
- APNs上の pseudo-HTTPレイヤー を通じて、IDSがクエリを送り応答を受け取れる
- APNsに接続するには Albert activation server が発行したクライアント証明書が必要
IDSとApple ID認証フロー
- IDSはiMessageの 鍵サーバー として機能し、FaceTimeのような他のサービスでも使われる
- IDSはIDentity Servicesの略だと見られるが、公式な確認はないとされている
- iMessageはエンドツーエンド暗号化を使うため、各参加者の 公開鍵 を安全に交換する必要がある
- IDS登録の最初のステップは認証トークンを受け取ること
- APIにApple IDのユーザー名とパスワードを渡す必要がある
- 2FAは後からIDS APIに合わせる形で組み込まれた
- レガシー方式では2FAコードをパスワードに直接連結する
- GrandSlam 方式では「Anisette data」で同一デバイスであることを証明し、2FAコードの再入力を不要にする
- その後、Password Equivalent Token(PET)を受け取り、パスワードや2FAコードのように使える
- 認証トークンを受け取った後は、すぐにより長く有効な 証明書 に交換しなければならない
- この証明書によってIDS登録は可能になるが、それだけで鍵照会を行うには十分ではない
IDS登録とvalidation data
- IDS設定で最も重要なステップは registration
- registrationでは公開暗号化鍵と署名鍵を鍵サーバーにアップロードする
- デバイスが対応する機能に関する各種 client data もあわせてアップロードされる
- IDS registrationリクエストには「validation data」というバイナリblobが必要
- これは非AppleデバイスがiMessageを利用できないようにするAppleの検証メカニズム
- validation dataの生成には、デバイスの serial number、model、disk UUID などの情報が使われる
- すべてのvalidation dataを同一に扱うことはできない
- Hackintoshと同様に、アカウントの古さや「score」によって、不正なserialの使用可否や「customer code」エラーの有無が左右される
- validation dataを生成するバイナリは強く難読化されている
pypushはcustom mach-o loaderとUnicorn Engineで難読化バイナリをエミュレートし、この問題を回避するpypushはserial numberのようなデバイス属性をdata.plistファイルに入れて、エミュレートされたバイナリに渡す
鍵照会とsession token
- IDS登録後には identity keypair を受け取る
- このkeypairを使って公開鍵照会を行える
- 照会したいアカウントを渡すと「identities」の一覧を受け取る
- 各identityは、そのアカウントに登録された1台のデバイスに対応する
- public key、push token、session token などの重要な情報が含まれる
- session token はデバイスにメッセージを送るために必要
- 最近照会を実行したことを証明する役割を持つ
- session tokenには有効期限がある
- 照会リクエストを実行したアカウントだけが使えるため共有できない
受信メッセージと暗号化形式
- メッセージを受け取るには、APNs接続を
com.apple.madridでフィルタリングし、active state packet を送ればよい - 受信メッセージの暗号化形式は、IDS登録時に通知したcapabilitiesと送信側デバイスのiOSバージョンによって変わる
- 旧式のpre-iOS 13形式は
pair - 新形式は
pair-ec
- 旧式のpre-iOS 13形式は
pair形式はより多く文書化されており、実装もしやすいpairは新しいpair-ecと異なり、「pre-keys」を用いた forward secrecy を提供しない- メッセージは複数の論文と
pypushの実装に従って復号できる - メッセージ署名の検証は任意だが、安全なクライアントを作るうえで重要
送信方式と実装時の注意点
- メッセージ送信は受信の逆過程に近い
- 受信者ごとにメッセージを個別送信できる
- 複数の受信者と、それぞれの受信者向け暗号化ペイロードを1つの大きなbundleにまとめて送ることも可能
- この場合、APNsがそれを分離する
- メッセージは会話のすべての参加者に配信される
- 自分のアカウントに紐づく他のデバイスにも配信される
- 送信時によく見落とされる点は、AES key が完全なランダムではないこと
- AES keyにはHMACがタグとして付加されている
- 完全にランダムなAES keyを使うと、最新デバイスでメッセージの復号に失敗する
関連実装と参考資料
pypush: iMessageを再実装するオープンソースプロジェクト- IMFreedom Knowledge Base: iMessage: iMessage関連のナレッジベース
- M. Frister:
pushproxy: 関連実装 - Nicolás:
apns-dissector: APNs解析ツール - QuarkSlab: iMessage Privacy: iMessage privacy 関連資料
- Garman et al. Chosen Ciphertext Attacks on Apple iMessage: Apple iMessageに対する選択暗号文攻撃の論文
- NowSecure: Reverse Engineering iMessage: iMessageリバースエンジニアリング資料
- Elcomsoft: iMessage Security and Attachments: iMessageのセキュリティと添付ファイル関連資料
- Eric Rabil’s
open-imcore: 関連プロジェクト - The Apple Wiki: Apple Push Notification Service: APNs関連文書
- Mihir Bellare and Igors Stepanovs: Security under Message-Derived Keys: Signcryption in iMessage: iMessage signcryption 関連論文
- Apple Platform Security: How iMessage sends and receives messages securely: AppleによるiMessageセキュリティの説明
- Nicolás: Apple IDS payload keys: Apple IDS payload key 資料
1件のコメント
Hacker Newsのコメント
Appleは attestation(DeviceCheck) でiMessageをロックし始める可能性が高そう
ただし、古い端末にはソフトウェアアップデートが必要になるという問題がある
「validation data」を作る際に、端末のシリアル番号、モデル、ディスクUUIDのような情報が使われており、Hackintoshのような環境では、アカウント年齢や「スコア」に応じて不正なシリアル番号を使えるか、それとも「customer code」エラーになるかが分かれる
「customer code」エラーは実質的にAppleのattestation失敗プロンプトで、一度引っかかるとApple Supportに連絡してApple IDのロックを解除しなければならない
正規ユーザーは正規端末でログインを承認する形で簡単に通過できるが、Hackintoshユーザーは回避テクニックでこの過程をごまかしている
https://old.reddit.com/r/hackintosh/comments/gij9rt/getting_...
OS全体のセキュリティの一部というより、少なくともAppleの Lockdown Mode に入るような機能に思える
もしかすると今をオープンな方向へ舵を切る良い機会と見ているのかもしれない
契約の解明は見事だが、iMessageインフラスタック も気になる
とてつもない規模なのにこれほど安定して動いている一方で、Appleの他のWebサービス、たとえばフォーラムや開発者ポータルはバグも多く未完成に感じられるので、なおさら不思議だ
すべてのサードパーティ製メッセンジャーアプリのプッシュ通知もこれを通るし、通知のある非メッセンジャーアプリも同様
内部のサイレント通知も含まれる。Macでカレンダーに会議を追加すると、iCloudデータが変わったので更新しろというプッシュがiPhoneに送られ、iCloud Driveのファイルを変更すると他の端末との同期のためにプッシュが飛ぶ
着信があるとContinuityでMacも鳴るが、これもiMessageのような暗号化されたプッシュ通知だ
このサービスを1秒あたりいったい何件のメッセージが通過しているのか気になる
これは Hack Club にぴったりの題材。参加してみるといいかも: https://hackclub.com/
本当にすごい仕事だ
この分野にどう入ったのかも短く書いてくれるとよさそう
Redditには、技術が得意になりたい、プログラミングを学びたい、技術職に就く方法を考えている高校生や大学生が多いので、そういう視点はかなり役に立つと思う
早く終わらせること、空き時間、本来そうしてはいけない場面でこっそり自分のことをやることで、約6か月でアプリを作って公開できたし、生産性も非常に高かった
すごく気になるのだが、話題が本当に
opertunisticなのか、それとも筆者のタイプミスなのかわからないrefererのように世代を超えて化石化していく タイプミス は興味深いただ、これがApple側のタイプミスなのかはわからないが、確かに妙ではある。ここでは
WindowsSerialのようにsを1つ多く付けたものではなく、WindowSerialを使うべきだhttps://github.com/JJTech0130/pypush/blob/8b33c0ee5d540d8ac7...
関連する話題がもう1つある: https://news.ycombinator.com/item?id=38531759
今日のiMessageリバースエンジニアリングの話題の土台になったオープンソースプロジェクト pypush は、MongoDBのServer Side Public Licenseで配布されており、所有者はBeeper
JJTechがDiscordで話したところによると、権利をBeeperに売却したとのこと
ライブラリ自体は素晴らしいが、非常に強いコピーレフトライセンスなので、どこに使えるかには影響がありそう
IDS登録リクエストを作るのに必要な「validation data」は、Appleが非Apple端末にiMessageを使わせないための確認メカニズムだというが、EUの DSAやDMA が施行されたらこれが違反になるのか気になる
AppleがどのようにDSAやDMAを順守するとしても、このやり方ではないはず
1st-partyのクロスプラットフォームiMessageは、しょせん技術オタクたちのかなわぬ夢に近く、個人的にはそれで十分だと思う
Beeper Miniの発表文 [1] を見ると、ユーザーはApple IDなしでも電話番号を登録してiMessageを送受信できるとはっきり書かれている
また、端末とAppleが直接通信すると説明している
だがこの記事では、IDSがiMessageの鍵サーバーとして使われ、IDS登録の最初の段階ではApple IDのユーザー名とパスワードで認証トークンを受け取り、登録後に受け取ったidentity keypairで公開鍵の問い合わせを行うとある
だとすると、Beeper Miniアプリが任意のAndroid電話番号をどうやってIDSに公開鍵として登録し、受信者の公開鍵問い合わせまで Apple IDなしで 行うのかが疑問だ
答えは、本文や [1] のどこでもほとんど説明されていない SMS Gateway のようで、それが秘密の材料に見える
[1] https://blog.beeper.com/i/139416474/security-and-privacy
本当に驚くべき仕事だ
ただ、記事中で既存のpair形式はドキュメントがより整っていて実装しやすいが、新しいpair-ec形式のようなSignal類似の「pre-keys」を用いた 前方秘匿性 を提供しないとしている点は引っかかる
最新、つまりECIESを使うiMessageが実際にpre-keyを使っている根拠があるのかはわからない
自分には、暗号化、あるいは署名の部分でRSAの代わりにECIESを差し込んだ程度に見え、それだけでは前方秘匿性は生まれない
根拠がないなら、RSA・楕円曲線・前方秘匿性の関係を誤解しているのかもしれない
WikipediaのiMessage記事も同じ誤りを広めているようだし、引用されている参考文献も実際にはそうした主張をしていない