Skip to content

refactor: unify signature verification behind one pluggable provider - #154

Open
kaidokert wants to merge 3 commits into
mainfrom
refactor/verifier-provider-unification
Open

refactor: unify signature verification behind one pluggable provider#154
kaidokert wants to merge 3 commits into
mainfrom
refactor/verifier-provider-unification

Conversation

@kaidokert

@kaidokert kaidokert commented Aug 25, 2026

Copy link
Copy Markdown
Owner

Pure architecture/extensibility refactor of the certificate-signature verification layer — behaviour-preserving, no protocol change.

Problem

Verification was asymmetric: Ed25519 and RSA were pluggable via provider type params (PreparedVerifier<E: Ed25519VerifierProvider, R: RsaVerifierProvider>), while ECDSA-P256/P384 and ML-DSA were hardcoded enum variants verified by direct backend calls. Every time an algorithm became pluggable the <E, R, …> type-param list grew, threaded through the whole verify stack.

Design

One uniform abstraction for all five algorithms:

  • SigAlgo — the algorithm names its borrowed Sig/Pubkey/KeyMat types (GATs), shared across backends.
  • SigVerifierProvider<A> — a backend prepares a per-key verifier; the prepared verifier is a standard signature::Verifier<A::Sig> and exposes its key material for the SPKI cross-check.
  • VerifierBackend — aggregates the per-algorithm bounds behind one bound (the single place per-algorithm feature gating lives), so the stack threads one backend param.

Adding an algorithm or a backend is now one impl, not a new trait.

What changed

  • PreparedVerifier<E,R>PreparedVerifier<P>; same collapse for Trusted, VerifyStrategy, TrustRootDecision, SafeStrategy, verify_server_flight. ECDSA and ML-DSA are now provider-backed variants like the others — no hardcoding.
  • ClientConfig: Ed25519 + Rsa slots → one Verifiers: VerifierBackend (default RustCrypto).
  • RSA's PSS/PKCS1 dispatch folds onto a scheme-carrying RsaSig; ECDSA's per-curve SHA prehash moves inside its Verifier impl (same hash + verify, relocated so verification is uniform verify(message, sig)).
  • Deletes Ed25519VerifierProvider / RsaVerifierProvider.

Verification

Default + all-features build, the full feature-combo matrix + lib tests, clippy --all-targets zero-warnings, and the existing canned/mTLS server-cert verify tests (Ed25519 / RSA / ECDSA / ML-DSA incl. the ML-DSA scheme-binding rejection) all pass — the behaviour-preservation proof.

Two failures are pre-existing on main (verified independently), unrelated to this layer: --all-features test-compile trips the carrier-bnum/carrier-crypto-bigint mutual-exclusion guard, and client_hello_advertises_mldsa_schemes isn't not(ecdsa)-gated.

Footprint

