diff --git a/README.md b/README.md
@@ -1,21 +1,18 @@
# mic
mic (mina-is-cute) is a modular Go proxy for controlling outbound TLS fingerprints.
-It lets you pick a browser fingerprint profile and the proxy will use the corresponding
-[`bogdanfinn/utls`](https://github.com/bogdanfinn/utls) preset when connecting to upstream
-servers, making your traffic look like a specific browser to any fingerprinting system.
+Pick a browser profile and the proxy connects upstream with the matching
+[`bogdanfinn/utls`](https://github.com/bogdanfinn/utls) preset.
-Two modes are supported:
+Two modes:
- **client-front**: HTTP CONNECT proxy with optional MitM TLS interception. The proxy
generates a local CA, issues per-host leaf certs on the fly, terminates TLS from
- the client, and re-dials the target with the configured uTLS fingerprint. Standard
+ the client, and re-dials the target with the configured fingerprint. Standard
tools (curl, browsers) work after importing the CA once.
-- **server-front**: the proxy terminates incoming TLS (with your own cert/key), then
- re-dials the backend with the configured fingerprint. Useful when the client cannot
- be configured to use a CONNECT proxy.
-
----
+- **server-front**: the proxy terminates incoming TLS with your own cert/key, then
+ re-dials the backend with the configured fingerprint. Use it when the client cannot
+ be pointed at a CONNECT proxy.
## How it works
@@ -54,12 +51,8 @@ sequenceDiagram
end
```
-In both modes the target sees a TLS handshake that matches the configured fingerprint
-(JA4), not the default Go TLS fingerprint. The ServerHello mic returns to the client
-(JA4S) is currently emitted by stdlib `crypto/tls` and is only measured, not yet
-spoofed. See the JA4S section below for details.
-
----
+The ServerHello mic returns to the client (JA4S) still comes from stdlib
+`crypto/tls`. It is measured, not spoofed. See the JA4S section.
## Build
@@ -67,8 +60,6 @@ spoofed. See the JA4S section below for details.
go build -o mic .
```
----
-
## Running
### client-front
@@ -79,8 +70,8 @@ mic client --listen :8080 --fingerprint chrome-120 \
```
`--intercept-cert` and `--intercept-key` enable MitM interception. mic generates the
-CA files on first run and reuses them. Import the cert once, then all traffic through
-the proxy is transparently intercepted and re-dialled with the configured fingerprint.
+CA files on first run and reuses them. Omit both to run as a plain CONNECT proxy with
+a raw tunnel and no MitM.
**Trust the CA** (pick whichever applies):
@@ -95,15 +86,13 @@ sudo cp ca.pem /usr/local/share/ca-certificates/mic-ca.crt && sudo update-ca-cer
sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain ca.pem
```
-After trusting, standard tools work without extra flags:
+Once trusted, no extra flags are needed:
```bash
curl -x http://localhost:8080 https://tlsinfo.me/json
# check the "ja4" field. It should match the fingerprint you configured.
```
-Omit `--intercept-*` to run as a plain CONNECT proxy (no MitM, raw tunnel only).
-
### server-front
Generate a cert for the proxy to present to clients:
@@ -119,7 +108,7 @@ mic server --listen :8080 --backend 10.0.0.1:443 \
--fingerprint chrome-120
```
-`--backend`, `--cert`, and `--key` are required. `--fingerprint` is optional; without
+`--backend`, `--cert`, and `--key` are required. `--fingerprint` is optional. Without
it the proxy falls back to a randomised uTLS preset.
### Available fingerprint profiles
@@ -140,19 +129,19 @@ preset actually emits. Re-run the probe after upgrading the utls dependency.
| `edge-106` | `t13d1516h2_8daaf6152771_e5627efa2ab1` |
| `opera-91` | same as `edge-106`³ |
| `android-11-okhttp` | `t12d120700_d34a8e72043a_036209cd1ead` (TLS 1.2) |
-
-> ¹ `chrome-120-pq` and `chrome-131` produce the same JA4 as `chrome-120` because JA4
-> does not distinguish key share entries. Use `chrome-120-pq` when you specifically need
-> the X25519MLKEM768 post-quantum key exchange; use `chrome-131` for the most current
-> non-PQ Chrome preset under this hash.
+| `ipad-15` | same as `safari-16`² |
+| `qq-11` | same as `edge-106`³ |
+| `360-7` | `t12d2010s2_0bf03fa604e3_736b2a1ed4d3` (TLS 1.2, spdy ALPN) |
+| `360-11` | `t13d1616h2_46e7e9700bed_4551aecd7b38` |
+
+> ¹ JA4 does not distinguish key share entries. Use `chrome-120-pq` when you need the
+> X25519MLKEM768 post-quantum key exchange, `chrome-131` for the newest non-PQ Chrome
+> preset under this hash.
>
-> ² `ios-16` collides with `safari-16` under JA4 (both ship the same TLS stack).
-> Pick whichever matches the user-agent you intend to imitate.
+> ² `ios-16`, `ipad-15` and `safari-16` ship the same TLS stack.
>
-> ³ `opera-91` collides with `edge-106` (both are Chromium derivatives with matching
-> ClientHello shape). Same logic as above.
-
----
+> ³ `opera-91`, `qq-11` and `edge-106` are all Chromium derivatives with the same
+> ClientHello shape.
## Testing
@@ -164,22 +153,18 @@ go test ./...
go test -tags integration -v ./proxy/... ./fingerprint/...
```
-The integration suite includes JA4 fingerprint verification tests: for each profile,
-both `TestClientFront_JA4` and `TestServerFront_JA4` capture the raw ClientHello sent
-by the proxy's uTLS engine and assert the computed JA4 hash matches the expected value.
-This is the offline equivalent of running `cmd/probe` against tlsinfo.me.
+`TestClientFront_JA4` and `TestServerFront_JA4` capture the raw ClientHello the uTLS
+engine sends for each profile and assert the computed JA4 hash. This is the offline
+equivalent of running `cmd/probe` against tlsinfo.me.
CI runs both suites on every push via `.github/workflows/ci.yml`.
----
-
## JA4S (server-side fingerprint, measurement only)
-mic also computes JA4S, the fingerprint of the ServerHello it emits to clients.
-This is currently **measurement only**: there is no spoofing engine. The
-integration tests `TestServerFront_JA4S_Baseline` and `TestClientFront_JA4S_Baseline`
-capture the bytes mic writes during the TLS handshake and assert the JA4S matches
-a recorded baseline.
+mic computes JA4S, the fingerprint of the ServerHello it emits to clients. There is no
+spoofing engine. `TestServerFront_JA4S_Baseline` and `TestClientFront_JA4S_Baseline`
+capture the bytes mic writes during the handshake and assert the JA4S against a
+recorded baseline.
The baseline is what stdlib `crypto/tls.Server` emits today: `t130200_1301_a56c5b993250`
(TLS 1.3, no ALPN, `TLS_AES_128_GCM_SHA256`, default extension set). It applies to
@@ -192,6 +177,4 @@ Why no spoofing yet:
- TLS 1.3 ServerHello carries only 2-3 extensions, so the JA4S surface is much
smaller than JA4.
-Spoofing would require either forking utls to add a `ServerHelloSpec`, or writing a
-custom TLS server. The measurement code is in place so we can see if that effort is
-worth it once we have real-world JA4S targets.
+Spoofing would need either a utls fork adding a `ServerHelloSpec`, or a custom TLS server.
|