Context
SPP 9.0 (Windows 11 base OS) introduces TLS 1.3 support. When a PySafeguard client negotiates TLS 1.3 for certificate-based authentication (RSTS cert grant / A2A credential retrieval), the asynchronous (aiohttp) code path fails to authenticate (server returns 60094 Authorization is denied). The synchronous (requests) path is unaffected and continues to work over TLS 1.3.
Root cause (SDK side)
On TLS 1.3 the client must be willing to present its certificate via post-handshake authentication (PHA, RFC 8446 Section 4.6.2). Python's ssl.SSLContext only answers a post-handshake CertificateRequest when post_handshake_auth = True. The requests/urllib3 stack sets this up such that cert auth works; the aiohttp SSLContext PySafeguard builds for the async path does not enable it, so the certificate is never sent and auth fails.
This is an SDK-side gap in the async client. Scope of this issue is the SDK only.
Requested enhancements (SDK)
- Enable post-handshake auth on the async cert-auth SSLContext. Set
ssl_ctx.post_handshake_auth = True on the SSLContext used for certificate authentication in the aiohttp path, so async cert/A2A auth succeeds over TLS 1.3.
- Add an opt-in TLS-version control (off by default). Allow a caller to pin the maximum TLS version (
ssl_ctx.maximum_version = ssl.TLSVersion.TLSv1_2) for environments where forcing TLS 1.2 is preferred as an interim measure. Must be explicit opt-in; default behavior should negotiate normally (incl. TLS 1.3).
Acceptance
- Async (aiohttp) certificate auth / A2A retrieval succeeds against an SPP 9.0 appliance over TLS 1.3.
- Sync path behavior unchanged.
- New TLS-version pin is opt-in and documented.
Context
SPP 9.0 (Windows 11 base OS) introduces TLS 1.3 support. When a PySafeguard client negotiates TLS 1.3 for certificate-based authentication (RSTS cert grant / A2A credential retrieval), the asynchronous (aiohttp) code path fails to authenticate (server returns
60094 Authorization is denied). The synchronous (requests) path is unaffected and continues to work over TLS 1.3.Root cause (SDK side)
On TLS 1.3 the client must be willing to present its certificate via post-handshake authentication (PHA, RFC 8446 Section 4.6.2). Python's
ssl.SSLContextonly answers a post-handshakeCertificateRequestwhenpost_handshake_auth = True. Therequests/urllib3 stack sets this up such that cert auth works; the aiohttpSSLContextPySafeguard builds for the async path does not enable it, so the certificate is never sent and auth fails.This is an SDK-side gap in the async client. Scope of this issue is the SDK only.
Requested enhancements (SDK)
ssl_ctx.post_handshake_auth = Trueon theSSLContextused for certificate authentication in the aiohttp path, so async cert/A2A auth succeeds over TLS 1.3.ssl_ctx.maximum_version = ssl.TLSVersion.TLSv1_2) for environments where forcing TLS 1.2 is preferred as an interim measure. Must be explicit opt-in; default behavior should negotiate normally (incl. TLS 1.3).Acceptance