Skip to content

Upgrade RustCrypto ecosystem to enable ml-dsa 0.1.0-rc.8#212

Merged
lukevalenta merged 1 commit intomainfrom
lvalenta/rustcrypto-v2
Apr 16, 2026
Merged

Upgrade RustCrypto ecosystem to enable ml-dsa 0.1.0-rc.8#212
lukevalenta merged 1 commit intomainfrom
lvalenta/rustcrypto-v2

Conversation

@lukevalenta
Copy link
Copy Markdown
Contributor

@lukevalenta lukevalenta commented Apr 14, 2026

Upgrades all RustCrypto crates to their latest RC versions to unblock
ml-dsa 0.1.0-rc.8, which fixes a WASM stack overflow with ML-DSA
signatures in Cloudflare Workers.

Workspace dependency changes:

  • der 0.7.10 (patched fork) → 0.8.0 (Tag::RelativeOid now native)
  • const-oid 0.9.6 → 0.10
  • spki 0.7 → 0.8
  • pkcs8 (new) 0.11.0-rc.11
  • signature 2.2.0 → 3.0.0-rc.10
  • sha1 0.10 → 0.11
  • sha2 0.10 → 0.11
  • digest (new) 0.11 (now used directly in verify_rsa bound)
  • rand 0.8.5 → 0.10.0
  • rand_core 0.6.4 → 0.10.0
  • getrandom 0.2 → 0.4
  • ed25519-dalek 2.1.1 → 3.0.0-pre.6
  • p256 0.13 → 0.14.0-rc.8
  • p384 0.13 → 0.14.0-rc.8
  • p521 0.13 → 0.14.0-rc.8
  • rsa 0.9 → 0.10.0-rc.17
  • x509-cert 0.2.5 → 0.3.0-rc.4
  • crypto-common (new) 0.2

In x509_util, adapt is_link_valid to the upgraded crates:

  • verify_rsa bound updated from sha2::digest::Digest + rsa::pkcs8::AssociatedOid
    to digest::Digest + const_oid::AssociatedOid to match rsa 0.10-rc's API
  • verify_p521 workaround removed: p521 0.14 makes VerifyingKey a type alias
    for ecdsa::VerifyingKey, so it now inherits TryFrom
    and DerSignature, matching the p256/p384 helper pattern

Add OwnedTbsCertificate and OwnedCertificate to x509_util:

  • Mirrors the pre-#1505 field layout of x509-cert's TbsCertificateInner
    and CertificateInner (all fields pub), making it straightforward to
    construct, modify, and re-encode certificates without the field-by-field
    DER boilerplate that x509-cert 0.3's private fields otherwise require
  • Implements From<&TbsCertificate>, From<&Certificate>, from_der, to_der,
    to_x509 for ergonomic construction and conversion
  • Replaces all field-by-field TBS/Certificate DER reconstruction sites:
    build_precert_tbs, extract_scts_from_cert, serialize_signatureless_cert
  • extract_scts_from_cert now parses directly to OwnedCertificate via
    from_der; extract_lifetime_days accepts &Validity instead of &Certificate
  • Adds OwnedTbsCertificate/OwnedCertificate round-trip tests including
    unique ID and extension encoding

Adapt to x509-cert 0.3 API changes (private fields, accessor methods,
Validity::new, RelativeDistinguishedName::try_from, etc.) throughout
bootstrap_mtc_api, bootstrap_mtc_worker, ct_worker, sct_validator,
static_ct_api, and integration_tests.

Adapt to rand 0.10 API changes (OsRng→SysRng, thread_rng()→rng(),
gen_range→random_range, RngExt, TryRng/TryCryptoRng in doc examples).

@lukevalenta lukevalenta self-assigned this Apr 14, 2026
@lukevalenta lukevalenta force-pushed the lvalenta/rustcrypto-v2 branch 2 times, most recently from 395add7 to 6f06cca Compare April 14, 2026 12:39
@lukevalenta
Copy link
Copy Markdown
Contributor Author

/bonk review

