Files
armatak/docs/development/authentication-flows.md
2026-08-07 14:06:49 -03:00

8.9 KiB

TAK authentication flows

This document describes the authentication and transport flows implemented by the ArmaTAK Rust extension. It is development documentation, not end-user documentation.

Security model

ArmaTAK currently exposes three TCP connection modes:

Mode ArmaTAK entry point Authentication Transport protection Intended use
Plain TCP tcp_socket.start None None Local development or explicitly trusted isolated networks only
Manual mTLS tcp_socket.start_mtls Client X.509 certificate TLS with server certificate validation Production-compatible secure connection
Credential enrollment followed by mTLS tcp_socket.start_enroll_mtls HTTP Basic credentials during enrollment, then client X.509 certificate Enrollment HTTPS currently skips certificate validation; the resulting TAK stream uses validated mTLS Transitional/bootstrap flow; do not treat the enrollment phase as secure until server verification is enabled

The official TAK Server example enables a TLS input on port 8089. Its plaintext TCP/streaming examples are anonymous and are shown on ports 8087 and 8088. ArmaTAK must not infer security from a port number; the selected connection mode controls the client-side security properties.

Insecure flow: plain TCP

The plain flow is deliberately simple:

Arma/SQF
   |
   | tcp_socket.start("host:port")
   v
ConnectionConfig::Plain
   |
   v
TCP connect
   |
   | unencrypted CoT bytes
   v
TAK Server plaintext/anonymous input

ConnectionConfig::Plain resolves the supplied address and opens a normal TcpStream. No TLS handshake occurs, there is no server identity verification, and no client identity is established by ArmaTAK.

Consequences:

  • CoT payloads can be observed or modified by an on-path attacker.
  • ArmaTAK cannot prove that it connected to the intended TAK Server.
  • The server cannot authenticate ArmaTAK by certificate.
  • Plain TCP must never be the production default.

The official TAK Server CoreConfig.example.xml keeps anonymous TCP inputs commented out and enables the TLS input instead. Use plain TCP only when a developer intentionally configures a corresponding non-TLS server input.

Secure flow: manual mTLS

The manual mTLS flow uses pre-provisioned certificate material:

Arma/SQF
   |
   | tcp_socket.start_mtls(
   |   address,
   |   server_name,
   |   ca_cert_path,
   |   client_cert_path,
   |   client_key_path
   | )
   v
ConnectionConfig::Mtls
   |
   +--> load trusted CA certificate(s)
   +--> load client certificate chain
   +--> load client private key
   |
   v
rustls client configuration
   |
   +--> validate server certificate chain
   +--> validate TLS server name
   +--> present client certificate
   v
Authenticated mTLS TAK stream

The CA file is loaded into a dedicated rustls::RootCertStore; the client certificate and private key are used for client authentication. When server_name is empty, ArmaTAK derives a name from the target address. A non-empty server_name should be preferred when DNS and certificate names are known.

This is the preferred production flow when certificate provisioning is handled outside ArmaTAK.

Enrollment flow: credentials to client certificate

TAK enrollment converts a username/password bootstrap credential into a short- or medium-lived client certificate, then reconnects using mTLS.

Protocol contract

ArmaTAK follows the contract visible in the official TAK Server and ATAK implementations:

  1. GET https://HOST:ENROLL_PORT/Marti/api/tls/config
  2. Authenticate the request with HTTP Basic credentials.
  3. Read serverPort and enrollPath from the TAK certificate configuration. If the fields are absent, ArmaTAK currently falls back to 8089 and /Marti/api/tls/signClient/v2.
  4. Generate a local RSA key pair and PKCS#10 CSR. The private key never needs to be sent to the server.
  5. POST https://HOST:ENROLL_PORT{enrollPath}?clientUid=CLIENT_UID
  6. Authenticate the signing request with HTTP Basic credentials, send the CSR as application/pkcs10, and request JSON.
  7. Parse signedCert and ca0 from the enrollment response.
  8. Build an in-memory client identity from the returned certificate plus the locally generated private key.
  9. Connect to HOST:serverPort with mTLS and validate the TAK streaming server against the returned CA.

The official TAK Server exposes /tls/config, /tls/signClient, and /tls/signClient/v2. The v2 endpoint can return JSON containing signedCert plus ca0, ca1, and additional CA-chain entries. The current ArmaTAK implementation consumes signedCert and ca0.

Current ArmaTAK enrollment security caveat

enrollment_http_client() currently uses danger_accept_invalid_certs(true). Therefore the HTTPS bootstrap does not authenticate the enrollment server certificate.

That means the current enrollment phase is vulnerable to an active man-in-the-middle attacker who can impersonate the HTTPS enrollment endpoint and receive the submitted Basic credentials. The private key remains local, but the username/password bootstrap secret is still exposed to the impersonating endpoint.

The connection established after enrollment is mTLS and uses the returned CA, but that does not retroactively secure the bootstrap exchange. Consequently:

  • start_enroll_mtls is a transitional flow, not the preferred production-secure flow in its current form.
  • start_mtls with a trusted CA and pre-provisioned client certificate is the secure production path today.
  • A future secure enrollment implementation must validate the HTTPS server with a trusted CA, certificate pin, or equivalent authenticated trust bootstrap.
  • An explicit insecure/development enrollment switch is preferable to silently disabling verification.

The official ATAK enrollment manager exposes a verifyHost choice and records whether host verification is on or off. ArmaTAK should converge on the same explicit distinction.

Target secure enrollment design

The intended production enrollment flow is:

username/password
      |
      v
HTTPS enrollment endpoint
(server certificate MUST validate)
      |
      +--> GET /Marti/api/tls/config
      +--> generate local private key + CSR
      +--> POST configured signClient endpoint
      v
signed client certificate + trusted CA
      |
      v
mTLS TAK streaming connection
      |
      +--> server authenticated by CA/name
      +--> client authenticated by certificate
      v
CoT traffic

The development-only insecure variant should be explicit:

username/password
      |
      v
HTTPS enrollment endpoint
(certificate verification explicitly disabled)
      |
      v
WARNING / development-only path

Do not silently fall back from verified enrollment to unverified enrollment after a certificate validation failure.

Secret-handling requirements

  • Never include passwords, private keys, certificate payloads, or Authorization headers in logs.
  • ConnectionConfig::describe() may include the username and client UID for diagnostics, but it must never include the password.
  • Keep generated private keys in memory unless a future feature explicitly requires persistence.
  • Do not commit development certificates or credentials to the repository.
  • Treat enrollment credentials as bootstrap secrets and rotate/revoke them according to the TAK Server deployment policy.

Test contract

Unit tests should lock down the protocol-level behavior that does not require a live TAK Server:

  • official endpoint paths and default mTLS port;
  • trimming and construction of enrollment URLs;
  • parsing TAK enrollment configuration with explicit values and fallback defaults;
  • PEM normalization;
  • absence of passwords from diagnostic descriptions;
  • TLS server-name derivation and PEM parsing where deterministic;
  • CoT and MAVLink pure serialization logic.

Live certificate signing, TLS handshake behavior, socket reconnect behavior, mDNS, video processes, and Arma callback behavior belong in integration/E2E tests because they depend on operating-system or external-server state.

Upstream references

The tests and protocol assumptions in this repository are based on these upstream implementations:

Pinning the source revisions in this document keeps the development contract reproducible. When the upstream protocol changes, update both the implementation/tests and these references together.