Certificate and MITM

When a module needs the local certificate, how it is created and installed, what is decrypted and what is not, and how to remove it.

To change HTTPS requests, a module has to read them. Letakof does this inside the VPN tunnel, for the hosts listed in the module’s mitmHosts only: it presents each host a certificate issued by a local certificate authority (CA) that exists on your iPhone alone. This is a man-in-the-middle (MITM) technique, and it works only if you install and trust that CA.

A certificate is not needed for blocking domains (domainRules, domainSets) or for rules on plain HTTP (port 80). It is needed only for HTTPS on port 443. Installing the certificate does not block anything by itself, and a module without hosts decrypts nothing.

How the certificate is made

  • The VPN extension creates it when the app asks, so connect first.
  • It is a root CA unique to your installation: ECDSA P-256, valid for one year, named Letakof Local CA with a short suffix. Certificates for individual hosts are issued on the fly, for 24 hours.
  • The private key is kept in the iOS Keychain, readable by the app and the extension only, after first unlock, on this device only, and without iCloud sync. It is never written to files or the log. The public certificate is stored as a file in the app’s shared folder.

Setting it up

Open Settings → Modules → Module certificate. The title shows the state: Certificate not created, Created, trust not confirmed or Created, installed and trusted, with the SHA-256 fingerprint and the expiry date.

  1. Create certificate (the VPN must be on).
  2. Install profile in Safari. Letakof serves a configuration profile (Letakof Local CA, public certificate only, removable) from a one-time address on your own device and opens it in Safari. Allow the download, then install it under Settings → General → VPN & Device Management.
  3. Enable full trust under Settings → General → About → Certificate Trust Settings → Letakof Local CA.
  4. Check trust (the VPN must be on). Letakof asks the VPN extension about a service name and compares the fingerprint. If it is not trusted, the app tells you to install the profile and enable full trust.

The system windows in steps 2 and 3 belong to iOS and may look different on your version.

What is decrypted

Only TCP connections on ports 443 and 80 to hosts from mitmHosts of enabled modules, except excludedHosts and hosts you excluded yourself. Everything else keeps its original encryption.

A hostname must be known, from the connection or its SNI. If it is unknown (for example a DNS substitution), the connection is not decrypted and the module shows Hostname unavailable.

What cannot be intercepted:

  • Apps that use certificate pinning reject the substitute certificate. This cannot be bypassed.
  • QUIC and other UDP. UDP to port 443 of a module host is rejected locally so the app falls back to TCP.
  • WebSocket and Upgrade pass through untouched, like video, audio, event streams and gRPC.

The connection to the real server is made on the profile’s usual route and verified in full; a chain that relies on the local CA is rejected. The installed CA does not bypass any server protection and gives no access to your accounts.

If an app refuses the substitute certificate, the module shows TLS incompatible. Host diagnostics lists the hosts, and Do not decrypt excludes a host for the following connections.

Removing it

  • Turn the module off, or all modules, and decryption stops. The certificate alone decrypts nothing.
  • Delete certificate removes the key from the Keychain. Then delete the profile yourself in Settings → General → VPN & Device Management. After you reinstall the app, the screen shows Not created and the old profile must also be removed by hand.

Read this before you enable a module

The certificate is needed only to read and change the HTTPS requests of hosts you allowed through modules. The key is created on the device and never leaves the iPhone. A module’s script sees headers, cookies and bodies of those requests. Install only modules whose code you have read: the source address, the author’s name and a SHA-256 do not prove authorship.

Found a mistake? Open an issue on GitHub.