From 6e63479f34157a5a38523fdb14be572dbc13a7da Mon Sep 17 00:00:00 2001 From: Varsha Prasad Narsing Date: Mon, 14 Sep 2026 19:27:08 -0700 Subject: [PATCH 01/10] refactor(crypto): centralize AWS-LC behind backend interface Signed-off-by: Varsha Prasad Narsing --- AGENTS.md | 1 + Cargo.lock | 32 +- Cargo.toml | 12 +- architecture/build.md | 19 + crates/openshell-bootstrap/Cargo.toml | 2 +- crates/openshell-bootstrap/src/jwt.rs | 6 +- crates/openshell-bootstrap/src/pki.rs | 27 +- crates/openshell-cli/Cargo.toml | 3 +- crates/openshell-cli/src/oidc_auth.rs | 2 +- crates/openshell-cli/src/tls.rs | 2 +- crates/openshell-cli/tests/helpers/mod.rs | 6 +- crates/openshell-core/Cargo.toml | 3 +- crates/openshell-core/src/oauth.rs | 2 +- crates/openshell-core/src/telemetry.rs | 2 +- crates/openshell-crypto/Cargo.toml | 39 ++ crates/openshell-crypto/README.md | 83 ++++ crates/openshell-crypto/src/aead.rs | 39 ++ crates/openshell-crypto/src/aws_lc.rs | 102 +++++ crates/openshell-crypto/src/jwt.rs | 25 ++ crates/openshell-crypto/src/lib.rs | 372 ++++++++++++++++++ crates/openshell-crypto/src/pki.rs | 42 ++ crates/openshell-crypto/src/tls.rs | 38 ++ .../tests/context_selection.rs | 74 ++++ crates/openshell-crypto/tests/tls_default.rs | 26 ++ crates/openshell-crypto/tests/tls_embedder.rs | 13 + .../openshell-driver-db-credstore/Cargo.toml | 3 +- .../openshell-driver-db-credstore/src/lib.rs | 57 +-- .../Cargo.toml | 1 + crates/openshell-driver-kubernetes/Cargo.toml | 1 + crates/openshell-driver-vault/Cargo.toml | 1 + crates/openshell-driver-vault/src/lib.rs | 2 +- crates/openshell-extension-core/Cargo.toml | 1 + .../openshell-extension-core/src/transport.rs | 8 +- crates/openshell-sdk/Cargo.toml | 1 + crates/openshell-sdk/src/oidc.rs | 2 +- crates/openshell-sdk/src/transport.rs | 2 +- crates/openshell-server/Cargo.toml | 3 +- crates/openshell-server/src/auth/oidc.rs | 20 +- .../openshell-server/src/auth/sandbox_jwt.rs | 5 +- crates/openshell-server/src/grpc/provider.rs | 2 +- crates/openshell-server/src/lib.rs | 2 +- .../openshell-server/src/provider_refresh.rs | 4 +- crates/openshell-server/src/tls.rs | 19 +- crates/openshell-server/src/tls_test_utils.rs | 5 +- crates/openshell-server/tests/common/mod.rs | 16 +- .../openshell-supervisor-network/Cargo.toml | 1 + .../src/l7/tls.rs | 12 +- .../src/token_grant.rs | 2 +- .../src/upstream_proxy.rs | 4 +- e2e/rust/Cargo.lock | 184 ++++++++- e2e/rust/Cargo.toml | 5 +- e2e/rust/src/harness/container.rs | 6 +- e2e/rust/src/harness/host_process.rs | 2 +- e2e/rust/src/harness/sandbox.rs | 2 +- e2e/rust/tests/gateway_start.rs | 10 +- e2e/rust/tests/gpu/device_selection.rs | 2 +- e2e/rust/tests/gpu/workloads.rs | 4 +- e2e/rust/tests/local_driver_token_restart.rs | 8 +- e2e/rust/tests/podman_corporate_proxy.rs | 4 +- e2e/rust/tests/podman_gateway_start.rs | 14 +- e2e/rust/tests/podman_userns.rs | 2 +- e2e/rust/tests/provider_token_exchange.rs | 2 +- e2e/rust/tests/vm_corporate_proxy.rs | 4 +- e2e/rust/tests/vm_gateway_start.rs | 12 +- examples/governance-interceptor/Cargo.lock | 15 + examples/governance-interceptor/Cargo.toml | 5 +- examples/governance-interceptor/src/main.rs | 8 +- .../src/smoke_client.rs | 3 +- .../Cargo.lock | 364 ++++++++++++++++- tasks/ci.toml | 1 + tasks/rust.toml | 5 + tasks/scripts/check-crypto-boundary.sh | 20 + 72 files changed, 1630 insertions(+), 198 deletions(-) create mode 100644 crates/openshell-crypto/Cargo.toml create mode 100644 crates/openshell-crypto/README.md create mode 100644 crates/openshell-crypto/src/aead.rs create mode 100644 crates/openshell-crypto/src/aws_lc.rs create mode 100644 crates/openshell-crypto/src/jwt.rs create mode 100644 crates/openshell-crypto/src/lib.rs create mode 100644 crates/openshell-crypto/src/pki.rs create mode 100644 crates/openshell-crypto/src/tls.rs create mode 100644 crates/openshell-crypto/tests/context_selection.rs create mode 100644 crates/openshell-crypto/tests/tls_default.rs create mode 100644 crates/openshell-crypto/tests/tls_embedder.rs create mode 100755 tasks/scripts/check-crypto-boundary.sh diff --git a/AGENTS.md b/AGENTS.md index b1a0ffeb60..6b59c5d24b 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -50,6 +50,7 @@ These pipelines connect skills into end-to-end workflows. Individual skill files | `crates/openshell-ocsf/` | OCSF logging | OCSF v1.8.0 event types, builders, shorthand/JSONL formatters, tracing layers | | `crates/openshell-otel/` | OpenTelemetry support | Shared OTLP trace provider, resource, and tracing-layer construction | | `crates/openshell-otel-test-support/` | OpenTelemetry test support | Shared loopback OTLP collector fixture for tracing tests | +| `crates/openshell-crypto/` | Crypto backend | Backend-neutral primitives and TLS, PKI, JWT adapters; AWS-LC implementation | | `crates/openshell-core/` | Shared core | Common types, configuration, error handling | | `crates/openshell-extension-core/` | Extension core | Shared extension identity, JWT claims, bearer-token rotation, and TLS transport primitives | | `crates/openshell-gateway/` | Gateway binary composition | Links selected first-party compute drivers into the backend-agnostic server registry | diff --git a/Cargo.lock b/Cargo.lock index 109e6df8d5..c6de3eee85 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3950,10 +3950,10 @@ dependencies = [ "bytes", "miette", "openshell-core", + "openshell-crypto", "rcgen", "serde", "serde_json", - "sha2 0.10.9", "tempfile", "tokio", "tracing", @@ -3985,6 +3985,7 @@ dependencies = [ "oauth2", "openshell-bootstrap", "openshell-core", + "openshell-crypto", "openshell-policy", "openshell-providers", "openshell-sdk", @@ -4047,6 +4048,7 @@ dependencies = [ "jsonwebtoken", "miette", "nix 0.29.0", + "openshell-crypto", "openshell-extension-core", "openshell-policy-schema", "prost", @@ -4075,18 +4077,35 @@ dependencies = [ "zeroize", ] +[[package]] +name = "openshell-crypto" +version = "0.0.0" +dependencies = [ + "aws-lc-rs", + "hyper-rustls", + "jsonwebtoken", + "k8s-openapi", + "kube", + "rcgen", + "rustls", + "serde", + "serde_json", + "sqlx", + "thiserror 2.0.18", + "tonic", +] + [[package]] name = "openshell-driver-db-credstore" version = "0.0.0" dependencies = [ "async-trait", - "aws-lc-rs", "base64", "futures", "openshell-core", + "openshell-crypto", "serde", "serde_json", - "sha2 0.10.9", "tempfile", "tokio", "toml", @@ -4146,6 +4165,7 @@ dependencies = [ "miette", "notify", "openshell-core", + "openshell-crypto", "openshell-isolation-interface", "openshell-otel", "openshell-otel-test-support", @@ -4180,6 +4200,7 @@ dependencies = [ "kube", "miette", "openshell-core", + "openshell-crypto", "serde", "sha2 0.10.9", "tokio", @@ -4258,6 +4279,7 @@ dependencies = [ "futures", "miette", "openshell-core", + "openshell-crypto", "rcgen", "reqwest 0.12.28", "rustls", @@ -4328,6 +4350,7 @@ version = "0.0.0" dependencies = [ "http 1.4.0", "hyper-util", + "openshell-crypto", "rcgen", "rustls", "serde", @@ -4591,6 +4614,7 @@ dependencies = [ "miette", "oauth2", "openshell-core", + "openshell-crypto", "reqwest 0.12.28", "rustls", "serde", @@ -4643,6 +4667,7 @@ dependencies = [ "notify", "openshell-bootstrap", "openshell-core", + "openshell-crypto", "openshell-driver-db-credstore", "openshell-driver-kubernetes-secrets", "openshell-driver-vault", @@ -4798,6 +4823,7 @@ dependencies = [ "noyalib", "openshell-binary-identity", "openshell-core", + "openshell-crypto", "openshell-isolation-interface", "openshell-ocsf", "openshell-policy", diff --git a/Cargo.toml b/Cargo.toml index f57b22c397..a1bdfc6cf0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -37,10 +37,10 @@ http-body-util = "0.1" h2 = "0.4" # TLS -tokio-rustls = { version = "0.26", default-features = false, features = ["logging", "tls12", "aws_lc_rs"] } -rustls = { version = "0.23", default-features = false, features = ["std", "logging", "tls12", "aws_lc_rs"] } +tokio-rustls = { version = "0.26", default-features = false, features = ["logging", "tls12"] } +rustls = { version = "0.23", default-features = false, features = ["std", "logging", "tls12"] } rustls-pemfile = "2" -rcgen = { version = "0.13", default-features = false, features = ["crypto", "pem", "aws_lc_rs", "x509-parser"] } +rcgen = { version = "0.13", default-features = false, features = ["crypto", "pem", "x509-parser"] } webpki-roots = "1" rustls-native-certs = "0.8" @@ -107,7 +107,7 @@ base64 = "0.22" # Crypto / Auth sha2 = "0.10" rand = "0.9" -jsonwebtoken = { version = "10", features = ["aws_lc_rs"] } +jsonwebtoken = { version = "10", default-features = false, features = ["use_pem"] } zeroize = { version = "1", features = ["derive"] } getrandom = "0.3" aws-lc-rs = "1.16" @@ -130,12 +130,12 @@ url = "2" indexmap = "2" # Database -sqlx = { version = "0.9", default-features = false, features = ["runtime-tokio", "tls-rustls-aws-lc-rs", "postgres", "sqlite", "migrate", "macros"] } +sqlx = { version = "0.9", default-features = false, features = ["runtime-tokio", "postgres", "sqlite", "migrate", "macros"] } # SQLx's facade couples native roots to ring; select native roots independently. sqlx-core = { version = "0.9", default-features = false, features = ["rustls-native-certs"] } # Kubernetes -kube = { version = "0.99", default-features = false, features = ["client", "runtime", "derive", "rustls-tls", "aws-lc-rs"] } +kube = { version = "0.99", default-features = false, features = ["client", "runtime", "derive", "rustls-tls"] } kube-runtime = "0.99" k8s-openapi = { version = "0.24", features = ["v1_29"] } diff --git a/architecture/build.md b/architecture/build.md index 5ac5ff5f18..3ba804dbfb 100644 --- a/architecture/build.md +++ b/architecture/build.md @@ -27,6 +27,25 @@ Sandbox community images are built outside this repository. ## Build Features +Rust builds require Rust 1.94 or newer. TLS and certificate generation use +AWS-LC, including the CLI and standalone examples. Native and cross-build +environments must provide the C toolchain required by aws-lc-sys; the Nix +development shells provide static AWS-LC libraries. + +First-party crypto selection lives in `openshell-crypto`: backend-neutral +primitive traits and protocol adapters preserve existing TLS, PKI, JWT, and +credential-storage behavior. Application crates enable integration features on +that crate instead of naming a backend. Process-default initialization preserves +existing embedder providers; context capability reporting does not attest those +globals or dependency-owned crypto. OpenSSL and strict FIPS operation are separate +follow-up work. The crate README defines extension and coverage boundaries. + +SQLx uses AWS-LC with native certificate roots. + The server enables +`sqlx-core/rustls-native-certs` directly because SQLx's facade does not expose +that root selection independently of the crypto provider. Credential storage +continues to use the same AES-256-GCM envelope format across backend changes. + Anonymous telemetry emission is gated behind a default-on `telemetry` Cargo feature. It is defined in `openshell-core` (where the emission code, HTTP client, and endpoint live) and forwarded by the binary crates that emit or diff --git a/crates/openshell-bootstrap/Cargo.toml b/crates/openshell-bootstrap/Cargo.toml index 3705bdced2..6e69186094 100644 --- a/crates/openshell-bootstrap/Cargo.toml +++ b/crates/openshell-bootstrap/Cargo.toml @@ -10,11 +10,11 @@ repository.workspace = true rust-version.workspace = true [dependencies] +openshell-crypto = { path = "../openshell-crypto" } openshell-core = { path = "../openshell-core", default-features = false } bytes = { workspace = true } miette = { workspace = true } rcgen = { workspace = true } -sha2 = { workspace = true } serde = { workspace = true } serde_json = { workspace = true } tempfile = "3" diff --git a/crates/openshell-bootstrap/src/jwt.rs b/crates/openshell-bootstrap/src/jwt.rs index cf8ab0dc1a..0bda1a9f66 100644 --- a/crates/openshell-bootstrap/src/jwt.rs +++ b/crates/openshell-bootstrap/src/jwt.rs @@ -11,8 +11,6 @@ //! validator and any future external verifiers. use miette::{IntoDiagnostic, Result, WrapErr}; -use rcgen::{KeyPair, PKCS_ED25519}; -use sha2::{Digest, Sha256}; /// All PEM-encoded material needed to mint and validate sandbox JWTs. /// @@ -39,7 +37,7 @@ pub struct JwtKeyMaterial { /// (validation), so the gateway can round-trip its own tokens with no /// further conversion. pub fn generate_jwt_key() -> Result { - let keypair = KeyPair::generate_for(&PKCS_ED25519) + let keypair = openshell_crypto::pki::generate_jwt_keypair() .into_diagnostic() .wrap_err("failed to generate Ed25519 JWT signing key")?; let signing_key_pem = keypair.serialize_pem(); @@ -58,7 +56,7 @@ pub fn generate_jwt_key() -> Result { /// signing keys a single deployment ever has, while staying short enough /// to keep JWT headers compact. fn kid_from_public_key_der(public_key_der: &[u8]) -> String { - let digest = Sha256::digest(public_key_der); + let digest = openshell_crypto::sha256(public_key_der); hex_encode_prefix(&digest, 16) } diff --git a/crates/openshell-bootstrap/src/pki.rs b/crates/openshell-bootstrap/src/pki.rs index 5e5839a11a..b9e798e461 100644 --- a/crates/openshell-bootstrap/src/pki.rs +++ b/crates/openshell-bootstrap/src/pki.rs @@ -4,7 +4,7 @@ use crate::jwt::{JwtKeyMaterial, generate_jwt_key}; use miette::{IntoDiagnostic, Result, WrapErr}; use rcgen::{ - BasicConstraints, CertificateParams, DnType, Ia5String, IsCa, KeyPair, KeyUsagePurpose, SanType, + BasicConstraints, CertificateParams, DnType, Ia5String, IsCa, KeyUsagePurpose, SanType, }; use std::net::IpAddr; @@ -54,7 +54,7 @@ pub const DEFAULT_SERVER_SANS: &[&str] = &[ /// are ephemeral to the cluster's lifetime. pub fn generate_pki(extra_sans: &[String]) -> Result { // --- CA --- - let ca_key = KeyPair::generate() + let ca_key = openshell_crypto::pki::generate_keypair() .into_diagnostic() .wrap_err("failed to generate CA key")?; let mut ca_params = CertificateParams::new(Vec::::new()) @@ -69,13 +69,12 @@ pub fn generate_pki(extra_sans: &[String]) -> Result { .distinguished_name .push(DnType::CommonName, "openshell-ca"); - let ca_cert = ca_params - .self_signed(&ca_key) + let ca_cert = openshell_crypto::pki::self_signed(ca_params, &ca_key) .into_diagnostic() .wrap_err("failed to self-sign CA certificate")?; // --- Server cert --- - let server_key = KeyPair::generate() + let server_key = openshell_crypto::pki::generate_keypair() .into_diagnostic() .wrap_err("failed to generate server key")?; let server_sans = build_server_sans(extra_sans); @@ -88,13 +87,13 @@ pub fn generate_pki(extra_sans: &[String]) -> Result { .distinguished_name .push(DnType::CommonName, "openshell-server"); - let server_cert = server_params - .signed_by(&server_key, &ca_cert, &ca_key) - .into_diagnostic() - .wrap_err("failed to sign server certificate")?; + let server_cert = + openshell_crypto::pki::signed_by(server_params, &server_key, &ca_cert, &ca_key) + .into_diagnostic() + .wrap_err("failed to sign server certificate")?; // --- Client cert (shared by CLI and sandbox pods) --- - let client_key = KeyPair::generate() + let client_key = openshell_crypto::pki::generate_keypair() .into_diagnostic() .wrap_err("failed to generate client key")?; let mut client_params = CertificateParams::new(Vec::::new()) @@ -108,10 +107,10 @@ pub fn generate_pki(extra_sans: &[String]) -> Result { .distinguished_name .push(DnType::OrganizationalUnitName, "openshell-user"); - let client_cert = client_params - .signed_by(&client_key, &ca_cert, &ca_key) - .into_diagnostic() - .wrap_err("failed to sign client certificate")?; + let client_cert = + openshell_crypto::pki::signed_by(client_params, &client_key, &ca_cert, &ca_key) + .into_diagnostic() + .wrap_err("failed to sign client certificate")?; // --- JWT signing key (Ed25519, used to mint per-sandbox identity tokens) --- let JwtKeyMaterial { diff --git a/crates/openshell-cli/Cargo.toml b/crates/openshell-cli/Cargo.toml index 94d69063c2..d3ab917f2d 100644 --- a/crates/openshell-cli/Cargo.toml +++ b/crates/openshell-cli/Cargo.toml @@ -15,6 +15,7 @@ name = "openshell" path = "src/main.rs" [dependencies] +openshell-crypto = { path = "../openshell-crypto", features = ["tls-hyper"] } openshell-bootstrap = { path = "../openshell-bootstrap" } openshell-core = { path = "../openshell-core", default-features = false } openshell-policy = { path = "../openshell-policy" } @@ -49,7 +50,7 @@ bytes = { workspace = true } http-body-util = { workspace = true } hyper = { workspace = true } hyper-util = { workspace = true } -hyper-rustls = { version = "0.27", default-features = false, features = ["native-tokio", "http1", "http2", "tls12", "logging", "aws-lc-rs"] } +hyper-rustls = { version = "0.27", default-features = false, features = ["native-tokio", "http1", "http2", "tls12", "logging"] } rustls = { workspace = true } rustls-pemfile = { workspace = true } tokio-rustls = { workspace = true } diff --git a/crates/openshell-cli/src/oidc_auth.rs b/crates/openshell-cli/src/oidc_auth.rs index 7e362bf420..d9bf347f6b 100644 --- a/crates/openshell-cli/src/oidc_auth.rs +++ b/crates/openshell-cli/src/oidc_auth.rs @@ -93,7 +93,7 @@ async fn discover(issuer: &str, insecure: bool) -> Result { } fn http_client(insecure: bool) -> reqwest::Client { - let _ = rustls::crypto::aws_lc_rs::default_provider().install_default(); + openshell_crypto::tls::ensure_default_provider(); let mut builder = reqwest::ClientBuilder::new().redirect(reqwest::redirect::Policy::none()); if insecure { builder = builder.danger_accept_invalid_certs(true); diff --git a/crates/openshell-cli/src/tls.rs b/crates/openshell-cli/src/tls.rs index 2578ed9617..8ac64298fe 100644 --- a/crates/openshell-cli/src/tls.rs +++ b/crates/openshell-cli/src/tls.rs @@ -284,7 +284,7 @@ impl ServerCertVerifier for InsecureServerCertVerifier { } fn supported_verify_schemes(&self) -> Vec { - rustls::crypto::aws_lc_rs::default_provider() + openshell_crypto::tls::provider() .signature_verification_algorithms .supported_schemes() } diff --git a/crates/openshell-cli/tests/helpers/mod.rs b/crates/openshell-cli/tests/helpers/mod.rs index 9c446a1b56..d5d7a9cf1c 100644 --- a/crates/openshell-cli/tests/helpers/mod.rs +++ b/crates/openshell-cli/tests/helpers/mod.rs @@ -177,7 +177,7 @@ impl Drop for EnvVarGuard { /// Generate a self-signed CA certificate and its key pair. #[allow(dead_code)] pub fn build_ca() -> (Certificate, KeyPair) { - let key_pair = KeyPair::generate().unwrap(); + let key_pair = openshell_crypto::pki::generate_keypair().unwrap(); let mut params = CertificateParams::new(Vec::::new()).unwrap(); params.is_ca = IsCa::Ca(BasicConstraints::Unconstrained); let cert = params.self_signed(&key_pair).unwrap(); @@ -189,7 +189,7 @@ pub fn build_ca() -> (Certificate, KeyPair) { /// Returns `(cert_pem, key_pem)`. #[allow(dead_code)] pub fn build_server_cert(ca: &Certificate, ca_key: &KeyPair) -> (String, String) { - let key_pair = KeyPair::generate().unwrap(); + let key_pair = openshell_crypto::pki::generate_keypair().unwrap(); let mut params = CertificateParams::new(vec!["localhost".to_string()]).unwrap(); params.extended_key_usages = vec![ExtendedKeyUsagePurpose::ServerAuth]; let cert = params.signed_by(&key_pair, ca, ca_key).unwrap(); @@ -201,7 +201,7 @@ pub fn build_server_cert(ca: &Certificate, ca_key: &KeyPair) -> (String, String) /// Returns `(cert_pem, key_pem)`. #[allow(dead_code)] pub fn build_client_cert(ca: &Certificate, ca_key: &KeyPair) -> (String, String) { - let key_pair = KeyPair::generate().unwrap(); + let key_pair = openshell_crypto::pki::generate_keypair().unwrap(); let mut params = CertificateParams::new(Vec::::new()).unwrap(); params.extended_key_usages = vec![ExtendedKeyUsagePurpose::ClientAuth]; let cert = params.signed_by(&key_pair, ca, ca_key).unwrap(); diff --git a/crates/openshell-core/Cargo.toml b/crates/openshell-core/Cargo.toml index a246a40442..f96f0889b8 100644 --- a/crates/openshell-core/Cargo.toml +++ b/crates/openshell-core/Cargo.toml @@ -11,13 +11,14 @@ license.workspace = true repository.workspace = true [dependencies] +openshell-crypto = { path = "../openshell-crypto", features = ["tls-tonic"] } async-trait = "0.1" openshell-extension-core = { path = "../openshell-extension-core" } openshell-policy-schema = { path = "../openshell-policy-schema" } glob = { workspace = true } prost = { workspace = true } prost-types = { workspace = true } -tonic = { workspace = true, features = ["channel", "tls-aws-lc"] } +tonic = { workspace = true, features = ["channel"] } tonic-prost = { workspace = true } tonic-types = { workspace = true } tokio = { workspace = true } diff --git a/crates/openshell-core/src/oauth.rs b/crates/openshell-core/src/oauth.rs index d3a9e34725..b4e9fdee9e 100644 --- a/crates/openshell-core/src/oauth.rs +++ b/crates/openshell-core/src/oauth.rs @@ -312,7 +312,7 @@ mod tests { } fn test_client() -> reqwest::Client { - let _ = rustls::crypto::aws_lc_rs::default_provider().install_default(); + openshell_crypto::tls::ensure_default_provider(); reqwest::Client::builder() .timeout(std::time::Duration::from_secs(5)) .no_proxy() diff --git a/crates/openshell-core/src/telemetry.rs b/crates/openshell-core/src/telemetry.rs index 9541598fea..4fefb08a64 100644 --- a/crates/openshell-core/src/telemetry.rs +++ b/crates/openshell-core/src/telemetry.rs @@ -426,7 +426,7 @@ fn telemetry_worker(rx: mpsc::Receiver) { #[cfg(feature = "telemetry")] fn publish_payload(endpoint: &str, payload: Value) -> Result<(), reqwest::Error> { - let _ = rustls::crypto::aws_lc_rs::default_provider().install_default(); + openshell_crypto::tls::ensure_default_provider(); Client::builder() .use_rustls_tls() .tls_built_in_root_certs(true) diff --git a/crates/openshell-crypto/Cargo.toml b/crates/openshell-crypto/Cargo.toml new file mode 100644 index 0000000000..050af7637c --- /dev/null +++ b/crates/openshell-crypto/Cargo.toml @@ -0,0 +1,39 @@ +# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +[package] +name = "openshell-crypto" +description = "Crypto backend contract and protocol adapters for OpenShell" +version.workspace = true +edition.workspace = true +rust-version.workspace = true +license.workspace = true +repository.workspace = true + +[features] +# Dependencies that select their own provider must be configured as well as +# first-party calls. Consumers enable these integration features, never a backend. +tls-tonic = ["dep:tonic", "tonic/tls-aws-lc"] +tls-hyper = ["dep:hyper-rustls", "hyper-rustls/aws-lc-rs"] +tls-kube = ["dep:kube", "dep:k8s-openapi", "kube/aws-lc-rs"] +tls-sqlx = ["dep:sqlx", "sqlx/tls-rustls-aws-lc-rs"] + +[dependencies] +tonic = { workspace = true, optional = true } +hyper-rustls = { version = "0.27", default-features = false, optional = true } +kube = { workspace = true, optional = true } +k8s-openapi = { workspace = true, optional = true } +sqlx = { workspace = true, optional = true } + +aws-lc-rs = { workspace = true } +rustls = { workspace = true, features = ["aws_lc_rs"] } +rcgen = { workspace = true, features = ["aws_lc_rs"] } +jsonwebtoken = { workspace = true, features = ["aws_lc_rs"] } +serde = { workspace = true } +thiserror = { workspace = true } + +[dev-dependencies] +serde_json = { workspace = true } + +[lints] +workspace = true diff --git a/crates/openshell-crypto/README.md b/crates/openshell-crypto/README.md new file mode 100644 index 0000000000..d018887a7f --- /dev/null +++ b/crates/openshell-crypto/README.md @@ -0,0 +1,83 @@ +# OpenShell crypto backend + +`openshell-crypto` owns first-party crypto backend selection. AWS-LC is the only +production implementation. This change preserves TLS algorithms, Ed25519 gateway +JWTs, P-256 certificate keys, native trust roots, and credential envelope formats. +It does not introduce OpenSSL or a FIPS build mode. + +## Boundaries + +`CryptoBackend` defines randomness, incremental SHA-256, and AES-256-GCM without +crypto-library types. `ProtocolBackend` adds Rustls, rcgen, and jsonwebtoken +adapters. These adapters retain their protocol libraries' validation and encoding; +they do not expose AWS-LC types. A later native OpenSSL TLS integration may need +an additional transport adapter; this interface does not claim to provide one. + +Callers use `aead`, `pki`, `tls`, and `jwt`, or an explicit `CryptoContext`. +Certificate policy and JWT claim validation remain at their existing callers. +The rcgen adapter returns key pairs that own their signing implementation; a +future backend must supply its own implementation (for example, rcgen remote +keys) rather than silently using rcgen's compiled default. Raw signing and +verification currently use the protocol adapters, not a new general signature API. + +Shared manifests do not select a provider. Consumers of dependencies that select +their own providers enable `tls-tonic`, `tls-hyper`, `tls-kube`, or `tls-sqlx` on +this crate. Those features retain the current dependency selections and do not +make the dependencies use `CryptoContext` at runtime. Adding another backend +requires adapting these integrations as well as implementing the traits. + +## Lifecycle and posture + +`default_context()` lazily selects AWS-LC. An embedder can call +`install_default_context(context)` before first use. Reinstalling a clone of the +same context succeeds; installing a different context fails even if names match. +There is no live backend switching. Independent contexts can be used without +changing process state, including in contract tests. + +`tls::provider()` constructs an explicit provider from the selected context. +`tls::ensure_default_provider()` preserves an embedder's existing process default +and returns the actual installed provider. This preserves existing SDK behavior. +It must not be used as evidence that the process default belongs to the context. + +JWT initialization likewise preserves an existing process provider. +`install_jwt_provider()` reports whether this call installed it; jsonwebtoken 10 +has no public getter for verifying a previously installed provider. JWT adapters +retain that library's algorithm/key binding and claim-validation checks. Select a +custom context before initializing either protocol library, including indirect +initialization by dependencies. Neither global provider can be replaced safely. + +`CryptoContext::verify_posture(false)` reports the context's capabilities, not +ownership of process globals. A strict request is always rejected in this stage. +The module version is explicitly unknown because the backend wrapper does not +provide that information through the API used here. Backend identity, enabled +algorithms, and a successful operation are not deployment FIPS evidence. + +## Compatibility and exclusions + +AEAD stores a random 12-byte nonce and appends a 16-byte tag to ciphertext. +AAD construction, envelope version, key IDs, and encoding remain in the credential +driver. Random nonces do not guarantee uniqueness; existing key-volume and +rotation constraints still apply. Authentication failures expose no plaintext or +distinction between wrong keys, AAD, nonce, ciphertext, or tags. + +Coverage excludes dependency-owned SSH/russh primitives, AWS SigV4 signing, +SPIFFE RustCrypto verification, and non-Rust client runtimes. AWS SDK HTTPS also +retains its dependency-owned selection. Non-security content hashes and ordinary +scheduling randomness are not migrated. No SSH or PQC capability is asserted by +the primitive capability report. OpenSSL, strict policy, module version discovery, +and deployment qualification belong in follow-up work. + +## Extending and checking + +Implement both traits without importing application crates. Retain provider/key +resources for the full operation lifetime, propagate entropy and authentication +failures, and never fall back after a failure. Document unsupported algorithms +and avoid secret-bearing diagnostics. Add protocol adapters rather than moving +certificate or authorization policy into primitive implementations. + +Run `cargo test -p openshell-crypto` for known-answer crypto, tampering, JWT +validation, context substitution, and isolated global-provider tests. Existing +bootstrap, credential-store, gateway TLS/OIDC, and proxy tests exercise the +migrated consumers. `mise run crypto:check` rejects direct backend imports and +feature selections outside this crate. The existing cargo-deny Ring ban remains +in force. A source scan cannot attest the behavior of transitive dependencies. diff --git a/crates/openshell-crypto/src/aead.rs b/crates/openshell-crypto/src/aead.rs new file mode 100644 index 0000000000..6272e9b85d --- /dev/null +++ b/crates/openshell-crypto/src/aead.rs @@ -0,0 +1,39 @@ +// SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +//! AES-256-GCM envelope adapter. The persisted nonce/tag layout is unchanged. + +use crate::{CryptoError, default_context}; + +/// AES-256 key size. +pub const KEY_LEN: usize = 32; +/// GCM nonce size. +pub const NONCE_LEN: usize = 12; +/// Persisted algorithm identifier. +pub const ALGORITHM: &str = "AES-256-GCM"; + +/// Ciphertext and its random nonce; ciphertext includes the trailing 16-byte tag. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct Sealed { + /// Random 96-bit nonce. Random generation reduces but cannot eliminate collision risk. + pub nonce: [u8; NONCE_LEN], + /// Ciphertext followed by its authentication tag. + pub ciphertext: Vec, +} + +/// Encrypt with a newly generated nonce. Callers must bind record identity in AAD. +pub fn seal(key: &[u8; KEY_LEN], aad: &[u8], plaintext: &[u8]) -> Result { + default_context().backend().seal(key, aad, plaintext) +} + +/// Authenticate and decrypt without exposing partially decrypted data on failure. +pub fn open( + key: &[u8; KEY_LEN], + aad: &[u8], + nonce: &[u8; NONCE_LEN], + ciphertext: &[u8], +) -> Result, CryptoError> { + default_context() + .backend() + .open(key, aad, nonce, ciphertext) +} diff --git a/crates/openshell-crypto/src/aws_lc.rs b/crates/openshell-crypto/src/aws_lc.rs new file mode 100644 index 0000000000..38bac58174 --- /dev/null +++ b/crates/openshell-crypto/src/aws_lc.rs @@ -0,0 +1,102 @@ +// SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +//! The sole production backend. Backend-specific imports belong here. + +use crate::{Capabilities, CryptoBackend, CryptoError, Digest, FipsState, ProtocolBackend}; +use aws_lc_rs::{ + aead, digest, + rand::{SecureRandom, SystemRandom}, +}; + +pub struct AwsLc; +struct Sha256(digest::Context); + +impl Digest for Sha256 { + fn update(&mut self, bytes: &[u8]) { + self.0.update(bytes); + } + fn finish(self: Box) -> [u8; 32] { + let mut output = [0; 32]; + output.copy_from_slice(self.0.finish().as_ref()); + output + } +} + +impl CryptoBackend for AwsLc { + fn capabilities(&self) -> Capabilities { + Capabilities { + backend: "aws-lc", + provider_version: None, + fips: FipsState::NotVerified, + primitives: &["CSPRNG", "SHA-256", "AES-256-GCM"], + key_algorithms: &["ECDSA-P256-SHA256", "ECDSA-P384-SHA384", "Ed25519"], + } + } + fn fill_random(&self, output: &mut [u8]) -> Result<(), CryptoError> { + SystemRandom::new() + .fill(output) + .map_err(|_| CryptoError::Random) + } + fn sha256_digest(&self) -> Box { + Box::new(Sha256(digest::Context::new(&digest::SHA256))) + } + fn seal( + &self, + key: &[u8; 32], + aad: &[u8], + plaintext: &[u8], + ) -> Result { + let mut nonce = [0; 12]; + self.fill_random(&mut nonce)?; + let mut ciphertext = plaintext.to_vec(); + key_handle(key)? + .seal_in_place_append_tag( + aead::Nonce::assume_unique_for_key(nonce), + aead::Aad::from(aad), + &mut ciphertext, + ) + .map_err(|_| CryptoError::Operation)?; + Ok(crate::aead::Sealed { nonce, ciphertext }) + } + fn open( + &self, + key: &[u8; 32], + aad: &[u8], + nonce: &[u8; 12], + ciphertext: &[u8], + ) -> Result, CryptoError> { + let mut buffer = ciphertext.to_vec(); + let len = key_handle(key)? + .open_in_place( + aead::Nonce::assume_unique_for_key(*nonce), + aead::Aad::from(aad), + &mut buffer, + ) + .map_err(|_| CryptoError::Authentication)? + .len(); + buffer.truncate(len); + Ok(buffer) + } +} + +fn key_handle(key: &[u8; 32]) -> Result { + aead::UnboundKey::new(&aead::AES_256_GCM, key) + .map(aead::LessSafeKey::new) + .map_err(|_| CryptoError::Operation) +} + +impl ProtocolBackend for AwsLc { + fn tls_provider(&self) -> rustls::crypto::CryptoProvider { + rustls::crypto::aws_lc_rs::default_provider() + } + fn generate_keypair( + &self, + algorithm: &'static rcgen::SignatureAlgorithm, + ) -> Result { + rcgen::KeyPair::generate_for(algorithm) + } + fn jwt_provider(&self) -> &'static jsonwebtoken::crypto::CryptoProvider { + &jsonwebtoken::crypto::aws_lc::DEFAULT_PROVIDER + } +} diff --git a/crates/openshell-crypto/src/jwt.rs b/crates/openshell-crypto/src/jwt.rs new file mode 100644 index 0000000000..3e055d1048 --- /dev/null +++ b/crates/openshell-crypto/src/jwt.rs @@ -0,0 +1,25 @@ +// SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +//! JWT adapter preserving jsonwebtoken's algorithm binding and claims validation. +//! Existing process defaults are retained for compatibility with embedded users. + +/// Sign claims without changing the caller's algorithm, headers, or key format. +pub fn encode( + header: &jsonwebtoken::Header, + claims: &T, + key: &jsonwebtoken::EncodingKey, +) -> jsonwebtoken::errors::Result { + crate::install_jwt_provider(); + jsonwebtoken::encode(header, claims, key) +} + +/// Verify a token and all caller-specified claims constraints. +pub fn decode( + token: impl AsRef<[u8]>, + key: &jsonwebtoken::DecodingKey, + validation: &jsonwebtoken::Validation, +) -> jsonwebtoken::errors::Result> { + crate::install_jwt_provider(); + jsonwebtoken::decode(token, key, validation) +} diff --git a/crates/openshell-crypto/src/lib.rs b/crates/openshell-crypto/src/lib.rs new file mode 100644 index 0000000000..b574910f3f --- /dev/null +++ b/crates/openshell-crypto/src/lib.rs @@ -0,0 +1,372 @@ +// SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +//! Backend-neutral crypto operations and library-specific protocol adapters. +//! +//! AWS-LC is the only production implementation in this first stage. This crate +//! does not enable FIPS mode, change algorithms, or attest dependency-owned crypto. +//! See the crate README for initialization and extension boundaries. + +pub mod aead; +mod aws_lc; +pub mod jwt; +pub mod pki; +pub mod tls; + +use std::sync::{Arc, OnceLock}; + +/// Errors contain no key material or authentication-failure details. +#[derive(Debug, Clone, Copy, PartialEq, Eq, thiserror::Error)] +pub enum CryptoError { + /// A backend could not obtain cryptographic randomness. + #[error("cryptographic random generation failed")] + Random, + /// Encryption or key initialization failed. + #[error("cryptographic operation failed")] + Operation, + /// Authentication failed; do not distinguish key, nonce, AAD, or tag errors. + #[error("ciphertext authentication failed")] + Authentication, + /// The installed process provider was not verified as this context's provider. + #[error("process crypto provider is not owned by this context")] + ProviderConflict, + /// The requested operating mode is not verified by this backend. + #[error("required crypto posture is unavailable")] + UnsupportedPosture, +} + +/// Module status, scoped to this backend's operations, not the deployment. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum FipsState { + /// No validated operating mode is asserted. + NotVerified, +} + +/// Operations implemented by a backend. Protocol coverage is documented separately. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct Capabilities { + /// Stable backend identifier. + pub backend: &'static str, + /// Underlying module version, if available from the backend API. + pub provider_version: Option<&'static str>, + /// Effective module posture; an unknown version must not become a claim. + pub fips: FipsState, + /// Primitive operations supported by this implementation. + pub primitives: &'static [&'static str], + /// Key generation algorithms available through the PKI adapter. + pub key_algorithms: &'static [&'static str], +} + +/// Object-safe incremental SHA-256 computation. +pub trait Digest: Send { + /// Append bytes without allocating a concatenated message. + fn update(&mut self, bytes: &[u8]); + /// Consume the state and return the digest. + fn finish(self: Box) -> [u8; 32]; +} + +/// Primitive contract. No concrete crypto-library types cross this boundary. +/// +/// Implementations must not fall back to another backend after an operation fails. +/// Protocol adapters are separate because their types and validation semantics +/// belong to the corresponding protocol library. +pub trait CryptoBackend: Send + Sync { + /// Describe implemented operations without claiming whole-process coverage. + fn capabilities(&self) -> Capabilities; + /// Fill the entire output or report an entropy failure. + fn fill_random(&self, output: &mut [u8]) -> Result<(), CryptoError>; + /// Create an incremental SHA-256 computation. + fn sha256_digest(&self) -> Box; + /// Encrypt with a fresh random 96-bit nonce, appending the 128-bit GCM tag. + fn seal( + &self, + key: &[u8; 32], + aad: &[u8], + plaintext: &[u8], + ) -> Result; + /// Authenticate before returning plaintext. All authentication failures are opaque. + fn open( + &self, + key: &[u8; 32], + aad: &[u8], + nonce: &[u8; 12], + ciphertext: &[u8], + ) -> Result, CryptoError>; +} + +/// Adapters for the protocol libraries currently used by `OpenShell`. +/// +/// A follow-up backend must implement these as well as the primitive contract. +/// Returning rcgen/rustls/jsonwebtoken types does not expose AWS-LC types. +pub trait ProtocolBackend: CryptoBackend { + /// Construct the full TLS provider, including certificate verification. + fn tls_provider(&self) -> rustls::crypto::CryptoProvider; + /// Generate a key for the requested certificate/JWT algorithm. + fn generate_keypair( + &self, + algorithm: &'static rcgen::SignatureAlgorithm, + ) -> Result; + /// JWT signing, verification, and JWK operations; claims validation stays in jsonwebtoken. + fn jwt_provider(&self) -> &'static jsonwebtoken::crypto::CryptoProvider; +} + +/// Explicit backend context for embedders and contract tests. +/// +/// Construction does not modify process-global providers. Retaining the context +/// retains backend resources. Select the application default before first use. +#[derive(Clone)] +pub struct CryptoContext { + backend: Arc, +} + +impl CryptoContext { + /// Construct a context without changing any process globals. + #[must_use] + pub fn new(backend: Box) -> Self { + Self { + backend: Arc::from(backend), + } + } + + /// The selected operations and protocol adapters. + #[must_use] + pub fn backend(&self) -> &dyn ProtocolBackend { + self.backend.as_ref() + } + + /// Verify the backend's limited posture. Strict FIPS is deliberately unsupported. + pub fn verify_posture(&self, require_fips: bool) -> Result { + if require_fips { + return Err(CryptoError::UnsupportedPosture); + } + Ok(self.backend.capabilities()) + } +} + +impl Default for CryptoContext { + fn default() -> Self { + Self::new(Box::new(aws_lc::AwsLc)) + } +} + +static DEFAULT: OnceLock = OnceLock::new(); + +/// Application default, initialized lazily to AWS-LC unless selected before first use. +#[must_use] +pub fn default_context() -> &'static CryptoContext { + DEFAULT.get_or_init(CryptoContext::default) +} + +/// Select a context before the first application crypto operation. +/// +/// Reinstalling a clone of the same context is idempotent. A different context +/// fails even if it reports the same backend name. This does not replace existing +/// Rustls or JWT globals: embedders must select before initializing those libraries. +pub fn install_default_context(context: CryptoContext) -> Result<(), CryptoError> { + match DEFAULT.set(context) { + Ok(()) => Ok(()), + Err(context) if Arc::ptr_eq(&default_context().backend, &context.backend) => Ok(()), + Err(_) => Err(CryptoError::ProviderConflict), + } +} + +/// Fill bytes using the application backend. +pub fn fill_random(output: &mut [u8]) -> Result<(), CryptoError> { + default_context().backend().fill_random(output) +} + +/// Generate a fixed-size random value. +pub fn random_bytes() -> Result<[u8; N], CryptoError> { + let mut output = [0; N]; + fill_random(&mut output)?; + Ok(output) +} + +/// Create an incremental SHA-256 computation. +#[must_use] +pub fn sha256_digest() -> Box { + default_context().backend().sha256_digest() +} + +/// Compute SHA-256 using the selected implementation. +#[must_use] +pub fn sha256(bytes: &[u8]) -> [u8; 32] { + let mut digest = sha256_digest(); + digest.update(bytes); + digest.finish() +} + +/// Install the JWT adapter if no provider has been installed. +/// +/// jsonwebtoken 10 does not expose its installed provider. A false return means +/// ownership cannot be verified, including when it auto-installed the same backend. +/// This preserves the existing embedder behavior; it is not a posture check. +pub fn install_jwt_provider() -> bool { + default_context() + .backend() + .jwt_provider() + .install_default() + .is_ok() +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn digest_known_answer_and_streaming_agree() { + let expected = [ + 0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, 0x41, 0x41, 0x40, 0xde, 0x5d, 0xae, + 0x22, 0x23, 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c, 0xb4, 0x10, 0xff, 0x61, + 0xf2, 0x00, 0x15, 0xad, + ]; + assert_eq!(sha256(b"abc"), expected); + let mut digest = sha256_digest(); + digest.update(b"a"); + digest.update(b"bc"); + assert_eq!(digest.finish(), expected); + } + + #[test] + fn aead_authenticates_every_input() { + let key = [7; 32]; + let sealed = aead::seal(&key, b"record", b"secret").unwrap(); + assert_eq!(sealed.ciphertext.len(), 6 + 16); + assert_eq!( + aead::open(&key, b"record", &sealed.nonce, &sealed.ciphertext).unwrap(), + b"secret" + ); + let mut bad_nonce = sealed.nonce; + bad_nonce[0] ^= 1; + let mut bad_tag = sealed.ciphertext.clone(); + *bad_tag.last_mut().unwrap() ^= 1; + for result in [ + aead::open(&[8; 32], b"record", &sealed.nonce, &sealed.ciphertext), + aead::open(&key, b"other", &sealed.nonce, &sealed.ciphertext), + aead::open(&key, b"record", &bad_nonce, &sealed.ciphertext), + aead::open(&key, b"record", &sealed.nonce, &bad_tag), + aead::open(&key, b"record", &sealed.nonce, &sealed.ciphertext[..15]), + ] { + assert_eq!(result, Err(CryptoError::Authentication)); + } + let empty = aead::seal(&key, b"", b"").unwrap(); + assert!( + aead::open(&key, b"", &empty.nonce, &empty.ciphertext) + .unwrap() + .is_empty() + ); + } + + #[test] + fn aes256_gcm_decrypts_known_answer() { + // NIST AES-GCM: 256-bit zero key, 96-bit zero IV, empty AAD/plaintext. + let tag = [ + 0x53, 0x0f, 0x8a, 0xfb, 0xc7, 0x45, 0x36, 0xb9, 0xa9, 0x63, 0xb4, 0xf1, 0xc4, 0xcb, + 0x73, 0x8b, + ]; + assert_eq!(aead::open(&[0; 32], b"", &[0; 12], &tag).unwrap(), b""); + } + + #[test] + fn jwt_preserves_eddsa_and_claim_validation() { + let key = pki::generate_jwt_keypair().unwrap(); + assert_eq!(key.algorithm(), &rcgen::PKCS_ED25519); + let signing = + jsonwebtoken::EncodingKey::from_ed_pem(key.serialize_pem().as_bytes()).unwrap(); + let verifying = + jsonwebtoken::DecodingKey::from_ed_pem(key.public_key_pem().as_bytes()).unwrap(); + let header = jsonwebtoken::Header::new(jsonwebtoken::Algorithm::EdDSA); + let claims = serde_json::json!({"sub":"sandbox", "iss":"gateway", "exp":4_000_000_000_u64}); + let token = jwt::encode(&header, &claims, &signing).unwrap(); + let mut validation = jsonwebtoken::Validation::new(jsonwebtoken::Algorithm::EdDSA); + validation.set_issuer(&["gateway"]); + let decoded = jwt::decode::(&token, &verifying, &validation).unwrap(); + assert_eq!(decoded.claims, claims); + validation.set_issuer(&["different"]); + assert!(jwt::decode::(&token, &verifying, &validation).is_err()); + let expired = jwt::encode(&header, &serde_json::json!({"exp":1}), &signing).unwrap(); + assert!(jwt::decode::(&expired, &verifying, &validation).is_err()); + assert!(jwt::encode(&jsonwebtoken::Header::default(), &claims, &signing).is_err()); + } + + struct NoEntropy; + impl CryptoBackend for NoEntropy { + fn capabilities(&self) -> Capabilities { + let mut caps = aws_lc::AwsLc.capabilities(); + caps.backend = "test-no-entropy"; + caps.primitives = &["SHA-256"]; + caps + } + fn fill_random(&self, _: &mut [u8]) -> Result<(), CryptoError> { + Err(CryptoError::Random) + } + fn sha256_digest(&self) -> Box { + aws_lc::AwsLc.sha256_digest() + } + fn seal(&self, _: &[u8; 32], _: &[u8], _: &[u8]) -> Result { + Err(CryptoError::Random) + } + fn open( + &self, + _: &[u8; 32], + _: &[u8], + _: &[u8; 12], + _: &[u8], + ) -> Result, CryptoError> { + Err(CryptoError::Operation) + } + } + impl ProtocolBackend for NoEntropy { + fn tls_provider(&self) -> rustls::crypto::CryptoProvider { + aws_lc::AwsLc.tls_provider() + } + fn generate_keypair( + &self, + _: &'static rcgen::SignatureAlgorithm, + ) -> Result { + Err(rcgen::Error::KeyGenerationUnavailable) + } + fn jwt_provider(&self) -> &'static jsonwebtoken::crypto::CryptoProvider { + aws_lc::AwsLc.jwt_provider() + } + } + + #[test] + fn context_substitution_propagates_failure_without_fallback() { + let context = CryptoContext::new(Box::new(NoEntropy)); + assert_eq!( + context.verify_posture(false).unwrap().backend, + "test-no-entropy" + ); + assert_eq!( + context.backend().fill_random(&mut [0; 32]), + Err(CryptoError::Random) + ); + assert_eq!( + context.backend().seal(&[0; 32], b"", b"secret"), + Err(CryptoError::Random) + ); + assert!( + context + .backend() + .generate_keypair(&rcgen::PKCS_ED25519) + .is_err() + ); + assert_eq!( + context.verify_posture(true), + Err(CryptoError::UnsupportedPosture) + ); + assert_eq!( + default_context().verify_posture(false).unwrap().backend, + "aws-lc" + ); + assert_eq!( + default_context().verify_posture(true), + Err(CryptoError::UnsupportedPosture) + ); + assert_eq!( + install_default_context(context), + Err(CryptoError::ProviderConflict) + ); + } +} diff --git a/crates/openshell-crypto/src/pki.rs b/crates/openshell-crypto/src/pki.rs new file mode 100644 index 0000000000..0100fe42cf --- /dev/null +++ b/crates/openshell-crypto/src/pki.rs @@ -0,0 +1,42 @@ +// SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +//! rcgen adapter. Certificate policy remains with the caller; key operations +//! route through the selected backend. No algorithm or format migration occurs. + +/// Generate the existing default ECDSA P-256 certificate key. +pub fn generate_keypair() -> Result { + generate_keypair_for(&rcgen::PKCS_ECDSA_P256_SHA256) +} + +/// Generate a key for an explicit protocol algorithm. +pub fn generate_keypair_for( + algorithm: &'static rcgen::SignatureAlgorithm, +) -> Result { + crate::default_context() + .backend() + .generate_keypair(algorithm) +} + +/// Generate the existing Ed25519 gateway JWT key. +pub fn generate_jwt_keypair() -> Result { + generate_keypair_for(&rcgen::PKCS_ED25519) +} + +/// Sign a certificate using its own key. +pub fn self_signed( + params: rcgen::CertificateParams, + key: &rcgen::KeyPair, +) -> Result { + params.self_signed(key) +} + +/// Sign a certificate with an issuer, retaining rcgen's encoding and validation. +pub fn signed_by( + params: rcgen::CertificateParams, + key: &rcgen::KeyPair, + issuer: &rcgen::Certificate, + issuer_key: &rcgen::KeyPair, +) -> Result { + params.signed_by(key, issuer, issuer_key) +} diff --git a/crates/openshell-crypto/src/tls.rs b/crates/openshell-crypto/src/tls.rs new file mode 100644 index 0000000000..cc24f12e67 --- /dev/null +++ b/crates/openshell-crypto/src/tls.rs @@ -0,0 +1,38 @@ +// SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +//! Rustls adapter. Explicit configurations use this provider. Library callers +//! may retain an embedder's process default; that default is not attested here. + +use rustls::crypto::{CryptoProvider, WebPkiSupportedAlgorithms}; +use std::sync::Arc; + +/// Construct the application's TLS provider without changing the process default. +#[must_use] +pub fn provider() -> CryptoProvider { + crate::default_context().backend().tls_provider() +} + +/// Ensure a provider is available, preserving a host application's existing choice. +/// +/// Returns the actual installed provider, including when another thread wins the +/// installation race. Callers must not infer backend identity from this operation. +pub fn ensure_default_provider() -> &'static Arc { + if CryptoProvider::get_default().is_none() { + let _ = provider().install_default(); + } + CryptoProvider::get_default().expect("a crypto provider was installed") +} + +/// Verification algorithms for custom TLS certificate verifiers. +#[must_use] +pub fn signature_verification_algorithms() -> WebPkiSupportedAlgorithms { + provider().signature_verification_algorithms +} + +/// Load a TLS signing key through the selected provider's key adapter. +pub fn any_supported_signing_key( + key: &rustls::pki_types::PrivateKeyDer<'_>, +) -> Result, rustls::Error> { + provider().key_provider.load_private_key(key.clone_key()) +} diff --git a/crates/openshell-crypto/tests/context_selection.rs b/crates/openshell-crypto/tests/context_selection.rs new file mode 100644 index 0000000000..d01a79bfff --- /dev/null +++ b/crates/openshell-crypto/tests/context_selection.rs @@ -0,0 +1,74 @@ +// SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +use openshell_crypto::{ + Capabilities, CryptoBackend, CryptoContext, CryptoError, Digest, ProtocolBackend, aead::Sealed, +}; + +struct TestBackend(CryptoContext); +impl CryptoBackend for TestBackend { + fn capabilities(&self) -> Capabilities { + let mut capabilities = self.0.backend().capabilities(); + capabilities.backend = "test"; + capabilities + } + fn fill_random(&self, bytes: &mut [u8]) -> Result<(), CryptoError> { + bytes.fill(0x55); + Ok(()) + } + fn sha256_digest(&self) -> Box { + self.0.backend().sha256_digest() + } + fn seal(&self, _: &[u8; 32], _: &[u8], _: &[u8]) -> Result { + Err(CryptoError::Random) + } + fn open(&self, _: &[u8; 32], _: &[u8], _: &[u8; 12], _: &[u8]) -> Result, CryptoError> { + Err(CryptoError::Authentication) + } +} +impl ProtocolBackend for TestBackend { + fn tls_provider(&self) -> rustls::crypto::CryptoProvider { + let mut provider = self.0.backend().tls_provider(); + provider.cipher_suites.truncate(1); + provider + } + fn generate_keypair( + &self, + _: &'static rcgen::SignatureAlgorithm, + ) -> Result { + Err(rcgen::Error::KeyGenerationUnavailable) + } + fn jwt_provider(&self) -> &'static jsonwebtoken::crypto::CryptoProvider { + self.0.backend().jwt_provider() + } +} + +#[test] +fn selected_context_controls_application_adapters_and_cannot_be_replaced() { + let context = CryptoContext::new(Box::new(TestBackend(CryptoContext::default()))); + openshell_crypto::install_default_context(context.clone()).unwrap(); + openshell_crypto::install_default_context(context).unwrap(); + assert_eq!(openshell_crypto::random_bytes::<8>().unwrap(), [0x55; 8]); + assert_eq!( + openshell_crypto::aead::seal(&[0; 32], b"", b""), + Err(CryptoError::Random) + ); + assert!(openshell_crypto::pki::generate_keypair().is_err()); + assert_eq!( + openshell_crypto::tls::ensure_default_provider() + .cipher_suites + .len(), + 1 + ); + assert_eq!( + openshell_crypto::default_context() + .verify_posture(false) + .unwrap() + .backend, + "test" + ); + assert_eq!( + openshell_crypto::install_default_context(CryptoContext::default()), + Err(CryptoError::ProviderConflict) + ); +} diff --git a/crates/openshell-crypto/tests/tls_default.rs b/crates/openshell-crypto/tests/tls_default.rs new file mode 100644 index 0000000000..ff6c1bb7a0 --- /dev/null +++ b/crates/openshell-crypto/tests/tls_default.rs @@ -0,0 +1,26 @@ +// SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +#[test] +fn default_initialization_is_idempotent() { + let first = openshell_crypto::tls::ensure_default_provider(); + let second = openshell_crypto::tls::ensure_default_provider(); + assert!(std::sync::Arc::ptr_eq(first, second)); + let expected = openshell_crypto::tls::provider(); + assert_eq!(first.cipher_suites, expected.cipher_suites); + assert_eq!( + first.kx_groups.iter().map(|g| g.name()).collect::>(), + expected + .kx_groups + .iter() + .map(|g| g.name()) + .collect::>() + ); +} + +#[test] +fn repeated_context_selection_accepts_only_the_same_context() { + let context = openshell_crypto::default_context().clone(); + openshell_crypto::install_default_context(context.clone()).unwrap(); + openshell_crypto::install_default_context(context).unwrap(); +} diff --git a/crates/openshell-crypto/tests/tls_embedder.rs b/crates/openshell-crypto/tests/tls_embedder.rs new file mode 100644 index 0000000000..fd33a6121e --- /dev/null +++ b/crates/openshell-crypto/tests/tls_embedder.rs @@ -0,0 +1,13 @@ +// SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +#[test] +fn library_initialization_preserves_embedder_policy() { + // Separate test executable: process-default state cannot leak from other tests. + let mut host = openshell_crypto::tls::provider(); + host.cipher_suites.truncate(1); + host.install_default().unwrap(); + let installed = openshell_crypto::tls::ensure_default_provider(); + assert_eq!(installed.cipher_suites.len(), 1); + assert!(openshell_crypto::tls::provider().cipher_suites.len() > 1); +} diff --git a/crates/openshell-driver-db-credstore/Cargo.toml b/crates/openshell-driver-db-credstore/Cargo.toml index 9f3f5427b4..92f9093601 100644 --- a/crates/openshell-driver-db-credstore/Cargo.toml +++ b/crates/openshell-driver-db-credstore/Cargo.toml @@ -11,15 +11,14 @@ license.workspace = true repository.workspace = true [dependencies] +openshell-crypto = { path = "../openshell-crypto" } openshell-core = { path = "../openshell-core", default-features = false } async-trait = "0.1" base64 = { workspace = true } futures = { workspace = true } -aws-lc-rs = { workspace = true } serde = { workspace = true } serde_json = { workspace = true } -sha2 = { workspace = true } toml = { workspace = true } tonic = { workspace = true } diff --git a/crates/openshell-driver-db-credstore/src/lib.rs b/crates/openshell-driver-db-credstore/src/lib.rs index 85ef0a5a69..871652bad3 100644 --- a/crates/openshell-driver-db-credstore/src/lib.rs +++ b/crates/openshell-driver-db-credstore/src/lib.rs @@ -17,8 +17,6 @@ use std::path::{Path, PathBuf}; use std::sync::Arc; use async_trait::async_trait; -use aws_lc_rs::aead::{AES_256_GCM, Aad, LessSafeKey, Nonce, UnboundKey}; -use aws_lc_rs::rand::{SecureRandom, SystemRandom}; use base64::{ Engine as _, engine::general_purpose::{STANDARD as BASE64, STANDARD_NO_PAD as BASE64_NO_PAD}, @@ -29,7 +27,6 @@ use openshell_core::proto::credentials::v1::{ }; use openshell_core::{Error, Result as CoreResult}; use serde::{Deserialize, Serialize}; -use sha2::{Digest, Sha256}; use tonic::Status; const HANDLE_VERSION: &str = "v1"; @@ -721,18 +718,11 @@ fn encrypt_bytes( aad: &[u8], plaintext: &[u8], ) -> Result { - let nonce = random_bytes_status::()?; - let key = aead_key(key_bytes)?; - let mut in_out = plaintext.to_vec(); - key.seal_in_place_append_tag( - Nonce::assume_unique_for_key(nonce), - Aad::from(aad), - &mut in_out, - ) - .map_err(|_| Status::internal("failed to encrypt default credential storage value"))?; + let sealed = openshell_crypto::aead::seal(key_bytes, aad, plaintext) + .map_err(|_| Status::internal("failed to encrypt default credential storage value"))?; Ok(EncryptedBytes { - nonce: BASE64.encode(nonce), - ciphertext: BASE64.encode(in_out), + nonce: BASE64.encode(sealed.nonce), + ciphertext: BASE64.encode(sealed.ciphertext), }) } @@ -742,23 +732,9 @@ fn decrypt_bytes( encrypted: &EncryptedBytes, ) -> Result, Status> { let nonce = decode_b64_array::("nonce", &encrypted.nonce)?; - let mut in_out = decode_b64_vec("ciphertext", &encrypted.ciphertext)?; - let key = aead_key(key_bytes)?; - let plaintext = key - .open_in_place( - Nonce::assume_unique_for_key(nonce), - Aad::from(aad), - &mut in_out, - ) - .map_err(|_| Status::data_loss("failed to decrypt default credential storage value"))?; - Ok(plaintext.to_vec()) -} - -fn aead_key(key_bytes: &[u8; KEY_LEN]) -> Result { - let unbound = UnboundKey::new(&AES_256_GCM, key_bytes).map_err(|_| { - Status::internal("failed to initialize default credential storage AEAD key") - })?; - Ok(LessSafeKey::new(unbound)) + let ciphertext = decode_b64_vec("ciphertext", &encrypted.ciphertext)?; + openshell_crypto::aead::open(key_bytes, aad, &nonce, &ciphertext) + .map_err(|_| Status::data_loss("failed to decrypt default credential storage value")) } fn dek_aad(id: &str, provider_name: &str, credential_key: &str) -> Vec { @@ -896,22 +872,21 @@ fn fixed_bytes(bytes: &[u8]) -> Result<[u8; N], ()> { fn random_bytes_core() -> CoreResult<[u8; N]> { let mut bytes = [0_u8; N]; - SystemRandom::new() - .fill(&mut bytes) + openshell_crypto::fill_random(&mut bytes) .map_err(|_| Error::config("failed to generate default credential storage key material"))?; Ok(bytes) } fn random_bytes_status() -> Result<[u8; N], Status> { let mut bytes = [0_u8; N]; - SystemRandom::new().fill(&mut bytes).map_err(|_| { + openshell_crypto::fill_random(&mut bytes).map_err(|_| { Status::internal("failed to generate default credential storage randomness") })?; Ok(bytes) } fn key_id(key: &[u8; KEY_LEN]) -> String { - let digest = Sha256::digest(key); + let digest = openshell_crypto::sha256(key); format!("sha256:{}", hex_encode(&digest)) } @@ -956,16 +931,8 @@ mod tests { ciphertext: ciphertext.to_string(), }; assert_eq!(decrypt_bytes(&key, &aad, &encrypted).unwrap(), plaintext); - let mut sealed = plaintext; - aead_key(&key) - .unwrap() - .seal_in_place_append_tag( - Nonce::assume_unique_for_key(nonce), - Aad::from(aad.as_slice()), - &mut sealed, - ) - .unwrap(); - assert_eq!(BASE64.encode(sealed), ciphertext); + let sealed = encrypt_bytes(&key, &aad, &plaintext).unwrap(); + assert_eq!(decrypt_bytes(&key, &aad, &sealed).unwrap(), plaintext); assert!(decrypt_bytes(&key, b"wrong-aad", &encrypted).is_err()); assert!(decrypt_bytes(&[0xff; KEY_LEN], &aad, &encrypted).is_err()); } diff --git a/crates/openshell-driver-kubernetes-secrets/Cargo.toml b/crates/openshell-driver-kubernetes-secrets/Cargo.toml index 3655013ffa..c337071633 100644 --- a/crates/openshell-driver-kubernetes-secrets/Cargo.toml +++ b/crates/openshell-driver-kubernetes-secrets/Cargo.toml @@ -15,6 +15,7 @@ name = "openshell-driver-kubernetes-secrets" path = "src/main.rs" [dependencies] +openshell-crypto = { path = "../openshell-crypto", features = ["tls-kube"] } openshell-core = { path = "../openshell-core", default-features = false } clap = { workspace = true } diff --git a/crates/openshell-driver-kubernetes/Cargo.toml b/crates/openshell-driver-kubernetes/Cargo.toml index 5b498a24d8..c79f0e65e6 100644 --- a/crates/openshell-driver-kubernetes/Cargo.toml +++ b/crates/openshell-driver-kubernetes/Cargo.toml @@ -15,6 +15,7 @@ name = "openshell-driver-kubernetes" path = "src/main.rs" [dependencies] +openshell-crypto = { path = "../openshell-crypto", features = ["tls-kube"] } openshell-core = { path = "../openshell-core", default-features = false } openshell-isolation-interface = { path = "../openshell-isolation-interface" } openshell-sandbox-backend = { path = "../openshell-sandbox-backend" } diff --git a/crates/openshell-driver-vault/Cargo.toml b/crates/openshell-driver-vault/Cargo.toml index e39c5d19e2..9fc658a23f 100644 --- a/crates/openshell-driver-vault/Cargo.toml +++ b/crates/openshell-driver-vault/Cargo.toml @@ -15,6 +15,7 @@ name = "openshell-driver-vault" path = "src/main.rs" [dependencies] +openshell-crypto = { path = "../openshell-crypto" } openshell-core = { path = "../openshell-core", default-features = false } clap = { workspace = true } diff --git a/crates/openshell-driver-vault/src/lib.rs b/crates/openshell-driver-vault/src/lib.rs index 471bb4a035..e3692888ef 100644 --- a/crates/openshell-driver-vault/src/lib.rs +++ b/crates/openshell-driver-vault/src/lib.rs @@ -128,7 +128,7 @@ impl VaultCredentialDriver { pub fn from_config(config: &toml::Table) -> CoreResult { let settings = VaultDriverSettings::from_table(config)?; let timeout_secs = timeout_secs(config)?; - let _ = rustls::crypto::aws_lc_rs::default_provider().install_default(); + openshell_crypto::tls::ensure_default_provider(); let mut client_builder = reqwest::Client::builder() .timeout(Duration::from_secs(timeout_secs)) // System HTTP proxies can turn an otherwise-local plaintext request diff --git a/crates/openshell-extension-core/Cargo.toml b/crates/openshell-extension-core/Cargo.toml index babbeca295..2109922f5f 100644 --- a/crates/openshell-extension-core/Cargo.toml +++ b/crates/openshell-extension-core/Cargo.toml @@ -19,6 +19,7 @@ tonic = { workspace = true, features = ["channel", "tls-native-roots"] } tower = { workspace = true } [dev-dependencies] +openshell-crypto = { path = "../openshell-crypto" } http = { workspace = true } rcgen = { workspace = true } rustls = { workspace = true } diff --git a/crates/openshell-extension-core/src/transport.rs b/crates/openshell-extension-core/src/transport.rs index 98bbeb89df..c77399048f 100644 --- a/crates/openshell-extension-core/src/transport.rs +++ b/crates/openshell-extension-core/src/transport.rs @@ -192,7 +192,7 @@ mod tests { use std::future::{Ready, ready}; use std::task::{Context, Poll}; - use rcgen::{BasicConstraints, CertificateParams, ExtendedKeyUsagePurpose, IsCa, KeyPair}; + use rcgen::{BasicConstraints, CertificateParams, ExtendedKeyUsagePurpose, IsCa}; use tokio::net::TcpListener; use tokio_stream::wrappers::TcpListenerStream; use tonic::body::Body; @@ -292,12 +292,12 @@ mod tests { #[tokio::test] async fn custom_ca_verifies_certificate_and_hostname() { - let ca_key = KeyPair::generate().unwrap(); + let ca_key = openshell_crypto::pki::generate_keypair().unwrap(); let mut ca_params = CertificateParams::new(Vec::::new()).unwrap(); ca_params.is_ca = IsCa::Ca(BasicConstraints::Unconstrained); let ca = ca_params.self_signed(&ca_key).unwrap(); - let server_key = KeyPair::generate().unwrap(); + let server_key = openshell_crypto::pki::generate_keypair().unwrap(); let mut server_params = CertificateParams::new(vec!["localhost".to_string()]).unwrap(); server_params.extended_key_usages = vec![ExtendedKeyUsagePurpose::ServerAuth]; let server_cert = server_params.signed_by(&server_key, &ca, &ca_key).unwrap(); @@ -331,7 +331,7 @@ mod tests { Err(TransportError::Connect(_)) )); - let rogue_key = KeyPair::generate().unwrap(); + let rogue_key = openshell_crypto::pki::generate_keypair().unwrap(); let mut rogue_params = CertificateParams::new(Vec::::new()).unwrap(); rogue_params.is_ca = IsCa::Ca(BasicConstraints::Unconstrained); let rogue_ca = rogue_params.self_signed(&rogue_key).unwrap(); diff --git a/crates/openshell-sdk/Cargo.toml b/crates/openshell-sdk/Cargo.toml index 8d80beaa74..00de17108b 100644 --- a/crates/openshell-sdk/Cargo.toml +++ b/crates/openshell-sdk/Cargo.toml @@ -11,6 +11,7 @@ license.workspace = true repository.workspace = true [dependencies] +openshell-crypto = { path = "../openshell-crypto" } openshell-core = { path = "../openshell-core" } async-trait = "0.1" futures = { workspace = true } diff --git a/crates/openshell-sdk/src/oidc.rs b/crates/openshell-sdk/src/oidc.rs index c39e8300ae..0d41d94079 100644 --- a/crates/openshell-sdk/src/oidc.rs +++ b/crates/openshell-sdk/src/oidc.rs @@ -139,7 +139,7 @@ pub async fn discover(issuer: &str, insecure: bool) -> Result { /// followed; OIDC providers should not redirect on the token endpoint. /// When `insecure` is true, TLS certificate verification is disabled. pub fn http_client(insecure: bool) -> reqwest::Client { - let _ = rustls::crypto::aws_lc_rs::default_provider().install_default(); + openshell_crypto::tls::ensure_default_provider(); let mut builder = reqwest::ClientBuilder::new().redirect(reqwest::redirect::Policy::none()); if insecure { builder = builder.danger_accept_invalid_certs(true); diff --git a/crates/openshell-sdk/src/transport.rs b/crates/openshell-sdk/src/transport.rs index 84f7096c06..7e1ba71b0d 100644 --- a/crates/openshell-sdk/src/transport.rs +++ b/crates/openshell-sdk/src/transport.rs @@ -183,7 +183,7 @@ impl ServerCertVerifier for InsecureServerCertVerifier { } fn supported_verify_schemes(&self) -> Vec { - rustls::crypto::aws_lc_rs::default_provider() + openshell_crypto::tls::provider() .signature_verification_algorithms .supported_schemes() } diff --git a/crates/openshell-server/Cargo.toml b/crates/openshell-server/Cargo.toml index 54c44a7bed..cfdf7a0d75 100644 --- a/crates/openshell-server/Cargo.toml +++ b/crates/openshell-server/Cargo.toml @@ -11,6 +11,7 @@ license.workspace = true repository.workspace = true [dependencies] +openshell-crypto = { path = "../openshell-crypto", features = ["tls-hyper", "tls-kube", "tls-sqlx"] } openshell-bootstrap = { path = "../openshell-bootstrap" } openshell-core = { path = "../openshell-core", default-features = false, features = ["jwt", "oauth"] } openshell-driver-db-credstore = { path = "../openshell-driver-db-credstore" } @@ -133,7 +134,7 @@ protoc-bin-vendored = { workspace = true } # would; the feature is test-only and never reaches a release binary. openshell-providers = { path = "../openshell-providers", features = ["example-profiles"] } base64 = { workspace = true } -hyper-rustls = { version = "0.27", default-features = false, features = ["native-tokio", "http1", "tls12", "logging", "aws-lc-rs"] } +hyper-rustls = { version = "0.27", default-features = false, features = ["native-tokio", "http1", "tls12", "logging"] } rcgen = { workspace = true } rsa = { version = "0.9", features = ["pem"] } tokio-tungstenite = { workspace = true } diff --git a/crates/openshell-server/src/auth/oidc.rs b/crates/openshell-server/src/auth/oidc.rs index 002385de95..83c1f94485 100644 --- a/crates/openshell-server/src/auth/oidc.rs +++ b/crates/openshell-server/src/auth/oidc.rs @@ -14,8 +14,9 @@ use super::authenticator::Authenticator; use super::identity::{Identity, IdentityProvider}; use super::principal::{Principal, UserPrincipal}; use async_trait::async_trait; -use jsonwebtoken::{Algorithm, DecodingKey, Validation, decode, decode_header}; +use jsonwebtoken::{Algorithm, DecodingKey, Validation, decode_header}; use openshell_core::OidcConfig; +use openshell_crypto::jwt::decode; use reqwest::Client; use serde::Deserialize; use std::collections::{HashMap, HashSet}; @@ -575,7 +576,7 @@ impl JwksCache { /// Create a new JWKS cache, discovering the JWKS URI and fetching the /// initial key set. pub async fn new(config: &OidcConfig) -> Result { - let _ = rustls::crypto::aws_lc_rs::default_provider().install_default(); + openshell_crypto::tls::ensure_default_provider(); let http = Client::builder() .timeout(Duration::from_secs(10)) .redirect(reqwest::redirect::Policy::none()) @@ -1379,7 +1380,7 @@ mod tests { header.kid = Some(kid.to_owned()); let key = jsonwebtoken::EncodingKey::from_rsa_pem(TEST_RSA_KEY.private_pem.as_bytes()) .expect("load RSA signing key"); - jsonwebtoken::encode(&header, claims, &key).expect("sign RS256 token") + openshell_crypto::jwt::encode(&header, claims, &key).expect("sign RS256 token") } fn claims_for(issuer: &str, audience: &str, exp: i64) -> serde_json::Value { @@ -1494,7 +1495,7 @@ mod tests { crate::install_jsonwebtoken_crypto_provider(); let mut header = jsonwebtoken::Header::new(Algorithm::RS256); header.kid = Some(TEST_KID.to_owned()); - let token = jsonwebtoken::encode( + let token = openshell_crypto::jwt::encode( &header, &claims_for(&server.uri(), TEST_AUDIENCE, now_secs() + 3600), &jsonwebtoken::EncodingKey::from_rsa_pem(other.private_pem.as_bytes()) @@ -1577,9 +1578,10 @@ mod tests { use super::*; use base64::Engine; use base64::engine::general_purpose::URL_SAFE_NO_PAD; - use jsonwebtoken::{EncodingKey, Header, encode}; + use jsonwebtoken::{EncodingKey, Header}; use openshell_core::OidcConfig; - use rcgen::{KeyPair, PKCS_ECDSA_P256_SHA256, PKCS_ECDSA_P384_SHA384, PKCS_ED25519}; + use openshell_crypto::jwt::encode; + use rcgen::{PKCS_ECDSA_P256_SHA256, PKCS_ECDSA_P384_SHA384, PKCS_ED25519}; use rsa::traits::PublicKeyParts; use std::time::{SystemTime, UNIX_EPOCH}; use wiremock::matchers::{method, path}; @@ -1684,12 +1686,12 @@ mod tests { fn ec_test_key(kid: &str, curve: &str) -> TestSigningKey { let (key_pair, algorithm, coord_len) = match curve { "P-256" => ( - KeyPair::generate_for(&PKCS_ECDSA_P256_SHA256).unwrap(), + openshell_crypto::pki::generate_keypair_for(&PKCS_ECDSA_P256_SHA256).unwrap(), Algorithm::ES256, 32, ), "P-384" => ( - KeyPair::generate_for(&PKCS_ECDSA_P384_SHA384).unwrap(), + openshell_crypto::pki::generate_keypair_for(&PKCS_ECDSA_P384_SHA384).unwrap(), Algorithm::ES384, 48, ), @@ -1715,7 +1717,7 @@ mod tests { } fn ed25519_test_key(kid: &str) -> TestSigningKey { - let key_pair = KeyPair::generate_for(&PKCS_ED25519).unwrap(); + let key_pair = openshell_crypto::pki::generate_keypair_for(&PKCS_ED25519).unwrap(); let encoding_key = EncodingKey::from_ed_pem(key_pair.serialize_pem().as_bytes()).unwrap(); let spki = key_pair.public_key_der(); diff --git a/crates/openshell-server/src/auth/sandbox_jwt.rs b/crates/openshell-server/src/auth/sandbox_jwt.rs index 8593c01b33..eb472e9faf 100644 --- a/crates/openshell-server/src/auth/sandbox_jwt.rs +++ b/crates/openshell-server/src/auth/sandbox_jwt.rs @@ -19,9 +19,8 @@ use super::authenticator::Authenticator; use super::principal::{Principal, SandboxIdentitySource, SandboxPrincipal}; use async_trait::async_trait; use base64::{Engine as _, engine::general_purpose::URL_SAFE_NO_PAD}; -use jsonwebtoken::{ - Algorithm, DecodingKey, EncodingKey, Header, Validation, decode, decode_header, encode, -}; +use jsonwebtoken::{Algorithm, DecodingKey, EncodingKey, Header, Validation, decode_header}; +use openshell_crypto::jwt::{decode, encode}; pub use openshell_extension_core::{ EXTENSION_JWT_TYP, ExtensionAudience, ExtensionCallerKind, ExtensionJwtClaims, MAX_EXTENSION_TOKEN_TTL, diff --git a/crates/openshell-server/src/grpc/provider.rs b/crates/openshell-server/src/grpc/provider.rs index a2563babeb..83fb156144 100644 --- a/crates/openshell-server/src/grpc/provider.rs +++ b/crates/openshell-server/src/grpc/provider.rs @@ -2405,7 +2405,7 @@ const MAX_INTERMEDIATE_TOKEN_CACHE_ENTRIES: usize = 1024; static TOKEN_EXCHANGE_HTTP_CLIENT: LazyLock> = LazyLock::new(|| { - let _ = rustls::crypto::aws_lc_rs::default_provider().install_default(); + openshell_crypto::tls::ensure_default_provider(); reqwest::Client::builder() .timeout(std::time::Duration::from_secs(30)) .connect_timeout(std::time::Duration::from_secs(30)) diff --git a/crates/openshell-server/src/lib.rs b/crates/openshell-server/src/lib.rs index a8cd09acca..66a4613bbc 100644 --- a/crates/openshell-server/src/lib.rs +++ b/crates/openshell-server/src/lib.rs @@ -80,7 +80,7 @@ pub(crate) static TEST_ENV_LOCK: LazyLock> = LazyLock::new(|| Mutex::n pub(crate) static TEST_TRACING_LOCK: LazyLock> = LazyLock::new(|| Mutex::new(())); pub(crate) fn install_jsonwebtoken_crypto_provider() { - let _ = jsonwebtoken::crypto::aws_lc::DEFAULT_PROVIDER.install_default(); + openshell_crypto::install_jwt_provider(); } use compute::ComputeRuntime; diff --git a/crates/openshell-server/src/provider_refresh.rs b/crates/openshell-server/src/provider_refresh.rs index 6d666fbd56..88d53e56de 100644 --- a/crates/openshell-server/src/provider_refresh.rs +++ b/crates/openshell-server/src/provider_refresh.rs @@ -1614,7 +1614,7 @@ async fn request_token( } } - let _ = rustls::crypto::aws_lc_rs::default_provider().install_default(); + openshell_crypto::tls::ensure_default_provider(); let client = reqwest::Client::builder() .timeout(Duration::from_secs(30)) .build() @@ -2536,7 +2536,7 @@ mod tests { .mount(&mock_server) .await; - let _ = rustls::crypto::aws_lc_rs::default_provider().install_default(); + openshell_crypto::tls::ensure_default_provider(); let response = reqwest::get(format!("{}/oversized", mock_server.uri())) .await .unwrap(); diff --git a/crates/openshell-server/src/tls.rs b/crates/openshell-server/src/tls.rs index 8ce64e3f25..f95621de48 100644 --- a/crates/openshell-server/src/tls.rs +++ b/crates/openshell-server/src/tls.rs @@ -18,7 +18,6 @@ use openshell_ocsf::{ ConfigStateChangeBuilder, EventContext, OCSF_TARGET, SeverityId, StateId, StatusId, }; use rustls::ServerConfig; -use rustls::crypto::aws_lc_rs::sign; use rustls::pki_types::{CertificateDer, PrivateKeyDer}; use rustls::server::{ClientHello, ResolvesServerCert, WebPkiClientVerifier}; use rustls::sign::CertifiedKey; @@ -324,7 +323,7 @@ impl std::fmt::Debug for DualCertResolver { fn load_certified_key(cert_path: &Path, key_path: &Path) -> Result> { let certs = load_certs(cert_path)?; let key = load_key(key_path)?; - let signing_key = sign::any_supported_type(&key) + let signing_key = openshell_crypto::tls::any_supported_signing_key(&key) .map_err(|e| Error::tls(format!("unsupported private key type: {e}")))?; Ok(Arc::new(CertifiedKey::new(certs, signing_key))) } @@ -387,7 +386,7 @@ fn build_server_config( // Validate the key type early — rustls defers this to handshake time, // which produces a cryptic error. A bad key type surfaces clearly here. - sign::any_supported_type(&key) + openshell_crypto::tls::any_supported_signing_key(&key) .map_err(|e| Error::tls(format!("unsupported private key type: {e}")))?; let resolver = build_cert_resolver( @@ -505,7 +504,8 @@ mod tests { fn generate_server_cert(ca_cert: &rcgen::Certificate, ca_key: &KeyPair, dir: &Path) { let server_params = CertificateParams::new(vec!["localhost".to_string()]) .expect("failed to create server params"); - let server_key = KeyPair::generate().expect("failed to generate server key"); + let server_key = + openshell_crypto::pki::generate_keypair().expect("failed to generate server key"); let server_cert = server_params .signed_by(&server_key, ca_cert, ca_key) .expect("failed to sign server cert"); @@ -918,7 +918,8 @@ mod tests { new_ca_params .distinguished_name .push(rcgen::DnType::CommonName, "new-ca"); - let new_ca_key = KeyPair::generate().expect("failed to generate new CA key"); + let new_ca_key = + openshell_crypto::pki::generate_keypair().expect("failed to generate new CA key"); let new_ca_cert = new_ca_params .self_signed(&new_ca_key) .expect("failed to sign new CA cert"); @@ -932,7 +933,8 @@ mod tests { .expect("reload with new CA should succeed"); // Generate client cert signed by new CA, write to files - let client_key = KeyPair::generate().expect("failed to generate client key"); + let client_key = + openshell_crypto::pki::generate_keypair().expect("failed to generate client key"); let mut client_params = CertificateParams::new(Vec::::new()).expect("failed to create client params"); client_params @@ -999,7 +1001,8 @@ mod tests { // Verify old CA is no longer trusted: a client cert signed by the // initial CA should be rejected after rotation. - let old_client_key = KeyPair::generate().expect("failed to generate old client key"); + let old_client_key = + openshell_crypto::pki::generate_keypair().expect("failed to generate old client key"); let mut old_client_params = CertificateParams::new(Vec::::new()) .expect("failed to create old client params"); old_client_params @@ -1074,7 +1077,7 @@ mod tests { ) { let params = CertificateParams::new(vec![san.to_string()]).expect("failed to create cert params"); - let key = KeyPair::generate().expect("failed to generate key"); + let key = openshell_crypto::pki::generate_keypair().expect("failed to generate key"); let cert = params .signed_by(&key, ca_cert, ca_key) .expect("failed to sign cert"); diff --git a/crates/openshell-server/src/tls_test_utils.rs b/crates/openshell-server/src/tls_test_utils.rs index bcb71b0b54..89acf4efa4 100644 --- a/crates/openshell-server/src/tls_test_utils.rs +++ b/crates/openshell-server/src/tls_test_utils.rs @@ -34,14 +34,15 @@ pub fn generate_test_certs_with_ca(dir: &Path) -> (rcgen::Certificate, KeyPair) ca_params .distinguished_name .push(rcgen::DnType::CommonName, "test-ca"); - let ca_key = KeyPair::generate().expect("failed to generate CA key"); + let ca_key = openshell_crypto::pki::generate_keypair().expect("failed to generate CA key"); let ca_cert = ca_params .self_signed(&ca_key) .expect("failed to sign CA cert"); let server_params = CertificateParams::new(vec!["localhost".to_string()]) .expect("failed to create server params"); - let server_key = KeyPair::generate().expect("failed to generate server key"); + let server_key = + openshell_crypto::pki::generate_keypair().expect("failed to generate server key"); let server_cert = server_params .signed_by(&server_key, &ca_cert, &ca_key) .expect("failed to sign server cert"); diff --git a/crates/openshell-server/tests/common/mod.rs b/crates/openshell-server/tests/common/mod.rs index 64e2762e2a..9882342165 100644 --- a/crates/openshell-server/tests/common/mod.rs +++ b/crates/openshell-server/tests/common/mod.rs @@ -30,7 +30,7 @@ use openshell_core::proto::{ open_shell_server::{OpenShell, OpenShellServer}, }; use openshell_server::{MultiplexedService, Store, TlsAcceptor, health_router}; -use rcgen::{CertificateParams, IsCa, KeyPair}; +use rcgen::{CertificateParams, IsCa}; use rustls::RootCertStore; use rustls::pki_types::CertificateDer; use rustls_pemfile::certs; @@ -668,7 +668,7 @@ pub fn generate_pki() -> (tempfile::TempDir, PkiBundle) { ca_params .distinguished_name .push(rcgen::DnType::CommonName, "test-ca"); - let ca_key = KeyPair::generate().expect("failed to generate CA key"); + let ca_key = openshell_crypto::pki::generate_keypair().expect("failed to generate CA key"); let ca_cert = ca_params .self_signed(&ca_key) .expect("failed to sign CA cert"); @@ -676,7 +676,8 @@ pub fn generate_pki() -> (tempfile::TempDir, PkiBundle) { // Generate server cert signed by CA let server_params = CertificateParams::new(vec!["localhost".to_string()]) .expect("failed to create server params"); - let server_key = KeyPair::generate().expect("failed to generate server key"); + let server_key = + openshell_crypto::pki::generate_keypair().expect("failed to generate server key"); let server_cert = server_params .signed_by(&server_key, &ca_cert, &ca_key) .expect("failed to sign server cert"); @@ -687,7 +688,8 @@ pub fn generate_pki() -> (tempfile::TempDir, PkiBundle) { client_params .distinguished_name .push(rcgen::DnType::CommonName, "test-client"); - let client_key = KeyPair::generate().expect("failed to generate client key"); + let client_key = + openshell_crypto::pki::generate_keypair().expect("failed to generate client key"); let client_cert = client_params .signed_by(&client_key, &ca_cert, &ca_key) .expect("failed to sign client cert"); @@ -766,7 +768,8 @@ pub fn generate_rogue_pki() -> RoguePkiBundle { rogue_ca_params .distinguished_name .push(rcgen::DnType::CommonName, "rogue-ca"); - let rogue_ca_key = KeyPair::generate().expect("failed to generate rogue CA key"); + let rogue_ca_key = + openshell_crypto::pki::generate_keypair().expect("failed to generate rogue CA key"); let rogue_ca_cert = rogue_ca_params .self_signed(&rogue_ca_key) .expect("failed to sign rogue CA cert"); @@ -776,7 +779,8 @@ pub fn generate_rogue_pki() -> RoguePkiBundle { rogue_client_params .distinguished_name .push(rcgen::DnType::CommonName, "rogue-client"); - let rogue_client_key = KeyPair::generate().expect("failed to generate rogue client key"); + let rogue_client_key = + openshell_crypto::pki::generate_keypair().expect("failed to generate rogue client key"); let rogue_client_cert = rogue_client_params .signed_by(&rogue_client_key, &rogue_ca_cert, &rogue_ca_key) .expect("failed to sign rogue client cert"); diff --git a/crates/openshell-supervisor-network/Cargo.toml b/crates/openshell-supervisor-network/Cargo.toml index d4aa9d1ee9..4b83b4cb63 100644 --- a/crates/openshell-supervisor-network/Cargo.toml +++ b/crates/openshell-supervisor-network/Cargo.toml @@ -12,6 +12,7 @@ rust-version.workspace = true [dependencies] openshell-binary-identity = { path = "../openshell-binary-identity" } +openshell-crypto = { path = "../openshell-crypto" } openshell-core = { path = "../openshell-core", features = ["oauth"] } openshell-isolation-interface = { path = "../openshell-isolation-interface" } openshell-ocsf = { path = "../openshell-ocsf" } diff --git a/crates/openshell-supervisor-network/src/l7/tls.rs b/crates/openshell-supervisor-network/src/l7/tls.rs index d106eb2060..9800162cb1 100644 --- a/crates/openshell-supervisor-network/src/l7/tls.rs +++ b/crates/openshell-supervisor-network/src/l7/tls.rs @@ -40,7 +40,7 @@ pub struct SandboxCa { impl SandboxCa { /// Generate a new ephemeral CA keypair. pub fn generate() -> Result { - let ca_key = KeyPair::generate().into_diagnostic()?; + let ca_key = openshell_crypto::pki::generate_keypair().into_diagnostic()?; let mut params = CertificateParams::default(); params.is_ca = IsCa::Ca(rcgen::BasicConstraints::Unconstrained); @@ -52,7 +52,7 @@ impl SandboxCa { .push(DnType::OrganizationName, "OpenShell"); params.key_usages = vec![KeyUsagePurpose::KeyCertSign, KeyUsagePurpose::CrlSign]; - let ca_cert = params.self_signed(&ca_key).into_diagnostic()?; + let ca_cert = openshell_crypto::pki::self_signed(params, &ca_key).into_diagnostic()?; let ca_cert_pem = ca_cert.pem(); Ok(Self { @@ -182,15 +182,15 @@ impl CertCache { /// Generate a new leaf certificate for the given hostname. fn generate_leaf(&self, hostname: &str) -> Result { - let leaf_key = KeyPair::generate().into_diagnostic()?; + let leaf_key = openshell_crypto::pki::generate_keypair().into_diagnostic()?; let mut params = CertificateParams::new(vec![hostname.to_string()]).into_diagnostic()?; params.distinguished_name.push(DnType::CommonName, hostname); params.use_authority_key_identifier_extension = true; - let leaf_cert = params - .signed_by(&leaf_key, &self.ca.ca_cert, &self.ca.ca_key) - .into_diagnostic()?; + let leaf_cert = + openshell_crypto::pki::signed_by(params, &leaf_key, &self.ca.ca_cert, &self.ca.ca_key) + .into_diagnostic()?; let leaf_der = CertificateDer::from(leaf_cert.der().to_vec()); let ca_der = CertificateDer::from(self.ca.ca_cert.der().to_vec()); diff --git a/crates/openshell-supervisor-network/src/token_grant.rs b/crates/openshell-supervisor-network/src/token_grant.rs index 5d03012f61..573224fccc 100644 --- a/crates/openshell-supervisor-network/src/token_grant.rs +++ b/crates/openshell-supervisor-network/src/token_grant.rs @@ -49,7 +49,7 @@ use spiffe::WorkloadApiClient; /// Token cache shared across all provider token grants. static TOKEN_CACHE: LazyLock = LazyLock::new(TokenCache::new); static TOKEN_GRANT_HTTP_CLIENT: LazyLock = LazyLock::new(|| { - let _ = rustls::crypto::aws_lc_rs::default_provider().install_default(); + openshell_crypto::tls::ensure_default_provider(); reqwest::Client::builder() .timeout(Duration::from_secs(30)) .connect_timeout(Duration::from_secs(30)) diff --git a/crates/openshell-supervisor-network/src/upstream_proxy.rs b/crates/openshell-supervisor-network/src/upstream_proxy.rs index ab5ccafece..c819a07ba2 100644 --- a/crates/openshell-supervisor-network/src/upstream_proxy.rs +++ b/crates/openshell-supervisor-network/src/upstream_proxy.rs @@ -2258,8 +2258,8 @@ mod tests { async fn fake_tls_proxy( tls_identity: &str, ) -> (SocketAddr, tokio::task::JoinHandle, String) { - let _ = rustls::crypto::aws_lc_rs::default_provider().install_default(); - let key = rcgen::KeyPair::generate().unwrap(); + openshell_crypto::tls::ensure_default_provider(); + let key = openshell_crypto::pki::generate_keypair().unwrap(); let cert = rcgen::CertificateParams::new(vec![tls_identity.to_string()]) .unwrap() .self_signed(&key) diff --git a/e2e/rust/Cargo.lock b/e2e/rust/Cargo.lock index c5235dff8b..c8088f185b 100644 --- a/e2e/rust/Cargo.lock +++ b/e2e/rust/Cargo.lock @@ -38,7 +38,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b281d307588d634de920874890732659e2e7672f72b5e10e81badc1a8a83621e" dependencies = [ "aws-lc-sys", - "untrusted", + "untrusted 0.7.1", "zeroize", ] @@ -278,7 +278,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys", + "windows-sys 0.61.2", ] [[package]] @@ -814,7 +814,7 @@ checksum = "30d65c71f1ce40ab09135ce117d742b9f8a19ff91a41a8b57ed50bc2de59c427" dependencies = [ "libc", "wasi", - "windows-sys", + "windows-sys 0.61.2", ] [[package]] @@ -885,6 +885,18 @@ version = "1.21.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" +[[package]] +name = "openshell-crypto" +version = "0.0.0" +dependencies = [ + "aws-lc-rs", + "jsonwebtoken", + "rcgen", + "rustls", + "serde", + "thiserror", +] + [[package]] name = "openshell-e2e" version = "0.1.0" @@ -900,6 +912,7 @@ dependencies = [ "jsonwebtoken", "nix", "noyalib", + "openshell-crypto", "prost", "rand", "serde", @@ -1102,6 +1115,19 @@ dependencies = [ "getrandom 0.3.4", ] +[[package]] +name = "rcgen" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75e669e5202259b5314d1ea5397316ad400819437857b90861765f24c4cf80a2" +dependencies = [ + "aws-lc-rs", + "pem", + "rustls-pki-types", + "time", + "yasna", +] + [[package]] name = "redox_syscall" version = "0.5.18" @@ -1111,6 +1137,20 @@ dependencies = [ "bitflags", ] +[[package]] +name = "ring" +version = "0.17.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" +dependencies = [ + "cc", + "cfg-if", + "getrandom 0.2.17", + "libc", + "untrusted 0.9.0", + "windows-sys 0.52.0", +] + [[package]] name = "rustc-hash" version = "2.1.3" @@ -1127,7 +1167,43 @@ dependencies = [ "errno", "libc", "linux-raw-sys", - "windows-sys", + "windows-sys 0.61.2", +] + +[[package]] +name = "rustls" +version = "0.23.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c54fcab019b409d04215d3a17cb438fd7fbf192ee61461f20f4fe18704bc138" +dependencies = [ + "aws-lc-rs", + "log", + "once_cell", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-pki-types" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "764899a24af3980067ee14bc143654f297b22eaebfe3c7b6b211920a5a59b046" +dependencies = [ + "zeroize", +] + +[[package]] +name = "rustls-webpki" +version = "0.103.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61c429a8649f110dddef65e2a5ad240f747e85f7758a6bccc7e5777bd33f756e" +dependencies = [ + "aws-lc-rs", + "ring", + "rustls-pki-types", + "untrusted 0.9.0", ] [[package]] @@ -1317,7 +1393,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3d1e2c7f27f8d4cb10542a02c49005dbd6e93095799d6f3be745fae9f8fedd4" dependencies = [ "libc", - "windows-sys", + "windows-sys 0.61.2", ] [[package]] @@ -1326,6 +1402,12 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + [[package]] name = "syn" version = "2.0.119" @@ -1375,7 +1457,7 @@ dependencies = [ "getrandom 0.4.3", "once_cell", "rustix", - "windows-sys", + "windows-sys 0.61.2", ] [[package]] @@ -1452,7 +1534,7 @@ dependencies = [ "signal-hook-registry", "socket2", "tokio-macros", - "windows-sys", + "windows-sys 0.61.2", ] [[package]] @@ -1617,6 +1699,12 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + [[package]] name = "url" version = "2.5.8" @@ -1738,6 +1826,15 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + [[package]] name = "windows-sys" version = "0.61.2" @@ -1747,6 +1844,70 @@ dependencies = [ "windows-link", ] +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + [[package]] name = "wit-bindgen" version = "0.57.1" @@ -1759,6 +1920,15 @@ version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4" +[[package]] +name = "yasna" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e17bb3549cc1321ae1296b9cdc2698e2b6cb1992adfa19a8c72e5b7a738f44cd" +dependencies = [ + "time", +] + [[package]] name = "yoke" version = "0.8.3" diff --git a/e2e/rust/Cargo.toml b/e2e/rust/Cargo.toml index 333acd0fec..c41a69f78a 100644 --- a/e2e/rust/Cargo.toml +++ b/e2e/rust/Cargo.toml @@ -11,7 +11,7 @@ name = "openshell-e2e" description = "End-to-end tests for the OpenShell CLI" version = "0.1.0" edition = "2024" -rust-version = "1.90" +rust-version = "1.94" license = "Apache-2.0" publish = false @@ -208,6 +208,7 @@ path = "tests/gpu.rs" required-features = ["e2e-gpu"] [dependencies] +openshell-crypto = { path = "../../crates/openshell-crypto" } base64 = "0.22" bollard = "0.20" bytes = "1" @@ -215,7 +216,7 @@ futures-util = "0.3" http-body-util = "0.1" hyper = { version = "1", features = ["client", "http1"] } hyper-util = { version = "0.1", features = ["tokio"] } -jsonwebtoken = { version = "10", features = ["aws_lc_rs"] } +jsonwebtoken = "10" prost = "0.14" tokio = { version = "1.43", features = ["full"] } tokio-stream = { version = "0.1", features = ["net"] } diff --git a/e2e/rust/src/harness/container.rs b/e2e/rust/src/harness/container.rs index 5e23a70ff9..b109d72fb4 100644 --- a/e2e/rust/src/harness/container.rs +++ b/e2e/rust/src/harness/container.rs @@ -244,7 +244,7 @@ impl ContainerHttpServer { async fn wait_until_ready(&self) -> Result<(), String> { let container_id = self.container_id.clone(); let engine = self.engine.clone(); - timeout(Duration::from_secs(60), async move { + timeout(Duration::from_mins(1), async move { let mut tick = interval(Duration::from_millis(500)); loop { tick.tick().await; @@ -407,7 +407,7 @@ impl HostSupportContainer { } async fn wait_until_listening(&self, container_port: u16) -> Result<(), String> { - let deadline = timeout(Duration::from_secs(60), async { + let deadline = timeout(Duration::from_mins(1), async { let mut tick = interval(Duration::from_millis(500)); loop { tick.tick().await; @@ -528,7 +528,7 @@ impl SupportContainer { let probe = format!( "import socket; socket.create_connection(('127.0.0.1', {port}), timeout=1).close()" ); - let deadline = timeout(Duration::from_secs(60), async { + let deadline = timeout(Duration::from_mins(1), async { let mut tick = interval(Duration::from_millis(500)); loop { tick.tick().await; diff --git a/e2e/rust/src/harness/host_process.rs b/e2e/rust/src/harness/host_process.rs index 9e086e4718..36911fcd91 100644 --- a/e2e/rust/src/harness/host_process.rs +++ b/e2e/rust/src/harness/host_process.rs @@ -65,7 +65,7 @@ impl HostPythonFixture { }; // Bind to 127.0.0.1 for the readiness probe even though the fixture // listens on 0.0.0.0; the host supervisor dials it over loopback. - wait_for_port("127.0.0.1", port, Duration::from_secs(60)) + wait_for_port("127.0.0.1", port, Duration::from_mins(1)) .await .map_err(|err| { format!( diff --git a/e2e/rust/src/harness/sandbox.rs b/e2e/rust/src/harness/sandbox.rs index e0a1f35898..b731952da1 100644 --- a/e2e/rust/src/harness/sandbox.rs +++ b/e2e/rust/src/harness/sandbox.rs @@ -30,7 +30,7 @@ fn extract_sandbox_name(output: &str) -> Option { /// from the content store on every boot (~250s for the 1GB sandbox /// base image), so 600s accommodates extraction + workspace-init + pod /// startup. -const SANDBOX_READY_TIMEOUT: Duration = Duration::from_secs(600); +const SANDBOX_READY_TIMEOUT: Duration = Duration::from_mins(10); static NEXT_SANDBOX_NAME: AtomicU64 = AtomicU64::new(1); diff --git a/e2e/rust/tests/gateway_start.rs b/e2e/rust/tests/gateway_start.rs index 31ffabb003..2bd9c0c738 100644 --- a/e2e/rust/tests/gateway_start.rs +++ b/e2e/rust/tests/gateway_start.rs @@ -162,7 +162,7 @@ async fn docker_gateway_restart_preserves_running_and_stopped_intent() { "sandbox state was not written before restart:\n{before_restart}" ); - wait_for_container_running(&namespace, &sandbox.name, true, Duration::from_secs(60)) + wait_for_container_running(&namespace, &sandbox.name, true, Duration::from_mins(1)) .await .expect("sandbox container should be running before gateway restart"); @@ -191,13 +191,13 @@ async fn docker_gateway_restart_preserves_running_and_stopped_intent() { .expect("gateway shutdown should stop a running-intent Docker sandbox"); gateway.start().expect("restart e2e gateway"); - wait_for_healthy(Duration::from_secs(120)) + wait_for_healthy(Duration::from_mins(2)) .await .expect("gateway should become healthy after restart"); - wait_for_container_running(&namespace, &sandbox.name, true, Duration::from_secs(120)) + wait_for_container_running(&namespace, &sandbox.name, true, Duration::from_mins(2)) .await .expect("gateway startup should restart the running-intent Docker sandbox container"); - wait_for_sandbox_phase(&stopped_sandbox.name, "Stopped", Duration::from_secs(120)) + wait_for_sandbox_phase(&stopped_sandbox.name, "Stopped", Duration::from_mins(2)) .await .expect("explicitly stopped Docker sandbox should remain stopped after restart"); wait_for_container_running( @@ -220,7 +220,7 @@ async fn docker_gateway_restart_preserves_running_and_stopped_intent() { &sandbox.name, &["cat", START_FILE], "before-restart", - Duration::from_secs(240), + Duration::from_mins(4), ) .await .expect("sandbox should become ready again with its state preserved"); diff --git a/e2e/rust/tests/gpu/device_selection.rs b/e2e/rust/tests/gpu/device_selection.rs index 56f0019d49..1842b516cf 100644 --- a/e2e/rust/tests/gpu/device_selection.rs +++ b/e2e/rust/tests/gpu/device_selection.rs @@ -16,7 +16,7 @@ use serde_json::{Map, Value}; use serial_test::serial; use tokio::time::timeout; -const SANDBOX_CREATE_TIMEOUT: Duration = Duration::from_secs(600); +const SANDBOX_CREATE_TIMEOUT: Duration = Duration::from_mins(10); const CDI_GPU_DEVICE_ALL: &str = "nvidia.com/gpu=all"; const CDI_GPU_DEVICE_PREFIX: &str = "nvidia.com/gpu="; const GPU_PROBE_IMAGE_ENV: &str = "OPENSHELL_E2E_GPU_PROBE_IMAGE"; diff --git a/e2e/rust/tests/gpu/workloads.rs b/e2e/rust/tests/gpu/workloads.rs index 312a05b437..be24979531 100644 --- a/e2e/rust/tests/gpu/workloads.rs +++ b/e2e/rust/tests/gpu/workloads.rs @@ -17,8 +17,8 @@ use tokio::time::timeout; const WORKLOAD_MANIFEST_ENV: &str = "OPENSHELL_E2E_WORKLOAD_MANIFEST"; const GPU_WORKLOAD_SUCCESS_MARKER: &str = "OPENSHELL_GPU_WORKLOAD_SUCCESS"; const GPU_WORKLOAD_FAILURE_MARKER: &str = "OPENSHELL_GPU_WORKLOAD_FAILURE"; -const WORKLOAD_SANDBOX_CREATE_TIMEOUT: Duration = Duration::from_secs(600); -const WORKLOAD_PHASE_TIMEOUT: Duration = Duration::from_secs(60); +const WORKLOAD_SANDBOX_CREATE_TIMEOUT: Duration = Duration::from_mins(10); +const WORKLOAD_PHASE_TIMEOUT: Duration = Duration::from_mins(1); #[derive(Debug, Deserialize)] struct WorkloadManifest { diff --git a/e2e/rust/tests/local_driver_token_restart.rs b/e2e/rust/tests/local_driver_token_restart.rs index 5c9661d89c..274760d6c0 100644 --- a/e2e/rust/tests/local_driver_token_restart.rs +++ b/e2e/rust/tests/local_driver_token_restart.rs @@ -295,7 +295,7 @@ async fn stop_container_sandbox( } run_engine(engine, &["stop".to_string(), container_id.clone()])?; - wait_for_container_running(engine, &container_id, false, Duration::from_secs(60)).await + wait_for_container_running(engine, &container_id, false, Duration::from_mins(1)).await } async fn wait_for_sandbox_error(sandbox_name: &str, timeout: Duration) -> Result<(), String> { @@ -331,7 +331,7 @@ async fn restart_vm_sandbox(gateway: &ManagedGateway, sandbox_name: &str) -> Res gateway.stop()?; gateway.start()?; - wait_for_healthy(Duration::from_secs(120)).await + wait_for_healthy(Duration::from_mins(2)).await } async fn wait_for_driver_reconnect(driver: LocalDriver, sandbox_name: &str) -> Result<(), String> { @@ -341,7 +341,7 @@ async fn wait_for_driver_reconnect(driver: LocalDriver, sandbox_name: &str) -> R sandbox_name, &["cat", RESTART_FILE], "before-local-driver-restart", - Duration::from_secs(240), + Duration::from_mins(4), ) .await } @@ -350,7 +350,7 @@ async fn wait_for_driver_reconnect(driver: LocalDriver, sandbox_name: &str) -> R sandbox_name, &["echo", "vm-reconnect-ok"], "vm-reconnect-ok", - Duration::from_secs(240), + Duration::from_mins(4), ) .await } diff --git a/e2e/rust/tests/podman_corporate_proxy.rs b/e2e/rust/tests/podman_corporate_proxy.rs index ef1a08f0b4..9864b5d47a 100644 --- a/e2e/rust/tests/podman_corporate_proxy.rs +++ b/e2e/rust/tests/podman_corporate_proxy.rs @@ -547,7 +547,7 @@ async fn restart_gateway() -> Result<(), String> { .ok_or_else(|| "managed gateway metadata disappeared".to_string())?; gateway.stop()?; gateway.start()?; - wait_for_healthy(Duration::from_secs(120)).await + wait_for_healthy(Duration::from_mins(2)).await } /// Names of the per-sandbox corporate proxy credential secrets. @@ -759,7 +759,7 @@ async fn podman_corporate_proxy_routes_approved_tls_egress() { sandbox.cleanup().await; - wait_for_secret_removal(&sandbox_secret, Duration::from_secs(60)) + wait_for_secret_removal(&sandbox_secret, Duration::from_mins(1)) .await .expect("sandbox deletion should remove the proxy-auth secret"); diff --git a/e2e/rust/tests/podman_gateway_start.rs b/e2e/rust/tests/podman_gateway_start.rs index 7e159ffa78..e53d0098ae 100644 --- a/e2e/rust/tests/podman_gateway_start.rs +++ b/e2e/rust/tests/podman_gateway_start.rs @@ -145,7 +145,7 @@ async fn podman_gateway_restart_preserves_running_and_stopped_intent() { let mut sandbox = SandboxGuard::create_keep(&["sh", "-lc", &script], READY_MARKER) .await .expect("create long-running Podman sandbox"); - wait_for_container_running(&sandbox.name, true, Duration::from_secs(60)) + wait_for_container_running(&sandbox.name, true, Duration::from_mins(1)) .await .expect("Podman sandbox container should initially be running"); @@ -165,19 +165,19 @@ async fn podman_gateway_restart_preserves_running_and_stopped_intent() { .expect("create Podman sandbox that will remain stopped"); let (stop_output, stop_code) = run_cli(&["sandbox", "stop", &stopped_sandbox.name]).await; assert_eq!(stop_code, 0, "sandbox stop should succeed:\n{stop_output}"); - wait_for_sandbox_phase(&stopped_sandbox.name, "Stopped", Duration::from_secs(120)) + wait_for_sandbox_phase(&stopped_sandbox.name, "Stopped", Duration::from_mins(2)) .await .expect("Podman sandbox should be stopped before gateway restart"); gateway.stop().expect("stop e2e gateway"); - wait_for_container_running(&sandbox.name, false, Duration::from_secs(60)) + wait_for_container_running(&sandbox.name, false, Duration::from_mins(1)) .await .expect("gateway shutdown should stop the running-intent Podman sandbox"); gateway.start().expect("restart e2e gateway"); - wait_for_healthy(Duration::from_secs(120)) + wait_for_healthy(Duration::from_mins(2)) .await .expect("gateway should become healthy after restart"); - wait_for_container_running(&sandbox.name, true, Duration::from_secs(120)) + wait_for_container_running(&sandbox.name, true, Duration::from_mins(2)) .await .expect("gateway startup should restart the running-intent Podman sandbox"); @@ -187,7 +187,7 @@ async fn podman_gateway_restart_preserves_running_and_stopped_intent() { "sandbox '{}' should still be listed after gateway restart. Names: {names:?}", sandbox.name ); - wait_for_sandbox_phase(&stopped_sandbox.name, "Stopped", Duration::from_secs(120)) + wait_for_sandbox_phase(&stopped_sandbox.name, "Stopped", Duration::from_mins(2)) .await .expect("explicitly stopped Podman sandbox should remain stopped after restart"); @@ -195,7 +195,7 @@ async fn podman_gateway_restart_preserves_running_and_stopped_intent() { &sandbox.name, &["cat", START_FILE], "before-restart", - Duration::from_secs(240), + Duration::from_mins(4), ) .await .expect("Podman sandbox should become ready again with its state preserved"); diff --git a/e2e/rust/tests/podman_userns.rs b/e2e/rust/tests/podman_userns.rs index 0e01aee818..8bfd7c46dc 100644 --- a/e2e/rust/tests/podman_userns.rs +++ b/e2e/rust/tests/podman_userns.rs @@ -139,7 +139,7 @@ async fn restart_gateway() -> Result<(), String> { .ok_or_else(|| "managed gateway metadata disappeared".to_string())?; gateway.stop()?; gateway.start()?; - wait_for_healthy(Duration::from_secs(120)).await + wait_for_healthy(Duration::from_mins(2)).await } #[tokio::test] diff --git a/e2e/rust/tests/provider_token_exchange.rs b/e2e/rust/tests/provider_token_exchange.rs index c4e06f029f..87f8403575 100644 --- a/e2e/rust/tests/provider_token_exchange.rs +++ b/e2e/rust/tests/provider_token_exchange.rs @@ -130,7 +130,7 @@ impl SpiffeWorkloadApi { "iat": now, "exp": now + 3600, }); - jsonwebtoken::encode(&header, &claims, &self.encoding_key) + openshell_crypto::jwt::encode(&header, &claims, &self.encoding_key) .map_err(|err| Status::internal(format!("sign JWT-SVID: {err}"))) } } diff --git a/e2e/rust/tests/vm_corporate_proxy.rs b/e2e/rust/tests/vm_corporate_proxy.rs index 1e34e71d0d..259079b0bc 100644 --- a/e2e/rust/tests/vm_corporate_proxy.rs +++ b/e2e/rust/tests/vm_corporate_proxy.rs @@ -555,7 +555,7 @@ impl GatewayProxyConfig { let _ = writeln!(extra, "no_proxy = \"{no_proxy}\""); } let guard = Self::apply_raw(&extra)?; - wait_for_healthy(Duration::from_secs(120)).await?; + wait_for_healthy(Duration::from_mins(2)).await?; Ok(guard) } @@ -574,7 +574,7 @@ impl GatewayProxyConfig { .ok_or_else(|| "managed gateway metadata disappeared".to_string())?; gateway.stop()?; gateway.start()?; - wait_for_healthy(Duration::from_secs(120)).await?; + wait_for_healthy(Duration::from_mins(2)).await?; self.restored = true; Ok(()) } diff --git a/e2e/rust/tests/vm_gateway_start.rs b/e2e/rust/tests/vm_gateway_start.rs index 5a6399a0fd..9c785a46cb 100644 --- a/e2e/rust/tests/vm_gateway_start.rs +++ b/e2e/rust/tests/vm_gateway_start.rs @@ -125,19 +125,19 @@ async fn vm_gateway_restart_preserves_running_and_stopped_intent() { .expect("create VM sandbox that will remain stopped"); let (stop_output, stop_code) = run_cli(&["sandbox", "stop", &stopped_sandbox.name]).await; assert_eq!(stop_code, 0, "sandbox stop should succeed:\n{stop_output}"); - wait_for_sandbox_phase(&stopped_sandbox.name, "Stopped", Duration::from_secs(120)) + wait_for_sandbox_phase(&stopped_sandbox.name, "Stopped", Duration::from_mins(2)) .await .expect("VM sandbox should be stopped before gateway restart"); gateway.stop().expect("stop e2e gateway"); - wait_for_vm_stopped_marker(&sandbox.name, true, Duration::from_secs(60)) + wait_for_vm_stopped_marker(&sandbox.name, true, Duration::from_mins(1)) .await .expect("gateway shutdown should stop the running-intent VM through its driver"); gateway.start().expect("restart e2e gateway"); - wait_for_healthy(Duration::from_secs(120)) + wait_for_healthy(Duration::from_mins(2)) .await .expect("gateway should become healthy after restart"); - wait_for_vm_stopped_marker(&sandbox.name, false, Duration::from_secs(120)) + wait_for_vm_stopped_marker(&sandbox.name, false, Duration::from_mins(2)) .await .expect("gateway startup should restart the running-intent VM"); @@ -147,7 +147,7 @@ async fn vm_gateway_restart_preserves_running_and_stopped_intent() { "sandbox '{}' should still be listed after gateway restart. Names: {names:?}", sandbox.name ); - wait_for_sandbox_phase(&stopped_sandbox.name, "Stopped", Duration::from_secs(120)) + wait_for_sandbox_phase(&stopped_sandbox.name, "Stopped", Duration::from_mins(2)) .await .expect("explicitly stopped VM sandbox should remain stopped after restart"); @@ -155,7 +155,7 @@ async fn vm_gateway_restart_preserves_running_and_stopped_intent() { &sandbox.name, &["cat", START_FILE], "before-restart", - Duration::from_secs(240), + Duration::from_mins(4), ) .await .expect("VM sandbox should become ready again with its overlay state preserved"); diff --git a/examples/governance-interceptor/Cargo.lock b/examples/governance-interceptor/Cargo.lock index 9aeef0fec9..0f5e5f9e4c 100644 --- a/examples/governance-interceptor/Cargo.lock +++ b/examples/governance-interceptor/Cargo.lock @@ -1066,6 +1066,7 @@ dependencies = [ "ipnet", "miette", "nix", + "openshell-crypto", "openshell-extension-core", "openshell-policy-schema", "prost", @@ -1089,6 +1090,19 @@ dependencies = [ "uuid", ] +[[package]] +name = "openshell-crypto" +version = "0.0.0" +dependencies = [ + "aws-lc-rs", + "jsonwebtoken", + "rcgen", + "rustls", + "serde", + "thiserror", + "tonic", +] + [[package]] name = "openshell-extension-core" version = "0.0.0" @@ -1108,6 +1122,7 @@ dependencies = [ "jsonwebtoken", "noyalib", "openshell-core", + "openshell-crypto", "openshell-policy", "openshell-providers", "prost", diff --git a/examples/governance-interceptor/Cargo.toml b/examples/governance-interceptor/Cargo.toml index 890ef67dc7..92fb8c4648 100644 --- a/examples/governance-interceptor/Cargo.toml +++ b/examples/governance-interceptor/Cargo.toml @@ -11,14 +11,15 @@ rust-version = "1.94" license = "Apache-2.0" [dependencies] -jsonwebtoken = { version = "10", features = ["aws_lc_rs"] } +openshell-crypto = { path = "../../crates/openshell-crypto" } +jsonwebtoken = "10" openshell-core = { path = "../../crates/openshell-core", default-features = false } openshell-policy = { path = "../../crates/openshell-policy" } openshell-providers = { path = "../../crates/openshell-providers" } prost = "0.14" prost-reflect = { version = "0.16.5", features = ["serde"] } prost-types = "0.14" -rcgen = { version = "0.13", default-features = false, features = ["crypto", "pem", "aws_lc_rs"] } +rcgen = { version = "0.13", default-features = false, features = ["crypto", "pem"] } serde = { version = "1", features = ["derive"] } serde_json = "1" serde_yml = { package = "noyalib", version = "0.0.28", default-features = false, features = ["std", "compat-serde-yaml"] } diff --git a/examples/governance-interceptor/src/main.rs b/examples/governance-interceptor/src/main.rs index 96a9942e38..1b8f291aac 100644 --- a/examples/governance-interceptor/src/main.rs +++ b/examples/governance-interceptor/src/main.rs @@ -10,9 +10,7 @@ use std::path::{Path, PathBuf}; use std::sync::{Arc, RwLock}; use std::time::{Duration, SystemTime, UNIX_EPOCH}; -use jsonwebtoken::{ - Algorithm, DecodingKey, EncodingKey, Header, Validation, decode, decode_header, encode, -}; +use jsonwebtoken::{Algorithm, DecodingKey, EncodingKey, Header, Validation, decode_header}; use openshell_core::proto::gateway_interceptor::v1::{ DescribeRequest, GatewayInterceptorPhase, InterceptorBinding, InterceptorEvaluation, InterceptorManifest, InterceptorResult, InterceptorSelector, JsonPatch, @@ -24,6 +22,7 @@ use openshell_core::proto::{ ListSandboxesRequest, ProviderProfile, Sandbox, SandboxPhase, SandboxPolicy, UpdateConfigRequest, open_shell_client::OpenShellClient, }; +use openshell_crypto::jwt::{decode, encode}; use openshell_policy::parse_sandbox_policy; use openshell_providers::{ProviderTypeProfile, normalize_profile_id}; use policy_hash::{ @@ -34,7 +33,6 @@ use prost::Message as _; use prost_types::ListValue; use prost_types::{Struct, Value as ProtoValue, value::Kind}; use proto_json::{decode_message_to_json, encode_json_to_message}; -use rcgen::{KeyPair, PKCS_ED25519}; use serde::{Deserialize, Serialize}; use serde_json::{Number, Value, json}; use sha2::{Digest, Sha256}; @@ -101,7 +99,7 @@ struct ProfileSignatureClaims { impl PolicySigner { fn generate() -> Result { - let keypair = KeyPair::generate_for(&PKCS_ED25519) + let keypair = openshell_crypto::pki::generate_jwt_keypair() .map_err(|err| format!("failed to generate policy signing key: {err}"))?; let signing_key_pem = keypair.serialize_pem(); let public_key_pem = keypair.public_key_pem(); diff --git a/examples/governance-interceptor/src/smoke_client.rs b/examples/governance-interceptor/src/smoke_client.rs index 8a73522617..d4ca7f6f48 100644 --- a/examples/governance-interceptor/src/smoke_client.rs +++ b/examples/governance-interceptor/src/smoke_client.rs @@ -3,11 +3,12 @@ //! Authenticated negative-path client for the governance example smoke suite. -use jsonwebtoken::{Algorithm, EncodingKey, Header, encode}; +use jsonwebtoken::{Algorithm, EncodingKey, Header}; use openshell_core::proto::{ GetSandboxConfigRequest, NetworkActivitySummary, PolicyChunk, SubmitPolicyAnalysisRequest, UpdateConfigRequest, open_shell_client::OpenShellClient, }; +use openshell_crypto::jwt::encode; use serde::Serialize; use tonic::Code; use tonic::metadata::AsciiMetadataValue; diff --git a/examples/supervisor-middleware-content-guard/Cargo.lock b/examples/supervisor-middleware-content-guard/Cargo.lock index 381cb63c40..29ed36eb92 100644 --- a/examples/supervisor-middleware-content-guard/Cargo.lock +++ b/examples/supervisor-middleware-content-guard/Cargo.lock @@ -82,6 +82,45 @@ version = "1.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "330a5ed07fa54e4702c9d6c4174f74427fc0ef6e214bbd677ae50a5099946470" +[[package]] +name = "asn1-rs" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5493c3bedbacf7fd7382c6346bbd66687d12bbaad3a89a2d2c303ee6cf20b048" +dependencies = [ + "asn1-rs-derive", + "asn1-rs-impl", + "displaydoc", + "nom", + "num-traits", + "rusticata-macros", + "thiserror 1.0.69", + "time", +] + +[[package]] +name = "asn1-rs-derive" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "965c2d33e53cb6b267e148a4cb0760bc01f4904c1cd4bb4002a085bb016d1490" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", + "synstructure 0.13.2", +] + +[[package]] +name = "asn1-rs-impl" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + [[package]] name = "async-trait" version = "0.1.92" @@ -99,6 +138,12 @@ version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" +[[package]] +name = "autocfg" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" + [[package]] name = "aws-lc-rs" version = "1.18.1" @@ -106,6 +151,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b281d307588d634de920874890732659e2e7672f72b5e10e81badc1a8a83621e" dependencies = [ "aws-lc-sys", + "untrusted 0.7.1", "zeroize", ] @@ -254,7 +300,7 @@ checksum = "65c35e4b699c7e15ccbe7ee35c005e4fc0a278d22238a2857e6ce2dadeda1b06" dependencies = [ "cfg-if", "cpufeatures 0.3.1", - "rand_core", + "rand_core 0.10.1", ] [[package]] @@ -378,6 +424,26 @@ version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4583a4551df46e2792f82ceeac45e850d2e2d5debba0b91f102385cda5b11f06" +[[package]] +name = "der-parser" +version = "9.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cd0a5c643689626bec213c4d8bd4d96acc8ffdb4ad4bb6bc16abf27d5f4b553" +dependencies = [ + "asn1-rs", + "displaydoc", + "nom", + "num-bigint", + "num-traits", + "rusticata-macros", +] + +[[package]] +name = "deranged" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" + [[package]] name = "digest" version = "0.10.7" @@ -541,7 +607,7 @@ dependencies = [ "cfg-if", "libc", "r-efi", - "rand_core", + "rand_core 0.10.1", ] [[package]] @@ -609,7 +675,7 @@ dependencies = [ "once_cell", "rand", "ring", - "thiserror", + "thiserror 2.0.20", "tinyvec", "tracing", "url", @@ -921,7 +987,7 @@ dependencies = [ "jni-sys", "log", "simd_cesu8", - "thiserror", + "thiserror 2.0.20", "walkdir", "windows-link", ] @@ -979,6 +1045,30 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "jsonwebtoken" +version = "10.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eba32bfb4ffdeaca3e34431072faf01745c9b26d25504aa7a6cf5684334fc4fc" +dependencies = [ + "aws-lc-rs", + "base64", + "getrandom 0.2.17", + "js-sys", + "pem", + "serde", + "serde_json", + "signature", + "simple_asn1", + "zeroize", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + [[package]] name = "libc" version = "0.2.189" @@ -1066,6 +1156,12 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + [[package]] name = "miniz_oxide" version = "0.8.9" @@ -1104,6 +1200,16 @@ dependencies = [ "libc", ] +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + [[package]] name = "noyalib" version = "0.0.28" @@ -1120,6 +1226,40 @@ dependencies = [ "smallvec", ] +[[package]] +name = "num-bigint" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c89e69e7e0f03bea5ef08013795c25018e101932225a656383bd384495ecc367" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-conv" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "521739c6d2bac4aa25192232afe6841231376b2b26d4d9fae5ecf8ca5772e441" + +[[package]] +name = "num-integer" +version = "0.1.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ce2d95d4b3734dc35aa2f45e1aa22cd416814592a4f9d9205e11affd5b8e10b" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + [[package]] name = "object" version = "0.37.3" @@ -1129,6 +1269,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "oid-registry" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8d8034d9489cdaf79228eb9f6a3b8d7bb32ba00d6645ebd48eef4077ceb5bd9" +dependencies = [ + "asn1-rs", +] + [[package]] name = "once_cell" version = "1.21.4" @@ -1155,6 +1304,7 @@ dependencies = [ "ipnet", "miette", "nix", + "openshell-crypto", "openshell-extension-core", "openshell-policy-schema", "prost", @@ -1166,7 +1316,7 @@ dependencies = [ "serde", "serde_json", "sha2", - "thiserror", + "thiserror 2.0.20", "tokio", "tokio-stream", "tonic", @@ -1178,13 +1328,26 @@ dependencies = [ "uuid", ] +[[package]] +name = "openshell-crypto" +version = "0.0.0" +dependencies = [ + "aws-lc-rs", + "jsonwebtoken", + "rcgen", + "rustls", + "serde", + "thiserror 2.0.20", + "tonic", +] + [[package]] name = "openshell-extension-core" version = "0.0.0" dependencies = [ "hyper-util", "serde", - "thiserror", + "thiserror 2.0.20", "tokio", "tonic", "tower", @@ -1261,6 +1424,16 @@ dependencies = [ "windows-link", ] +[[package]] +name = "pem" +version = "3.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d30c53c26bc5b31a98cd02d20f25a7c8567146caf63ed593a9d87b2775291be" +dependencies = [ + "base64", + "serde_core", +] + [[package]] name = "percent-encoding" version = "2.3.2" @@ -1327,6 +1500,12 @@ dependencies = [ "zerovec", ] +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + [[package]] name = "prettyplease" version = "0.2.37" @@ -1506,7 +1685,16 @@ checksum = "c7f5fa3a058cd35567ef9bfa5e75732bee0f9e4c55fa90477bef2dfcdbc4be80" dependencies = [ "chacha20", "getrandom 0.4.3", - "rand_core", + "rand_core 0.10.1", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.17", ] [[package]] @@ -1515,6 +1703,20 @@ version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" +[[package]] +name = "rcgen" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75e669e5202259b5314d1ea5397316ad400819437857b90861765f24c4cf80a2" +dependencies = [ + "aws-lc-rs", + "pem", + "rustls-pki-types", + "time", + "x509-parser", + "yasna", +] + [[package]] name = "redox_syscall" version = "0.5.18" @@ -1563,7 +1765,7 @@ dependencies = [ "cfg-if", "getrandom 0.2.17", "libc", - "untrusted", + "untrusted 0.9.0", "windows-sys 0.52.0", ] @@ -1588,6 +1790,15 @@ dependencies = [ "semver", ] +[[package]] +name = "rusticata-macros" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "faf0c4a6ece9950b9abdb62b1cfcf2a68b3b67a10ba445b3bb85be2a293d0632" +dependencies = [ + "nom", +] + [[package]] name = "rustix" version = "1.1.4" @@ -1655,7 +1866,7 @@ dependencies = [ "aws-lc-rs", "ring", "rustls-pki-types", - "untrusted", + "untrusted 0.9.0", ] [[package]] @@ -1787,6 +1998,15 @@ dependencies = [ "libc", ] +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "rand_core 0.6.4", +] + [[package]] name = "simd_cesu8" version = "1.2.0" @@ -1803,6 +2023,18 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" +[[package]] +name = "simple_asn1" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d585997b0ac10be3c5ee635f1bab02d512760d14b7c468801ac8a01d9ae5f1d" +dependencies = [ + "num-bigint", + "num-traits", + "thiserror 2.0.20", + "time", +] + [[package]] name = "slab" version = "0.4.12" @@ -1892,6 +2124,17 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + [[package]] name = "synstructure" version = "0.14.0" @@ -1936,13 +2179,33 @@ dependencies = [ "unicode-width 0.2.2", ] +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", +] + [[package]] name = "thiserror" version = "2.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec86235f5fcc2a73650310756d2ac5b138a5780bbbdfae3eeccec992c435ba4f" dependencies = [ - "thiserror-impl", + "thiserror-impl 2.0.20", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", ] [[package]] @@ -1956,6 +2219,36 @@ dependencies = [ "syn 3.0.5", ] +[[package]] +name = "time" +version = "0.3.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb87b95ec50ddfa440816d227a17b2ccbdda963a316a727fda0fc4334f7d134" +dependencies = [ + "deranged", + "num-conv", + "powerfmt", + "serde_core", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1c906769ad99c88eaa54e728060edef082f8e358ff32030cb7c7d315e81109" + +[[package]] +name = "time-macros" +version = "0.2.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e689342a48d2ea927c87ea50cabf8594854bf940e9310208848d680d668ed85" +dependencies = [ + "num-conv", + "time-core", +] + [[package]] name = "tinystr" version = "0.8.4" @@ -2215,6 +2508,12 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" +[[package]] +name = "untrusted" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" + [[package]] name = "untrusted" version = "0.9.0" @@ -2435,6 +2734,33 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3ad82d2a33cdc9674dc7465672f271e096168fcdbe0f799d9e6db8c5892679dc" +[[package]] +name = "x509-parser" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcbc162f30700d6f3f82a24bf7cc62ffe7caea42c0b2cba8bf7f3ae50cf51f69" +dependencies = [ + "asn1-rs", + "data-encoding", + "der-parser", + "lazy_static", + "nom", + "oid-registry", + "ring", + "rusticata-macros", + "thiserror 1.0.69", + "time", +] + +[[package]] +name = "yasna" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e17bb3549cc1321ae1296b9cdc2698e2b6cb1992adfa19a8c72e5b7a738f44cd" +dependencies = [ + "time", +] + [[package]] name = "yoke" version = "0.8.3" @@ -2455,7 +2781,7 @@ dependencies = [ "proc-macro2", "quote", "syn 3.0.5", - "synstructure", + "synstructure 0.14.0", ] [[package]] @@ -2476,7 +2802,7 @@ dependencies = [ "proc-macro2", "quote", "syn 3.0.5", - "synstructure", + "synstructure 0.14.0", ] [[package]] @@ -2484,6 +2810,20 @@ name = "zeroize" version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e13c156562582aa81c60cb29407084cdb54c4164760106ab78e6c5b0858cf64e" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c50655cbb0fe3fc43170059e702f1ce5e19b84cec58dc87b037a09935c2f328" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] [[package]] name = "zerotrie" diff --git a/tasks/ci.toml b/tasks/ci.toml index e2a388e6b1..fdb70c829b 100644 --- a/tasks/ci.toml +++ b/tasks/ci.toml @@ -52,6 +52,7 @@ hide = true [lint] description = "Run repository lint checks" depends = [ + "crypto:check", "license:check", "rust:format:check", "rust:lockfiles:check", diff --git a/tasks/rust.toml b/tasks/rust.toml index 32928b8f69..f7b01c5be8 100644 --- a/tasks/rust.toml +++ b/tasks/rust.toml @@ -96,3 +96,8 @@ run = [ # Guard: webpki-root-certs must not appear either (webpki-roots re-exports it). "bash -c 'if cargo tree -p openshell-supervisor -i webpki-root-certs --no-default-features --features system-ca-roots 2>/dev/null | grep -q webpki-root-certs; then echo \"ERROR: webpki-root-certs found in system CA roots build\" >&2; exit 1; fi'", ] + +["crypto:check"] +description = "Check first-party crypto backend boundaries" +run = "bash tasks/scripts/check-crypto-boundary.sh" +hide = true diff --git a/tasks/scripts/check-crypto-boundary.sh b/tasks/scripts/check-crypto-boundary.sh new file mode 100755 index 0000000000..1f35d6b8df --- /dev/null +++ b/tasks/scripts/check-crypto-boundary.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +set -euo pipefail +cd "$(git rev-parse --show-toplevel)" + +# Backend names are permitted only in the adapter implementation and its manifest. +# Word boundaries avoid matching identifiers such as String::from. +if rg -n '\b(aws_lc_rs|ring)::|\bcrypto::aws_lc::|tls-aws-lc|tls-rustls-aws-lc-rs|"aws[-_]lc[-_]rs"|^aws-lc-rs\s*=' \ + crates examples e2e --glob '*.rs' --glob Cargo.toml \ + --glob '!**/openshell-crypto/**'; then + echo 'Direct backend use must live in openshell-crypto.' >&2 + exit 1 +else + result=$? + if [[ "$result" != 1 ]]; then + exit "$result" + fi +fi From b2e06d88e11324830820e5e4c1a39c5969f9877c Mon Sep 17 00:00:00 2001 From: Varsha Prasad Narsing Date: Tue, 15 Sep 2026 11:56:18 -0700 Subject: [PATCH 02/10] refactor(crypto): route new host proxy tests through facade Signed-off-by: Varsha Prasad Narsing --- Cargo.lock | 2 +- crates/openshell-driver-mxc/Cargo.toml | 2 +- crates/openshell-driver-mxc/tests/wxc_exec_real.rs | 2 +- crates/openshell-supervisor-network/src/host.rs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c6de3eee85..255dd52db2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4218,10 +4218,10 @@ dependencies = [ "futures", "noyalib", "openshell-core", + "openshell-crypto", "openshell-ocsf", "openshell-policy", "openshell-supervisor-network", - "rustls", "serde", "serde_json", "tempfile", diff --git a/crates/openshell-driver-mxc/Cargo.toml b/crates/openshell-driver-mxc/Cargo.toml index 5907e92a84..7a5314aaa3 100644 --- a/crates/openshell-driver-mxc/Cargo.toml +++ b/crates/openshell-driver-mxc/Cargo.toml @@ -36,6 +36,7 @@ openshell-supervisor-network = { path = "../openshell-supervisor-network" } windows = { workspace = true } [dev-dependencies] +openshell-crypto = { path = "../openshell-crypto" } tokio = { workspace = true } # tempfile is not a workspace dependency; 3.27 is already resolved in Cargo.lock. tempfile = "3" @@ -47,7 +48,6 @@ openshell-policy = { path = "../openshell-policy" } # base64 and serde_json are already [dependencies] but dev-dependency resolution # is independent; explicit entries make them visible to integration tests. base64 = { workspace = true } -rustls = { workspace = true } serde_json = { workspace = true } # Used by the drift guard test (handled_fields_inventory) to parse YAML into a # generic serde_json::Value for key enumeration. diff --git a/crates/openshell-driver-mxc/tests/wxc_exec_real.rs b/crates/openshell-driver-mxc/tests/wxc_exec_real.rs index 960067b784..7c3097143e 100644 --- a/crates/openshell-driver-mxc/tests/wxc_exec_real.rs +++ b/crates/openshell-driver-mxc/tests/wxc_exec_real.rs @@ -760,7 +760,7 @@ async fn pc_https_egress_reads_injected_ca_bundle() { ..Default::default() }; - let _ = rustls::crypto::aws_lc_rs::default_provider().install_default(); + openshell_crypto::tls::ensure_default_provider(); let config = MxcComputeConfig { wxc_exec_path: wxc.to_string_lossy().into_owned(), egress_proxy: true, diff --git a/crates/openshell-supervisor-network/src/host.rs b/crates/openshell-supervisor-network/src/host.rs index f52ec29fb8..1dfc851258 100644 --- a/crates/openshell-supervisor-network/src/host.rs +++ b/crates/openshell-supervisor-network/src/host.rs @@ -312,7 +312,7 @@ mod tests { #[tokio::test] async fn starts_loopback_proxy_and_serves_policy_local() { - let _ = rustls::crypto::aws_lc_rs::default_provider().install_default(); + openshell_crypto::tls::ensure_default_provider(); let binary = tempfile::NamedTempFile::new().unwrap(); std::fs::write(binary.path(), b"agent").unwrap(); From 3283402bd74be184b52302d20f103362e197c8bb Mon Sep 17 00:00:00 2001 From: Varsha Prasad Narsing Date: Tue, 15 Sep 2026 12:25:57 -0700 Subject: [PATCH 03/10] fix(crypto): make backend boundary check portable Signed-off-by: Varsha Prasad Narsing --- architecture/build.md | 2 + tasks/rust.toml | 2 +- tasks/scripts/check-crypto-boundary.sh | 20 --------- tasks/scripts/check_crypto_boundary.py | 57 ++++++++++++++++++++++++++ 4 files changed, 60 insertions(+), 21 deletions(-) delete mode 100755 tasks/scripts/check-crypto-boundary.sh create mode 100644 tasks/scripts/check_crypto_boundary.py diff --git a/architecture/build.md b/architecture/build.md index 3ba804dbfb..ecca5326b4 100644 --- a/architecture/build.md +++ b/architecture/build.md @@ -39,6 +39,8 @@ that crate instead of naming a backend. Process-default initialization preserves existing embedder providers; context capability reporting does not attest those globals or dependency-owned crypto. OpenSSL and strict FIPS operation are separate follow-up work. The crate README defines extension and coverage boundaries. +The `crypto:check` lint uses the managed Python toolchain and Git on all platforms +to reject direct backend references outside the facade. SQLx uses AWS-LC with native certificate roots. The server enables diff --git a/tasks/rust.toml b/tasks/rust.toml index f7b01c5be8..3df3313ce7 100644 --- a/tasks/rust.toml +++ b/tasks/rust.toml @@ -99,5 +99,5 @@ run = [ ["crypto:check"] description = "Check first-party crypto backend boundaries" -run = "bash tasks/scripts/check-crypto-boundary.sh" +run = "uv run --no-project python tasks/scripts/check_crypto_boundary.py" hide = true diff --git a/tasks/scripts/check-crypto-boundary.sh b/tasks/scripts/check-crypto-boundary.sh deleted file mode 100755 index 1f35d6b8df..0000000000 --- a/tasks/scripts/check-crypto-boundary.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/env bash -# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 - -set -euo pipefail -cd "$(git rev-parse --show-toplevel)" - -# Backend names are permitted only in the adapter implementation and its manifest. -# Word boundaries avoid matching identifiers such as String::from. -if rg -n '\b(aws_lc_rs|ring)::|\bcrypto::aws_lc::|tls-aws-lc|tls-rustls-aws-lc-rs|"aws[-_]lc[-_]rs"|^aws-lc-rs\s*=' \ - crates examples e2e --glob '*.rs' --glob Cargo.toml \ - --glob '!**/openshell-crypto/**'; then - echo 'Direct backend use must live in openshell-crypto.' >&2 - exit 1 -else - result=$? - if [[ "$result" != 1 ]]; then - exit "$result" - fi -fi diff --git a/tasks/scripts/check_crypto_boundary.py b/tasks/scripts/check_crypto_boundary.py new file mode 100644 index 0000000000..c4dd492a47 --- /dev/null +++ b/tasks/scripts/check_crypto_boundary.py @@ -0,0 +1,57 @@ +# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +"""Reject direct crypto backend use outside the facade on every host platform.""" + +import re +import subprocess +import sys +from pathlib import Path + +BACKEND_USE = re.compile( + r"\b(aws_lc_rs|ring)::|\bcrypto::aws_lc::|tls-aws-lc|tls-rustls-aws-lc-rs|" + r'"aws[-_]lc[-_]rs"|^aws-lc-rs\s*=' +) + + +def check(root: Path) -> int: + """Scan tracked and unignored new sources without traversing build outputs.""" + paths = subprocess.check_output( + [ + "git", + "ls-files", + "--cached", + "--others", + "--exclude-standard", + "-z", + "--", + "crates", + "examples", + "e2e", + ], + cwd=root, + ) + failed = False + for name in sorted(set(paths.decode("utf-8").split("\0")) - {""}): + path = Path(name) + if "openshell-crypto" in path.parts: + continue + if path.suffix != ".rs" and path.name != "Cargo.toml": + continue + source = root / path + # Git still lists tracked files removed from the working tree. + if not source.exists(): + continue + for number, line in enumerate( + source.read_text(encoding="utf-8").splitlines(), 1 + ): + if BACKEND_USE.search(line): + print(f"{path.as_posix()}:{number}:{line}") + failed = True + if failed: + print("Direct backend use must live in openshell-crypto.", file=sys.stderr) + return int(failed) + + +if __name__ == "__main__": + sys.exit(check(Path(__file__).resolve().parents[2])) From 2627aef4f7f5643f70703b64a198b7e63191fb35 Mon Sep 17 00:00:00 2001 From: Varsha Prasad Narsing Date: Tue, 15 Sep 2026 12:39:37 -0700 Subject: [PATCH 04/10] fix(crypto): route Google JWT signing through facade and verify context dispatch Signed-off-by: Varsha Prasad Narsing --- .../tests/context_selection.rs | 45 ++++++++++++++++++- .../openshell-server/src/provider_refresh.rs | 2 +- 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/crates/openshell-crypto/tests/context_selection.rs b/crates/openshell-crypto/tests/context_selection.rs index d01a79bfff..9eabb5df79 100644 --- a/crates/openshell-crypto/tests/context_selection.rs +++ b/crates/openshell-crypto/tests/context_selection.rs @@ -4,6 +4,31 @@ use openshell_crypto::{ Capabilities, CryptoBackend, CryptoContext, CryptoError, Digest, ProtocolBackend, aead::Sealed, }; +use std::sync::{ + LazyLock, + atomic::{AtomicUsize, Ordering}, +}; + +static JWT_SIGNERS: AtomicUsize = AtomicUsize::new(0); +static JWT_VERIFIERS: AtomicUsize = AtomicUsize::new(0); +static JWT_PROVIDER: LazyLock = LazyLock::new(|| { + let mut provider = CryptoContext::default().backend().jwt_provider().clone(); + provider.signer_factory = |algorithm, key| { + JWT_SIGNERS.fetch_add(1, Ordering::SeqCst); + (CryptoContext::default() + .backend() + .jwt_provider() + .signer_factory)(algorithm, key) + }; + provider.verifier_factory = |algorithm, key| { + JWT_VERIFIERS.fetch_add(1, Ordering::SeqCst); + (CryptoContext::default() + .backend() + .jwt_provider() + .verifier_factory)(algorithm, key) + }; + provider +}); struct TestBackend(CryptoContext); impl CryptoBackend for TestBackend { @@ -39,7 +64,7 @@ impl ProtocolBackend for TestBackend { Err(rcgen::Error::KeyGenerationUnavailable) } fn jwt_provider(&self) -> &'static jsonwebtoken::crypto::CryptoProvider { - self.0.backend().jwt_provider() + &JWT_PROVIDER } } @@ -54,6 +79,24 @@ fn selected_context_controls_application_adapters_and_cannot_be_replaced() { Err(CryptoError::Random) ); assert!(openshell_crypto::pki::generate_keypair().is_err()); + // A plain round trip could pass with the default backend. Instrument both + // factories to prove that JWT operations use the selected context instead. + let claims = serde_json::json!({"sub": "sandbox", "exp": 4_000_000_000_u64}); + let token = openshell_crypto::jwt::encode( + &jsonwebtoken::Header::new(jsonwebtoken::Algorithm::HS256), + &claims, + &jsonwebtoken::EncodingKey::from_secret(b"test-context-secret"), + ) + .unwrap(); + assert_eq!(JWT_SIGNERS.load(Ordering::SeqCst), 1); + let decoded = openshell_crypto::jwt::decode::( + &token, + &jsonwebtoken::DecodingKey::from_secret(b"test-context-secret"), + &jsonwebtoken::Validation::new(jsonwebtoken::Algorithm::HS256), + ) + .unwrap(); + assert_eq!(decoded.claims, claims); + assert_eq!(JWT_VERIFIERS.load(Ordering::SeqCst), 1); assert_eq!( openshell_crypto::tls::ensure_default_provider() .cipher_suites diff --git a/crates/openshell-server/src/provider_refresh.rs b/crates/openshell-server/src/provider_refresh.rs index 88d53e56de..102e888dc3 100644 --- a/crates/openshell-server/src/provider_refresh.rs +++ b/crates/openshell-server/src/provider_refresh.rs @@ -1450,7 +1450,7 @@ async fn mint_google_service_account_jwt( exp: now_secs.saturating_add(lifetime_secs), sub: subject.as_deref(), }; - let assertion = jsonwebtoken::encode( + let assertion = openshell_crypto::jwt::encode( &jsonwebtoken::Header::new(jsonwebtoken::Algorithm::RS256), &claims, &jsonwebtoken::EncodingKey::from_rsa_pem(private_key.as_bytes()).map_err(|_| { From ce0d3cc9c00cba317e1498e5d81ebbb2c66279b1 Mon Sep 17 00:00:00 2001 From: Varsha Prasad Narsing Date: Tue, 15 Sep 2026 15:36:20 -0700 Subject: [PATCH 05/10] refactor(crypto): propagate digest backend failures Signed-off-by: Varsha Prasad Narsing --- architecture/build.md | 2 + crates/openshell-bootstrap/src/jwt.rs | 18 ++++---- crates/openshell-crypto/README.md | 4 ++ crates/openshell-crypto/src/aws_lc.rs | 11 ++--- crates/openshell-crypto/src/lib.rs | 32 +++++++------- .../tests/context_selection.rs | 44 ++++++++++++++++++- .../openshell-driver-db-credstore/src/lib.rs | 9 ++-- 7 files changed, 85 insertions(+), 35 deletions(-) diff --git a/architecture/build.md b/architecture/build.md index ecca5326b4..b811d14e0e 100644 --- a/architecture/build.md +++ b/architecture/build.md @@ -39,6 +39,8 @@ that crate instead of naming a backend. Process-default initialization preserves existing embedder providers; context capability reporting does not attest those globals or dependency-owned crypto. OpenSSL and strict FIPS operation are separate follow-up work. The crate README defines extension and coverage boundaries. +Digest operations propagate backend failures through JWT and credential key-ID +generation rather than requiring infallible provider operations. The `crypto:check` lint uses the managed Python toolchain and Git on all platforms to reject direct backend references outside the facade. diff --git a/crates/openshell-bootstrap/src/jwt.rs b/crates/openshell-bootstrap/src/jwt.rs index 0bda1a9f66..8c17f1978d 100644 --- a/crates/openshell-bootstrap/src/jwt.rs +++ b/crates/openshell-bootstrap/src/jwt.rs @@ -42,7 +42,7 @@ pub fn generate_jwt_key() -> Result { .wrap_err("failed to generate Ed25519 JWT signing key")?; let signing_key_pem = keypair.serialize_pem(); let public_key_pem = keypair.public_key_pem(); - let kid = kid_from_public_key_der(&keypair.public_key_der()); + let kid = kid_from_public_key_der(&keypair.public_key_der())?; Ok(JwtKeyMaterial { signing_key_pem, public_key_pem, @@ -55,9 +55,11 @@ pub fn generate_jwt_key() -> Result { /// First 16 bytes hex-encoded — collision-resistant for the small N of /// signing keys a single deployment ever has, while staying short enough /// to keep JWT headers compact. -fn kid_from_public_key_der(public_key_der: &[u8]) -> String { - let digest = openshell_crypto::sha256(public_key_der); - hex_encode_prefix(&digest, 16) +fn kid_from_public_key_der(public_key_der: &[u8]) -> Result { + let digest = openshell_crypto::sha256(public_key_der) + .into_diagnostic() + .wrap_err("failed to derive JWT signing key ID")?; + Ok(hex_encode_prefix(&digest, 16)) } fn hex_encode_prefix(bytes: &[u8], n: usize) -> String { @@ -85,15 +87,15 @@ mod tests { #[test] fn kid_is_stable_for_identical_public_keys() { // Same input -> same kid. Hash of a fixed byte string. - let kid_a = kid_from_public_key_der(b"abc"); - let kid_b = kid_from_public_key_der(b"abc"); + let kid_a = kid_from_public_key_der(b"abc").unwrap(); + let kid_b = kid_from_public_key_der(b"abc").unwrap(); assert_eq!(kid_a, kid_b); } #[test] fn kid_differs_for_different_public_keys() { - let kid_a = kid_from_public_key_der(b"first"); - let kid_b = kid_from_public_key_der(b"second"); + let kid_a = kid_from_public_key_der(b"first").unwrap(); + let kid_b = kid_from_public_key_der(b"second").unwrap(); assert_ne!(kid_a, kid_b); } diff --git a/crates/openshell-crypto/README.md b/crates/openshell-crypto/README.md index d018887a7f..7fb10a0ecd 100644 --- a/crates/openshell-crypto/README.md +++ b/crates/openshell-crypto/README.md @@ -13,6 +13,10 @@ adapters. These adapters retain their protocol libraries' validation and encodin they do not expose AWS-LC types. A later native OpenSSL TLS integration may need an additional transport adapter; this interface does not claim to provide one. +Digest creation, updates, and finalization return `Result` so backends can report +provider and operation failures. Callers discard a digest after an update error; +the one-shot SHA-256 helper propagates the first failure without fallback. + Callers use `aead`, `pki`, `tls`, and `jwt`, or an explicit `CryptoContext`. Certificate policy and JWT claim validation remain at their existing callers. The rcgen adapter returns key pairs that own their signing implementation; a diff --git a/crates/openshell-crypto/src/aws_lc.rs b/crates/openshell-crypto/src/aws_lc.rs index 38bac58174..222a2682ff 100644 --- a/crates/openshell-crypto/src/aws_lc.rs +++ b/crates/openshell-crypto/src/aws_lc.rs @@ -13,13 +13,14 @@ pub struct AwsLc; struct Sha256(digest::Context); impl Digest for Sha256 { - fn update(&mut self, bytes: &[u8]) { + fn update(&mut self, bytes: &[u8]) -> Result<(), CryptoError> { self.0.update(bytes); + Ok(()) } - fn finish(self: Box) -> [u8; 32] { + fn finish(self: Box) -> Result<[u8; 32], CryptoError> { let mut output = [0; 32]; output.copy_from_slice(self.0.finish().as_ref()); - output + Ok(output) } } @@ -38,8 +39,8 @@ impl CryptoBackend for AwsLc { .fill(output) .map_err(|_| CryptoError::Random) } - fn sha256_digest(&self) -> Box { - Box::new(Sha256(digest::Context::new(&digest::SHA256))) + fn sha256_digest(&self) -> Result, CryptoError> { + Ok(Box::new(Sha256(digest::Context::new(&digest::SHA256)))) } fn seal( &self, diff --git a/crates/openshell-crypto/src/lib.rs b/crates/openshell-crypto/src/lib.rs index b574910f3f..4fd7fa3bdc 100644 --- a/crates/openshell-crypto/src/lib.rs +++ b/crates/openshell-crypto/src/lib.rs @@ -21,7 +21,7 @@ pub enum CryptoError { /// A backend could not obtain cryptographic randomness. #[error("cryptographic random generation failed")] Random, - /// Encryption or key initialization failed. + /// Digest, encryption, or key initialization failed. #[error("cryptographic operation failed")] Operation, /// Authentication failed; do not distinguish key, nonce, AAD, or tag errors. @@ -58,11 +58,13 @@ pub struct Capabilities { } /// Object-safe incremental SHA-256 computation. +/// +/// After an update fails, callers must discard the computation without finalizing it. pub trait Digest: Send { /// Append bytes without allocating a concatenated message. - fn update(&mut self, bytes: &[u8]); + fn update(&mut self, bytes: &[u8]) -> Result<(), CryptoError>; /// Consume the state and return the digest. - fn finish(self: Box) -> [u8; 32]; + fn finish(self: Box) -> Result<[u8; 32], CryptoError>; } /// Primitive contract. No concrete crypto-library types cross this boundary. @@ -76,7 +78,7 @@ pub trait CryptoBackend: Send + Sync { /// Fill the entire output or report an entropy failure. fn fill_random(&self, output: &mut [u8]) -> Result<(), CryptoError>; /// Create an incremental SHA-256 computation. - fn sha256_digest(&self) -> Box; + fn sha256_digest(&self) -> Result, CryptoError>; /// Encrypt with a fresh random 96-bit nonce, appending the 128-bit GCM tag. fn seal( &self, @@ -183,16 +185,14 @@ pub fn random_bytes() -> Result<[u8; N], CryptoError> { } /// Create an incremental SHA-256 computation. -#[must_use] -pub fn sha256_digest() -> Box { +pub fn sha256_digest() -> Result, CryptoError> { default_context().backend().sha256_digest() } /// Compute SHA-256 using the selected implementation. -#[must_use] -pub fn sha256(bytes: &[u8]) -> [u8; 32] { - let mut digest = sha256_digest(); - digest.update(bytes); +pub fn sha256(bytes: &[u8]) -> Result<[u8; 32], CryptoError> { + let mut digest = sha256_digest()?; + digest.update(bytes)?; digest.finish() } @@ -220,11 +220,11 @@ mod tests { 0x22, 0x23, 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c, 0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad, ]; - assert_eq!(sha256(b"abc"), expected); - let mut digest = sha256_digest(); - digest.update(b"a"); - digest.update(b"bc"); - assert_eq!(digest.finish(), expected); + assert_eq!(sha256(b"abc").unwrap(), expected); + let mut digest = sha256_digest().unwrap(); + digest.update(b"a").unwrap(); + digest.update(b"bc").unwrap(); + assert_eq!(digest.finish().unwrap(), expected); } #[test] @@ -300,7 +300,7 @@ mod tests { fn fill_random(&self, _: &mut [u8]) -> Result<(), CryptoError> { Err(CryptoError::Random) } - fn sha256_digest(&self) -> Box { + fn sha256_digest(&self) -> Result, CryptoError> { aws_lc::AwsLc.sha256_digest() } fn seal(&self, _: &[u8; 32], _: &[u8], _: &[u8]) -> Result { diff --git a/crates/openshell-crypto/tests/context_selection.rs b/crates/openshell-crypto/tests/context_selection.rs index 9eabb5df79..1fbd992698 100644 --- a/crates/openshell-crypto/tests/context_selection.rs +++ b/crates/openshell-crypto/tests/context_selection.rs @@ -11,6 +11,28 @@ use std::sync::{ static JWT_SIGNERS: AtomicUsize = AtomicUsize::new(0); static JWT_VERIFIERS: AtomicUsize = AtomicUsize::new(0); +static DIGEST_FAILURE: AtomicUsize = AtomicUsize::new(0); +static DIGEST_UPDATES: AtomicUsize = AtomicUsize::new(0); +static DIGEST_FINISHES: AtomicUsize = AtomicUsize::new(0); + +struct FailingDigest(usize); +impl Digest for FailingDigest { + fn update(&mut self, _: &[u8]) -> Result<(), CryptoError> { + DIGEST_UPDATES.fetch_add(1, Ordering::SeqCst); + if self.0 == 2 { + Err(CryptoError::Operation) + } else { + Ok(()) + } + } + + fn finish(self: Box) -> Result<[u8; 32], CryptoError> { + DIGEST_FINISHES.fetch_add(1, Ordering::SeqCst); + assert_eq!(self.0, 3, "must not finalize after an update failure"); + Err(CryptoError::Operation) + } +} + static JWT_PROVIDER: LazyLock = LazyLock::new(|| { let mut provider = CryptoContext::default().backend().jwt_provider().clone(); provider.signer_factory = |algorithm, key| { @@ -41,8 +63,12 @@ impl CryptoBackend for TestBackend { bytes.fill(0x55); Ok(()) } - fn sha256_digest(&self) -> Box { - self.0.backend().sha256_digest() + fn sha256_digest(&self) -> Result, CryptoError> { + match DIGEST_FAILURE.load(Ordering::SeqCst) { + 0 => self.0.backend().sha256_digest(), + 1 => Err(CryptoError::Operation), + stage => Ok(Box::new(FailingDigest(stage))), + } } fn seal(&self, _: &[u8; 32], _: &[u8], _: &[u8]) -> Result { Err(CryptoError::Random) @@ -79,6 +105,20 @@ fn selected_context_controls_application_adapters_and_cannot_be_replaced() { Err(CryptoError::Random) ); assert!(openshell_crypto::pki::generate_keypair().is_err()); + // Exercise each fallible stage through the public helper. No failed stage + // may be retried with the default backend or followed by another operation. + for (stage, updates, finishes) in [(1, 0, 0), (2, 1, 0), (3, 1, 1)] { + DIGEST_FAILURE.store(stage, Ordering::SeqCst); + DIGEST_UPDATES.store(0, Ordering::SeqCst); + DIGEST_FINISHES.store(0, Ordering::SeqCst); + assert_eq!( + openshell_crypto::sha256(b"abc"), + Err(CryptoError::Operation) + ); + assert_eq!(DIGEST_UPDATES.load(Ordering::SeqCst), updates); + assert_eq!(DIGEST_FINISHES.load(Ordering::SeqCst), finishes); + } + DIGEST_FAILURE.store(0, Ordering::SeqCst); // A plain round trip could pass with the default backend. Instrument both // factories to prove that JWT operations use the selected context instead. let claims = serde_json::json!({"sub": "sandbox", "exp": 4_000_000_000_u64}); diff --git a/crates/openshell-driver-db-credstore/src/lib.rs b/crates/openshell-driver-db-credstore/src/lib.rs index 871652bad3..96e19c1506 100644 --- a/crates/openshell-driver-db-credstore/src/lib.rs +++ b/crates/openshell-driver-db-credstore/src/lib.rs @@ -472,7 +472,7 @@ impl EncryptedGatewayCredentialSettings { impl EncryptedGatewayCredentialState { fn from_settings(settings: EncryptedGatewayCredentialSettings) -> CoreResult { let key_encryption_key = load_key_encryption_key(&settings)?; - let key_encryption_key_id = key_id(&key_encryption_key); + let key_encryption_key_id = key_id(&key_encryption_key)?; Ok(Self { settings, key_encryption_key, @@ -885,9 +885,10 @@ fn random_bytes_status() -> Result<[u8; N], Status> { Ok(bytes) } -fn key_id(key: &[u8; KEY_LEN]) -> String { - let digest = openshell_crypto::sha256(key); - format!("sha256:{}", hex_encode(&digest)) +fn key_id(key: &[u8; KEY_LEN]) -> CoreResult { + let digest = openshell_crypto::sha256(key) + .map_err(|_| Error::config("failed to derive default credential storage key ID"))?; + Ok(format!("sha256:{}", hex_encode(&digest))) } fn hex_encode(bytes: &[u8]) -> String { From 000c0f218a3cc5014311fb6f13a86881395fe165 Mon Sep 17 00:00:00 2001 From: Varsha Prasad Narsing Date: Tue, 15 Sep 2026 15:41:20 -0700 Subject: [PATCH 06/10] refactor(crypto): route Vault TLS fixtures through facade Signed-off-by: Varsha Prasad Narsing --- crates/openshell-driver-vault/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/openshell-driver-vault/src/lib.rs b/crates/openshell-driver-vault/src/lib.rs index e3692888ef..a66ef628e2 100644 --- a/crates/openshell-driver-vault/src/lib.rs +++ b/crates/openshell-driver-vault/src/lib.rs @@ -1007,14 +1007,14 @@ mod tests { fn test_ca() -> (rcgen::Certificate, KeyPair) { let mut params = CertificateParams::new(Vec::::new()).unwrap(); params.is_ca = IsCa::Ca(rcgen::BasicConstraints::Unconstrained); - let key = KeyPair::generate().unwrap(); + let key = openshell_crypto::pki::generate_keypair().unwrap(); let certificate = params.self_signed(&key).unwrap(); (certificate, key) } async fn start_tls_server(response: String) -> (SocketAddr, String) { let (ca_certificate, ca_key) = test_ca(); - let server_key = KeyPair::generate().unwrap(); + let server_key = openshell_crypto::pki::generate_keypair().unwrap(); let server_certificate = CertificateParams::new(vec!["localhost".to_string()]) .unwrap() .signed_by(&server_key, &ca_certificate, &ca_key) From 2caef2ed376106b1092c2a6aad82b7d5c53da665 Mon Sep 17 00:00:00 2001 From: Varsha Prasad Narsing Date: Wed, 16 Sep 2026 12:41:41 -0700 Subject: [PATCH 07/10] refactor(crypto): adapt isolation runtime callers after main rebase Signed-off-by: Varsha Prasad Narsing --- Cargo.lock | 2 + crates/openshell-core/src/jwt.rs | 18 ++- crates/openshell-crypto/README.md | 9 +- .../src/sandbox_runtime.rs | 5 +- crates/openshell-sandbox-backend/Cargo.toml | 1 + .../src/boundary_protocol.rs | 11 +- .../openshell-sandbox-backend/src/runtime.rs | 4 +- .../src/sandbox_auth.rs | 4 +- .../openshell-sandbox/src/boundary_server.rs | 10 +- crates/openshell-server/src/auth/oidc.rs | 8 +- .../src/l7/tls.rs | 2 +- crates/openshell-supervisor/Cargo.toml | 1 + crates/openshell-supervisor/src/main.rs | 4 +- e2e/rust/Cargo.lock | 146 ++++++++++++++++- examples/governance-interceptor/Cargo.lock | 148 +++++++++++++++++- 15 files changed, 329 insertions(+), 44 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 255dd52db2..86c1da2978 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4580,6 +4580,7 @@ dependencies = [ "hyper-util", "libc", "openshell-core", + "openshell-crypto", "openshell-isolation-interface", "prost", "protoc-bin-vendored", @@ -4742,6 +4743,7 @@ dependencies = [ "miette", "nix 0.29.0", "openshell-core", + "openshell-crypto", "openshell-extension-core", "openshell-isolation-interface", "openshell-ocsf", diff --git a/crates/openshell-core/src/jwt.rs b/crates/openshell-core/src/jwt.rs index 5cd8c60438..e968493792 100644 --- a/crates/openshell-core/src/jwt.rs +++ b/crates/openshell-core/src/jwt.rs @@ -36,9 +36,8 @@ mod session { use std::sync::Arc; use std::time::{Duration, SystemTime, UNIX_EPOCH}; - use jsonwebtoken::{ - Algorithm, DecodingKey, EncodingKey, Header, Validation, decode, decode_header, encode, - }; + use jsonwebtoken::{Algorithm, DecodingKey, EncodingKey, Header, Validation, decode_header}; + use openshell_crypto::jwt::{decode, encode}; use serde::{Deserialize, Serialize}; use uuid::Uuid; use zeroize::Zeroizing; @@ -807,7 +806,7 @@ mod session { } fn install_crypto_provider() { - let _ = jsonwebtoken::crypto::aws_lc::DEFAULT_PROVIDER.install_default(); + openshell_crypto::install_jwt_provider(); } fn validate_ttl(ttl: Duration) -> Result<(), SessionJwtError> { @@ -894,8 +893,9 @@ mod tests { mod session_tests { use std::sync::Arc; - use jsonwebtoken::{Algorithm, EncodingKey, Header, encode}; - use rcgen::{KeyPair, PKCS_ED25519}; + use jsonwebtoken::{Algorithm, EncodingKey, Header}; + use openshell_crypto::jwt::encode; + use rcgen::PKCS_ED25519; use serde::Serialize; use super::super::session::*; @@ -917,7 +917,8 @@ mod tests { SessionJwtVerifier, SandboxRuntimeIdentity, ) { - let key = KeyPair::generate_for(&PKCS_ED25519).expect("generate Ed25519 key"); + let key = openshell_crypto::pki::generate_keypair_for(&PKCS_ED25519) + .expect("generate Ed25519 key"); let public_key_pem = key.public_key_pem().into_bytes(); let clock: Arc = Arc::new(FixedClock(1_900_000_000)); let issuer = SessionJwtIssuer::from_ed25519_pem( @@ -1035,7 +1036,8 @@ mod tests { #[test] fn audience_arrays_are_rejected() { - let key = KeyPair::generate_for(&PKCS_ED25519).expect("generate Ed25519 key"); + let key = openshell_crypto::pki::generate_keypair_for(&PKCS_ED25519) + .expect("generate Ed25519 key"); let clock: Arc = Arc::new(FixedClock(1_900_000_000)); let verifier = SessionJwtVerifier::new( "test", diff --git a/crates/openshell-crypto/README.md b/crates/openshell-crypto/README.md index 7fb10a0ecd..acac194d4a 100644 --- a/crates/openshell-crypto/README.md +++ b/crates/openshell-crypto/README.md @@ -71,6 +71,10 @@ scheduling randomness are not migrated. No SSH or PQC capability is asserted by the primitive capability report. OpenSSL, strict policy, module version discovery, and deployment qualification belong in follow-up work. +Durable proxy CA loading retains rcgen's PEM key import and X.509 parser. The +parser and build-time Z3 downloader retain the narrowly allowed Ring dependencies +listed in `deny.toml`; context capabilities do not attest these paths. + ## Extending and checking Implement both traits without importing application crates. Retain provider/key @@ -83,5 +87,6 @@ Run `cargo test -p openshell-crypto` for known-answer crypto, tampering, JWT validation, context substitution, and isolated global-provider tests. Existing bootstrap, credential-store, gateway TLS/OIDC, and proxy tests exercise the migrated consumers. `mise run crypto:check` rejects direct backend imports and -feature selections outside this crate. The existing cargo-deny Ring ban remains -in force. A source scan cannot attest the behavior of transitive dependencies. +feature selections outside this crate. The cargo-deny Ring restrictions and their +explicit wrapper exceptions remain in force. A source scan cannot attest the +behavior of transitive dependencies. diff --git a/crates/openshell-driver-kubernetes/src/sandbox_runtime.rs b/crates/openshell-driver-kubernetes/src/sandbox_runtime.rs index 791cbda3c3..424d022b22 100644 --- a/crates/openshell-driver-kubernetes/src/sandbox_runtime.rs +++ b/crates/openshell-driver-kubernetes/src/sandbox_runtime.rs @@ -16,7 +16,7 @@ use k8s_openapi::api::core::v1::{ use k8s_openapi::apimachinery::pkg::apis::meta::v1::OwnerReference; use k8s_openapi::apimachinery::pkg::util::intstr::IntOrString; use kube::core::ObjectMeta; -use rcgen::{CertificateParams, DnType, IsCa, KeyPair, KeyUsagePurpose}; +use rcgen::{CertificateParams, DnType, IsCa, KeyUsagePurpose}; use crate::isolation::{ BOUNDARY_PAIR_LABEL, BOUNDARY_ROLE_LABEL, KubernetesSandboxRuntimeNetworkFence, @@ -51,7 +51,8 @@ pub struct ProxyCaMaterial { } pub fn generate_proxy_ca_material() -> Result { - let key = KeyPair::generate().map_err(|error| format!("generate proxy CA key: {error}"))?; + let key = openshell_crypto::pki::generate_keypair() + .map_err(|error| format!("generate proxy CA key: {error}"))?; let mut params = CertificateParams::default(); params.is_ca = IsCa::Ca(rcgen::BasicConstraints::Unconstrained); params diff --git a/crates/openshell-sandbox-backend/Cargo.toml b/crates/openshell-sandbox-backend/Cargo.toml index 6d39fc37d5..f08e5d43ff 100644 --- a/crates/openshell-sandbox-backend/Cargo.toml +++ b/crates/openshell-sandbox-backend/Cargo.toml @@ -11,6 +11,7 @@ license.workspace = true repository.workspace = true [dependencies] +openshell-crypto = { path = "../openshell-crypto" } openshell-core = { path = "../openshell-core", default-features = false, features = ["jwt"] } openshell-isolation-interface = { path = "../openshell-isolation-interface" } async-trait = "0.1" diff --git a/crates/openshell-sandbox-backend/src/boundary_protocol.rs b/crates/openshell-sandbox-backend/src/boundary_protocol.rs index 05542fb2bc..149cb31ebb 100644 --- a/crates/openshell-sandbox-backend/src/boundary_protocol.rs +++ b/crates/openshell-sandbox-backend/src/boundary_protocol.rs @@ -26,7 +26,7 @@ use openshell_isolation_interface::contract::{ BackendDescriptor, BackendError, BinaryIdentity, BoundaryExitStatus, BoundarySignal, DriverFenceEvidence, ExecSpec, ResolveError, SandboxConfirmEvidence, }; -use rcgen::{CertificateParams, DnType, ExtendedKeyUsagePurpose, IsCa, KeyPair, KeyUsagePurpose}; +use rcgen::{CertificateParams, DnType, ExtendedKeyUsagePurpose, IsCa, KeyUsagePurpose}; use serde::de::DeserializeOwned; use serde::{Deserialize, Serialize}; use sha2::{Digest as _, Sha256}; @@ -194,7 +194,7 @@ pub fn generate_sandbox_tls_material( session_id: SandboxSessionId, ) -> Result { let server_name = format!("sandbox.{session_id}.openshell.internal"); - let ca_key = KeyPair::generate_for(&rcgen::PKCS_ED25519) + let ca_key = openshell_crypto::pki::generate_keypair_for(&rcgen::PKCS_ED25519) .map_err(|error| BackendError::Descriptor(format!("generate sandbox CA key: {error}")))?; let mut ca_params = CertificateParams::default(); ca_params.not_before = rcgen::date_time_ymd(1975, 1, 1); @@ -208,9 +208,10 @@ pub fn generate_sandbox_tls_material( BackendError::Descriptor(format!("generate sandbox CA certificate: {error}")) })?; - let sandbox_key = KeyPair::generate_for(&rcgen::PKCS_ED25519).map_err(|error| { - BackendError::Descriptor(format!("generate sandbox TLS server key: {error}")) - })?; + let sandbox_key = + openshell_crypto::pki::generate_keypair_for(&rcgen::PKCS_ED25519).map_err(|error| { + BackendError::Descriptor(format!("generate sandbox TLS server key: {error}")) + })?; let mut sandbox_params = CertificateParams::new(vec![server_name.clone()]) .map_err(|error| BackendError::Descriptor(format!("build sandbox certificate: {error}")))?; sandbox_params.not_before = rcgen::date_time_ymd(1975, 1, 1); diff --git a/crates/openshell-sandbox-backend/src/runtime.rs b/crates/openshell-sandbox-backend/src/runtime.rs index 1b56d6df9d..55fffe6924 100644 --- a/crates/openshell-sandbox-backend/src/runtime.rs +++ b/crates/openshell-sandbox-backend/src/runtime.rs @@ -234,7 +234,7 @@ fn validate_client_tls(tls: &SandboxTlsClientConfig) -> Result<(), BackendError> } fn tls_client_config(tls: &SandboxTlsClientConfig) -> Result { - let _ = rustls::crypto::aws_lc_rs::default_provider().install_default(); + openshell_crypto::tls::ensure_default_provider(); let certificates = rustls_pemfile::certs(&mut tls.trust_anchor_pem.as_bytes()) .collect::, _>>() .map_err(|error| { @@ -2427,7 +2427,7 @@ mod tests { fn test_certificate_with_protocol_versions( protocol_versions: &[&'static rustls::SupportedProtocolVersion], ) -> TestCertificate { - let _ = rustls::crypto::aws_lc_rs::default_provider().install_default(); + openshell_crypto::tls::ensure_default_provider(); let material = generate_sandbox_tls_material(test_session_id()).expect("generate test material"); let certificates = rustls_pemfile::certs(&mut material.certificate_chain_pem.as_bytes()) diff --git a/crates/openshell-sandbox-backend/src/sandbox_auth.rs b/crates/openshell-sandbox-backend/src/sandbox_auth.rs index 8cd3878283..566d3a8a62 100644 --- a/crates/openshell-sandbox-backend/src/sandbox_auth.rs +++ b/crates/openshell-sandbox-backend/src/sandbox_auth.rs @@ -356,7 +356,7 @@ mod tests { SessionTokenProfile, SessionVerificationKey, }; use openshell_core::sandbox_generation::SandboxGenerationId; - use rcgen::{KeyPair, PKCS_ED25519}; + use rcgen::PKCS_ED25519; use super::*; @@ -375,7 +375,7 @@ mod tests { SandboxProtocolAuthenticator, openshell_core::jwt::MintedSessionToken, ) { - let key = KeyPair::generate_for(&PKCS_ED25519).expect("generate key"); + let key = openshell_crypto::pki::generate_keypair_for(&PKCS_ED25519).expect("generate key"); let public_key_pem = key.public_key_pem().into_bytes(); let clock: Arc = Arc::new(FixedClock); let sandbox_id = SandboxId::parse("sandbox-a").expect("sandbox ID"); diff --git a/crates/openshell-sandbox/src/boundary_server.rs b/crates/openshell-sandbox/src/boundary_server.rs index 5452ea6efa..d1db847599 100644 --- a/crates/openshell-sandbox/src/boundary_server.rs +++ b/crates/openshell-sandbox/src/boundary_server.rs @@ -3283,7 +3283,7 @@ mod linux { fn load_tls_server_config( tls: &openshell_sandbox_backend::boundary_protocol::SandboxTlsServerConfig, ) -> io::Result { - let _ = rustls::crypto::aws_lc_rs::default_provider().install_default(); + openshell_crypto::tls::ensure_default_provider(); let certificate_bytes = std::fs::read(&tls.certificate_chain_path)?; let certificates = rustls_pemfile::certs(&mut certificate_bytes.as_slice()) .collect::, _>>()?; @@ -3525,7 +3525,7 @@ mod linux { GatewayVerificationKey, SandboxTlsClientConfig, SandboxTlsServerConfig, generate_sandbox_tls_material, }; - use rcgen::{KeyPair, PKCS_ED25519}; + use rcgen::PKCS_ED25519; #[test] fn exec_tombstones_outlive_retained_handles_and_fail_closed_at_capacity() { @@ -3592,7 +3592,8 @@ mod linux { } fn test_verification_key() -> GatewayVerificationKey { - let key = KeyPair::generate_for(&PKCS_ED25519).expect("generate gateway key"); + let key = openshell_crypto::pki::generate_keypair_for(&PKCS_ED25519) + .expect("generate gateway key"); GatewayVerificationKey { key_id: "test-key".to_string(), public_key_pem: key.public_key_pem(), @@ -3600,7 +3601,8 @@ mod linux { } fn test_auth_material(sandbox_id: &str) -> (GatewayVerificationKey, String) { - let key = KeyPair::generate_for(&PKCS_ED25519).expect("generate gateway key"); + let key = openshell_crypto::pki::generate_keypair_for(&PKCS_ED25519) + .expect("generate gateway key"); let verification_key = GatewayVerificationKey { key_id: "test-key".to_string(), public_key_pem: key.public_key_pem(), diff --git a/crates/openshell-server/src/auth/oidc.rs b/crates/openshell-server/src/auth/oidc.rs index 83c1f94485..8af6ca519e 100644 --- a/crates/openshell-server/src/auth/oidc.rs +++ b/crates/openshell-server/src/auth/oidc.rs @@ -1003,22 +1003,22 @@ mod tests { #[tokio::test] async fn oidc_loads_discovery_and_jwks_from_tls_idp_with_rotated_local_ca() { - use rcgen::{BasicConstraints, CertificateParams, IsCa, KeyPair}; + use rcgen::{BasicConstraints, CertificateParams, IsCa}; use rustls::pki_types::PrivateKeyDer; use tokio::io::{AsyncReadExt, AsyncWriteExt}; let mut old_ca_params = CertificateParams::new(Vec::::new()).unwrap(); old_ca_params.is_ca = IsCa::Ca(BasicConstraints::Unconstrained); - let old_ca_key = KeyPair::generate().unwrap(); + let old_ca_key = openshell_crypto::pki::generate_keypair().unwrap(); let old_ca_cert = old_ca_params.self_signed(&old_ca_key).unwrap(); let mut ca_params = CertificateParams::new(Vec::::new()).unwrap(); ca_params.is_ca = IsCa::Ca(BasicConstraints::Unconstrained); - let ca_key = KeyPair::generate().unwrap(); + let ca_key = openshell_crypto::pki::generate_keypair().unwrap(); let ca_cert = ca_params.self_signed(&ca_key).unwrap(); let server_params = CertificateParams::new(vec!["localhost".to_string()]).unwrap(); - let server_key = KeyPair::generate().unwrap(); + let server_key = openshell_crypto::pki::generate_keypair().unwrap(); let server_cert = server_params .signed_by(&server_key, &ca_cert, &ca_key) .unwrap(); diff --git a/crates/openshell-supervisor-network/src/l7/tls.rs b/crates/openshell-supervisor-network/src/l7/tls.rs index 9800162cb1..ee7d8b750b 100644 --- a/crates/openshell-supervisor-network/src/l7/tls.rs +++ b/crates/openshell-supervisor-network/src/l7/tls.rs @@ -100,7 +100,7 @@ impl SandboxCa { /// Load a durable CA while preserving the exact certificate bytes supplied /// by the provisioner for boundary launch replay. pub fn from_pem(certificate_pem: &str, private_key_pem: &str) -> Result { - let _ = rustls::crypto::aws_lc_rs::default_provider().install_default(); + openshell_crypto::tls::ensure_default_provider(); let ca_key = KeyPair::from_pem(private_key_pem) .into_diagnostic() .wrap_err("parse proxy CA private key")?; diff --git a/crates/openshell-supervisor/Cargo.toml b/crates/openshell-supervisor/Cargo.toml index d4fb9cee68..a244880960 100644 --- a/crates/openshell-supervisor/Cargo.toml +++ b/crates/openshell-supervisor/Cargo.toml @@ -15,6 +15,7 @@ name = "openshell-supervisor" path = "src/main.rs" [dependencies] +openshell-crypto = { path = "../openshell-crypto" } openshell-core = { path = "../openshell-core", default-features = false, features = ["jwt"] } openshell-extension-core = { path = "../openshell-extension-core" } openshell-isolation-interface = { path = "../openshell-isolation-interface" } diff --git a/crates/openshell-supervisor/src/main.rs b/crates/openshell-supervisor/src/main.rs index 515572b083..2abf25071a 100644 --- a/crates/openshell-supervisor/src/main.rs +++ b/crates/openshell-supervisor/src/main.rs @@ -279,7 +279,7 @@ fn main() -> Result<()> { .build() .into_diagnostic()?; return runtime.block_on(async move { - let _ = rustls::crypto::aws_lc_rs::default_provider().install_default(); + openshell_crypto::tls::ensure_default_provider(); let exit = openshell_supervisor_process::debug_rpc::run(&raw_args[2..]).await?; std::process::exit(exit); }); @@ -324,7 +324,7 @@ fn main() -> Result<()> { .into_diagnostic()?; let exit_code = runtime.block_on(async move { - let _ = rustls::crypto::aws_lc_rs::default_provider().install_default(); + openshell_crypto::tls::ensure_default_provider(); let log_push_state = if args.role == SupervisorRole::IsolationBackend && let (Some(sandbox_id), Some(endpoint)) = (&args.sandbox_id, &args.openshell_endpoint) { diff --git a/e2e/rust/Cargo.lock b/e2e/rust/Cargo.lock index c8088f185b..4795ab512e 100644 --- a/e2e/rust/Cargo.lock +++ b/e2e/rust/Cargo.lock @@ -8,6 +8,45 @@ version = "1.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "330a5ed07fa54e4702c9d6c4174f74427fc0ef6e214bbd677ae50a5099946470" +[[package]] +name = "asn1-rs" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5493c3bedbacf7fd7382c6346bbd66687d12bbaad3a89a2d2c303ee6cf20b048" +dependencies = [ + "asn1-rs-derive", + "asn1-rs-impl", + "displaydoc", + "nom", + "num-traits", + "rusticata-macros", + "thiserror 1.0.69", + "time", +] + +[[package]] +name = "asn1-rs-derive" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "965c2d33e53cb6b267e148a4cb0760bc01f4904c1cd4bb4002a085bb016d1490" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", + "synstructure", +] + +[[package]] +name = "asn1-rs-impl" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + [[package]] name = "async-trait" version = "0.1.91" @@ -143,7 +182,7 @@ dependencies = [ "serde_derive", "serde_json", "serde_urlencoded", - "thiserror", + "thiserror 2.0.19", "tokio", "tokio-util", "tower-service", @@ -226,6 +265,26 @@ dependencies = [ "typenum", ] +[[package]] +name = "data-encoding" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4583a4551df46e2792f82ceeac45e850d2e2d5debba0b91f102385cda5b11f06" + +[[package]] +name = "der-parser" +version = "9.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cd0a5c643689626bec213c4d8bd4d96acc8ffdb4ad4bb6bc16abf27d5f4b553" +dependencies = [ + "asn1-rs", + "displaydoc", + "nom", + "num-bigint", + "num-traits", + "rusticata-macros", +] + [[package]] name = "deranged" version = "0.5.8" @@ -749,6 +808,12 @@ dependencies = [ "zeroize", ] +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + [[package]] name = "libc" version = "0.2.189" @@ -806,6 +871,12 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + [[package]] name = "mio" version = "1.2.2" @@ -829,6 +900,16 @@ dependencies = [ "libc", ] +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + [[package]] name = "noyalib" version = "0.0.28" @@ -879,6 +960,15 @@ dependencies = [ "autocfg", ] +[[package]] +name = "oid-registry" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8d8034d9489cdaf79228eb9f6a3b8d7bb32ba00d6645ebd48eef4077ceb5bd9" +dependencies = [ + "asn1-rs", +] + [[package]] name = "once_cell" version = "1.21.4" @@ -894,7 +984,7 @@ dependencies = [ "rcgen", "rustls", "serde", - "thiserror", + "thiserror 2.0.19", ] [[package]] @@ -1125,6 +1215,7 @@ dependencies = [ "pem", "rustls-pki-types", "time", + "x509-parser", "yasna", ] @@ -1157,6 +1248,15 @@ version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6b1e7f9a428571be2dc5bc0505c13fb6bf936822b894ec87abf8a08a4e51742d" +[[package]] +name = "rusticata-macros" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "faf0c4a6ece9950b9abdb62b1cfcf2a68b3b67a10ba445b3bb85be2a293d0632" +dependencies = [ + "nom", +] + [[package]] name = "rustix" version = "1.1.4" @@ -1370,7 +1470,7 @@ checksum = "0d585997b0ac10be3c5ee635f1bab02d512760d14b7c468801ac8a01d9ae5f1d" dependencies = [ "num-bigint", "num-traits", - "thiserror", + "thiserror 2.0.19", "time", ] @@ -1460,13 +1560,33 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", +] + [[package]] name = "thiserror" version = "2.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09a43598840e33d5b0331f38c5e30d13bb11c11210a4b58f0d9b18a5a5eefcd9" dependencies = [ - "thiserror-impl", + "thiserror-impl 2.0.19", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", ] [[package]] @@ -1920,6 +2040,24 @@ version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4" +[[package]] +name = "x509-parser" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcbc162f30700d6f3f82a24bf7cc62ffe7caea42c0b2cba8bf7f3ae50cf51f69" +dependencies = [ + "asn1-rs", + "data-encoding", + "der-parser", + "lazy_static", + "nom", + "oid-registry", + "ring", + "rusticata-macros", + "thiserror 1.0.69", + "time", +] + [[package]] name = "yasna" version = "0.5.2" diff --git a/examples/governance-interceptor/Cargo.lock b/examples/governance-interceptor/Cargo.lock index 0f5e5f9e4c..c79cca717d 100644 --- a/examples/governance-interceptor/Cargo.lock +++ b/examples/governance-interceptor/Cargo.lock @@ -32,6 +32,45 @@ version = "1.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "330a5ed07fa54e4702c9d6c4174f74427fc0ef6e214bbd677ae50a5099946470" +[[package]] +name = "asn1-rs" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5493c3bedbacf7fd7382c6346bbd66687d12bbaad3a89a2d2c303ee6cf20b048" +dependencies = [ + "asn1-rs-derive", + "asn1-rs-impl", + "displaydoc", + "nom", + "num-traits", + "rusticata-macros", + "thiserror 1.0.69", + "time", +] + +[[package]] +name = "asn1-rs-derive" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "965c2d33e53cb6b267e148a4cb0760bc01f4904c1cd4bb4002a085bb016d1490" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", + "synstructure", +] + +[[package]] +name = "asn1-rs-impl" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + [[package]] name = "async-trait" version = "0.1.92" @@ -289,6 +328,20 @@ version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4583a4551df46e2792f82ceeac45e850d2e2d5debba0b91f102385cda5b11f06" +[[package]] +name = "der-parser" +version = "9.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cd0a5c643689626bec213c4d8bd4d96acc8ffdb4ad4bb6bc16abf27d5f4b553" +dependencies = [ + "asn1-rs", + "displaydoc", + "nom", + "num-bigint", + "num-traits", + "rusticata-macros", +] + [[package]] name = "deranged" version = "0.5.8" @@ -526,7 +579,7 @@ dependencies = [ "once_cell", "rand", "ring", - "thiserror", + "thiserror 2.0.20", "tinyvec", "tracing", "url", @@ -786,7 +839,7 @@ dependencies = [ "jni-sys", "log", "simd_cesu8", - "thiserror", + "thiserror 2.0.20", "walkdir", "windows-link", ] @@ -862,6 +915,12 @@ dependencies = [ "zeroize", ] +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + [[package]] name = "libc" version = "0.2.189" @@ -949,6 +1008,12 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + [[package]] name = "miniz_oxide" version = "0.8.9" @@ -987,6 +1052,16 @@ dependencies = [ "libc", ] +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + [[package]] name = "noyalib" version = "0.0.28" @@ -1046,6 +1121,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "oid-registry" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8d8034d9489cdaf79228eb9f6a3b8d7bb32ba00d6645ebd48eef4077ceb5bd9" +dependencies = [ + "asn1-rs", +] + [[package]] name = "once_cell" version = "1.21.4" @@ -1078,7 +1162,7 @@ dependencies = [ "serde", "serde_json", "sha2", - "thiserror", + "thiserror 2.0.20", "tokio", "tokio-stream", "tonic", @@ -1099,7 +1183,7 @@ dependencies = [ "rcgen", "rustls", "serde", - "thiserror", + "thiserror 2.0.20", "tonic", ] @@ -1109,7 +1193,7 @@ version = "0.0.0" dependencies = [ "hyper-util", "serde", - "thiserror", + "thiserror 2.0.20", "tokio", "tonic", "tower", @@ -1170,7 +1254,7 @@ dependencies = [ "prost-types", "serde", "serde_json", - "thiserror", + "thiserror 2.0.20", "url", ] @@ -1518,6 +1602,7 @@ dependencies = [ "pem", "rustls-pki-types", "time", + "x509-parser", "yasna", ] @@ -1594,6 +1679,15 @@ dependencies = [ "semver", ] +[[package]] +name = "rusticata-macros" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "faf0c4a6ece9950b9abdb62b1cfcf2a68b3b67a10ba445b3bb85be2a293d0632" +dependencies = [ + "nom", +] + [[package]] name = "rustix" version = "1.1.4" @@ -1836,7 +1930,7 @@ checksum = "0d585997b0ac10be3c5ee635f1bab02d512760d14b7c468801ac8a01d9ae5f1d" dependencies = [ "num-bigint", "num-traits", - "thiserror", + "thiserror 2.0.20", "time", ] @@ -1967,13 +2061,33 @@ dependencies = [ "unicode-width 0.2.2", ] +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", +] + [[package]] name = "thiserror" version = "2.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec86235f5fcc2a73650310756d2ac5b138a5780bbbdfae3eeccec992c435ba4f" dependencies = [ - "thiserror-impl", + "thiserror-impl 2.0.20", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", ] [[package]] @@ -2510,6 +2624,24 @@ version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4" +[[package]] +name = "x509-parser" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcbc162f30700d6f3f82a24bf7cc62ffe7caea42c0b2cba8bf7f3ae50cf51f69" +dependencies = [ + "asn1-rs", + "data-encoding", + "der-parser", + "lazy_static", + "nom", + "oid-registry", + "ring", + "rusticata-macros", + "thiserror 1.0.69", + "time", +] + [[package]] name = "yasna" version = "0.5.2" From 11fdc1e1d80a07cfbfa9003993dcca686140b883 Mon Sep 17 00:00:00 2001 From: Varsha Prasad Narsing Date: Wed, 16 Sep 2026 15:41:16 -0700 Subject: [PATCH 08/10] fix(crypto): declare sandbox dependency and remove boundary lint Signed-off-by: Varsha Prasad Narsing --- Cargo.lock | 1 + architecture/build.md | 2 - crates/openshell-crypto/README.md | 6 +-- crates/openshell-sandbox/Cargo.toml | 1 + tasks/ci.toml | 1 - tasks/rust.toml | 5 --- tasks/scripts/check_crypto_boundary.py | 57 -------------------------- 7 files changed, 4 insertions(+), 69 deletions(-) delete mode 100644 tasks/scripts/check_crypto_boundary.py diff --git a/Cargo.lock b/Cargo.lock index 86c1da2978..a143a8e52d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4549,6 +4549,7 @@ dependencies = [ "nix 0.29.0", "openshell-binary-identity", "openshell-core", + "openshell-crypto", "openshell-isolation-interface", "openshell-ocsf", "openshell-policy", diff --git a/architecture/build.md b/architecture/build.md index b811d14e0e..215244cf26 100644 --- a/architecture/build.md +++ b/architecture/build.md @@ -41,8 +41,6 @@ globals or dependency-owned crypto. OpenSSL and strict FIPS operation are separa follow-up work. The crate README defines extension and coverage boundaries. Digest operations propagate backend failures through JWT and credential key-ID generation rather than requiring infallible provider operations. -The `crypto:check` lint uses the managed Python toolchain and Git on all platforms -to reject direct backend references outside the facade. SQLx uses AWS-LC with native certificate roots. The server enables diff --git a/crates/openshell-crypto/README.md b/crates/openshell-crypto/README.md index acac194d4a..cca566396f 100644 --- a/crates/openshell-crypto/README.md +++ b/crates/openshell-crypto/README.md @@ -86,7 +86,5 @@ certificate or authorization policy into primitive implementations. Run `cargo test -p openshell-crypto` for known-answer crypto, tampering, JWT validation, context substitution, and isolated global-provider tests. Existing bootstrap, credential-store, gateway TLS/OIDC, and proxy tests exercise the -migrated consumers. `mise run crypto:check` rejects direct backend imports and -feature selections outside this crate. The cargo-deny Ring restrictions and their -explicit wrapper exceptions remain in force. A source scan cannot attest the -behavior of transitive dependencies. +migrated consumers. The cargo-deny Ring restrictions and their explicit wrapper +exceptions remain in force. diff --git a/crates/openshell-sandbox/Cargo.toml b/crates/openshell-sandbox/Cargo.toml index 1283dd063b..c6108f9cfa 100644 --- a/crates/openshell-sandbox/Cargo.toml +++ b/crates/openshell-sandbox/Cargo.toml @@ -24,6 +24,7 @@ perf-harness = [] [dependencies] openshell-core = { path = "../openshell-core", default-features = false } +openshell-crypto = { path = "../openshell-crypto" } openshell-binary-identity = { path = "../openshell-binary-identity" } openshell-isolation-interface = { path = "../openshell-isolation-interface" } openshell-sandbox-backend = { path = "../openshell-sandbox-backend" } diff --git a/tasks/ci.toml b/tasks/ci.toml index fdb70c829b..e2a388e6b1 100644 --- a/tasks/ci.toml +++ b/tasks/ci.toml @@ -52,7 +52,6 @@ hide = true [lint] description = "Run repository lint checks" depends = [ - "crypto:check", "license:check", "rust:format:check", "rust:lockfiles:check", diff --git a/tasks/rust.toml b/tasks/rust.toml index 3df3313ce7..32928b8f69 100644 --- a/tasks/rust.toml +++ b/tasks/rust.toml @@ -96,8 +96,3 @@ run = [ # Guard: webpki-root-certs must not appear either (webpki-roots re-exports it). "bash -c 'if cargo tree -p openshell-supervisor -i webpki-root-certs --no-default-features --features system-ca-roots 2>/dev/null | grep -q webpki-root-certs; then echo \"ERROR: webpki-root-certs found in system CA roots build\" >&2; exit 1; fi'", ] - -["crypto:check"] -description = "Check first-party crypto backend boundaries" -run = "uv run --no-project python tasks/scripts/check_crypto_boundary.py" -hide = true diff --git a/tasks/scripts/check_crypto_boundary.py b/tasks/scripts/check_crypto_boundary.py deleted file mode 100644 index c4dd492a47..0000000000 --- a/tasks/scripts/check_crypto_boundary.py +++ /dev/null @@ -1,57 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 - -"""Reject direct crypto backend use outside the facade on every host platform.""" - -import re -import subprocess -import sys -from pathlib import Path - -BACKEND_USE = re.compile( - r"\b(aws_lc_rs|ring)::|\bcrypto::aws_lc::|tls-aws-lc|tls-rustls-aws-lc-rs|" - r'"aws[-_]lc[-_]rs"|^aws-lc-rs\s*=' -) - - -def check(root: Path) -> int: - """Scan tracked and unignored new sources without traversing build outputs.""" - paths = subprocess.check_output( - [ - "git", - "ls-files", - "--cached", - "--others", - "--exclude-standard", - "-z", - "--", - "crates", - "examples", - "e2e", - ], - cwd=root, - ) - failed = False - for name in sorted(set(paths.decode("utf-8").split("\0")) - {""}): - path = Path(name) - if "openshell-crypto" in path.parts: - continue - if path.suffix != ".rs" and path.name != "Cargo.toml": - continue - source = root / path - # Git still lists tracked files removed from the working tree. - if not source.exists(): - continue - for number, line in enumerate( - source.read_text(encoding="utf-8").splitlines(), 1 - ): - if BACKEND_USE.search(line): - print(f"{path.as_posix()}:{number}:{line}") - failed = True - if failed: - print("Direct backend use must live in openshell-crypto.", file=sys.stderr) - return int(failed) - - -if __name__ == "__main__": - sys.exit(check(Path(__file__).resolve().parents[2])) From bacab4f73e44e755cc38f51f522d43fc8cd99e68 Mon Sep 17 00:00:00 2001 From: Varsha Prasad Narsing Date: Fri, 18 Sep 2026 15:01:37 -0700 Subject: [PATCH 09/10] refactor(crypto): support independent backends and backend-free CA import Signed-off-by: Varsha Prasad Narsing --- Cargo.lock | 190 ++- Cargo.toml | 4 +- architecture/build.md | 17 +- crates/openshell-binary-identity/Cargo.toml | 2 +- crates/openshell-binary-identity/src/lib.rs | 10 +- crates/openshell-bootstrap/Cargo.toml | 2 +- crates/openshell-bootstrap/src/jwt.rs | 2 +- crates/openshell-bootstrap/src/pki.rs | 8 +- crates/openshell-cli/Cargo.toml | 2 +- crates/openshell-cli/src/tls.rs | 6 +- crates/openshell-cli/tests/helpers/mod.rs | 16 +- crates/openshell-core/Cargo.toml | 2 +- crates/openshell-core/src/driver_utils.rs | 6 +- crates/openshell-core/src/jwt.rs | 5 +- crates/openshell-crypto/Cargo.toml | 24 +- crates/openshell-crypto/README.md | 102 +- crates/openshell-crypto/src/aws_lc.rs | 188 ++- crates/openshell-crypto/src/lib.rs | 126 +- crates/openshell-crypto/src/pki.rs | 221 ++- crates/openshell-crypto/src/pki/issuer.rs | 96 ++ crates/openshell-crypto/src/tls.rs | 52 +- .../tests/context_selection.rs | 64 +- .../tests/independent_backend.rs | 217 +++ crates/openshell-crypto/tests/tls_default.rs | 2 + crates/openshell-crypto/tests/tls_embedder.rs | 6 + .../openshell-driver-db-credstore/Cargo.toml | 2 +- .../Cargo.toml | 2 +- crates/openshell-driver-kubernetes/Cargo.toml | 2 +- .../src/sandbox_runtime.rs | 7 +- crates/openshell-driver-mxc/Cargo.toml | 2 +- crates/openshell-driver-vault/Cargo.toml | 2 +- crates/openshell-driver-vault/src/lib.rs | 23 +- crates/openshell-extension-core/Cargo.toml | 2 +- .../openshell-extension-core/src/transport.rs | 9 +- crates/openshell-sandbox-backend/Cargo.toml | 2 +- .../src/boundary_protocol.rs | 9 +- .../openshell-sandbox-backend/src/runtime.rs | 4 +- .../src/sandbox_auth.rs | 2 +- crates/openshell-sandbox/Cargo.toml | 2 +- .../openshell-sandbox/src/boundary_server.rs | 15 +- crates/openshell-sdk/Cargo.toml | 2 +- crates/openshell-sdk/src/transport.rs | 4 +- crates/openshell-server/Cargo.toml | 2 +- crates/openshell-server/src/auth/oidc.rs | 18 +- crates/openshell-server/src/config_file.rs | 10 +- crates/openshell-server/src/tls.rs | 76 +- crates/openshell-server/src/tls_test_utils.rs | 22 +- crates/openshell-server/tests/common/mod.rs | 46 +- .../tests/edge_tunnel_auth.rs | 4 +- .../tests/multiplex_tls_integration.rs | 2 +- .../openshell-supervisor-network/Cargo.toml | 4 +- .../src/l7/tls.rs | 78 +- .../src/procfs.rs | 8 +- .../src/upstream_proxy.rs | 13 +- crates/openshell-supervisor/Cargo.toml | 2 +- deny.toml | 2 +- e2e/rust/Cargo.lock | 1406 ++++++++++++++++- examples/governance-interceptor/Cargo.lock | 1287 ++++++++++++++- examples/governance-interceptor/Cargo.toml | 2 - examples/governance-interceptor/src/main.rs | 13 +- .../governance-interceptor/src/policy_hash.rs | 48 +- .../Cargo.lock | 1304 ++++++++++++++- tasks/test.toml | 2 + 63 files changed, 5285 insertions(+), 525 deletions(-) create mode 100644 crates/openshell-crypto/src/pki/issuer.rs create mode 100644 crates/openshell-crypto/tests/independent_backend.rs diff --git a/Cargo.lock b/Cargo.lock index a143a8e52d..9220d80ccd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -185,7 +185,7 @@ version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5493c3bedbacf7fd7382c6346bbd66687d12bbaad3a89a2d2c303ee6cf20b048" dependencies = [ - "asn1-rs-derive", + "asn1-rs-derive 0.5.1", "asn1-rs-impl", "displaydoc", "nom", @@ -195,6 +195,22 @@ dependencies = [ "time", ] +[[package]] +name = "asn1-rs" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7f43a50ac4fdca5df8e885c21b835997f0a1cdee65494a6847694a98652d9d8" +dependencies = [ + "asn1-rs-derive 0.6.0", + "asn1-rs-impl", + "displaydoc", + "nom", + "num-traits", + "rusticata-macros", + "thiserror 2.0.18", + "time", +] + [[package]] name = "asn1-rs-derive" version = "0.5.1" @@ -207,6 +223,18 @@ dependencies = [ "synstructure", ] +[[package]] +name = "asn1-rs-derive" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3109e49b1e4909e9db6515a30c633684d68cdeaa252f215214cb4fa1a5bfee2c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", + "synstructure", +] + [[package]] name = "asn1-rs-impl" version = "0.2.0" @@ -636,7 +664,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "31b698c5f9a010f6573133b09e0de5408834d0c82f8d7475a89fc1867a71cd90" dependencies = [ "axum-core", - "base64", + "base64 0.22.1", "bytes", "form_urlencoded", "futures-util", @@ -737,6 +765,12 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +[[package]] +name = "base64" +version = "0.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac07cdecf99051d9a5238b80f35af32cdeba5b336e55d957b318b50137e18da5" + [[package]] name = "base64-simd" version = "0.8.0" @@ -764,6 +798,15 @@ dependencies = [ "sha2 0.11.0", ] +[[package]] +name = "bit-vec" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b71798fca2c1fe1086445a7258a4bc81e6e49dcd24c8d0dd9a1e57395b603f51" +dependencies = [ + "serde", +] + [[package]] name = "bitflags" version = "1.3.2" @@ -832,7 +875,7 @@ version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ee04c4c84f1f811b017f2fbb7dd8815c976e7ca98593de9c1e2afad0f636bff4" dependencies = [ - "base64", + "base64 0.22.1", "bollard-stubs", "bytes", "futures-core", @@ -1555,7 +1598,21 @@ version = "9.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5cd0a5c643689626bec213c4d8bd4d96acc8ffdb4ad4bb6bc16abf27d5f4b553" dependencies = [ - "asn1-rs", + "asn1-rs 0.6.2", + "displaydoc", + "nom", + "num-bigint", + "num-traits", + "rusticata-macros", +] + +[[package]] +name = "der-parser" +version = "10.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07da5016415d5a3c4dd39b11ed26f915f52fc4e0dc197d87908bc916e51bc1a6" +dependencies = [ + "asn1-rs 0.7.2", "displaydoc", "nom", "num-bigint", @@ -2361,7 +2418,7 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b3314d5adb5d94bcdf56771f2e50dbbc80bb4bdf88967526706205ac9eff24eb" dependencies = [ - "base64", + "base64 0.22.1", "bytes", "headers-core", "http 1.4.0", @@ -2659,7 +2716,7 @@ version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0" dependencies = [ - "base64", + "base64 0.22.1", "bytes", "futures-channel", "futures-util", @@ -3135,14 +3192,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0529410abe238729a60b108898784df8984c87f6054c9c4fcacc47e4803c1ce1" dependencies = [ "aws-lc-rs", - "base64", + "base64 0.22.1", "ed25519-dalek 2.2.0", "getrandom 0.2.17", "hmac 0.12.1", "js-sys", "p256 0.13.2", "p384 0.13.1", - "pem", + "pem 3.0.6", "rand 0.8.6", "rsa 0.9.10", "serde", @@ -3158,7 +3215,7 @@ version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2c75b990324f09bef15e791606b7b7a296d02fc88a344f6eba9390970a870ad5" dependencies = [ - "base64", + "base64 0.22.1", "chrono", "serde", "serde-value", @@ -3239,7 +3296,7 @@ version = "0.99.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fc2ed952042df20d15ac2fe9614d0ec14b6118eab89633985d4b36e688dccf1" dependencies = [ - "base64", + "base64 0.22.1", "bytes", "chrono", "either", @@ -3256,7 +3313,7 @@ dependencies = [ "jsonpath-rust", "k8s-openapi", "kube-core", - "pem", + "pem 3.0.6", "rustls", "secrecy", "serde", @@ -3517,7 +3574,7 @@ version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3589659543c04c7dc5526ec858591015b87cd8746583b51b48ef4353f99dbcda" dependencies = [ - "base64", + "base64 0.22.1", "http-body-util", "hyper", "hyper-util", @@ -3833,7 +3890,7 @@ version = "5.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51e219e79014df21a225b1860a479e2dcd7cbd9130f4defd4bd0e191ea31d67d" dependencies = [ - "base64", + "base64 0.22.1", "chrono", "getrandom 0.2.17", "http 1.4.0", @@ -3905,7 +3962,16 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8d8034d9489cdaf79228eb9f6a3b8d7bb32ba00d6645ebd48eef4077ceb5bd9" dependencies = [ - "asn1-rs", + "asn1-rs 0.6.2", +] + +[[package]] +name = "oid-registry" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12f40cff3dde1b6087cc5d5f5d4d65712f34016a03ed60e9c08dcc392736b5b7" +dependencies = [ + "asn1-rs 0.7.2", ] [[package]] @@ -3939,8 +4005,8 @@ checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" name = "openshell-binary-identity" version = "0.0.0" dependencies = [ + "openshell-crypto", "openshell-isolation-interface", - "sha2 0.10.9", ] [[package]] @@ -3957,7 +4023,7 @@ dependencies = [ "tempfile", "tokio", "tracing", - "x509-parser", + "x509-parser 0.16.0", ] [[package]] @@ -3965,7 +4031,7 @@ name = "openshell-cli" version = "0.0.0" dependencies = [ "anyhow", - "base64", + "base64 0.22.1", "bytes", "chrono", "clap", @@ -4041,7 +4107,7 @@ name = "openshell-core" version = "0.0.0" dependencies = [ "async-trait", - "base64", + "base64 0.22.1", "chrono", "glob", "ipnet", @@ -4086,6 +4152,7 @@ dependencies = [ "jsonwebtoken", "k8s-openapi", "kube", + "pem 3.0.6", "rcgen", "rustls", "serde", @@ -4093,6 +4160,7 @@ dependencies = [ "sqlx", "thiserror 2.0.18", "tonic", + "x509-parser 0.18.1", ] [[package]] @@ -4100,7 +4168,7 @@ name = "openshell-driver-db-credstore" version = "0.0.0" dependencies = [ "async-trait", - "base64", + "base64 0.22.1", "futures", "openshell-core", "openshell-crypto", @@ -4214,7 +4282,7 @@ dependencies = [ name = "openshell-driver-mxc" version = "0.0.0" dependencies = [ - "base64", + "base64 0.22.1", "futures", "noyalib", "openshell-core", @@ -4301,7 +4369,7 @@ dependencies = [ name = "openshell-driver-vm" version = "0.0.0" dependencies = [ - "base64", + "base64 0.22.1", "bollard", "clap", "flate2", @@ -4537,7 +4605,7 @@ version = "0.0.0" dependencies = [ "anyhow", "async-trait", - "base64", + "base64 0.22.1", "bytes", "capctl", "clap", @@ -4642,7 +4710,7 @@ dependencies = [ "aws-config", "aws-sdk-sts", "axum", - "base64", + "base64 0.22.1", "bytes", "chrono", "clap", @@ -4723,7 +4791,7 @@ dependencies = [ "url", "uuid", "wiremock", - "x509-parser", + "x509-parser 0.16.0", ] [[package]] @@ -4812,7 +4880,7 @@ dependencies = [ "aws-credential-types", "aws-sigv4", "aws-smithy-runtime-api", - "base64", + "base64 0.22.1", "bytes", "flate2", "futures", @@ -4865,7 +4933,7 @@ version = "0.0.0" dependencies = [ "anyhow", "async-trait", - "base64", + "base64 0.22.1", "bytes", "hex", "libc", @@ -4891,7 +4959,7 @@ dependencies = [ name = "openshell-tui" version = "0.0.0" dependencies = [ - "base64", + "base64 0.22.1", "crossterm 0.28.1", "futures", "indexmap", @@ -5167,7 +5235,17 @@ version = "3.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d30c53c26bc5b31a98cd02d20f25a7c8567146caf63ed593a9d87b2775291be" dependencies = [ - "base64", + "base64 0.22.1", + "serde_core", +] + +[[package]] +name = "pem" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d354a98a3d1251555de99e8fdd8afda05573c31b82f59063a7b0a29b5527f120" +dependencies = [ + "base64 0.23.1", "serde_core", ] @@ -5576,7 +5654,7 @@ version = "0.16.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "01b80ea363c31af2de2b92e3c07ed1156628f7838c4afb4df75ee78a37fedbd1" dependencies = [ - "base64", + "base64 0.22.1", "prost", "prost-types", "serde", @@ -5894,15 +5972,15 @@ dependencies = [ [[package]] name = "rcgen" -version = "0.13.2" +version = "0.14.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75e669e5202259b5314d1ea5397316ad400819437857b90861765f24c4cf80a2" +checksum = "8774e05a7d0de114588e6a28fe7e71694b82614ed569d86d8b389dfbc98b8ad8" dependencies = [ "aws-lc-rs", - "pem", + "pem 4.0.0", "rustls-pki-types", "time", - "x509-parser", + "x509-parser 0.18.1", "yasna", ] @@ -5985,7 +6063,7 @@ version = "0.12.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147" dependencies = [ - "base64", + "base64 0.22.1", "bytes", "futures-channel", "futures-core", @@ -6026,7 +6104,7 @@ version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab3f43e3283ab1488b624b44b0e988d0acea0b3214e694730a055cb6b2efa801" dependencies = [ - "base64", + "base64 0.22.1", "bytes", "futures-core", "futures-util", @@ -6969,7 +7047,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05b44e85bf579a8eeb4ceaa77a3a523baf2bf0e9bac7e40f405d537b5d2d5ccb" dependencies = [ - "base64", + "base64 0.22.1", "bytes", "cfg-if", "crc", @@ -7071,7 +7149,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "87a2bdd6e83f6b3ea525ca9fee568030508b58355a43d0b2c1674d5f79dcd65e" dependencies = [ "atoi", - "base64", + "base64 0.22.1", "bitflags 2.11.1", "byteorder", "crc", @@ -7667,7 +7745,7 @@ checksum = "ac2a5518c70fa84342385732db33fb3f44bc4cc748936eb5833d2df34d6445ef" dependencies = [ "async-trait", "axum", - "base64", + "base64 0.22.1", "bytes", "h2", "http 1.4.0", @@ -7765,7 +7843,7 @@ version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8" dependencies = [ - "base64", + "base64 0.22.1", "bitflags 2.11.1", "bytes", "futures-util", @@ -7793,7 +7871,7 @@ version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6511f1f32c7cb7fd4525edc0eb4dcf307db8f7eceb2833ab24a37b4cc10cda61" dependencies = [ - "base64", + "base64 0.22.1", "serde", "serde_json", "thiserror 2.0.18", @@ -8784,7 +8862,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08db1edfb05d9b3c1542e521aea074442088292f00b5f28e435c714a98f85031" dependencies = [ "assert-json-diff", - "base64", + "base64 0.22.1", "deadpool", "futures", "http 1.4.0", @@ -8917,18 +8995,35 @@ version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fcbc162f30700d6f3f82a24bf7cc62ffe7caea42c0b2cba8bf7f3ae50cf51f69" dependencies = [ - "asn1-rs", + "asn1-rs 0.6.2", "data-encoding", - "der-parser", + "der-parser 9.0.0", "lazy_static", "nom", - "oid-registry", - "ring", + "oid-registry 0.7.1", "rusticata-macros", "thiserror 1.0.69", "time", ] +[[package]] +name = "x509-parser" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d43b0f71ce057da06bc0851b23ee24f3f86190b07203dd8f567d0b706a185202" +dependencies = [ + "asn1-rs 0.7.2", + "aws-lc-rs", + "data-encoding", + "der-parser 10.0.0", + "lazy_static", + "nom", + "oid-registry 0.8.1", + "rusticata-macros", + "thiserror 2.0.18", + "time", +] + [[package]] name = "xattr" version = "1.6.1" @@ -8953,10 +9048,11 @@ checksum = "7008a9d8ba97a7e47d9b2df63fcdb8dade303010c5a7cd5bf2469d4da6eba673" [[package]] name = "yasna" -version = "0.5.2" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e17bb3549cc1321ae1296b9cdc2698e2b6cb1992adfa19a8c72e5b7a738f44cd" +checksum = "b5f6765e852b9b4dc8e2a76843e4d64d1cea8e79bcde0b6901aea8e7c7f08282" dependencies = [ + "bit-vec", "time", ] diff --git a/Cargo.toml b/Cargo.toml index a1bdfc6cf0..d37420d6d5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,6 +13,8 @@ license = "Apache-2.0" repository = "https://github.com/NVIDIA/OpenShell" [workspace.dependencies] +# Product backend selection. Consumer crates inherit this choice. +openshell-crypto = { path = "crates/openshell-crypto", default-features = false, features = ["aws-lc"] } # Async runtime tokio = { version = "1.43", features = ["full"] } @@ -40,7 +42,7 @@ h2 = "0.4" tokio-rustls = { version = "0.26", default-features = false, features = ["logging", "tls12"] } rustls = { version = "0.23", default-features = false, features = ["std", "logging", "tls12"] } rustls-pemfile = "2" -rcgen = { version = "0.13", default-features = false, features = ["crypto", "pem", "x509-parser"] } +rcgen = { version = "0.14.10", default-features = false, features = ["pem"] } webpki-roots = "1" rustls-native-certs = "0.8" diff --git a/architecture/build.md b/architecture/build.md index 215244cf26..634cb8d15b 100644 --- a/architecture/build.md +++ b/architecture/build.md @@ -35,12 +35,21 @@ development shells provide static AWS-LC libraries. First-party crypto selection lives in `openshell-crypto`: backend-neutral primitive traits and protocol adapters preserve existing TLS, PKI, JWT, and credential-storage behavior. Application crates enable integration features on -that crate instead of naming a backend. Process-default initialization preserves -existing embedder providers; context capability reporting does not attest those -globals or dependency-owned crypto. OpenSSL and strict FIPS operation are separate -follow-up work. The crate README defines extension and coverage boundaries. +that crate instead of naming a backend. The workspace selects the default AWS-LC +feature centrally. Backend-owned signing keys support fallible export and import; +rcgen only adapts certificate encoding. Explicit context selection controls +first-party TLS configuration even after Rustls global initialization. Without +explicit selection, builders preserve embedder defaults. Capability reporting +does not attest globals or dependency-owned crypto. This boundary prepares a +system-OpenSSL backend; its proof of concept, dynamic-link packaging, and strict +FIPS operation are separate follow-up work. The crate README defines extension and coverage boundaries. Digest operations propagate backend failures through JWT and credential key-ID generation rather than requiring infallible provider operations. +Persisted CA metadata is parsed by `openshell-crypto` using `x509-parser` +without verification features. rcgen's parser feature remains disabled because +it couples parsing to built-in CSR verification backends. Backend keys implement +rcgen's signing trait directly; the proxy checks certificate/key matching through +the selected TLS backend and retains the original CA bytes in certificate chains. SQLx uses AWS-LC with native certificate roots. The server enables diff --git a/crates/openshell-binary-identity/Cargo.toml b/crates/openshell-binary-identity/Cargo.toml index a8b8714be4..0907110b68 100644 --- a/crates/openshell-binary-identity/Cargo.toml +++ b/crates/openshell-binary-identity/Cargo.toml @@ -12,7 +12,7 @@ repository.workspace = true [dependencies] openshell-isolation-interface = { path = "../openshell-isolation-interface" } -sha2 = { workspace = true } +openshell-crypto = { workspace = true } [lints] workspace = true diff --git a/crates/openshell-binary-identity/src/lib.rs b/crates/openshell-binary-identity/src/lib.rs index eb06934eaf..80f12b7449 100644 --- a/crates/openshell-binary-identity/src/lib.rs +++ b/crates/openshell-binary-identity/src/lib.rs @@ -329,11 +329,11 @@ fn executable_path(pid: u32) -> Result { #[cfg(target_os = "linux")] fn hash_executable(pid: u32, executable: &mut std::fs::File) -> Result { - use sha2::{Digest as _, Sha256}; use std::io::Read as _; let path = format!("/proc/{pid}/exe"); - let mut digest = Sha256::new(); + let crypto_error = |error| ResolveError::Failed(format!("hash executable: {error}")); + let mut digest = openshell_crypto::sha256_digest().map_err(crypto_error)?; let mut buffer = [0_u8; 8 * 1024]; loop { let length = executable @@ -342,9 +342,11 @@ fn hash_executable(pid: u32, executable: &mut std::fs::File) -> Result Result { let keypair = openshell_crypto::pki::generate_jwt_keypair() .into_diagnostic() .wrap_err("failed to generate Ed25519 JWT signing key")?; - let signing_key_pem = keypair.serialize_pem(); + let signing_key_pem = keypair.serialize_pem().into_diagnostic()?; let public_key_pem = keypair.public_key_pem(); let kid = kid_from_public_key_der(&keypair.public_key_der())?; Ok(JwtKeyMaterial { diff --git a/crates/openshell-bootstrap/src/pki.rs b/crates/openshell-bootstrap/src/pki.rs index b9e798e461..652820b7bf 100644 --- a/crates/openshell-bootstrap/src/pki.rs +++ b/crates/openshell-bootstrap/src/pki.rs @@ -4,7 +4,7 @@ use crate::jwt::{JwtKeyMaterial, generate_jwt_key}; use miette::{IntoDiagnostic, Result, WrapErr}; use rcgen::{ - BasicConstraints, CertificateParams, DnType, Ia5String, IsCa, KeyUsagePurpose, SanType, + BasicConstraints, CertificateParams, DnType, IsCa, KeyUsagePurpose, SanType, string::Ia5String, }; use std::net::IpAddr; @@ -121,11 +121,11 @@ pub fn generate_pki(extra_sans: &[String]) -> Result { Ok(PkiBundle { ca_cert_pem: ca_cert.pem(), - ca_key_pem: ca_key.serialize_pem(), + ca_key_pem: ca_key.serialize_pem().into_diagnostic()?, server_cert_pem: server_cert.pem(), - server_key_pem: server_key.serialize_pem(), + server_key_pem: server_key.serialize_pem().into_diagnostic()?, client_cert_pem: client_cert.pem(), - client_key_pem: client_key.serialize_pem(), + client_key_pem: client_key.serialize_pem().into_diagnostic()?, jwt_signing_key_pem, jwt_public_key_pem, jwt_key_id, diff --git a/crates/openshell-cli/Cargo.toml b/crates/openshell-cli/Cargo.toml index d3ab917f2d..8ce7e02cb2 100644 --- a/crates/openshell-cli/Cargo.toml +++ b/crates/openshell-cli/Cargo.toml @@ -15,7 +15,7 @@ name = "openshell" path = "src/main.rs" [dependencies] -openshell-crypto = { path = "../openshell-crypto", features = ["tls-hyper"] } +openshell-crypto = { workspace = true, features = ["tls-hyper"] } openshell-bootstrap = { path = "../openshell-bootstrap" } openshell-core = { path = "../openshell-core", default-features = false } openshell-policy = { path = "../openshell-policy" } diff --git a/crates/openshell-cli/src/tls.rs b/crates/openshell-cli/src/tls.rs index 8ac64298fe..aa2acf3dae 100644 --- a/crates/openshell-cli/src/tls.rs +++ b/crates/openshell-cli/src/tls.rs @@ -215,7 +215,7 @@ pub fn build_rustls_config(materials: &TlsMaterials) -> Result Vec { - openshell_crypto::tls::provider() + openshell_crypto::tls::configuration_provider() .signature_verification_algorithms .supported_schemes() } @@ -324,7 +324,7 @@ impl tower::Service for InsecureTlsConnector { } pub fn build_insecure_rustls_config() -> Result { - let config = rustls::ClientConfig::builder() + let config = openshell_crypto::tls::client_builder() .dangerous() .with_custom_certificate_verifier(std::sync::Arc::new(InsecureServerCertVerifier)) .with_no_client_auth(); diff --git a/crates/openshell-cli/tests/helpers/mod.rs b/crates/openshell-cli/tests/helpers/mod.rs index d5d7a9cf1c..0cdca2d0bb 100644 --- a/crates/openshell-cli/tests/helpers/mod.rs +++ b/crates/openshell-cli/tests/helpers/mod.rs @@ -111,9 +111,9 @@ macro_rules! unimplemented_sandbox_template_rpcs { }; } -use rcgen::{ - BasicConstraints, Certificate, CertificateParams, ExtendedKeyUsagePurpose, IsCa, KeyPair, -}; +use openshell_crypto::pki::Certificate; +use openshell_crypto::pki::KeyPair; +use rcgen::{BasicConstraints, CertificateParams, ExtendedKeyUsagePurpose, IsCa}; // ── EnvVarGuard ────────────────────────────────────────────────────────────── @@ -180,7 +180,7 @@ pub fn build_ca() -> (Certificate, KeyPair) { let key_pair = openshell_crypto::pki::generate_keypair().unwrap(); let mut params = CertificateParams::new(Vec::::new()).unwrap(); params.is_ca = IsCa::Ca(BasicConstraints::Unconstrained); - let cert = params.self_signed(&key_pair).unwrap(); + let cert = openshell_crypto::pki::self_signed(params, &key_pair).unwrap(); (cert, key_pair) } @@ -192,8 +192,8 @@ pub fn build_server_cert(ca: &Certificate, ca_key: &KeyPair) -> (String, String) let key_pair = openshell_crypto::pki::generate_keypair().unwrap(); let mut params = CertificateParams::new(vec!["localhost".to_string()]).unwrap(); params.extended_key_usages = vec![ExtendedKeyUsagePurpose::ServerAuth]; - let cert = params.signed_by(&key_pair, ca, ca_key).unwrap(); - (cert.pem(), key_pair.serialize_pem()) + let cert = openshell_crypto::pki::signed_by(params, &key_pair, ca, ca_key).unwrap(); + (cert.pem(), key_pair.serialize_pem().unwrap()) } /// Generate a client authentication certificate signed by `ca`. @@ -204,6 +204,6 @@ pub fn build_client_cert(ca: &Certificate, ca_key: &KeyPair) -> (String, String) let key_pair = openshell_crypto::pki::generate_keypair().unwrap(); let mut params = CertificateParams::new(Vec::::new()).unwrap(); params.extended_key_usages = vec![ExtendedKeyUsagePurpose::ClientAuth]; - let cert = params.signed_by(&key_pair, ca, ca_key).unwrap(); - (cert.pem(), key_pair.serialize_pem()) + let cert = openshell_crypto::pki::signed_by(params, &key_pair, ca, ca_key).unwrap(); + (cert.pem(), key_pair.serialize_pem().unwrap()) } diff --git a/crates/openshell-core/Cargo.toml b/crates/openshell-core/Cargo.toml index f96f0889b8..419cf8dc77 100644 --- a/crates/openshell-core/Cargo.toml +++ b/crates/openshell-core/Cargo.toml @@ -11,7 +11,7 @@ license.workspace = true repository.workspace = true [dependencies] -openshell-crypto = { path = "../openshell-crypto", features = ["tls-tonic"] } +openshell-crypto = { workspace = true, features = ["tls-tonic"] } async-trait = "0.1" openshell-extension-core = { path = "../openshell-extension-core" } openshell-policy-schema = { path = "../openshell-policy-schema" } diff --git a/crates/openshell-core/src/driver_utils.rs b/crates/openshell-core/src/driver_utils.rs index 33bff374e5..67bd227f6a 100644 --- a/crates/openshell-core/src/driver_utils.rs +++ b/crates/openshell-core/src/driver_utils.rs @@ -1223,8 +1223,10 @@ mod tests { fn ca_bundle_file_accepts_a_real_certificate() { // The positive case that pins host acceptance to guest acceptance: // what the driver stages is exactly what rustls will trust. - let cert = rcgen::generate_simple_self_signed(vec!["proxy.corp.example".to_string()]) - .expect("test CA"); + let cert = openshell_crypto::pki::generate_simple_self_signed(vec![ + "proxy.corp.example".to_string(), + ]) + .expect("test CA"); let dir = tempfile::tempdir().unwrap(); let path = dir.path().join("proxy-ca.pem"); std::fs::write(&path, cert.cert.pem()).unwrap(); diff --git a/crates/openshell-core/src/jwt.rs b/crates/openshell-core/src/jwt.rs index e968493792..00ce6d52d4 100644 --- a/crates/openshell-core/src/jwt.rs +++ b/crates/openshell-core/src/jwt.rs @@ -922,7 +922,7 @@ mod tests { let public_key_pem = key.public_key_pem().into_bytes(); let clock: Arc = Arc::new(FixedClock(1_900_000_000)); let issuer = SessionJwtIssuer::from_ed25519_pem( - key.serialize_pem().as_bytes(), + key.serialize_pem().unwrap().as_bytes(), "current", "test", DEFAULT_SESSION_TOKEN_TTL, @@ -1067,7 +1067,8 @@ mod tests { let token = encode( &header, &claims, - &EncodingKey::from_ed_pem(key.serialize_pem().as_bytes()).expect("encoding key"), + &EncodingKey::from_ed_pem(key.serialize_pem().unwrap().as_bytes()) + .expect("encoding key"), ) .expect("token"); assert_eq!(verifier.verify(&token), Err(SessionJwtError::InvalidToken)); diff --git a/crates/openshell-crypto/Cargo.toml b/crates/openshell-crypto/Cargo.toml index 050af7637c..a85cb079a5 100644 --- a/crates/openshell-crypto/Cargo.toml +++ b/crates/openshell-crypto/Cargo.toml @@ -11,12 +11,14 @@ license.workspace = true repository.workspace = true [features] -# Dependencies that select their own provider must be configured as well as -# first-party calls. Consumers enable these integration features, never a backend. -tls-tonic = ["dep:tonic", "tonic/tls-aws-lc"] -tls-hyper = ["dep:hyper-rustls", "hyper-rustls/aws-lc-rs"] -tls-kube = ["dep:kube", "dep:k8s-openapi", "kube/aws-lc-rs"] -tls-sqlx = ["dep:sqlx", "sqlx/tls-rustls-aws-lc-rs"] +# Only this feature selects the default backend. With defaults disabled an +# embedder must install its backend before any crypto operation. +default = ["aws-lc"] +aws-lc = ["dep:aws-lc-rs", "rustls/aws_lc_rs", "rcgen/aws_lc_rs", "jsonwebtoken/aws_lc_rs", "tonic?/tls-aws-lc", "hyper-rustls?/aws-lc-rs", "kube?/aws-lc-rs", "sqlx?/tls-rustls-aws-lc-rs"] +tls-tonic = ["dep:tonic"] +tls-hyper = ["dep:hyper-rustls"] +tls-kube = ["dep:kube", "dep:k8s-openapi"] +tls-sqlx = ["dep:sqlx"] [dependencies] tonic = { workspace = true, optional = true } @@ -25,10 +27,12 @@ kube = { workspace = true, optional = true } k8s-openapi = { workspace = true, optional = true } sqlx = { workspace = true, optional = true } -aws-lc-rs = { workspace = true } -rustls = { workspace = true, features = ["aws_lc_rs"] } -rcgen = { workspace = true, features = ["aws_lc_rs"] } -jsonwebtoken = { workspace = true, features = ["aws_lc_rs"] } +aws-lc-rs = { workspace = true, optional = true } +rustls = { workspace = true } +rcgen = { workspace = true } +jsonwebtoken = { workspace = true } +pem = "3" +x509-parser = { version = "0.18.1", default-features = false } serde = { workspace = true } thiserror = { workspace = true } diff --git a/crates/openshell-crypto/README.md b/crates/openshell-crypto/README.md index cca566396f..b2a70f0d9e 100644 --- a/crates/openshell-crypto/README.md +++ b/crates/openshell-crypto/README.md @@ -3,7 +3,10 @@ `openshell-crypto` owns first-party crypto backend selection. AWS-LC is the only production implementation. This change preserves TLS algorithms, Ed25519 gateway JWTs, P-256 certificate keys, native trust roots, and credential envelope formats. -It does not introduce OpenSSL or a FIPS build mode. +The interface is intended to support a system-OpenSSL backend for regulated +deployments, related to [#900](https://github.com/NVIDIA/OpenShell/issues/900). +This stage implements AWS-LC only. An OpenSSL proof of concept will validate the +provider integration separately; this is not a FIPS build or compliance claim. ## Boundaries @@ -19,36 +22,73 @@ the one-shot SHA-256 helper propagates the first failure without fallback. Callers use `aead`, `pki`, `tls`, and `jwt`, or an explicit `CryptoContext`. Certificate policy and JWT claim validation remain at their existing callers. -The rcgen adapter returns key pairs that own their signing implementation; a -future backend must supply its own implementation (for example, rcgen remote -keys) rather than silently using rcgen's compiled default. Raw signing and -verification currently use the protocol adapters, not a new general signature API. - -Shared manifests do not select a provider. Consumers of dependencies that select -their own providers enable `tls-tonic`, `tls-hyper`, `tls-kube`, or `tls-sqlx` on -this crate. Those features retain the current dependency selections and do not -make the dependencies use `CryptoContext` at runtime. Adding another backend -requires adapting these integrations as well as implementing the traits. +`pki::KeyPair` owns a backend `SigningKey` and implements rcgen 0.14's +`PublicKeyData` and `SigningKey` traits directly. +The backend generates/imports keys, signs messages, and exports PKCS#8 DER. +PEM wrapping and certificate encoding remain in the facade. Public keys expose +algorithm-specific bytes and SPKI; private exports are fallible, including for +non-exportable keys. Certificate encoding never requires private-key export. +`pki::Certificate` retains public issuance parameters separately from the encoded +certificate, allowing generated certificates to be used as issuers without +retaining private keys. Persisted proxy CAs use `pki::issuer_from_der` and keep +their original certificate bytes in issued chains. +Persisted CA keys are imported through the selected backend. Provider resources +must remain alive for the full key lifetime. +Default certificate serial numbers and key identifiers are derived through the +selected digest backend, preserving the existing SHA-256 derivation without +depending on rcgen's compiled crypto implementation. + +## Build selection + +The crate's default `aws-lc` feature selects the current implementation. The root +workspace declares that choice once in its `openshell-crypto` dependency; +application crates inherit it rather than choosing a backend independently. +Standalone examples select their own default through their path dependency. +Disabling crate defaults removes its AWS-LC implementation and requires an +explicit context before use; use without initialization fails closed with an +initialization panic. This mode is for embedders and backend contract tests, not +an independently runnable OpenShell product configuration. + +Integration features (`tls-tonic`, `tls-hyper`, `tls-kube`, `tls-sqlx`) activate +dependencies. The `aws-lc` feature supplies their AWS-LC choices conditionally. +These libraries still own their crypto selection internally; they do not consult +`CryptoContext`. Cargo feature unification does not prevent direct library use. +A second backend must adapt these integrations and the application startup path. +Disabling this crate's feature alone does not remove dependency-owned crypto +from the entire product graph. + +The later OpenSSL build must use system shared libraries without vendoring, +respect system provider configuration, and verify the resulting linked artifacts. +Linking and module qualification are build/deployment concerns, separate from the +Rust key and primitive contracts. The proof of concept will test those concerns +and the Rustls provider integration before a production OpenSSL backend is added. ## Lifecycle and posture -`default_context()` lazily selects AWS-LC. An embedder can call +`default_context()` lazily selects AWS-LC when that feature is enabled. An embedder can call `install_default_context(context)` before first use. Reinstalling a clone of the same context succeeds; installing a different context fails even if names match. There is no live backend switching. Independent contexts can be used without changing process state, including in contract tests. -`tls::provider()` constructs an explicit provider from the selected context. -`tls::ensure_default_provider()` preserves an embedder's existing process default -and returns the actual installed provider. This preserves existing SDK behavior. -It must not be used as evidence that the process default belongs to the context. +`tls::provider()` constructs the selected context's provider. +`tls::ensure_default_provider()` retains an existing Rustls process default and +returns it; it does not attest ownership. OpenShell configurations use facade +client/server builders instead of Rustls's implicit builders. If a context was +explicitly selected before facade use, these builders use that context even if +another library already initialized Rustls. Otherwise they preserve an embedder's +installed provider. Key loading, custom verification algorithms, and the gateway +client-certificate verifier use the same configuration-provider policy. +Explicit protocol-version constraints remain unchanged. A provider incompatible +with the requested versions fails during construction rather than falling back. +This rule controls first-party configs; it cannot override dependency-owned TLS. JWT initialization likewise preserves an existing process provider. `install_jwt_provider()` reports whether this call installed it; jsonwebtoken 10 has no public getter for verifying a previously installed provider. JWT adapters retain that library's algorithm/key binding and claim-validation checks. Select a -custom context before initializing either protocol library, including indirect -initialization by dependencies. Neither global provider can be replaced safely. +custom context before JWT initialization, including indirect initialization by +dependencies. Neither global provider can be replaced safely. `CryptoContext::verify_posture(false)` reports the context's capabilities, not ownership of process globals. A strict request is always rejected in this stage. @@ -71,9 +111,20 @@ scheduling randomness are not migrated. No SSH or PQC capability is asserted by the primitive capability report. OpenSSL, strict policy, module version discovery, and deployment qualification belong in follow-up work. -Durable proxy CA loading retains rcgen's PEM key import and X.509 parser. The -parser and build-time Z3 downloader retain the narrowly allowed Ring dependencies -listed in `deny.toml`; context capabilities do not attest these paths. +Durable proxy CA loading uses backend key import and `pki::issuer_from_der`. +The helper uses `x509-parser` without verification features to read the subject, +key usage, and subject key identifier. Missing identifiers use the selected +backend's SHA-256 over SPKI, truncated to 20 bytes. It rejects trailing bytes, +malformed metadata, and subject names that rcgen cannot represent without loss +(including repeated attribute OIDs and multi-valued RDNs). +Parsing does not establish trust or verify signatures; the proxy separately +checks certificate/key matching through the selected TLS backend. +rcgen's `x509-parser` feature stays disabled: in 0.14.10 it also compiles CSR +verification that requires AWS-LC or Ring. No fork or fallback backend is needed +for CA import, and the parser's former Ring exception is removed from `deny.toml`. +The standalone facade also excludes AWS-LC when default features are disabled. +The build-time Z3 archive downloader retains the narrowly allowed Rustls/Ring +wrappers in `deny.toml`; context capabilities do not attest build tools. ## Extending and checking @@ -84,7 +135,12 @@ and avoid secret-bearing diagnostics. Add protocol adapters rather than moving certificate or authorization policy into primitive implementations. Run `cargo test -p openshell-crypto` for known-answer crypto, tampering, JWT -validation, context substitution, and isolated global-provider tests. Existing -bootstrap, credential-store, gateway TLS/OIDC, and proxy tests exercise the +validation, key import/export, encryption compatibility, context substitution, +and an actual TLS handshake after process-default preemption. +`cargo test -p openshell-crypto --no-default-features --test independent_backend` +exercises independent test-only key and AEAD implementations without AWS-LC or +Ring. Inspect that boundary with +`cargo tree -p openshell-crypto --no-default-features --edges normal,build`. +Existing bootstrap, credential-store, gateway TLS/OIDC, and proxy tests exercise the migrated consumers. The cargo-deny Ring restrictions and their explicit wrapper exceptions remain in force. diff --git a/crates/openshell-crypto/src/aws_lc.rs b/crates/openshell-crypto/src/aws_lc.rs index 222a2682ff..6a6e2a667c 100644 --- a/crates/openshell-crypto/src/aws_lc.rs +++ b/crates/openshell-crypto/src/aws_lc.rs @@ -31,7 +31,12 @@ impl CryptoBackend for AwsLc { provider_version: None, fips: FipsState::NotVerified, primitives: &["CSPRNG", "SHA-256", "AES-256-GCM"], - key_algorithms: &["ECDSA-P256-SHA256", "ECDSA-P384-SHA384", "Ed25519"], + key_algorithms: &[ + "ECDSA-P256-SHA256", + "ECDSA-P384-SHA384", + "ECDSA-P521-SHA512", + "Ed25519", + ], } } fn fill_random(&self, output: &mut [u8]) -> Result<(), CryptoError> { @@ -94,10 +99,187 @@ impl ProtocolBackend for AwsLc { fn generate_keypair( &self, algorithm: &'static rcgen::SignatureAlgorithm, - ) -> Result { - rcgen::KeyPair::generate_for(algorithm) + ) -> Result { + wrap_key(rcgen::KeyPair::generate_for(algorithm)?) + } + fn import_keypair_pem(&self, pem: &str) -> Result { + wrap_key(rcgen::KeyPair::from_pem(pem)?) + } + fn import_keypair_der(&self, der: &[u8]) -> Result { + wrap_key(rcgen::KeyPair::try_from(der)?) } fn jwt_provider(&self) -> &'static jsonwebtoken::crypto::CryptoProvider { &jsonwebtoken::crypto::aws_lc::DEFAULT_PROVIDER } } + +struct Key { + material: rcgen::KeyPair, + signer: Box, +} +fn wrap_key(mut material: rcgen::KeyPair) -> Result { + use aws_lc_rs::{ + encoding::{AsDer, Pkcs8V1Der}, + signature, + }; + use rustls::{SignatureScheme, pki_types::PrivateKeyDer}; + // rcgen retains the input encoding on import. Normalize traditional RSA/EC + // inputs before exposing the facade's PKCS#8 export contract. + let input = material.serialize_der(); + let normalized = match PrivateKeyDer::try_from(input.as_slice()) + .map_err(|_| rcgen::Error::CouldNotParseKeyPair)? + { + PrivateKeyDer::Pkcs1(_) => { + let key = signature::RsaKeyPair::from_der(&input) + .map_err(|_| rcgen::Error::CouldNotParseKeyPair)?; + let encoded: Pkcs8V1Der<'static> = + key.as_der().map_err(|_| rcgen::Error::RemoteKeyError)?; + Some(encoded.as_ref().to_vec()) + } + PrivateKeyDer::Sec1(_) => { + let algorithm = match material.algorithm() { + a if a == &rcgen::PKCS_ECDSA_P256_SHA256 => { + &signature::ECDSA_P256_SHA256_ASN1_SIGNING + } + a if a == &rcgen::PKCS_ECDSA_P384_SHA384 => { + &signature::ECDSA_P384_SHA384_ASN1_SIGNING + } + a if a == &rcgen::PKCS_ECDSA_P521_SHA512 => { + &signature::ECDSA_P521_SHA512_ASN1_SIGNING + } + _ => return Err(rcgen::Error::UnsupportedSignatureAlgorithm), + }; + let key = signature::EcdsaKeyPair::from_private_key_der(algorithm, &input) + .map_err(|_| rcgen::Error::CouldNotParseKeyPair)?; + Some( + key.to_pkcs8v1() + .map_err(|_| rcgen::Error::RemoteKeyError)? + .as_ref() + .to_vec(), + ) + } + PrivateKeyDer::Pkcs8(_) => None, + _ => return Err(rcgen::Error::CouldNotParseKeyPair), + }; + if let Some(der) = normalized { + material = rcgen::KeyPair::try_from(der.as_slice())?; + } + let scheme = match material.algorithm() { + a if a == &rcgen::PKCS_ED25519 => SignatureScheme::ED25519, + a if a == &rcgen::PKCS_ECDSA_P256_SHA256 => SignatureScheme::ECDSA_NISTP256_SHA256, + a if a == &rcgen::PKCS_ECDSA_P384_SHA384 => SignatureScheme::ECDSA_NISTP384_SHA384, + a if a == &rcgen::PKCS_ECDSA_P521_SHA512 => SignatureScheme::ECDSA_NISTP521_SHA512, + a if a == &rcgen::PKCS_RSA_SHA256 => SignatureScheme::RSA_PKCS1_SHA256, + a if a == &rcgen::PKCS_RSA_SHA384 => SignatureScheme::RSA_PKCS1_SHA384, + a if a == &rcgen::PKCS_RSA_SHA512 => SignatureScheme::RSA_PKCS1_SHA512, + _ => return Err(rcgen::Error::UnsupportedSignatureAlgorithm), + }; + let der = rustls::pki_types::PrivatePkcs8KeyDer::from(material.serialize_der()); + let signer = rustls::crypto::aws_lc_rs::sign::any_supported_type(&der.into()) + .map_err(|_| rcgen::Error::RemoteKeyError)? + .choose_scheme(&[scheme]) + .ok_or(rcgen::Error::UnsupportedSignatureAlgorithm)?; + crate::pki::KeyPair::new(Box::new(Key { material, signer })) +} +impl crate::pki::SigningKey for Key { + fn algorithm(&self) -> &'static rcgen::SignatureAlgorithm { + self.material.algorithm() + } + fn public_key_raw(&self) -> &[u8] { + self.material.public_key_raw() + } + fn sign(&self, message: &[u8]) -> Result, rcgen::Error> { + self.signer + .sign(message) + .map_err(|_| rcgen::Error::RemoteKeyError) + } + fn export_pkcs8_der(&self) -> Result, rcgen::Error> { + Ok(self.material.serialize_der()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use rustls::client::danger::ServerCertVerifier as _; + #[test] + fn exported_keys_round_trip_and_sign_certificates() { + for algorithm in [ + &rcgen::PKCS_ECDSA_P256_SHA256, + &rcgen::PKCS_ECDSA_P384_SHA384, + &rcgen::PKCS_ED25519, + &rcgen::PKCS_ECDSA_P521_SHA512, + ] { + let native = rcgen::KeyPair::generate_for(algorithm).unwrap(); + let native_pem = native.serialize_pem(); + let key = wrap_key(native).unwrap(); + assert_eq!(key.serialize_pem().unwrap(), native_pem); + let der = key.serialize_der().unwrap(); + let pem = key.serialize_pem().unwrap(); + let imported = AwsLc.import_keypair_pem(&pem).unwrap(); + let imported_der = AwsLc.import_keypair_der(&der).unwrap(); + assert_eq!(imported.public_key_der(), key.public_key_der()); + assert_eq!(imported_der.serialize_der().unwrap(), der); + assert_eq!(imported.serialize_pem().unwrap(), pem); + let cert = crate::pki::self_signed( + rcgen::CertificateParams::new(vec!["localhost".into()]).unwrap(), + &imported, + ) + .unwrap(); + let mut roots = rustls::RootCertStore::empty(); + roots.add(cert.der().clone()).unwrap(); + let verifier = rustls::client::WebPkiServerVerifier::builder_with_provider( + std::sync::Arc::new(roots), + std::sync::Arc::new(AwsLc.tls_provider()), + ) + .build() + .unwrap(); + verifier + .verify_server_cert( + cert.der(), + &[], + &"localhost".try_into().unwrap(), + &[], + rustls::pki_types::UnixTime::now(), + ) + .unwrap(); + } + } + #[test] + fn imports_traditional_ec_keys_and_exports_pkcs8() { + use aws_lc_rs::{encoding::AsDer, signature}; + let native = + signature::EcdsaKeyPair::generate(&signature::ECDSA_P256_SHA256_ASN1_SIGNING).unwrap(); + let sec1 = native.private_key().as_der().unwrap(); + let encoded = pem::encode(&pem::Pem::new("EC PRIVATE KEY", sec1.as_ref())); + let imported = AwsLc.import_keypair_pem(&encoded).unwrap(); + let exported = imported.serialize_der().unwrap(); + assert!(matches!( + rustls::pki_types::PrivateKeyDer::try_from(exported.as_slice()).unwrap(), + rustls::pki_types::PrivateKeyDer::Pkcs8(_) + )); + let reimported = AwsLc.import_keypair_der(&exported).unwrap(); + assert_eq!(imported.public_key_der(), reimported.public_key_der()); + } + #[test] + fn encryption_output_matches_the_previous_ciphertext_layout() { + for plaintext in [b"".as_slice(), b"credential plaintext".as_slice()] { + let key = [0x11; 32]; + let aad = b"record identity"; + let sealed = crate::aead::seal(&key, aad, plaintext).unwrap(); + // Independent legacy API invocation, using the returned random nonce. + // This checks encryption bytes, not a round-trip through our decryptor. + let legacy = + aead::LessSafeKey::new(aead::UnboundKey::new(&aead::AES_256_GCM, &key).unwrap()); + let mut expected = plaintext.to_vec(); + legacy + .seal_in_place_append_tag( + aead::Nonce::assume_unique_for_key(sealed.nonce), + aead::Aad::from(aad), + &mut expected, + ) + .unwrap(); + assert_eq!(sealed.ciphertext, expected); + } + } +} diff --git a/crates/openshell-crypto/src/lib.rs b/crates/openshell-crypto/src/lib.rs index 4fd7fa3bdc..31a49488e2 100644 --- a/crates/openshell-crypto/src/lib.rs +++ b/crates/openshell-crypto/src/lib.rs @@ -5,9 +5,12 @@ //! //! AWS-LC is the only production implementation in this first stage. This crate //! does not enable FIPS mode, change algorithms, or attest dependency-owned crypto. -//! See the crate README for initialization and extension boundaries. +//! The extension target is a system-OpenSSL backend for regulated deployments +//! (). See the crate README for +//! initialization, key ownership, and dependency coverage boundaries. pub mod aead; +#[cfg(feature = "aws-lc")] mod aws_lc; pub mod jwt; pub mod pki; @@ -99,7 +102,7 @@ pub trait CryptoBackend: Send + Sync { /// Adapters for the protocol libraries currently used by `OpenShell`. /// /// A follow-up backend must implement these as well as the primitive contract. -/// Returning rcgen/rustls/jsonwebtoken types does not expose AWS-LC types. +/// Keys retain backend ownership; protocol parameters do not expose AWS-LC types. pub trait ProtocolBackend: CryptoBackend { /// Construct the full TLS provider, including certificate verification. fn tls_provider(&self) -> rustls::crypto::CryptoProvider; @@ -107,7 +110,11 @@ pub trait ProtocolBackend: CryptoBackend { fn generate_keypair( &self, algorithm: &'static rcgen::SignatureAlgorithm, - ) -> Result; + ) -> Result; + /// Import a persisted PEM private key using this backend. + fn import_keypair_pem(&self, pem: &str) -> Result; + /// Import a persisted PKCS#8 DER private key using this backend. + fn import_keypair_der(&self, der: &[u8]) -> Result; /// JWT signing, verification, and JWK operations; claims validation stays in jsonwebtoken. fn jwt_provider(&self) -> &'static jsonwebtoken::crypto::CryptoProvider; } @@ -145,29 +152,59 @@ impl CryptoContext { } } +#[cfg(feature = "aws-lc")] impl Default for CryptoContext { fn default() -> Self { Self::new(Box::new(aws_lc::AwsLc)) } } -static DEFAULT: OnceLock = OnceLock::new(); +struct DefaultContext { + context: CryptoContext, + explicit: bool, +} +static DEFAULT: OnceLock = OnceLock::new(); + +pub(crate) fn explicitly_selected() -> bool { + DEFAULT.get().is_some_and(|selected| selected.explicit) +} /// Application default, initialized lazily to AWS-LC unless selected before first use. #[must_use] pub fn default_context() -> &'static CryptoContext { - DEFAULT.get_or_init(CryptoContext::default) + #[cfg(feature = "aws-lc")] + { + &DEFAULT + .get_or_init(|| DefaultContext { + context: CryptoContext::default(), + explicit: false, + }) + .context + } + #[cfg(not(feature = "aws-lc"))] + { + &DEFAULT + .get() + .expect("install a crypto context before use when no default backend is built") + .context + } } /// Select a context before the first application crypto operation. /// /// Reinstalling a clone of the same context is idempotent. A different context /// fails even if it reports the same backend name. This does not replace existing -/// Rustls or JWT globals: embedders must select before initializing those libraries. +/// Rustls or JWT globals. Select before facade use and before JWT initialization; +/// explicit TLS builders can override an already initialized Rustls global. pub fn install_default_context(context: CryptoContext) -> Result<(), CryptoError> { - match DEFAULT.set(context) { + match DEFAULT.set(DefaultContext { + context, + explicit: true, + }) { Ok(()) => Ok(()), - Err(context) if Arc::ptr_eq(&default_context().backend, &context.backend) => Ok(()), + Err(selected) if Arc::ptr_eq(&default_context().backend, &selected.context.backend) => { + Ok(()) + } Err(_) => Err(CryptoError::ProviderConflict), } } @@ -209,7 +246,7 @@ pub fn install_jwt_provider() -> bool { .is_ok() } -#[cfg(test)] +#[cfg(all(test, feature = "aws-lc"))] mod tests { use super::*; @@ -269,10 +306,12 @@ mod tests { #[test] fn jwt_preserves_eddsa_and_claim_validation() { + use jsonwebtoken::errors::ErrorKind; let key = pki::generate_jwt_keypair().unwrap(); assert_eq!(key.algorithm(), &rcgen::PKCS_ED25519); let signing = - jsonwebtoken::EncodingKey::from_ed_pem(key.serialize_pem().as_bytes()).unwrap(); + jsonwebtoken::EncodingKey::from_ed_pem(key.serialize_pem().unwrap().as_bytes()) + .unwrap(); let verifying = jsonwebtoken::DecodingKey::from_ed_pem(key.public_key_pem().as_bytes()).unwrap(); let header = jsonwebtoken::Header::new(jsonwebtoken::Algorithm::EdDSA); @@ -283,10 +322,61 @@ mod tests { let decoded = jwt::decode::(&token, &verifying, &validation).unwrap(); assert_eq!(decoded.claims, claims); validation.set_issuer(&["different"]); - assert!(jwt::decode::(&token, &verifying, &validation).is_err()); - let expired = jwt::encode(&header, &serde_json::json!({"exp":1}), &signing).unwrap(); - assert!(jwt::decode::(&expired, &verifying, &validation).is_err()); - assert!(jwt::encode(&jsonwebtoken::Header::default(), &claims, &signing).is_err()); + assert_eq!( + jwt::decode::(&token, &verifying, &validation) + .unwrap_err() + .kind(), + &ErrorKind::InvalidIssuer + ); + validation.set_issuer(&["gateway"]); + let expired = jwt::encode( + &header, + &serde_json::json!({"iss":"gateway", "exp":1}), + &signing, + ) + .unwrap(); + assert_eq!( + jwt::decode::(&expired, &verifying, &validation) + .unwrap_err() + .kind(), + &ErrorKind::ExpiredSignature + ); + assert_eq!( + jwt::encode(&jsonwebtoken::Header::default(), &claims, &signing) + .unwrap_err() + .kind(), + &ErrorKind::InvalidAlgorithm + ); + let wrong_algorithm = jsonwebtoken::Validation::new(jsonwebtoken::Algorithm::HS256); + assert_eq!( + jwt::decode::(&token, &verifying, &wrong_algorithm) + .unwrap_err() + .kind(), + &ErrorKind::InvalidAlgorithm + ); + let audience_token = jwt::encode( + &header, + &serde_json::json!({"iss":"gateway", "aud":"other", "exp":4_000_000_000_u64}), + &signing, + ) + .unwrap(); + validation.set_audience(&["sandbox"]); + assert_eq!( + jwt::decode::(&audience_token, &verifying, &validation) + .unwrap_err() + .kind(), + &ErrorKind::InvalidAudience + ); + let (message, signature) = token.rsplit_once('.').unwrap(); + let mut signature = signature.as_bytes().to_vec(); + signature[0] = if signature[0] == b'A' { b'B' } else { b'A' }; + let tampered = format!("{message}.{}", String::from_utf8(signature).unwrap()); + assert_eq!( + jwt::decode::(&tampered, &verifying, &validation) + .unwrap_err() + .kind(), + &ErrorKind::InvalidSignature + ); } struct NoEntropy; @@ -323,7 +413,13 @@ mod tests { fn generate_keypair( &self, _: &'static rcgen::SignatureAlgorithm, - ) -> Result { + ) -> Result { + Err(rcgen::Error::KeyGenerationUnavailable) + } + fn import_keypair_pem(&self, _: &str) -> Result { + Err(rcgen::Error::KeyGenerationUnavailable) + } + fn import_keypair_der(&self, _: &[u8]) -> Result { Err(rcgen::Error::KeyGenerationUnavailable) } fn jwt_provider(&self) -> &'static jsonwebtoken::crypto::CryptoProvider { diff --git a/crates/openshell-crypto/src/pki.rs b/crates/openshell-crypto/src/pki.rs index 0100fe42cf..bf6f2d4287 100644 --- a/crates/openshell-crypto/src/pki.rs +++ b/crates/openshell-crypto/src/pki.rs @@ -1,42 +1,221 @@ // SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 -//! rcgen adapter. Certificate policy remains with the caller; key operations -//! route through the selected backend. No algorithm or format migration occurs. +//! Backend-owned keys with rcgen used for certificate encoding and policy. -/// Generate the existing default ECDSA P-256 certificate key. -pub fn generate_keypair() -> Result { - generate_keypair_for(&rcgen::PKCS_ECDSA_P256_SHA256) +mod issuer; +pub use issuer::issuer_from_der; + +use std::sync::Arc; + +/// Backend-owned signing key. +/// +/// Signatures use the declared rcgen algorithm's +/// encoding (DER ECDSA or raw Ed25519/RSA). Retain provider resources for the +/// full key lifetime; failed operations must never fall back to another backend. +pub trait SigningKey: Send + Sync { + /// Certificate signing algorithm. + fn algorithm(&self) -> &'static rcgen::SignatureAlgorithm; + /// Algorithm-specific public key bytes expected by rcgen remote keys. + fn public_key_raw(&self) -> &[u8]; + /// Sign an unhashed message. + fn sign(&self, message: &[u8]) -> Result, rcgen::Error>; + /// Export PKCS#8 DER, or return an error for non-exportable keys. + fn export_pkcs8_der(&self) -> Result, rcgen::Error>; +} + +/// Owns a backend key and implements rcgen's signing contract directly. +/// Private key export remains a separate, fallible backend operation. +pub struct KeyPair { + backend: Arc, +} +impl rcgen::PublicKeyData for KeyPair { + fn der_bytes(&self) -> &[u8] { + self.backend.public_key_raw() + } + fn algorithm(&self) -> &'static rcgen::SignatureAlgorithm { + self.backend.algorithm() + } +} +impl rcgen::SigningKey for KeyPair { + fn sign(&self, message: &[u8]) -> Result, rcgen::Error> { + self.backend.sign(message) + } +} + +impl KeyPair { + /// Wrap an independently implemented key without selecting crypto. + pub fn new(key: Box) -> Result { + let backend: Arc = Arc::from(key); + Ok(Self { backend }) + } + /// Import PEM through the selected backend. + pub fn from_pem(pem: &str) -> Result { + crate::default_context().backend().import_keypair_pem(pem) + } + /// Import PKCS#8 DER through the selected backend. + pub fn from_pkcs8_der(der: &[u8]) -> Result { + crate::default_context().backend().import_keypair_der(der) + } + /// Export the private key in PKCS#8 DER format, if permitted. + pub fn serialize_der(&self) -> Result, rcgen::Error> { + self.backend.export_pkcs8_der() + } + /// Export the private key in PKCS#8 PEM format, if permitted. + pub fn serialize_pem(&self) -> Result { + let line_ending = if cfg!(target_family = "windows") { + pem::LineEnding::CRLF + } else { + pem::LineEnding::LF + }; + Ok(pem::encode_config( + &pem::Pem::new("PRIVATE KEY", self.serialize_der()?), + pem::EncodeConfig::new().set_line_ending(line_ending), + )) + } + /// Public key in `SubjectPublicKeyInfo` DER format. + #[must_use] + pub fn public_key_der(&self) -> Vec { + rcgen::PublicKeyData::subject_public_key_info(self) + } + /// Public key in `SubjectPublicKeyInfo` PEM format. + #[must_use] + pub fn public_key_pem(&self) -> String { + pem::encode_config( + &pem::Pem::new("PUBLIC KEY", self.public_key_der()), + pem::EncodeConfig::new().set_line_ending(if cfg!(target_family = "windows") { + pem::LineEnding::CRLF + } else { + pem::LineEnding::LF + }), + ) + } + /// Signing algorithm. + #[must_use] + pub fn algorithm(&self) -> &'static rcgen::SignatureAlgorithm { + self.backend.algorithm() + } } -/// Generate a key for an explicit protocol algorithm. +/// Generate the existing default P-256 certificate key. +pub fn generate_keypair() -> Result { + generate_keypair_for(&rcgen::PKCS_ECDSA_P256_SHA256) +} +/// Generate a key through the selected backend. pub fn generate_keypair_for( algorithm: &'static rcgen::SignatureAlgorithm, -) -> Result { +) -> Result { crate::default_context() .backend() .generate_keypair(algorithm) } - -/// Generate the existing Ed25519 gateway JWT key. -pub fn generate_jwt_keypair() -> Result { +/// Generate the existing Ed25519 JWT key. +pub fn generate_jwt_keypair() -> Result { generate_keypair_for(&rcgen::PKCS_ED25519) } +/// Encoded certificate and public issuance parameters, with no private key. +/// Parameters are retained because rcgen 0.14 separates certificates and issuers. +#[derive(Clone, Debug)] +pub struct Certificate { + inner: rcgen::Certificate, + params: rcgen::CertificateParams, +} +impl Certificate { + /// DER certificate bytes. + #[must_use] + pub fn der(&self) -> &rustls::pki_types::CertificateDer<'static> { + self.inner.der() + } + /// PEM certificate text. + #[must_use] + pub fn pem(&self) -> String { + self.inner.pem() + } + /// Move the public issuer parameters and backend key into an issuer. + #[must_use] + pub fn into_issuer(self, key: KeyPair) -> rcgen::Issuer<'static, KeyPair> { + rcgen::Issuer::new(self.params, key) + } +} -/// Sign a certificate using its own key. +/// Encode and sign a certificate using its backend-owned key. pub fn self_signed( params: rcgen::CertificateParams, - key: &rcgen::KeyPair, -) -> Result { - params.self_signed(key) + key: &KeyPair, +) -> Result { + let params = prepare_params(params, key)?; + let inner = params.self_signed(key)?; + Ok(Certificate { inner, params }) } - -/// Sign a certificate with an issuer, retaining rcgen's encoding and validation. +/// Encode and sign a certificate using the backend-owned issuer key. pub fn signed_by( params: rcgen::CertificateParams, - key: &rcgen::KeyPair, - issuer: &rcgen::Certificate, - issuer_key: &rcgen::KeyPair, -) -> Result { - params.signed_by(key, issuer, issuer_key) + key: &KeyPair, + issuer: &Certificate, + issuer_key: &KeyPair, +) -> Result { + signed_by_issuer( + params, + key, + &rcgen::Issuer::from_params(&issuer.params, issuer_key), + ) +} +/// Encode and sign using an issuer loaded from a persisted CA or generated locally. +pub fn signed_by_issuer( + params: rcgen::CertificateParams, + key: &KeyPair, + issuer: &rcgen::Issuer<'_, impl rcgen::SigningKey>, +) -> Result { + let params = prepare_params(params, key)?; + let inner = params.signed_by(key, issuer)?; + Ok(Certificate { inner, params }) +} + +/// A generated certificate and its backend-owned private key. +pub struct CertifiedKey { + /// Generated self-signed certificate. + pub cert: Certificate, + /// Backend-owned key used to sign it. + pub key_pair: KeyPair, +} +/// Generate a default certificate and key, primarily for local fixtures. +pub fn generate_simple_self_signed( + names: impl Into>, +) -> Result { + let key_pair = generate_keypair()?; + let cert = self_signed(rcgen::CertificateParams::new(names)?, &key_pair)?; + Ok(CertifiedKey { cert, key_pair }) +} + +// Preserve rcgen's default serial and key-ID derivation while routing hashing +// through the selected backend, including builds without rcgen's crypto feature. +fn prepare_params( + mut params: rcgen::CertificateParams, + key: &KeyPair, +) -> Result { + let hash = |bytes: &[u8]| crate::sha256(bytes).map_err(|_| rcgen::Error::RemoteKeyError); + if params.serial_number.is_none() { + let digest = hash(key.backend.public_key_raw())?; + let mut serial = digest[..20].to_vec(); + serial[0] &= 0x7f; + params.serial_number = Some(serial.into()); + } + // rcgen defaults to SHA-256 with built-in crypto enabled, or an empty + // pre-specified ID without it. Compare with its default rather than gating + // on our own backend feature: another dependency may enable rcgen crypto. + let derive = + params.key_identifier_method == rcgen::CertificateParams::default().key_identifier_method; + if !derive + && !matches!( + params.key_identifier_method, + rcgen::KeyIdMethod::PreSpecified(_) + ) + { + return Err(rcgen::Error::UnsupportedSignatureAlgorithm); + } + if derive { + params.key_identifier_method = + rcgen::KeyIdMethod::PreSpecified(hash(&key.public_key_der())?[..20].to_vec()); + } + Ok(params) } diff --git a/crates/openshell-crypto/src/pki/issuer.rs b/crates/openshell-crypto/src/pki/issuer.rs new file mode 100644 index 0000000000..c8ec3cd2b2 --- /dev/null +++ b/crates/openshell-crypto/src/pki/issuer.rs @@ -0,0 +1,96 @@ +// SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +use rcgen::{ + CertificateParams, DistinguishedName, DnType, DnValue, Error, KeyIdMethod, KeyUsagePurpose, +}; +use x509_parser::{der_parser::asn1_rs::Tag, extensions::ParsedExtension}; + +use super::KeyPair; + +/// Read issuer metadata without enabling a parser-owned cryptographic backend. +/// +/// This does not establish trust, verify the certificate signature, or check +/// that the key matches. Callers must validate their provisioned certificate and +/// key separately. Unsupported subject encodings are rejected rather than +/// silently changing the issuer name. The original certificate is not reissued. +pub fn issuer_from_der(der: &[u8], key: KeyPair) -> Result, Error> { + let invalid = || Error::CouldNotParseCertificate; + let (rest, cert) = x509_parser::parse_x509_certificate(der).map_err(|_| invalid())?; + if !rest.is_empty() { + return Err(invalid()); + } + let mut name = DistinguishedName::new(); + for rdn in cert.subject().iter_rdn() { + let mut attributes = rdn.iter(); + let attribute = attributes.next().ok_or_else(invalid)?; + // rcgen represents each RDN as one attribute and each OID only once. + if attributes.next().is_some() { + return Err(invalid()); + } + let oid: Vec<_> = attribute.attr_type().iter().ok_or_else(invalid)?.collect(); + let kind = DnType::from_oid(&oid); + if name.get(&kind).is_some() { + return Err(invalid()); + } + let value = attribute.attr_value(); + let string = || std::str::from_utf8(value.data).map_err(|_| invalid()); + let value = match value.tag() { + Tag::Utf8String => DnValue::Utf8String(string()?.to_owned()), + Tag::PrintableString => DnValue::PrintableString(string()?.try_into()?), + Tag::Ia5String => DnValue::Ia5String(string()?.try_into()?), + Tag::T61String => DnValue::TeletexString(string()?.try_into()?), + Tag::BmpString => { + DnValue::BmpString(rcgen::string::BmpString::from_utf16be(value.data.to_vec())?) + } + Tag::UniversalString => DnValue::UniversalString( + rcgen::string::UniversalString::from_utf32be(value.data.to_vec())?, + ), + _ => return Err(invalid()), + }; + name.push(kind, value); + } + let mut usages = Vec::new(); + if let Some(extension) = cert.key_usage().map_err(|_| invalid())? { + let usage = extension.value; + for (present, purpose) in [ + (usage.digital_signature(), KeyUsagePurpose::DigitalSignature), + (usage.non_repudiation(), KeyUsagePurpose::ContentCommitment), + (usage.key_encipherment(), KeyUsagePurpose::KeyEncipherment), + (usage.data_encipherment(), KeyUsagePurpose::DataEncipherment), + (usage.key_agreement(), KeyUsagePurpose::KeyAgreement), + (usage.key_cert_sign(), KeyUsagePurpose::KeyCertSign), + (usage.crl_sign(), KeyUsagePurpose::CrlSign), + (usage.encipher_only(), KeyUsagePurpose::EncipherOnly), + (usage.decipher_only(), KeyUsagePurpose::DecipherOnly), + ] { + if present { + usages.push(purpose); + } + } + } + let mut identifier = None; + for extension in cert.extensions() { + if extension.oid == x509_parser::oid_registry::OID_X509_EXT_SUBJECT_KEY_IDENTIFIER { + if identifier.is_some() { + return Err(invalid()); + } + let ParsedExtension::SubjectKeyIdentifier(value) = extension.parsed_extension() else { + return Err(invalid()); + }; + identifier = Some(value.0.to_vec()); + } + } + // Match our certificate-generation default, using the selected backend. + let identifier = match identifier { + Some(identifier) => identifier, + None => { + crate::sha256(cert.public_key().raw).map_err(|_| Error::RemoteKeyError)?[..20].to_vec() + } + }; + let mut params = CertificateParams::default(); + params.distinguished_name = name; + params.key_usages = usages; + params.key_identifier_method = KeyIdMethod::PreSpecified(identifier); + Ok(rcgen::Issuer::new(params, key)) +} diff --git a/crates/openshell-crypto/src/tls.rs b/crates/openshell-crypto/src/tls.rs index cc24f12e67..c11f9cb6e7 100644 --- a/crates/openshell-crypto/src/tls.rs +++ b/crates/openshell-crypto/src/tls.rs @@ -27,12 +27,60 @@ pub fn ensure_default_provider() -> &'static Arc { /// Verification algorithms for custom TLS certificate verifiers. #[must_use] pub fn signature_verification_algorithms() -> WebPkiSupportedAlgorithms { - provider().signature_verification_algorithms + configuration_provider().signature_verification_algorithms } /// Load a TLS signing key through the selected provider's key adapter. pub fn any_supported_signing_key( key: &rustls::pki_types::PrivateKeyDer<'_>, ) -> Result, rustls::Error> { - provider().key_provider.load_private_key(key.clone_key()) + configuration_provider() + .key_provider + .load_private_key(key.clone_key()) +} + +/// Provider for `OpenShell` configurations. +/// +/// An explicitly selected context +/// wins even if a dependency initialized Rustls first. Otherwise retain an +/// embedder's installed provider, preserving the existing library contract. +#[must_use] +pub fn configuration_provider() -> Arc { + if crate::explicitly_selected() { + Arc::new(provider()) + } else { + ensure_default_provider().clone() + } +} + +/// Client builder using the same provider as key loading and custom verifiers. +#[must_use] +pub fn client_builder() -> rustls::ConfigBuilder { + client_builder_with_protocol_versions(rustls::DEFAULT_VERSIONS) +} + +/// Client builder preserving an explicit protocol-version policy. +#[must_use] +pub fn client_builder_with_protocol_versions( + versions: &[&'static rustls::SupportedProtocolVersion], +) -> rustls::ConfigBuilder { + rustls::ClientConfig::builder_with_provider(configuration_provider()) + .with_protocol_versions(versions) + .expect("selected TLS provider must support the requested protocol versions") +} + +/// Server builder using the selected configuration provider. +#[must_use] +pub fn server_builder() -> rustls::ConfigBuilder { + server_builder_with_protocol_versions(rustls::DEFAULT_VERSIONS) +} + +/// Server builder preserving an explicit protocol-version policy. +#[must_use] +pub fn server_builder_with_protocol_versions( + versions: &[&'static rustls::SupportedProtocolVersion], +) -> rustls::ConfigBuilder { + rustls::ServerConfig::builder_with_provider(configuration_provider()) + .with_protocol_versions(versions) + .expect("selected TLS provider must support the requested protocol versions") } diff --git a/crates/openshell-crypto/tests/context_selection.rs b/crates/openshell-crypto/tests/context_selection.rs index 1fbd992698..2a0205e61f 100644 --- a/crates/openshell-crypto/tests/context_selection.rs +++ b/crates/openshell-crypto/tests/context_selection.rs @@ -1,6 +1,8 @@ // SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 +#![cfg(feature = "aws-lc")] + use openshell_crypto::{ Capabilities, CryptoBackend, CryptoContext, CryptoError, Digest, ProtocolBackend, aead::Sealed, }; @@ -86,7 +88,13 @@ impl ProtocolBackend for TestBackend { fn generate_keypair( &self, _: &'static rcgen::SignatureAlgorithm, - ) -> Result { + ) -> Result { + Err(rcgen::Error::KeyGenerationUnavailable) + } + fn import_keypair_pem(&self, _: &str) -> Result { + Err(rcgen::Error::KeyGenerationUnavailable) + } + fn import_keypair_der(&self, _: &[u8]) -> Result { Err(rcgen::Error::KeyGenerationUnavailable) } fn jwt_provider(&self) -> &'static jsonwebtoken::crypto::CryptoProvider { @@ -96,6 +104,11 @@ impl ProtocolBackend for TestBackend { #[test] fn selected_context_controls_application_adapters_and_cannot_be_replaced() { + // Reproduce dependency initialization before explicit context selection. + let _ = rustls::ClientConfig::builder(); + let host = rustls::crypto::CryptoProvider::get_default() + .unwrap() + .clone(); let context = CryptoContext::new(Box::new(TestBackend(CryptoContext::default()))); openshell_crypto::install_default_context(context.clone()).unwrap(); openshell_crypto::install_default_context(context).unwrap(); @@ -138,11 +151,58 @@ fn selected_context_controls_application_adapters_and_cannot_be_replaced() { assert_eq!(decoded.claims, claims); assert_eq!(JWT_VERIFIERS.load(Ordering::SeqCst), 1); assert_eq!( - openshell_crypto::tls::ensure_default_provider() + openshell_crypto::tls::configuration_provider() .cipher_suites .len(), 1 ); + assert!(std::sync::Arc::ptr_eq( + openshell_crypto::tls::ensure_default_provider(), + &host + )); + let key = CryptoContext::default() + .backend() + .generate_keypair(&rcgen::PKCS_ECDSA_P256_SHA256) + .unwrap(); + let cert = openshell_crypto::pki::self_signed( + rcgen::CertificateParams::new(vec!["localhost".into()]).unwrap(), + &key, + ) + .unwrap(); + let mut roots = rustls::RootCertStore::empty(); + roots.add(cert.der().clone()).unwrap(); + let client = openshell_crypto::tls::client_builder() + .with_root_certificates(roots) + .with_no_client_auth(); + let server = openshell_crypto::tls::server_builder() + .with_no_client_auth() + .with_single_cert( + vec![cert.der().clone()], + rustls::pki_types::PrivatePkcs8KeyDer::from(key.serialize_der().unwrap()).into(), + ) + .unwrap(); + assert_eq!(client.crypto_provider().cipher_suites.len(), 1); + assert_eq!(server.crypto_provider().cipher_suites.len(), 1); + let suite = client.crypto_provider().cipher_suites[0].suite(); + let mut client = + rustls::ClientConnection::new(std::sync::Arc::new(client), "localhost".try_into().unwrap()) + .unwrap(); + let mut server = rustls::ServerConnection::new(std::sync::Arc::new(server)).unwrap(); + for _ in 0..10 { + let mut wire = Vec::new(); + client.write_tls(&mut wire).unwrap(); + server.read_tls(&mut wire.as_slice()).unwrap(); + server.process_new_packets().unwrap(); + wire.clear(); + server.write_tls(&mut wire).unwrap(); + client.read_tls(&mut wire.as_slice()).unwrap(); + client.process_new_packets().unwrap(); + if !client.is_handshaking() && !server.is_handshaking() { + break; + } + } + assert!(!client.is_handshaking() && !server.is_handshaking()); + assert_eq!(client.negotiated_cipher_suite().unwrap().suite(), suite); assert_eq!( openshell_crypto::default_context() .verify_posture(false) diff --git a/crates/openshell-crypto/tests/independent_backend.rs b/crates/openshell-crypto/tests/independent_backend.rs new file mode 100644 index 0000000000..8b87252fb1 --- /dev/null +++ b/crates/openshell-crypto/tests/independent_backend.rs @@ -0,0 +1,217 @@ +// SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +//! Contract probes, deliberately not real cryptography. Also run without any +//! default backend to detect accidental reliance on compiled AWS-LC operations. +use openshell_crypto::{ + Capabilities, CryptoBackend, CryptoContext, CryptoError, Digest, FipsState, ProtocolBackend, + aead, pki, +}; +use std::sync::{ + Arc, + atomic::{AtomicUsize, Ordering}, +}; + +static SIGNS: AtomicUsize = AtomicUsize::new(0); +static IMPORTS: AtomicUsize = AtomicUsize::new(0); +struct Key { + exportable: bool, + drops: Arc, +} +impl Drop for Key { + fn drop(&mut self) { + self.drops.fetch_add(1, Ordering::SeqCst); + } +} +impl pki::SigningKey for Key { + fn algorithm(&self) -> &'static rcgen::SignatureAlgorithm { + &rcgen::PKCS_ED25519 + } + fn public_key_raw(&self) -> &[u8] { + &[7; 32] + } + fn sign(&self, _: &[u8]) -> Result, rcgen::Error> { + SIGNS.fetch_add(1, Ordering::SeqCst); + Ok(vec![9; 64]) + } + fn export_pkcs8_der(&self) -> Result, rcgen::Error> { + if self.exportable { + Ok(b"test backend key".to_vec()) + } else { + Err(rcgen::Error::RemoteKeyError) + } + } +} +struct TestDigest([u8; 32]); +impl Digest for TestDigest { + fn update(&mut self, bytes: &[u8]) -> Result<(), CryptoError> { + for (index, byte) in bytes.iter().enumerate() { + self.0[index % 32] ^= byte; + } + Ok(()) + } + fn finish(self: Box) -> Result<[u8; 32], CryptoError> { + Ok(self.0) + } +} +struct Backend; +impl CryptoBackend for Backend { + fn capabilities(&self) -> Capabilities { + Capabilities { + backend: "test-only", + provider_version: None, + fips: FipsState::NotVerified, + primitives: &[], + key_algorithms: &[], + } + } + fn fill_random(&self, _: &mut [u8]) -> Result<(), CryptoError> { + Err(CryptoError::Random) + } + fn sha256_digest(&self) -> Result, CryptoError> { + Ok(Box::new(TestDigest([0; 32]))) + } + fn seal( + &self, + key: &[u8; 32], + aad: &[u8], + plaintext: &[u8], + ) -> Result { + // Opaque sentinel layout verifies dispatch; it is NOT an encryption scheme. + let mut ciphertext = key.to_vec(); + ciphertext.extend_from_slice(aad); + ciphertext.extend_from_slice(plaintext); + Ok(aead::Sealed { + nonce: [42; 12], + ciphertext, + }) + } + fn open( + &self, + key: &[u8; 32], + aad: &[u8], + nonce: &[u8; 12], + ciphertext: &[u8], + ) -> Result, CryptoError> { + let prefix = [key.as_slice(), aad].concat(); + if nonce != &[42; 12] || !ciphertext.starts_with(&prefix) { + return Err(CryptoError::Authentication); + } + Ok(ciphertext[prefix.len()..].to_vec()) + } +} +impl ProtocolBackend for Backend { + fn tls_provider(&self) -> rustls::crypto::CryptoProvider { + panic!("TLS is not used by this contract probe") + } + fn jwt_provider(&self) -> &'static jsonwebtoken::crypto::CryptoProvider { + panic!("JWT is not used by this contract probe") + } + fn generate_keypair( + &self, + algorithm: &'static rcgen::SignatureAlgorithm, + ) -> Result { + if algorithm != &rcgen::PKCS_ED25519 { + return Err(rcgen::Error::UnsupportedSignatureAlgorithm); + } + pki::KeyPair::new(Box::new(Key { + exportable: true, + drops: Arc::default(), + })) + } + fn import_keypair_der(&self, der: &[u8]) -> Result { + if der != b"test backend key" { + return Err(rcgen::Error::RemoteKeyError); + } + IMPORTS.fetch_add(1, Ordering::SeqCst); + self.generate_keypair(&rcgen::PKCS_ED25519) + } + fn import_keypair_pem(&self, value: &str) -> Result { + let parsed = pem::parse(value).map_err(|_| rcgen::Error::RemoteKeyError)?; + self.import_keypair_der(parsed.contents()) + } +} +#[test] +fn independent_backend_controls_envelopes_and_the_entire_key_lifecycle() { + openshell_crypto::install_default_context(CryptoContext::new(Box::new(Backend))).unwrap(); + let sealed = aead::seal(&[1; 32], b"record", b"payload").unwrap(); + assert_eq!(sealed.nonce, [42; 12]); + assert_eq!( + aead::open(&[1; 32], b"record", &sealed.nonce, &sealed.ciphertext).unwrap(), + b"payload" + ); + assert_eq!( + aead::open(&[1; 32], b"wrong", &sealed.nonce, &sealed.ciphertext), + Err(CryptoError::Authentication) + ); + let key = pki::generate_jwt_keypair().unwrap(); + let der = key.serialize_der().unwrap(); + let pem = key.serialize_pem().unwrap(); + let imported = pki::KeyPair::from_pem(&pem).unwrap(); + let imported_der = pki::KeyPair::from_pkcs8_der(&der).unwrap(); + assert_eq!(IMPORTS.load(Ordering::SeqCst), 2); + assert_eq!(imported.public_key_der(), imported_der.public_key_der()); + let issuer = pki::self_signed(rcgen::CertificateParams::default(), &imported).unwrap(); + pki::signed_by( + rcgen::CertificateParams::default(), + &key, + &issuer, + &imported, + ) + .unwrap(); + assert_eq!(SIGNS.load(Ordering::SeqCst), 2); + // Importing a CA must work even when neither rcgen crypto backend exists. + for with_identifier in [false, true] { + let mut params = rcgen::CertificateParams::default(); + params.distinguished_name.push( + rcgen::DnType::CommonName, + rcgen::DnValue::PrintableString("Persisted CA".try_into().unwrap()), + ); + params.key_usages = vec![rcgen::KeyUsagePurpose::KeyCertSign]; + if with_identifier { + params.is_ca = rcgen::IsCa::Ca(rcgen::BasicConstraints::Unconstrained); + params.key_identifier_method = rcgen::KeyIdMethod::PreSpecified(vec![42; 20]); + } + let ca = pki::self_signed(params, &key).unwrap(); + let imported = + pki::issuer_from_der(ca.der(), pki::generate_jwt_keypair().unwrap()).unwrap(); + assert_eq!( + imported.key_usages(), + &[rcgen::KeyUsagePurpose::KeyCertSign] + ); + let mut params = rcgen::CertificateParams::default(); + params.use_authority_key_identifier_extension = true; + let leaf = pki::signed_by_issuer(params, &key, &imported).unwrap(); + let (_, parsed_ca) = x509_parser::parse_x509_certificate(ca.der()).unwrap(); + let (_, parsed_leaf) = x509_parser::parse_x509_certificate(leaf.der()).unwrap(); + assert_eq!(parsed_leaf.issuer().as_raw(), parsed_ca.subject().as_raw()); + let expected = if with_identifier { + vec![42; 20] + } else { + openshell_crypto::sha256(parsed_ca.public_key().raw).unwrap()[..20].to_vec() + }; + assert!(parsed_leaf.extensions().iter().any(|extension| { + matches!(extension.parsed_extension(), + x509_parser::extensions::ParsedExtension::AuthorityKeyIdentifier(value) + if value.key_identifier.as_ref().unwrap().0 == expected) + })); + let mut trailing = ca.der().to_vec(); + trailing.push(0); + assert!(pki::issuer_from_der(&trailing, pki::generate_jwt_keypair().unwrap()).is_err()); + assert!( + pki::issuer_from_der(&ca.der()[..10], pki::generate_jwt_keypair().unwrap()).is_err() + ); + } + let drops = Arc::new(AtomicUsize::new(0)); + let non_exportable = pki::KeyPair::new(Box::new(Key { + exportable: false, + drops: drops.clone(), + })) + .unwrap(); + assert!(non_exportable.serialize_der().is_err()); + assert!(non_exportable.serialize_pem().is_err()); + pki::self_signed(rcgen::CertificateParams::default(), &non_exportable).unwrap(); + assert_eq!(drops.load(Ordering::SeqCst), 0); + drop(non_exportable); + assert_eq!(drops.load(Ordering::SeqCst), 1); +} diff --git a/crates/openshell-crypto/tests/tls_default.rs b/crates/openshell-crypto/tests/tls_default.rs index ff6c1bb7a0..71633af8de 100644 --- a/crates/openshell-crypto/tests/tls_default.rs +++ b/crates/openshell-crypto/tests/tls_default.rs @@ -1,6 +1,8 @@ // SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 +#![cfg(feature = "aws-lc")] + #[test] fn default_initialization_is_idempotent() { let first = openshell_crypto::tls::ensure_default_provider(); diff --git a/crates/openshell-crypto/tests/tls_embedder.rs b/crates/openshell-crypto/tests/tls_embedder.rs index fd33a6121e..447f56a30d 100644 --- a/crates/openshell-crypto/tests/tls_embedder.rs +++ b/crates/openshell-crypto/tests/tls_embedder.rs @@ -1,6 +1,8 @@ // SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. // SPDX-License-Identifier: Apache-2.0 +#![cfg(feature = "aws-lc")] + #[test] fn library_initialization_preserves_embedder_policy() { // Separate test executable: process-default state cannot leak from other tests. @@ -10,4 +12,8 @@ fn library_initialization_preserves_embedder_policy() { let installed = openshell_crypto::tls::ensure_default_provider(); assert_eq!(installed.cipher_suites.len(), 1); assert!(openshell_crypto::tls::provider().cipher_suites.len() > 1); + let client = openshell_crypto::tls::client_builder() + .with_root_certificates(rustls::RootCertStore::empty()) + .with_no_client_auth(); + assert!(std::sync::Arc::ptr_eq(client.crypto_provider(), installed)); } diff --git a/crates/openshell-driver-db-credstore/Cargo.toml b/crates/openshell-driver-db-credstore/Cargo.toml index 92f9093601..2ca54826ab 100644 --- a/crates/openshell-driver-db-credstore/Cargo.toml +++ b/crates/openshell-driver-db-credstore/Cargo.toml @@ -11,7 +11,7 @@ license.workspace = true repository.workspace = true [dependencies] -openshell-crypto = { path = "../openshell-crypto" } +openshell-crypto = { workspace = true } openshell-core = { path = "../openshell-core", default-features = false } async-trait = "0.1" diff --git a/crates/openshell-driver-kubernetes-secrets/Cargo.toml b/crates/openshell-driver-kubernetes-secrets/Cargo.toml index c337071633..f7f60c04a4 100644 --- a/crates/openshell-driver-kubernetes-secrets/Cargo.toml +++ b/crates/openshell-driver-kubernetes-secrets/Cargo.toml @@ -15,7 +15,7 @@ name = "openshell-driver-kubernetes-secrets" path = "src/main.rs" [dependencies] -openshell-crypto = { path = "../openshell-crypto", features = ["tls-kube"] } +openshell-crypto = { workspace = true, features = ["tls-kube"] } openshell-core = { path = "../openshell-core", default-features = false } clap = { workspace = true } diff --git a/crates/openshell-driver-kubernetes/Cargo.toml b/crates/openshell-driver-kubernetes/Cargo.toml index c79f0e65e6..421d3bf2f2 100644 --- a/crates/openshell-driver-kubernetes/Cargo.toml +++ b/crates/openshell-driver-kubernetes/Cargo.toml @@ -15,7 +15,7 @@ name = "openshell-driver-kubernetes" path = "src/main.rs" [dependencies] -openshell-crypto = { path = "../openshell-crypto", features = ["tls-kube"] } +openshell-crypto = { workspace = true, features = ["tls-kube"] } openshell-core = { path = "../openshell-core", default-features = false } openshell-isolation-interface = { path = "../openshell-isolation-interface" } openshell-sandbox-backend = { path = "../openshell-sandbox-backend" } diff --git a/crates/openshell-driver-kubernetes/src/sandbox_runtime.rs b/crates/openshell-driver-kubernetes/src/sandbox_runtime.rs index 424d022b22..3c8f1fb754 100644 --- a/crates/openshell-driver-kubernetes/src/sandbox_runtime.rs +++ b/crates/openshell-driver-kubernetes/src/sandbox_runtime.rs @@ -62,12 +62,13 @@ pub fn generate_proxy_ca_material() -> Result { .distinguished_name .push(DnType::OrganizationName, "OpenShell"); params.key_usages = vec![KeyUsagePurpose::KeyCertSign, KeyUsagePurpose::CrlSign]; - let certificate = params - .self_signed(&key) + let certificate = openshell_crypto::pki::self_signed(params, &key) .map_err(|error| format!("generate proxy CA certificate: {error}"))?; Ok(ProxyCaMaterial { certificate_pem: certificate.pem(), - private_key_pem: key.serialize_pem(), + private_key_pem: key + .serialize_pem() + .map_err(|error| format!("export proxy CA key: {error}"))?, }) } diff --git a/crates/openshell-driver-mxc/Cargo.toml b/crates/openshell-driver-mxc/Cargo.toml index 7a5314aaa3..8b2d75a6a1 100644 --- a/crates/openshell-driver-mxc/Cargo.toml +++ b/crates/openshell-driver-mxc/Cargo.toml @@ -36,7 +36,7 @@ openshell-supervisor-network = { path = "../openshell-supervisor-network" } windows = { workspace = true } [dev-dependencies] -openshell-crypto = { path = "../openshell-crypto" } +openshell-crypto = { workspace = true } tokio = { workspace = true } # tempfile is not a workspace dependency; 3.27 is already resolved in Cargo.lock. tempfile = "3" diff --git a/crates/openshell-driver-vault/Cargo.toml b/crates/openshell-driver-vault/Cargo.toml index 9fc658a23f..93fcbc397b 100644 --- a/crates/openshell-driver-vault/Cargo.toml +++ b/crates/openshell-driver-vault/Cargo.toml @@ -15,7 +15,7 @@ name = "openshell-driver-vault" path = "src/main.rs" [dependencies] -openshell-crypto = { path = "../openshell-crypto" } +openshell-crypto = { workspace = true } openshell-core = { path = "../openshell-core", default-features = false } clap = { workspace = true } diff --git a/crates/openshell-driver-vault/src/lib.rs b/crates/openshell-driver-vault/src/lib.rs index a66ef628e2..b871d4a1e0 100644 --- a/crates/openshell-driver-vault/src/lib.rs +++ b/crates/openshell-driver-vault/src/lib.rs @@ -971,11 +971,12 @@ fn extract_secret_value( #[cfg(test)] mod tests { + use openshell_crypto::pki::KeyPair; use std::net::SocketAddr; use std::sync::Arc; use openshell_core::proto::CredentialHandle; - use rcgen::{CertificateParams, IsCa, KeyPair}; + use rcgen::{CertificateParams, IsCa}; use tokio::io::{AsyncReadExt, AsyncWriteExt}; use tonic::Code; use wiremock::matchers::{body_string_contains, header, method, path}; @@ -1004,26 +1005,30 @@ mod tests { file } - fn test_ca() -> (rcgen::Certificate, KeyPair) { + fn test_ca() -> (openshell_crypto::pki::Certificate, KeyPair) { let mut params = CertificateParams::new(Vec::::new()).unwrap(); params.is_ca = IsCa::Ca(rcgen::BasicConstraints::Unconstrained); let key = openshell_crypto::pki::generate_keypair().unwrap(); - let certificate = params.self_signed(&key).unwrap(); + let certificate = openshell_crypto::pki::self_signed(params, &key).unwrap(); (certificate, key) } async fn start_tls_server(response: String) -> (SocketAddr, String) { let (ca_certificate, ca_key) = test_ca(); let server_key = openshell_crypto::pki::generate_keypair().unwrap(); - let server_certificate = CertificateParams::new(vec!["localhost".to_string()]) - .unwrap() - .signed_by(&server_key, &ca_certificate, &ca_key) - .unwrap(); - let server_config = rustls::ServerConfig::builder() + let server_certificate = openshell_crypto::pki::signed_by( + CertificateParams::new(vec!["localhost".to_string()]).unwrap(), + &server_key, + &ca_certificate, + &ca_key, + ) + .unwrap(); + let server_config = openshell_crypto::tls::server_builder() .with_no_client_auth() .with_single_cert( vec![server_certificate.der().clone()], - rustls::pki_types::PrivateKeyDer::try_from(server_key.serialize_der()).unwrap(), + rustls::pki_types::PrivateKeyDer::try_from(server_key.serialize_der().unwrap()) + .unwrap(), ) .unwrap(); let acceptor = tokio_rustls::TlsAcceptor::from(Arc::new(server_config)); diff --git a/crates/openshell-extension-core/Cargo.toml b/crates/openshell-extension-core/Cargo.toml index 2109922f5f..b4f0c24687 100644 --- a/crates/openshell-extension-core/Cargo.toml +++ b/crates/openshell-extension-core/Cargo.toml @@ -19,7 +19,7 @@ tonic = { workspace = true, features = ["channel", "tls-native-roots"] } tower = { workspace = true } [dev-dependencies] -openshell-crypto = { path = "../openshell-crypto" } +openshell-crypto = { workspace = true } http = { workspace = true } rcgen = { workspace = true } rustls = { workspace = true } diff --git a/crates/openshell-extension-core/src/transport.rs b/crates/openshell-extension-core/src/transport.rs index c77399048f..07b77ad6f4 100644 --- a/crates/openshell-extension-core/src/transport.rs +++ b/crates/openshell-extension-core/src/transport.rs @@ -295,19 +295,20 @@ mod tests { let ca_key = openshell_crypto::pki::generate_keypair().unwrap(); let mut ca_params = CertificateParams::new(Vec::::new()).unwrap(); ca_params.is_ca = IsCa::Ca(BasicConstraints::Unconstrained); - let ca = ca_params.self_signed(&ca_key).unwrap(); + let ca = openshell_crypto::pki::self_signed(ca_params, &ca_key).unwrap(); let server_key = openshell_crypto::pki::generate_keypair().unwrap(); let mut server_params = CertificateParams::new(vec!["localhost".to_string()]).unwrap(); server_params.extended_key_usages = vec![ExtendedKeyUsagePurpose::ServerAuth]; - let server_cert = server_params.signed_by(&server_key, &ca, &ca_key).unwrap(); + let server_cert = + openshell_crypto::pki::signed_by(server_params, &server_key, &ca, &ca_key).unwrap(); let listener = TcpListener::bind("127.0.0.1:0").await.unwrap(); let address = listener.local_addr().unwrap(); let incoming = TcpListenerStream::new(listener); let tls = ServerTlsConfig::new().identity(Identity::from_pem( server_cert.pem(), - server_key.serialize_pem(), + server_key.serialize_pem().unwrap(), )); tokio::spawn(async move { Server::builder() @@ -334,7 +335,7 @@ mod tests { let rogue_key = openshell_crypto::pki::generate_keypair().unwrap(); let mut rogue_params = CertificateParams::new(Vec::::new()).unwrap(); rogue_params.is_ca = IsCa::Ca(BasicConstraints::Unconstrained); - let rogue_ca = rogue_params.self_signed(&rogue_key).unwrap(); + let rogue_ca = openshell_crypto::pki::self_signed(rogue_params, &rogue_key).unwrap(); let wrong_ca = ExtensionChannelConfig::new(format!("https://localhost:{}", address.port())) .with_custom_ca_pem(rogue_ca.pem()); assert!(matches!( diff --git a/crates/openshell-sandbox-backend/Cargo.toml b/crates/openshell-sandbox-backend/Cargo.toml index f08e5d43ff..504fd8bc9f 100644 --- a/crates/openshell-sandbox-backend/Cargo.toml +++ b/crates/openshell-sandbox-backend/Cargo.toml @@ -11,7 +11,7 @@ license.workspace = true repository.workspace = true [dependencies] -openshell-crypto = { path = "../openshell-crypto" } +openshell-crypto = { workspace = true } openshell-core = { path = "../openshell-core", default-features = false, features = ["jwt"] } openshell-isolation-interface = { path = "../openshell-isolation-interface" } async-trait = "0.1" diff --git a/crates/openshell-sandbox-backend/src/boundary_protocol.rs b/crates/openshell-sandbox-backend/src/boundary_protocol.rs index 149cb31ebb..4fc99bcbe1 100644 --- a/crates/openshell-sandbox-backend/src/boundary_protocol.rs +++ b/crates/openshell-sandbox-backend/src/boundary_protocol.rs @@ -204,7 +204,7 @@ pub fn generate_sandbox_tls_material( .distinguished_name .push(DnType::CommonName, "OpenShell sandbox session CA"); ca_params.key_usages = vec![KeyUsagePurpose::KeyCertSign, KeyUsagePurpose::CrlSign]; - let ca = ca_params.self_signed(&ca_key).map_err(|error| { + let ca = openshell_crypto::pki::self_signed(ca_params, &ca_key).map_err(|error| { BackendError::Descriptor(format!("generate sandbox CA certificate: {error}")) })?; @@ -220,8 +220,7 @@ pub fn generate_sandbox_tls_material( .distinguished_name .push(DnType::CommonName, "OpenShell sandbox runtime"); sandbox_params.extended_key_usages = vec![ExtendedKeyUsagePurpose::ServerAuth]; - let sandbox = sandbox_params - .signed_by(&sandbox_key, &ca, &ca_key) + let sandbox = openshell_crypto::pki::signed_by(sandbox_params, &sandbox_key, &ca, &ca_key) .map_err(|error| { BackendError::Descriptor(format!("sign sandbox TLS server certificate: {error}")) })?; @@ -230,7 +229,9 @@ pub fn generate_sandbox_tls_material( server_name, trust_anchor_pem: ca.pem(), certificate_chain_pem: sandbox.pem(), - private_key_pem: sandbox_key.serialize_pem(), + private_key_pem: sandbox_key + .serialize_pem() + .map_err(|error| BackendError::Descriptor(format!("export sandbox key: {error}")))?, }) } diff --git a/crates/openshell-sandbox-backend/src/runtime.rs b/crates/openshell-sandbox-backend/src/runtime.rs index 55fffe6924..ef586ee6f6 100644 --- a/crates/openshell-sandbox-backend/src/runtime.rs +++ b/crates/openshell-sandbox-backend/src/runtime.rs @@ -252,7 +252,7 @@ fn tls_client_config(tls: &SandboxTlsClientConfig) -> Result = Arc::new(FixedClock); let sandbox_id = SandboxId::parse("sandbox-a").expect("sandbox ID"); let issuer = SessionJwtIssuer::from_ed25519_pem( - key.serialize_pem().as_bytes(), + key.serialize_pem().unwrap().as_bytes(), "current", "test", DEFAULT_SESSION_TOKEN_TTL, diff --git a/crates/openshell-sandbox/Cargo.toml b/crates/openshell-sandbox/Cargo.toml index c6108f9cfa..bb38982960 100644 --- a/crates/openshell-sandbox/Cargo.toml +++ b/crates/openshell-sandbox/Cargo.toml @@ -24,7 +24,7 @@ perf-harness = [] [dependencies] openshell-core = { path = "../openshell-core", default-features = false } -openshell-crypto = { path = "../openshell-crypto" } +openshell-crypto = { workspace = true } openshell-binary-identity = { path = "../openshell-binary-identity" } openshell-isolation-interface = { path = "../openshell-isolation-interface" } openshell-sandbox-backend = { path = "../openshell-sandbox-backend" } diff --git a/crates/openshell-sandbox/src/boundary_server.rs b/crates/openshell-sandbox/src/boundary_server.rs index d1db847599..53bc381f54 100644 --- a/crates/openshell-sandbox/src/boundary_server.rs +++ b/crates/openshell-sandbox/src/boundary_server.rs @@ -3301,11 +3301,12 @@ mod linux { "boundary TLS private-key file contains no private key", ) })?; - let mut config = - rustls::ServerConfig::builder_with_protocol_versions(&[&rustls::version::TLS13]) - .with_no_client_auth() - .with_single_cert(certificates, private_key) - .map_err(|error| io::Error::new(io::ErrorKind::InvalidInput, error))?; + let mut config = openshell_crypto::tls::server_builder_with_protocol_versions(&[ + &rustls::version::TLS13, + ]) + .with_no_client_auth() + .with_single_cert(certificates, private_key) + .map_err(|error| io::Error::new(io::ErrorKind::InvalidInput, error))?; config.alpn_protocols = vec![b"h2".to_vec()]; for path in [&tls.certificate_chain_path, &tls.private_key_path] { std::fs::remove_file(path)?; @@ -3608,7 +3609,7 @@ mod linux { public_key_pem: key.public_key_pem(), }; let issuer = SessionJwtIssuer::from_ed25519_pem( - key.serialize_pem().as_bytes(), + key.serialize_pem().unwrap().as_bytes(), "test-key", "test-gateway", DEFAULT_SESSION_TOKEN_TTL, @@ -3681,7 +3682,7 @@ mod linux { .add(certificate.expect("parse test CA")) .expect("add test CA"); } - let mut config = rustls::ClientConfig::builder() + let mut config = openshell_crypto::tls::client_builder() .with_root_certificates(roots) .with_no_client_auth(); config.alpn_protocols = vec![b"h2".to_vec()]; diff --git a/crates/openshell-sdk/Cargo.toml b/crates/openshell-sdk/Cargo.toml index 00de17108b..b744b02657 100644 --- a/crates/openshell-sdk/Cargo.toml +++ b/crates/openshell-sdk/Cargo.toml @@ -11,7 +11,7 @@ license.workspace = true repository.workspace = true [dependencies] -openshell-crypto = { path = "../openshell-crypto" } +openshell-crypto = { workspace = true } openshell-core = { path = "../openshell-core" } async-trait = "0.1" futures = { workspace = true } diff --git a/crates/openshell-sdk/src/transport.rs b/crates/openshell-sdk/src/transport.rs index 7e1ba71b0d..07ced55215 100644 --- a/crates/openshell-sdk/src/transport.rs +++ b/crates/openshell-sdk/src/transport.rs @@ -183,7 +183,7 @@ impl ServerCertVerifier for InsecureServerCertVerifier { } fn supported_verify_schemes(&self) -> Vec { - openshell_crypto::tls::provider() + openshell_crypto::tls::configuration_provider() .signature_verification_algorithms .supported_schemes() } @@ -195,7 +195,7 @@ impl ServerCertVerifier for InsecureServerCertVerifier { /// verification (development, debug). Returns `Result` for symmetry with /// future verifying variants; the current implementation cannot fail. pub fn build_insecure_rustls_config() -> Result { - Ok(rustls::ClientConfig::builder() + Ok(openshell_crypto::tls::client_builder() .dangerous() .with_custom_certificate_verifier(std::sync::Arc::new(InsecureServerCertVerifier)) .with_no_client_auth()) diff --git a/crates/openshell-server/Cargo.toml b/crates/openshell-server/Cargo.toml index cfdf7a0d75..4bbf7f1333 100644 --- a/crates/openshell-server/Cargo.toml +++ b/crates/openshell-server/Cargo.toml @@ -11,7 +11,7 @@ license.workspace = true repository.workspace = true [dependencies] -openshell-crypto = { path = "../openshell-crypto", features = ["tls-hyper", "tls-kube", "tls-sqlx"] } +openshell-crypto = { workspace = true, features = ["tls-hyper", "tls-kube", "tls-sqlx"] } openshell-bootstrap = { path = "../openshell-bootstrap" } openshell-core = { path = "../openshell-core", default-features = false, features = ["jwt", "oauth"] } openshell-driver-db-credstore = { path = "../openshell-driver-db-credstore" } diff --git a/crates/openshell-server/src/auth/oidc.rs b/crates/openshell-server/src/auth/oidc.rs index 8af6ca519e..59a92d5564 100644 --- a/crates/openshell-server/src/auth/oidc.rs +++ b/crates/openshell-server/src/auth/oidc.rs @@ -1010,23 +1010,23 @@ mod tests { let mut old_ca_params = CertificateParams::new(Vec::::new()).unwrap(); old_ca_params.is_ca = IsCa::Ca(BasicConstraints::Unconstrained); let old_ca_key = openshell_crypto::pki::generate_keypair().unwrap(); - let old_ca_cert = old_ca_params.self_signed(&old_ca_key).unwrap(); + let old_ca_cert = openshell_crypto::pki::self_signed(old_ca_params, &old_ca_key).unwrap(); let mut ca_params = CertificateParams::new(Vec::::new()).unwrap(); ca_params.is_ca = IsCa::Ca(BasicConstraints::Unconstrained); let ca_key = openshell_crypto::pki::generate_keypair().unwrap(); - let ca_cert = ca_params.self_signed(&ca_key).unwrap(); + let ca_cert = openshell_crypto::pki::self_signed(ca_params, &ca_key).unwrap(); let server_params = CertificateParams::new(vec!["localhost".to_string()]).unwrap(); let server_key = openshell_crypto::pki::generate_keypair().unwrap(); - let server_cert = server_params - .signed_by(&server_key, &ca_cert, &ca_key) - .unwrap(); - let server_config = rustls::ServerConfig::builder() + let server_cert = + openshell_crypto::pki::signed_by(server_params, &server_key, &ca_cert, &ca_key) + .unwrap(); + let server_config = openshell_crypto::tls::server_builder() .with_no_client_auth() .with_single_cert( vec![server_cert.der().clone()], - PrivateKeyDer::Pkcs8(server_key.serialize_der().into()), + PrivateKeyDer::Pkcs8(server_key.serialize_der().unwrap().into()), ) .unwrap(); let acceptor = tokio_rustls::TlsAcceptor::from(Arc::new(server_config)); @@ -1698,7 +1698,7 @@ mod tests { other => panic!("unsupported curve {other}"), }; let encoding_key = - EncodingKey::from_ec_pem(key_pair.serialize_pem().as_bytes()).unwrap(); + EncodingKey::from_ec_pem(key_pair.serialize_pem().unwrap().as_bytes()).unwrap(); let (x, y) = ec_coords_from_spki(&key_pair.public_key_der(), coord_len); let jwk = serde_json::json!({ "kty": "EC", @@ -1719,7 +1719,7 @@ mod tests { fn ed25519_test_key(kid: &str) -> TestSigningKey { let key_pair = openshell_crypto::pki::generate_keypair_for(&PKCS_ED25519).unwrap(); let encoding_key = - EncodingKey::from_ed_pem(key_pair.serialize_pem().as_bytes()).unwrap(); + EncodingKey::from_ed_pem(key_pair.serialize_pem().unwrap().as_bytes()).unwrap(); let spki = key_pair.public_key_der(); let x = URL_SAFE_NO_PAD.encode(&spki[spki.len() - 32..]); let jwk = serde_json::json!({ diff --git a/crates/openshell-server/src/config_file.rs b/crates/openshell-server/src/config_file.rs index 6bddddc4c2..1f3c151746 100644 --- a/crates/openshell-server/src/config_file.rs +++ b/crates/openshell-server/src/config_file.rs @@ -913,8 +913,9 @@ allow_unauthenticated_users = true #[test] fn parses_supervisor_middleware_registration() { - let certificate = rcgen::generate_simple_self_signed(vec!["localhost".to_string()]) - .expect("test certificate"); + let certificate = + openshell_crypto::pki::generate_simple_self_signed(vec!["localhost".to_string()]) + .expect("test certificate"); let mut ca = tempfile::Builder::new() .suffix(".pem") .tempfile() @@ -1017,14 +1018,15 @@ timeout = "2s" use std::io::Write as _; let certificate = - rcgen::generate_simple_self_signed(vec!["localhost".into()]).expect("test certificate"); + openshell_crypto::pki::generate_simple_self_signed(vec!["localhost".into()]) + .expect("test certificate"); let mut ca = tempfile::Builder::new() .suffix(".pem") .tempfile() .expect("CA tempfile"); ca.write_all(certificate.cert.pem().as_bytes()) .expect("write certificate"); - ca.write_all(certificate.key_pair.serialize_pem().as_bytes()) + ca.write_all(certificate.key_pair.serialize_pem().unwrap().as_bytes()) .expect("write private key"); let config = MiddlewareServiceFileConfig { name: "local-guard".into(), diff --git a/crates/openshell-server/src/tls.rs b/crates/openshell-server/src/tls.rs index f95621de48..fa921d608f 100644 --- a/crates/openshell-server/src/tls.rs +++ b/crates/openshell-server/src/tls.rs @@ -406,7 +406,10 @@ fn build_server_config( .map_err(|e| Error::tls(format!("failed to add CA certificate: {e}")))?; } - let verifier_builder = WebPkiClientVerifier::builder(Arc::new(root_store)); + let verifier_builder = WebPkiClientVerifier::builder_with_provider( + Arc::new(root_store), + openshell_crypto::tls::configuration_provider(), + ); let verifier = if require_client_auth { verifier_builder } else { @@ -415,7 +418,7 @@ fn build_server_config( .build() .map_err(|e| Error::tls(format!("failed to build client verifier: {e}")))?; - let builder = ServerConfig::builder().with_client_cert_verifier(verifier); + let builder = openshell_crypto::tls::server_builder().with_client_cert_verifier(verifier); if let Some(resolver) = resolver { builder.with_cert_resolver(resolver) } else { @@ -424,7 +427,7 @@ fn build_server_config( .map_err(|e| Error::tls(format!("failed to create TLS config: {e}")))? } } else { - let builder = ServerConfig::builder().with_no_client_auth(); + let builder = openshell_crypto::tls::server_builder().with_no_client_auth(); if let Some(resolver) = resolver { builder.with_cert_resolver(resolver) } else { @@ -496,22 +499,31 @@ fn tls_ocsf_ctx() -> EventContext { mod tests { use super::*; use crate::tls_test_utils::{generate_test_certs_with_ca, write_test_file}; - use rcgen::{CertificateParams, IsCa, KeyPair, KeyUsagePurpose}; + use openshell_crypto::pki::KeyPair; + use rcgen::{CertificateParams, IsCa, KeyUsagePurpose}; use tokio::net::{TcpListener, TcpStream}; /// Generate a new server cert + key in `dir`, signed by the given CA. /// Overwrites `server-cert.pem` and `server-key.pem`. - fn generate_server_cert(ca_cert: &rcgen::Certificate, ca_key: &KeyPair, dir: &Path) { + fn generate_server_cert( + ca_cert: &openshell_crypto::pki::Certificate, + ca_key: &KeyPair, + dir: &Path, + ) { let server_params = CertificateParams::new(vec!["localhost".to_string()]) .expect("failed to create server params"); let server_key = openshell_crypto::pki::generate_keypair().expect("failed to generate server key"); - let server_cert = server_params - .signed_by(&server_key, ca_cert, ca_key) - .expect("failed to sign server cert"); + let server_cert = + openshell_crypto::pki::signed_by(server_params, &server_key, ca_cert, ca_key) + .expect("failed to sign server cert"); write_test_file(dir, "server-cert.pem", server_cert.pem().as_bytes()); - write_test_file(dir, "server-key.pem", server_key.serialize_pem().as_bytes()); + write_test_file( + dir, + "server-key.pem", + server_key.serialize_pem().unwrap().as_bytes(), + ); } fn build_test_client_config(ca_path: &Path) -> Arc { @@ -523,7 +535,7 @@ mod tests { .expect("failed to add CA to root store"); } Arc::new( - rustls::ClientConfig::builder() + openshell_crypto::tls::client_builder() .with_root_certificates(root_store) .with_no_client_auth(), ) @@ -920,8 +932,7 @@ mod tests { .push(rcgen::DnType::CommonName, "new-ca"); let new_ca_key = openshell_crypto::pki::generate_keypair().expect("failed to generate new CA key"); - let new_ca_cert = new_ca_params - .self_signed(&new_ca_key) + let new_ca_cert = openshell_crypto::pki::self_signed(new_ca_params, &new_ca_key) .expect("failed to sign new CA cert"); std::fs::write(dir.path().join("ca.pem"), new_ca_cert.pem().as_bytes()) .expect("failed to write new CA"); @@ -944,17 +955,20 @@ mod tests { KeyUsagePurpose::DigitalSignature, KeyUsagePurpose::KeyEncipherment, ]; - let client_cert = client_params - .signed_by(&client_key, &new_ca_cert, &new_ca_key) - .expect("failed to sign client cert"); + let client_cert = + openshell_crypto::pki::signed_by(client_params, &client_key, &new_ca_cert, &new_ca_key) + .expect("failed to sign client cert"); // Write client cert + key as PEM files and load via load_certs/load_key let client_cert_path = dir.path().join("client-cert.pem"); let client_key_path = dir.path().join("client-key.pem"); std::fs::write(&client_cert_path, client_cert.pem().as_bytes()) .expect("failed to write client cert"); - std::fs::write(&client_key_path, client_key.serialize_pem().as_bytes()) - .expect("failed to write client key"); + std::fs::write( + &client_key_path, + client_key.serialize_pem().unwrap().as_bytes(), + ) + .expect("failed to write client key"); let client_cert_chain = load_certs(&client_cert_path).expect("failed to load client cert"); let client_private_key = load_key(&client_key_path).expect("failed to load client key"); @@ -964,7 +978,7 @@ mod tests { .add(CertificateDer::from(new_ca_cert.der().to_vec())) .expect("failed to add new CA to root store"); let new_ca_client_config = Arc::new( - rustls::ClientConfig::builder() + openshell_crypto::tls::client_builder() .with_root_certificates(root_store) .with_client_auth_cert(client_cert_chain, client_private_key) .expect("failed to set client auth cert"), @@ -1012,16 +1026,23 @@ mod tests { KeyUsagePurpose::DigitalSignature, KeyUsagePurpose::KeyEncipherment, ]; - let old_client_cert = old_client_params - .signed_by(&old_client_key, &initial_ca_cert, &initial_ca_key) - .expect("failed to sign old client cert"); + let old_client_cert = openshell_crypto::pki::signed_by( + old_client_params, + &old_client_key, + &initial_ca_cert, + &initial_ca_key, + ) + .expect("failed to sign old client cert"); let old_cert_path = dir.path().join("old-client-cert.pem"); let old_key_path = dir.path().join("old-client-key.pem"); std::fs::write(&old_cert_path, old_client_cert.pem().as_bytes()) .expect("failed to write old client cert"); - std::fs::write(&old_key_path, old_client_key.serialize_pem().as_bytes()) - .expect("failed to write old client key"); + std::fs::write( + &old_key_path, + old_client_key.serialize_pem().unwrap().as_bytes(), + ) + .expect("failed to write old client key"); let old_cert_chain = load_certs(&old_cert_path).expect("failed to load old client cert"); let old_key_der = load_key(&old_key_path).expect("failed to load old client key"); @@ -1031,7 +1052,7 @@ mod tests { .add(CertificateDer::from(new_ca_cert.der().to_vec())) .expect("failed to add new CA to root store"); let old_ca_client_config = Arc::new( - rustls::ClientConfig::builder() + openshell_crypto::tls::client_builder() .with_root_certificates(old_root_store) .with_client_auth_cert(old_cert_chain, old_key_der) .expect("failed to set old client auth cert"), @@ -1068,7 +1089,7 @@ mod tests { /// Generate a cert+key pair with given SANs, signed by the provided CA, /// and write them to the specified files in `dir`. fn generate_named_cert( - ca_cert: &rcgen::Certificate, + ca_cert: &openshell_crypto::pki::Certificate, ca_key: &KeyPair, dir: &Path, cert_file: &str, @@ -1078,11 +1099,10 @@ mod tests { let params = CertificateParams::new(vec![san.to_string()]).expect("failed to create cert params"); let key = openshell_crypto::pki::generate_keypair().expect("failed to generate key"); - let cert = params - .signed_by(&key, ca_cert, ca_key) + let cert = openshell_crypto::pki::signed_by(params, &key, ca_cert, ca_key) .expect("failed to sign cert"); write_test_file(dir, cert_file, cert.pem().as_bytes()); - write_test_file(dir, key_file, key.serialize_pem().as_bytes()); + write_test_file(dir, key_file, key.serialize_pem().unwrap().as_bytes()); } #[test] diff --git a/crates/openshell-server/src/tls_test_utils.rs b/crates/openshell-server/src/tls_test_utils.rs index 89acf4efa4..3f6289b668 100644 --- a/crates/openshell-server/src/tls_test_utils.rs +++ b/crates/openshell-server/src/tls_test_utils.rs @@ -3,11 +3,12 @@ //! Shared test helpers for TLS-related tests. +use openshell_crypto::pki::KeyPair; use std::fs::File; use std::io::Write; use std::path::Path; -use rcgen::{CertificateParams, IsCa, KeyPair}; +use rcgen::{CertificateParams, IsCa}; /// Write bytes to a file inside `dir`, panicking on failure. pub fn write_test_file(dir: &Path, name: &str, data: &[u8]) { @@ -27,7 +28,7 @@ pub fn write_test_file(dir: &Path, name: &str, data: &[u8]) { /// - `ca.pem` /// - `server-cert.pem` /// - `server-key.pem` -pub fn generate_test_certs_with_ca(dir: &Path) -> (rcgen::Certificate, KeyPair) { +pub fn generate_test_certs_with_ca(dir: &Path) -> (openshell_crypto::pki::Certificate, KeyPair) { let mut ca_params = CertificateParams::new(Vec::::new()).expect("failed to create CA params"); ca_params.is_ca = IsCa::Ca(rcgen::BasicConstraints::Unconstrained); @@ -35,21 +36,24 @@ pub fn generate_test_certs_with_ca(dir: &Path) -> (rcgen::Certificate, KeyPair) .distinguished_name .push(rcgen::DnType::CommonName, "test-ca"); let ca_key = openshell_crypto::pki::generate_keypair().expect("failed to generate CA key"); - let ca_cert = ca_params - .self_signed(&ca_key) - .expect("failed to sign CA cert"); + let ca_cert = + openshell_crypto::pki::self_signed(ca_params, &ca_key).expect("failed to sign CA cert"); let server_params = CertificateParams::new(vec!["localhost".to_string()]) .expect("failed to create server params"); let server_key = openshell_crypto::pki::generate_keypair().expect("failed to generate server key"); - let server_cert = server_params - .signed_by(&server_key, &ca_cert, &ca_key) - .expect("failed to sign server cert"); + let server_cert = + openshell_crypto::pki::signed_by(server_params, &server_key, &ca_cert, &ca_key) + .expect("failed to sign server cert"); write_test_file(dir, "ca.pem", ca_cert.pem().as_bytes()); write_test_file(dir, "server-cert.pem", server_cert.pem().as_bytes()); - write_test_file(dir, "server-key.pem", server_key.serialize_pem().as_bytes()); + write_test_file( + dir, + "server-key.pem", + server_key.serialize_pem().unwrap().as_bytes(), + ); (ca_cert, ca_key) } diff --git a/crates/openshell-server/tests/common/mod.rs b/crates/openshell-server/tests/common/mod.rs index 9882342165..b3f6957cfc 100644 --- a/crates/openshell-server/tests/common/mod.rs +++ b/crates/openshell-server/tests/common/mod.rs @@ -669,18 +669,17 @@ pub fn generate_pki() -> (tempfile::TempDir, PkiBundle) { .distinguished_name .push(rcgen::DnType::CommonName, "test-ca"); let ca_key = openshell_crypto::pki::generate_keypair().expect("failed to generate CA key"); - let ca_cert = ca_params - .self_signed(&ca_key) - .expect("failed to sign CA cert"); + let ca_cert = + openshell_crypto::pki::self_signed(ca_params, &ca_key).expect("failed to sign CA cert"); // Generate server cert signed by CA let server_params = CertificateParams::new(vec!["localhost".to_string()]) .expect("failed to create server params"); let server_key = openshell_crypto::pki::generate_keypair().expect("failed to generate server key"); - let server_cert = server_params - .signed_by(&server_key, &ca_cert, &ca_key) - .expect("failed to sign server cert"); + let server_cert = + openshell_crypto::pki::signed_by(server_params, &server_key, &ca_cert, &ca_key) + .expect("failed to sign server cert"); // Generate client cert signed by CA let mut client_params = @@ -690,9 +689,9 @@ pub fn generate_pki() -> (tempfile::TempDir, PkiBundle) { .push(rcgen::DnType::CommonName, "test-client"); let client_key = openshell_crypto::pki::generate_keypair().expect("failed to generate client key"); - let client_cert = client_params - .signed_by(&client_key, &ca_cert, &ca_key) - .expect("failed to sign client cert"); + let client_cert = + openshell_crypto::pki::signed_by(client_params, &client_key, &ca_cert, &ca_key) + .expect("failed to sign client cert"); let dir = tempdir().expect("failed to create tempdir"); let write_file = |name: &str, data: &[u8]| { @@ -704,16 +703,22 @@ pub fn generate_pki() -> (tempfile::TempDir, PkiBundle) { write_file("ca.pem", ca_cert.pem().as_bytes()); write_file("server-cert.pem", server_cert.pem().as_bytes()); - write_file("server-key.pem", server_key.serialize_pem().as_bytes()); + write_file( + "server-key.pem", + server_key.serialize_pem().unwrap().as_bytes(), + ); write_file("client-cert.pem", client_cert.pem().as_bytes()); - write_file("client-key.pem", client_key.serialize_pem().as_bytes()); + write_file( + "client-key.pem", + client_key.serialize_pem().unwrap().as_bytes(), + ); let bundle = PkiBundle { ca_cert_pem: ca_cert.pem().into_bytes(), server_cert_pem: server_cert.pem().into_bytes(), - server_key_pem: server_key.serialize_pem().into_bytes(), + server_key_pem: server_key.serialize_pem().unwrap().into_bytes(), client_cert_pem: client_cert.pem().into_bytes(), - client_key_pem: client_key.serialize_pem().into_bytes(), + client_key_pem: client_key.serialize_pem().unwrap().into_bytes(), }; (dir, bundle) @@ -770,8 +775,7 @@ pub fn generate_rogue_pki() -> RoguePkiBundle { .push(rcgen::DnType::CommonName, "rogue-ca"); let rogue_ca_key = openshell_crypto::pki::generate_keypair().expect("failed to generate rogue CA key"); - let rogue_ca_cert = rogue_ca_params - .self_signed(&rogue_ca_key) + let rogue_ca_cert = openshell_crypto::pki::self_signed(rogue_ca_params, &rogue_ca_key) .expect("failed to sign rogue CA cert"); let mut rogue_client_params = @@ -781,13 +785,17 @@ pub fn generate_rogue_pki() -> RoguePkiBundle { .push(rcgen::DnType::CommonName, "rogue-client"); let rogue_client_key = openshell_crypto::pki::generate_keypair().expect("failed to generate rogue client key"); - let rogue_client_cert = rogue_client_params - .signed_by(&rogue_client_key, &rogue_ca_cert, &rogue_ca_key) - .expect("failed to sign rogue client cert"); + let rogue_client_cert = openshell_crypto::pki::signed_by( + rogue_client_params, + &rogue_client_key, + &rogue_ca_cert, + &rogue_ca_key, + ) + .expect("failed to sign rogue client cert"); RoguePkiBundle { client_cert_pem: rogue_client_cert.pem(), - client_key_pem: rogue_client_key.serialize_pem(), + client_key_pem: rogue_client_key.serialize_pem().unwrap(), } } diff --git a/crates/openshell-server/tests/edge_tunnel_auth.rs b/crates/openshell-server/tests/edge_tunnel_auth.rs index c236d99956..df027b653b 100644 --- a/crates/openshell-server/tests/edge_tunnel_auth.rs +++ b/crates/openshell-server/tests/edge_tunnel_auth.rs @@ -122,7 +122,7 @@ fn https_client_mtls( .expect("failed to parse client key pem") .expect("no private key found") }; - let tls_config = rustls::ClientConfig::builder() + let tls_config = openshell_crypto::tls::client_builder() .with_root_certificates(roots) .with_client_auth_cert(client_certs, client_key) .expect("failed to build client TLS config with client cert"); @@ -142,7 +142,7 @@ fn https_client_no_cert( Empty, > { let roots = build_tls_root(ca_pem); - let tls_config = rustls::ClientConfig::builder() + let tls_config = openshell_crypto::tls::client_builder() .with_root_certificates(roots) .with_no_client_auth(); let https = HttpsConnectorBuilder::new() diff --git a/crates/openshell-server/tests/multiplex_tls_integration.rs b/crates/openshell-server/tests/multiplex_tls_integration.rs index adc6837cc4..c61a3be83a 100644 --- a/crates/openshell-server/tests/multiplex_tls_integration.rs +++ b/crates/openshell-server/tests/multiplex_tls_integration.rs @@ -40,7 +40,7 @@ fn https_client_mtls( .expect("no private key found") }; - let tls_config = rustls::ClientConfig::builder() + let tls_config = openshell_crypto::tls::client_builder() .with_root_certificates(roots) .with_client_auth_cert(client_certs, client_key) .expect("failed to build client TLS config with client cert"); diff --git a/crates/openshell-supervisor-network/Cargo.toml b/crates/openshell-supervisor-network/Cargo.toml index 4b83b4cb63..3f634b0cc1 100644 --- a/crates/openshell-supervisor-network/Cargo.toml +++ b/crates/openshell-supervisor-network/Cargo.toml @@ -11,8 +11,9 @@ repository.workspace = true rust-version.workspace = true [dependencies] +sha2 = { workspace = true } openshell-binary-identity = { path = "../openshell-binary-identity" } -openshell-crypto = { path = "../openshell-crypto" } +openshell-crypto = { workspace = true } openshell-core = { path = "../openshell-core", features = ["oauth"] } openshell-isolation-interface = { path = "../openshell-isolation-interface" } openshell-ocsf = { path = "../openshell-ocsf" } @@ -46,7 +47,6 @@ serde = { workspace = true } serde_json = { workspace = true } serde_yml = { workspace = true } sha1 = "0.10" -sha2 = { workspace = true } spiffe = { workspace = true } tempfile = "3" thiserror = { workspace = true } diff --git a/crates/openshell-supervisor-network/src/l7/tls.rs b/crates/openshell-supervisor-network/src/l7/tls.rs index ee7d8b750b..4584288f92 100644 --- a/crates/openshell-supervisor-network/src/l7/tls.rs +++ b/crates/openshell-supervisor-network/src/l7/tls.rs @@ -9,9 +9,10 @@ //! inspects the plaintext HTTP, then re-encrypts to upstream using real root CAs. use miette::{IntoDiagnostic, Result, WrapErr, miette}; -use rcgen::{CertificateParams, DnType, IsCa, KeyPair, KeyUsagePurpose}; +use openshell_crypto::pki::KeyPair; +use rcgen::{CertificateParams, DnType, IsCa, KeyUsagePurpose}; +use rustls::ClientConfig; use rustls::pki_types::{CertificateDer, PrivateKeyDer, ServerName}; -use rustls::{ClientConfig, ServerConfig}; use std::collections::HashMap; use std::io::{BufReader, Write as _}; use std::path::{Path, PathBuf}; @@ -32,8 +33,8 @@ const SYSTEM_CA_PATHS: &[&str] = &[ /// Ephemeral CA certificate and key for MITM TLS termination. #[allow(clippy::struct_field_names)] pub struct SandboxCa { - ca_cert: rcgen::Certificate, - ca_key: KeyPair, + issuer: rcgen::Issuer<'static, KeyPair>, + ca_der: CertificateDer<'static>, ca_cert_pem: String, } @@ -56,8 +57,8 @@ impl SandboxCa { let ca_cert_pem = ca_cert.pem(); Ok(Self { - ca_cert, - ca_key, + ca_der: ca_cert.der().clone(), + issuer: ca_cert.into_issuer(ca_key), ca_cert_pem, }) } @@ -68,8 +69,8 @@ impl SandboxCa { } /// Returns the CA private key in PKCS#8 PEM format. - pub fn private_key_pem(&self) -> String { - self.ca_key.serialize_pem() + pub fn private_key_pem(&self) -> Result { + self.issuer.key().serialize_pem().into_diagnostic() } /// Load a durable CA certificate and matching private key from absolute paths. @@ -117,22 +118,19 @@ impl SandboxCa { .into_diagnostic() .wrap_err("parse proxy CA private key")? .ok_or_else(|| miette!("proxy CA private key file contains no private key"))?; - ServerConfig::builder() + let ca_der = certificates[0].clone(); + openshell_crypto::tls::server_builder() .with_no_client_auth() .with_single_cert(certificates, private_key) .into_diagnostic() .wrap_err("proxy CA certificate and private key do not match")?; - let params = CertificateParams::from_ca_cert_pem(certificate_pem) + let issuer = openshell_crypto::pki::issuer_from_der(&ca_der, ca_key) .into_diagnostic() .wrap_err("parse proxy CA signing certificate")?; - let ca_cert = params - .self_signed(&ca_key) - .into_diagnostic() - .wrap_err("initialize proxy CA signer")?; Ok(Self { - ca_cert, - ca_key, + issuer, + ca_der, ca_cert_pem: certificate_pem.to_string(), }) } @@ -188,13 +186,12 @@ impl CertCache { params.distinguished_name.push(DnType::CommonName, hostname); params.use_authority_key_identifier_extension = true; - let leaf_cert = - openshell_crypto::pki::signed_by(params, &leaf_key, &self.ca.ca_cert, &self.ca.ca_key) - .into_diagnostic()?; + let leaf_cert = openshell_crypto::pki::signed_by_issuer(params, &leaf_key, &self.ca.issuer) + .into_diagnostic()?; let leaf_der = CertificateDer::from(leaf_cert.der().to_vec()); - let ca_der = CertificateDer::from(self.ca.ca_cert.der().to_vec()); - let key_der = PrivateKeyDer::try_from(leaf_key.serialize_der()) + let ca_der = self.ca.ca_der.clone(); + let key_der = PrivateKeyDer::try_from(leaf_key.serialize_der().into_diagnostic()?) .map_err(|e| miette::miette!("failed to serialize leaf key: {e}"))?; Ok(CertifiedLeaf { @@ -222,7 +219,7 @@ impl ProxyTlsState { /// Get or generate a leaf cert for the hostname and return a TLS acceptor. fn acceptor_for(&self, hostname: &str) -> Result { let leaf = self.cert_cache.get_or_generate(hostname)?; - let mut server_config = ServerConfig::builder() + let mut server_config = openshell_crypto::tls::server_builder() .with_no_client_auth() .with_single_cert(leaf.cert_chain.clone(), leaf.private_key.clone_key()) .into_diagnostic()?; @@ -279,7 +276,7 @@ pub async fn tls_connect_upstream( /// `system_ca_bundle` is ignored because the native store already reflects all /// operator-installed trust anchors. pub fn build_upstream_client_config(system_ca_bundle: &str) -> Result> { - let mut config = ClientConfig::builder() + let mut config = openshell_crypto::tls::client_builder() .with_root_certificates(build_upstream_root_store(system_ca_bundle)?) .with_no_client_auth(); config.alpn_protocols = vec![b"http/1.1".to_vec()]; @@ -701,18 +698,47 @@ mod tests { fn durable_ca_round_trip_preserves_certificate_bytes() { let generated = SandboxCa::generate().unwrap(); let certificate = generated.cert_pem().to_string(); - let private_key = generated.private_key_pem(); + let private_key = generated.private_key_pem().unwrap(); let loaded = SandboxCa::from_pem(&certificate, &private_key).unwrap(); assert_eq!(loaded.cert_pem(), certificate); - assert_eq!(loaded.private_key_pem(), private_key); + assert_eq!(loaded.private_key_pem().unwrap(), private_key); + let original_der = rustls_pemfile::certs(&mut certificate.as_bytes()) + .next() + .unwrap() + .unwrap(); + let leaf = CertCache::new(loaded).get_or_generate("localhost").unwrap(); + assert_eq!(leaf.cert_chain[1], original_der); + let mut roots = rustls::RootCertStore::empty(); + roots.add(original_der).unwrap(); + let verifier = rustls::client::WebPkiServerVerifier::builder_with_provider( + Arc::new(roots), + openshell_crypto::tls::configuration_provider(), + ) + .build() + .unwrap(); + rustls::client::danger::ServerCertVerifier::verify_server_cert( + verifier.as_ref(), + &leaf.cert_chain[0], + &[], + &ServerName::try_from("localhost").unwrap(), + &[], + rustls::pki_types::UnixTime::now(), + ) + .unwrap(); } #[test] fn durable_ca_rejects_mismatched_key_and_relative_paths() { let certificate = SandboxCa::generate().unwrap(); let other_key = SandboxCa::generate().unwrap(); - assert!(SandboxCa::from_pem(certificate.cert_pem(), &other_key.private_key_pem()).is_err()); + assert!( + SandboxCa::from_pem( + certificate.cert_pem(), + &other_key.private_key_pem().unwrap() + ) + .is_err() + ); assert!(SandboxCa::load_from_paths(Path::new("ca.pem"), Path::new("ca.key")).is_err()); } } diff --git a/crates/openshell-supervisor-network/src/procfs.rs b/crates/openshell-supervisor-network/src/procfs.rs index a40f812dc5..485a2ef72a 100644 --- a/crates/openshell-supervisor-network/src/procfs.rs +++ b/crates/openshell-supervisor-network/src/procfs.rs @@ -569,13 +569,13 @@ fn collect_descendant_pids_with_depth(root_pid: u32) -> Vec { /// result. Subsequent requests from the same binary path must produce the /// same hash, or the request is denied. pub fn file_sha256(path: &Path) -> Result { - use sha2::{Digest, Sha256}; + use miette::IntoDiagnostic as _; use std::io::Read; let start = std::time::Instant::now(); let mut file = std::fs::File::open(path) .map_err(|e| miette::miette!("Failed to open {}: {e}", path.display()))?; - let mut hasher = Sha256::new(); + let mut hasher = openshell_crypto::sha256_digest().into_diagnostic()?; let mut buf = vec![0u8; 65536].into_boxed_slice(); let mut total_read = 0u64; loop { @@ -586,10 +586,10 @@ pub fn file_sha256(path: &Path) -> Result { break; } total_read += n as u64; - hasher.update(&buf[..n]); + hasher.update(&buf[..n]).into_diagnostic()?; } - let hash = hasher.finalize(); + let hash = hasher.finish().into_diagnostic()?; debug!( " file_sha256: {}ms size={} path={}", start.elapsed().as_millis(), diff --git a/crates/openshell-supervisor-network/src/upstream_proxy.rs b/crates/openshell-supervisor-network/src/upstream_proxy.rs index c819a07ba2..e5dd365c47 100644 --- a/crates/openshell-supervisor-network/src/upstream_proxy.rs +++ b/crates/openshell-supervisor-network/src/upstream_proxy.rs @@ -2260,17 +2260,18 @@ mod tests { ) -> (SocketAddr, tokio::task::JoinHandle, String) { openshell_crypto::tls::ensure_default_provider(); let key = openshell_crypto::pki::generate_keypair().unwrap(); - let cert = rcgen::CertificateParams::new(vec![tls_identity.to_string()]) - .unwrap() - .self_signed(&key) - .unwrap(); + let cert = openshell_crypto::pki::self_signed( + rcgen::CertificateParams::new(vec![tls_identity.to_string()]).unwrap(), + &key, + ) + .unwrap(); let cert_pem = cert.pem(); - let server_config = rustls::ServerConfig::builder() + let server_config = openshell_crypto::tls::server_builder() .with_no_client_auth() .with_single_cert( vec![cert.der().clone()], - rustls::pki_types::PrivateKeyDer::try_from(key.serialize_der()).unwrap(), + rustls::pki_types::PrivateKeyDer::try_from(key.serialize_der().unwrap()).unwrap(), ) .unwrap(); let acceptor = tokio_rustls::TlsAcceptor::from(Arc::new(server_config)); diff --git a/crates/openshell-supervisor/Cargo.toml b/crates/openshell-supervisor/Cargo.toml index a244880960..a812e93c01 100644 --- a/crates/openshell-supervisor/Cargo.toml +++ b/crates/openshell-supervisor/Cargo.toml @@ -15,7 +15,7 @@ name = "openshell-supervisor" path = "src/main.rs" [dependencies] -openshell-crypto = { path = "../openshell-crypto" } +openshell-crypto = { workspace = true } openshell-core = { path = "../openshell-core", default-features = false, features = ["jwt"] } openshell-extension-core = { path = "../openshell-extension-core" } openshell-isolation-interface = { path = "../openshell-isolation-interface" } diff --git a/deny.toml b/deny.toml index 410a92e3b3..64ee8bdbb0 100644 --- a/deny.toml +++ b/deny.toml @@ -57,7 +57,7 @@ registries = [] # -- Bans ---------------------------------------------------------------------- [bans] deny = [ - { name = "ring", wrappers = ["rustls", "rustls-webpki", "x509-parser"], reason = "Use the AWS-LC crypto backend instead. These wrappers are required only by rcgen's CA certificate parser and z3-sys's prebuilt archive downloader." }, + { name = "ring", wrappers = ["rustls", "rustls-webpki"], reason = "Use the selected crypto backend instead. These wrappers are allowed for z3-sys's prebuilt archive downloader." }, ] multiple-versions = "warn" wildcards = "allow" diff --git a/e2e/rust/Cargo.lock b/e2e/rust/Cargo.lock index 4795ab512e..9c1ce78f92 100644 --- a/e2e/rust/Cargo.lock +++ b/e2e/rust/Cargo.lock @@ -2,6 +2,34 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "ahash" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" +dependencies = [ + "cfg-if", + "getrandom 0.3.4", + "once_cell", + "version_check", + "zerocopy", +] + +[[package]] +name = "aho-corasick" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c982642fa9e8606056828ee9a8505737230110bb1099153c79efe865c59d12ba" +dependencies = [ + "memchr", +] + +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + [[package]] name = "anyhow" version = "1.0.104" @@ -10,9 +38,9 @@ checksum = "330a5ed07fa54e4702c9d6c4174f74427fc0ef6e214bbd677ae50a5099946470" [[package]] name = "asn1-rs" -version = "0.6.2" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5493c3bedbacf7fd7382c6346bbd66687d12bbaad3a89a2d2c303ee6cf20b048" +checksum = "b7f43a50ac4fdca5df8e885c21b835997f0a1cdee65494a6847694a98652d9d8" dependencies = [ "asn1-rs-derive", "asn1-rs-impl", @@ -20,15 +48,15 @@ dependencies = [ "nom", "num-traits", "rusticata-macros", - "thiserror 1.0.69", + "thiserror", "time", ] [[package]] name = "asn1-rs-derive" -version = "0.5.1" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "965c2d33e53cb6b267e148a4cb0760bc01f4904c1cd4bb4002a085bb016d1490" +checksum = "3109e49b1e4909e9db6515a30c633684d68cdeaa252f215214cb4fa1a5bfee2c" dependencies = [ "proc-macro2", "quote", @@ -47,6 +75,40 @@ dependencies = [ "syn 2.0.119", ] +[[package]] +name = "async-broadcast" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "435a87a52755b8f27fcf321ac4f04b2802e337c8c4872923137471ec39c37532" +dependencies = [ + "event-listener", + "event-listener-strategy", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-stream" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" +dependencies = [ + "async-stream-impl", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-stream-impl" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + [[package]] name = "async-trait" version = "0.1.91" @@ -58,6 +120,15 @@ dependencies = [ "syn 3.0.3", ] +[[package]] +name = "atoi" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28d99ec8bfea296261ca1af174f24225171fea9664ba9003cbebee704810528" +dependencies = [ + "num-traits", +] + [[package]] name = "atomic-waker" version = "1.1.2" @@ -137,17 +208,46 @@ dependencies = [ "tower-service", ] +[[package]] +name = "backon" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cffb0e931875b666fc4fcb20fee52e9bbd1ef836fd9e9e04ec21555f9f85f7ef" +dependencies = [ + "fastrand", + "gloo-timers", + "tokio", +] + [[package]] name = "base64" version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +[[package]] +name = "base64" +version = "0.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac07cdecf99051d9a5238b80f35af32cdeba5b336e55d957b318b50137e18da5" + +[[package]] +name = "bit-vec" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b71798fca2c1fe1086445a7258a4bc81e6e49dcd24c8d0dd9a1e57395b603f51" +dependencies = [ + "serde", +] + [[package]] name = "bitflags" version = "2.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b588b76d00fde79687d7646a9b5bdf3cc0f655e0bbd080335a95d7e96f3587da" +dependencies = [ + "serde_core", +] [[package]] name = "block-buffer" @@ -158,13 +258,22 @@ dependencies = [ "generic-array", ] +[[package]] +name = "block-buffer" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2f6c7dbe95a6ed67ad9f18e57daf93a2f034c524b99fd2b76d18fdfeb6660aa" +dependencies = [ + "hybrid-array", +] + [[package]] name = "bollard" version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ee04c4c84f1f811b017f2fbb7dd8815c976e7ca98593de9c1e2afad0f636bff4" dependencies = [ - "base64", + "base64 0.22.1", "bollard-stubs", "bytes", "futures-core", @@ -182,7 +291,7 @@ dependencies = [ "serde_derive", "serde_json", "serde_urlencoded", - "thiserror 2.0.19", + "thiserror", "tokio", "tokio-util", "tower-service", @@ -207,6 +316,12 @@ version = "3.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + [[package]] name = "bytes" version = "1.12.1" @@ -237,6 +352,27 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f079e83a288787bcd14a6aea84cee5c87a67c5a3e660c30f557a3d24761b3527" +[[package]] +name = "chacha20" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65c35e4b699c7e15ccbe7ee35c005e4fc0a278d22238a2857e6ce2dadeda1b06" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.1", + "rand_core 0.10.1", +] + +[[package]] +name = "chrono" +version = "0.4.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aa79e62e7697b8e29b513a68abacf485adcd1fe8284a4316c5ae868e6633327" +dependencies = [ + "num-traits", + "serde", +] + [[package]] name = "cmake" version = "0.1.58" @@ -246,6 +382,28 @@ dependencies = [ "cc", ] +[[package]] +name = "cmov" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c9ea0ac24bc397ab3c98583a3c9ba74fa56b09a4449bbe172b9b1ddb016027a" + +[[package]] +name = "core-foundation" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + [[package]] name = "cpufeatures" version = "0.2.17" @@ -255,6 +413,45 @@ dependencies = [ "libc", ] +[[package]] +name = "cpufeatures" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ca28b0ae3115b884660db4118d803791fd6756b6e88f39c0f3f7859060d7566" +dependencies = [ + "libc", +] + +[[package]] +name = "crc" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5eb8a2a1cd12ab0d987a5d5e825195d372001a4094a0376319d5a0ad71c1ba0d" +dependencies = [ + "crc-catalog", +] + +[[package]] +name = "crc-catalog" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "217698eaf96b4a3f0bc4f3662aaa55bdf913cd54d7204591faa790070c6d0853" + +[[package]] +name = "crossbeam-queue" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03e8bd762f7479489c70ed6c768ddca99d7296857de437a68dcb2a94365b3fae" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a31eee39dddec8330830986fcd7625edb5a24ec90ea038215273bbc3adb08ac6" + [[package]] name = "crypto-common" version = "0.1.7" @@ -265,6 +462,59 @@ dependencies = [ "typenum", ] +[[package]] +name = "crypto-common" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce6e4c961d6cd6c9a86db418387425e8bdeaf05b3c8bc1411e6dca4c252f1453" +dependencies = [ + "hybrid-array", +] + +[[package]] +name = "ctutils" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d5515a3834141de9eafb9717ad39eea8247b5674e6066c404e8c4b365d2a29e" +dependencies = [ + "cmov", +] + +[[package]] +name = "darling" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.119", +] + +[[package]] +name = "darling_macro" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" +dependencies = [ + "darling_core", + "quote", + "syn 2.0.119", +] + [[package]] name = "data-encoding" version = "2.11.1" @@ -273,9 +523,9 @@ checksum = "4583a4551df46e2792f82ceeac45e850d2e2d5debba0b91f102385cda5b11f06" [[package]] name = "der-parser" -version = "9.0.0" +version = "10.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cd0a5c643689626bec213c4d8bd4d96acc8ffdb4ad4bb6bc16abf27d5f4b553" +checksum = "07da5016415d5a3c4dd39b11ed26f915f52fc4e0dc197d87908bc916e51bc1a6" dependencies = [ "asn1-rs", "displaydoc", @@ -297,8 +547,19 @@ version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ - "block-buffer", - "crypto-common", + "block-buffer 0.10.4", + "crypto-common 0.1.7", +] + +[[package]] +name = "digest" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2" +dependencies = [ + "block-buffer 0.12.1", + "crypto-common 0.2.2", + "ctutils", ] [[package]] @@ -312,17 +573,64 @@ dependencies = [ "syn 3.0.3", ] +[[package]] +name = "dotenvy" +version = "0.15.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" + [[package]] name = "dunce" version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" +[[package]] +name = "dyn-clone" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" + +[[package]] +name = "educe" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7bc049e1bd8cdeb31b68bbd586a9464ecf9f3944af3958a7a9d0f8b9799417" +dependencies = [ + "enum-ordinalize", + "proc-macro2", + "quote", + "syn 2.0.119", +] + [[package]] name = "either" version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e5e8f6c15a24b9a3ee5efec809ccd006d3b30e8b3bb63c39af737c7f87daa1d" +dependencies = [ + "serde", +] + +[[package]] +name = "enum-ordinalize" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89dd01549b09589510cf0647475075d12071456586d70f5c75c98ae2a5537677" +dependencies = [ + "enum-ordinalize-derive", +] + +[[package]] +name = "enum-ordinalize-derive" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a65863d15a4ce2888bd2f0f543cc963d3879c3a022c8ee43f6141d479a3ac815" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.3", +] [[package]] name = "equivalent" @@ -340,6 +648,36 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "etcetera" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de48cc4d1c1d97a20fd819def54b890cadde72ed3ad0c614822a0a433361be96" +dependencies = [ + "cfg-if", + "windows-sys 0.61.2", +] + +[[package]] +name = "event-listener" +version = "5.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a23add41df1562121a9393cb065eab5146a1242410f23a644851e90cfd669d2" +dependencies = [ + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" +dependencies = [ + "event-listener", + "pin-project-lite", +] + [[package]] name = "fastrand" version = "2.5.0" @@ -352,12 +690,35 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" +[[package]] +name = "flume" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e139bc46ca777eb5efaf62df0ab8cc5fd400866427e56c68b22e414e53bd3be" +dependencies = [ + "futures-core", + "futures-sink", + "spin", +] + [[package]] name = "fnv" version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + +[[package]] +name = "foldhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + [[package]] name = "form_urlencoded" version = "1.2.2" @@ -373,6 +734,20 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" +[[package]] +name = "futures" +version = "0.3.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a88cf1f829d945f548cf8fec32c61b1f202b6d93b45848602fc02af4b12ad218" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + [[package]] name = "futures-channel" version = "0.3.33" @@ -380,6 +755,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "262590f4fe6afeb0bc83be1daa64e52657fe185690a958af7f3ad0e92085c5ae" dependencies = [ "futures-core", + "futures-sink", ] [[package]] @@ -399,6 +775,23 @@ dependencies = [ "futures-util", ] +[[package]] +name = "futures-intrusive" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d930c203dd0b6ff06e0201a4a2fe9149b43c684fd4420555b26d21b1a02956f" +dependencies = [ + "futures-core", + "lock_api", + "parking_lot", +] + +[[package]] +name = "futures-io" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53c0fa8157de1303bfffdaa1cc2a673bfffb60102f76b0ef4441659124373fed" + [[package]] name = "futures-macro" version = "0.3.33" @@ -428,9 +821,13 @@ version = "0.3.33" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a77a90a256fce34da66415271e30f94ee91c57b04b8a2c042d9cf3220179deaa" dependencies = [ + "futures-channel", "futures-core", + "futures-io", "futures-macro", + "futures-sink", "futures-task", + "memchr", "pin-project-lite", "slab", ] @@ -477,6 +874,19 @@ dependencies = [ "cfg-if", "libc", "r-efi 6.0.0", + "rand_core 0.10.1", +] + +[[package]] +name = "gloo-timers" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbb143cf96099802033e0d4f4963b19fd2e0b728bcf076cd9cf7f6634f092994" +dependencies = [ + "futures-channel", + "futures-core", + "js-sys", + "wasm-bindgen", ] [[package]] @@ -498,18 +908,117 @@ dependencies = [ "tracing", ] +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash 0.1.5", +] + +[[package]] +name = "hashbrown" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash 0.2.0", +] + [[package]] name = "hashbrown" version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" +[[package]] +name = "hashlink" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "824e001ac4f3012dd16a264bec811403a67ca9deb6c102fc5049b32c4574b35f" +dependencies = [ + "hashbrown 0.16.1", +] + +[[package]] +name = "headers" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3314d5adb5d94bcdf56771f2e50dbbc80bb4bdf88967526706205ac9eff24eb" +dependencies = [ + "base64 0.22.1", + "bytes", + "headers-core", + "http", + "httpdate", + "mime", + "sha1 0.10.7", +] + +[[package]] +name = "headers-core" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54b4a22553d4242c49fddb9ba998a99962b5cc6f22cb5a3482bec22522403ce4" +dependencies = [ + "http", +] + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + [[package]] name = "hex" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[package]] +name = "hkdf" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4aaa26c720c68b866f2c96ef5c1264b3e6f473fe5d4ce61cd44bbe913e553018" +dependencies = [ + "hmac", +] + +[[package]] +name = "hmac" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6303bc9732ae41b04cb554b844a762b4115a61bfaa81e3e83050991eeb56863f" +dependencies = [ + "digest 0.11.3", +] + +[[package]] +name = "home" +version = "0.5.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "hostname" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "617aaa3557aef3810a6369d0a99fac8a080891b68bd9f9812a1eeda0c0730cbd" +dependencies = [ + "cfg-if", + "libc", + "windows-link", +] + [[package]] name = "http" version = "1.5.0" @@ -555,6 +1064,15 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" +[[package]] +name = "hybrid-array" +version = "0.4.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27f864f10dfb56725ce5ce5472bc52252c8f93a4ab86327122cebf62c5f59a17" +dependencies = [ + "typenum", +] + [[package]] name = "hyper" version = "1.11.0" @@ -577,6 +1095,25 @@ dependencies = [ "want", ] +[[package]] +name = "hyper-http-proxy" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd1d471ea2f65ba45eddb1d6ab7d58ac2671d2d4ac14da5c6516ae1d97e1327a" +dependencies = [ + "bytes", + "futures-util", + "headers", + "http", + "hyper", + "hyper-rustls", + "hyper-util", + "pin-project-lite", + "tokio", + "tokio-rustls", + "tower-service", +] + [[package]] name = "hyper-named-pipe" version = "0.1.1" @@ -591,6 +1128,23 @@ dependencies = [ "tower-service", ] +[[package]] +name = "hyper-rustls" +version = "0.27.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ca68d021ef39cf6463ab54c1d0f5daf03377b70561305bb89a8f83aab66e0f" +dependencies = [ + "http", + "hyper", + "hyper-util", + "log", + "rustls", + "rustls-native-certs", + "tokio", + "tokio-rustls", + "tower-service", +] + [[package]] name = "hyper-timeout" version = "0.5.2" @@ -721,6 +1275,12 @@ dependencies = [ "zerovec", ] +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + [[package]] name = "idna" version = "1.1.0" @@ -749,7 +1309,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" dependencies = [ "equivalent", - "hashbrown", + "hashbrown 0.17.1", "serde", "serde_core", ] @@ -790,6 +1350,41 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "json-patch" +version = "4.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7421438de105a0827e44fadd05377727847d717c80ce29a229f85fd04c427b72" +dependencies = [ + "jsonptr", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "jsonpath-rust" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c00ae348f9f8fd2d09f82a98ca381c60df9e0820d8d79fce43e649b4dc3128b" +dependencies = [ + "pest", + "pest_derive", + "regex", + "serde_json", + "thiserror", +] + +[[package]] +name = "jsonptr" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5a3cc660ba5d72bce0b3bb295bf20847ccbb40fd423f3f05b61273672e561fe" +dependencies = [ + "serde", + "serde_json", +] + [[package]] name = "jsonwebtoken" version = "10.4.0" @@ -797,10 +1392,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eba32bfb4ffdeaca3e34431072faf01745c9b26d25504aa7a6cf5684334fc4fc" dependencies = [ "aws-lc-rs", - "base64", + "base64 0.22.1", "getrandom 0.2.17", "js-sys", - "pem", + "pem 3.0.6", "serde", "serde_json", "signature", @@ -808,6 +1403,129 @@ dependencies = [ "zeroize", ] +[[package]] +name = "k8s-openapi" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c75b990324f09bef15e791606b7b7a296d02fc88a344f6eba9390970a870ad5" +dependencies = [ + "base64 0.22.1", + "chrono", + "serde", + "serde-value", + "serde_json", +] + +[[package]] +name = "kube" +version = "0.99.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a4eb20010536b48abe97fec37d23d43069bcbe9686adcf9932202327bc5ca6e" +dependencies = [ + "k8s-openapi", + "kube-client", + "kube-core", + "kube-derive", + "kube-runtime", +] + +[[package]] +name = "kube-client" +version = "0.99.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fc2ed952042df20d15ac2fe9614d0ec14b6118eab89633985d4b36e688dccf1" +dependencies = [ + "base64 0.22.1", + "bytes", + "chrono", + "either", + "futures", + "home", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-http-proxy", + "hyper-rustls", + "hyper-timeout", + "hyper-util", + "jsonpath-rust", + "k8s-openapi", + "kube-core", + "pem 3.0.6", + "rustls", + "secrecy", + "serde", + "serde_json", + "serde_yaml", + "thiserror", + "tokio", + "tokio-util", + "tower", + "tower-http", + "tracing", +] + +[[package]] +name = "kube-core" +version = "0.99.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff0d0793db58e70ca6d689489183816cb3aa481673e7433dc618cf7e8007c675" +dependencies = [ + "chrono", + "form_urlencoded", + "http", + "json-patch", + "k8s-openapi", + "schemars", + "serde", + "serde-value", + "serde_json", + "thiserror", +] + +[[package]] +name = "kube-derive" +version = "0.99.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c562f58dc9f7ca5feac8a6ee5850ca221edd6f04ce0dd2ee873202a88cd494c9" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "serde", + "serde_json", + "syn 2.0.119", +] + +[[package]] +name = "kube-runtime" +version = "0.99.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88f34cfab9b4bd8633062e0e85edb81df23cb09f159f2e31c60b069ae826ffdc" +dependencies = [ + "ahash", + "async-broadcast", + "async-stream", + "async-trait", + "backon", + "educe", + "futures", + "hashbrown 0.15.5", + "hostname", + "json-patch", + "k8s-openapi", + "kube-client", + "parking_lot", + "pin-project", + "serde", + "serde_json", + "thiserror", + "tokio", + "tokio-util", + "tracing", +] + [[package]] name = "lazy_static" version = "1.5.0" @@ -826,6 +1544,17 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" +[[package]] +name = "libsqlite3-sys" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f111c8c41e7c61a49cd34e44c7619462967221a6443b0ec299e0ac30cfb9b1" +dependencies = [ + "cc", + "pkg-config", + "vcpkg", +] + [[package]] name = "linux-raw-sys" version = "0.12.1" @@ -859,6 +1588,16 @@ version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" +[[package]] +name = "md-5" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69b6441f590336821bb897fb28fc622898ccceb1d6cea3fde5ea86b090c4de98" +dependencies = [ + "cfg-if", + "digest 0.11.3", +] + [[package]] name = "memchr" version = "2.8.3" @@ -916,7 +1655,7 @@ version = "0.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f075ef19fa3bcf8697c0ef96c37d5c435d339a40ab8081cae3aac3a4e7fee9a" dependencies = [ - "hashbrown", + "hashbrown 0.17.1", "indexmap", "libm", "memchr", @@ -962,9 +1701,9 @@ dependencies = [ [[package]] name = "oid-registry" -version = "0.7.1" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8d8034d9489cdaf79228eb9f6a3b8d7bb32ba00d6645ebd48eef4077ceb5bd9" +checksum = "12f40cff3dde1b6087cc5d5f5d4d65712f34016a03ed60e9c08dcc392736b5b7" dependencies = [ "asn1-rs", ] @@ -980,18 +1719,24 @@ name = "openshell-crypto" version = "0.0.0" dependencies = [ "aws-lc-rs", + "hyper-rustls", "jsonwebtoken", + "kube", + "pem 3.0.6", "rcgen", "rustls", "serde", - "thiserror 2.0.19", + "sqlx", + "thiserror", + "tonic", + "x509-parser", ] [[package]] name = "openshell-e2e" version = "0.1.0" dependencies = [ - "base64", + "base64 0.22.1", "bollard", "bytes", "futures-util", @@ -1004,12 +1749,12 @@ dependencies = [ "noyalib", "openshell-crypto", "prost", - "rand", + "rand 0.9.5", "serde", "serde_json", "serial_test", - "sha1", - "sha2", + "sha1 0.10.7", + "sha2 0.10.9", "tempfile", "tokio", "tokio-stream", @@ -1019,6 +1764,27 @@ dependencies = [ "url", ] +[[package]] +name = "openssl-probe" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" + +[[package]] +name = "ordered-float" +version = "2.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68f19d67e5a2795c94e73e0bb1cc1a7edeb2e28efd39e2e1c9b7a40c1108b11c" +dependencies = [ + "num-traits", +] + +[[package]] +name = "parking" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" + [[package]] name = "parking_lot" version = "0.12.5" @@ -1048,7 +1814,17 @@ version = "3.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d30c53c26bc5b31a98cd02d20f25a7c8567146caf63ed593a9d87b2775291be" dependencies = [ - "base64", + "base64 0.22.1", + "serde_core", +] + +[[package]] +name = "pem" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d354a98a3d1251555de99e8fdd8afda05573c31b82f59063a7b0a29b5527f120" +dependencies = [ + "base64 0.23.1", "serde_core", ] @@ -1058,6 +1834,48 @@ version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" +[[package]] +name = "pest" +version = "2.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d45aeb61b4bf818e12d4205f2466f8c4748f85f4fce0146d1c03d69d753f0ad" +dependencies = [ + "memchr", + "ucd-trie", +] + +[[package]] +name = "pest_derive" +version = "2.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89cc5a242e25ed4e7704d0be240f2cfbe20a8c27e7e252d94835be93d92dc39f" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" +version = "2.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7abf21475cc3820fe4b2ca2dc2142902f67a02189f3b5b3a229f4febc01a43e5" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "pest_meta" +version = "2.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adba4db388f687393c18c51348d44a41d870ca9df71a2c98172ea3035dc6936e" +dependencies = [ + "pest", +] + [[package]] name = "pin-project" version = "1.1.13" @@ -1177,6 +1995,17 @@ dependencies = [ "rand_core 0.9.5", ] +[[package]] +name = "rand" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7f5fa3a058cd35567ef9bfa5e75732bee0f9e4c55fa90477bef2dfcdbc4be80" +dependencies = [ + "chacha20", + "getrandom 0.4.3", + "rand_core 0.10.1", +] + [[package]] name = "rand_chacha" version = "0.9.0" @@ -1205,14 +2034,20 @@ dependencies = [ "getrandom 0.3.4", ] +[[package]] +name = "rand_core" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" + [[package]] name = "rcgen" -version = "0.13.2" +version = "0.14.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75e669e5202259b5314d1ea5397316ad400819437857b90861765f24c4cf80a2" +checksum = "8774e05a7d0de114588e6a28fe7e71694b82614ed569d86d8b389dfbc98b8ad8" dependencies = [ "aws-lc-rs", - "pem", + "pem 4.0.0", "rustls-pki-types", "time", "x509-parser", @@ -1228,6 +2063,35 @@ dependencies = [ "bitflags", ] +[[package]] +name = "regex" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f020237b6c8eed93db2e2cb53c00c60a8e1bc73da7d073199a1180401450218d" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad8553b9b26413251cbf30e620595c7a41b3887f03da04579c0e6b0d6a06b4b2" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4" + [[package]] name = "ring" version = "0.17.14" @@ -1285,6 +2149,18 @@ dependencies = [ "zeroize", ] +[[package]] +name = "rustls-native-certs" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dab5152771c58876a2146916e53e35057e1a4dfa2b9df0f0305b07f611fdea4d" +dependencies = [ + "openssl-probe", + "rustls-pki-types", + "schannel", + "security-framework", +] + [[package]] name = "rustls-pki-types" version = "1.15.0" @@ -1307,22 +2183,87 @@ dependencies = [ ] [[package]] -name = "rustversion" -version = "1.0.23" +name = "rustversion" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f" + +[[package]] +name = "ryu" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" + +[[package]] +name = "schannel" +version = "0.1.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91c1b7e4904c873ef0710c1f407dde2e6287de2bebc1bbbf7d430bb7cbffd939" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "schemars" +version = "0.8.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fbf2ae1b8bc8e02df939598064d22402220cd5bbcca1c76f7d6a310974d5615" +dependencies = [ + "dyn-clone", + "schemars_derive", + "serde", + "serde_json", +] + +[[package]] +name = "schemars_derive" +version = "0.8.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32e265784ad618884abaea0600a9adf15393368d840e0222d101a072f3f7534d" +dependencies = [ + "proc-macro2", + "quote", + "serde_derive_internals", + "syn 2.0.119", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "secrecy" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f" +checksum = "e891af845473308773346dc847b2c23ee78fe442e0472ac50e22a18a93d3ae5a" +dependencies = [ + "zeroize", +] [[package]] -name = "ryu" -version = "1.0.23" +name = "security-framework" +version = "3.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" +checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d" +dependencies = [ + "bitflags", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] [[package]] -name = "scopeguard" -version = "1.2.0" +name = "security-framework-sys" +version = "2.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +checksum = "6ce2691df843ecc5d231c0b14ece2acc3efb62c0a398c7e1d875f3983ce020e3" +dependencies = [ + "core-foundation-sys", + "libc", +] [[package]] name = "serde" @@ -1334,6 +2275,16 @@ dependencies = [ "serde_derive", ] +[[package]] +name = "serde-value" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3a1a3341211875ef120e117ea7fd5228530ae7e7036a779fdc9117be6b3282c" +dependencies = [ + "ordered-float", + "serde", +] + [[package]] name = "serde_core" version = "1.0.229" @@ -1354,6 +2305,17 @@ dependencies = [ "syn 3.0.3", ] +[[package]] +name = "serde_derive_internals" +version = "0.29.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + [[package]] name = "serde_json" version = "1.0.151" @@ -1390,6 +2352,19 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_yaml" +version = "0.9.34+deprecated" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" +dependencies = [ + "indexmap", + "itoa", + "ryu", + "serde", + "unsafe-libyaml", +] + [[package]] name = "serial_test" version = "3.5.0" @@ -1422,8 +2397,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a978451301f4db1d02937a4ab3ccce137717b81826e79b7d49ffe3244a13c3b8" dependencies = [ "cfg-if", - "cpufeatures", - "digest", + "cpufeatures 0.2.17", + "digest 0.10.7", +] + +[[package]] +name = "sha1" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aacc4cc499359472b4abe1bf11d0b12e688af9a805fa5e3016f9a386dc2d0214" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.1", + "digest 0.11.3", ] [[package]] @@ -1433,8 +2419,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ "cfg-if", - "cpufeatures", - "digest", + "cpufeatures 0.2.17", + "digest 0.10.7", +] + +[[package]] +name = "sha2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "446ba717509524cb3f22f17ecc096f10f4822d76ab5c0b9822c5f9c284e825f4" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.1", + "digest 0.11.3", ] [[package]] @@ -1470,7 +2467,7 @@ checksum = "0d585997b0ac10be3c5ee635f1bab02d512760d14b7c468801ac8a01d9ae5f1d" dependencies = [ "num-bigint", "num-traits", - "thiserror 2.0.19", + "thiserror", "time", ] @@ -1485,6 +2482,9 @@ name = "smallvec" version = "1.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ed6a63f02c8539c91a8685a86f4099661ba3da017932f6ebbea6de3f0fa7c90" +dependencies = [ + "serde", +] [[package]] name = "socket2" @@ -1496,12 +2496,210 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "spin" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3763264f6b73151db08c50ff20d7d8a0b8796e021cdea7ceedad07b80155fa0e" +dependencies = [ + "lock_api", +] + +[[package]] +name = "sqlx" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "378620ccc25c62c89d8be1c819e76a88d59bdcc3304733330788948e619bfd71" +dependencies = [ + "sqlx-core", + "sqlx-macros", + "sqlx-mysql", + "sqlx-postgres", + "sqlx-sqlite", +] + +[[package]] +name = "sqlx-core" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05b44e85bf579a8eeb4ceaa77a3a523baf2bf0e9bac7e40f405d537b5d2d5ccb" +dependencies = [ + "base64 0.22.1", + "bytes", + "cfg-if", + "crc", + "crossbeam-queue", + "either", + "event-listener", + "futures-core", + "futures-intrusive", + "futures-io", + "futures-util", + "hashbrown 0.16.1", + "hashlink", + "indexmap", + "log", + "memchr", + "percent-encoding", + "rustls", + "serde", + "serde_json", + "sha2 0.10.9", + "smallvec", + "thiserror", + "tokio", + "tokio-stream", + "tracing", + "url", + "webpki-roots", +] + +[[package]] +name = "sqlx-macros" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd2b84f2bc39a5705ef27ec785a11c934a41bbd4a24941e257927cddc26b60bf" +dependencies = [ + "proc-macro2", + "quote", + "sqlx-core", + "sqlx-macros-core", + "syn 2.0.119", +] + +[[package]] +name = "sqlx-macros-core" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb8d96de5fdc85a5c4ec813432b523ec637e80ba98f046555f75f7908ddac7c3" +dependencies = [ + "cfg-if", + "dotenvy", + "either", + "heck", + "hex", + "proc-macro2", + "quote", + "serde", + "serde_json", + "sha2 0.10.9", + "sqlx-core", + "sqlx-postgres", + "sqlx-sqlite", + "syn 2.0.119", + "thiserror", + "tokio", + "url", +] + +[[package]] +name = "sqlx-mysql" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90b8020fe17c5f2c245bfa2505d7ef59c5604839527c740266ad2214acebea27" +dependencies = [ + "bitflags", + "byteorder", + "bytes", + "crc", + "digest 0.11.3", + "dotenvy", + "either", + "futures-core", + "futures-util", + "generic-array", + "log", + "percent-encoding", + "serde", + "sha1 0.11.0", + "sha2 0.11.0", + "sqlx-core", + "thiserror", + "tracing", +] + +[[package]] +name = "sqlx-postgres" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87a2bdd6e83f6b3ea525ca9fee568030508b58355a43d0b2c1674d5f79dcd65e" +dependencies = [ + "atoi", + "base64 0.22.1", + "bitflags", + "byteorder", + "crc", + "dotenvy", + "etcetera", + "futures-channel", + "futures-core", + "futures-util", + "hex", + "hkdf", + "hmac", + "itoa", + "log", + "md-5", + "memchr", + "rand 0.10.2", + "serde", + "serde_json", + "sha2 0.11.0", + "smallvec", + "sqlx-core", + "stringprep", + "thiserror", + "tracing", + "whoami", +] + +[[package]] +name = "sqlx-sqlite" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "488e99c397a62007e4229aec669a179816339afc6d2620ca6fa420dbee2e982c" +dependencies = [ + "atoi", + "flume", + "form_urlencoded", + "futures-channel", + "futures-core", + "futures-executor", + "futures-intrusive", + "futures-util", + "libsqlite3-sys", + "log", + "percent-encoding", + "serde", + "sqlx-core", + "thiserror", + "tracing", + "url", +] + [[package]] name = "stable_deref_trait" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" +[[package]] +name = "stringprep" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b4df3d392d81bd458a8a621b8bffbd2302a12ffe288a9d931670948749463b1" +dependencies = [ + "unicode-bidi", + "unicode-normalization", + "unicode-properties", +] + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + [[package]] name = "subtle" version = "2.6.1" @@ -1560,33 +2758,13 @@ dependencies = [ "windows-sys 0.61.2", ] -[[package]] -name = "thiserror" -version = "1.0.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" -dependencies = [ - "thiserror-impl 1.0.69", -] - [[package]] name = "thiserror" version = "2.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09a43598840e33d5b0331f38c5e30d13bb11c11210a4b58f0d9b18a5a5eefcd9" dependencies = [ - "thiserror-impl 2.0.19", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.119", + "thiserror-impl", ] [[package]] @@ -1640,6 +2818,12 @@ dependencies = [ "zerovec", ] +[[package]] +name = "tinyvec" +version = "1.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd3ca314f692efd6c868f8408f53fe444634a845f96c028b97d35f6a1f79f0ee" + [[package]] name = "tokio" version = "1.53.1" @@ -1668,6 +2852,16 @@ dependencies = [ "syn 3.0.3", ] +[[package]] +name = "tokio-rustls" +version = "0.26.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0c85f2c3ef0b1cd58b36682f4b17aaa995f0e5db534d85692b4903abce21f67" +dependencies = [ + "rustls", + "tokio", +] + [[package]] name = "tokio-stream" version = "0.1.19" @@ -1690,6 +2884,7 @@ dependencies = [ "futures-sink", "libc", "pin-project-lite", + "slab", "tokio", ] @@ -1701,7 +2896,7 @@ checksum = "ac2a5518c70fa84342385732db33fb3f44bc4cc748936eb5833d2df34d6445ef" dependencies = [ "async-trait", "axum", - "base64", + "base64 0.22.1", "bytes", "h2", "http", @@ -1715,6 +2910,7 @@ dependencies = [ "socket2", "sync_wrapper", "tokio", + "tokio-rustls", "tokio-stream", "tower", "tower-layer", @@ -1752,6 +2948,24 @@ dependencies = [ "tracing", ] +[[package]] +name = "tower-http" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cfcf7e2740e6fc6d4d688b4ef00650406bb94adf4731e43c096c3a19fe40840" +dependencies = [ + "base64 0.22.1", + "bitflags", + "bytes", + "http", + "http-body", + "mime", + "pin-project-lite", + "tower-layer", + "tower-service", + "tracing", +] + [[package]] name = "tower-layer" version = "0.3.3" @@ -1770,6 +2984,7 @@ version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" dependencies = [ + "log", "pin-project-lite", "tracing-attributes", "tracing-core", @@ -1807,12 +3022,45 @@ version = "1.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" +[[package]] +name = "ucd-trie" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" + +[[package]] +name = "unicode-bidi" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" + [[package]] name = "unicode-ident" version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" +[[package]] +name = "unicode-normalization" +version = "0.1.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fd4f6878c9cb28d874b009da9e8d183b5abc80117c40bbd187a1fde336be6e8" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-properties" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7df058c713841ad818f1dc5d3fd88063241cc61f49f5fbea4b951e8cf5a8d71d" + +[[package]] +name = "unsafe-libyaml" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" + [[package]] name = "untrusted" version = "0.7.1" @@ -1843,6 +3091,12 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + [[package]] name = "version_check" version = "0.9.5" @@ -1918,6 +3172,21 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "webpki-roots" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dcd9d09a39985f5344844e66b0c530a33843579125f23e21e9f0f220850f22a" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "whoami" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "626c4bac6755d76ffc12cb01b2eac751db1996b9e0041de9aa02c8c211ddc82c" + [[package]] name = "winapi" version = "0.3.9" @@ -2042,28 +3311,29 @@ checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4" [[package]] name = "x509-parser" -version = "0.16.0" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcbc162f30700d6f3f82a24bf7cc62ffe7caea42c0b2cba8bf7f3ae50cf51f69" +checksum = "d43b0f71ce057da06bc0851b23ee24f3f86190b07203dd8f567d0b706a185202" dependencies = [ "asn1-rs", + "aws-lc-rs", "data-encoding", "der-parser", "lazy_static", "nom", "oid-registry", - "ring", "rusticata-macros", - "thiserror 1.0.69", + "thiserror", "time", ] [[package]] name = "yasna" -version = "0.5.2" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e17bb3549cc1321ae1296b9cdc2698e2b6cb1992adfa19a8c72e5b7a738f44cd" +checksum = "b5f6765e852b9b4dc8e2a76843e4d64d1cea8e79bcde0b6901aea8e7c7f08282" dependencies = [ + "bit-vec", "time", ] diff --git a/examples/governance-interceptor/Cargo.lock b/examples/governance-interceptor/Cargo.lock index c79cca717d..7c0d46fa13 100644 --- a/examples/governance-interceptor/Cargo.lock +++ b/examples/governance-interceptor/Cargo.lock @@ -17,6 +17,19 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" +[[package]] +name = "ahash" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" +dependencies = [ + "cfg-if", + "getrandom 0.3.4", + "once_cell", + "version_check", + "zerocopy", +] + [[package]] name = "aho-corasick" version = "1.1.5" @@ -26,6 +39,12 @@ dependencies = [ "memchr", ] +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + [[package]] name = "anyhow" version = "1.0.104" @@ -34,9 +53,9 @@ checksum = "330a5ed07fa54e4702c9d6c4174f74427fc0ef6e214bbd677ae50a5099946470" [[package]] name = "asn1-rs" -version = "0.6.2" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5493c3bedbacf7fd7382c6346bbd66687d12bbaad3a89a2d2c303ee6cf20b048" +checksum = "b7f43a50ac4fdca5df8e885c21b835997f0a1cdee65494a6847694a98652d9d8" dependencies = [ "asn1-rs-derive", "asn1-rs-impl", @@ -44,15 +63,15 @@ dependencies = [ "nom", "num-traits", "rusticata-macros", - "thiserror 1.0.69", + "thiserror", "time", ] [[package]] name = "asn1-rs-derive" -version = "0.5.1" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "965c2d33e53cb6b267e148a4cb0760bc01f4904c1cd4bb4002a085bb016d1490" +checksum = "3109e49b1e4909e9db6515a30c633684d68cdeaa252f215214cb4fa1a5bfee2c" dependencies = [ "proc-macro2", "quote", @@ -71,6 +90,40 @@ dependencies = [ "syn 2.0.119", ] +[[package]] +name = "async-broadcast" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "435a87a52755b8f27fcf321ac4f04b2802e337c8c4872923137471ec39c37532" +dependencies = [ + "event-listener", + "event-listener-strategy", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-stream" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" +dependencies = [ + "async-stream-impl", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-stream-impl" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + [[package]] name = "async-trait" version = "0.1.92" @@ -82,6 +135,15 @@ dependencies = [ "syn 3.0.5", ] +[[package]] +name = "atoi" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28d99ec8bfea296261ca1af174f24225171fea9664ba9003cbebee704810528" +dependencies = [ + "num-traits", +] + [[package]] name = "atomic-waker" version = "1.1.2" @@ -161,6 +223,17 @@ dependencies = [ "tower-service", ] +[[package]] +name = "backon" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cffb0e931875b666fc4fcb20fee52e9bbd1ef836fd9e9e04ec21555f9f85f7ef" +dependencies = [ + "fastrand", + "gloo-timers", + "tokio", +] + [[package]] name = "backtrace" version = "0.3.76" @@ -191,11 +264,29 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +[[package]] +name = "base64" +version = "0.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac07cdecf99051d9a5238b80f35af32cdeba5b336e55d957b318b50137e18da5" + +[[package]] +name = "bit-vec" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b71798fca2c1fe1086445a7258a4bc81e6e49dcd24c8d0dd9a1e57395b603f51" +dependencies = [ + "serde", +] + [[package]] name = "bitflags" version = "2.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3ded4057c258ba199e2d26386d3af3780957ecaee6c4ef4041c6b4b8b97c0b06" +dependencies = [ + "serde_core", +] [[package]] name = "block-buffer" @@ -206,12 +297,27 @@ dependencies = [ "generic-array", ] +[[package]] +name = "block-buffer" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2f6c7dbe95a6ed67ad9f18e57daf93a2f034c524b99fd2b76d18fdfeb6660aa" +dependencies = [ + "hybrid-array", +] + [[package]] name = "bumpalo" version = "3.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + [[package]] name = "bytes" version = "1.12.1" @@ -253,6 +359,16 @@ dependencies = [ "rand_core 0.10.1", ] +[[package]] +name = "chrono" +version = "0.4.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aa79e62e7697b8e29b513a68abacf485adcd1fe8284a4316c5ae868e6633327" +dependencies = [ + "num-traits", + "serde", +] + [[package]] name = "cmake" version = "0.1.58" @@ -262,6 +378,12 @@ dependencies = [ "cc", ] +[[package]] +name = "cmov" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c9ea0ac24bc397ab3c98583a3c9ba74fa56b09a4449bbe172b9b1ddb016027a" + [[package]] name = "combine" version = "4.6.7" @@ -306,12 +428,42 @@ dependencies = [ "libc", ] +[[package]] +name = "crc" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5eb8a2a1cd12ab0d987a5d5e825195d372001a4094a0376319d5a0ad71c1ba0d" +dependencies = [ + "crc-catalog", +] + +[[package]] +name = "crc-catalog" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "217698eaf96b4a3f0bc4f3662aaa55bdf913cd54d7204591faa790070c6d0853" + [[package]] name = "critical-section" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" +[[package]] +name = "crossbeam-queue" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03e8bd762f7479489c70ed6c768ddca99d7296857de437a68dcb2a94365b3fae" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a31eee39dddec8330830986fcd7625edb5a24ec90ea038215273bbc3adb08ac6" + [[package]] name = "crypto-common" version = "0.1.7" @@ -322,6 +474,59 @@ dependencies = [ "typenum", ] +[[package]] +name = "crypto-common" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce6e4c961d6cd6c9a86db418387425e8bdeaf05b3c8bc1411e6dca4c252f1453" +dependencies = [ + "hybrid-array", +] + +[[package]] +name = "ctutils" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d5515a3834141de9eafb9717ad39eea8247b5674e6066c404e8c4b365d2a29e" +dependencies = [ + "cmov", +] + +[[package]] +name = "darling" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.119", +] + +[[package]] +name = "darling_macro" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" +dependencies = [ + "darling_core", + "quote", + "syn 2.0.119", +] + [[package]] name = "data-encoding" version = "2.11.1" @@ -330,9 +535,9 @@ checksum = "4583a4551df46e2792f82ceeac45e850d2e2d5debba0b91f102385cda5b11f06" [[package]] name = "der-parser" -version = "9.0.0" +version = "10.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cd0a5c643689626bec213c4d8bd4d96acc8ffdb4ad4bb6bc16abf27d5f4b553" +checksum = "07da5016415d5a3c4dd39b11ed26f915f52fc4e0dc197d87908bc916e51bc1a6" dependencies = [ "asn1-rs", "displaydoc", @@ -354,8 +559,19 @@ version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ - "block-buffer", - "crypto-common", + "block-buffer 0.10.4", + "crypto-common 0.1.7", +] + +[[package]] +name = "digest" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2" +dependencies = [ + "block-buffer 0.12.1", + "crypto-common 0.2.2", + "ctutils", ] [[package]] @@ -369,17 +585,64 @@ dependencies = [ "syn 3.0.5", ] +[[package]] +name = "dotenvy" +version = "0.15.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" + [[package]] name = "dunce" version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" +[[package]] +name = "dyn-clone" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" + +[[package]] +name = "educe" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7bc049e1bd8cdeb31b68bbd586a9464ecf9f3944af3958a7a9d0f8b9799417" +dependencies = [ + "enum-ordinalize", + "proc-macro2", + "quote", + "syn 2.0.119", +] + [[package]] name = "either" version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "252afb9ae5eaa683babdc6a068b3f5726eb19e05070c731f9b2a23a7c3e8ed34" +dependencies = [ + "serde", +] + +[[package]] +name = "enum-ordinalize" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89dd01549b09589510cf0647475075d12071456586d70f5c75c98ae2a5537677" +dependencies = [ + "enum-ordinalize-derive", +] + +[[package]] +name = "enum-ordinalize-derive" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a65863d15a4ce2888bd2f0f543cc963d3879c3a022c8ee43f6141d479a3ac815" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.5", +] [[package]] name = "equivalent" @@ -397,6 +660,36 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "etcetera" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de48cc4d1c1d97a20fd819def54b890cadde72ed3ad0c614822a0a433361be96" +dependencies = [ + "cfg-if", + "windows-sys 0.61.2", +] + +[[package]] +name = "event-listener" +version = "5.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a23add41df1562121a9393cb065eab5146a1242410f23a644851e90cfd669d2" +dependencies = [ + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" +dependencies = [ + "event-listener", + "pin-project-lite", +] + [[package]] name = "fastrand" version = "2.5.0" @@ -415,6 +708,17 @@ version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99" +[[package]] +name = "flume" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e139bc46ca777eb5efaf62df0ab8cc5fd400866427e56c68b22e414e53bd3be" +dependencies = [ + "futures-core", + "futures-sink", + "spin", +] + [[package]] name = "fnv" version = "1.0.7" @@ -427,6 +731,12 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" +[[package]] +name = "foldhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + [[package]] name = "form_urlencoded" version = "1.2.2" @@ -442,6 +752,20 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" +[[package]] +name = "futures" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a31d2a3fbaaeb2af2368bbdd904aa8e812d3c04a1ee10d3171f52d556e5d0a3" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + [[package]] name = "futures-channel" version = "0.3.34" @@ -449,6 +773,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1f9e3d69d39e4862ffed03ed071a76f9a13ba1d9109d355b0f0aa6b15e393c4" dependencies = [ "futures-core", + "futures-sink", ] [[package]] @@ -457,6 +782,45 @@ version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "92d699e522242e69e3003b94ecc1f960f3a5e015aa7c5d7486e65ad01dd94f5e" +[[package]] +name = "futures-executor" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "031b47cf1a3c6cc8bc2fc76cd437f521619387907d469316e7c0bc278f1f5432" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-intrusive" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d930c203dd0b6ff06e0201a4a2fe9149b43c684fd4420555b26d21b1a02956f" +dependencies = [ + "futures-core", + "lock_api", + "parking_lot", +] + +[[package]] +name = "futures-io" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53c0fa8157de1303bfffdaa1cc2a673bfffb60102f76b0ef4441659124373fed" + +[[package]] +name = "futures-macro" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fb9654ba8355388abeb8dcb4fc62f511300867002afc858860463bdd9fe0c44" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.5", +] + [[package]] name = "futures-sink" version = "0.3.34" @@ -475,8 +839,13 @@ version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0d50a92467f8ba5dd6e3ee5d4bd04d73ab2e4e1c44474a0674821dfce14b79bc" dependencies = [ + "futures-channel", "futures-core", + "futures-io", + "futures-macro", + "futures-sink", "futures-task", + "memchr", "pin-project-lite", "slab", ] @@ -502,6 +871,18 @@ dependencies = [ "wasi", ] +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "libc", + "r-efi 5.3.0", + "wasip2", +] + [[package]] name = "getrandom" version = "0.4.3" @@ -510,7 +891,7 @@ checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099" dependencies = [ "cfg-if", "libc", - "r-efi", + "r-efi 6.0.0", "rand_core 0.10.1", ] @@ -526,6 +907,18 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" +[[package]] +name = "gloo-timers" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbb143cf96099802033e0d4f4963b19fd2e0b728bcf076cd9cf7f6634f092994" +dependencies = [ + "futures-channel", + "futures-core", + "js-sys", + "wasm-bindgen", +] + [[package]] name = "h2" version = "0.4.19" @@ -551,7 +944,20 @@ version = "0.15.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" dependencies = [ - "foldhash", + "allocator-api2", + "equivalent", + "foldhash 0.1.5", +] + +[[package]] +name = "hashbrown" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash 0.2.0", ] [[package]] @@ -560,12 +966,51 @@ version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" +[[package]] +name = "hashlink" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "824e001ac4f3012dd16a264bec811403a67ca9deb6c102fc5049b32c4574b35f" +dependencies = [ + "hashbrown 0.16.1", +] + +[[package]] +name = "headers" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3314d5adb5d94bcdf56771f2e50dbbc80bb4bdf88967526706205ac9eff24eb" +dependencies = [ + "base64 0.22.1", + "bytes", + "headers-core", + "http", + "httpdate", + "mime", + "sha1 0.10.7", +] + +[[package]] +name = "headers-core" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54b4a22553d4242c49fddb9ba998a99962b5cc6f22cb5a3482bec22522403ce4" +dependencies = [ + "http", +] + [[package]] name = "heck" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + [[package]] name = "hickory-proto" version = "0.26.1" @@ -579,12 +1024,50 @@ dependencies = [ "once_cell", "rand", "ring", - "thiserror 2.0.20", + "thiserror", "tinyvec", "tracing", "url", ] +[[package]] +name = "hkdf" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4aaa26c720c68b866f2c96ef5c1264b3e6f473fe5d4ce61cd44bbe913e553018" +dependencies = [ + "hmac", +] + +[[package]] +name = "hmac" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6303bc9732ae41b04cb554b844a762b4115a61bfaa81e3e83050991eeb56863f" +dependencies = [ + "digest 0.11.3", +] + +[[package]] +name = "home" +version = "0.5.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "hostname" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "617aaa3557aef3810a6369d0a99fac8a080891b68bd9f9812a1eeda0c0730cbd" +dependencies = [ + "cfg-if", + "libc", + "windows-link", +] + [[package]] name = "http" version = "1.5.0" @@ -630,6 +1113,15 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" +[[package]] +name = "hybrid-array" +version = "0.4.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27f864f10dfb56725ce5ce5472bc52252c8f93a4ab86327122cebf62c5f59a17" +dependencies = [ + "typenum", +] + [[package]] name = "hyper" version = "1.11.1" @@ -652,6 +1144,42 @@ dependencies = [ "want", ] +[[package]] +name = "hyper-http-proxy" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd1d471ea2f65ba45eddb1d6ab7d58ac2671d2d4ac14da5c6516ae1d97e1327a" +dependencies = [ + "bytes", + "futures-util", + "headers", + "http", + "hyper", + "hyper-rustls", + "hyper-util", + "pin-project-lite", + "tokio", + "tokio-rustls", + "tower-service", +] + +[[package]] +name = "hyper-rustls" +version = "0.27.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ca68d021ef39cf6463ab54c1d0f5daf03377b70561305bb89a8f83aab66e0f" +dependencies = [ + "http", + "hyper", + "hyper-util", + "log", + "rustls", + "rustls-native-certs", + "tokio", + "tokio-rustls", + "tower-service", +] + [[package]] name = "hyper-timeout" version = "0.5.2" @@ -767,6 +1295,12 @@ dependencies = [ "zerovec", ] +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + [[package]] name = "idna" version = "1.1.0" @@ -839,7 +1373,7 @@ dependencies = [ "jni-sys", "log", "simd_cesu8", - "thiserror 2.0.20", + "thiserror", "walkdir", "windows-link", ] @@ -897,6 +1431,41 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "json-patch" +version = "4.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7421438de105a0827e44fadd05377727847d717c80ce29a229f85fd04c427b72" +dependencies = [ + "jsonptr", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "jsonpath-rust" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c00ae348f9f8fd2d09f82a98ca381c60df9e0820d8d79fce43e649b4dc3128b" +dependencies = [ + "pest", + "pest_derive", + "regex", + "serde_json", + "thiserror", +] + +[[package]] +name = "jsonptr" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5a3cc660ba5d72bce0b3bb295bf20847ccbb40fd423f3f05b61273672e561fe" +dependencies = [ + "serde", + "serde_json", +] + [[package]] name = "jsonwebtoken" version = "10.4.0" @@ -904,10 +1473,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eba32bfb4ffdeaca3e34431072faf01745c9b26d25504aa7a6cf5684334fc4fc" dependencies = [ "aws-lc-rs", - "base64", + "base64 0.22.1", "getrandom 0.2.17", "js-sys", - "pem", + "pem 3.0.6", "serde", "serde_json", "signature", @@ -915,6 +1484,129 @@ dependencies = [ "zeroize", ] +[[package]] +name = "k8s-openapi" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c75b990324f09bef15e791606b7b7a296d02fc88a344f6eba9390970a870ad5" +dependencies = [ + "base64 0.22.1", + "chrono", + "serde", + "serde-value", + "serde_json", +] + +[[package]] +name = "kube" +version = "0.99.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a4eb20010536b48abe97fec37d23d43069bcbe9686adcf9932202327bc5ca6e" +dependencies = [ + "k8s-openapi", + "kube-client", + "kube-core", + "kube-derive", + "kube-runtime", +] + +[[package]] +name = "kube-client" +version = "0.99.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fc2ed952042df20d15ac2fe9614d0ec14b6118eab89633985d4b36e688dccf1" +dependencies = [ + "base64 0.22.1", + "bytes", + "chrono", + "either", + "futures", + "home", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-http-proxy", + "hyper-rustls", + "hyper-timeout", + "hyper-util", + "jsonpath-rust", + "k8s-openapi", + "kube-core", + "pem 3.0.6", + "rustls", + "secrecy", + "serde", + "serde_json", + "serde_yaml", + "thiserror", + "tokio", + "tokio-util", + "tower", + "tower-http", + "tracing", +] + +[[package]] +name = "kube-core" +version = "0.99.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff0d0793db58e70ca6d689489183816cb3aa481673e7433dc618cf7e8007c675" +dependencies = [ + "chrono", + "form_urlencoded", + "http", + "json-patch", + "k8s-openapi", + "schemars", + "serde", + "serde-value", + "serde_json", + "thiserror", +] + +[[package]] +name = "kube-derive" +version = "0.99.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c562f58dc9f7ca5feac8a6ee5850ca221edd6f04ce0dd2ee873202a88cd494c9" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "serde", + "serde_json", + "syn 2.0.119", +] + +[[package]] +name = "kube-runtime" +version = "0.99.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88f34cfab9b4bd8633062e0e85edb81df23cb09f159f2e31c60b069ae826ffdc" +dependencies = [ + "ahash", + "async-broadcast", + "async-stream", + "async-trait", + "backon", + "educe", + "futures", + "hashbrown 0.15.5", + "hostname", + "json-patch", + "k8s-openapi", + "kube-client", + "parking_lot", + "pin-project", + "serde", + "serde_json", + "thiserror", + "tokio", + "tokio-util", + "tracing", +] + [[package]] name = "lazy_static" version = "1.5.0" @@ -933,6 +1625,17 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" +[[package]] +name = "libsqlite3-sys" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f111c8c41e7c61a49cd34e44c7619462967221a6443b0ec299e0ac30cfb9b1" +dependencies = [ + "cc", + "pkg-config", + "vcpkg", +] + [[package]] name = "linux-raw-sys" version = "0.12.1" @@ -966,6 +1669,16 @@ version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" +[[package]] +name = "md-5" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69b6441f590336821bb897fb28fc622898ccceb1d6cea3fde5ea86b090c4de98" +dependencies = [ + "cfg-if", + "digest 0.11.3", +] + [[package]] name = "memchr" version = "2.8.3" @@ -1123,9 +1836,9 @@ dependencies = [ [[package]] name = "oid-registry" -version = "0.7.1" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8d8034d9489cdaf79228eb9f6a3b8d7bb32ba00d6645ebd48eef4077ceb5bd9" +checksum = "12f40cff3dde1b6087cc5d5f5d4d65712f34016a03ed60e9c08dcc392736b5b7" dependencies = [ "asn1-rs", ] @@ -1145,7 +1858,7 @@ name = "openshell-core" version = "0.0.0" dependencies = [ "async-trait", - "base64", + "base64 0.22.1", "glob", "ipnet", "miette", @@ -1161,8 +1874,8 @@ dependencies = [ "rustls-pemfile", "serde", "serde_json", - "sha2", - "thiserror 2.0.20", + "sha2 0.10.9", + "thiserror", "tokio", "tokio-stream", "tonic", @@ -1179,12 +1892,17 @@ name = "openshell-crypto" version = "0.0.0" dependencies = [ "aws-lc-rs", + "hyper-rustls", "jsonwebtoken", + "kube", + "pem 3.0.6", "rcgen", "rustls", "serde", - "thiserror 2.0.20", + "sqlx", + "thiserror", "tonic", + "x509-parser", ] [[package]] @@ -1193,7 +1911,7 @@ version = "0.0.0" dependencies = [ "hyper-util", "serde", - "thiserror 2.0.20", + "thiserror", "tokio", "tonic", "tower", @@ -1212,10 +1930,8 @@ dependencies = [ "prost", "prost-reflect", "prost-types", - "rcgen", "serde", "serde_json", - "sha2", "tokio", "tonic", ] @@ -1254,7 +1970,7 @@ dependencies = [ "prost-types", "serde", "serde_json", - "thiserror 2.0.20", + "thiserror", "url", ] @@ -1279,6 +1995,12 @@ version = "4.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d211803b9b6b570f68772237e415a029d5a50c65d382910b879fb19d3271f94d" +[[package]] +name = "parking" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" + [[package]] name = "parking_lot" version = "0.12.5" @@ -1308,7 +2030,17 @@ version = "3.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d30c53c26bc5b31a98cd02d20f25a7c8567146caf63ed593a9d87b2775291be" dependencies = [ - "base64", + "base64 0.22.1", + "serde_core", +] + +[[package]] +name = "pem" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d354a98a3d1251555de99e8fdd8afda05573c31b82f59063a7b0a29b5527f120" +dependencies = [ + "base64 0.23.1", "serde_core", ] @@ -1318,6 +2050,48 @@ version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" +[[package]] +name = "pest" +version = "2.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d45aeb61b4bf818e12d4205f2466f8c4748f85f4fce0146d1c03d69d753f0ad" +dependencies = [ + "memchr", + "ucd-trie", +] + +[[package]] +name = "pest_derive" +version = "2.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89cc5a242e25ed4e7704d0be240f2cfbe20a8c27e7e252d94835be93d92dc39f" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" +version = "2.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7abf21475cc3820fe4b2ca2dc2142902f67a02189f3b5b3a229f4febc01a43e5" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "pest_meta" +version = "2.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adba4db388f687393c18c51348d44a41d870ca9df71a2c98172ea3035dc6936e" +dependencies = [ + "pest", +] + [[package]] name = "petgraph" version = "0.8.3" @@ -1451,7 +2225,7 @@ version = "0.16.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "01b80ea363c31af2de2b92e3c07ed1156628f7838c4afb4df75ee78a37fedbd1" dependencies = [ - "base64", + "base64 0.22.1", "prost", "prost-types", "serde", @@ -1560,6 +2334,12 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + [[package]] name = "r-efi" version = "6.0.0" @@ -1594,12 +2374,12 @@ checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" [[package]] name = "rcgen" -version = "0.13.2" +version = "0.14.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75e669e5202259b5314d1ea5397316ad400819437857b90861765f24c4cf80a2" +checksum = "8774e05a7d0de114588e6a28fe7e71694b82614ed569d86d8b389dfbc98b8ad8" dependencies = [ "aws-lc-rs", - "pem", + "pem 4.0.0", "rustls-pki-types", "time", "x509-parser", @@ -1764,6 +2544,12 @@ version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f" +[[package]] +name = "ryu" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" + [[package]] name = "same-file" version = "1.0.6" @@ -1782,12 +2568,45 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "schemars" +version = "0.8.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fbf2ae1b8bc8e02df939598064d22402220cd5bbcca1c76f7d6a310974d5615" +dependencies = [ + "dyn-clone", + "schemars_derive", + "serde", + "serde_json", +] + +[[package]] +name = "schemars_derive" +version = "0.8.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32e265784ad618884abaea0600a9adf15393368d840e0222d101a072f3f7534d" +dependencies = [ + "proc-macro2", + "quote", + "serde_derive_internals", + "syn 2.0.119", +] + [[package]] name = "scopeguard" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "secrecy" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e891af845473308773346dc847b2c23ee78fe442e0472ac50e22a18a93d3ae5a" +dependencies = [ + "zeroize", +] + [[package]] name = "security-framework" version = "3.7.0" @@ -1857,6 +2676,17 @@ dependencies = [ "syn 3.0.5", ] +[[package]] +name = "serde_derive_internals" +version = "0.29.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + [[package]] name = "serde_json" version = "1.0.151" @@ -1870,6 +2700,41 @@ dependencies = [ "zmij", ] +[[package]] +name = "serde_yaml" +version = "0.9.34+deprecated" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" +dependencies = [ + "indexmap", + "itoa", + "ryu", + "serde", + "unsafe-libyaml", +] + +[[package]] +name = "sha1" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a978451301f4db1d02937a4ab3ccce137717b81826e79b7d49ffe3244a13c3b8" +dependencies = [ + "cfg-if", + "cpufeatures 0.2.17", + "digest 0.10.7", +] + +[[package]] +name = "sha1" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aacc4cc499359472b4abe1bf11d0b12e688af9a805fa5e3016f9a386dc2d0214" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.0", + "digest 0.11.3", +] + [[package]] name = "sha2" version = "0.10.9" @@ -1878,7 +2743,18 @@ checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ "cfg-if", "cpufeatures 0.2.17", - "digest", + "digest 0.10.7", +] + +[[package]] +name = "sha2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "446ba717509524cb3f22f17ecc096f10f4822d76ab5c0b9822c5f9c284e825f4" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.0", + "digest 0.11.3", ] [[package]] @@ -1930,7 +2806,7 @@ checksum = "0d585997b0ac10be3c5ee635f1bab02d512760d14b7c468801ac8a01d9ae5f1d" dependencies = [ "num-bigint", "num-traits", - "thiserror 2.0.20", + "thiserror", "time", ] @@ -1945,6 +2821,9 @@ name = "smallvec" version = "1.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba467056f1b547ed52077911161fc86985becbc60e8e1857c8a144dab0def891" +dependencies = [ + "serde", +] [[package]] name = "socket2" @@ -1956,12 +2835,210 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "spin" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3763264f6b73151db08c50ff20d7d8a0b8796e021cdea7ceedad07b80155fa0e" +dependencies = [ + "lock_api", +] + +[[package]] +name = "sqlx" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "378620ccc25c62c89d8be1c819e76a88d59bdcc3304733330788948e619bfd71" +dependencies = [ + "sqlx-core", + "sqlx-macros", + "sqlx-mysql", + "sqlx-postgres", + "sqlx-sqlite", +] + +[[package]] +name = "sqlx-core" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05b44e85bf579a8eeb4ceaa77a3a523baf2bf0e9bac7e40f405d537b5d2d5ccb" +dependencies = [ + "base64 0.22.1", + "bytes", + "cfg-if", + "crc", + "crossbeam-queue", + "either", + "event-listener", + "futures-core", + "futures-intrusive", + "futures-io", + "futures-util", + "hashbrown 0.16.1", + "hashlink", + "indexmap", + "log", + "memchr", + "percent-encoding", + "rustls", + "serde", + "serde_json", + "sha2 0.10.9", + "smallvec", + "thiserror", + "tokio", + "tokio-stream", + "tracing", + "url", + "webpki-roots", +] + +[[package]] +name = "sqlx-macros" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd2b84f2bc39a5705ef27ec785a11c934a41bbd4a24941e257927cddc26b60bf" +dependencies = [ + "proc-macro2", + "quote", + "sqlx-core", + "sqlx-macros-core", + "syn 2.0.119", +] + +[[package]] +name = "sqlx-macros-core" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb8d96de5fdc85a5c4ec813432b523ec637e80ba98f046555f75f7908ddac7c3" +dependencies = [ + "cfg-if", + "dotenvy", + "either", + "heck", + "hex", + "proc-macro2", + "quote", + "serde", + "serde_json", + "sha2 0.10.9", + "sqlx-core", + "sqlx-postgres", + "sqlx-sqlite", + "syn 2.0.119", + "thiserror", + "tokio", + "url", +] + +[[package]] +name = "sqlx-mysql" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90b8020fe17c5f2c245bfa2505d7ef59c5604839527c740266ad2214acebea27" +dependencies = [ + "bitflags", + "byteorder", + "bytes", + "crc", + "digest 0.11.3", + "dotenvy", + "either", + "futures-core", + "futures-util", + "generic-array", + "log", + "percent-encoding", + "serde", + "sha1 0.11.0", + "sha2 0.11.0", + "sqlx-core", + "thiserror", + "tracing", +] + +[[package]] +name = "sqlx-postgres" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87a2bdd6e83f6b3ea525ca9fee568030508b58355a43d0b2c1674d5f79dcd65e" +dependencies = [ + "atoi", + "base64 0.22.1", + "bitflags", + "byteorder", + "crc", + "dotenvy", + "etcetera", + "futures-channel", + "futures-core", + "futures-util", + "hex", + "hkdf", + "hmac", + "itoa", + "log", + "md-5", + "memchr", + "rand", + "serde", + "serde_json", + "sha2 0.11.0", + "smallvec", + "sqlx-core", + "stringprep", + "thiserror", + "tracing", + "whoami", +] + +[[package]] +name = "sqlx-sqlite" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "488e99c397a62007e4229aec669a179816339afc6d2620ca6fa420dbee2e982c" +dependencies = [ + "atoi", + "flume", + "form_urlencoded", + "futures-channel", + "futures-core", + "futures-executor", + "futures-intrusive", + "futures-util", + "libsqlite3-sys", + "log", + "percent-encoding", + "serde", + "sqlx-core", + "thiserror", + "tracing", + "url", +] + [[package]] name = "stable_deref_trait" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" +[[package]] +name = "stringprep" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b4df3d392d81bd458a8a621b8bffbd2302a12ffe288a9d931670948749463b1" +dependencies = [ + "unicode-bidi", + "unicode-normalization", + "unicode-properties", +] + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + [[package]] name = "subtle" version = "2.6.1" @@ -2061,33 +3138,13 @@ dependencies = [ "unicode-width 0.2.2", ] -[[package]] -name = "thiserror" -version = "1.0.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" -dependencies = [ - "thiserror-impl 1.0.69", -] - [[package]] name = "thiserror" version = "2.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec86235f5fcc2a73650310756d2ac5b138a5780bbbdfae3eeccec992c435ba4f" dependencies = [ - "thiserror-impl 2.0.20", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.119", + "thiserror-impl", ] [[package]] @@ -2216,6 +3273,7 @@ dependencies = [ "futures-sink", "libc", "pin-project-lite", + "slab", "tokio", ] @@ -2227,7 +3285,7 @@ checksum = "ac2a5518c70fa84342385732db33fb3f44bc4cc748936eb5833d2df34d6445ef" dependencies = [ "async-trait", "axum", - "base64", + "base64 0.22.1", "bytes", "h2", "http", @@ -2319,6 +3377,24 @@ dependencies = [ "tracing", ] +[[package]] +name = "tower-http" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cfcf7e2740e6fc6d4d688b4ef00650406bb94adf4731e43c096c3a19fe40840" +dependencies = [ + "base64 0.22.1", + "bitflags", + "bytes", + "http", + "http-body", + "mime", + "pin-project-lite", + "tower-layer", + "tower-service", + "tracing", +] + [[package]] name = "tower-layer" version = "0.3.3" @@ -2337,6 +3413,7 @@ version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" dependencies = [ + "log", "pin-project-lite", "tracing-attributes", "tracing-core", @@ -2374,12 +3451,24 @@ version = "1.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" +[[package]] +name = "ucd-trie" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" + [[package]] name = "unicase" version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dbc4bc3a9f746d862c45cb89d705aa10f187bb96c76001afab07a0d35ce60142" +[[package]] +name = "unicode-bidi" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" + [[package]] name = "unicode-ident" version = "1.0.24" @@ -2392,6 +3481,21 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f" +[[package]] +name = "unicode-normalization" +version = "0.1.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fd4f6878c9cb28d874b009da9e8d183b5abc80117c40bbd187a1fde336be6e8" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-properties" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7df058c713841ad818f1dc5d3fd88063241cc61f49f5fbea4b951e8cf5a8d71d" + [[package]] name = "unicode-width" version = "0.1.14" @@ -2404,6 +3508,12 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" +[[package]] +name = "unsafe-libyaml" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" + [[package]] name = "untrusted" version = "0.7.1" @@ -2445,6 +3555,12 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + [[package]] name = "version_check" version = "0.9.5" @@ -2476,6 +3592,15 @@ version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" +[[package]] +name = "wasip2" +version = "1.0.4+wasi-0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67efb37e106e55ce722a510d6b5f9c17f083e5fc79afc2badeb12cc313d9487" +dependencies = [ + "wit-bindgen", +] + [[package]] name = "wasm-bindgen" version = "0.2.126" @@ -2521,6 +3646,21 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "webpki-roots" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dcd9d09a39985f5344844e66b0c530a33843579125f23e21e9f0f220850f22a" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "whoami" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "626c4bac6755d76ffc12cb01b2eac751db1996b9e0041de9aa02c8c211ddc82c" + [[package]] name = "winapi-util" version = "0.1.11" @@ -2618,6 +3758,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +[[package]] +name = "wit-bindgen" +version = "0.57.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" + [[package]] name = "writeable" version = "0.6.3" @@ -2626,28 +3772,29 @@ checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4" [[package]] name = "x509-parser" -version = "0.16.0" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcbc162f30700d6f3f82a24bf7cc62ffe7caea42c0b2cba8bf7f3ae50cf51f69" +checksum = "d43b0f71ce057da06bc0851b23ee24f3f86190b07203dd8f567d0b706a185202" dependencies = [ "asn1-rs", + "aws-lc-rs", "data-encoding", "der-parser", "lazy_static", "nom", "oid-registry", - "ring", "rusticata-macros", - "thiserror 1.0.69", + "thiserror", "time", ] [[package]] name = "yasna" -version = "0.5.2" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e17bb3549cc1321ae1296b9cdc2698e2b6cb1992adfa19a8c72e5b7a738f44cd" +checksum = "b5f6765e852b9b4dc8e2a76843e4d64d1cea8e79bcde0b6901aea8e7c7f08282" dependencies = [ + "bit-vec", "time", ] @@ -2674,6 +3821,26 @@ dependencies = [ "synstructure", ] +[[package]] +name = "zerocopy" +version = "0.8.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d35102a9f36d089ccae9e4c6802bc118be4487b80aaffc0ab4e0cf5ce92d2873" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "146c01f5ab44258da43cf276c74a2763db2ff3969c9c652c3f2de07041d0b2bc" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + [[package]] name = "zerofrom" version = "0.1.8" diff --git a/examples/governance-interceptor/Cargo.toml b/examples/governance-interceptor/Cargo.toml index 92fb8c4648..dc79794be1 100644 --- a/examples/governance-interceptor/Cargo.toml +++ b/examples/governance-interceptor/Cargo.toml @@ -19,11 +19,9 @@ openshell-providers = { path = "../../crates/openshell-providers" } prost = "0.14" prost-reflect = { version = "0.16.5", features = ["serde"] } prost-types = "0.14" -rcgen = { version = "0.13", default-features = false, features = ["crypto", "pem"] } serde = { version = "1", features = ["derive"] } serde_json = "1" serde_yml = { package = "noyalib", version = "0.0.28", default-features = false, features = ["std", "compat-serde-yaml"] } -sha2 = "0.10" tokio = { version = "1.43", features = ["macros", "rt-multi-thread", "fs", "signal"] } tonic = { version = "0.14", features = ["transport"] } diff --git a/examples/governance-interceptor/src/main.rs b/examples/governance-interceptor/src/main.rs index 1b8f291aac..bfaff5090d 100644 --- a/examples/governance-interceptor/src/main.rs +++ b/examples/governance-interceptor/src/main.rs @@ -35,7 +35,6 @@ use prost_types::{Struct, Value as ProtoValue, value::Kind}; use proto_json::{decode_message_to_json, encode_json_to_message}; use serde::{Deserialize, Serialize}; use serde_json::{Number, Value, json}; -use sha2::{Digest, Sha256}; use tonic::Code; use tonic::transport::{Channel, Server}; use tonic::{Request, Response, Status}; @@ -101,13 +100,15 @@ impl PolicySigner { fn generate() -> Result { let keypair = openshell_crypto::pki::generate_jwt_keypair() .map_err(|err| format!("failed to generate policy signing key: {err}"))?; - let signing_key_pem = keypair.serialize_pem(); + let signing_key_pem = keypair + .serialize_pem() + .map_err(|error| format!("export signing key: {error}"))?; let public_key_pem = keypair.public_key_pem(); let encoding_key = EncodingKey::from_ed_pem(signing_key_pem.as_bytes()) .map_err(|err| format!("failed to parse policy signing key: {err}"))?; let decoding_key = DecodingKey::from_ed_pem(public_key_pem.as_bytes()) .map_err(|err| format!("failed to parse policy verification key: {err}"))?; - let kid = kid_from_public_key_der(&keypair.public_key_der()); + let kid = kid_from_public_key_der(&keypair.public_key_der())?; Ok(Self { encoding_key, decoding_key, @@ -1043,9 +1044,9 @@ fn normalize_for_struct(value: Value) -> Result { json_to_proto_value(&value).map(|value| proto_value_to_json(&value)) } -fn kid_from_public_key_der(public_key_der: &[u8]) -> String { - let digest = Sha256::digest(public_key_der); - hex_encode_prefix(&digest, 16) +fn kid_from_public_key_der(public_key_der: &[u8]) -> Result { + let digest = openshell_crypto::sha256(public_key_der).map_err(|error| error.to_string())?; + Ok(hex_encode_prefix(&digest, 16)) } fn hex_encode_prefix(bytes: &[u8], n: usize) -> String { diff --git a/examples/governance-interceptor/src/policy_hash.rs b/examples/governance-interceptor/src/policy_hash.rs index 7344d5209e..f6f62d80d3 100644 --- a/examples/governance-interceptor/src/policy_hash.rs +++ b/examples/governance-interceptor/src/policy_hash.rs @@ -2,9 +2,9 @@ // SPDX-License-Identifier: Apache-2.0 use openshell_core::proto::{ProviderProfile, SandboxPolicy}; +use openshell_crypto::Digest; use prost::Message; use serde_json::Value; -use sha2::{Digest, Sha256}; use crate::proto_json::decode_message_to_json; @@ -38,21 +38,26 @@ pub(crate) fn canonical_profile_snapshot_revision( .collect::, String>>()?; canonical_profiles.sort_by(|left, right| left.0.cmp(right.0)); - let mut hasher = Sha256::new(); - hasher.update(HASH_ALGORITHM.as_bytes()); - hash_framed(&mut hasher, PROFILE_SNAPSHOT_DOMAIN.as_bytes())?; - hash_framed(&mut hasher, PROVIDER_PROFILE_TYPE.as_bytes())?; + let mut hasher = openshell_crypto::sha256_digest().map_err(|error| error.to_string())?; + hasher + .update(HASH_ALGORITHM.as_bytes()) + .map_err(|error| error.to_string())?; + hash_framed(hasher.as_mut(), PROFILE_SNAPSHOT_DOMAIN.as_bytes())?; + hash_framed(hasher.as_mut(), PROVIDER_PROFILE_TYPE.as_bytes())?; hash_framed( - &mut hasher, + hasher.as_mut(), &u64::try_from(canonical_profiles.len()) .map_err(|_| "provider profile count exceeds hash framing limit")? .to_be_bytes(), )?; for (id, canonical) in canonical_profiles { - hash_framed(&mut hasher, id)?; - hash_framed(&mut hasher, &canonical)?; + hash_framed(hasher.as_mut(), id)?; + hash_framed(hasher.as_mut(), &canonical)?; } - Ok(format!("{HASH_PREFIX}{}", hex_encode(&hasher.finalize()))) + Ok(format!( + "{HASH_PREFIX}{}", + hex_encode(&hasher.finish().map_err(|error| error.to_string())?) + )) } pub(crate) fn is_v2_digest(value: &str) -> bool { @@ -69,12 +74,17 @@ where M: Message, { let canonical = canonical_message_bytes(type_name, message)?; - let mut hasher = Sha256::new(); - hasher.update(HASH_ALGORITHM.as_bytes()); - hash_framed(&mut hasher, domain.as_bytes())?; - hash_framed(&mut hasher, type_name.as_bytes())?; - hash_framed(&mut hasher, &canonical)?; - Ok(format!("{HASH_PREFIX}{}", hex_encode(&hasher.finalize()))) + let mut hasher = openshell_crypto::sha256_digest().map_err(|error| error.to_string())?; + hasher + .update(HASH_ALGORITHM.as_bytes()) + .map_err(|error| error.to_string())?; + hash_framed(hasher.as_mut(), domain.as_bytes())?; + hash_framed(hasher.as_mut(), type_name.as_bytes())?; + hash_framed(hasher.as_mut(), &canonical)?; + Ok(format!( + "{HASH_PREFIX}{}", + hex_encode(&hasher.finish().map_err(|error| error.to_string())?) + )) } fn canonical_message_bytes(type_name: &str, message: &M) -> Result, String> @@ -120,10 +130,12 @@ fn write_canonical_json(value: &Value, output: &mut Vec) -> Result<(), Strin Ok(()) } -fn hash_framed(hasher: &mut Sha256, bytes: &[u8]) -> Result<(), String> { +fn hash_framed(hasher: &mut dyn Digest, bytes: &[u8]) -> Result<(), String> { let length = u64::try_from(bytes.len()).map_err(|_| "hash input exceeds framing limit")?; - hasher.update(length.to_be_bytes()); - hasher.update(bytes); + hasher + .update(&length.to_be_bytes()) + .map_err(|error| error.to_string())?; + hasher.update(bytes).map_err(|error| error.to_string())?; Ok(()) } diff --git a/examples/supervisor-middleware-content-guard/Cargo.lock b/examples/supervisor-middleware-content-guard/Cargo.lock index 29ed36eb92..77a8acc507 100644 --- a/examples/supervisor-middleware-content-guard/Cargo.lock +++ b/examples/supervisor-middleware-content-guard/Cargo.lock @@ -17,6 +17,19 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" +[[package]] +name = "ahash" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" +dependencies = [ + "cfg-if", + "getrandom 0.3.4", + "once_cell", + "version_check", + "zerocopy", +] + [[package]] name = "aho-corasick" version = "1.1.5" @@ -26,6 +39,12 @@ dependencies = [ "memchr", ] +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + [[package]] name = "anstream" version = "1.0.0" @@ -84,9 +103,9 @@ checksum = "330a5ed07fa54e4702c9d6c4174f74427fc0ef6e214bbd677ae50a5099946470" [[package]] name = "asn1-rs" -version = "0.6.2" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5493c3bedbacf7fd7382c6346bbd66687d12bbaad3a89a2d2c303ee6cf20b048" +checksum = "b7f43a50ac4fdca5df8e885c21b835997f0a1cdee65494a6847694a98652d9d8" dependencies = [ "asn1-rs-derive", "asn1-rs-impl", @@ -94,15 +113,15 @@ dependencies = [ "nom", "num-traits", "rusticata-macros", - "thiserror 1.0.69", + "thiserror", "time", ] [[package]] name = "asn1-rs-derive" -version = "0.5.1" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "965c2d33e53cb6b267e148a4cb0760bc01f4904c1cd4bb4002a085bb016d1490" +checksum = "3109e49b1e4909e9db6515a30c633684d68cdeaa252f215214cb4fa1a5bfee2c" dependencies = [ "proc-macro2", "quote", @@ -121,6 +140,40 @@ dependencies = [ "syn 2.0.119", ] +[[package]] +name = "async-broadcast" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "435a87a52755b8f27fcf321ac4f04b2802e337c8c4872923137471ec39c37532" +dependencies = [ + "event-listener", + "event-listener-strategy", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-stream" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" +dependencies = [ + "async-stream-impl", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-stream-impl" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + [[package]] name = "async-trait" version = "0.1.92" @@ -132,6 +185,15 @@ dependencies = [ "syn 3.0.5", ] +[[package]] +name = "atoi" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28d99ec8bfea296261ca1af174f24225171fea9664ba9003cbebee704810528" +dependencies = [ + "num-traits", +] + [[package]] name = "atomic-waker" version = "1.1.2" @@ -211,6 +273,17 @@ dependencies = [ "tower-service", ] +[[package]] +name = "backon" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cffb0e931875b666fc4fcb20fee52e9bbd1ef836fd9e9e04ec21555f9f85f7ef" +dependencies = [ + "fastrand", + "gloo-timers", + "tokio", +] + [[package]] name = "backtrace" version = "0.3.76" @@ -241,11 +314,29 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +[[package]] +name = "base64" +version = "0.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac07cdecf99051d9a5238b80f35af32cdeba5b336e55d957b318b50137e18da5" + +[[package]] +name = "bit-vec" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b71798fca2c1fe1086445a7258a4bc81e6e49dcd24c8d0dd9a1e57395b603f51" +dependencies = [ + "serde", +] + [[package]] name = "bitflags" version = "2.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3ded4057c258ba199e2d26386d3af3780957ecaee6c4ef4041c6b4b8b97c0b06" +dependencies = [ + "serde_core", +] [[package]] name = "block-buffer" @@ -256,12 +347,27 @@ dependencies = [ "generic-array", ] +[[package]] +name = "block-buffer" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2f6c7dbe95a6ed67ad9f18e57daf93a2f034c524b99fd2b76d18fdfeb6660aa" +dependencies = [ + "hybrid-array", +] + [[package]] name = "bumpalo" version = "3.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + [[package]] name = "bytes" version = "1.12.1" @@ -303,6 +409,16 @@ dependencies = [ "rand_core 0.10.1", ] +[[package]] +name = "chrono" +version = "0.4.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aa79e62e7697b8e29b513a68abacf485adcd1fe8284a4316c5ae868e6633327" +dependencies = [ + "num-traits", + "serde", +] + [[package]] name = "clap" version = "4.6.7" @@ -352,6 +468,12 @@ dependencies = [ "cc", ] +[[package]] +name = "cmov" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c9ea0ac24bc397ab3c98583a3c9ba74fa56b09a4449bbe172b9b1ddb016027a" + [[package]] name = "colorchoice" version = "1.0.5" @@ -402,12 +524,42 @@ dependencies = [ "libc", ] +[[package]] +name = "crc" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5eb8a2a1cd12ab0d987a5d5e825195d372001a4094a0376319d5a0ad71c1ba0d" +dependencies = [ + "crc-catalog", +] + +[[package]] +name = "crc-catalog" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "217698eaf96b4a3f0bc4f3662aaa55bdf913cd54d7204591faa790070c6d0853" + [[package]] name = "critical-section" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" +[[package]] +name = "crossbeam-queue" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03e8bd762f7479489c70ed6c768ddca99d7296857de437a68dcb2a94365b3fae" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a31eee39dddec8330830986fcd7625edb5a24ec90ea038215273bbc3adb08ac6" + [[package]] name = "crypto-common" version = "0.1.7" @@ -418,6 +570,59 @@ dependencies = [ "typenum", ] +[[package]] +name = "crypto-common" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce6e4c961d6cd6c9a86db418387425e8bdeaf05b3c8bc1411e6dca4c252f1453" +dependencies = [ + "hybrid-array", +] + +[[package]] +name = "ctutils" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d5515a3834141de9eafb9717ad39eea8247b5674e6066c404e8c4b365d2a29e" +dependencies = [ + "cmov", +] + +[[package]] +name = "darling" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.119", +] + +[[package]] +name = "darling_macro" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" +dependencies = [ + "darling_core", + "quote", + "syn 2.0.119", +] + [[package]] name = "data-encoding" version = "2.11.1" @@ -426,9 +631,9 @@ checksum = "4583a4551df46e2792f82ceeac45e850d2e2d5debba0b91f102385cda5b11f06" [[package]] name = "der-parser" -version = "9.0.0" +version = "10.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cd0a5c643689626bec213c4d8bd4d96acc8ffdb4ad4bb6bc16abf27d5f4b553" +checksum = "07da5016415d5a3c4dd39b11ed26f915f52fc4e0dc197d87908bc916e51bc1a6" dependencies = [ "asn1-rs", "displaydoc", @@ -450,8 +655,19 @@ version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ - "block-buffer", - "crypto-common", + "block-buffer 0.10.4", + "crypto-common 0.1.7", +] + +[[package]] +name = "digest" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2" +dependencies = [ + "block-buffer 0.12.1", + "crypto-common 0.2.2", + "ctutils", ] [[package]] @@ -465,17 +681,64 @@ dependencies = [ "syn 3.0.5", ] +[[package]] +name = "dotenvy" +version = "0.15.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" + [[package]] name = "dunce" version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" +[[package]] +name = "dyn-clone" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" + +[[package]] +name = "educe" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7bc049e1bd8cdeb31b68bbd586a9464ecf9f3944af3958a7a9d0f8b9799417" +dependencies = [ + "enum-ordinalize", + "proc-macro2", + "quote", + "syn 2.0.119", +] + [[package]] name = "either" version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "252afb9ae5eaa683babdc6a068b3f5726eb19e05070c731f9b2a23a7c3e8ed34" +dependencies = [ + "serde", +] + +[[package]] +name = "enum-ordinalize" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89dd01549b09589510cf0647475075d12071456586d70f5c75c98ae2a5537677" +dependencies = [ + "enum-ordinalize-derive", +] + +[[package]] +name = "enum-ordinalize-derive" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a65863d15a4ce2888bd2f0f543cc963d3879c3a022c8ee43f6141d479a3ac815" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.5", +] [[package]] name = "equivalent" @@ -493,6 +756,36 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "etcetera" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de48cc4d1c1d97a20fd819def54b890cadde72ed3ad0c614822a0a433361be96" +dependencies = [ + "cfg-if", + "windows-sys 0.61.2", +] + +[[package]] +name = "event-listener" +version = "5.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a23add41df1562121a9393cb065eab5146a1242410f23a644851e90cfd669d2" +dependencies = [ + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" +dependencies = [ + "event-listener", + "pin-project-lite", +] + [[package]] name = "fastrand" version = "2.5.0" @@ -511,6 +804,17 @@ version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99" +[[package]] +name = "flume" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e139bc46ca777eb5efaf62df0ab8cc5fd400866427e56c68b22e414e53bd3be" +dependencies = [ + "futures-core", + "futures-sink", + "spin", +] + [[package]] name = "fnv" version = "1.0.7" @@ -523,6 +827,12 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" +[[package]] +name = "foldhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + [[package]] name = "form_urlencoded" version = "1.2.2" @@ -538,6 +848,20 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" +[[package]] +name = "futures" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a31d2a3fbaaeb2af2368bbdd904aa8e812d3c04a1ee10d3171f52d556e5d0a3" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + [[package]] name = "futures-channel" version = "0.3.34" @@ -545,6 +869,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1f9e3d69d39e4862ffed03ed071a76f9a13ba1d9109d355b0f0aa6b15e393c4" dependencies = [ "futures-core", + "futures-sink", ] [[package]] @@ -553,6 +878,45 @@ version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "92d699e522242e69e3003b94ecc1f960f3a5e015aa7c5d7486e65ad01dd94f5e" +[[package]] +name = "futures-executor" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "031b47cf1a3c6cc8bc2fc76cd437f521619387907d469316e7c0bc278f1f5432" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-intrusive" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d930c203dd0b6ff06e0201a4a2fe9149b43c684fd4420555b26d21b1a02956f" +dependencies = [ + "futures-core", + "lock_api", + "parking_lot", +] + +[[package]] +name = "futures-io" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53c0fa8157de1303bfffdaa1cc2a673bfffb60102f76b0ef4441659124373fed" + +[[package]] +name = "futures-macro" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fb9654ba8355388abeb8dcb4fc62f511300867002afc858860463bdd9fe0c44" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.5", +] + [[package]] name = "futures-sink" version = "0.3.34" @@ -571,8 +935,13 @@ version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0d50a92467f8ba5dd6e3ee5d4bd04d73ab2e4e1c44474a0674821dfce14b79bc" dependencies = [ + "futures-channel", "futures-core", + "futures-io", + "futures-macro", + "futures-sink", "futures-task", + "memchr", "pin-project-lite", "slab", ] @@ -598,6 +967,18 @@ dependencies = [ "wasi", ] +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "libc", + "r-efi 5.3.0", + "wasip2", +] + [[package]] name = "getrandom" version = "0.4.3" @@ -606,7 +987,7 @@ checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099" dependencies = [ "cfg-if", "libc", - "r-efi", + "r-efi 6.0.0", "rand_core 0.10.1", ] @@ -622,6 +1003,18 @@ version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e4eba85ea1d0a966a983acd07deee566e67395d2d96b6fb39e62b5a833f1eb0b" +[[package]] +name = "gloo-timers" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbb143cf96099802033e0d4f4963b19fd2e0b728bcf076cd9cf7f6634f092994" +dependencies = [ + "futures-channel", + "futures-core", + "js-sys", + "wasm-bindgen", +] + [[package]] name = "h2" version = "0.4.19" @@ -643,18 +1036,64 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.15.5" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash 0.1.5", +] + +[[package]] +name = "hashbrown" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash 0.2.0", +] + +[[package]] +name = "hashbrown" +version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" + +[[package]] +name = "hashlink" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "824e001ac4f3012dd16a264bec811403a67ca9deb6c102fc5049b32c4574b35f" dependencies = [ - "foldhash", + "hashbrown 0.16.1", ] [[package]] -name = "hashbrown" -version = "0.17.1" +name = "headers" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" +checksum = "b3314d5adb5d94bcdf56771f2e50dbbc80bb4bdf88967526706205ac9eff24eb" +dependencies = [ + "base64 0.22.1", + "bytes", + "headers-core", + "http", + "httpdate", + "mime", + "sha1 0.10.7", +] + +[[package]] +name = "headers-core" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54b4a22553d4242c49fddb9ba998a99962b5cc6f22cb5a3482bec22522403ce4" +dependencies = [ + "http", +] [[package]] name = "heck" @@ -662,6 +1101,12 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + [[package]] name = "hickory-proto" version = "0.26.3" @@ -675,12 +1120,50 @@ dependencies = [ "once_cell", "rand", "ring", - "thiserror 2.0.20", + "thiserror", "tinyvec", "tracing", "url", ] +[[package]] +name = "hkdf" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4aaa26c720c68b866f2c96ef5c1264b3e6f473fe5d4ce61cd44bbe913e553018" +dependencies = [ + "hmac", +] + +[[package]] +name = "hmac" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6303bc9732ae41b04cb554b844a762b4115a61bfaa81e3e83050991eeb56863f" +dependencies = [ + "digest 0.11.3", +] + +[[package]] +name = "home" +version = "0.5.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "hostname" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "617aaa3557aef3810a6369d0a99fac8a080891b68bd9f9812a1eeda0c0730cbd" +dependencies = [ + "cfg-if", + "libc", + "windows-link", +] + [[package]] name = "http" version = "1.5.0" @@ -726,6 +1209,15 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" +[[package]] +name = "hybrid-array" +version = "0.4.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27f864f10dfb56725ce5ce5472bc52252c8f93a4ab86327122cebf62c5f59a17" +dependencies = [ + "typenum", +] + [[package]] name = "hyper" version = "1.11.1" @@ -748,6 +1240,42 @@ dependencies = [ "want", ] +[[package]] +name = "hyper-http-proxy" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd1d471ea2f65ba45eddb1d6ab7d58ac2671d2d4ac14da5c6516ae1d97e1327a" +dependencies = [ + "bytes", + "futures-util", + "headers", + "http", + "hyper", + "hyper-rustls", + "hyper-util", + "pin-project-lite", + "tokio", + "tokio-rustls", + "tower-service", +] + +[[package]] +name = "hyper-rustls" +version = "0.27.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ca68d021ef39cf6463ab54c1d0f5daf03377b70561305bb89a8f83aab66e0f" +dependencies = [ + "http", + "hyper", + "hyper-util", + "log", + "rustls", + "rustls-native-certs", + "tokio", + "tokio-rustls", + "tower-service", +] + [[package]] name = "hyper-timeout" version = "0.5.2" @@ -909,6 +1437,12 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae293c039020f9ec10710af98d29ce6aa2051486638b49c9a6409f3b4a9e98ad" +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + [[package]] name = "idna" version = "1.1.0" @@ -987,7 +1521,7 @@ dependencies = [ "jni-sys", "log", "simd_cesu8", - "thiserror 2.0.20", + "thiserror", "walkdir", "windows-link", ] @@ -1045,6 +1579,41 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "json-patch" +version = "4.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7421438de105a0827e44fadd05377727847d717c80ce29a229f85fd04c427b72" +dependencies = [ + "jsonptr", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "jsonpath-rust" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c00ae348f9f8fd2d09f82a98ca381c60df9e0820d8d79fce43e649b4dc3128b" +dependencies = [ + "pest", + "pest_derive", + "regex", + "serde_json", + "thiserror", +] + +[[package]] +name = "jsonptr" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5a3cc660ba5d72bce0b3bb295bf20847ccbb40fd423f3f05b61273672e561fe" +dependencies = [ + "serde", + "serde_json", +] + [[package]] name = "jsonwebtoken" version = "10.4.0" @@ -1052,10 +1621,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eba32bfb4ffdeaca3e34431072faf01745c9b26d25504aa7a6cf5684334fc4fc" dependencies = [ "aws-lc-rs", - "base64", + "base64 0.22.1", "getrandom 0.2.17", "js-sys", - "pem", + "pem 3.0.6", "serde", "serde_json", "signature", @@ -1063,6 +1632,129 @@ dependencies = [ "zeroize", ] +[[package]] +name = "k8s-openapi" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c75b990324f09bef15e791606b7b7a296d02fc88a344f6eba9390970a870ad5" +dependencies = [ + "base64 0.22.1", + "chrono", + "serde", + "serde-value", + "serde_json", +] + +[[package]] +name = "kube" +version = "0.99.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a4eb20010536b48abe97fec37d23d43069bcbe9686adcf9932202327bc5ca6e" +dependencies = [ + "k8s-openapi", + "kube-client", + "kube-core", + "kube-derive", + "kube-runtime", +] + +[[package]] +name = "kube-client" +version = "0.99.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fc2ed952042df20d15ac2fe9614d0ec14b6118eab89633985d4b36e688dccf1" +dependencies = [ + "base64 0.22.1", + "bytes", + "chrono", + "either", + "futures", + "home", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-http-proxy", + "hyper-rustls", + "hyper-timeout", + "hyper-util", + "jsonpath-rust", + "k8s-openapi", + "kube-core", + "pem 3.0.6", + "rustls", + "secrecy", + "serde", + "serde_json", + "serde_yaml", + "thiserror", + "tokio", + "tokio-util", + "tower", + "tower-http", + "tracing", +] + +[[package]] +name = "kube-core" +version = "0.99.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff0d0793db58e70ca6d689489183816cb3aa481673e7433dc618cf7e8007c675" +dependencies = [ + "chrono", + "form_urlencoded", + "http", + "json-patch", + "k8s-openapi", + "schemars", + "serde", + "serde-value", + "serde_json", + "thiserror", +] + +[[package]] +name = "kube-derive" +version = "0.99.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c562f58dc9f7ca5feac8a6ee5850ca221edd6f04ce0dd2ee873202a88cd494c9" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "serde", + "serde_json", + "syn 2.0.119", +] + +[[package]] +name = "kube-runtime" +version = "0.99.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88f34cfab9b4bd8633062e0e85edb81df23cb09f159f2e31c60b069ae826ffdc" +dependencies = [ + "ahash", + "async-broadcast", + "async-stream", + "async-trait", + "backon", + "educe", + "futures", + "hashbrown 0.15.5", + "hostname", + "json-patch", + "k8s-openapi", + "kube-client", + "parking_lot", + "pin-project", + "serde", + "serde_json", + "thiserror", + "tokio", + "tokio-util", + "tracing", +] + [[package]] name = "lazy_static" version = "1.5.0" @@ -1081,6 +1773,17 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" +[[package]] +name = "libsqlite3-sys" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f111c8c41e7c61a49cd34e44c7619462967221a6443b0ec299e0ac30cfb9b1" +dependencies = [ + "cc", + "pkg-config", + "vcpkg", +] + [[package]] name = "linux-raw-sys" version = "0.12.1" @@ -1114,6 +1817,16 @@ version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" +[[package]] +name = "md-5" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69b6441f590336821bb897fb28fc622898ccceb1d6cea3fde5ea86b090c4de98" +dependencies = [ + "cfg-if", + "digest 0.11.3", +] + [[package]] name = "memchr" version = "2.8.3" @@ -1271,9 +1984,9 @@ dependencies = [ [[package]] name = "oid-registry" -version = "0.7.1" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8d8034d9489cdaf79228eb9f6a3b8d7bb32ba00d6645ebd48eef4077ceb5bd9" +checksum = "12f40cff3dde1b6087cc5d5f5d4d65712f34016a03ed60e9c08dcc392736b5b7" dependencies = [ "asn1-rs", ] @@ -1299,7 +2012,7 @@ name = "openshell-core" version = "0.0.0" dependencies = [ "async-trait", - "base64", + "base64 0.22.1", "glob", "ipnet", "miette", @@ -1315,8 +2028,8 @@ dependencies = [ "rustls-pemfile", "serde", "serde_json", - "sha2", - "thiserror 2.0.20", + "sha2 0.10.9", + "thiserror", "tokio", "tokio-stream", "tonic", @@ -1333,12 +2046,17 @@ name = "openshell-crypto" version = "0.0.0" dependencies = [ "aws-lc-rs", + "hyper-rustls", "jsonwebtoken", + "kube", + "pem 3.0.6", "rcgen", "rustls", "serde", - "thiserror 2.0.20", + "sqlx", + "thiserror", "tonic", + "x509-parser", ] [[package]] @@ -1347,7 +2065,7 @@ version = "0.0.0" dependencies = [ "hyper-util", "serde", - "thiserror 2.0.20", + "thiserror", "tokio", "tonic", "tower", @@ -1395,12 +2113,27 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" +[[package]] +name = "ordered-float" +version = "2.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68f19d67e5a2795c94e73e0bb1cc1a7edeb2e28efd39e2e1c9b7a40c1108b11c" +dependencies = [ + "num-traits", +] + [[package]] name = "owo-colors" version = "4.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13c45bb4a6ae1280ec0803b1ef9d3455eb50f01efbbe1447ab020f1d54fba9d8" +[[package]] +name = "parking" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" + [[package]] name = "parking_lot" version = "0.12.5" @@ -1430,7 +2163,17 @@ version = "3.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d30c53c26bc5b31a98cd02d20f25a7c8567146caf63ed593a9d87b2775291be" dependencies = [ - "base64", + "base64 0.22.1", + "serde_core", +] + +[[package]] +name = "pem" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d354a98a3d1251555de99e8fdd8afda05573c31b82f59063a7b0a29b5527f120" +dependencies = [ + "base64 0.23.1", "serde_core", ] @@ -1440,6 +2183,48 @@ version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" +[[package]] +name = "pest" +version = "2.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d45aeb61b4bf818e12d4205f2466f8c4748f85f4fce0146d1c03d69d753f0ad" +dependencies = [ + "memchr", + "ucd-trie", +] + +[[package]] +name = "pest_derive" +version = "2.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89cc5a242e25ed4e7704d0be240f2cfbe20a8c27e7e252d94835be93d92dc39f" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" +version = "2.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7abf21475cc3820fe4b2ca2dc2142902f67a02189f3b5b3a229f4febc01a43e5" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "pest_meta" +version = "2.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adba4db388f687393c18c51348d44a41d870ca9df71a2c98172ea3035dc6936e" +dependencies = [ + "pest", +] + [[package]] name = "petgraph" version = "0.8.3" @@ -1671,6 +2456,12 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + [[package]] name = "r-efi" version = "6.0.0" @@ -1705,12 +2496,12 @@ checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" [[package]] name = "rcgen" -version = "0.13.2" +version = "0.14.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75e669e5202259b5314d1ea5397316ad400819437857b90861765f24c4cf80a2" +checksum = "8774e05a7d0de114588e6a28fe7e71694b82614ed569d86d8b389dfbc98b8ad8" dependencies = [ "aws-lc-rs", - "pem", + "pem 4.0.0", "rustls-pki-types", "time", "x509-parser", @@ -1875,6 +2666,12 @@ version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f" +[[package]] +name = "ryu" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" + [[package]] name = "same-file" version = "1.0.6" @@ -1893,12 +2690,45 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "schemars" +version = "0.8.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fbf2ae1b8bc8e02df939598064d22402220cd5bbcca1c76f7d6a310974d5615" +dependencies = [ + "dyn-clone", + "schemars_derive", + "serde", + "serde_json", +] + +[[package]] +name = "schemars_derive" +version = "0.8.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32e265784ad618884abaea0600a9adf15393368d840e0222d101a072f3f7534d" +dependencies = [ + "proc-macro2", + "quote", + "serde_derive_internals", + "syn 2.0.119", +] + [[package]] name = "scopeguard" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "secrecy" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e891af845473308773346dc847b2c23ee78fe442e0472ac50e22a18a93d3ae5a" +dependencies = [ + "zeroize", +] + [[package]] name = "security-framework" version = "3.7.0" @@ -1938,6 +2768,16 @@ dependencies = [ "serde_derive", ] +[[package]] +name = "serde-value" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3a1a3341211875ef120e117ea7fd5228530ae7e7036a779fdc9117be6b3282c" +dependencies = [ + "ordered-float", + "serde", +] + [[package]] name = "serde_core" version = "1.0.229" @@ -1958,6 +2798,17 @@ dependencies = [ "syn 3.0.5", ] +[[package]] +name = "serde_derive_internals" +version = "0.29.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + [[package]] name = "serde_json" version = "1.0.151" @@ -1971,6 +2822,41 @@ dependencies = [ "zmij", ] +[[package]] +name = "serde_yaml" +version = "0.9.34+deprecated" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" +dependencies = [ + "indexmap", + "itoa", + "ryu", + "serde", + "unsafe-libyaml", +] + +[[package]] +name = "sha1" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a978451301f4db1d02937a4ab3ccce137717b81826e79b7d49ffe3244a13c3b8" +dependencies = [ + "cfg-if", + "cpufeatures 0.2.17", + "digest 0.10.7", +] + +[[package]] +name = "sha1" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aacc4cc499359472b4abe1bf11d0b12e688af9a805fa5e3016f9a386dc2d0214" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.1", + "digest 0.11.3", +] + [[package]] name = "sha2" version = "0.10.9" @@ -1979,7 +2865,18 @@ checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ "cfg-if", "cpufeatures 0.2.17", - "digest", + "digest 0.10.7", +] + +[[package]] +name = "sha2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "446ba717509524cb3f22f17ecc096f10f4822d76ab5c0b9822c5f9c284e825f4" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.1", + "digest 0.11.3", ] [[package]] @@ -2031,7 +2928,7 @@ checksum = "0d585997b0ac10be3c5ee635f1bab02d512760d14b7c468801ac8a01d9ae5f1d" dependencies = [ "num-bigint", "num-traits", - "thiserror 2.0.20", + "thiserror", "time", ] @@ -2046,6 +2943,9 @@ name = "smallvec" version = "1.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba467056f1b547ed52077911161fc86985becbc60e8e1857c8a144dab0def891" +dependencies = [ + "serde", +] [[package]] name = "socket2" @@ -2057,12 +2957,204 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "spin" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3763264f6b73151db08c50ff20d7d8a0b8796e021cdea7ceedad07b80155fa0e" +dependencies = [ + "lock_api", +] + +[[package]] +name = "sqlx" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "378620ccc25c62c89d8be1c819e76a88d59bdcc3304733330788948e619bfd71" +dependencies = [ + "sqlx-core", + "sqlx-macros", + "sqlx-mysql", + "sqlx-postgres", + "sqlx-sqlite", +] + +[[package]] +name = "sqlx-core" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05b44e85bf579a8eeb4ceaa77a3a523baf2bf0e9bac7e40f405d537b5d2d5ccb" +dependencies = [ + "base64 0.22.1", + "bytes", + "cfg-if", + "crc", + "crossbeam-queue", + "either", + "event-listener", + "futures-core", + "futures-intrusive", + "futures-io", + "futures-util", + "hashbrown 0.16.1", + "hashlink", + "indexmap", + "log", + "memchr", + "percent-encoding", + "rustls", + "serde", + "serde_json", + "sha2 0.10.9", + "smallvec", + "thiserror", + "tokio", + "tokio-stream", + "tracing", + "url", + "webpki-roots", +] + +[[package]] +name = "sqlx-macros" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd2b84f2bc39a5705ef27ec785a11c934a41bbd4a24941e257927cddc26b60bf" +dependencies = [ + "proc-macro2", + "quote", + "sqlx-core", + "sqlx-macros-core", + "syn 2.0.119", +] + +[[package]] +name = "sqlx-macros-core" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb8d96de5fdc85a5c4ec813432b523ec637e80ba98f046555f75f7908ddac7c3" +dependencies = [ + "cfg-if", + "dotenvy", + "either", + "heck", + "hex", + "proc-macro2", + "quote", + "serde", + "serde_json", + "sha2 0.10.9", + "sqlx-core", + "sqlx-postgres", + "sqlx-sqlite", + "syn 2.0.119", + "thiserror", + "tokio", + "url", +] + +[[package]] +name = "sqlx-mysql" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90b8020fe17c5f2c245bfa2505d7ef59c5604839527c740266ad2214acebea27" +dependencies = [ + "bitflags", + "byteorder", + "bytes", + "crc", + "digest 0.11.3", + "dotenvy", + "either", + "futures-core", + "futures-util", + "generic-array", + "log", + "percent-encoding", + "serde", + "sha1 0.11.0", + "sha2 0.11.0", + "sqlx-core", + "thiserror", + "tracing", +] + +[[package]] +name = "sqlx-postgres" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87a2bdd6e83f6b3ea525ca9fee568030508b58355a43d0b2c1674d5f79dcd65e" +dependencies = [ + "atoi", + "base64 0.22.1", + "bitflags", + "byteorder", + "crc", + "dotenvy", + "etcetera", + "futures-channel", + "futures-core", + "futures-util", + "hex", + "hkdf", + "hmac", + "itoa", + "log", + "md-5", + "memchr", + "rand", + "serde", + "serde_json", + "sha2 0.11.0", + "smallvec", + "sqlx-core", + "stringprep", + "thiserror", + "tracing", + "whoami", +] + +[[package]] +name = "sqlx-sqlite" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "488e99c397a62007e4229aec669a179816339afc6d2620ca6fa420dbee2e982c" +dependencies = [ + "atoi", + "flume", + "form_urlencoded", + "futures-channel", + "futures-core", + "futures-executor", + "futures-intrusive", + "futures-util", + "libsqlite3-sys", + "log", + "percent-encoding", + "serde", + "sqlx-core", + "thiserror", + "tracing", + "url", +] + [[package]] name = "stable_deref_trait" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" +[[package]] +name = "stringprep" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b4df3d392d81bd458a8a621b8bffbd2302a12ffe288a9d931670948749463b1" +dependencies = [ + "unicode-bidi", + "unicode-normalization", + "unicode-properties", +] + [[package]] name = "strsim" version = "0.11.1" @@ -2179,33 +3271,13 @@ dependencies = [ "unicode-width 0.2.2", ] -[[package]] -name = "thiserror" -version = "1.0.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" -dependencies = [ - "thiserror-impl 1.0.69", -] - [[package]] name = "thiserror" version = "2.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec86235f5fcc2a73650310756d2ac5b138a5780bbbdfae3eeccec992c435ba4f" dependencies = [ - "thiserror-impl 2.0.20", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.119", + "thiserror-impl", ] [[package]] @@ -2326,6 +3398,7 @@ dependencies = [ "futures-sink", "libc", "pin-project-lite", + "slab", "tokio", ] @@ -2337,7 +3410,7 @@ checksum = "ac2a5518c70fa84342385732db33fb3f44bc4cc748936eb5833d2df34d6445ef" dependencies = [ "async-trait", "axum", - "base64", + "base64 0.22.1", "bytes", "h2", "http", @@ -2429,6 +3502,24 @@ dependencies = [ "tracing", ] +[[package]] +name = "tower-http" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cfcf7e2740e6fc6d4d688b4ef00650406bb94adf4731e43c096c3a19fe40840" +dependencies = [ + "base64 0.22.1", + "bitflags", + "bytes", + "http", + "http-body", + "mime", + "pin-project-lite", + "tower-layer", + "tower-service", + "tracing", +] + [[package]] name = "tower-layer" version = "0.3.3" @@ -2447,6 +3538,7 @@ version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" dependencies = [ + "log", "pin-project-lite", "tracing-attributes", "tracing-core", @@ -2484,18 +3576,45 @@ version = "1.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" +[[package]] +name = "ucd-trie" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" + [[package]] name = "unicase" version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dbc4bc3a9f746d862c45cb89d705aa10f187bb96c76001afab07a0d35ce60142" +[[package]] +name = "unicode-bidi" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" + [[package]] name = "unicode-ident" version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" +[[package]] +name = "unicode-normalization" +version = "0.1.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fd4f6878c9cb28d874b009da9e8d183b5abc80117c40bbd187a1fde336be6e8" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-properties" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7df058c713841ad818f1dc5d3fd88063241cc61f49f5fbea4b951e8cf5a8d71d" + [[package]] name = "unicode-width" version = "0.1.14" @@ -2508,6 +3627,12 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" +[[package]] +name = "unsafe-libyaml" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" + [[package]] name = "untrusted" version = "0.7.1" @@ -2555,6 +3680,12 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + [[package]] name = "version_check" version = "0.9.5" @@ -2586,6 +3717,15 @@ version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" +[[package]] +name = "wasip2" +version = "1.0.4+wasi-0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67efb37e106e55ce722a510d6b5f9c17f083e5fc79afc2badeb12cc313d9487" +dependencies = [ + "wit-bindgen", +] + [[package]] name = "wasm-bindgen" version = "0.2.128" @@ -2631,6 +3771,21 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "webpki-roots" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dcd9d09a39985f5344844e66b0c530a33843579125f23e21e9f0f220850f22a" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "whoami" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "626c4bac6755d76ffc12cb01b2eac751db1996b9e0041de9aa02c8c211ddc82c" + [[package]] name = "winapi-util" version = "0.1.11" @@ -2728,6 +3883,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +[[package]] +name = "wit-bindgen" +version = "0.57.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" + [[package]] name = "writeable" version = "0.6.4" @@ -2736,28 +3897,29 @@ checksum = "3ad82d2a33cdc9674dc7465672f271e096168fcdbe0f799d9e6db8c5892679dc" [[package]] name = "x509-parser" -version = "0.16.0" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcbc162f30700d6f3f82a24bf7cc62ffe7caea42c0b2cba8bf7f3ae50cf51f69" +checksum = "d43b0f71ce057da06bc0851b23ee24f3f86190b07203dd8f567d0b706a185202" dependencies = [ "asn1-rs", + "aws-lc-rs", "data-encoding", "der-parser", "lazy_static", "nom", "oid-registry", - "ring", "rusticata-macros", - "thiserror 1.0.69", + "thiserror", "time", ] [[package]] name = "yasna" -version = "0.5.2" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e17bb3549cc1321ae1296b9cdc2698e2b6cb1992adfa19a8c72e5b7a738f44cd" +checksum = "b5f6765e852b9b4dc8e2a76843e4d64d1cea8e79bcde0b6901aea8e7c7f08282" dependencies = [ + "bit-vec", "time", ] @@ -2784,6 +3946,26 @@ dependencies = [ "synstructure 0.14.0", ] +[[package]] +name = "zerocopy" +version = "0.8.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d35102a9f36d089ccae9e4c6802bc118be4487b80aaffc0ab4e0cf5ce92d2873" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "146c01f5ab44258da43cf276c74a2763db2ff3969c9c652c3f2de07041d0b2bc" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + [[package]] name = "zerofrom" version = "0.1.8" diff --git a/tasks/test.toml b/tasks/test.toml index 30f348bebd..a0e3b75338 100644 --- a/tasks/test.toml +++ b/tasks/test.toml @@ -81,6 +81,8 @@ description = "Run Rust tests" depends = ["rust:lockfiles:check"] env = { OPENSHELL_TELEMETRY_ENABLED = "false" } run = [ + # Prove the facade contract without the default backend's compiled features. + "cargo test -p openshell-crypto --no-default-features --test independent_backend", # Run the workspace once without openshell-server so we can run that crate # with test-only helpers enabled. "cargo test --workspace --exclude openshell-server", From 1a5604e72ea429a59de5b222b24a94bf9f484a20 Mon Sep 17 00:00:00 2001 From: Varsha Prasad Narsing Date: Fri, 18 Sep 2026 15:07:54 -0700 Subject: [PATCH 10/10] chore(crypto): refresh feature suite lockfile after rebase Signed-off-by: Varsha Prasad Narsing --- tests/suites/features/Cargo.lock | 1684 +++++++++++++++++++++++++++++- 1 file changed, 1642 insertions(+), 42 deletions(-) diff --git a/tests/suites/features/Cargo.lock b/tests/suites/features/Cargo.lock index 20ebe58016..05d4afbd66 100644 --- a/tests/suites/features/Cargo.lock +++ b/tests/suites/features/Cargo.lock @@ -2,12 +2,113 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "ahash" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" +dependencies = [ + "cfg-if", + "getrandom 0.3.4", + "once_cell", + "version_check", + "zerocopy", +] + +[[package]] +name = "aho-corasick" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c982642fa9e8606056828ee9a8505737230110bb1099153c79efe865c59d12ba" +dependencies = [ + "memchr", +] + +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + [[package]] name = "anyhow" version = "1.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "330a5ed07fa54e4702c9d6c4174f74427fc0ef6e214bbd677ae50a5099946470" +[[package]] +name = "asn1-rs" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7f43a50ac4fdca5df8e885c21b835997f0a1cdee65494a6847694a98652d9d8" +dependencies = [ + "asn1-rs-derive", + "asn1-rs-impl", + "displaydoc", + "nom", + "num-traits", + "rusticata-macros", + "thiserror", + "time", +] + +[[package]] +name = "asn1-rs-derive" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3109e49b1e4909e9db6515a30c633684d68cdeaa252f215214cb4fa1a5bfee2c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", + "synstructure 0.13.2", +] + +[[package]] +name = "asn1-rs-impl" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "async-broadcast" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "435a87a52755b8f27fcf321ac4f04b2802e337c8c4872923137471ec39c37532" +dependencies = [ + "event-listener", + "event-listener-strategy", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-stream" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" +dependencies = [ + "async-stream-impl", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-stream-impl" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + [[package]] name = "async-trait" version = "0.1.92" @@ -19,6 +120,15 @@ dependencies = [ "syn 3.0.5", ] +[[package]] +name = "atoi" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28d99ec8bfea296261ca1af174f24225171fea9664ba9003cbebee704810528" +dependencies = [ + "num-traits", +] + [[package]] name = "atomic-waker" version = "1.1.2" @@ -38,7 +148,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b281d307588d634de920874890732659e2e7672f72b5e10e81badc1a8a83621e" dependencies = [ "aws-lc-sys", - "untrusted", + "untrusted 0.7.1", "zeroize", ] @@ -98,17 +208,46 @@ dependencies = [ "tower-service", ] +[[package]] +name = "backon" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cffb0e931875b666fc4fcb20fee52e9bbd1ef836fd9e9e04ec21555f9f85f7ef" +dependencies = [ + "fastrand", + "gloo-timers", + "tokio", +] + [[package]] name = "base64" version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +[[package]] +name = "base64" +version = "0.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac07cdecf99051d9a5238b80f35af32cdeba5b336e55d957b318b50137e18da5" + +[[package]] +name = "bit-vec" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b71798fca2c1fe1086445a7258a4bc81e6e49dcd24c8d0dd9a1e57395b603f51" +dependencies = [ + "serde", +] + [[package]] name = "bitflags" version = "2.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3ded4057c258ba199e2d26386d3af3780957ecaee6c4ef4041c6b4b8b97c0b06" +dependencies = [ + "serde_core", +] [[package]] name = "block-buffer" @@ -119,13 +258,22 @@ dependencies = [ "generic-array", ] +[[package]] +name = "block-buffer" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2f6c7dbe95a6ed67ad9f18e57daf93a2f034c524b99fd2b76d18fdfeb6660aa" +dependencies = [ + "hybrid-array", +] + [[package]] name = "bollard" version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ee04c4c84f1f811b017f2fbb7dd8815c976e7ca98593de9c1e2afad0f636bff4" dependencies = [ - "base64", + "base64 0.22.1", "bollard-stubs", "bytes", "futures-core", @@ -168,6 +316,12 @@ version = "3.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + [[package]] name = "bytes" version = "1.12.1" @@ -198,6 +352,27 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f079e83a288787bcd14a6aea84cee5c87a67c5a3e660c30f557a3d24761b3527" +[[package]] +name = "chacha20" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65c35e4b699c7e15ccbe7ee35c005e4fc0a278d22238a2857e6ce2dadeda1b06" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.1", + "rand_core 0.10.1", +] + +[[package]] +name = "chrono" +version = "0.4.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aa79e62e7697b8e29b513a68abacf485adcd1fe8284a4316c5ae868e6633327" +dependencies = [ + "num-traits", + "serde", +] + [[package]] name = "cmake" version = "0.1.58" @@ -207,6 +382,28 @@ dependencies = [ "cc", ] +[[package]] +name = "cmov" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c9ea0ac24bc397ab3c98583a3c9ba74fa56b09a4449bbe172b9b1ddb016027a" + +[[package]] +name = "core-foundation" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + [[package]] name = "cpufeatures" version = "0.2.17" @@ -216,6 +413,45 @@ dependencies = [ "libc", ] +[[package]] +name = "cpufeatures" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ca28b0ae3115b884660db4118d803791fd6756b6e88f39c0f3f7859060d7566" +dependencies = [ + "libc", +] + +[[package]] +name = "crc" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5eb8a2a1cd12ab0d987a5d5e825195d372001a4094a0376319d5a0ad71c1ba0d" +dependencies = [ + "crc-catalog", +] + +[[package]] +name = "crc-catalog" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "217698eaf96b4a3f0bc4f3662aaa55bdf913cd54d7204591faa790070c6d0853" + +[[package]] +name = "crossbeam-queue" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03e8bd762f7479489c70ed6c768ddca99d7296857de437a68dcb2a94365b3fae" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a31eee39dddec8330830986fcd7625edb5a24ec90ea038215273bbc3adb08ac6" + [[package]] name = "crypto-common" version = "0.1.7" @@ -226,6 +462,79 @@ dependencies = [ "typenum", ] +[[package]] +name = "crypto-common" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce6e4c961d6cd6c9a86db418387425e8bdeaf05b3c8bc1411e6dca4c252f1453" +dependencies = [ + "hybrid-array", +] + +[[package]] +name = "ctutils" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d5515a3834141de9eafb9717ad39eea8247b5674e6066c404e8c4b365d2a29e" +dependencies = [ + "cmov", +] + +[[package]] +name = "darling" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.119", +] + +[[package]] +name = "darling_macro" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" +dependencies = [ + "darling_core", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "data-encoding" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4583a4551df46e2792f82ceeac45e850d2e2d5debba0b91f102385cda5b11f06" + +[[package]] +name = "der-parser" +version = "10.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07da5016415d5a3c4dd39b11ed26f915f52fc4e0dc197d87908bc916e51bc1a6" +dependencies = [ + "asn1-rs", + "displaydoc", + "nom", + "num-bigint", + "num-traits", + "rusticata-macros", +] + [[package]] name = "deranged" version = "0.5.8" @@ -238,8 +547,19 @@ version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ - "block-buffer", - "crypto-common", + "block-buffer 0.10.4", + "crypto-common 0.1.7", +] + +[[package]] +name = "digest" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2" +dependencies = [ + "block-buffer 0.12.1", + "crypto-common 0.2.2", + "ctutils", ] [[package]] @@ -253,17 +573,64 @@ dependencies = [ "syn 3.0.5", ] +[[package]] +name = "dotenvy" +version = "0.15.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" + [[package]] name = "dunce" version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" +[[package]] +name = "dyn-clone" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" + +[[package]] +name = "educe" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7bc049e1bd8cdeb31b68bbd586a9464ecf9f3944af3958a7a9d0f8b9799417" +dependencies = [ + "enum-ordinalize", + "proc-macro2", + "quote", + "syn 2.0.119", +] + [[package]] name = "either" version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "252afb9ae5eaa683babdc6a068b3f5726eb19e05070c731f9b2a23a7c3e8ed34" +dependencies = [ + "serde", +] + +[[package]] +name = "enum-ordinalize" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89dd01549b09589510cf0647475075d12071456586d70f5c75c98ae2a5537677" +dependencies = [ + "enum-ordinalize-derive", +] + +[[package]] +name = "enum-ordinalize-derive" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a65863d15a4ce2888bd2f0f543cc963d3879c3a022c8ee43f6141d479a3ac815" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.5", +] [[package]] name = "equivalent" @@ -278,7 +645,37 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys", + "windows-sys 0.61.2", +] + +[[package]] +name = "etcetera" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de48cc4d1c1d97a20fd819def54b890cadde72ed3ad0c614822a0a433361be96" +dependencies = [ + "cfg-if", + "windows-sys 0.61.2", +] + +[[package]] +name = "event-listener" +version = "5.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a23add41df1562121a9393cb065eab5146a1242410f23a644851e90cfd669d2" +dependencies = [ + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" +dependencies = [ + "event-listener", + "pin-project-lite", ] [[package]] @@ -293,12 +690,35 @@ version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3e0f1c7c3a72c66fd80abe965175f7523475c0489a87d3ff9d6e8c87d87a9d2d" +[[package]] +name = "flume" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e139bc46ca777eb5efaf62df0ab8cc5fd400866427e56c68b22e414e53bd3be" +dependencies = [ + "futures-core", + "futures-sink", + "spin", +] + [[package]] name = "fnv" version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + +[[package]] +name = "foldhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + [[package]] name = "form_urlencoded" version = "1.2.2" @@ -314,6 +734,20 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" +[[package]] +name = "futures" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a31d2a3fbaaeb2af2368bbdd904aa8e812d3c04a1ee10d3171f52d556e5d0a3" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + [[package]] name = "futures-channel" version = "0.3.34" @@ -321,6 +755,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1f9e3d69d39e4862ffed03ed071a76f9a13ba1d9109d355b0f0aa6b15e393c4" dependencies = [ "futures-core", + "futures-sink", ] [[package]] @@ -329,6 +764,34 @@ version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "92d699e522242e69e3003b94ecc1f960f3a5e015aa7c5d7486e65ad01dd94f5e" +[[package]] +name = "futures-executor" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "031b47cf1a3c6cc8bc2fc76cd437f521619387907d469316e7c0bc278f1f5432" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-intrusive" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d930c203dd0b6ff06e0201a4a2fe9149b43c684fd4420555b26d21b1a02956f" +dependencies = [ + "futures-core", + "lock_api", + "parking_lot", +] + +[[package]] +name = "futures-io" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53c0fa8157de1303bfffdaa1cc2a673bfffb60102f76b0ef4441659124373fed" + [[package]] name = "futures-macro" version = "0.3.34" @@ -358,9 +821,13 @@ version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0d50a92467f8ba5dd6e3ee5d4bd04d73ab2e4e1c44474a0674821dfce14b79bc" dependencies = [ + "futures-channel", "futures-core", + "futures-io", "futures-macro", + "futures-sink", "futures-task", + "memchr", "pin-project-lite", "slab", ] @@ -407,6 +874,19 @@ dependencies = [ "cfg-if", "libc", "r-efi 6.0.0", + "rand_core 0.10.1", +] + +[[package]] +name = "gloo-timers" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbb143cf96099802033e0d4f4963b19fd2e0b728bcf076cd9cf7f6634f092994" +dependencies = [ + "futures-channel", + "futures-core", + "js-sys", + "wasm-bindgen", ] [[package]] @@ -428,18 +908,117 @@ dependencies = [ "tracing", ] +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash 0.1.5", +] + +[[package]] +name = "hashbrown" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash 0.2.0", +] + [[package]] name = "hashbrown" version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" +[[package]] +name = "hashlink" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "824e001ac4f3012dd16a264bec811403a67ca9deb6c102fc5049b32c4574b35f" +dependencies = [ + "hashbrown 0.16.1", +] + +[[package]] +name = "headers" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3314d5adb5d94bcdf56771f2e50dbbc80bb4bdf88967526706205ac9eff24eb" +dependencies = [ + "base64 0.22.1", + "bytes", + "headers-core", + "http", + "httpdate", + "mime", + "sha1 0.10.7", +] + +[[package]] +name = "headers-core" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54b4a22553d4242c49fddb9ba998a99962b5cc6f22cb5a3482bec22522403ce4" +dependencies = [ + "http", +] + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + [[package]] name = "hex" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[package]] +name = "hkdf" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4aaa26c720c68b866f2c96ef5c1264b3e6f473fe5d4ce61cd44bbe913e553018" +dependencies = [ + "hmac", +] + +[[package]] +name = "hmac" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6303bc9732ae41b04cb554b844a762b4115a61bfaa81e3e83050991eeb56863f" +dependencies = [ + "digest 0.11.3", +] + +[[package]] +name = "home" +version = "0.5.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "hostname" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "617aaa3557aef3810a6369d0a99fac8a080891b68bd9f9812a1eeda0c0730cbd" +dependencies = [ + "cfg-if", + "libc", + "windows-link", +] + [[package]] name = "http" version = "1.5.0" @@ -485,6 +1064,15 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" +[[package]] +name = "hybrid-array" +version = "0.4.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27f864f10dfb56725ce5ce5472bc52252c8f93a4ab86327122cebf62c5f59a17" +dependencies = [ + "typenum", +] + [[package]] name = "hyper" version = "1.11.1" @@ -507,6 +1095,25 @@ dependencies = [ "want", ] +[[package]] +name = "hyper-http-proxy" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd1d471ea2f65ba45eddb1d6ab7d58ac2671d2d4ac14da5c6516ae1d97e1327a" +dependencies = [ + "bytes", + "futures-util", + "headers", + "http", + "hyper", + "hyper-rustls", + "hyper-util", + "pin-project-lite", + "tokio", + "tokio-rustls", + "tower-service", +] + [[package]] name = "hyper-named-pipe" version = "0.1.1" @@ -521,6 +1128,23 @@ dependencies = [ "tower-service", ] +[[package]] +name = "hyper-rustls" +version = "0.27.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ca68d021ef39cf6463ab54c1d0f5daf03377b70561305bb89a8f83aab66e0f" +dependencies = [ + "http", + "hyper", + "hyper-util", + "log", + "rustls", + "rustls-native-certs", + "tokio", + "tokio-rustls", + "tower-service", +] + [[package]] name = "hyper-timeout" version = "0.5.2" @@ -652,6 +1276,12 @@ dependencies = [ "zerovec", ] +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + [[package]] name = "idna" version = "1.1.0" @@ -680,7 +1310,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cc4e190f5d26ca7051642629da2c52fc03bde85a03197c99408dcd291734c855" dependencies = [ "equivalent", - "hashbrown", + "hashbrown 0.17.1", "serde", "serde_core", ] @@ -714,31 +1344,195 @@ dependencies = [ name = "js-sys" version = "0.3.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce57d20d1ea864ce2ac172ab472d409214f4fd359f0b2a2775abdf522e2af99e" +checksum = "ce57d20d1ea864ce2ac172ab472d409214f4fd359f0b2a2775abdf522e2af99e" +dependencies = [ + "cfg-if", + "futures-util", + "wasm-bindgen", +] + +[[package]] +name = "json-patch" +version = "4.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7421438de105a0827e44fadd05377727847d717c80ce29a229f85fd04c427b72" +dependencies = [ + "jsonptr", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "jsonpath-rust" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c00ae348f9f8fd2d09f82a98ca381c60df9e0820d8d79fce43e649b4dc3128b" +dependencies = [ + "pest", + "pest_derive", + "regex", + "serde_json", + "thiserror", +] + +[[package]] +name = "jsonptr" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5a3cc660ba5d72bce0b3bb295bf20847ccbb40fd423f3f05b61273672e561fe" +dependencies = [ + "serde", + "serde_json", +] + +[[package]] +name = "jsonwebtoken" +version = "10.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eba32bfb4ffdeaca3e34431072faf01745c9b26d25504aa7a6cf5684334fc4fc" +dependencies = [ + "aws-lc-rs", + "base64 0.22.1", + "getrandom 0.2.17", + "js-sys", + "pem 3.0.6", + "serde", + "serde_json", + "signature", + "simple_asn1", + "zeroize", +] + +[[package]] +name = "k8s-openapi" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c75b990324f09bef15e791606b7b7a296d02fc88a344f6eba9390970a870ad5" +dependencies = [ + "base64 0.22.1", + "chrono", + "serde", + "serde-value", + "serde_json", +] + +[[package]] +name = "kube" +version = "0.99.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a4eb20010536b48abe97fec37d23d43069bcbe9686adcf9932202327bc5ca6e" +dependencies = [ + "k8s-openapi", + "kube-client", + "kube-core", + "kube-derive", + "kube-runtime", +] + +[[package]] +name = "kube-client" +version = "0.99.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fc2ed952042df20d15ac2fe9614d0ec14b6118eab89633985d4b36e688dccf1" +dependencies = [ + "base64 0.22.1", + "bytes", + "chrono", + "either", + "futures", + "home", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-http-proxy", + "hyper-rustls", + "hyper-timeout", + "hyper-util", + "jsonpath-rust", + "k8s-openapi", + "kube-core", + "pem 3.0.6", + "rustls", + "secrecy", + "serde", + "serde_json", + "serde_yaml", + "thiserror", + "tokio", + "tokio-util", + "tower", + "tower-http", + "tracing", +] + +[[package]] +name = "kube-core" +version = "0.99.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff0d0793db58e70ca6d689489183816cb3aa481673e7433dc618cf7e8007c675" +dependencies = [ + "chrono", + "form_urlencoded", + "http", + "json-patch", + "k8s-openapi", + "schemars", + "serde", + "serde-value", + "serde_json", + "thiserror", +] + +[[package]] +name = "kube-derive" +version = "0.99.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c562f58dc9f7ca5feac8a6ee5850ca221edd6f04ce0dd2ee873202a88cd494c9" dependencies = [ - "cfg-if", - "futures-util", - "wasm-bindgen", + "darling", + "proc-macro2", + "quote", + "serde", + "serde_json", + "syn 2.0.119", ] [[package]] -name = "jsonwebtoken" -version = "10.4.0" +name = "kube-runtime" +version = "0.99.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eba32bfb4ffdeaca3e34431072faf01745c9b26d25504aa7a6cf5684334fc4fc" +checksum = "88f34cfab9b4bd8633062e0e85edb81df23cb09f159f2e31c60b069ae826ffdc" dependencies = [ - "aws-lc-rs", - "base64", - "getrandom 0.2.17", - "js-sys", - "pem", + "ahash", + "async-broadcast", + "async-stream", + "async-trait", + "backon", + "educe", + "futures", + "hashbrown 0.15.5", + "hostname", + "json-patch", + "k8s-openapi", + "kube-client", + "parking_lot", + "pin-project", "serde", "serde_json", - "signature", - "simple_asn1", - "zeroize", + "thiserror", + "tokio", + "tokio-util", + "tracing", ] +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + [[package]] name = "libc" version = "0.2.189" @@ -751,6 +1545,17 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" +[[package]] +name = "libsqlite3-sys" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f111c8c41e7c61a49cd34e44c7619462967221a6443b0ec299e0ac30cfb9b1" +dependencies = [ + "cc", + "pkg-config", + "vcpkg", +] + [[package]] name = "linux-raw-sys" version = "0.12.1" @@ -784,6 +1589,16 @@ version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" +[[package]] +name = "md-5" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69b6441f590336821bb897fb28fc622898ccceb1d6cea3fde5ea86b090c4de98" +dependencies = [ + "cfg-if", + "digest 0.11.3", +] + [[package]] name = "memchr" version = "2.8.3" @@ -796,6 +1611,12 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + [[package]] name = "mio" version = "1.2.3" @@ -804,7 +1625,7 @@ checksum = "4b18443e9c262bfe8fa82f51666e2642c53393f7e5c27b3e1aeab922cff5b9d8" dependencies = [ "libc", "wasi", - "windows-sys", + "windows-sys 0.61.2", ] [[package]] @@ -819,13 +1640,23 @@ dependencies = [ "libc", ] +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + [[package]] name = "noyalib" version = "0.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f075ef19fa3bcf8697c0ef96c37d5c435d339a40ab8081cae3aac3a4e7fee9a" dependencies = [ - "hashbrown", + "hashbrown 0.17.1", "indexmap", "libm", "memchr", @@ -869,6 +1700,15 @@ dependencies = [ "autocfg", ] +[[package]] +name = "oid-registry" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12f40cff3dde1b6087cc5d5f5d4d65712f34016a03ed60e9c08dcc392736b5b7" +dependencies = [ + "asn1-rs", +] + [[package]] name = "once_cell" version = "1.21.4" @@ -879,17 +1719,35 @@ checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" name = "openshell-conformance" version = "0.0.0" dependencies = [ - "rand", + "rand 0.9.5", "serde", "serde_json", "tokio", ] +[[package]] +name = "openshell-crypto" +version = "0.0.0" +dependencies = [ + "aws-lc-rs", + "hyper-rustls", + "jsonwebtoken", + "kube", + "pem 3.0.6", + "rcgen", + "rustls", + "serde", + "sqlx", + "thiserror", + "tonic", + "x509-parser", +] + [[package]] name = "openshell-e2e" version = "0.1.0" dependencies = [ - "base64", + "base64 0.22.1", "bollard", "bytes", "futures-util", @@ -900,12 +1758,13 @@ dependencies = [ "jsonwebtoken", "nix", "noyalib", + "openshell-crypto", "prost", - "rand", + "rand 0.9.5", "serde", "serde_json", - "sha1", - "sha2", + "sha1 0.10.7", + "sha2 0.10.9", "tempfile", "tokio", "tokio-stream", @@ -926,6 +1785,27 @@ dependencies = [ "tokio", ] +[[package]] +name = "openssl-probe" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" + +[[package]] +name = "ordered-float" +version = "2.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68f19d67e5a2795c94e73e0bb1cc1a7edeb2e28efd39e2e1c9b7a40c1108b11c" +dependencies = [ + "num-traits", +] + +[[package]] +name = "parking" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" + [[package]] name = "parking_lot" version = "0.12.5" @@ -955,7 +1835,17 @@ version = "3.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d30c53c26bc5b31a98cd02d20f25a7c8567146caf63ed593a9d87b2775291be" dependencies = [ - "base64", + "base64 0.22.1", + "serde_core", +] + +[[package]] +name = "pem" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d354a98a3d1251555de99e8fdd8afda05573c31b82f59063a7b0a29b5527f120" +dependencies = [ + "base64 0.23.1", "serde_core", ] @@ -965,6 +1855,48 @@ version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" +[[package]] +name = "pest" +version = "2.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d45aeb61b4bf818e12d4205f2466f8c4748f85f4fce0146d1c03d69d753f0ad" +dependencies = [ + "memchr", + "ucd-trie", +] + +[[package]] +name = "pest_derive" +version = "2.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89cc5a242e25ed4e7704d0be240f2cfbe20a8c27e7e252d94835be93d92dc39f" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" +version = "2.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7abf21475cc3820fe4b2ca2dc2142902f67a02189f3b5b3a229f4febc01a43e5" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "pest_meta" +version = "2.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adba4db388f687393c18c51348d44a41d870ca9df71a2c98172ea3035dc6936e" +dependencies = [ + "pest", +] + [[package]] name = "pin-project" version = "1.1.13" @@ -1084,6 +2016,17 @@ dependencies = [ "rand_core 0.9.5", ] +[[package]] +name = "rand" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7f5fa3a058cd35567ef9bfa5e75732bee0f9e4c55fa90477bef2dfcdbc4be80" +dependencies = [ + "chacha20", + "getrandom 0.4.3", + "rand_core 0.10.1", +] + [[package]] name = "rand_chacha" version = "0.9.0" @@ -1112,6 +2055,26 @@ dependencies = [ "getrandom 0.3.4", ] +[[package]] +name = "rand_core" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" + +[[package]] +name = "rcgen" +version = "0.14.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8774e05a7d0de114588e6a28fe7e71694b82614ed569d86d8b389dfbc98b8ad8" +dependencies = [ + "aws-lc-rs", + "pem 4.0.0", + "rustls-pki-types", + "time", + "x509-parser", + "yasna", +] + [[package]] name = "redox_syscall" version = "0.5.18" @@ -1121,12 +2084,64 @@ dependencies = [ "bitflags", ] +[[package]] +name = "regex" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f020237b6c8eed93db2e2cb53c00c60a8e1bc73da7d073199a1180401450218d" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad8553b9b26413251cbf30e620595c7a41b3887f03da04579c0e6b0d6a06b4b2" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4" + +[[package]] +name = "ring" +version = "0.17.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" +dependencies = [ + "cc", + "cfg-if", + "getrandom 0.2.17", + "libc", + "untrusted 0.9.0", + "windows-sys 0.52.0", +] + [[package]] name = "rustc-hash" version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6b1e7f9a428571be2dc5bc0505c13fb6bf936822b894ec87abf8a08a4e51742d" +[[package]] +name = "rusticata-macros" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "faf0c4a6ece9950b9abdb62b1cfcf2a68b3b67a10ba445b3bb85be2a293d0632" +dependencies = [ + "nom", +] + [[package]] name = "rustix" version = "1.1.4" @@ -1137,7 +2152,55 @@ dependencies = [ "errno", "libc", "linux-raw-sys", - "windows-sys", + "windows-sys 0.61.2", +] + +[[package]] +name = "rustls" +version = "0.23.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d41d731c7d2f962d1ccc364cec258de3c0e93b38c2fb3ba97ac74513048d634" +dependencies = [ + "aws-lc-rs", + "log", + "once_cell", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-native-certs" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dab5152771c58876a2146916e53e35057e1a4dfa2b9df0f0305b07f611fdea4d" +dependencies = [ + "openssl-probe", + "rustls-pki-types", + "schannel", + "security-framework", +] + +[[package]] +name = "rustls-pki-types" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f4925028c7eb5d1fcdaf196971378ed9d2c1c4efc7dc5d011256f76c99c0a96" +dependencies = [ + "zeroize", +] + +[[package]] +name = "rustls-webpki" +version = "0.103.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3c3cf1d8b1e7d4927e2d154c3fcb02979afb9939629c62cd9048d4f07b60ac2" +dependencies = [ + "aws-lc-rs", + "ring", + "rustls-pki-types", + "untrusted 0.9.0", ] [[package]] @@ -1152,12 +2215,77 @@ version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" +[[package]] +name = "schannel" +version = "0.1.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91c1b7e4904c873ef0710c1f407dde2e6287de2bebc1bbbf7d430bb7cbffd939" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "schemars" +version = "0.8.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fbf2ae1b8bc8e02df939598064d22402220cd5bbcca1c76f7d6a310974d5615" +dependencies = [ + "dyn-clone", + "schemars_derive", + "serde", + "serde_json", +] + +[[package]] +name = "schemars_derive" +version = "0.8.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32e265784ad618884abaea0600a9adf15393368d840e0222d101a072f3f7534d" +dependencies = [ + "proc-macro2", + "quote", + "serde_derive_internals", + "syn 2.0.119", +] + [[package]] name = "scopeguard" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "secrecy" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e891af845473308773346dc847b2c23ee78fe442e0472ac50e22a18a93d3ae5a" +dependencies = [ + "zeroize", +] + +[[package]] +name = "security-framework" +version = "3.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d" +dependencies = [ + "bitflags", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2691df843ecc5d231c0b14ece2acc3efb62c0a398c7e1d875f3983ce020e3" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "serde" version = "1.0.229" @@ -1168,6 +2296,16 @@ dependencies = [ "serde_derive", ] +[[package]] +name = "serde-value" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3a1a3341211875ef120e117ea7fd5228530ae7e7036a779fdc9117be6b3282c" +dependencies = [ + "ordered-float", + "serde", +] + [[package]] name = "serde_core" version = "1.0.229" @@ -1188,6 +2326,17 @@ dependencies = [ "syn 3.0.5", ] +[[package]] +name = "serde_derive_internals" +version = "0.29.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + [[package]] name = "serde_json" version = "1.0.151" @@ -1224,15 +2373,39 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_yaml" +version = "0.9.34+deprecated" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" +dependencies = [ + "indexmap", + "itoa", + "ryu", + "serde", + "unsafe-libyaml", +] + +[[package]] +name = "sha1" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a978451301f4db1d02937a4ab3ccce137717b81826e79b7d49ffe3244a13c3b8" +dependencies = [ + "cfg-if", + "cpufeatures 0.2.17", + "digest 0.10.7", +] + [[package]] name = "sha1" -version = "0.10.7" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a978451301f4db1d02937a4ab3ccce137717b81826e79b7d49ffe3244a13c3b8" +checksum = "aacc4cc499359472b4abe1bf11d0b12e688af9a805fa5e3016f9a386dc2d0214" dependencies = [ "cfg-if", - "cpufeatures", - "digest", + "cpufeatures 0.3.1", + "digest 0.11.3", ] [[package]] @@ -1242,8 +2415,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ "cfg-if", - "cpufeatures", - "digest", + "cpufeatures 0.2.17", + "digest 0.10.7", +] + +[[package]] +name = "sha2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "446ba717509524cb3f22f17ecc096f10f4822d76ab5c0b9822c5f9c284e825f4" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.1", + "digest 0.11.3", ] [[package]] @@ -1294,6 +2478,9 @@ name = "smallvec" version = "1.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba467056f1b547ed52077911161fc86985becbc60e8e1857c8a144dab0def891" +dependencies = [ + "serde", +] [[package]] name = "socket2" @@ -1302,7 +2489,188 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3d1e2c7f27f8d4cb10542a02c49005dbd6e93095799d6f3be745fae9f8fedd4" dependencies = [ "libc", - "windows-sys", + "windows-sys 0.61.2", +] + +[[package]] +name = "spin" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3763264f6b73151db08c50ff20d7d8a0b8796e021cdea7ceedad07b80155fa0e" +dependencies = [ + "lock_api", +] + +[[package]] +name = "sqlx" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "378620ccc25c62c89d8be1c819e76a88d59bdcc3304733330788948e619bfd71" +dependencies = [ + "sqlx-core", + "sqlx-macros", + "sqlx-mysql", + "sqlx-postgres", + "sqlx-sqlite", +] + +[[package]] +name = "sqlx-core" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05b44e85bf579a8eeb4ceaa77a3a523baf2bf0e9bac7e40f405d537b5d2d5ccb" +dependencies = [ + "base64 0.22.1", + "bytes", + "cfg-if", + "crc", + "crossbeam-queue", + "either", + "event-listener", + "futures-core", + "futures-intrusive", + "futures-io", + "futures-util", + "hashbrown 0.16.1", + "hashlink", + "indexmap", + "log", + "memchr", + "percent-encoding", + "rustls", + "serde", + "serde_json", + "sha2 0.10.9", + "smallvec", + "thiserror", + "tokio", + "tokio-stream", + "tracing", + "url", + "webpki-roots", +] + +[[package]] +name = "sqlx-macros" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd2b84f2bc39a5705ef27ec785a11c934a41bbd4a24941e257927cddc26b60bf" +dependencies = [ + "proc-macro2", + "quote", + "sqlx-core", + "sqlx-macros-core", + "syn 2.0.119", +] + +[[package]] +name = "sqlx-macros-core" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb8d96de5fdc85a5c4ec813432b523ec637e80ba98f046555f75f7908ddac7c3" +dependencies = [ + "cfg-if", + "dotenvy", + "either", + "heck", + "hex", + "proc-macro2", + "quote", + "serde", + "serde_json", + "sha2 0.10.9", + "sqlx-core", + "sqlx-postgres", + "sqlx-sqlite", + "syn 2.0.119", + "thiserror", + "tokio", + "url", +] + +[[package]] +name = "sqlx-mysql" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90b8020fe17c5f2c245bfa2505d7ef59c5604839527c740266ad2214acebea27" +dependencies = [ + "bitflags", + "byteorder", + "bytes", + "crc", + "digest 0.11.3", + "dotenvy", + "either", + "futures-core", + "futures-util", + "generic-array", + "log", + "percent-encoding", + "serde", + "sha1 0.11.0", + "sha2 0.11.0", + "sqlx-core", + "thiserror", + "tracing", +] + +[[package]] +name = "sqlx-postgres" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87a2bdd6e83f6b3ea525ca9fee568030508b58355a43d0b2c1674d5f79dcd65e" +dependencies = [ + "atoi", + "base64 0.22.1", + "bitflags", + "byteorder", + "crc", + "dotenvy", + "etcetera", + "futures-channel", + "futures-core", + "futures-util", + "hex", + "hkdf", + "hmac", + "itoa", + "log", + "md-5", + "memchr", + "rand 0.10.2", + "serde", + "serde_json", + "sha2 0.11.0", + "smallvec", + "sqlx-core", + "stringprep", + "thiserror", + "tracing", + "whoami", +] + +[[package]] +name = "sqlx-sqlite" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "488e99c397a62007e4229aec669a179816339afc6d2620ca6fa420dbee2e982c" +dependencies = [ + "atoi", + "flume", + "form_urlencoded", + "futures-channel", + "futures-core", + "futures-executor", + "futures-intrusive", + "futures-util", + "libsqlite3-sys", + "log", + "percent-encoding", + "serde", + "sqlx-core", + "thiserror", + "tracing", + "url", ] [[package]] @@ -1311,6 +2679,29 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" +[[package]] +name = "stringprep" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b4df3d392d81bd458a8a621b8bffbd2302a12ffe288a9d931670948749463b1" +dependencies = [ + "unicode-bidi", + "unicode-normalization", + "unicode-properties", +] + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + [[package]] name = "syn" version = "2.0.119" @@ -1339,6 +2730,17 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + [[package]] name = "synstructure" version = "0.14.0" @@ -1360,7 +2762,7 @@ dependencies = [ "getrandom 0.4.3", "once_cell", "rustix", - "windows-sys", + "windows-sys 0.61.2", ] [[package]] @@ -1423,6 +2825,12 @@ dependencies = [ "zerovec", ] +[[package]] +name = "tinyvec" +version = "1.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd3ca314f692efd6c868f8408f53fe444634a845f96c028b97d35f6a1f79f0ee" + [[package]] name = "tokio" version = "1.53.1" @@ -1437,7 +2845,7 @@ dependencies = [ "signal-hook-registry", "socket2", "tokio-macros", - "windows-sys", + "windows-sys 0.61.2", ] [[package]] @@ -1451,6 +2859,16 @@ dependencies = [ "syn 3.0.5", ] +[[package]] +name = "tokio-rustls" +version = "0.26.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0c85f2c3ef0b1cd58b36682f4b17aaa995f0e5db534d85692b4903abce21f67" +dependencies = [ + "rustls", + "tokio", +] + [[package]] name = "tokio-stream" version = "0.1.19" @@ -1473,6 +2891,7 @@ dependencies = [ "futures-sink", "libc", "pin-project-lite", + "slab", "tokio", ] @@ -1484,7 +2903,7 @@ checksum = "ac2a5518c70fa84342385732db33fb3f44bc4cc748936eb5833d2df34d6445ef" dependencies = [ "async-trait", "axum", - "base64", + "base64 0.22.1", "bytes", "h2", "http", @@ -1498,6 +2917,7 @@ dependencies = [ "socket2", "sync_wrapper", "tokio", + "tokio-rustls", "tokio-stream", "tower", "tower-layer", @@ -1535,6 +2955,24 @@ dependencies = [ "tracing", ] +[[package]] +name = "tower-http" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cfcf7e2740e6fc6d4d688b4ef00650406bb94adf4731e43c096c3a19fe40840" +dependencies = [ + "base64 0.22.1", + "bitflags", + "bytes", + "http", + "http-body", + "mime", + "pin-project-lite", + "tower-layer", + "tower-service", + "tracing", +] + [[package]] name = "tower-layer" version = "0.3.3" @@ -1553,6 +2991,7 @@ version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" dependencies = [ + "log", "pin-project-lite", "tracing-attributes", "tracing-core", @@ -1590,18 +3029,57 @@ version = "1.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" +[[package]] +name = "ucd-trie" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" + +[[package]] +name = "unicode-bidi" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" + [[package]] name = "unicode-ident" version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" +[[package]] +name = "unicode-normalization" +version = "0.1.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fd4f6878c9cb28d874b009da9e8d183b5abc80117c40bbd187a1fde336be6e8" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-properties" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7df058c713841ad818f1dc5d3fd88063241cc61f49f5fbea4b951e8cf5a8d71d" + +[[package]] +name = "unsafe-libyaml" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" + [[package]] name = "untrusted" version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + [[package]] name = "url" version = "2.5.8" @@ -1620,6 +3098,12 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + [[package]] name = "version_check" version = "0.9.5" @@ -1695,6 +3179,21 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "webpki-roots" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dcd9d09a39985f5344844e66b0c530a33843579125f23e21e9f0f220850f22a" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "whoami" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "626c4bac6755d76ffc12cb01b2eac751db1996b9e0041de9aa02c8c211ddc82c" + [[package]] name = "winapi" version = "0.3.9" @@ -1723,6 +3222,15 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + [[package]] name = "windows-sys" version = "0.61.2" @@ -1732,6 +3240,70 @@ dependencies = [ "windows-link", ] +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + [[package]] name = "wit-bindgen" version = "0.57.1" @@ -1744,6 +3316,34 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3ad82d2a33cdc9674dc7465672f271e096168fcdbe0f799d9e6db8c5892679dc" +[[package]] +name = "x509-parser" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d43b0f71ce057da06bc0851b23ee24f3f86190b07203dd8f567d0b706a185202" +dependencies = [ + "asn1-rs", + "aws-lc-rs", + "data-encoding", + "der-parser", + "lazy_static", + "nom", + "oid-registry", + "rusticata-macros", + "thiserror", + "time", +] + +[[package]] +name = "yasna" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5f6765e852b9b4dc8e2a76843e4d64d1cea8e79bcde0b6901aea8e7c7f08282" +dependencies = [ + "bit-vec", + "time", +] + [[package]] name = "yoke" version = "0.8.3" @@ -1764,7 +3364,7 @@ dependencies = [ "proc-macro2", "quote", "syn 3.0.5", - "synstructure", + "synstructure 0.14.0", ] [[package]] @@ -1805,7 +3405,7 @@ dependencies = [ "proc-macro2", "quote", "syn 3.0.5", - "synstructure", + "synstructure 0.14.0", ] [[package]]