diff --git a/.devcontainer/squid-https-test/.gitignore b/.devcontainer/squid-https-test/.gitignore new file mode 100644 index 0000000..4feb3e6 --- /dev/null +++ b/.devcontainer/squid-https-test/.gitignore @@ -0,0 +1 @@ +squid-ssl diff --git a/.devcontainer/squid-https-test/.vscode/tasks.json b/.devcontainer/squid-https-test/.vscode/tasks.json new file mode 100644 index 0000000..e6b1ed8 --- /dev/null +++ b/.devcontainer/squid-https-test/.vscode/tasks.json @@ -0,0 +1,13 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "squid", + "type": "shell", + "command": "stunnel /etc/stunnel/stunnel.conf & squid -N -d1 -f /etc/squid/squid.conf & sleep 2 && tail -n +1 -F /var/log/squid/access.log", + "runOptions": { + "runOn": "folderOpen" + } + } + ] +} diff --git a/.devcontainer/squid-https-test/Dockerfile b/.devcontainer/squid-https-test/Dockerfile new file mode 100644 index 0000000..b7b0b10 --- /dev/null +++ b/.devcontainer/squid-https-test/Dockerfile @@ -0,0 +1,20 @@ +FROM ubuntu:latest + +# squid-openssl is the Squid build with OpenSSL / SSL-Bump (TLS interception) support. +# stunnel provides the TLS-terminating proxy port in front of Squid. +RUN apt-get update \ + && apt-get install -y \ + squid-openssl \ + stunnel4 \ + openssl \ + ca-certificates \ + iputils-ping \ + dnsutils \ + && rm -rf /var/lib/apt/lists/* + +COPY squid.conf /etc/squid/squid.conf +COPY stunnel.conf /etc/stunnel/stunnel.conf +COPY setup.sh /usr/local/bin/setup.sh +RUN chmod +x /usr/local/bin/setup.sh + +CMD ["sleep", "inf"] diff --git a/.devcontainer/squid-https-test/README.md b/.devcontainer/squid-https-test/README.md new file mode 100644 index 0000000..5259a0e --- /dev/null +++ b/.devcontainer/squid-https-test/README.md @@ -0,0 +1,12 @@ +## Squid HTTPS Test + +A second TLS-intercepting proxy (in addition to the mitmproxy-based `HTTPS Proxy Test`), using Squid with SSL-Bump behind stunnel. + +Squid can only do SSL-Bump on an explicit HTTP `http_port` (it bumps the tunneled TLS of each `CONNECT`), not on an explicit TLS `https_port`. To still expose a real TLS proxy port, stunnel terminates TLS on port `3128` and forwards the decrypted proxy traffic to Squid's localhost-only `http_port`, where SSL-Bump intercepts the connections. A single CA signs both the proxy's `localhost` certificate and the per-host certificates Squid generates, so you only install one certificate on the host. + +- `Dev Containers: Reopen in Container` > `Squid HTTPS Test`. +- The dev container should show two log terminals: one for Squid and one for stunnel (the TLS proxy port). +- First time: Install the CA certificate from `.devcontainer/squid-https-test/squid-ssl/ca.crt` in the OS trust store and restart VS Code. The certificate is generated on the first container start, so it only appears after the container is up. +- Add the user setting `"http.proxy": "https://localhost:3133"`. +- Install GitHub Copilot Chat and use `Developer: GitHub Copilot Chat Diagnostics` to test connections with a HTTPS proxy. Use a second window to test connections from a local extension host. +- Verify in the log terminals of the dev container that the proxy is being used. diff --git a/.devcontainer/squid-https-test/devcontainer-lock.json b/.devcontainer/squid-https-test/devcontainer-lock.json new file mode 100644 index 0000000..219acb6 --- /dev/null +++ b/.devcontainer/squid-https-test/devcontainer-lock.json @@ -0,0 +1,3 @@ +{ + "features": {} +} diff --git a/.devcontainer/squid-https-test/devcontainer.json b/.devcontainer/squid-https-test/devcontainer.json new file mode 100644 index 0000000..2d1b68d --- /dev/null +++ b/.devcontainer/squid-https-test/devcontainer.json @@ -0,0 +1,6 @@ +{ + "name": "Squid HTTPS Test", + "dockerComposeFile": "docker-compose.yml", + "service": "devcontainer", + "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}/.devcontainer/squid-https-test" +} diff --git a/.devcontainer/squid-https-test/docker-compose.yml b/.devcontainer/squid-https-test/docker-compose.yml new file mode 100644 index 0000000..c0dc43a --- /dev/null +++ b/.devcontainer/squid-https-test/docker-compose.yml @@ -0,0 +1,13 @@ +version: '3.4' + +services: + devcontainer: + build: + context: . + dockerfile: Dockerfile + volumes: + - ../../..:/workspaces + - ./squid-ssl:/etc/squid/ssl + ports: + - "127.0.0.1:3133:3128" + command: /bin/sh -c "/usr/local/bin/setup.sh && sleep inf" diff --git a/.devcontainer/squid-https-test/setup.sh b/.devcontainer/squid-https-test/setup.sh new file mode 100644 index 0000000..ed7e563 --- /dev/null +++ b/.devcontainer/squid-https-test/setup.sh @@ -0,0 +1,54 @@ +#!/bin/bash +# Generates the CA used as the signing CA for the certificates Squid generates +# on the fly when bumping (intercepting) TLS connections, plus the localhost +# server certificate stunnel presents on the TLS proxy port. Both are signed by +# the same CA, so installing ca.crt in the host trust store covers everything. +# Idempotent: safe to run on every start. +set -e + +SSL_DIR=/etc/squid/ssl +SSL_DB=/var/lib/squid/ssl_db + +mkdir -p "$SSL_DIR" + +if [ ! -f "$SSL_DIR/ca.crt" ] || [ ! -f "$SSL_DIR/ca.key" ]; then + echo "Generating CA certificate ..." + openssl req -x509 -newkey rsa:2048 -sha256 -days 3650 -nodes \ + -keyout "$SSL_DIR/ca.key" \ + -out "$SSL_DIR/ca.crt" \ + -subj "/CN=Squid HTTPS Test CA" \ + -addext "basicConstraints=critical,CA:TRUE" \ + -addext "keyUsage=critical,keyCertSign,cRLSign" +fi + +# The localhost server certificate stunnel presents on the TLS proxy port. +if [ ! -f "$SSL_DIR/proxy.crt" ] || [ ! -f "$SSL_DIR/proxy.key" ]; then + echo "Generating proxy server certificate ..." + openssl req -new -newkey rsa:2048 -nodes \ + -keyout "$SSL_DIR/proxy.key" \ + -out "$SSL_DIR/proxy.csr" \ + -subj "/CN=localhost" + # macOS (SecTrustEvaluateWithError) enforces Apple's TLS server cert policy: + # leaf validity must be <= 398 days and the serverAuth EKU must be present, + # otherwise the cert is rejected as "not standards compliant" (errSecCertificateNotStandardsCompliant / -67901). + openssl x509 -req -in "$SSL_DIR/proxy.csr" \ + -CA "$SSL_DIR/ca.crt" -CAkey "$SSL_DIR/ca.key" -CAcreateserial \ + -out "$SSL_DIR/proxy.crt" -days 397 -sha256 \ + -extfile <(printf "subjectAltName=DNS:localhost,IP:127.0.0.1\nbasicConstraints=CA:FALSE\nkeyUsage=digitalSignature,keyEncipherment\nextendedKeyUsage=serverAuth") + rm -f "$SSL_DIR/proxy.csr" +fi + +# Squid drops privileges to the 'proxy' user, which must be able to read the key. +chmod 644 "$SSL_DIR/ca.crt" "$SSL_DIR/proxy.crt" +chmod 640 "$SSL_DIR/ca.key" "$SSL_DIR/proxy.key" +chgrp proxy "$SSL_DIR/ca.key" 2>/dev/null || true + +# Initialize the database used to cache the per-host certificates Squid generates. +if [ ! -d "$SSL_DB" ]; then + echo "Initializing SSL certificate database ..." + mkdir -p "$(dirname "$SSL_DB")" + /usr/lib/squid/security_file_certgen -c -s "$SSL_DB" -M 20MB +fi +chown -R proxy:proxy "$SSL_DB" 2>/dev/null || true + +echo "CA certificate to install on the host: .devcontainer/squid-https-test/squid-ssl/ca.crt" diff --git a/.devcontainer/squid-https-test/squid.conf b/.devcontainer/squid-https-test/squid.conf new file mode 100644 index 0000000..9ce95cf --- /dev/null +++ b/.devcontainer/squid-https-test/squid.conf @@ -0,0 +1,28 @@ +# Minimal Squid configuration for a TLS-intercepting proxy. +# +# The TLS-terminating proxy port is provided by stunnel (see stunnel.conf), which +# forwards the decrypted proxy traffic to this plaintext, localhost-only port. +# Squid is a normal HTTP forward proxy here; SSL-Bump intercepts (bumps) the +# tunneled TLS connections established via CONNECT. The CA (ca.crt / ca.key) is +# the signing CA for the per-host certificates Squid generates on the fly. +# (Squid only allows ssl-bump on http_port for explicit forward proxies, not on +# an explicit https_port.) + +http_port 127.0.0.1:3130 ssl-bump cert=/etc/squid/ssl/ca.crt key=/etc/squid/ssl/ca.key \ + generate-host-certificates=on dynamic_cert_mem_cache_size=20MB + +sslcrtd_program /usr/lib/squid/security_file_certgen -s /var/lib/squid/ssl_db -M 20MB +sslcrtd_children 5 + +acl step1 at_step SslBump1 +ssl_bump peek step1 +ssl_bump bump all + +http_access allow all + +# Squid runs as the 'proxy' user and cannot write to /dev/stdout, so log to +# files under /var/log/squid; the `squid` task tails them into the terminal. +logfile_rotate 0 +access_log stdio:/var/log/squid/access.log squid + +coredump_dir /var/spool/squid diff --git a/.devcontainer/squid-https-test/stunnel.conf b/.devcontainer/squid-https-test/stunnel.conf new file mode 100644 index 0000000..e7569de --- /dev/null +++ b/.devcontainer/squid-https-test/stunnel.conf @@ -0,0 +1,15 @@ +# stunnel provides the TLS-terminating HTTPS proxy port. It accepts TLS on 3128 +# (presenting the localhost server certificate) and forwards the decrypted proxy +# traffic to Squid's plaintext, localhost-only port, where SSL-Bump intercepts +# the tunneled TLS connections. + +foreground = yes +pid = +debug = 4 +output = /dev/stdout + +[https-proxy] +accept = 0.0.0.0:3128 +connect = 127.0.0.1:3130 +cert = /etc/squid/ssl/proxy.crt +key = /etc/squid/ssl/proxy.key