Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions .cargo/audit.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# cargo-audit configuration.
# Run: cargo audit
#
# RUSTSEC-2023-0071 — "Marvin Attack" timing sidechannel in `rsa` 0.9.x
# (rsa -> jsonwebtoken rust_crypto backend -> structured-proxy).
#
# Ignored deliberately; mirror of the rationale in deny.toml.
# See https://github.com/structured-world/structured-proxy/issues/48
# - No fixed `rsa` release exists (latest 0.10.0-rc; advisory patched:[]).
# - We keep the pure-Rust `rust_crypto` backend over `aws_lc_rs` (C FFI).
# - RSA is used for JWT verification (public key) only; Marvin targets
# private-key timing, not exploitable on the verify path.
[advisories]
ignore = ["RUSTSEC-2023-0071"]
37 changes: 33 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,21 @@ env:

jobs:
quality-checks:
name: Quality Checks
name: Quality Checks (${{ matrix.backend.name }})
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
backend:
# The jsonwebtoken crypto backends are mutually exclusive (enabling
# both panics at runtime), so each is exercised on its own leg instead
# of via `--all-features`.
- name: rust_crypto
# Pure-Rust default backend (RustCrypto / rsa).
flags: "--features redis"
- name: aws_lc_rs
# Opt-in constant-time backend (aws-lc, C FFI); disables the default.
flags: "--no-default-features --features aws_lc_rs,redis"
steps:
- uses: actions/checkout@v6
with:
Expand All @@ -30,16 +43,32 @@ jobs:
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2

- name: Format
if: matrix.backend.name == 'rust_crypto'
run: cargo fmt --all -- --check

- name: Clippy
run: cargo clippy --all-targets --all-features
run: cargo clippy --all-targets ${{ matrix.backend.flags }}

- name: Build
run: cargo build --release
run: cargo build --release ${{ matrix.backend.flags }}

- name: Test
run: cargo test --all-features
run: cargo test ${{ matrix.backend.flags }}

- name: Publish dry-run
if: matrix.backend.name == 'rust_crypto'
run: cargo publish --dry-run

security-audit:
name: Security Audit
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
with:
persist-credentials: false
# Scans Cargo.lock for RustSec advisories; honors the ignore list in
# deny.toml. Third-party action: pinned to a commit SHA (dependabot
# keeps it fresh).
- uses: EmbarkStudios/cargo-deny-action@bb137d7af7e4fb67e5f82a49c4fce4fad40782fe # v2.0.20
with:
command: check advisories
22 changes: 20 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,11 @@ ipnet = "2"
# Optional shared rate-limit store for multi-instance deployments.
redis = { version = "0.27", features = ["tokio-comp"], optional = true }

# Auth (JWT validation, route policies)
jsonwebtoken = { version = "10", features = ["rust_crypto"] }
# Auth (JWT validation, route policies).
# Crypto backend is selected via this crate's `rust_crypto` / `aws_lc_rs`
# features (see [features] below); `use_pem` is always required for PEM key
# parsing and is therefore enabled unconditionally.
jsonwebtoken = { version = "10", default-features = false, features = ["use_pem"] }
reqwest = { version = "0.12", default-features = false, features = ["rustls-tls", "json"] }
globset = "0.4"
base64 = "0.22"
Expand All @@ -78,6 +81,21 @@ clap = { version = "4", features = ["derive"] }
envoy-types = "0.7"

[features]
default = ["rust_crypto"]

# JWT crypto backend. Mutually exclusive: enable exactly one. jsonwebtoken
# picks its provider from these features and panics at runtime if both (or
# neither) are on, so do NOT build with `--all-features`.
#
# `rust_crypto` (default): pure-Rust RustCrypto backend. Pulls in `rsa`, which
# carries RUSTSEC-2023-0071 (Marvin Attack). Not exploitable on our verify-only
# path (public key, no private-key ops); see deny.toml / issue #48.
rust_crypto = ["jsonwebtoken/rust_crypto"]
# `aws_lc_rs`: constant-time / FIPS-capable backend via aws-lc (C FFI),
# advisory-free. Opt-in for consumers that allow FFI; enable with
# `default-features = false, features = ["aws_lc_rs"]`.
aws_lc_rs = ["jsonwebtoken/aws_lc_rs"]
Comment thread
coderabbitai[bot] marked this conversation as resolved.

# Shared Redis-backed rate-limit store for multi-instance deployments.
redis = ["dep:redis"]

Expand Down
21 changes: 21 additions & 0 deletions deny.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# cargo-deny configuration.
# Run: cargo deny check advisories
#
# Only the advisories section is configured here; license/bans/sources checks
# fall back to cargo-deny defaults.

[advisories]
# RUSTSEC-2023-0071 — "Marvin Attack" timing sidechannel in `rsa` 0.9.x.
# Chain: rsa -> jsonwebtoken (rust_crypto backend) -> structured-proxy.
#
# Ignored deliberately. See https://github.com/structured-world/structured-proxy/issues/48
# 1. No fix exists: latest `rsa` is 0.10.0-rc and the advisory has patched:[] /
# unaffected:[] in the RustSec DB. Nothing to upgrade to.
# 2. We keep jsonwebtoken's pure-Rust `rust_crypto` backend over `aws_lc_rs`
# (C FFI), required by no-FFI consumers (e.g. CoordiNode ADR-013).
# 3. RSA here is used for JWT *verification* (public key) only. Marvin targets
# private-key timing (decrypt/sign), which never runs on the verify path.
# Revisit when RustCrypto ships a constant-time `rsa` stable release.
ignore = [
{ id = "RUSTSEC-2023-0071", reason = "No fixed `rsa` release exists (latest 0.10.0-rc; advisory patched:[]). We deliberately keep jsonwebtoken's pure-Rust `rust_crypto` backend over `aws_lc_rs` (C FFI). RSA is used for JWT verification (public key) only; Marvin targets private-key timing, not exploitable on the verify path. Revisit when RustCrypto ships a constant-time `rsa` stable. Tracking: structured-world/structured-proxy#48" },
]
15 changes: 15 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,21 @@
//! structured-proxy --config sid-proxy.yaml
//! structured-proxy --config sflow-proxy.yaml
//! ```
//!
//! ## JWT crypto backend
//!
//! Exactly one crypto backend feature must be enabled (they are mutually
//! exclusive): `rust_crypto` (default, pure Rust) or `aws_lc_rs` (opt-in,
//! constant-time / FIPS-capable, links aws-lc via C FFI). Enabling both or
//! neither is rejected at compile time by the guards below.

// jsonwebtoken selects its provider from these features and would otherwise
// panic at runtime on an invalid combination; turn that into a build error.
#[cfg(all(feature = "rust_crypto", feature = "aws_lc_rs"))]
compile_error!("features `rust_crypto` and `aws_lc_rs` are mutually exclusive; enable exactly one");

#[cfg(not(any(feature = "rust_crypto", feature = "aws_lc_rs")))]
compile_error!("exactly one JWT crypto backend must be enabled: `rust_crypto` or `aws_lc_rs`");

pub mod auth;
pub mod config;
Expand Down