πŸ”’ Security Architecture

Encryption, authentication, and access control at every layer.

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

DataProtectionLevel
Core Data (CoT, contacts, missions)NSPersistentStoreFileProtectionKeycompleteUntilFirstUserAuthentication
Log filesURLFileProtectioncompleteUntilFirstUserAuthentication
Server certificatesiOS KeychainkSecAttrAccessibleAfterFirstUnlockThisDeviceOnly
Server passwordsiOS KeychainkSecAttrAccessibleAfterFirstUnlockThisDeviceOnly
Mesh PSKiOS KeychainkSecAttrAccessibleAfterFirstUnlockThisDeviceOnly

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

Security & Code Review β†’  Β·  ← Back to Documentation