TAK Can authenticates and encrypts every channel it uses, and it keeps each network's data separate on the device when you connect to more than one TAK server at the same time. This page details how communication is secured and how that isolation works.
Architecture & Data Flow
How each channel reaches the device, where it is encrypted, and where the isolation boundaries sit:
flowchart TB SA["TAK Server A
(private)"] SB["TAK Server B
(public)"] FEED["Public feeds
weather Β· ADS-B Β· AIS"] subgraph DEV["TAK Can device"] direction TB ISO["Per-connection isolation
no cross-server forwarding"] BR{"Per-server bridge gate
default-deny"} KC["iOS Keychain
per-server certs and creds Β· device-only"] end MESH["Local mesh
BLE: AES-256-GCM + HMAC
Multipeer: DTLS"] PEERS["Nearby team devices"] SA -->|"mTLS + pinned cert"| ISO SB -->|"mTLS + pinned cert"| ISO FEED -->|"validated HTTPS"| ISO ISO --> BR BR -->|"only if that server opted in"| MESH MESH --- PEERS KC -.->|secures connections| ISO
Security Model Overview
flowchart TB
subgraph SEC["TAK Can Security Layers"]
direction TB
subgraph L1["Transport Security"]
T["TAK Server: TLS 1.2+ mutual cert + TOFU pinning
MC Mesh: DTLS (automatic)
BLE Mesh: AES-256-GCM Β· PSK"]
end
subgraph L2["Data at Rest"]
D2["Core Data: file protection
Logs: completeUntilFirstUserAuth
Keychain: ThisDeviceOnly"]
end
subgraph L3["Access Control"]
AC["Per-server data isolation β no cross-server forwarding
Mesh bridge: per-server opt-in (default-deny)
BLE advertising: callsign hidden"]
end
end
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
Certificate Pinning & Re-Trust
Many TAK servers use self-signed or non-standards-compliant certificates. For those, TAK Can pins the server's certificate the first time it connects (trust-on-first-use). On every later connection the presented certificate must match the pinned one β if it changes, the connection is refused rather than silently accepted, and the server list shows a βCertificate changed β tap to re-trustβ control. This applies to both the live streaming connection and the API client, so a man-in-the-middle inserted after the first trust is detected, not trusted by default. Re-trusting clears the pin so the next connection re-pins whatever the server now presents β for example after a legitimate certificate renewal.
sequenceDiagram
participant A as TAK Can
participant S as TAK Server
A->>S: TLS 1.2+ handshake (+ client cert / mTLS)
S->>A: Server certificate
alt First connection
A->>A: Pin certificate (trust-on-first-use)
A-->>S: Proceed β encrypted channel
else Certificate matches pin
A-->>S: Proceed β encrypted channel
else Certificate changed
Note over A,S: Connection refused.
Server list shows "Certificate changed β tap to re-trust".
end
Multi-Server Data Isolation
TAK Can can connect to several TAK servers at the same time. By default, data is isolated per connection: a Cursor-on-Target event received from one server is never forwarded to another server. Networks the device bridges stay compartmentalized β a marker or position from a private server does not leak onto a public server, and vice-versa.
flowchart LR A["Server A
(private)"] --> D["TAK Can
device"] B["Server B
(public)"] --> D D -. "no cross-server forwarding" .-> X(("β"))
Sharing to the local BLE / Multipeer mesh is per-server opt-in and default-deny. A server's CoT is bridged to the mesh only if that specific server has been explicitly enabled for bridging in its settings. So a private server's data does not fan out to the mesh β or, indirectly, to other connected servers β unless you have consented for that server. The meshβserver direction is symmetric: mesh traffic only reaches servers you have authorized.
Credentials and certificates are stored per server in the iOS Keychain, device-only β never synced to iCloud Keychain and never included in a device backup.
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
Peers authenticate with a challenge-response handshake β HMAC-SHA256 over a random nonce, keyed by the shared PSK:
sequenceDiagram participant P as Peripheral participant C as Central C->>P: BLE connect P->>C: 32-byte random nonce C->>P: HMAC-SHA256(nonce, PSK) Note over P: verify HMAC β match accepts,
mismatch disconnects
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.
Mesh Bridge Access Control
Bridging between a TAK server and the local mesh is off unless you enable it, and it is gated per-server in both directions:
flowchart TD
RX["CoT received"] --> Q1{"From a server
connection?"}
Q1 -->|"yes"| Q2{"Source server
marked 'Bridge'?"}
Q1 -->|"from mesh"| Q3{"Onboarded peer routed to
an authorized server?"}
Q2 -->|"yes"| TOMESH["Share to mesh"]
Q2 -->|"no"| LOCAL["Local only β not bridged"]
Q3 -->|"yes"| TOSRV["Forward to that server"]
Q3 -->|"no"| DROP["Dropped β no leakage"]
Server β mesh (per-server opt-in, default-deny):
CoT from a server is shared to the mesh ONLY if that
server is explicitly marked "Bridge" in its settings.
Servers that are not marked stay fully isolated.
Mesh β server (authorized routing):
1. Route mesh CoT to the server the originating peer is
registered with, when that is known.
2. Otherwise deliver only to servers marked "Bridge".
3. Onboarded peers only β non-onboarded peers' data is
never forwarded to a server.
4. Otherwise dropped β no cross-account leakage.
Result: non-onboarded devices can see each other on mesh
but cannot reach a TAK server through a bridge, and
no server's data crosses to the mesh (or to another
server) unless you have explicitly authorized it.
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
- Mesh replay protection: Replayed mesh messages are rejected β message-ID de-duplication plus a freshness window on the Multipeer mesh; on BLE, events past their validity (stale) time are dropped
- Hardened file import: Data packages, KMZ overlays, and attachments are validated before use β size/entry caps against zip bombs, path-traversal rejection, external-entity (XXE) prevention, and sanitization of server-supplied filenames and hashes
- Phishing-resistant enrollment: The destination host is confirmed before credentials are sent, and the app warns when enrollment fields were pre-filled from an external link
- Thread safety: Connection state, feed IDs, the mesh de-duplication set, and per-server bridge/watchlist state are protected with serial queues and locks