Skip to content

fix(security): make Sigstore cert pinning fail-closed#123

Open
avrabe wants to merge 1 commit into
mainfrom
security/cert-pinning-fail-closed
Open

fix(security): make Sigstore cert pinning fail-closed#123
avrabe wants to merge 1 commit into
mainfrom
security/cert-pinning-fail-closed

Conversation

@avrabe
Copy link
Copy Markdown
Contributor

@avrabe avrabe commented May 20, 2026

Summary

Closes #95. Audit finding C-4 raised the SPKI cert pinning as a possible silent posture downgrade. The issue prescribed a ureqreqwest migration on the premise that pins were validated post-handshake and only logged.

That premise is stale. TLS-layer enforcement is already in place: PinnedCertVerifier implements rustls::ServerCertVerifier, wired into the ureq agent via a custom connector in transport.rs. A pin mismatch returns Err(TlsError) and aborts the handshake — this is exactly what failed the v0.8.3 release when the Fulcio leaf rotated. No client migration is needed.

The genuine residual was a fail-open path in agent construction:

  1. create_agent_with_optional_pinning silently fell back to an unpinned standard agent when the pinned agent couldn't be built (unless WSC_REQUIRE_CERT_PINNING=1).
  2. The RekorClient/FulcioClient constructors then swallowed even that hard error and fell back to create_standard_agent() regardless — so a configured pin set could still be dropped silently.

Changes

  • create_agent_with_optional_pinning: a non-empty pin set makes pinning mandatory — construction failure propagates, never downgrades. Sigstore production always supplies pins, so pinning is now unconditional and WSC_REQUIRE_CERT_PINNING is redundant (kept for back-compat, documented deprecated).
  • RekorClient/FulcioClient constructors return Result<Self, WSError> and propagate failure. Unused Default impls removed.
  • KeylessSigner threads the Result through with ?.

Staging is unaffected — PinningConfig::fulcio/rekor auto-detect staging via WSC_SIGSTORE_STAGING, and verify_certificate short-circuits to plain WebPKI when no pins are configured.

Test plan

  • cargo build --workspace clean
  • cargo test -p wsc --lib keyless — 166 passed, 0 failed
  • cargo clippy -p wsc --lib — no new warnings in touched files
  • CI green

🤖 Generated with Claude Code

Audit finding C-4 flagged the SPKI pinning as a possible silent posture
downgrade. Investigation shows TLS-layer enforcement is already in place
— `PinnedCertVerifier` implements `rustls::ServerCertVerifier` and a pin
mismatch aborts the handshake (this is what failed the v0.8.3 release
when the Fulcio leaf rotated). The real residual was a fail-open path in
agent *construction*, not verification:

  1. `create_agent_with_optional_pinning` fell back to an unpinned
     standard agent whenever the pinned agent could not be built, unless
     `WSC_REQUIRE_CERT_PINNING=1` was set.
  2. Worse, `RekorClient::with_url` / `FulcioClient::with_url` caught even
     that hard error and fell back to `create_standard_agent()` anyway —
     so a configured pin set could still be silently dropped.

Changes:

- `create_agent_with_optional_pinning`: when a non-empty pin set is
  supplied, pinning is mandatory — any failure to build the pinned agent
  is propagated, never masked by an unpinned fallback. The Sigstore
  production path always supplies a non-empty pin set, so pinning is now
  unconditional there and `WSC_REQUIRE_CERT_PINNING` is redundant
  (retained for backwards compatibility, documented as deprecated).
- `RekorClient` / `FulcioClient` constructors now return
  `Result<Self, WSError>` and propagate pinned-agent construction
  failure instead of downgrading to standard TLS. The unused `Default`
  impls (which assumed an infallible `new()`) are removed.
- `KeylessSigner` threads the new `Result` through with `?`.

Staging endpoints are unaffected: `PinningConfig::fulcio`/`rekor`
auto-detect staging via `WSC_SIGSTORE_STAGING`, and `verify_certificate`
short-circuits to plain WebPKI when no pins are configured.

Fixes: #95

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@codecov
Copy link
Copy Markdown

codecov Bot commented May 20, 2026

Codecov Report

❌ Patch coverage is 70.00000% with 9 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/lib/src/signature/keyless/signer.rs 0.00% 6 Missing ⚠️
src/lib/src/signature/keyless/transport.rs 57.14% 3 Missing ⚠️

📢 Thoughts on this report? Let us know!

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.

[audit] Enforce SPKI cert pinning — migrate keyless HTTP from ureq to rustls

1 participant