Skip to content

Add SPKI-based certificate pinning support#883

Open
o-nnerb wants to merge 28 commits intoswift-server:mainfrom
o-nnerb:main
Open

Add SPKI-based certificate pinning support#883
o-nnerb wants to merge 28 commits intoswift-server:mainfrom
o-nnerb:main

Conversation

@o-nnerb
Copy link
Copy Markdown
Contributor

@o-nnerb o-nnerb commented Feb 2, 2026

This PR introduces SPKI-based certificate pinning to AsyncHTTPClient, enabling clients to enforce explicit trust in server certificates beyond standard PKI validation. This provides protection against compromised Certificate Authorities and MITM attacks.

🔑 Key features

  • SPKI pinning (not full certificate pinning) — survives legitimate certificate rotations by pinning the public key structure (RFC 5280, Section 4.1)
  • Two verification modes:
    • .strict (production): blocks connections on pin mismatch
    • .audit (staging): allows connections but logs warnings for observability
  • Multi-algorithm support: SHA-256 (default), SHA-384, and SHA-512 via generic init SPKIHash(algorithm:*:)
  • Constant-time comparison: Resistant to timing attacks during pin validation
  • Seamless integration: Works alongside existing TLS configuration (OpenSSL/BoringSSL backend only)

🛡️ Security by design

  • Rotation safety: Emits runtime warning when < 2 pins are configured in .strict mode (caller-managed redundancy)
  • No silent failures: Explicit HTTPClientError.invalidCertificatePinning on mismatch
  • OWASP/NIST aligned: Compliant with MSTG-NETWORK-4 and NIST SP 800-52 Rev. 2 Section 3.4.3

🧪 Usage example

let config = HTTPClient.Configuration(
    tlsPinning: SPKIPinningConfiguration(
        pins: [
            SPKIHash(base64: "dJEGUdm2BuEalPybF+8enWB7R4AeiwE0gsQHyQrhzhY="),
            SPKIHash(base64: "backup-pin-for-rotation") // Redundancy required for safe rotation
        ],
        policy: .strict
    )
)

let client = HTTPClient(configuration: config)

⚠️ Important notes

  • Backend requirement: Pinning requires OpenSSL/BoringSSL backend — Network.framework (NIOTS) connections ignore pinning configuration
  • Rotation safety: Always deploy ≥2 pins in production (current + upcoming certificates) to avoid lockout during rotation
  • Hash generation: Pins must be Base64-encoded hashes of the DER-encoded SPKI structure:
    openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | \
      openssl x509 -pubkey -noout | \
      openssl pkey -pubin -outform der | \
      openssl dgst -sha256 -binary | \
      openssl base64 -A

📚 References

@o-nnerb o-nnerb marked this pull request as draft February 2, 2026 03:25
@o-nnerb
Copy link
Copy Markdown
Contributor Author

o-nnerb commented Feb 2, 2026

Good morning, @Lukasa. Does this PR make sense for AsyncHTTPClient?

I’m currently developing an application and need this feature. I’ve researched the topic and found some use cases on https://github.com/datatheorem/TrustKit.

I’ve also made this a draft because I’ll need more time to implement the tests.

@o-nnerb o-nnerb marked this pull request as ready for review February 2, 2026 21:19
@o-nnerb o-nnerb requested a review from Lukasa February 7, 2026 14:57
@Lukasa Lukasa added the 🆕 semver/minor Adds new public API. label Feb 9, 2026
@o-nnerb o-nnerb requested a review from Lukasa February 10, 2026 12:41
@o-nnerb
Copy link
Copy Markdown
Contributor Author

o-nnerb commented Feb 18, 2026

@Lukasa, any updates on this?

@o-nnerb
Copy link
Copy Markdown
Contributor Author

o-nnerb commented Mar 3, 2026

Hi @Lukasa, just checking in on this PR. No rush, but let me know if there's anything else you'd like me to adjust before we move forward. 🙏

@o-nnerb
Copy link
Copy Markdown
Contributor Author

o-nnerb commented Mar 10, 2026

Hi @Lukasa, just checking in again. I noticed there are still 2 workflows awaiting maintainer approval which might be blocking the checks. I need to move forward with this feature in my project, so if there's no traction soon, I'll likely close this PR to keep my workspace clean and maintain it on a fork. Let me know if you think this is still on the roadmap!

@o-nnerb
Copy link
Copy Markdown
Contributor Author

o-nnerb commented Mar 11, 2026

@fabianfett, will this PR be acceptable? Is this feature relevant to this package?

@o-nnerb
Copy link
Copy Markdown
Contributor Author

o-nnerb commented Mar 15, 2026

@fabianfett @Lukasa, could you please run the CI again? I believe all the updates have been applied.

@o-nnerb
Copy link
Copy Markdown
Contributor Author

o-nnerb commented Mar 26, 2026

@fabianfett @Lukasa, please provide any updates. I believe it’s ready for a new review and CI check. 😢

@o-nnerb
Copy link
Copy Markdown
Contributor Author

o-nnerb commented Mar 26, 2026

@fabianfett, could you please explain the linkage error and its relation to this implementation? I’m unable to identify the specific change that would resolve this issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🆕 semver/minor Adds new public API.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants