Files
revkit/docs/spec/03_ios.md
T
tkgstrator 220e1d51a2 feat(msl-ios): improve iOS CBOR MSL decryption and tweak DH key capture
Enhances iOS MSL CBOR decoder for multi-item parsing, iOS-specific payload
handling, and IV extraction from ciphertext. Updates NetflixCrypto to support
Tweak-format key JSON. Extends the Tweak to capture DH key exchange material
and session keys more reliably, saving full key histories and implementing
better appboot phase tracking. Adds scripts for DH-derived HKDF parameter
analysis and appboot key response investigation.

Improves documentation on iOS CBOR MSL protocol differences, decryption
pipeline, and key extraction workflow.

Relates to iOS MSL traffic analysis and decryption research.
2026-04-08 10:18:44 +00:00

176 lines
5.3 KiB
Markdown

# Netflix MSL クライアント仕様: iOS
共通仕様: [00_common.md](00_common.md)
---
## 1. フロー
```mermaid
%%{init: {'theme': 'dark'}}%%
sequenceDiagram
participant App as iOS App (Argo)
participant MSL as MSL Gateway<br/>(ios.prod.cloud)
participant FP as FairPlay CDM
rect rgba(80, 80, 80, 0.3)
Note over App,MSL: 認証・ESN 取得
App->>MSL: /getProxyEsn
MSL-->>App: PRV ESN + PXA ESN
end
rect rgba(60, 100, 60, 0.3)
Note over App,FP: マニフェスト → ライセンス → 復号
App->>MSL: /manifest (MSL暗号化)
MSL-->>App: マニフェスト (HEVC + H.264 streams)
App->>FP: SPC 生成 (Server Playback Context)
FP-->>App: SPC データ
App->>MSL: /nq/iosplatform/pbo_license/router
Note right of App: licenseType=standard<br/>SPC (FairPlay challenge)
MSL-->>App: CKC (Content Key Context)
App->>FP: CKC をインストール
FP-->>App: コンテンツ鍵 ready
Note over App: AVPlayer で HLS セグメント復号・再生
end
rect rgba(80, 80, 80, 0.3)
Note over App,MSL: テレメトリ
loop 再生中
App->>MSL: /msl/playapi/ios/event
App->>MSL: /msl/playapi/ios/logblob
end
end
```
---
## 2. 認証
| 項目 | 値 |
|------|---|
| ESN プレフィックス | `NFAPPL-02-` |
| PRV ESN 例 | `NFAPPL-02-IPHONE9=1-AD0455EF27D3A7B8...` |
| PXA ESN 例 | `NFAPPL-02-IPHONE9=1-PXA-0202P2P3KTB3...` |
| ESN 取得方法 | `/getProxyEsn` で動的取得 |
| DRM | **FairPlay** (Widevine ではない) |
| MSL トランスポート | NSURLSession (HTTPS) |
| MSL ペイロード暗号化 | AES-CBC + HMAC-SHA256 |
### 二重 ESN 体系
| ESN 種別 | 用途 | 形式 |
|---------|------|------|
| PRV (Private) | ライセンス取得、MSL 通信 | `NFAPPL-02-{MODEL}-{hash}` |
| PXA (Proxy Auth) | HTTP 直接通信 (Falcor UI) | `NFAPPL-02-{MODEL}-PXA-{hash}` |
### HTTP ヘッダー (Falcor 直接通信時)
```
X-Netflix.client.ftl.esn: {PXA ESN}
X-Netflix.client.type: argo
User-Agent: Argo/15.48.1 (iPhone; iOS 15.8.3; Scale/2.00)
Cookie: NetflixId=...; SecureNetflixId=...; nfvdid=...
```
---
## 3. マニフェスト取得
MSL ゲートウェイ: `ios.prod.ftl.netflix.com` / `ios.prod.cloud.netflix.com`
### 提供されるコーデック (実測)
| 解像度 | プロファイル |
|--------|------------|
| 480x270 〜 1920x1080 | `playready-h264hpl22-dash` 〜 `playready-h264hpl40-dash` |
| 480x270 〜 1920x1080 | `hevc-main10-L30-dash-cenc-prk-do` 〜 `hevc-main10-L31-dash-cenc-prk-do` |
H.264 と HEVC の両方が提供される。
---
## 4. ライセンスチャレンジ (FairPlay)
**エンドポイント:** `POST /nq/iosplatform/pbo_license/~1.0.0/router`
### FairPlay フロー (Widevine とは異なる)
```
SPC (Server Playback Context) → Netflix サーバー → CKC (Content Key Context) → FairPlay CDM
```
1. マニフェストからコンテンツ ID を取得
2. FairPlay CDM に SPC (Server Playback Context) 生成を要求
3. SPC を MSL ペイロードに包んで `/pbo_license/router` に POST
4. レスポンスから CKC (Content Key Context) を取得
5. CKC を FairPlay CDM にインストール → コンテンツ鍵 ready
### ライセンスリクエストパラメータ
```json
{
"url": "/license?licenseType=standard&playbackContextId=...&esn=NFAPPL-02-...-PRV-...",
"params": {
"videoTrackName": "...",
"preferredlanguages": [...]
}
}
```
### FairPlay 固有の暗号化操作 (実測)
MSL ペイロード内で以下の暗号化操作が行われる:
- `aesCbcEncrypt`: リクエストペイロードの暗号化
- `aesCbcDecrypt`: レスポンスペイロードの復号
- `hmacSha256`: メッセージ認証コード生成
- `hmacVerify`: メッセージ認証コード検証
---
## 5. 再生方式
- **HLS** (HTTP Live Streaming) — DASH ではない
- **AVPlayer** で再生
- FairPlay DRM で保護されたセグメントを AVPlayer が透過的に復号
---
## 6. テレメトリ
| エンドポイント | 用途 |
|--------------|------|
| `/msl/playapi/ios/event` | 再生イベント (play, pause, stop, position) |
| `/msl/playapi/ios/logblob` | テレメトリデータ (品質指標、バッファリング等) |
---
## 7. MSL 復号パイプライン
詳細: [ios_msl_decrypt_pipeline.md](ios_msl_decrypt_pipeline.md)
### 7.1 鍵取得
Tweak `AppbootKeyExtract` が NFWebCrypto.framework の OpenSSL エクスポート関数をフックし、
DH 鍵交換 + セッション鍵をキャプチャする:
| フック対象 | 取得する鍵 |
|-----------|----------|
| `DH_generate_key` | DH 公開鍵・秘密鍵 (各 128 bytes) |
| `DH_compute_key` | DH 共有秘密 (128 bytes) |
| `AES_set_encrypt_key` (128-bit) | セッション暗号化鍵 (16 bytes) |
| `HMAC` (key_len=32) | セッション署名鍵 (32 bytes) |
### 7.2 CBOR MSL 固有の差異
| 項目 | JSON MSL (Chrome) | CBOR MSL (iOS) |
|------|--------------------|---------------|
| IV 格納 | `"iv"` フィールド (Base64, 16B) | ciphertext に prepend |
| 復号後圧縮 (リクエスト) | gzip (Base64 経由) | CBOR bstr フレーム + gzip |
| 復号後圧縮 (レスポンス) | gzip | raw deflate (`00 00` prefix) |
### 7.3 復号 CLI
```bash
python tools/decrypt_capture.py --keys raws/msl_keys.json --input capture.bin
```