HTTPS TLS Encryption and Certificate Guide
Overview
Toron features built-in HTTPS TLS transport layer security with automatic development certificate generation, ALPN HTTP/2 negotiation (h2, http/1.1), and TLS 1.2+ protocol enforcement.
Configuration in config.yaml
Enable HTTPS and configure certificate paths under the server.tls section of config.yaml:
server:
host: "0.0.0.0"
port: 8443
tls:
enabled: true
cert_file: "./certs/server.crt"
key_file: "./certs/server.key"
auto_dev_cert: false
Auto Development Mode (Self-Signed Certificates)
For local development without existing certificate files, enable auto_dev_cert:
server:
tls:
enabled: true
auto_dev_cert: true
Toron automatically generates an in-memory ECDSA P-256 certificate for localhost and 127.0.0.1.
Per-Host Dynamic SNI & Mutual TLS (mTLS) in routes.yaml
Toron supports configuring dedicated X.509 certificates, Mutual TLS (mTLS) client certificate verification, and minimum TLS versions per virtual host domain directly within routes.yaml:
routes:
# 1. Standard Multi-Tenant Virtual Host with Dedicated Certificate
- type: "upstream"
host: "app.example.com"
prefix: "/"
target: "http://localhost:9001"
tls:
cert_file: "./certs/app.crt"
key_file: "./certs/app.key"
# 2. High-Security Internal Host with Strict Mutual TLS (mTLS) & TLS 1.3
- type: "upstream"
host: "secure.internal.local"
prefix: "/"
target: "http://localhost:9002"
tls:
cert_file: "./certs/internal.crt"
key_file: "./certs/internal.key"
ca_file: "./certs/internal_ca.crt"
client_auth: "require_and_verify" # "no_client_cert", "request_client_cert", "require_any_client_cert", "verify_client_cert_if_given", "require_and_verify"
min_version: "tls1.3" # "tls1.2", "tls1.3"
Supported Client Authentication Policies (client_auth)
no_client_cert: Standard TLS without requesting client certificates (default).request_client_cert: Requests a client certificate during handshake but allows unauthenticated clients.require_any_client_cert: Requires the client to present a certificate without verifying against a CA.verify_client_cert_if_given: Verifies client certificate againstca_fileonly if provided.require_and_verify: Strictly mandates and validates client certificates signed by the configuredca_file(mTLS).
🛡️ ACME Zero-Touch SSL & Hardened HTTP-01 Challenge Responder ([SEC-38])
Toron provides automated, zero-touch certificate issuance and background renewal via ACME (RFC 8555, e.g. Let’s Encrypt). The gateway automatically registers endpoints, proves domain ownership via the HTTP-01 challenge responder (/.well-known/acme-challenge/<token>), and hot-reloads issued certificates into the TLS runtime.
HTTP-01 Protocol Hardening & Validation Standards ([SEC-38])
Prior to SEC-38 (REQ-100, ADR-100, TASK-123), incoming challenge validation requests (/.well-known/acme-challenge/<token>) were processed without strict input validation, allowing arbitrary string payloads to query internal challenge tables under lock contention.
The hardened ACME challenge responder enforces six security and protocol compliance guarantees:
- RFC 8555 §8.3 Base64URL Token Validation:
All tokens are strictly validated via the public zero-allocation validator
IsValidACMEToken. Tokens must consist strictly of characters from the unpadded base64url alphabet ([a-zA-Z0-9_-]). Padding characters (=), directory traversal patterns (..), path separators (/,\), control characters, and high-order Unicode bytes are strictly rejected with400 Bad Request. - Strict Length Boundary Enforcement:
Tokens are strictly bounded to $1 \le \text{len}(token) \le 128$ bytes. Empty tokens (
/.well-known/acme-challenge/) or oversized tokens (>128 bytes) fail fast with400 Bad Request. - Elimination of Silent Whitespace Trimming:
Unlike permissive implementations, Toron eliminates silent
strings.TrimSpace(token). Tokens with leading, trailing, or embedded whitespace strictly trigger400 Bad Request. - HTTP Method Hardening (RFC 7231 §6.5.5 Compliance):
The HTTP-01 challenge responder permits only
GETandHEADmethods. Disallowed methods (POST,PUT,DELETE,PATCH,OPTIONS,CONNECT,TRACE) immediately receive405 Method Not Allowedwith mandatory headersAllow: GET, HEADandContent-Type: text/plain. - Fail-Fast Lock Isolation (CWE-20 / CWE-400 Protection):
Method, syntax, and length validations execute before querying the challenge registry, ensuring invalid or malicious requests never acquire reader locks (
m.mu.RLock()) or trigger hash computations on the gateway’s token registry. - RFC 7231 §4.3.2 HEAD Semantics:
Automated CA validation probes issuing
HEADrequests receive200 OK,Content-Type: text/plain, and exactContent-Length: len(keyAuth), while the response body is strictly omitted (res.Body.Len() == 0). Valid unregistered tokens return404 Not Found(with empty body onHEAD).
ACME Challenge Validation Flow
flowchart TD
Req(["HTTP Request to /.well-known/acme-challenge/*"]) --> MethodCheck{"Method in [GET, HEAD]?"}
MethodCheck -- No --> MethodReject["405 Method Not Allowed<br/>Header: Allow: GET, HEAD<br/>Header: Content-Type: text/plain"]
MethodReject --> End405(["Return HTTP 405 (Lock Never Acquired)"])
MethodCheck -- Yes --> TokenExtract["Extract raw token segment<br/>(No silent whitespace trimming)"]
TokenExtract --> TokenValid{"IsValidACMEToken(token)?<br/>- 1 <= len <= 128<br/>- Alphabet: [a-zA-Z0-9_-]"}
TokenValid -- No --> BadReq["400 Bad Request:<br/>'Invalid ACME Challenge Token'"]
BadReq --> End400(["Return HTTP 400 (Lock Never Acquired)"])
TokenValid -- Yes --> LockAcquire["m.GetHTTP01Challenge(token)<br/>(Acquires m.mu.RLock())"]
LockAcquire --> TokenExists{"Token registered in<br/>m.http01Tokens?"}
TokenExists -- No --> NotFound["404 Not Found<br/>(Write body on GET; empty on HEAD)"]
NotFound --> End404(["Return HTTP 404"])
TokenExists -- Yes --> FormatResp["Status: 200 OK<br/>Content-Type: text/plain<br/>Content-Length: len(keyAuth)"]
FormatResp --> IsHead{"Method == HEAD?"}
IsHead -- Yes --> HeadResp["Omit response body<br/>(RFC 7231 §4.3.2 compliant)"] --> End200(["Return HTTP 200 OK"])
IsHead -- No --> GetResp["Write keyAuth to body"] --> End200