Copy link
Copy Markdown

@ask-bonk ask-bonk bot left a comment

Choose a reason for hiding this comment

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

Review: Upgrade RustCrypto ecosystem to enable ml-dsa 0.1.0-rc.8

This is a large but well-structured PR that upgrades the entire RustCrypto dependency tree to enable ml-dsa 0.1.0-rc.8 (fixing a WASM stack overflow). I've reviewed all 37 changed files. Overall this is solid work — the changes are mechanically sound and the approach of introducing OwnedTbsCertificate/OwnedCertificate to work around x509-cert 0.3's private fields is pragmatic.

Architecture & Design

OwnedTbsCertificate / OwnedCertificate (x509_util) — Good solution to x509-cert 0.3's private fields. The manual DER encoding in OwnedTbsCertificate::to_der() is inherently fragile (any ASN.1 encoding bug would silently produce invalid certificates), but the round-trip tests and golden file tests provide good coverage. The from_der → to_der round-trip test confirming byte-for-byte equality with the original cert DER is the right thing to test here.

Removal of x509-verify — Replacing the x509-verify crate with hand-rolled signature dispatch in x509_util::is_link_valid is a notable change. The new code dispatches on OID to verify_p256, verify_p384, and verify_rsa — this covers the algorithms that matter for WebPKI chains (P-256, P-384, RSA with SHA-256/384/512). This is cleaner than pulling in x509-verify with all its feature flags (md2, md5, dsa, k256, p192, p224, p521...). Worth noting that if chains signed with algorithms outside this set appear in the wild, they'll be silently rejected — but that's the right behavior for CT/MTC.

Removal of [patch.crates-io] for der — The der fork is no longer needed since der 0.8 natively supports Tag::RelativeOid. Good cleanup.

LogEntry Trait Changes

The addition of the Metadata associated type and make_metadata() to the LogEntry trait is a clean generalization. This decouples the sequencer from the specific metadata shape, enabling future applications (like IETF MTC) that need old_tree_size/new_tree_size in their metadata. The existing CT and bootstrap MTC implementations correctly pass through SequenceMetadata unchanged.

Specific Observations

  1. bootstrap_mtc_api::tbs_cert_to_log_entry — The function signature changed from taking owned TbsCertificate and RdnSequence to references (&TbsCertificate, &RdnSequence). This is a good API improvement. The Name::from_der(&issuer.to_der()?) round-trip to convert RdnSequence → Name is a bit unfortunate but necessary since Name is a newtype over RdnSequence with no direct From impl.

  2. sct_validator::extract_scts_from_cert — Now parses to OwnedCertificate via from_der, mutates extensions in-place, and re-serializes. This is cleaner than the previous approach of reconstructing the TBS field-by-field. The extract_lifetime_days function now takes &Validity instead of &Certificate, which is a better API.

  3. rand migration — The OsRngrand::rng(), thread_rng()rand::rng(), gen_rangerandom_range changes look correct throughout. The CryptoRng trait bound change in generate_encoded_ed25519_key from CryptoRngCore to CryptoRng + ?Sized follows the rand 0.10 API.

  4. getrandom features — The feature flag change from js to wasm_js matches the getrandom 0.4 rename. This is required for WASM targets.

  5. Golden file tests — The build_precert_tbs and extract_scts_from_cert golden file tests are important for catching any DER encoding regressions introduced by the OwnedTbsCertificate manual encoding path.

  6. Integration test fixtures — The fixtures.rs changes for x509-cert 0.3 builder API (BuilderProfile, Criticality trait, Validity::new, etc.) look correct. The use of crypto_common::Generate for key generation follows the new RustCrypto patterns.