M3 default .text +68 B (50,992 → 51,060). No new monomorphizations — the delta is the uniform fallible prepare applied to the formerly-infallible Ed25519 leaf-prep (its never-taken Err branch doesn't fold at opt-level="z"). Clawing it back would mean special-casing Ed25519, defeating the uniformity.

Summary by Sourcery

Replace the per-algorithm verification wiring with one extensible backend abstraction without changing protocol behavior.

Enhancements:

  • Unify certificate and CertificateVerify signature checking behind a single pluggable verifier backend covering Ed25519, RSA, ECDSA, and ML-DSA.
  • Reduce verification-stack and client-configuration generic parameters to one backend type while exposing algorithm-specific provider interfaces for custom implementations.
  • Route RSA scheme selection and ECDSA hashing through the common verifier interface while preserving existing signature and key-binding behavior.

Tests:

  • Update verification, strategy, connection, DTLS, and footprint coverage for the unified backend API and supported algorithms.

Chores:

  • Remove the superseded Ed25519 and RSA provider traits and replace them with the unified provider module.

Summary by CodeRabbit

  • New Features

    • Added support for ECDSA P-256 and P-384 signature verification.
    • Added unified verification support across Ed25519, RSA, ECDSA, and ML-DSA algorithms.
    • Added RSA signature handling for PKCS#1 v1.5 and RSA-PSS configurations.
  • Improvements

    • Simplified verification configuration across TLS and DTLS connections.
    • Improved certificate key and signature validation, including clearer handling of invalid verification data.

Every cert-signature algorithm (Ed25519, RSA, ECDSA-P256/P384, ML-DSA) now sits
behind a single `SigVerifierProvider<A>` abstraction over a `SigAlgo` GAT
descriptor, aggregated by `VerifierBackend`. This removes the asymmetry where
Ed25519/RSA were pluggable provider type params but ECDSA and ML-DSA were
hardcoded `PreparedVerifier` variants, and collapses the growing `<E, R, ...>`
type-param list across the verify stack (`PreparedVerifier`, `VerifyStrategy`,
`TrustRootDecision`, `SafeStrategy`, `verify_server_flight`, `ClientConfig`) to a
single backend param `P`. `ClientConfig` gains one `Verifiers` slot in place of
`Ed25519` + `Rsa`; adding an algorithm or backend is now one impl, not a new
trait.

Behaviour-preserving: RSA's PSS/PKCS1 dispatch folds onto a scheme-carrying
`RsaSig`, and ECDSA's per-curve SHA prehash moves inside its `Verifier` impl
(same hash + verify, relocated). Deletes the `Ed25519VerifierProvider` /
`RsaVerifierProvider` traits. Default-build footprint +68 B on M3 (no new
monomorphizations — the uniform fallible `prepare` on the formerly-infallible
Ed25519 leaf-prep).
@cursor

cursor Bot commented Aug 25, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_63181452-1291-4e34-ba24-163143b70230)

@coderabbitai

coderabbitai Bot commented Aug 25, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Currently processing new changes in this PR. This may take a few minutes, please wait...

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 075a27ff-fcbb-4dc4-8bc3-90ffd2583b0e

📥 Commits

Reviewing files that changed from the base of the PR and between 2b0bc9e and a735147.

📒 Files selected for processing (24)
  • footprint/handshakes/src/lib.rs
  • krabitls/src/backends/ecdsa_verify.rs
  • krabitls/src/backends/mod.rs
  • krabitls/src/backends/pin_or_self_signed.rs
  • krabitls/src/backends/pinned_roots.rs
  • krabitls/src/backends/rsa_verify.rs
  • krabitls/src/backends/rustcrypto.rs
  • krabitls/src/client/config.rs
  • krabitls/src/client/engine.rs
  • krabitls/src/client/mod.rs
  • krabitls/src/client/stream.rs
  • krabitls/src/connection.rs
  • krabitls/src/connection/tests.rs
  • krabitls/src/dtls/client.rs
  • krabitls/src/dtls/stream.rs
  • krabitls/src/server_flight.rs
  • krabitls/src/tests.rs
  • krabitls/src/traits/ed25519_verify.rs
  • krabitls/src/traits/mod.rs
  • krabitls/src/traits/rsa_verify.rs
  • krabitls/src/traits/verify_provider.rs
  • krabitls/src/traits/verify_strategy.rs
  • krabitls/tests/strategy_coverage.rs
  • krabitls_cli/src/transport.rs
 _________________________________________________________
< Nuke the bugs from orbit. It's the only way to be sure. >
 ---------------------------------------------------------
  \
   \   (\__/)
       (•ㅅ•)
       /   づ
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch refactor/verifier-provider-unification

Comment @coderabbitai help to get the list of available commands.

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 2 issues

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="krabitls/src/traits/verify_strategy.rs" line_range="465" />
<code_context>
 /// any parsed cert — a chain entry or a `PinnedRoots` stored anchor parsed from
 /// flash — the dispatch is on `parent`'s key family, nothing is bound to "self".
-pub(crate) fn verify_link<E, R>(child: &CertView<'_>, parent: &CertView<'_>) -> Result<(), LinkErr>
+pub(crate) fn verify_link<P>(child: &CertView<'_>, parent: &CertView<'_>) -> Result<(), LinkErr>
 where
-    E: Ed25519VerifierProvider,
</code_context>
<issue_to_address>
**issue (broader_impact):** The new `P: VerifierBackend` parameter is ignored for ML-DSA and ECDSA certificate signatures: `verify_link` and `verify_self_sig` still construct `MlDsaVerifierKey` and call the hardcoded `verify_p256`/`verify_p384` functions directly. Custom providers therefore affect leaf CertificateVerify and RSA/Ed25519 checks but are bypassed for chain-link and self-signature verification.

