Aller au contenu principal

ADR-028: RFC 8705 Certificate Binding Validation

Status

Accepted

Date

2026-02-01

Context

STOA supports mTLS for API client authentication using RFC 8705 Certificate-Bound Access Tokens. JWT tokens contain a cnf.x5t#S256 claim with the client certificate's SHA-256 fingerprint. The MCP Gateway must validate that the certificate presented by the client (via the TLS-terminating proxy header) matches the fingerprint bound to the JWT.

The challenge: different systems in the chain use different fingerprint formats.

SystemFormatExample
RFC 8705 JWT (cnf.x5t#S256)base64urlhLmVMvjnmCm_I4d8_3nw5A
F5 / Nginx (default)hex lowercase84b99532f8e79829bf23877cff79f0e4
OpenSSL CLI outputhex with colons84:B9:95:32:F8:E7:98:29:BF:23:87:7C:FF:79:F0:E4

Additionally, the header name injected by the TLS-terminating proxy varies per deployment (X-SSL-Client-Cert-SHA256, X-Client-Cert-Fingerprint, SSL_CLIENT_FINGERPRINT, etc.).

  • ADR-027: X509 Header-Based Authentication — header contract between F5 and Keycloak
  • ADR-011: API Security Modes — mTLS for CORE internal APIs
  • CAB-868: Certificate Binding Metrics
  • CAB-1024: UAC-Driven Certificate Binding Policy

Decision

1. Normalize to hex lowercase for all comparisons

All three fingerprint formats are normalized to lowercase hex (no separators) before comparison. This avoids case-sensitivity issues and format ambiguity.

base64url  →  decode  →  hex lowercase
hex upper → lower → hex lowercase
hex:colons → strip → hex lowercase

2. Timing-safe comparison

All fingerprint comparisons use secrets.compare_digest() to prevent timing-based side-channel attacks. This applies to both the MCP Gateway middleware and the shared fingerprint_utils module.

3. Auto-detect format when not specified

detect_format(fingerprint) inspects the string pattern:

  • Contains :hex_colons
  • Matches ^[a-fA-F0-9]+$hex
  • Otherwise → base64url (with charset validation: ^[A-Za-z0-9\-_]+$)

4. UAC-driven configuration

All certificate binding parameters are configurable per tenant via the UAC (Universal API Contract) schema:

UAC PathTypeDefaultDescription
security.authentication.mtls.cert_binding.enabledbooleantrueEnable cert binding validation
security.authentication.mtls.cert_binding.header_namestringX-SSL-Client-Cert-SHA256Header from TLS proxy
security.authentication.mtls.cert_binding.fingerprint_formatenumhexFormat: base64url, hex, hex_colons
security.authentication.mtls.cert_binding.jwt_claimstringcnf.x5t#S256JWT claim path
security.authentication.mtls.cert_binding.strict_modebooleantrueReject if cnf present but header absent

5. Centralized utilities

All format conversion logic lives in control-plane-api/src/services/fingerprint_utils.py:

  • FingerprintFormat enum
  • detect_format(), normalize_to_hex(), hex_to_base64url()
  • fingerprints_match() — timing-safe cross-format comparison

The MCP Gateway duplicates normalization inline (cannot import from control-plane-api), but follows the same algorithm.

6. webMethods policy generation

The UAC cert_binding config generates a webMethods requestProcessing policy action via mappers.py, passing header name, format, JWT claim, and strict mode as input mapping parameters.

Consequences

Positive

  • Works with any F5/LB configuration — header name and format are configurable, not hardcoded
  • No code changes per deployment — UAC schema drives all configuration
  • Secure against timing attackssecrets.compare_digest throughout
  • Cross-format matching — same fingerprint in hex, base64url, or colons all match correctly
  • Feature flagcert_binding_enabled allows progressive rollout

Negative

  • Three format conversions — must handle base64url, hex, and hex_colons correctly
  • UAC schema complexity — adds a nested cert_binding object to security.authentication.mtls
  • Duplicated normalization — MCP Gateway and control-plane-api each have their own implementation (different runtimes)

Risks

  • Base64url ambiguity — a hex string like abcdef1234 could be misdetected as hex when it's actually base64url. Mitigated by explicit format hints in UAC config.
  • Header spoofing — if the proxy header is not stripped from external requests, an attacker could inject a forged fingerprint. Mitigated by F5/Nginx configuration (trusted proxy only).