Potential Concerns

  • Pre-release dependencies: The PR pins several crates to RC/pre versions (ed25519-dalek 3.0.0-pre.6, p256/p384 0.14.0-rc.8, rsa 0.10.0-rc.17, signature 3.0.0-rc.10, x509-cert 0.3.0-rc.4, pkcs8 0.11.0-rc.11). The tracking comment in Cargo.toml is good — these should be upgraded to stable once the coordinated RustCrypto release happens. The p384 entry was added to workspace dependencies (previously not present), which is fine since it was already used transitively.

  • OwnedTbsCertificate::to_der() manual encoding: This hand-rolls ASN.1 SEQUENCE construction with manual header + content concatenation. If x509-cert ever exposes a builder or public field API again, this should be replaced. The comment linking to RustCrypto/formats#1505 is helpful for future maintenance.

  • validate_chain in bootstrap_mtc_api: The issuer parameter changed from RdnSequence to &RdnSequence. This is a breaking API change if anything external calls this function, but since bootstrap_mtc_api is internal, this is fine.

Build Changes

The CI build command changed from cargo build --verbose to cargo build --tests --workspace --verbose — this ensures test-only code also compiles, which is good for catching compile errors in dev-dependencies.

Overall this is a well-executed dependency upgrade. The main risk is the manual DER encoding in OwnedTbsCertificate/OwnedCertificate, which is well-mitigated by the round-trip and golden file tests.

@ask-bonk
Copy link
Copy Markdown

ask-bonk bot commented Apr 14, 2026

Review posted on PR #212. Here's a summary of the key findings:

Overall: Well-structured dependency upgrade across 37 files. The changes are mechanically sound.

Key highlights:

  • OwnedTbsCertificate/OwnedCertificate in x509_util are a pragmatic workaround for x509-cert 0.3's private fields, with good round-trip and golden file test coverage
  • Removal of x509-verify in favor of focused signature dispatch (P-256, P-384, RSA) is cleaner for the CT/MTC use case
  • The der fork patch is no longer needed since der 0.8 has native RelativeOid support
  • The LogEntry trait's new Metadata associated type is a clean generalization for future use
  • rand 0.10 and getrandom 0.4 migrations are straightforward

Main risks: Manual ASN.1 encoding in OwnedTbsCertificate::to_der() and the use of pre-release RustCrypto crates (both well-mitigated by tests and tracking comments).

github run

@lukevalenta lukevalenta force-pushed the lvalenta/rustcrypto-v2 branch from 6f06cca to 2a71055 Compare April 14, 2026 19:57
@lukevalenta
Copy link
Copy Markdown
Contributor Author

/bonk review

Copy link
Copy Markdown

@ask-bonk ask-bonk bot left a comment

Choose a reason for hiding this comment

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

Review: RustCrypto ecosystem upgrade for ml-dsa 0.1.0-rc.8

I've reviewed all 29 changed files. This is a well-executed coordinated dependency upgrade. The code is correct, the API adaptations are mechanical and sound, and the new OwnedTbsCertificate/OwnedCertificate abstraction is a pragmatic solution to x509-cert 0.3's private fields. Approving.