**Triggers:** When a caller supplies a custom verifier backend for ML-DSA or ECDSA and verifies a chain or self-signed certificate.

**Suggested fix:** Prepare the ML-DSA/ECDSA verifier through the corresponding `SigVerifierProvider<A>` implementation and call its `signature::Verifier` implementation in these paths as well.
</issue_to_address>

### Comment 2
<location path="krabitls/src/traits/verify_provider.rs" line_range="3-6" />
<code_context>
+//! Unified per-algorithm signature-verification backend surface.
+//!
+//! One [`SigVerifierProvider`] per algorithm ([`SigAlgo`]) routes every cert /
+//! CertificateVerify signature through the same prepare→`Verifier` shape, so
+//! the verify stack threads a single [`VerifierBackend`] type param rather than
+//! one provider param per algorithm.
+
</code_context>
<issue_to_address>
**nitpick:** The module documentation claims one `SigVerifierProvider` routes every certificate signature through the uniform prepare-to-`Verifier` path, but ML-DSA and ECDSA chain-link and self-signature paths still bypass the provider and call concrete backends directly.

**Suggested fix:** Update the remaining ML-DSA and ECDSA certificate-signature paths to use `SigVerifierProvider`, or narrow the documentation until that migration is complete.

```suggestion
//! [`SigVerifierProvider`] defines a uniform prepare→`Verifier` shape for
//! provider-backed algorithms. The verify stack threads a single
//! [`VerifierBackend`] type param rather than one provider param per algorithm.
```
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread krabitls/src/traits/verify_strategy.rs
Comment thread krabitls/src/traits/verify_provider.rs
@coveralls

coveralls commented Aug 25, 2026

Copy link
Copy Markdown

Coverage Report for CI Build 32823777884

Coverage increased (+0.5%) to 80.414%

Details

  • Coverage increased (+0.5%) from the base build.
  • Patch coverage: 22 uncovered changes across 3 files (113 of 135 lines covered, 83.7%).
  • 5 coverage regressions across 2 files.

Uncovered Changes

File Changed Covered %
krabitls/src/traits/verify_strategy.rs 43 29 67.44%
krabitls/src/backends/pinned_roots.rs 5 0 0.0%
krabitls/src/backends/rsa_verify.rs 9 6 66.67%
Total (9 files) 135 113 83.7%

Coverage Regressions

5 previously-covered lines in 2 files lost coverage.

File Lines Losing Coverage Coverage
krabitls/src/backends/rsa_verify.rs 4 84.88%
krabitls/src/server_flight.rs 1 92.22%

Coverage Stats

Coverage Status
Relevant Lines: 6423
Covered Lines: 5165
Line Coverage: 80.41%
Coverage Strength: 147.65 hits per line

💛 - Coveralls

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 765f8f6b1c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread krabitls/src/client/mod.rs
Comment thread krabitls/src/traits/verify_strategy.rs
Comment thread krabitls/src/dtls/client.rs
Route the ECDSA and ML-DSA chain-link / self-sig verification through the
pluggable provider `P`; they still called `verify_p256`/`verify_p384` and
`MlDsaVerifierKey::new` directly, so a custom backend was honored only on the
leaf. Export the per-algorithm markers (`Rsa`, `EcdsaP256`, `EcdsaP384`,
`MlDsa`) from `krabitls::client` so downstream backends can name them.

Un-gate `signature::Verifier` (it was `cfg(ecdsa)`, which broke the default
non-ecdsa build once the Ed25519 arm started calling `.verify()`), and migrate
`krabitls_cli` and `footprint` to the single `Verifiers` config slot.
@cursor

cursor Bot commented Aug 25, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_393c54ff-8c09-463f-9c06-f003905e3d5e)

Fix a stale rustdoc link (`prepare_ed25519` → the `SigVerifierProvider::prepare`
impl) and a `matches` cfg list that omitted the `ecdsa` build. Trim three
what/how comments to the WHY they carry.
@cursor

cursor Bot commented Aug 26, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_9d208868-c9e5-4351-aa42-180716411dbf)

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.

2 participants