Security Model Overview
┌─────────────────────────────────────────────────────────┐
│ TAK Can Security Layers │
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Transport Security │ │
│ │ • TAK Server: TLS 1.2+ with mutual certificate │ │
│ │ • MC Mesh: DTLS (Apple framework, automatic) │ │
│ │ • BLE Mesh: AES-256-GCM with pre-shared key │ │
│ └─────────────────────────────────────────────────────┘ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Data at Rest │ │
│ │ • Core Data: NSPersistentStoreFileProtectionKey │ │
│ │ • Log files: completeUntilFirstUserAuthentication │ │
│ │ • Keychain: ThisDeviceOnly (no iCloud sync) │ │
│ └─────────────────────────────────────────────────────┘ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Access Control │ │
│ │ • Mesh bridge: onboarded peers only │ │
│ │ • Team filter: same-team connections only │ │
│ │ • BLE advertising: callsign hidden │ │
│ └─────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────┘
Server Connection Security
TLS Configuration
Protocol: TLS 1.2 minimum (enforced via sec_protocol_options)
Auth: Mutual TLS — client certificate + server certificate
Identity: SecIdentity from iOS Keychain
Trust: Custom CA truststore + system root CAs
Verification: SecTrustEvaluateWithError with custom anchor certificates
Certificate Flow
1. User imports server data package (.zip) or scans QR code
2. Client certificate + CA cert extracted and stored in Keychain
3. On connect: NWConnection with NWProtocolTLS.Options
4. Client presents SecIdentity to server
5. Server cert verified against custom truststore + system CAs
6. TLS 1.2+ handshake completes → encrypted channel established
Mesh Encryption
MultipeerConnectivity (Foreground)
Apple's framework provides DTLS encryption automatically. Encryption preference is set to .required — unencrypted connections are rejected.
BLE Mesh (Background)
Algorithm: AES-256-GCM (CryptoKit)
Key: 256-bit pre-shared key (PSK)
Key storage: iOS Keychain (kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly)
Nonce: 12 bytes, random per message
Tag: 16 bytes, appended for integrity
Encryption flow:
plaintext CoT → AES.GCM.seal(data, using: psk) → sealed box
sealed box = nonce (12B) + ciphertext + tag (16B)
Decryption flow:
sealed box → AES.GCM.open(box, using: psk) → plaintext CoT
If decryption fails → message dropped (wrong key or tampered)
PSK Distribution
Generation: SecRandomCopyBytes (32 bytes)
Encoding: QR code → takcan-mesh-psk://<base64url-encoded-key>
Distribution: Mission commander displays QR, team scans
Rotation: New key per mission / operational period
Storage: iOS Keychain with Secure Enclave backing
Deletion: Wiped on mission end via MeshPSKManager.deleteKey()
BLE Authentication
Challenge-Response (HMAC-SHA256):
Peripheral Central
│ │
│◄──── BLE connect ────────────────│
│ │
│──── 32-byte random nonce ───────►│
│ │
│◄──── HMAC-SHA256(nonce, PSK) ────│
│ │
│ verify HMAC │
│ match → accept │
│ mismatch → disconnect │
│ │
Data at Rest
| Data | Protection | Level |
|---|---|---|
| Core Data (CoT, contacts, missions) | NSPersistentStoreFileProtectionKey | completeUntilFirstUserAuthentication |
| Log files | URLFileProtection | completeUntilFirstUserAuthentication |
| Server certificates | iOS Keychain | kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly |
| Server passwords | iOS Keychain | kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly |
| Mesh PSK | iOS Keychain | kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly |
ThisDeviceOnly means credentials are never synced to iCloud Keychain or backed up. If the device is lost, credentials cannot be extracted from a backup.
Bridge Access Control
Mesh CoT received by bridge device:
1. Check origin peer's onboarded flag (from discovery message)
2. If onboarded=true → forward to TAK server via TLS
3. If onboarded=false → process locally only, do NOT forward
4. Self-originated CoT → always forward (device is authenticated)
Result: non-onboarded devices can see each other on mesh
but cannot reach the TAK server through a bridge
Additional Protections
- BLE advertising: Generic device name "TAKCan" — callsign not exposed over the air
- Emergency rate limiting: Watch emergency capped at 5-second minimum interval to prevent accidental spam
- XML escaping: All user-supplied values (callsign, video URL, alias) are XML-escaped before CoT generation to prevent malformed messages
- Thread safety: Connection state, feed IDs, and annotation cache protected with serial queues and NSLock