Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,13 @@
/shard.lock

/http_proxy
/.mitm-certs/

# Local MITM certificates/keys (generated for manual testing)
/mitm-ca.crt
/mitm-ca.key
/mitm-ca.srl
/mitm.crt
/mitm.key
/mitm.csr
/mitm.ext
65 changes: 65 additions & 0 deletions MITM_CHECKLIST.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# MITM Production Readiness Checklist

Status key:

- [x] Done
- [ ] Not done
- [~] Partial

## Security

- [ ] Store CA private key outside repository with strict permissions (`600`) and dedicated service account.
- [ ] Add CA key rotation procedure and documented migration plan.
- [ ] Add encrypted CA key / passphrase support.
- [~] Keep sensitive logging disabled by default (`debug: false`), but add redaction for auth/cookies/tokens when debug is enabled.
- [ ] Add host allowlist/denylist policy for MITM interception.

## Certificate Generation

- [x] Dynamic per-host certificate generation is implemented.
- [x] In-process generator is implemented in `src/http/proxy/server/certificate_generator.cr`.
- [x] Certificate cache directory support exists (`certificate_cache_dir`).
- [x] Basic SAN generation exists for DNS/IP hostnames.
- [ ] Serial number strategy should be strengthened (currently timestamp-based).
- [ ] Add cert cache lifecycle controls (TTL/max size/pruning).

## Protocol Behavior

- [x] CONNECT MITM flow for HTTP/1.1 is implemented.
- [x] ALPN is constrained to HTTP/1.1 in server contexts.
- [~] Non-HTTP streams are detected and aborted in MITM path; consider explicit passthrough/tunnel fallback policy.
- [ ] Define and document policy for HTTP/2/HTTP/3 handling in production mode.

## Reliability & Resilience

- [x] Mutex-protected per-host context cache prevents concurrent generation races.
- [ ] Add bounded concurrency / connection limits.
- [ ] Add timeout and retry policy for upstream requests and TLS handshakes.
- [ ] Add graceful shutdown behavior for active MITM sessions under load.
- [ ] Add robust error taxonomy and user-facing failure modes.

## Observability

- [x] Debug output is gated behind `MITMConfig#debug`.
- [ ] Replace ad-hoc debug prints with structured logs for production diagnostics.
- [ ] Add metrics (handshake failures, generation latency, cache hits/misses, upstream status rates).
- [ ] Add health/readiness check endpoint or command.

## Testing

- [ ] Unit tests for certificate generator (key generation, CSR, signing, SAN DNS/IP).
- [ ] Integration tests for browser trust flow (Firefox/Chromium with local CA).
- [ ] Negative tests (invalid CA files, malformed CONNECT targets, broken cert cache files).
- [ ] Load/stress tests for concurrent CONNECT traffic and cert generation.

## Operations

- [~] Runtime sample exists (`samples/server_mitm.cr`) and README usage is documented.
- [ ] Add deployment profile (systemd/service config, restart policy, file permissions).
- [ ] Add operational runbook (bootstrap CA, trust install, rotation, incident recovery).
- [ ] Add secure secret management guidance for CA private key.

## Current Assessment

