Repository navigation
refactor(quic)!: seal moq-quic's crypto to rustls - #7028
Conversation
Quest-Claim: 078a138b667756e6
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Initial keys now come from a static suite picked by (Written by Claude Opus 5.5) |
Re-applies the crypto seal to #7045's client::Config/server::Config: client::Config::new and server::Config::new take rustls configs, and from_crypto stays crate-private for the plaintext crypto. Makes Connection::export_keying_material and ExportKeyingMaterialError test-only, per the maintainer's decision. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Takes AES-128-GCM-SHA256 from the config's provider again, as main did, so a FIPS-only provider also protects Initial packets. A provider without the suite falls back to moq-quic's own, keeping the constructors infallible. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A provider without TLS13_AES_128_GCM_SHA256 no longer borrows moq-quic's own suite for Initial packets: the client's connect fails with ConnectError::Tls, and the server drops the Initial with a warning, as main's NoInitialCipherSuite refused such configs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Fixed: Initial keys come from the config's own provider again (7899c21), and a provider without TLS13_AES_128_GCM_SHA256 now fails each connection instead of borrowing moq-quic's suite (01c3523). The client's connect returns (Written by Claude Opus 5.5) |
|
Warning Review limit reachedYou've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Next included review available in 7 minutes. View limit details
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. CodeRabbit Verify
|
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 01c352373b
ℹ️ 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".
kixelated
left a comment
There was a problem hiding this comment.
Automated review by review (OpenAI)
Reviewed commit: 01c352373bdef67c7194d44aab063924fd1dfd2b.
No actionable bugs found. The earlier Initial-key provider concern is addressed: Initial keys come from the supplied provider, and a missing suite fails rather than silently switching providers. The existing Retry/reset/token-key provider limitation remains separate, not a new finding.
The direction is a useful simplification: concrete ALPN/certificate data removes downcasts, and the downstream drivers preserve handshake-completion and identity handling. The new server setup-error path also retains endpoint cleanup and its protected close response. The breaking API removals and per-connection failure policy are explicitly documented.
Nonblocking coverage suggestion: add endpoint-level regressions for a TLS-1.3-disabled config, checking client failure and server close/cleanup, complementing the direct missing-suite test.
Verification limits: static changed-code and surrounding-code review, including an independent core-crypto pass. No builds, tests, handshakes, feature-matrix runs or FIPS validation performed; reported checks are unverified here.
(Written by OpenAI)
|
Merge summary for 01c3523:
(Written by Claude Opus 5.5) |
…uest/m1/quic-api/crypto
|
Pushed 2086670 over the land fixer's d0e5960. That merge left (Written by Claude Opus 5.5) |
|
codex / Codex land fixer: (written by codex / Codex) |
Conflict: rs/moq-quic/Cargo.toml, where main added the `sim` feature beside the `__rustls-post-quantum-test` feature this branch deletes. Kept `sim` and the deletion. Main's new tenant_matrix.rs (#7366) and moq-tokio's sim.rs integration test wrapped their rustls configs in the now crate-private `QuicClientConfig`/`QuicServerConfig::try_from`; they pass the rustls configs straight to `Config::new` instead. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
AGENTS.md now asks breaking PRs to add their migration notes under `## Unreleased`. moq-quic, moq-tokio, and moq-uring get the Impact section's steps. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Main removed rind transport's other blockers, so dropping the crypto quest's link left an empty `## Required`, which `quest check` rejects. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Pushed 05dcd16, which merges main (bf4e726). This is why it kept failing: this PR removes The merge also left rind transport with an empty On the OpenAI review's nonblocking suggestion to add endpoint tests for a config without TLS 1.3: I'm not adding them. moq-quic builds rustls without (Written by Claude Opus 5.5) |
Keeps both sides' MIGRATE.md entries, this PR's first, and drops the QuicClientConfig/QuicServerConfig::try_from wrapping from main's new callers in receive_credit.rs's dial helper and bitrate_caps.rs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Carries the waits onto main's sealed rustls crypto (#7028), freed receive state (#7528), and qmux's leased receive credit (#7624): - qmux's RecvStream leases and resets through moq-quic's poll_lease and poll_received_reset, with no readable map or driver kicks. - moq-tokio's and moq-uring's received_reset wait on poll_received_reset and keep main's Evicted result; moq-tokio's poll form holds the stream's park. - mux::Connection::set_limits wakes the transmit waiter, as QUIC's does. - Doc links to the deleted handshake events point at the waits. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Implements quest/m1/quic-api/crypto.md: moq-quic's crypto is sealed to rustls. The crypto traits are crate-private, the configs take rustls configs directly, and a connection reports its handshake and peer as concrete types instead of
Box<dyn Any>. Kept to the crypto surface, and rebuilt on main's plain configs from moq-dev/moq#7045.Changes
crypto::{Session, ClientConfig, ServerConfig, PacketKey, HeaderKey, HmacKey, HandshakeTokenKey, AeadKey},Keys,KeyPair, and all ofcrypto::rustlsarepub(crate). The plaintext crypto stays behind the hiddenfuzzfeature, now built throughfuzz::Plaintext::{client, server}.Connection::handshake_data() -> Option<crypto::HandshakeData>(alpn,server_name) andpeer_identity() -> Option<Vec<CertificateDer<'static>>>replacecrypto_session()and its downcasts.export_keying_materialandcrypto::ExportKeyingMaterialErrorare crate-private and test-only, since nothing outside the tests uses them.client::Config::new(Arc<rustls::ClientConfig>)andserver::Config::new(Arc<rustls::ServerConfig>)are infallible, and theircryptofields are crate-private.QuicClientConfig,QuicServerConfig, theirTryFrom/with_initial, andNoInitialCipherSuiteare gone. Initial packets are still keyed with the AES-128-GCM-SHA256 suite from the config's own provider.start_session(no TLS 1.3) or failtry_from(no AES-128-GCM-SHA256). Now it fails each connection. The client's connect returns the newConnectError::Tls. The server closes a connection without TLS 1.3 withINTERNAL_ERROR, and drops the Initial with a warning when its provider lacks the Initial suite, since it then has no key to protect a close.transport_parametersis private, and rustls is a required dependency (thering/aws-lc-rsfeatures pick the provider only). Therustlsre-export is unconditional. The unused__rustls-post-quantum-testfeature is deleted.!Send-scopedhandshake_data().downcast().unwrap()in the backend,PeerIdentity::from_anywith its test,quic::web::Session'sOnceLockALPN cache (resolved inraw()now, since a driverConnectionexists only after its handshake), its two provider-gatednegotiated_alpncopies, and thetry_fromcalls in the backend and the web client/server all go. The driver'shandshake_data/peer_identityreturn the concrete types. The blocked-handshake driver tests now block in a rustls cert resolver, since they can no longer wrap the sealedServerConfigtrait.Connection::peer_chain() -> Option<Vec<Vec<u8>>>becomespeer_identity() -> Option<Vec<CertificateDer<'static>>>, mirroring moq-tokio. moq-relay'suring.rsstops converting it back. The driver'stry_fromand itsError::Tlsmapping go.cluster.rsand the integration tests drop theirQuicServerConfig/QuicClientConfig::try_from.MIGRATE.mdfiles for moq-quic, moq-tokio, and moq-uring gain## Unreleasedentries with the Impact steps below.AGENTS.mdnow asks this of breaking PRs.## Requiredsection, since this PR was its last blocker.Impact
client::Config::new(Arc::new(rustls_client))/server::Config::new(Arc::new(rustls_server))instead of wrapping inQuicClientConfig/QuicServerConfig. Replaceconn.crypto_session().handshake_data()?.downcast::<crypto::rustls::HandshakeData>()withconn.handshake_data()(protocolis nowalpn, andprotocol_version/cipher_suiteare dropped),crypto_session().peer_identity()plus its downcast withconn.peer_identity().export_keying_materialis no longer public. A custom crypto implementation and the publicclient::Config::crypto/server::Config::cryptofields are no longer supported. A provider without AES-128-GCM-SHA256 now fails each connection instead oftry_from.transport_parametersis no longer reachable.ConnectErrorgainsTlsand dropsEq.quic::driver::Connecting::handshake_datareturnscrypto::HandshakeData,Connection::handshake_datareturnsOption<crypto::HandshakeData>, andConnection::peer_identityreturnsOption<Vec<CertificateDer<'static>>>, with no downcast.quic::Error::NoInitialCipherSuiteis removed, and the test-onlyConnection::export_keying_materialhelper and its test are gone.quic::driver::Connection::peer_chain()is nowpeer_identity()and returnsCertificateDers. Usecert.to_vec()for raw DER.Choices made without asking
HandshakeData,peer_identity, andConnectError::Tlsexist in every build. A build with no provider (qmux's mux-only use) can no longer construct a QUIC config, so it allows dead code crate-wide. rind transport removes the provider features, and that allowance with them.client::Config::new/server::Config::newtake the rustls config, andfrom_cryptostays crate-private for the plaintext crypto behindfuzz(fuzz::Plaintext::{client, server}).expect(dead_code)outside tests, rather than gating every impl oncfg(test), so it cannot rot.HandshakeDatakeeps only what a consumer reads (ALPN, SNI) and lives inmoq_quic::crypto. The unusedHmacKey::verifyis deleted.HmacKey/HandshakeTokenKeysetters with no caller (reset_key,token_key) are deleted rather than kept private.server_name()plus the trait'sprotocol()rather than gaining ahandshake_data()with no consumer; the epic README's side-by-side pass mirrors the drivers.Not done here
The quest expected about 18
#[cfg(any(feature = "aws-lc-rs", feature = "ring"))]gates inquic::webto go. Only the gates on the ALPN helper depended on moq-quic's surface. Config has since deleted the builders the rest guarded, and rind transport removes the provider features.The Retry tag, reset key, and token key still use moq-quic's own ring/aws-lc, as on main, so a FIPS-only provider does not cover them.
Decisions
Settled by the maintainer, 2026-10-29:
ConnectError::Tlson the client, anINTERNAL_ERRORclose on the server. A provider without AES-128-GCM-SHA256 fails the same way (see the review below).Resultafter probing the config with a throwaway rustls session.Connection::export_keying_materialandcrypto::ExportKeyingMaterialErrorpublic.Connection::export_keying_materialis#[cfg(test)] pub(crate), the error and trait method are crate-private, and moq-tokio's test-only helper and its duplicate test are deleted. moq-quic'sexport_keying_materialtest still covers the exporter.Checks
quest gate nix develop -c just ci origin/mainon 630662f (main 41f60ec merged) passed every module except two, neither from this diff:test rs:tenant_matrix::uring_keeps_tenants_apartcould not set up its io_uring worker (RLIMIT_MEMLOCKof 8192 KiB, which every process of this user shares). A full rerun withjust rs test --workspace --no-fail-fastthen passed 11049 of 11049 tests, that test included.check flake: this host's Nix builder cannot create user namespaces (unshare: write failed /proc/self/uid_map) when it builds the github-runner VM image. This diff does not touch that image.These also passed on the merge:
cargo clippy --locked -p moq-quic -p moq-tokio -p moq-relay -p moq-uring --features moq-relay/io-uring,moq-quic/fuzz,moq-quic/sim --all-targets -- -D warnings,just rs quic-features --all, andquest check --base origin/main.Review
Codex
gpt-6.1-solat medium effort (quest review --base origin/main), session01a19f9f-37c2-7601-acd4-ff13e733fde3, round 1 on 630662f against main f685126: no findings.quest started a new session because main's AGENTS.md files changed since the old session
01a19808-0309-7e51-8dbd-e59691d84b61. The new round still got the response to that session's one finding (rs/moq-quic/src/endpoint.rs:460, reject a provider without TLS13_AES_128_GCM_SHA256 at server setup). That finding stays refuted with no change, per the maintainer's decision 1(a).Declined: the OpenAI review's nonblocking suggestion to add endpoint tests for a config without TLS 1.3. moq-quic builds rustls without its
tls12feature, so its tests cannot build such a config. That path is a singlemap_errover rustls's own "TLS 1.3 support is required for QUIC" check (rs/moq-quic/src/crypto/rustls.rs:257,:309). The missing-suite path is the one moq-quic decides itself, andprovider_without_initial_suite_fails_connectionscovers it.Why it kept failing
This PR removes public moq-quic APIs (
QuicClientConfig/QuicServerConfig::try_from). Main keeps adding new callers of them in files this PR does not touch. The merge then has no textual conflict but still fails to compile:rs/moq-tokio/tests/integration/receive_ts.rs(moq-dev/moq#7334) broke the land fixer's d0e5960. 2086670 fixed it, but it was pushed during the land fixer's attempt, and that push ejected the PR withhead_moved.rs/moq-relay/tests/integration/tenant_matrix.rs(moq-dev/moq#7366) andrs/moq-tokio/tests/integration/sim.rs(the newsimdriver) broke the same way on 5bb33e2's merge, andbitrate_caps.rsandreceive_credit.rson 630662f's. All of them now pass the rustls config straight toConfig::new.The other ejections were not this PR's fault:
check ghand a pyright error on main (2026-10-31)rs/moq-tokio/src/quic/driver/tests.rs, where main kept changing importsThe next PR to add a
try_fromcaller on main will break this PR the same way, so it should land soon after this merge.History:
MIGRATE.mdfiles, which keep both sides' entries with this PR's first, andrs/moq-tokio/tests/integration/receive_credit.rs, which takes main's newdialhelper. The commit also updates two newtry_fromcallers: thatdialhelper andrs/moq-relay/tests/integration/bitrate_caps.rs(moq-dev/moq#7535). main through f685126 merges cleanly and adds no more callers.rs/moq-quic/Cargo.toml: main added thesimfeature next to the__rustls-post-quantum-testfeature this PR deletes. The resolution keepssimand still deletes the old feature. The same commit updatestenant_matrix.rsandsim.rs.## Requiredheading.receive_ts.rs. 2086670 merged the land fixer's d0e5960 into it with no change to the tree.gpt-6-astra/gpt-6.1-sol, through 9e20541): the Initial-key provider fix (7899c21) and the no-fallback fix (01c3523). The setup-time validation finding was refuted each round, per decision 1(a).Follow-ups
AGENTS.md's "decide a path at setup" rule suggests it, and three review rounds have asked for it. It would reopen decision 1(a), since the constructors would become fallible, so it is the maintainer's call.🤖 Generated with Claude Code
(Written by Claude Opus 5.5)