Skip to content

Add configurable min/max TLS version with hybrid per-transport default - #7

Draft
DanPeterson wants to merge 2 commits into
OneIdentity:mainfrom
DanPeterson:danpeterson-tls13-pha-evaluation
Draft

Add configurable min/max TLS version with hybrid per-transport default#7
DanPeterson wants to merge 2 commits into
OneIdentity:mainfrom
DanPeterson:danpeterson-tls13-pha-evaluation

Conversation

@DanPeterson

Copy link
Copy Markdown
Contributor

Summary

SPP 9.0 enables TLS 1.3. Go's crypto/tls client cannot answer a TLS 1.3 post-handshake CertificateRequest (verified in the stdlib: handlePostHandshakeMessage only handles newSessionTicketMsgTLS13/keyUpdateMsg; a certificateRequestMsgTLS13 errors with unexpected_message, and Go never advertises post_handshake_auth). Because SPP certificate login and A2A rely on SPP's post-handshake certificate request, they break against a TLS 1.3-only appliance on the Standard binding. Password / PKCE / browser / device-code / token flows are unaffected.

This PR makes the TLS version window configurable and picks a safe hybrid default so cert-auth keeps working out of the box on 9.0.

What changed

New options (tls.go):

  • WithMinTLSVersion(v uint16) / WithMaxTLSVersion(v uint16) — a uint16 passthrough to crypto/tls version constants. No custom enum, so a future TLS 1.4 works with zero SDK change. Sub-1.2 is allowed as an explicit escape hatch (guarded #nosec G402).

Hybrid per-transport default (transport.go, tls.go):

  • TLS 1.2 floor everywhere.
  • serverTrust transport (password/token/PKCE) stays open to 1.3.
  • clientCert transport (certificate login, A2A) is capped at 1.2 when no explicit version option is set — so post-handshake cert-auth "just works" on the 9.0 Standard binding.
  • Setting either option lifts the cap on both transports, enabling TLS 1.3 cert-auth against the appliance Cert SNI hostname (where the cert is requested in the initial handshake). No new code path needed — the existing clientCert transport already presents the cert up front.

Docs & sample:

  • .agents/skills/api-patterns, architecture, a2a-workflow skills + AGENTS.md document the version window, hybrid default, the Cert SNI route, and the 60094 Authorization is denied symptom.
  • samples/certificate gains -min-tls / -max-tls flags.

Tests

tls_test.go: TestBuildTLSConfigVersionWindow, TestClientCertMaxTLSResolver, TestClientCertTransportCapsMaxTLS (default caps clientCert to 1.2 while serverTrust stays open; explicit options lift the cap; max < min is rejected). go build, go vet, gofmt -l, golangci-lint run, and go test ./... are all green.

Live validation against a 9.0 appliance is a maintainer step (CI has no appliance): confirm default cert-auth works at effective 1.2 on the Standard binding, WithMaxTLSVersion(tls.VersionTLS13) + Cert SNI hostname enables 1.3 cert-auth, and WithMinTLSVersion(tls.VersionTLS13) fails closed on Standard-binding cert flows.

Relation to SafeguardJava #190

Same root limitation (JSSE also can't do TLS 1.3 client PHA). Differences: Java defaults to TLS 1.2-only for all traffic via a process-wide static enum; this PR keeps 1.3 for non-cert flows via a per-client, per-transport default and a future-proof uint16 window, matching the PySafeguard min/max approach.

SPP 9.0 enables TLS 1.3. Go's crypto/tls client cannot answer a TLS 1.3
post-handshake CertificateRequest, so certificate login and A2A (which rely
on SPP's post-handshake certificate request) break against a TLS 1.3-only
appliance on the Standard binding.

Add WithMinTLSVersion / WithMaxTLSVersion functional options as a uint16
passthrough to crypto/tls (future-proof; no enum to age). Default is hybrid
per-transport: TLS 1.2 floor everywhere, serverTrust open to 1.3, but the
clientCert transport (certificate login, A2A) capped at 1.2 so post-handshake
cert-auth keeps working out of the box. Setting either option lifts the cap,
enabling TLS 1.3 cert-auth against the appliance Cert SNI hostname.

Update api-patterns/architecture/a2a-workflow skills, AGENTS.md, and the
certificate sample (-min-tls/-max-tls flags).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant