TLS 1.3 (SPP 9.0): opt-in min/max version pins + cert TLS 1.2 auto-cap (8.2.0) - #57
Draft
DanPeterson wants to merge 4 commits into
Draft
TLS 1.3 (SPP 9.0): opt-in min/max version pins + cert TLS 1.2 auto-cap (8.2.0)#57DanPeterson wants to merge 4 commits into
DanPeterson wants to merge 4 commits into
Conversation
SPP 9.0 enables TLS 1.3, which moves client-certificate auth to a post-handshake exchange (RFC 8446 4.6.2). Node has no client-side post-handshake authentication (nodejs/node#46120, closed NOT_PLANNED), so over TLS 1.3 the cert is never presented and cert/A2A auth fails with 60094. Unlike PySafeguard we cannot enable PHA, so we use TLS-version control instead. - Add opt-in minVersion/maxVersion (TlsVersion) + pfx to TlsOptions. - resolveTlsConnectOptions() plumbs pins into the undici Agent and auto-caps cert connections (cert/key/pfx) at TLSv1.2 when neither bound is pinned, so cert/A2A auth works by default on the Standard binding. Password/token connections keep negotiating TLS 1.3. TLS 1.3 cert-auth is reachable via the Cert SNI hostname with minVersion TLSv1.3. - Unit tests for the version/auto-cap logic. - Docs: README TLS 1.3/SPP 9.0 section, AGENTS.md, api-patterns + a2a-workflow + architecture skills, certificate-auth sample. - Bump 8.1.0 -> 8.2.0. Fixes OneIdentity#46, OneIdentity#48
undici negotiates HTTP/2 via ALPN by default, but the appliance's HTTP/2-capable Standard binding rejects client-certificate auth (cert auth and A2A) with HTTP_1_1_REQUIRED, independent of TLS version. Disable HTTP/2 on the undici Agent whenever a client certificate is present, completing the cert-auth support for issue #650 (the TLS-version cap alone was not sufficient). Password/token connections carry no certificate and keep HTTP/2.
The A2A client's list, retrieve, and write paths had never been exercised against a live appliance (no live A2A coverage) and were incorrect: - getRetrievableAccounts targeted the a2a service with a single request; retrievable accounts live under the core service as a two-step enumeration (registrations, then each registration's retrievable accounts), authorized by the client certificate. - retrievePassword/retrievePrivateKey returned the raw response body, so callers received a JSON-quoted string; decode the JSON string. - setPassword used Credentials?type=Password (405); the write endpoint is Credentials/Password. Add live certificate-auth and A2A integration tests (mirroring the other SDK suites) plus their bootstrap fixtures, and run integration files serially since they share one appliance and a single fixed client certificate. Update the A2A unit tests to the corrected wire contract.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes #46 and #48 together. SPP 9.0 enables TLS 1.3, which moves client-certificate authentication to a post-handshake exchange (RFC 8446 §4.6.2). On TLS 1.3 the appliance requests the client cert after the handshake; the client must answer that
CertificateRequest.Node.js has no client-side post-handshake authentication. The upstream request (nodejs/node#46120) was closed NOT_PLANNED, and
tls.connectexposes no toggle for it. So over a plain TLS 1.3 connection the cert is never presented and cert/A2A auth fails against SPP 9.0 with60094 Authorization is denied. Password/token auth is unaffected.Unlike the PySafeguard fix (which enables Python's
post_handshake_auth), Node cannot do PHA at all — so this SDK uses a TLS min/max version strategy instead (mirroring the pysafeguard/SafeguardJava min/max API shape).Changes
1. Opt-in TLS version pins
TlsOptions(onNodeHttpClient) gainsminVersion/maxVersion(TlsVersion = 'TLSv1.3' | 'TLSv1.2' | 'TLSv1.1' | 'TLSv1', default unset = negotiate). Also addspfxtoTlsOptionsso PFX/PKCS12 mTLS material actually reaches the undiciAgent.2. Cert-auth works by default (auto-cap at TLS 1.2)
New
resolveTlsConnectOptions()insrc/http/node.ts: when a client cert (cert/key/pfx) is present and neither bound is pinned, the connection is capped atTLSv1.2so the cert is requested in-handshake. This keeps certificate/A2A auth working by default on SPP 9.0's Standard binding. Password/token connections carry no cert and keep negotiating TLS 1.3.3. TLS 1.3 cert-auth via Cert SNI
Setting
minVersion/maxVersionexplicitly disables the auto-cap. For TLS 1.3 cert-auth, target the appliance's Cert SNI hostname (in-handshake cert request) and pinminVersion: 'TLSv1.3'.4. HTTP/1.1
undici stays on HTTP/1.1 (its default);
allowH2is never enabled — HTTP/2 disallows the post-handshakeCertificateRequest.5. Version
Bumped
8.1.0→8.2.0(backward-compatible minor).Usage
Tests
New unit tests (
tests/unit/http-node.test.ts) cover the version plumbing and the cert auto-cap (default cap, no-cap for password/token, Cert SNI override, explicit-pin override, mTLS forwarding). Full suite: 162 passed;typecheckandbuildclean;lint0 errors.Docs
README (TLS 1.3 and SPP 9.0 section with JS gotchas),
AGENTS.md, theapi-patterns/a2a-workflow/architectureskills, and thecertificate-authsample.Not yet validated against live appliances. Please confirm on real hardware:
minVersion: 'TLSv1.3'.Follow-up: add appliance-backed cert/A2A integration tests (per #46) once a 9.0 appliance is available in CI.