What I verified

  • OwnedTbsCertificate::to_der() manual ASN.1 encoding (x509_util/src/lib.rs:79-148): The field ordering exactly matches the RFC 5280 TBSCertificate SEQUENCE (version, serialNumber, signature, issuer, validity, subject, subjectPublicKeyInfo, issuerUniqueID, subjectUniqueID, extensions). Context-specific tags and tag modes (EXPLICIT for version/extensions, IMPLICIT for unique IDs) are correct. The round-trip tests (test_owned_tbs_certificate_round_trip, test_owned_certificate_round_trip) and golden file tests provide good regression coverage.

  • is_link_valid signature dispatch (x509_util/src/lib.rs:633-674): Replacing x509-verify with direct OID dispatch to verify_p256, verify_p384, verify_p521, and verify_rsa<D> is clean. The algorithm coverage (P-256, P-384, P-521, RSA SHA-1/256/384/512) matches what's needed for WebPKI chains. The SHA-1 RSA and P-521 ECDSA chain validation tests confirm these paths work.

  • x509-cert 0.3 accessor method migration: All field accesses (tbs_certificate, subject, issuer, validity, extensions, signature, subject_public_key_info, issuer_unique_id, subject_unique_id) consistently use the new accessor methods (.tbs_certificate(), .subject(), etc.) across all crates.

  • rand 0.10 migration: OsRngrand::rng(), thread_rng()rand::rng(), gen_rangerandom_range, gen()random(), CryptoRngCoreCryptoRng + ?Sized — all correct. The doc example in signed_note/src/lib.rs properly uses TryRng/TryCryptoRng for the rand 0.10 API.

  • extract_scts_from_cert refactor (sct_validator/src/sct.rs:52-68): The switch to OwnedCertificate for mutable TBS access is cleaner than the previous field-by-field reconstruction. extract_lifetime_days now takes &Validity instead of &Certificate, which is a better API boundary.

  • build_precert_tbs refactor (static_ct_api/src/rfc6962.rs:224-240): Uses OwnedTbsCertificate::from(tbs), mutates extensions in-place to remove CT poison, then calls to_der(). Clean and correct.

  • serialize_signatureless_cert (bootstrap_mtc_api/src/lib.rs:220-269): Constructs OwnedTbsCertificate and OwnedCertificate directly from log entry fields. The test_serialize_signatureless_cert test verifies the round-trip.

  • tbs_cert_to_log_entry signature change (bootstrap_mtc_api/src/lib.rs:483-533): Now takes &TbsCertificate and &RdnSequence (was owned). The Name::from_der(&issuer.to_der()?) round-trip for RdnSequence → Name is a necessary workaround since Name is a newtype with no direct From<RdnSequence>.

  • LogEntry trait Metadata associated type (tlog_tiles/src/entries.rs:70-90): The make_metadata factory method with old_tree_size/new_tree_size parameters is a clean generalization. Existing implementations (BootstrapMtcLogEntry, StaticCTLogEntry) correctly ignore the extra parameters and pass through SequenceMetadata.

  • CI build command (.github/workflows/rust.yml:32): cargo build --tests --workspace --verbose is better than the previous cargo build --verbose — it catches compile errors in test-only code and dev-dependencies.

  • der patch removal (Cargo.toml): The [patch.crates-io] for the forked der crate is gone, since der 0.8 natively supports Tag::RelativeOid.

  • getrandom feature rename: jswasm_js matches the getrandom 0.4 API.

  • integration_tests/src/fixtures.rs: Correctly adapted to x509-cert 0.3's BuilderProfile trait, Criticality trait, Validity::new, and crypto_common::Generate for key generation.

Minor observations (non-blocking)

  1. The Validity::new constructor at x509_util/src/lib.rs:1058-1071 (in the test) creates the value with separate Time::UtcTime(...) calls. This pattern appears in several places and works correctly, but it's verbose. If x509-cert ever provides a convenience constructor, it would simplify these.

  2. The tracking comment at Cargo.toml:80-85 for pre-release RC crates is important for future maintenance. All pinned RC versions (ed25519-dalek 3.0.0-pre.6, p256/p384/p521 0.14.0-rc.8, rsa 0.10.0-rc.17, signature 3.0.0-rc.10, x509-cert 0.3.0-rc.4, pkcs8 0.11.0-rc.11) should be upgraded together once the RustCrypto coordinated release lands.

  3. The rebuild_cert_with_extensions helper in static_ct_api/src/rfc6962.rs:436-443 is a nice demonstration of the OwnedCertificate API's ergonomics for test utilities.

LGTM — clean upgrade with good test coverage for the manual DER encoding paths.

@ask-bonk
Copy link
Copy Markdown

ask-bonk bot commented Apr 14, 2026

Review posted on PR #212 with approval. Here's a summary of what I reviewed:

