Files
Portal-Camera/mac/README.md
T
2026-09-13 12:15:36 -07:00

50 lines
3.1 KiB
Markdown

# PortalCam for macOS (`mac2`)
Native macOS companion app (`PortalCam.app`) and CoreMediaIO Camera Extension (`CamExtension`) for streaming high-definition video and audio from Portal TV.
## Security Architecture
PortalCam uses a channel-bound, zero-knowledge authentication scheme to pair with Portal TV without sending secrets over the network or exposing connections to Man-in-the-Middle (MITM) proxies:
1. **Self-Signed ECDSA P-256 TLS**:
* Portal TV serves all endpoints over HTTPS via an on-device generated ECDSA NIST P-256 (`secp256r1`) certificate.
2. **Channel-Bound SRP-6a Handshake (RFC 5054)**:
* **Initiation**: User clicks **Pair** in the app. The app calls `POST https://<portal-ip>:5654/auth/srp/init` over an ephemeral TLS session.
* **Channel Binding**: The app extracts the presented leaf TLS certificate DER and computes:
$$\mathbf{tls\_hash} = \text{SHA256}(\text{cert\_der})$$
* **Proof $M_1$ Generation**: The user enters the 6-digit PIN displayed on the TV. The client computes:
$$M_1 = \text{SHA256}(\text{pad256}(A) \parallel \text{pad256}(B) \parallel K \parallel s \parallel \mathbf{tls\_hash})$$
and submits it to `POST https://<portal-ip>:5654/auth/srp/verify`.
* **Mutual Proof $M_2$ Verification**: The Portal TV verifies $M_1$ against its own certificate hash. If verified, it returns server proof $M_2$:
$$M_2 = \text{SHA256}(\text{pad256}(A) \parallel M_1 \parallel K \parallel \mathbf{tls\_hash})$$
along with a random 256-bit bearer token.
* **Client Verification**: The app verifies $M_2$ to confirm the Portal independently knows the shared secret before trusting the server.
### Why Active MITM Attacks Cannot Succeed
If an attacker deploys a rogue proxy:
1. The rogue proxy presents a substitute TLS certificate $C_{\text{rogue}}$ to the Mac.
2. The Mac computes $M_1$ using $\text{SHA256}(C_{\text{rogue}})$.
3. The Portal verifies $M_1$ using $\text{SHA256}(C_{\text{portal}})$.
4. Because the certificate fingerprints differ, $M_1$ verification fails on the Portal TV.
5. The attacker cannot forge $M_1$ or $M_2$ without knowing the ephemeral PIN, which is displayed solely on the physical TV screen and never leaves the room.
### Certificate Pinning & Keychain Storage
Once pairing succeeds:
* The 256-bit bearer token and the certificate's SHA-256 fingerprint are saved in the macOS Data Protection Keychain under access group `ENT9X9U544.com.kovtash.portalcam`:
* `portalAuthToken` — Bearer auth token
* `portalPinnedCertSha256` — Hex SHA-256 digest of the server's ECDSA certificate
* A fallback copy is mirrored into the shared App Group `UserDefaults` (`ENT9X9U544.com.kovtash.portalcam`) for seamless access by the sandboxed camera extension.
* `PortalPinnedSessionDelegate` evaluates all subsequent HTTPS requests (`/video.h264`, `/audio.aac`, `/control/*`). Any TLS certificate mismatch aborts the connection immediately.
## Building and Installing
```sh
cd mac2/PortalCam
xcodebuild -scheme PortalCam -configuration Debug build -derivedDataPath ./build
killall PortalCam 2>/dev/null || true
cp -R ./build/Build/Products/Debug/PortalCam.app /Applications/
open /Applications/PortalCam.app
```