You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
SPKI Pinning is implemented on the tls-pinning branch — a new SPKIPinning property, composed
inside SecureConnection, that pins the server's public key structure (SubjectPublicKeyInfo) instead
of trusting the certificate chain alone. It's a real defense-in-depth layer: it survives legitimate
certificate rotation (same key, new expiration) and blocks MITM from a compromised or coerced CA,
which chain-of-trust validation alone can't.
SPKIPinning(policy:content:) — a Property that composes into SecureConnection, taking a @PropertyBuilder block of SPKIHash values (active + backup pins, no separate wrapper to
distinguish them) and a SPKIPinningPolicy.
SPKIHash<Algorithm: HashFunction> — generic over swift-crypto's HashFunction (SHA-256 by
default, SHA-384/SHA-512 also supported), constructible from a base64-encoded digest or raw bytes.
Validates encoding and digest length against the algorithm at construction time.
SPKIPinningPolicy — .strict (terminate the connection on pin mismatch — production) or .audit (log a warning but allow the connection — staging/debugging, explicitly documented as
never for production use).
Full usage docs, key benefits, and the openssl one-liner for generating pins are already written in Secure-connection.md.
Implementation status
Fully implemented on tls-pinning: the Property/PropertyNode layer
(SPKIPinning/SPKIHash/SPKIHashNode), the Internals layer bridging into AsyncHTTPClient.SPKIHash/SPKIPinningConfiguration (Internals.SPKIHash, Internals.SecureConnection.buildTLSPinning()), wiring into Internals.Session.Configuration.build()
(HTTPClient.Configuration(tlsPinning:)), and test coverage
(InternalsSecureConnectionTests, SPKIPinningTests).
This feature only exists because AsyncHTTPClient doesn't have SPKI pinning natively yet. swift-server/async-http-client#910 — "Add SPKI certificate pinning support" — adds it: SPKIPinningHandler, SPKIPinningConfiguration, AsyncHTTPClient.SPKIHash, .strict/.audit modes, multi-algorithm hashing, constant-time
comparison. RequestDL's SPKIPinning is a declarative wrapper directly on top of those types.
That PR is open, not yet merged. Until it lands and is released, tls-pinning's Package.swift
points at a fork instead of the official package:
(vs. main's https://github.com/swift-server/async-http-client, from: "1.30.2"). tls-pinning
can't merge into main — and RequestDL can't cut a release with this feature — while it depends on a
fork/beta pin instead of a tagged release of the official package.
A design constraint inherited from #910, not a RequestDL gap
#910 itself documents: "Requires OpenSSL/BoringSSL backend (Network.framework connections ignore
pinning configuration)" — this is deliberate scope, not a bug to fix later. RequestDL's own Internals.SecureConnection.isCompatibleWithNetworkFramework already respects it: a session with tlsPins set is treated as incompatible with Network.framework and steered onto MultiThreadedEventLoopGroup instead of NIOTSEventLoopGroup, so SPKIPinning + Session().enableNetworkFramework() degrades safely (NIOSSL transport) rather than crashing. No
further work needed here on the RequestDL side for this.
Status
Shipped in 4.3.0.#248 merged into main on 2026-09-02: SPKIPinning/SPKIHash are implemented and available.
One constraint carries forward: Package.swift on main still points at the request-dl/async-http-client fork's beta tag (1.37.0-beta.2) instead of the official package,
because swift-server/async-http-client#910 is still open upstream. That's intentional, not an
oversight — it'll stay that way until #910 merges and ships in a tagged release, at which point Package.swift can point back at the official package. Tracked separately; doesn't block using SPKIPinning today.
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Summary
SPKI Pinningis implemented on thetls-pinningbranch — a newSPKIPinningproperty, composedinside
SecureConnection, that pins the server's public key structure (SubjectPublicKeyInfo) insteadof trusting the certificate chain alone. It's a real defense-in-depth layer: it survives legitimate
certificate rotation (same key, new expiration) and blocks MITM from a compromised or coerced CA,
which chain-of-trust validation alone can't.
API surface
SPKIPinning(policy:content:)— aPropertythat composes intoSecureConnection, taking a@PropertyBuilderblock ofSPKIHashvalues (active + backup pins, no separate wrapper todistinguish them) and a
SPKIPinningPolicy.SPKIHash<Algorithm: HashFunction>— generic overswift-crypto'sHashFunction(SHA-256 bydefault, SHA-384/SHA-512 also supported), constructible from a base64-encoded digest or raw bytes.
Validates encoding and digest length against the algorithm at construction time.
SPKIPinningPolicy—.strict(terminate the connection on pin mismatch — production) or.audit(log a warning but allow the connection — staging/debugging, explicitly documented asnever for production use).
Full usage docs, key benefits, and the
opensslone-liner for generating pins are already written inSecure-connection.md.Implementation status
Fully implemented on
tls-pinning: theProperty/PropertyNodelayer(
SPKIPinning/SPKIHash/SPKIHashNode), theInternalslayer bridging intoAsyncHTTPClient.SPKIHash/SPKIPinningConfiguration(Internals.SPKIHash,Internals.SecureConnection.buildTLSPinning()), wiring intoInternals.Session.Configuration.build()(
HTTPClient.Configuration(tlsPinning:)), and test coverage(
InternalsSecureConnectionTests,SPKIPinningTests).Dependency: swift-server/async-http-client#910
This feature only exists because
AsyncHTTPClientdoesn't have SPKI pinning natively yet.swift-server/async-http-client#910 —
"Add SPKI certificate pinning support" — adds it:
SPKIPinningHandler,SPKIPinningConfiguration,AsyncHTTPClient.SPKIHash,.strict/.auditmodes, multi-algorithm hashing, constant-timecomparison. RequestDL's
SPKIPinningis a declarative wrapper directly on top of those types.That PR is open, not yet merged. Until it lands and is released,
tls-pinning'sPackage.swiftpoints at a fork instead of the official package:
(vs.
main'shttps://github.com/swift-server/async-http-client,from: "1.30.2").tls-pinningcan't merge into
main— and RequestDL can't cut a release with this feature — while it depends on afork/beta pin instead of a tagged release of the official package.
A design constraint inherited from #910, not a RequestDL gap
#910 itself documents: "Requires OpenSSL/BoringSSL backend (Network.framework connections ignore
pinning configuration)" — this is deliberate scope, not a bug to fix later. RequestDL's own
Internals.SecureConnection.isCompatibleWithNetworkFrameworkalready respects it: a session withtlsPinsset is treated as incompatible with Network.framework and steered ontoMultiThreadedEventLoopGroupinstead ofNIOTSEventLoopGroup, soSPKIPinning+Session().enableNetworkFramework()degrades safely (NIOSSL transport) rather than crashing. Nofurther work needed here on the RequestDL side for this.
Status
Shipped in 4.3.0. #248 merged into
mainon 2026-09-02:SPKIPinning/SPKIHashare implemented and available.One constraint carries forward:
Package.swiftonmainstill points at therequest-dl/async-http-clientfork's beta tag (1.37.0-beta.2) instead of the official package,because
swift-server/async-http-client#910is still open upstream. That's intentional, not anoversight — it'll stay that way until #910 merges and ships in a tagged release, at which point
Package.swiftcan point back at the official package. Tracked separately; doesn't block usingSPKIPinningtoday.All reactions