Skip to content

Conversation

@lbaquerofierro
Copy link
Contributor

@lbaquerofierro lbaquerofierro commented Dec 24, 2025

Summary

  • Add sct_validator crate for validating Signed Certificate Timestamps (SCTs) embedded in certificates
  • Implement Chrome's Certificate Transparency policy requirements
  • Integrate optional SCT validation into the mtc_worker submission flow
  • Add cron job to fetch and cache Google's CT log list

Changes

New sct_validator crate

A WASM-compatible SCT validation library that implements Chrome's CT policy:

  • Certificates ≤ 180 days require 2 SCTs from unique logs
  • Certificates > 180 days require 3 SCTs from unique logs
  • Always requires SCTs from 2 different log operators
  • Handles log states: Qualified, Usable, ReadOnly (rejects Pending/Retired)
  • Auto-succeeds if log list is stale (> 70 days old)

mtc_worker integration

  • New ct_logs_cron.rs: Fetches Chrome's CT log list and caches in KV
  • New config option enable_sct_validation (default: false)
  • Frontend validates embedded SCTs before accepting certificates when enabled
  • Added ct_logs KV namespace binding in wrangler.jsonc

@lbaquerofierro lbaquerofierro changed the title RTG-3686: Add WASM-compatible SCT validation with Chrome CT policy Add WASM-compatible SCT validation with Chrome CT policy Dec 24, 2025
@lbaquerofierro lbaquerofierro force-pushed the lina/sct-validation branch 7 times, most recently from 0f5eb70 to 6db3196 Compare December 30, 2025 13:01
@bwesterb bwesterb self-requested a review December 30, 2025 15:09
));
}

let lifetime_secs = not_after_secs - not_before_secs;
Copy link
Member

Choose a reason for hiding this comment

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

If notBefore = notAfter, then the certificate is valid at that instant, so one second? So should we add a +1? What does Chrome do?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Per RFC 5280 validity is "notBefore through notAfter, inclusive", so strictly speaking a cert where notBefore == notAfter is valid for one instant, meaning we should technically add +1. However, concert uses a simple not_after - not_before difference without +1, matching https://googlechrome.github.io/CertificateTransparency/ct_policy.html behavior. Keeping it consistent with that

Copy link
Member

Choose a reason for hiding this comment

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

Where does the policy say that the lifetime is computed like that?

@bwesterb
Copy link
Member

We should add tests with existing certificates.


// Get leaf and issuer DER for SCT validation
let leaf_der = req.chain.first().ok_or("Chain is empty")?;
let issuer_der = req.chain.get(1).ok_or("Chain must have at least 2 certificates")?;
Copy link
Member

Choose a reason for hiding this comment

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

Quoting validate_chain:

/// * `raw_chain` - The 'bootstrap' chain of certificates submitted to the
///   `add-entry` endpoint. Each entry must sign the previous entry, and the
///   chain must start with a leaf certificate and end with a certificate that
///   is a trusted root or is signed by a trusted root.

This means that the trusted root certificate need not be part of the chain. If the root directly signs the leaf, then the chain is of length one. Obviously today this is rare, but that might change in the future.

@lbaquerofierro lbaquerofierro force-pushed the lina/sct-validation branch 2 times, most recently from cd62c57 to dfabc17 Compare January 7, 2026 10:16
@bwesterb bwesterb self-requested a review January 21, 2026 13:33
Copy link
Member

@bwesterb bwesterb left a comment

Choose a reason for hiding this comment

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

Great work, thanks. Before merging, we should really test with some actual certificates.

…pport

Adds sct_validator crate for validating Signed Certificate Timestamps (SCTs)
embedded in X.509 certificates, targeting WASM environments.

Key features:
- Chrome CT policy compliance (2-3 logs based on cert lifetime, 2 operators)
- ECDSA P-256 and RSA signature verification
- CT log list parsing from Google's JSON format
- Stale log list handling (auto-succeed after 70 days per Chrome policy)

Integration:
- New cron job fetches CT log list from Google
- Frontend validates SCTs when enable_sct_validation=true

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
@cjpatton cjpatton merged commit de2185d into cloudflare:main Jan 23, 2026
1 check passed
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.

6 participants