- Overall maturity: **Advanced MVP / Beta**
- Not yet production-ready due to outstanding hardening, testing depth, and operational controls.
56 changes: 55 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,60 @@ server = HTTP::Proxy::Server.new(handlers: [
end
```

#### HTTPS MITM (MVP, CONNECT HTTP/1.1 only)

```crystal
server = HTTP::Proxy::Server.new
server.mitm = HTTP::Proxy::Server::MITMConfig.new(
ca_certificate_path: "./certs/mitm-ca.crt",
ca_private_key_path: "./certs/mitm-ca.key",
certificate_cache_dir: "./.mitm-certs",
debug: false,
)

address = server.bind_tcp("127.0.0.1", 8080)
puts "Listening on http://#{address}"
server.listen
```

Notes:

- This enables HTTPS interception for `CONNECT` requests.
- The certificate authority (CA) used to sign MITM certs must be trusted by clients.
- This MVP is intended for HTTP/1.1 traffic over CONNECT.

Certificate files:

- `mitm-ca.crt` / `mitm-ca.key`: local CA (trust anchor used to sign dynamic leaf certs).
- `./.mitm-certs/*.crt` / `./.mitm-certs/*.key`: generated per-host leaf certificates.

Static mode is still available:

- `mitm.crt` / `mitm.key`: a single leaf certificate and key presented by the proxy.

Firefox setup:

- Import `mitm-ca.crt` in **Authorities** and trust it for websites.
- Do **not** import `mitm.crt` into Authorities.

Server setup:

- Dynamic mode (recommended): pass `mitm-ca.crt` as `ca_certificate_path` and `mitm-ca.key` as `ca_private_key_path`.
- Static mode: pass `mitm.crt` as `certificate_chain_path` and `mitm.key` as `private_key_path`.

Run dynamic MITM sample:

```bash
crystal run samples/server_mitm.cr
```

Useful flags:

- `--ca-cert ./mitm-ca.crt`
- `--ca-key ./mitm-ca.key`
- `--cache-dir ./.mitm-certs`
- `--debug` (enable verbose MITM request/response output)

### Client

#### Make request with proxy
Expand Down Expand Up @@ -112,7 +166,7 @@ puts response.body
* [x] HTTPS Proxy: CONNECT support
* [x] Make context.request & context.response writable
* [x] Basic Authentication
* [ ] MITM HTTPS Proxy
* [x] MITM HTTPS Proxy (MVP, CONNECT HTTP/1.1)

### Proxy client

Expand Down
30 changes: 30 additions & 0 deletions mitm-ca.crt
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
-----BEGIN CERTIFICATE-----
MIIFITCCAwmgAwIBAgIUKE5Bbf3Q2Y6N9QR1x4yEZPa0pFIwDQYJKoZIhvcNAQEL
BQAwGDEWMBQGA1UEAwwNTG9jYWwgTUlUTSBDQTAeFw0yNjAyMjcxNTM5MjhaFw0z
NjAyMjUxNTM5MjhaMBgxFjAUBgNVBAMMDUxvY2FsIE1JVE0gQ0EwggIiMA0GCSqG
SIb3DQEBAQUAA4ICDwAwggIKAoICAQDb8uaLhVtvrSso3j/G0HJBiz5zMl6zUBnz
zLuv0Dhqpyia4t/6qKu8jco4+iW978bjx4LvsNPzM/jq6Mc0I/BTH6opP/ckPGfL
IK7VYPoaWbQMFy0NpEmesgZgyb62TiSCuWtlBNDRYOyqriTcH4xMk9M1PKtx0GBp
cmphX+b0o/VHzXJ3WcxNnLn3k/vTmSGjzBV3eHE47A2iZVR0ukUm/GJOz3i+zaWq
CimY7VGUEuOK+iSf/zcXE+NcUkofdw3ZuLsRrBZZyQeh+lGRD7YU6OYsczuzb3XJ
AECIte83Ko03KkLxyoD+rYlT+CVb0S4O0w5TycGxLa5RzzCXmu0ZVoEtz9bw6VoD
eiBiI+FGlNFxgSi6WtRCsZ11Uw9Z/Pry2Ot62k18U9rS5lQhTOqplfEmksKIEsTK
7RDABEPeP8PPASrVr6BuSzgWq2FbVVu41tZ/TWwXwY9KsbhYTe9Sr8HbvWoT8mQS
UAe/lZWvCZvP8vp0fnHIj5Ci+2nGLy42p0Ft6ON7GEfbqQV63bKWZjP6jtgF7SNs
Tb7cMCyam4J5f181Uds0qMw0IdobUmG2LN64CNAVjF+8d+VRobkO8sKVYxIAAO+G
JeOTOtRSMvLD2+SQQ27XQBx4lMNeOo6fFs3jkcG7LQ8okXwo4lc9StVKWexh1WhP
APVBZs9DLQIDAQABo2MwYTAdBgNVHQ4EFgQUr4xEWjgXxTQgiArF09zoj4GIxw4w
HwYDVR0jBBgwFoAUr4xEWjgXxTQgiArF09zoj4GIxw4wDwYDVR0TAQH/BAUwAwEB
/zAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQELBQADggIBAMfKybOvRZalGj8p
IZxm/QERRYbk8mTuc9j/KZ4B6Nrr7DLKi5Dsx/dqBRYkdsQEJzxDw2RESYW+HxlS
BtLTpJyO4Mj9oBzaN0MFfKk8gAgNEeT7hbdKwiCoug26r/+LOfnhddlw1gayB8JF
Egu4x67EGWwP2gZJRJYY1/fjr8F39TByqhBWTzbmpq6INNu9hIfBSq+libPwnTNL
dBvmeY9mo7441HScXeGW8JJnf1sg3vGwC+3qDVFZilvV33/FRehb3g78yR8VTyp7
9dEi0y/PqFOLOQFvvgwKo6g8yruoCPGeMLW99za6Xts79/tpj1QYIqsJb31ESxEc
ZBEqPXuRJOPjs2mGw3bnoYYlTrKB50gxezN1nOd4uvXohqKmoZ/S4Oc6fI8VuaHc
SfC9PJQ9AeW/DMgvBdo3dIc2KTd0536iW6RwybMKg7KGM7J39LRjbIriM1hU9wzV
KJW5wsUqENu7S+Vy2IUk8uZ4YJGPAbVbOSV2mpN03DJebpVeY6u5IoIj1LqDPZ/L
SXxKrlPSMCkrHfUoJWSIFuXglVYQnS0vXk7NyFbtT4tkb+7QO7XprJA9DD+oLpSK
GRH53WVAZL8JbCA5EifM5Ff24qCFHgzfe5fvNqUfF3qy5CyRmxugtEUzmAkJJfo/
Y8ZH/T0v0jhMXQgbLRMr2t/Gz/xT
-----END CERTIFICATE-----
52 changes: 52 additions & 0 deletions mitm-ca.key
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
-----BEGIN PRIVATE KEY-----
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
2XDQweSmPKqwgTMSvbabrXiI0Ekm
-----END PRIVATE KEY-----
2 changes: 1 addition & 1 deletion samples/server.cr
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ require "../src/http_proxy"
require "option_parser"

host = "127.0.0.1"
port = 8081
port = 8080

OptionParser.parse do |opts|
opts.on("-h HOST", "--host HOST", "define host to run server") do |opt|
Expand Down
65 changes: 65 additions & 0 deletions samples/server_mitm.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
require "../src/http_proxy"
require "option_parser"

host = "127.0.0.1"
port = 8080
ca_certificate_path = "./mitm-ca.crt"
ca_private_key_path = "./mitm-ca.key"
certificate_cache_dir = "./.mitm-certs"
upstream_insecure = false
debug = false

OptionParser.parse do |opts|
opts.banner = "Usage: crystal run samples/server_mitm.cr -- [arguments]"

opts.on("-h HOST", "--host HOST", "define host to run server") do |opt|
host = opt
end

opts.on("-p PORT", "--port PORT", "define port to run server") do |opt|
port = opt.to_i
end

opts.on("--ca-cert PATH", "path to MITM CA certificate PEM (dynamic per-host cert mode)") do |opt|
ca_certificate_path = opt
end

opts.on("--ca-key PATH", "path to MITM CA private key PEM (dynamic per-host cert mode)") do |opt|
ca_private_key_path = opt
end

opts.on("--cache-dir PATH", "directory to store generated host certificates") do |opt|
certificate_cache_dir = opt
end

opts.on("--upstream-insecure", "disable upstream TLS verification") do
upstream_insecure = true
end

opts.on("--debug", "enable verbose MITM request/response debug output") do
debug = true
end
end

server = HTTP::Proxy::Server.new(handlers: [
HTTP::LogHandler.new,
])

server.mitm = HTTP::Proxy::Server::MITMConfig.new(
ca_certificate_path: ca_certificate_path,
ca_private_key_path: ca_private_key_path,
certificate_cache_dir: certificate_cache_dir,
upstream_insecure: upstream_insecure,
debug: debug,
)

address = server.bind_tcp(host, port)
puts "Listening on http://#{address}"
puts "MITM mode enabled (CONNECT HTTP/1.1 MVP)"
puts "Certificate mode: dynamic per-host"
puts "CA certificate: #{ca_certificate_path}"
puts "CA private key: #{ca_private_key_path}"
puts "Certificate cache dir: #{certificate_cache_dir}"
puts "Upstream TLS verification: #{upstream_insecure ? "DISABLED" : "ENABLED"}"
puts "MITM debug output: #{debug ? "ENABLED" : "DISABLED"}"
server.listen
48 changes: 48 additions & 0 deletions src/ext/openssl/lib_crypro.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
require "openssl/lib_crypto"

lib LibCrypto
alias EVP_PKEY = Void*
alias EVP_PKEY_CTX = Void*
alias X509_REQ = Void*
alias ASN1_INTEGER = Void*
alias ASN1_TIME = Void*

EVP_PKEY_RSA = 6

fun evp_pkey_ctx_new_id = EVP_PKEY_CTX_new_id(id : Int32, e : Void*) : EVP_PKEY_CTX
fun evp_pkey_ctx_free = EVP_PKEY_CTX_free(ctx : EVP_PKEY_CTX)
fun evp_pkey_keygen_init = EVP_PKEY_keygen_init(ctx : EVP_PKEY_CTX) : Int32
fun evp_pkey_ctx_ctrl_str = EVP_PKEY_CTX_ctrl_str(ctx : EVP_PKEY_CTX, type : UInt8*, value : UInt8*) : Int32
fun evp_pkey_keygen = EVP_PKEY_keygen(ctx : EVP_PKEY_CTX, ppkey : EVP_PKEY*) : Int32
fun evp_pkey_free = EVP_PKEY_free(pkey : EVP_PKEY)

fun bio_new_file = BIO_new_file(filename : UInt8*, mode : UInt8*) : Bio*
fun bio_free_all = BIO_free_all(bio : Bio*) : Int32

fun pem_read_bio_private_key = PEM_read_bio_PrivateKey(bp : Bio*, x : EVP_PKEY*, cb : Void*, u : Void*) : EVP_PKEY
fun pem_write_bio_private_key = PEM_write_bio_PrivateKey(bp : Bio*, x : EVP_PKEY, enc : Void*, kstr : UInt8*, klen : Int32, cb : Void*, u : Void*) : Int32

fun pem_read_bio_x509 = PEM_read_bio_X509(bp : Bio*, x : X509*, cb : Void*, u : Void*) : X509
fun pem_write_bio_x509_req = PEM_write_bio_X509_REQ(bp : Bio*, x : X509_REQ) : Int32
fun pem_write_bio_x509 = PEM_write_bio_X509(bp : Bio*, x : X509) : Int32

fun x509_req_new = X509_REQ_new : X509_REQ
fun x509_req_free = X509_REQ_free(req : X509_REQ)
fun x509_req_set_version = X509_REQ_set_version(req : X509_REQ, version : Long) : Int32
fun x509_req_set_subject_name = X509_REQ_set_subject_name(req : X509_REQ, name : X509_NAME) : Int32
fun x509_req_set_pubkey = X509_REQ_set_pubkey(req : X509_REQ, pkey : EVP_PKEY) : Int32
fun x509_req_sign = X509_REQ_sign(req : X509_REQ, pkey : EVP_PKEY, md : EVP_MD) : Int32
fun x509_req_get_subject_name = X509_REQ_get_subject_name(req : X509_REQ) : X509_NAME
fun x509_req_get_pubkey = X509_REQ_get_pubkey(req : X509_REQ) : EVP_PKEY

fun x509_set_version = X509_set_version(x : X509, version : Long) : Int32
fun x509_set_issuer_name = X509_set_issuer_name(x : X509, name : X509_NAME) : Int32
fun x509_set_pubkey = X509_set_pubkey(x : X509, pkey : EVP_PKEY) : Int32
fun x509_sign = X509_sign(x : X509, pkey : EVP_PKEY, md : EVP_MD) : Int32
fun x509_get_serial_number = X509_get_serialNumber(x : X509) : ASN1_INTEGER
fun x509_getm_not_before = X509_getm_notBefore(x : X509) : ASN1_TIME
fun x509_getm_not_after = X509_getm_notAfter(x : X509) : ASN1_TIME

fun asn1_integer_set = ASN1_INTEGER_set(a : ASN1_INTEGER, v : Long) : Int32
fun x509_gmtime_adj = X509_gmtime_adj(s : ASN1_TIME, adj : Long) : ASN1_TIME
end
5 changes: 4 additions & 1 deletion src/http/proxy/server.cr
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ require "socket"
require "wait_group"
require "./server/handler"
require "./server/context"
require "./server/mitm_config"
{% if !flag?(:without_openssl) %}
require "openssl"
{% end %}
Expand All @@ -28,6 +29,8 @@ class HTTP::Proxy::Server
# Returns `true` if this server is listening on its sockets.
getter? listening : Bool = false

property mitm : MITMConfig?

# Creates a new HTTP Proxy server
def initialize
handler = build_middleware
Expand Down Expand Up @@ -61,7 +64,7 @@ class HTTP::Proxy::Server
end

private def build_middleware(handler : (Context ->)? = nil)
proxy_handler = Handler.new
proxy_handler = Handler.new(-> { @mitm })
proxy_handler.next = handler if handler
proxy_handler
end
Expand Down
Loading