All 29 changed files examined. The PR is a well-executed coordinated RustCrypto dependency upgrade. Key findings:

  • OwnedTbsCertificate/OwnedCertificate in x509_util: Manual ASN.1 encoding matches RFC 5280 field ordering and tag modes correctly. Round-trip and golden file tests provide good regression coverage.
  • is_link_valid refactor: Replacing x509-verify with direct OID-based signature dispatch (P-256, P-384, P-521, RSA SHA-1/256/384/512) is cleaner and covers all WebPKI algorithms needed for CT/MTC.
  • x509-cert 0.3 migration: All field accesses consistently updated to use accessor methods across all crates.
  • rand 0.10 migration: All API changes (OsRngrand::rng(), gen_rangerandom_range, CryptoRngCoreCryptoRng + ?Sized) are correct.
  • LogEntry trait generalization: The Metadata associated type and make_metadata factory method are a clean design for future extensibility.
  • CI improvement: Build command now includes --tests --workspace to catch compile errors in dev-dependencies.
  • der fork removed: No longer needed since der 0.8 has native Tag::RelativeOid support.

github run

@lukevalenta lukevalenta force-pushed the lvalenta/rustcrypto-v2 branch from 2a71055 to a5862ba Compare April 15, 2026 00:42
Comment thread crates/bootstrap_mtc_api/src/cosigner.rs
Comment thread crates/generic_log_worker/src/log_ops.rs
Upgrades all RustCrypto crates to their latest RC versions to unblock
ml-dsa 0.1.0-rc.8, which fixes a WASM stack overflow with ML-DSA
signatures in Cloudflare Workers.

Workspace dependency changes:
- der 0.7.10 (patched fork) → 0.8.0 (Tag::RelativeOid now native)
- const-oid 0.9.6 → 0.10
- spki 0.7 → 0.8
- pkcs8 (new) 0.11.0-rc.11
- signature 2.2.0 → 3.0.0-rc.10
- sha1 0.10 → 0.11
- sha2 0.10 → 0.11
- digest (new) 0.11
- rand 0.8.5 → 0.10.0
- rand_core 0.6.4 → 0.10.0
- getrandom 0.2 → 0.4
- ed25519-dalek 2.1.1 → 3.0.0-pre.6
- p256 0.13 → 0.14.0-rc.8
- p384 0.13 → 0.14.0-rc.8
- p521 0.13 → 0.14.0-rc.8
- rsa 0.9 → 0.10.0-rc.17
- x509-cert 0.2.5 → 0.3.0-rc.4
- crypto-common (new) 0.2

Add OwnedTbsCertificate and OwnedCertificate to x509_util:
- Freely mutable owned representations of the x509-cert types whose
  fields were made private in x509-cert 0.3 (RustCrypto/formats#1505)
- DER encoding/decoding via #[derive(Sequence)] with #[asn1(...)]
  attributes, matching the pattern used by TbsCertificateLogEntry in
  bootstrap_mtc_api and the original x509-cert 0.2 structs
- Used in static_ct_api (rfc6962.rs) and bootstrap_mtc_api wherever
  certificate fields need to be mutated before re-encoding

Adapt to x509-cert 0.3 API changes (private fields → accessor methods,
Validity::new, RelativeDistinguishedName::try_from, etc.) throughout
bootstrap_mtc_api, bootstrap_mtc_worker, ct_worker, sct_validator,
static_ct_api, and integration_tests.

Adapt to rand 0.10 API changes (OsRng→SysRng, thread_rng()→rng(),
gen_range→random_range, RngExt, TryRng/TryCryptoRng in doc examples).

Adapt is_link_valid in x509_util to the upgraded crates:
- verify_rsa bound: sha2::digest::Digest + rsa::pkcs8::AssociatedOid →
  digest::Digest + const_oid::AssociatedOid (rsa 0.10-rc API)
- verify_p521: p521 0.14 makes VerifyingKey a type alias for
  ecdsa::VerifyingKey<NistP521>, so it now uses the same
  TryFrom<SubjectPublicKeyInfoRef>/DerSignature pattern as p256/p384
@lukevalenta lukevalenta force-pushed the lvalenta/rustcrypto-v2 branch from a5862ba to 04a9e43 Compare April 16, 2026 19:28
@lukevalenta lukevalenta merged commit 56bb829 into main Apr 16, 2026
7 checks passed
@lukevalenta lukevalenta deleted the lvalenta/rustcrypto-v2 branch April 16, 2026 19:38
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