From 93a0a764817f8bf679ec509fd5b9a33b9b3167e8 Mon Sep 17 00:00:00 2001 From: Varsha Prasad Narsing Date: Mon, 14 Sep 2026 19:27:08 -0700 Subject: [PATCH 01/25] refactor(crypto): centralize AWS-LC behind backend interface Signed-off-by: Varsha Prasad Narsing --- AGENTS.md | 1 + Cargo.lock | 32 +- Cargo.toml | 12 +- 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 | 3 +- 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/upstream_proxy.rs | 4 +- e2e/rust/Cargo.lock | 35 ++ 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/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 + 68 files changed, 1466 insertions(+), 186 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 e7eec57bfd..7217f941b9 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -36,6 +36,7 @@ Do not rely on this file for a full inventory. The detailed public and contribut | `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 e152fdc96d..36490b16a7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4231,10 +4231,10 @@ dependencies = [ "bytes", "miette", "openshell-core", + "openshell-crypto", "rcgen", "serde", "serde_json", - "sha2 0.10.9", "tempfile", "tokio", "tracing", @@ -4266,6 +4266,7 @@ dependencies = [ "oauth2", "openshell-bootstrap", "openshell-core", + "openshell-crypto", "openshell-policy", "openshell-providers", "openshell-sdk", @@ -4318,6 +4319,7 @@ dependencies = [ "jsonwebtoken", "miette", "nix 0.29.0", + "openshell-crypto", "openshell-extension-core", "openshell-otel", "openshell-policy-schema", @@ -4349,18 +4351,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 0.22.1", "futures", "openshell-core", + "openshell-crypto", "serde", "serde_json", - "sha2 0.10.9", "tempfile", "tokio", "toml", @@ -4422,6 +4441,7 @@ dependencies = [ "miette", "notify", "openshell-core", + "openshell-crypto", "openshell-isolation-interface", "openshell-otel", "openshell-otel-test-support", @@ -4456,6 +4476,7 @@ dependencies = [ "kube", "miette", "openshell-core", + "openshell-crypto", "serde", "sha2 0.10.9", "tokio", @@ -4536,6 +4557,7 @@ dependencies = [ "futures", "miette", "openshell-core", + "openshell-crypto", "rcgen", "reqwest 0.12.28", "rustls", @@ -4606,6 +4628,7 @@ version = "0.0.0" dependencies = [ "http 1.4.0", "hyper-util", + "openshell-crypto", "rcgen", "rustls", "serde", @@ -4879,6 +4902,7 @@ dependencies = [ "miette", "oauth2", "openshell-core", + "openshell-crypto", "reqwest 0.12.28", "rustls", "serde", @@ -4931,6 +4955,7 @@ dependencies = [ "notify", "openshell-bootstrap", "openshell-core", + "openshell-crypto", "openshell-driver-db-credstore", "openshell-driver-kubernetes-secrets", "openshell-driver-vault", @@ -5096,6 +5121,7 @@ dependencies = [ "noyalib", "openshell-binary-identity", "openshell-core", + "openshell-crypto", "openshell-driver-vm", "openshell-isolation-interface", "openshell-ocsf", diff --git a/Cargo.toml b/Cargo.toml index b37051dd89..8bbc3cfadd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -38,10 +38,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"] } +rcgen = { version = "0.13", default-features = false, features = ["crypto", "pem"] } webpki-roots = "1" rustls-native-certs = "0.8" @@ -109,7 +109,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" @@ -133,12 +133,12 @@ indexmap = "2" shell-words = "1.1.1" # 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/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 e615e73fa3..8fa9e75d56 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")?; // --- User client cert (CLI only; sandboxes use bearer identity) --- - 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 5c92eefe5b..e70ec7dace 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" } @@ -50,7 +51,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 5b379cbee9..1e7bfec4a9 100644 --- a/crates/openshell-cli/src/tls.rs +++ b/crates/openshell-cli/src/tls.rs @@ -285,7 +285,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 9659f4c69b..7c918b5e33 100644 --- a/crates/openshell-cli/tests/helpers/mod.rs +++ b/crates/openshell-cli/tests/helpers/mod.rs @@ -125,7 +125,7 @@ pub use environment::{Environment, FixtureDir as TempDir, fixture_dir as tempdir /// 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(); @@ -137,7 +137,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(); @@ -149,7 +149,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 93c4c4b0b2..db31f1bd82 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 51dc40a9f3..3b4bc5a120 100644 --- a/crates/openshell-core/src/oauth.rs +++ b/crates/openshell-core/src/oauth.rs @@ -52,7 +52,7 @@ impl TokenGrantClient { fn builder() -> reqwest::ClientBuilder { // A process may already have installed this provider. Installation is // idempotent for this caller and never relaxes peer authentication. - 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-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 9f28f4fcd5..1853c9b7e2 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 b2738e3602..2750c620b6 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 abbac2a9de..26ecd32b13 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 883e75d479..b80c23c146 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" } @@ -138,7 +139,7 @@ tokio = { workspace = true, features = ["test-util"] } openshell-providers = { path = "../openshell-providers", features = ["example-profiles"] } openshell-ocsf = { path = "../openshell-ocsf", features = ["test-support"] } 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 ed3ddaeca1..7f011e6e2f 100644 --- a/crates/openshell-server/src/auth/oidc.rs +++ b/crates/openshell-server/src/auth/oidc.rs @@ -15,8 +15,9 @@ use super::authenticator::{AuthRejection, Authentication, Authenticator, bearer_ 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}; @@ -577,7 +578,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()) @@ -1424,7 +1425,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 { @@ -1541,7 +1542,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()) @@ -1682,9 +1683,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}; @@ -1789,12 +1791,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, ), @@ -1820,7 +1822,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 2b4499183d..260a9a1d81 100644 --- a/crates/openshell-server/src/auth/sandbox_jwt.rs +++ b/crates/openshell-server/src/auth/sandbox_jwt.rs @@ -16,7 +16,8 @@ use super::authenticator::{AuthRejection, Authentication, Authenticator, bearer_ 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, EncodingKey, Header, decode_header, encode}; +use jsonwebtoken::{Algorithm, EncodingKey, Header, decode_header}; +use openshell_crypto::jwt::encode; pub use openshell_extension_core::{ EXTENSION_JWT_TYP, ExtensionAudience, ExtensionCallerKind, ExtensionJwtClaims, MAX_EXTENSION_TOKEN_TTL, diff --git a/crates/openshell-server/src/lib.rs b/crates/openshell-server/src/lib.rs index 06eed25352..44dfc4945c 100644 --- a/crates/openshell-server/src/lib.rs +++ b/crates/openshell-server/src/lib.rs @@ -86,7 +86,7 @@ use tracing::{debug, error, info, warn}; 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 2e24579450..e13dbcdea9 100644 --- a/crates/openshell-server/src/provider_refresh.rs +++ b/crates/openshell-server/src/provider_refresh.rs @@ -1904,7 +1904,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() @@ -2898,7 +2898,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 90372b9dad..e043ee4afa 100644 --- a/crates/openshell-server/src/tls.rs +++ b/crates/openshell-server/src/tls.rs @@ -16,7 +16,6 @@ use notify::{Event, RecursiveMode, Watcher}; use openshell_core::{Error, Result}; use openshell_ocsf::{ConfigStateChangeBuilder, EventContext, 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; @@ -314,7 +313,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))) } @@ -377,7 +376,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( @@ -487,7 +486,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"); @@ -900,7 +900,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"); @@ -914,7 +915,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 @@ -981,7 +983,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 @@ -1056,7 +1059,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 be52bdd7a2..fb2534595f 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; @@ -712,7 +712,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"); @@ -720,7 +720,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"); @@ -731,7 +732,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"); @@ -810,7 +812,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"); @@ -820,7 +823,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 ff0e3e7eb3..f9b7f3e47f 100644 --- a/crates/openshell-supervisor-network/Cargo.toml +++ b/crates/openshell-supervisor-network/Cargo.toml @@ -13,6 +13,7 @@ rust-version.workspace = true [dependencies] openshell-sandbox-backend = { path = "../openshell-sandbox-backend" } 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 aae99ba6c3..18e83daf6c 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/upstream_proxy.rs b/crates/openshell-supervisor-network/src/upstream_proxy.rs index 9b47a7ea31..39cdd8f8c0 100644 --- a/crates/openshell-supervisor-network/src/upstream_proxy.rs +++ b/crates/openshell-supervisor-network/src/upstream_proxy.rs @@ -2253,8 +2253,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 b5403e2ac3..8a5eab70b4 100644 --- a/e2e/rust/Cargo.lock +++ b/e2e/rust/Cargo.lock @@ -884,6 +884,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" @@ -899,6 +911,7 @@ dependencies = [ "jsonwebtoken", "nix", "noyalib", + "openshell-crypto", "prost", "rand", "rustls", @@ -1104,6 +1117,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" @@ -1915,6 +1941,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 c6ca7c4828..5cbfafc928 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 @@ -247,6 +247,7 @@ path = "tests/gpu.rs" required-features = ["e2e-gpu"] [dependencies] +openshell-crypto = { path = "../../crates/openshell-crypto" } base64 = "0.22" bollard = "0.20" bytes = "1" @@ -254,7 +255,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 a85c7747d0..39b40abae2 100644 --- a/e2e/rust/src/harness/container.rs +++ b/e2e/rust/src/harness/container.rs @@ -243,7 +243,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; @@ -446,7 +446,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; @@ -567,7 +567,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 5791729433..0d6ff621dd 100644 --- a/e2e/rust/src/harness/sandbox.rs +++ b/e2e/rust/src/harness/sandbox.rs @@ -43,7 +43,7 @@ fn extract_sandbox_name(output: &str) -> Option { /// In VM mode, the overlayfs snapshotter re-extracts image layers from the /// content store on every boot, so 600s accommodates cold image preparation, /// workspace initialization, and sandbox 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 16ac292fa4..0616180b81 100644 --- a/e2e/rust/tests/local_driver_token_restart.rs +++ b/e2e/rust/tests/local_driver_token_restart.rs @@ -317,7 +317,7 @@ async fn stop_container_sandbox( } run_engine(engine, &["stop".to_string(), workload_id.clone()])?; - wait_for_container_running(engine, &workload_id, false, Duration::from_secs(60)).await + wait_for_container_running(engine, &workload_id, false, Duration::from_mins(1)).await } async fn wait_for_sandbox_error(sandbox_name: &str, timeout: Duration) -> Result<(), String> { @@ -353,7 +353,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> { @@ -363,7 +363,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 } @@ -372,7 +372,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 59f6c11066..36906d8ada 100644 --- a/e2e/rust/tests/podman_corporate_proxy.rs +++ b/e2e/rust/tests/podman_corporate_proxy.rs @@ -552,7 +552,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. @@ -766,7 +766,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 2dee7c333e..907f9c71b4 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/provider_token_exchange.rs b/e2e/rust/tests/provider_token_exchange.rs index 7493a8fe89..9105be98bc 100644 --- a/e2e/rust/tests/provider_token_exchange.rs +++ b/e2e/rust/tests/provider_token_exchange.rs @@ -157,7 +157,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 4b6efae5f7..d914cb1c03 100644 --- a/e2e/rust/tests/vm_corporate_proxy.rs +++ b/e2e/rust/tests/vm_corporate_proxy.rs @@ -573,7 +573,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) } @@ -592,7 +592,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 a673129a47..128b946e33 100644 --- a/examples/governance-interceptor/Cargo.lock +++ b/examples/governance-interceptor/Cargo.lock @@ -1065,6 +1065,7 @@ dependencies = [ "ipnet", "miette", "nix", + "openshell-crypto", "openshell-extension-core", "openshell-policy-schema", "prost", @@ -1088,6 +1089,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" @@ -1107,6 +1121,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 23dbd5037b..260205bae6 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.53", 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 48116c73c4..4d1e9e489f 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 c90a6dd3dc..c48a70d91f 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.53" @@ -1119,6 +1225,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" @@ -1128,6 +1268,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" @@ -1154,6 +1303,7 @@ dependencies = [ "ipnet", "miette", "nix", + "openshell-crypto", "openshell-extension-core", "openshell-policy-schema", "prost", @@ -1165,7 +1315,7 @@ dependencies = [ "serde", "serde_json", "sha2", - "thiserror", + "thiserror 2.0.20", "tokio", "tokio-stream", "tonic", @@ -1177,13 +1327,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", @@ -1262,6 +1425,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" @@ -1328,6 +1501,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" @@ -1507,7 +1686,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]] @@ -1516,6 +1704,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" @@ -1564,7 +1766,7 @@ dependencies = [ "cfg-if", "getrandom 0.2.17", "libc", - "untrusted", + "untrusted 0.9.0", "windows-sys 0.52.0", ] @@ -1589,6 +1791,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" @@ -1656,7 +1867,7 @@ dependencies = [ "aws-lc-rs", "ring", "rustls-pki-types", - "untrusted", + "untrusted 0.9.0", ] [[package]] @@ -1799,6 +2010,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" @@ -1815,6 +2035,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" @@ -1904,6 +2136,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" @@ -1948,13 +2191,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]] @@ -1968,6 +2231,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" @@ -2227,6 +2520,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" @@ -2447,6 +2746,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" @@ -2467,7 +2793,7 @@ dependencies = [ "proc-macro2", "quote", "syn 3.0.5", - "synstructure", + "synstructure 0.14.0", ] [[package]] @@ -2488,7 +2814,7 @@ dependencies = [ "proc-macro2", "quote", "syn 3.0.5", - "synstructure", + "synstructure 0.14.0", ] [[package]] @@ -2496,6 +2822,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 7f896c570d..c784c3dcac 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 89f2061bc6..e4a264fe67 100644 --- a/tasks/rust.toml +++ b/tasks/rust.toml @@ -99,3 +99,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 0d478841cf8e43cb4c13452253c58437658a4133 Mon Sep 17 00:00:00 2001 From: Varsha Prasad Narsing Date: Tue, 15 Sep 2026 11:56:18 -0700 Subject: [PATCH 02/25] 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 36490b16a7..8e5407ce91 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4494,10 +4494,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 895d7c8d4c..f6a5a82dcf 100644 --- a/crates/openshell-driver-mxc/Cargo.toml +++ b/crates/openshell-driver-mxc/Cargo.toml @@ -37,6 +37,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" @@ -45,7 +46,6 @@ tempfile = "3" # 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 df4c3a5dba..df800d7aea 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 5ae44dfff9..b07bc0f537 100644 --- a/crates/openshell-supervisor-network/src/host.rs +++ b/crates/openshell-supervisor-network/src/host.rs @@ -315,7 +315,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 787532081b94a04b1b4687d951a7845108fee4f7 Mon Sep 17 00:00:00 2001 From: Varsha Prasad Narsing Date: Tue, 15 Sep 2026 12:25:57 -0700 Subject: [PATCH 03/25] fix(crypto): make backend boundary check portable Signed-off-by: Varsha Prasad Narsing --- tasks/rust.toml | 2 +- tasks/scripts/check-crypto-boundary.sh | 20 --------- tasks/scripts/check_crypto_boundary.py | 57 ++++++++++++++++++++++++++ 3 files changed, 58 insertions(+), 21 deletions(-) delete mode 100755 tasks/scripts/check-crypto-boundary.sh create mode 100644 tasks/scripts/check_crypto_boundary.py diff --git a/tasks/rust.toml b/tasks/rust.toml index e4a264fe67..961e75252e 100644 --- a/tasks/rust.toml +++ b/tasks/rust.toml @@ -102,5 +102,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 7a864ee7850e56b188053c71c3b29282a8da1aca Mon Sep 17 00:00:00 2001 From: Varsha Prasad Narsing Date: Tue, 15 Sep 2026 12:39:37 -0700 Subject: [PATCH 04/25] 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 e13dbcdea9..248e85b86d 100644 --- a/crates/openshell-server/src/provider_refresh.rs +++ b/crates/openshell-server/src/provider_refresh.rs @@ -1740,7 +1740,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 16d426292da2d591aa105d53b0eaf296de2da80f Mon Sep 17 00:00:00 2001 From: Varsha Prasad Narsing Date: Tue, 15 Sep 2026 15:36:20 -0700 Subject: [PATCH 05/25] refactor(crypto): propagate digest backend failures Signed-off-by: Varsha Prasad Narsing --- 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 ++-- 6 files changed, 83 insertions(+), 35 deletions(-) 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 dbaa68d898d1d3f674a3ea897772a2f0ae7bc13e Mon Sep 17 00:00:00 2001 From: Varsha Prasad Narsing Date: Tue, 15 Sep 2026 15:41:20 -0700 Subject: [PATCH 06/25] 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 2750c620b6..5e5bdb49eb 100644 --- a/crates/openshell-driver-vault/src/lib.rs +++ b/crates/openshell-driver-vault/src/lib.rs @@ -1053,14 +1053,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 3464624a44f490dad04603396274618838f049a1 Mon Sep 17 00:00:00 2001 From: Varsha Prasad Narsing Date: Wed, 16 Sep 2026 12:41:41 -0700 Subject: [PATCH 07/25] 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 8e5407ce91..d8dab62952 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4867,6 +4867,7 @@ dependencies = [ "hyper-util", "libc", "openshell-core", + "openshell-crypto", "openshell-isolation-interface", "prost", "prost-types", @@ -5034,6 +5035,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 8c41dfc5e8..903c95b3be 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; @@ -902,7 +901,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> { @@ -990,8 +989,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::*; @@ -1013,7 +1013,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( @@ -1214,7 +1215,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 d3bc1b27ec..abc788e158 100644 --- a/crates/openshell-driver-kubernetes/src/sandbox_runtime.rs +++ b/crates/openshell-driver-kubernetes/src/sandbox_runtime.rs @@ -17,7 +17,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, @@ -84,7 +84,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 1f5908662d..766c1ade9c 100644 --- a/crates/openshell-sandbox-backend/Cargo.toml +++ b/crates/openshell-sandbox-backend/Cargo.toml @@ -14,6 +14,7 @@ repository.workspace = true test-support = [] [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 4bbcaca879..60561b4778 100644 --- a/crates/openshell-sandbox-backend/src/boundary_protocol.rs +++ b/crates/openshell-sandbox-backend/src/boundary_protocol.rs @@ -27,7 +27,7 @@ use openshell_isolation_interface::contract::{ BackendDescriptor, BackendError, BinaryIdentity, BoundaryConfirmation, BoundaryExitStatus, BoundarySignal, ExecSpec, ExecutableIdentity, ProvisioningEvidence, ResolveError, ShellSpec, }; -use rcgen::{CertificateParams, DnType, ExtendedKeyUsagePurpose, IsCa, KeyPair, KeyUsagePurpose}; +use rcgen::{CertificateParams, DnType, ExtendedKeyUsagePurpose, IsCa, KeyUsagePurpose}; use serde::{Deserialize, Serialize}; use sha2::{Digest as _, Sha256}; use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt}; @@ -296,7 +296,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); @@ -310,9 +310,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 bcda27830c..8e049c6b6f 100644 --- a/crates/openshell-sandbox-backend/src/runtime.rs +++ b/crates/openshell-sandbox-backend/src/runtime.rs @@ -305,7 +305,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| { @@ -3152,7 +3152,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 69a6c8db56..6f2598083b 100644 --- a/crates/openshell-sandbox-backend/src/sandbox_auth.rs +++ b/crates/openshell-sandbox-backend/src/sandbox_auth.rs @@ -361,7 +361,7 @@ mod tests { SessionTokenProfile, SessionVerificationKey, }; use openshell_core::sandbox_generation::SandboxGenerationId; - use rcgen::{KeyPair, PKCS_ED25519}; + use rcgen::PKCS_ED25519; use super::*; @@ -380,7 +380,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 a0c3bf5bc5..e8318a516b 100644 --- a/crates/openshell-sandbox/src/boundary_server.rs +++ b/crates/openshell-sandbox/src/boundary_server.rs @@ -3608,7 +3608,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::, _>>()?; @@ -3852,7 +3852,7 @@ mod linux { }; use openshell_sandbox_backend::proto::{exchange_frame::Payload, mediate_frame}; use openshell_sandbox_backend::protobuf::WireMessage as _; - use rcgen::{KeyPair, PKCS_ED25519}; + use rcgen::PKCS_ED25519; struct FailedWaitProcess; @@ -3992,7 +3992,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(), @@ -4000,7 +4001,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 7f011e6e2f..165703769b 100644 --- a/crates/openshell-server/src/auth/oidc.rs +++ b/crates/openshell-server/src/auth/oidc.rs @@ -1045,22 +1045,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 18e83daf6c..017f06367e 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 84865bbd03..06b12efe2b 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", "trace-context"] } 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 081526eddd..7e98eb3e94 100644 --- a/crates/openshell-supervisor/src/main.rs +++ b/crates/openshell-supervisor/src/main.rs @@ -355,7 +355,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); }); @@ -419,7 +419,7 @@ fn main() -> Result<()> { let ocsf_layer = ocsf_export.as_ref().map(openshell_otel::OcsfOtlp::layer); 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 8a5eab70b4..5538d67fea 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.53" @@ -878,6 +959,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" @@ -893,7 +983,7 @@ dependencies = [ "rcgen", "rustls", "serde", - "thiserror", + "thiserror 2.0.19", ] [[package]] @@ -1127,6 +1217,7 @@ dependencies = [ "pem", "rustls-pki-types", "time", + "x509-parser", "yasna", ] @@ -1159,6 +1250,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" @@ -1381,7 +1481,7 @@ checksum = "0d585997b0ac10be3c5ee635f1bab02d512760d14b7c468801ac8a01d9ae5f1d" dependencies = [ "num-bigint", "num-traits", - "thiserror", + "thiserror 2.0.19", "time", ] @@ -1471,13 +1571,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]] @@ -1941,6 +2061,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 128b946e33..04d9356428 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.53" @@ -1045,6 +1120,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" @@ -1077,7 +1161,7 @@ dependencies = [ "serde", "serde_json", "sha2", - "thiserror", + "thiserror 2.0.20", "tokio", "tokio-stream", "tonic", @@ -1098,7 +1182,7 @@ dependencies = [ "rcgen", "rustls", "serde", - "thiserror", + "thiserror 2.0.20", "tonic", ] @@ -1108,7 +1192,7 @@ version = "0.0.0" dependencies = [ "hyper-util", "serde", - "thiserror", + "thiserror 2.0.20", "tokio", "tonic", "tower", @@ -1171,7 +1255,7 @@ dependencies = [ "prost-types", "serde", "serde_json", - "thiserror", + "thiserror 2.0.20", "url", ] @@ -1519,6 +1603,7 @@ dependencies = [ "pem", "rustls-pki-types", "time", + "x509-parser", "yasna", ] @@ -1595,6 +1680,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" @@ -1848,7 +1942,7 @@ checksum = "0d585997b0ac10be3c5ee635f1bab02d512760d14b7c468801ac8a01d9ae5f1d" dependencies = [ "num-bigint", "num-traits", - "thiserror", + "thiserror 2.0.20", "time", ] @@ -1979,13 +2073,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]] @@ -2522,6 +2636,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 f68d190e60a80cb5a19ab2ba7fba4f13c6136ec7 Mon Sep 17 00:00:00 2001 From: Varsha Prasad Narsing Date: Wed, 16 Sep 2026 15:41:16 -0700 Subject: [PATCH 08/25] fix(crypto): declare sandbox dependency and remove boundary lint Signed-off-by: Varsha Prasad Narsing --- Cargo.lock | 1 + 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 -------------------------- 6 files changed, 4 insertions(+), 67 deletions(-) delete mode 100644 tasks/scripts/check_crypto_boundary.py diff --git a/Cargo.lock b/Cargo.lock index d8dab62952..24b806202d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4833,6 +4833,7 @@ dependencies = [ "nix 0.29.0", "openshell-binary-identity", "openshell-core", + "openshell-crypto", "openshell-isolation-interface", "openshell-ocsf", "openshell-policy", 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 88bce43fab..a4385a6af4 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 c784c3dcac..7f896c570d 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 961e75252e..89f2061bc6 100644 --- a/tasks/rust.toml +++ b/tasks/rust.toml @@ -99,8 +99,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 a59f9c8912c97295ed3ccb81353cb0ec7b4c02b6 Mon Sep 17 00:00:00 2001 From: Varsha Prasad Narsing Date: Fri, 18 Sep 2026 15:01:37 -0700 Subject: [PATCH 09/25] refactor(crypto): support independent backends and backend-free CA import Signed-off-by: Varsha Prasad Narsing --- Cargo.lock | 128 +- Cargo.toml | 4 +- 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 | 6 +- .../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 | 1428 ++++++++++++++++- examples/governance-interceptor/Cargo.lock | 1295 ++++++++++++++- examples/governance-interceptor/Cargo.toml | 2 - examples/governance-interceptor/src/main.rs | 13 +- .../governance-interceptor/src/policy_hash.rs | 48 +- .../Cargo.lock | 1300 ++++++++++++++- tasks/test.toml | 2 + 62 files changed, 5247 insertions(+), 512 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 24b806202d..4a5166f565 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -194,7 +194,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", @@ -204,6 +204,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" @@ -216,6 +232,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" @@ -794,7 +822,7 @@ version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" dependencies = [ - "bit-vec", + "bit-vec 0.6.3", ] [[package]] @@ -803,6 +831,15 @@ version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" +[[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" @@ -1665,7 +1702,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 0.4.6", + "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 0.4.6", @@ -3333,7 +3384,7 @@ dependencies = [ "js-sys", "p256 0.13.2", "p384 0.13.1", - "pem", + "pem 3.0.6", "rand 0.8.6", "rsa 0.9.10", "serde", @@ -3458,7 +3509,7 @@ dependencies = [ "jsonpath-rust", "k8s-openapi", "kube-core", - "pem", + "pem 3.0.6", "rustls", "secrecy", "serde", @@ -4186,7 +4237,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]] @@ -4220,8 +4280,8 @@ checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" name = "openshell-binary-identity" version = "0.0.0" dependencies = [ + "openshell-crypto", "openshell-isolation-interface", - "sha2 0.10.9", ] [[package]] @@ -4238,7 +4298,7 @@ dependencies = [ "tempfile", "tokio", "tracing", - "x509-parser", + "x509-parser 0.16.0", ] [[package]] @@ -4360,6 +4420,7 @@ dependencies = [ "jsonwebtoken", "k8s-openapi", "kube", + "pem 3.0.6", "rcgen", "rustls", "serde", @@ -4367,6 +4428,7 @@ dependencies = [ "sqlx", "thiserror 2.0.18", "tonic", + "x509-parser 0.18.1", ] [[package]] @@ -5015,7 +5077,7 @@ dependencies = [ "url", "uuid", "wiremock", - "x509-parser", + "x509-parser 0.16.0", ] [[package]] @@ -5514,6 +5576,16 @@ dependencies = [ "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", +] + [[package]] name = "pem-rfc7468" version = "0.7.0" @@ -6359,15 +6431,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", ] @@ -9530,18 +9602,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" @@ -9566,10 +9655,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 0.9.1", "time", ] diff --git a/Cargo.toml b/Cargo.toml index 8bbc3cfadd..905065d843 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"] } @@ -41,7 +43,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"] } +rcgen = { version = "0.14.10", default-features = false, features = ["pem"] } webpki-roots = "1" rustls-native-certs = "0.8" 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 3b42e99b21..091ecb3dc8 100644 --- a/crates/openshell-binary-identity/src/lib.rs +++ b/crates/openshell-binary-identity/src/lib.rs @@ -364,11 +364,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 @@ -377,9 +377,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 8fa9e75d56..4ade3465f5 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 e70ec7dace..8338cf5762 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 1e7bfec4a9..f96cbe01f4 100644 --- a/crates/openshell-cli/src/tls.rs +++ b/crates/openshell-cli/src/tls.rs @@ -216,7 +216,7 @@ pub fn build_rustls_config(materials: &TlsMaterials) -> Result Vec { - openshell_crypto::tls::provider() + openshell_crypto::tls::configuration_provider() .signature_verification_algorithms .supported_schemes() } @@ -325,7 +325,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 7c918b5e33..be84c9ce6e 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}; #[path = "../../../../tests/support/environment.rs"] mod environment; @@ -128,7 +128,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) } @@ -140,8 +140,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`. @@ -152,6 +152,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 db31f1bd82..d03aafee99 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 14a1500cd5..bb2261708d 100644 --- a/crates/openshell-core/src/driver_utils.rs +++ b/crates/openshell-core/src/driver_utils.rs @@ -1251,8 +1251,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 903c95b3be..d360acabe1 100644 --- a/crates/openshell-core/src/jwt.rs +++ b/crates/openshell-core/src/jwt.rs @@ -1018,7 +1018,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", Some(DEFAULT_SESSION_TOKEN_TTL), @@ -1246,7 +1246,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 1853c9b7e2..6f6857f29c 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 abc788e158..fa35636b20 100644 --- a/crates/openshell-driver-kubernetes/src/sandbox_runtime.rs +++ b/crates/openshell-driver-kubernetes/src/sandbox_runtime.rs @@ -95,12 +95,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 f6a5a82dcf..9855e48478 100644 --- a/crates/openshell-driver-mxc/Cargo.toml +++ b/crates/openshell-driver-mxc/Cargo.toml @@ -37,7 +37,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 5e5bdb49eb..cdfafc3ce1 100644 --- a/crates/openshell-driver-vault/src/lib.rs +++ b/crates/openshell-driver-vault/src/lib.rs @@ -985,11 +985,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}; @@ -1050,26 +1051,30 @@ mod tests { ); } - 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 766c1ade9c..fd2c486288 100644 --- a/crates/openshell-sandbox-backend/Cargo.toml +++ b/crates/openshell-sandbox-backend/Cargo.toml @@ -14,7 +14,7 @@ repository.workspace = true test-support = [] [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 60561b4778..9051b8dc7a 100644 --- a/crates/openshell-sandbox-backend/src/boundary_protocol.rs +++ b/crates/openshell-sandbox-backend/src/boundary_protocol.rs @@ -306,7 +306,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}")) })?; @@ -322,8 +322,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}")) })?; @@ -332,7 +331,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 8e049c6b6f..906d8f20d9 100644 --- a/crates/openshell-sandbox-backend/src/runtime.rs +++ b/crates/openshell-sandbox-backend/src/runtime.rs @@ -323,7 +323,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", Some(DEFAULT_SESSION_TOKEN_TTL), diff --git a/crates/openshell-sandbox/Cargo.toml b/crates/openshell-sandbox/Cargo.toml index a4385a6af4..78414b267a 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 e8318a516b..fe290b7f1c 100644 --- a/crates/openshell-sandbox/src/boundary_server.rs +++ b/crates/openshell-sandbox/src/boundary_server.rs @@ -3626,11 +3626,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)?; @@ -4008,7 +4009,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", Some(DEFAULT_SESSION_TOKEN_TTL), @@ -4136,7 +4137,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 26ecd32b13..6c4d0523b4 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 b80c23c146..b5abaab0bf 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 165703769b..08f22d4b57 100644 --- a/crates/openshell-server/src/auth/oidc.rs +++ b/crates/openshell-server/src/auth/oidc.rs @@ -1052,23 +1052,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)); @@ -1803,7 +1803,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", @@ -1824,7 +1824,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 cba890bff2..817a6a02ad 100644 --- a/crates/openshell-server/src/config_file.rs +++ b/crates/openshell-server/src/config_file.rs @@ -1438,8 +1438,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() @@ -1542,14 +1543,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 e043ee4afa..26bcb713ce 100644 --- a/crates/openshell-server/src/tls.rs +++ b/crates/openshell-server/src/tls.rs @@ -396,7 +396,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 { @@ -405,7 +408,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 { @@ -414,7 +417,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 { @@ -478,22 +481,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 { @@ -505,7 +517,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(), ) @@ -902,8 +914,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"); @@ -926,17 +937,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"); @@ -946,7 +960,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"), @@ -994,16 +1008,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"); @@ -1013,7 +1034,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"), @@ -1050,7 +1071,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, @@ -1060,11 +1081,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 fb2534595f..4d41124c01 100644 --- a/crates/openshell-server/tests/common/mod.rs +++ b/crates/openshell-server/tests/common/mod.rs @@ -713,18 +713,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 = @@ -734,9 +733,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]| { @@ -748,16 +747,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) @@ -814,8 +819,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 = @@ -825,13 +829,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 f9b7f3e47f..6ac1239573 100644 --- a/crates/openshell-supervisor-network/Cargo.toml +++ b/crates/openshell-supervisor-network/Cargo.toml @@ -12,8 +12,9 @@ rust-version.workspace = true [dependencies] openshell-sandbox-backend = { path = "../openshell-sandbox-backend" } +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" } @@ -38,7 +39,7 @@ hickory-proto = "0.26.1" ipnet = "2" miette = { workspace = true } prost-types = { workspace = true } -rcgen = { workspace = true, features = ["x509-parser"] } +rcgen = { workspace = true } regorus = { version = "0.9", default-features = false, features = ["std", "arc", "glob", "yaml"] } reqwest = { workspace = true } rustls = { workspace = true } @@ -48,7 +49,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 017f06367e..6539b1061a 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()]; @@ -770,18 +767,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 839b5de2f5..000bbaa6bd 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 39cdd8f8c0..dd0360f7a9 100644 --- a/crates/openshell-supervisor-network/src/upstream_proxy.rs +++ b/crates/openshell-supervisor-network/src/upstream_proxy.rs @@ -2255,17 +2255,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 06b12efe2b..9e2e0ea8ad 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", "trace-context"] } openshell-extension-core = { path = "../openshell-extension-core" } openshell-isolation-interface = { path = "../openshell-isolation-interface" } diff --git a/deny.toml b/deny.toml index 38f350bf93..16be75953e 100644 --- a/deny.toml +++ b/deny.toml @@ -63,7 +63,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 5538d67fea..7df58aab90 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" @@ -567,14 +1085,33 @@ dependencies = [ "futures-core", "h2", "http", - "http-body", - "httparse", - "httpdate", - "itoa", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "smallvec", + "tokio", + "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", - "smallvec", "tokio", - "want", + "tokio-rustls", + "tower-service", ] [[package]] @@ -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.53" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "962838abbd8dd2cd3844d2208dc502458bba6985f8bf1dc21761b30260fcbd7f" dependencies = [ - "hashbrown", + "hashbrown 0.17.1", "indexmap", "libm", "memchr", @@ -961,9 +1700,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", ] @@ -979,18 +1718,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", @@ -1003,14 +1748,14 @@ dependencies = [ "noyalib", "openshell-crypto", "prost", - "rand", + "rand 0.9.5", "rustls", "rustls-pemfile", "serde", "serde_json", "serial_test", - "sha1", - "sha2", + "sha1 0.10.7", + "sha2 0.10.9", "tempfile", "tokio", "tokio-rustls", @@ -1021,6 +1766,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" @@ -1050,7 +1816,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", ] @@ -1060,6 +1836,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" @@ -1179,6 +1997,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" @@ -1207,14 +2036,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", @@ -1230,6 +2065,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" @@ -1287,6 +2151,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-pemfile" version = "2.2.0" @@ -1306,34 +2182,99 @@ dependencies = [ ] [[package]] -name = "rustls-webpki" -version = "0.103.15" +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]] +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 = "f3c3cf1d8b1e7d4927e2d154c3fcb02979afb9939629c62cd9048d4f07b60ac2" +checksum = "e891af845473308773346dc847b2c23ee78fe442e0472ac50e22a18a93d3ae5a" dependencies = [ - "aws-lc-rs", - "ring", - "rustls-pki-types", - "untrusted 0.9.0", + "zeroize", ] [[package]] -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" +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" @@ -1345,6 +2286,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" @@ -1365,6 +2316,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" @@ -1401,6 +2363,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" @@ -1433,8 +2408,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]] @@ -1444,8 +2430,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]] @@ -1481,7 +2478,7 @@ checksum = "0d585997b0ac10be3c5ee635f1bab02d512760d14b7c468801ac8a01d9ae5f1d" dependencies = [ "num-bigint", "num-traits", - "thiserror 2.0.19", + "thiserror", "time", ] @@ -1496,6 +2493,9 @@ name = "smallvec" version = "1.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ed6a63f02c8539c91a8685a86f4099661ba3da017932f6ebbea6de3f0fa7c90" +dependencies = [ + "serde", +] [[package]] name = "socket2" @@ -1507,12 +2507,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" @@ -1571,33 +2769,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]] @@ -1651,6 +2829,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" @@ -1711,6 +2895,7 @@ dependencies = [ "futures-sink", "libc", "pin-project-lite", + "slab", "tokio", ] @@ -1722,7 +2907,7 @@ checksum = "ac2a5518c70fa84342385732db33fb3f44bc4cc748936eb5833d2df34d6445ef" dependencies = [ "async-trait", "axum", - "base64", + "base64 0.22.1", "bytes", "h2", "http", @@ -1736,6 +2921,7 @@ dependencies = [ "socket2", "sync_wrapper", "tokio", + "tokio-rustls", "tokio-stream", "tower", "tower-layer", @@ -1773,6 +2959,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" @@ -1791,6 +2995,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", @@ -1828,12 +3033,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" @@ -1864,6 +3102,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" @@ -1939,6 +3183,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" @@ -2063,28 +3322,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 04d9356428..d37416762d 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" @@ -549,16 +942,62 @@ dependencies = [ name = "hashbrown" version = "0.15.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +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 = [ - "foldhash", + "base64 0.22.1", + "bytes", + "headers-core", + "http", + "httpdate", + "mime", + "sha1 0.10.7", ] [[package]] -name = "hashbrown" -version = "0.17.1" +name = "headers-core" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" +checksum = "54b4a22553d4242c49fddb9ba998a99962b5cc6f22cb5a3482bec22522403ce4" +dependencies = [ + "http", +] [[package]] name = "heck" @@ -566,6 +1005,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.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" @@ -1122,9 +1835,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", ] @@ -1144,7 +1857,7 @@ name = "openshell-core" version = "0.0.0" dependencies = [ "async-trait", - "base64", + "base64 0.22.1", "glob", "ipnet", "miette", @@ -1160,8 +1873,8 @@ dependencies = [ "rustls-pemfile", "serde", "serde_json", - "sha2", - "thiserror 2.0.20", + "sha2 0.10.9", + "thiserror", "tokio", "tokio-stream", "tonic", @@ -1178,12 +1891,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]] @@ -1192,7 +1910,7 @@ version = "0.0.0" dependencies = [ "hyper-util", "serde", - "thiserror 2.0.20", + "thiserror", "tokio", "tonic", "tower", @@ -1211,10 +1929,8 @@ dependencies = [ "prost", "prost-reflect", "prost-types", - "rcgen", "serde", "serde_json", - "sha2", "tokio", "tonic", ] @@ -1255,7 +1971,7 @@ dependencies = [ "prost-types", "serde", "serde_json", - "thiserror 2.0.20", + "thiserror", "url", ] @@ -1280,6 +1996,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" @@ -1309,7 +2031,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", ] @@ -1319,6 +2051,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" @@ -1452,7 +2226,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", @@ -1561,6 +2335,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" @@ -1595,12 +2375,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", @@ -1765,6 +2545,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" @@ -1783,12 +2569,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" @@ -1858,6 +2677,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" @@ -1882,6 +2712,41 @@ dependencies = [ "serde_core", ] +[[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" @@ -1890,7 +2755,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]] @@ -1942,7 +2818,7 @@ checksum = "0d585997b0ac10be3c5ee635f1bab02d512760d14b7c468801ac8a01d9ae5f1d" dependencies = [ "num-bigint", "num-traits", - "thiserror 2.0.20", + "thiserror", "time", ] @@ -1957,6 +2833,9 @@ name = "smallvec" version = "1.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba467056f1b547ed52077911161fc86985becbc60e8e1857c8a144dab0def891" +dependencies = [ + "serde", +] [[package]] name = "socket2" @@ -1968,12 +2847,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" @@ -2073,33 +3150,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]] @@ -2228,6 +3285,7 @@ dependencies = [ "futures-sink", "libc", "pin-project-lite", + "slab", "tokio", ] @@ -2239,7 +3297,7 @@ checksum = "ac2a5518c70fa84342385732db33fb3f44bc4cc748936eb5833d2df34d6445ef" dependencies = [ "async-trait", "axum", - "base64", + "base64 0.22.1", "bytes", "h2", "http", @@ -2331,6 +3389,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" @@ -2349,6 +3425,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", @@ -2386,12 +3463,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" @@ -2404,6 +3493,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" @@ -2416,6 +3520,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" @@ -2457,6 +3567,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" @@ -2488,6 +3604,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" @@ -2533,6 +3658,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" @@ -2630,6 +3770,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" @@ -2638,28 +3784,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", ] @@ -2686,6 +3833,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 260205bae6..a2ab52ef99 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.53", 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 4d1e9e489f..2d670f82cf 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, @@ -1057,9 +1058,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 c48a70d91f..8aa96a3a9b 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" @@ -647,7 +1040,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]] @@ -656,12 +1062,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.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" @@ -1270,9 +1983,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", ] @@ -1298,7 +2011,7 @@ name = "openshell-core" version = "0.0.0" dependencies = [ "async-trait", - "base64", + "base64 0.22.1", "glob", "ipnet", "miette", @@ -1314,8 +2027,8 @@ dependencies = [ "rustls-pemfile", "serde", "serde_json", - "sha2", - "thiserror 2.0.20", + "sha2 0.10.9", + "thiserror", "tokio", "tokio-stream", "tonic", @@ -1332,12 +2045,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]] @@ -1346,7 +2064,7 @@ version = "0.0.0" dependencies = [ "hyper-util", "serde", - "thiserror 2.0.20", + "thiserror", "tokio", "tonic", "tower", @@ -1396,12 +2114,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" @@ -1431,7 +2164,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", ] @@ -1441,6 +2184,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" @@ -1672,6 +2457,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" @@ -1706,12 +2497,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", @@ -1876,6 +2667,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" @@ -1894,12 +2691,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" @@ -1933,10 +2763,20 @@ checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" name = "serde" version = "1.0.229" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba" +checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde-value" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3a1a3341211875ef120e117ea7fd5228530ae7e7036a779fdc9117be6b3282c" dependencies = [ - "serde_core", - "serde_derive", + "ordered-float", + "serde", ] [[package]] @@ -1959,6 +2799,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" @@ -1983,6 +2834,41 @@ dependencies = [ "serde_core", ] +[[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" @@ -1991,7 +2877,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]] @@ -2043,7 +2940,7 @@ checksum = "0d585997b0ac10be3c5ee635f1bab02d512760d14b7c468801ac8a01d9ae5f1d" dependencies = [ "num-bigint", "num-traits", - "thiserror 2.0.20", + "thiserror", "time", ] @@ -2058,6 +2955,9 @@ name = "smallvec" version = "1.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba467056f1b547ed52077911161fc86985becbc60e8e1857c8a144dab0def891" +dependencies = [ + "serde", +] [[package]] name = "socket2" @@ -2069,12 +2969,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" @@ -2191,33 +3283,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]] @@ -2338,6 +3410,7 @@ dependencies = [ "futures-sink", "libc", "pin-project-lite", + "slab", "tokio", ] @@ -2349,7 +3422,7 @@ checksum = "ac2a5518c70fa84342385732db33fb3f44bc4cc748936eb5833d2df34d6445ef" dependencies = [ "async-trait", "axum", - "base64", + "base64 0.22.1", "bytes", "h2", "http", @@ -2441,6 +3514,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" @@ -2459,6 +3550,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", @@ -2496,18 +3588,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" @@ -2520,6 +3639,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" @@ -2567,6 +3692,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" @@ -2598,6 +3729,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" @@ -2643,6 +3783,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" @@ -2740,6 +3895,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" @@ -2748,28 +3909,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", ] @@ -2796,6 +3958,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 79b246320c..95e049d9ab 100644 --- a/tasks/test.toml +++ b/tasks/test.toml @@ -112,6 +112,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 a046428ed52cf2732f5ac62732f02277cffb894d Mon Sep 17 00:00:00 2001 From: Varsha Prasad Narsing Date: Fri, 18 Sep 2026 15:07:54 -0700 Subject: [PATCH 10/25] chore(crypto): refresh feature suite lockfile after rebase Signed-off-by: Varsha Prasad Narsing --- tests/suites/features/Cargo.lock | 1587 ++++++++++++++++++++++++++++-- 1 file changed, 1521 insertions(+), 66 deletions(-) diff --git a/tests/suites/features/Cargo.lock b/tests/suites/features/Cargo.lock index b92ccd05f5..31876064b5 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" @@ -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" @@ -281,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" @@ -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" @@ -664,81 +1294,245 @@ dependencies = [ ] [[package]] -name = "idna_adapter" -version = "1.2.2" +name = "idna_adapter" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb68373c0d6620ef8105e855e7745e18b0d00d3bdb07fb532e434244cdb9a714" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "indexmap" +version = "2.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc4e190f5d26ca7051642629da2c52fc03bde85a03197c99408dcd291734c855" +dependencies = [ + "equivalent", + "hashbrown 0.17.1", + "serde", + "serde_core", +] + +[[package]] +name = "itertools" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + +[[package]] +name = "jobserver" +version = "0.1.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c00acbd29eabad4a2392fa0e921c874934dbbf4194312ad20f04a0ed67a3cb3" +dependencies = [ + "getrandom 0.4.3", + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.105" +source = "registry+https://github.com/rust-lang/crates.io-index" +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 = "cb68373c0d6620ef8105e855e7745e18b0d00d3bdb07fb532e434244cdb9a714" +checksum = "eba32bfb4ffdeaca3e34431072faf01745c9b26d25504aa7a6cf5684334fc4fc" dependencies = [ - "icu_normalizer", - "icu_properties", + "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 = "indexmap" -version = "2.14.2" +name = "k8s-openapi" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc4e190f5d26ca7051642629da2c52fc03bde85a03197c99408dcd291734c855" +checksum = "2c75b990324f09bef15e791606b7b7a296d02fc88a344f6eba9390970a870ad5" dependencies = [ - "equivalent", - "hashbrown", + "base64 0.22.1", + "chrono", "serde", - "serde_core", + "serde-value", + "serde_json", ] [[package]] -name = "itertools" -version = "0.14.0" +name = "kube" +version = "0.99.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +checksum = "9a4eb20010536b48abe97fec37d23d43069bcbe9686adcf9932202327bc5ca6e" dependencies = [ - "either", + "k8s-openapi", + "kube-client", + "kube-core", + "kube-derive", + "kube-runtime", ] [[package]] -name = "itoa" -version = "1.0.18" +name = "kube-client" +version = "0.99.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" +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 = "jobserver" -version = "0.1.35" +name = "kube-core" +version = "0.99.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c00acbd29eabad4a2392fa0e921c874934dbbf4194312ad20f04a0ed67a3cb3" +checksum = "ff0d0793db58e70ca6d689489183816cb3aa481673e7433dc618cf7e8007c675" dependencies = [ - "getrandom 0.4.3", - "libc", + "chrono", + "form_urlencoded", + "http", + "json-patch", + "k8s-openapi", + "schemars", + "serde", + "serde-value", + "serde_json", + "thiserror", ] [[package]] -name = "js-sys" -version = "0.3.105" +name = "kube-derive" +version = "0.99.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce57d20d1ea864ce2ac172ab472d409214f4fd359f0b2a2775abdf522e2af99e" +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" @@ -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.53" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "962838abbd8dd2cd3844d2208dc502458bba6985f8bf1dc21761b30260fcbd7f" dependencies = [ - "hashbrown", + "hashbrown 0.17.1", "indexmap", "libm", "memchr", @@ -868,6 +1699,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" @@ -878,18 +1718,36 @@ checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" name = "openshell-conformance" version = "0.0.0" dependencies = [ - "rand", + "rand 0.9.5", "serde", "serde_json", "tempfile", "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,14 +1758,15 @@ dependencies = [ "jsonwebtoken", "nix", "noyalib", + "openshell-crypto", "prost", - "rand", + "rand 0.9.5", "rustls", "rustls-pemfile", "serde", "serde_json", - "sha1", - "sha2", + "sha1 0.10.7", + "sha2 0.10.9", "tempfile", "tokio", "tokio-rustls", @@ -939,6 +1798,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" @@ -968,7 +1848,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", ] @@ -978,6 +1868,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" @@ -1097,6 +2029,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" @@ -1125,6 +2068,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" @@ -1134,6 +2097,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" @@ -1154,6 +2146,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.5" @@ -1191,6 +2192,18 @@ dependencies = [ "rustls-pki-types", ] +[[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" @@ -1213,22 +2226,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" @@ -1240,6 +2318,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" @@ -1260,6 +2348,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" @@ -1296,6 +2395,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 = "sha1" version = "0.10.7" @@ -1303,8 +2415,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]] @@ -1314,8 +2437,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]] @@ -1366,6 +2500,9 @@ name = "smallvec" version = "1.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba467056f1b547ed52077911161fc86985becbc60e8e1857c8a144dab0def891" +dependencies = [ + "serde", +] [[package]] name = "socket2" @@ -1377,12 +2514,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" @@ -1417,6 +2752,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" @@ -1501,6 +2847,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" @@ -1561,6 +2913,7 @@ dependencies = [ "futures-sink", "libc", "pin-project-lite", + "slab", "tokio", ] @@ -1572,7 +2925,7 @@ checksum = "ac2a5518c70fa84342385732db33fb3f44bc4cc748936eb5833d2df34d6445ef" dependencies = [ "async-trait", "axum", - "base64", + "base64 0.22.1", "bytes", "h2", "http", @@ -1586,6 +2939,7 @@ dependencies = [ "socket2", "sync_wrapper", "tokio", + "tokio-rustls", "tokio-stream", "tower", "tower-layer", @@ -1623,6 +2977,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" @@ -1641,6 +3013,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", @@ -1678,12 +3051,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" @@ -1714,6 +3120,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" @@ -1789,6 +3201,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" @@ -1911,6 +3338,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" @@ -1931,7 +3386,7 @@ dependencies = [ "proc-macro2", "quote", "syn 3.0.5", - "synstructure", + "synstructure 0.14.0", ] [[package]] @@ -1972,7 +3427,7 @@ dependencies = [ "proc-macro2", "quote", "syn 3.0.5", - "synstructure", + "synstructure 0.14.0", ] [[package]] From d31b690ff84f087f65475a8810788fe80606c383 Mon Sep 17 00:00:00 2001 From: Varsha Prasad Narsing Date: Tue, 22 Sep 2026 21:09:46 -0700 Subject: [PATCH 11/25] fix(crypto): route runtime integrity and entropy through backend Signed-off-by: Varsha Prasad Narsing --- Cargo.lock | 5 +- crates/openshell-crypto/README.md | 24 ++++ crates/openshell-driver-kubernetes/Cargo.toml | 1 - .../openshell-driver-kubernetes/src/driver.rs | 11 +- crates/openshell-driver-vm/Cargo.toml | 4 +- crates/openshell-driver-vm/src/driver.rs | 12 +- crates/openshell-sandbox-backend/Cargo.toml | 1 - .../src/boundary_protocol.rs | 17 ++- .../openshell-sandbox-backend/src/runtime.rs | 4 +- .../tests/crypto_dispatch.rs | 107 ++++++++++++++++++ .../openshell-server/src/auth/sandbox_jwt.rs | 4 +- .../src/auth/sandbox_session.rs | 83 +++++++++----- .../src/compute/rootfs_tar.rs | 11 +- crates/openshell-server/src/grpc/auth_rpc.rs | 25 ++-- 14 files changed, 242 insertions(+), 67 deletions(-) create mode 100644 crates/openshell-sandbox-backend/tests/crypto_dispatch.rs diff --git a/Cargo.lock b/Cargo.lock index 4a5166f565..9cc957ed7d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4513,7 +4513,6 @@ dependencies = [ "opentelemetry_sdk", "prost", "prost-types", - "rand 0.9.4", "rcgen", "serde", "serde_json", @@ -4653,6 +4652,7 @@ dependencies = [ "nix 0.29.0", "oci-client", "openshell-core", + "openshell-crypto", "openshell-driver-podman", "openshell-isolation-interface", "openshell-otel", @@ -4665,7 +4665,6 @@ dependencies = [ "polling", "prost", "prost-types", - "rand 0.9.4", "rustix 1.1.4", "serde", "serde_json", @@ -4928,6 +4927,7 @@ dependencies = [ "async-trait", "bytes", "hyper-util", + "jsonwebtoken", "libc", "openshell-core", "openshell-crypto", @@ -4940,7 +4940,6 @@ dependencies = [ "rustls-pemfile", "serde", "serde_json", - "sha2 0.10.9", "socket2", "thiserror 2.0.20", "tokio", diff --git a/crates/openshell-crypto/README.md b/crates/openshell-crypto/README.md index b2a70f0d9e..dfacc37851 100644 --- a/crates/openshell-crypto/README.md +++ b/crates/openshell-crypto/README.md @@ -111,6 +111,30 @@ 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. +Runtime refresh replay hashes and derived token IDs, bearer-cache fingerprints, +Sandbox Protocol request digests and request-ID entropy, Kubernetes/VM runtime +fence entropy, and rootfs staging-token entropy use the selected backend. +These operations retain SHA-256, UUID v4 encoding where applicable, and existing +hex encodings. Backend failures propagate; callers must not substitute another +implementation or continue with a placeholder identity. + +The remaining first-party uses require explicit classification; the facade is +not a whole-application crypto coverage claim: + +| Remaining use | Current scope and follow-up | +| --- | --- | +| VM image/archive digest verification and cached supervisor validation (`openshell-driver-vm`) | Security-relevant artifact integrity remains outside this runtime credential migration. Moving it requires covering the streaming readers, embedded-artifact cache, and build-time digest generation together; it must be addressed before claiming exclusive backend ownership. | +| UUID generation outside Sandbox Protocol request envelopes | Includes runtime identities, authentication nonces, and session identifiers as well as ordinary correlation IDs. These still use the UUID library's entropy source. They are not attested by context posture; a follow-up must classify each use and propagate entropy failure through currently infallible constructors. | +| DNS policy contract fingerprints (`openshell-supervisor-network::policy_dns`) | These bind cached DNS state to policy and are security-relevant. They remain outside this migration; migrating the cache identity API and its failure handling is required for exclusive backend ownership. | +| Credential-storage names (`credentials`, Kubernetes Secrets, Vault) | Deterministic namespace derivation, not encryption or proof of authorization. These retain their current hashing implementation and stored names; backend coverage is not asserted for them. | +| Endpoint IDs and pagination fingerprints | Deterministic identification/request matching, not authentication. These remain outside the selected-backend contract. | +| Debug token fingerprints | Diagnostic display only; direct hashing remains outside the contract even though the input is a credential. | +| Schema compatibility tests, content-cache identities, retry jitter, test fixtures | Non-authentication uses remain unchanged. | + +Cargo feature selection does not prevent a crate from adding another crypto +dependency. Review first-party security-sensitive operations against this scope; +no source-scanning boundary lint is installed. + 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 diff --git a/crates/openshell-driver-kubernetes/Cargo.toml b/crates/openshell-driver-kubernetes/Cargo.toml index 6f6857f29c..9da035039c 100644 --- a/crates/openshell-driver-kubernetes/Cargo.toml +++ b/crates/openshell-driver-kubernetes/Cargo.toml @@ -41,7 +41,6 @@ tracing-subscriber = { workspace = true } thiserror = { workspace = true } miette = { workspace = true } notify = "8" -rand = { workspace = true } rcgen = { workspace = true } [dev-dependencies] diff --git a/crates/openshell-driver-kubernetes/src/driver.rs b/crates/openshell-driver-kubernetes/src/driver.rs index f30b49f501..d627c0b782 100644 --- a/crates/openshell-driver-kubernetes/src/driver.rs +++ b/crates/openshell-driver-kubernetes/src/driver.rs @@ -67,7 +67,6 @@ use openshell_sandbox_backend::boundary_protocol::{ GatewayVerificationKey, SandboxTlsClientConfig, SandboxTlsServerConfig, generate_sandbox_tls_material, }; -use rand::RngCore as _; use serde::Deserialize; use std::collections::{BTreeMap, HashSet}; use std::path::{Path, PathBuf}; @@ -286,16 +285,16 @@ const SANDBOX_RUNTIME_RECONCILE_INTERVAL: Duration = Duration::from_secs(30); /// Bound how long a crash-interrupted, fail-closed bootstrap may remain stranded. const SANDBOX_RUNTIME_BOOTSTRAP_GRACE: Duration = Duration::from_mins(5); -fn random_sandbox_runtime_token() -> String { +fn random_sandbox_runtime_token() -> Result { use std::fmt::Write as _; - let mut bytes = [0_u8; 32]; - rand::rng().fill_bytes(&mut bytes); + let bytes = openshell_crypto::random_bytes::<32>() + .map_err(|error| KubernetesDriverError::Message(error.to_string()))?; let mut token = String::with_capacity(bytes.len() * 2); for byte in bytes { write!(token, "{byte:02x}").expect("writing to String cannot fail"); } - token + Ok(token) } fn decode_launch_authentication( @@ -2034,7 +2033,7 @@ impl KubernetesComputeDriver { .resolve_sandbox_identity_in_namespace(&target_namespace) .await; - let generation = random_sandbox_runtime_token(); + let generation = random_sandbox_runtime_token()?; let proxy_names = SandboxRuntimeNames::for_generation(&sandbox.id, &generation); let image_pull_secrets = self.generation_image_pull_secret_names(&proxy_names); let main_process_spec = openshell_core::sandbox_env::MainProcessConfig::encode_driver_spec( diff --git a/crates/openshell-driver-vm/Cargo.toml b/crates/openshell-driver-vm/Cargo.toml index f8ed6c70e9..691592c7c7 100644 --- a/crates/openshell-driver-vm/Cargo.toml +++ b/crates/openshell-driver-vm/Cargo.toml @@ -50,7 +50,7 @@ opentelemetry = { workspace = true, optional = true } opentelemetry_sdk = { workspace = true, optional = true } tracing-opentelemetry = { workspace = true, optional = true } miette = { workspace = true, optional = true } -rand = { workspace = true, optional = true } +openshell-crypto = { workspace = true, optional = true } url = { workspace = true, optional = true } serde = { workspace = true } serde_json = { workspace = true } @@ -88,7 +88,7 @@ compute-driver = [ "dep:polling", "dep:prost", "dep:prost-types", - "dep:rand", + "dep:openshell-crypto", "dep:sha2", "dep:tar", "dep:tokio-stream", diff --git a/crates/openshell-driver-vm/src/driver.rs b/crates/openshell-driver-vm/src/driver.rs index d0309a2efd..990bcd5386 100644 --- a/crates/openshell-driver-vm/src/driver.rs +++ b/crates/openshell-driver-vm/src/driver.rs @@ -1452,9 +1452,9 @@ impl VmDriver { let boundary_generation = match tokio::fs::read_to_string(state_dir.join(HOST_BOUNDARY_GENERATION_FILE)).await { Ok(generation) if !generation.trim().is_empty() => generation.trim().to_string(), - Ok(_) => random_boundary_token(), + Ok(_) => random_boundary_token()?, Err(error) if error.kind() == std::io::ErrorKind::NotFound => { - random_boundary_token() + random_boundary_token()? } Err(error) => { return Err(Status::internal(format!( @@ -6224,12 +6224,14 @@ fn merged_environment(sandbox: &Sandbox) -> HashMap { environment } -fn random_boundary_token() -> String { +fn random_boundary_token() -> Result { let mut token = String::with_capacity(64); - for byte in rand::random::<[u8; 32]>() { + for byte in openshell_crypto::random_bytes::<32>() + .map_err(|error| Status::internal(error.to_string()))? + { write!(&mut token, "{byte:02x}").expect("writing to String cannot fail"); } - token + Ok(token) } fn build_guest_environment(sandbox: &Sandbox, config: &VmDriverConfig) -> Vec { diff --git a/crates/openshell-sandbox-backend/Cargo.toml b/crates/openshell-sandbox-backend/Cargo.toml index fd2c486288..64c643790a 100644 --- a/crates/openshell-sandbox-backend/Cargo.toml +++ b/crates/openshell-sandbox-backend/Cargo.toml @@ -27,7 +27,6 @@ rustls = { workspace = true } rustls-pemfile = { workspace = true } serde = { workspace = true } serde_json = { workspace = true } -sha2 = { workspace = true } socket2 = { workspace = true } thiserror = { workspace = true } tokio = { workspace = true } diff --git a/crates/openshell-sandbox-backend/src/boundary_protocol.rs b/crates/openshell-sandbox-backend/src/boundary_protocol.rs index 9051b8dc7a..ddf22fa61c 100644 --- a/crates/openshell-sandbox-backend/src/boundary_protocol.rs +++ b/crates/openshell-sandbox-backend/src/boundary_protocol.rs @@ -29,7 +29,6 @@ use openshell_isolation_interface::contract::{ }; use rcgen::{CertificateParams, DnType, ExtendedKeyUsagePurpose, IsCa, KeyUsagePurpose}; use serde::{Deserialize, Serialize}; -use sha2::{Digest as _, Sha256}; use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt}; pub const MAX_CONTROL_FRAME_BYTES: usize = 1024 * 1024; @@ -594,7 +593,9 @@ impl RequestEnvelope { }; let payload_digest = request_envelope_digest(&request, exec_admission_deadline_unix_ms)?; Ok(Self { - request_id: uuid::Uuid::new_v4().to_string(), + request_id: uuid::Builder::from_random_bytes(openshell_crypto::random_bytes::<16>()?) + .into_uuid() + .to_string(), payload_digest, exec_admission_deadline_unix_ms, request, @@ -625,6 +626,8 @@ pub(crate) fn request_envelope_digest( request: &Request, exec_admission_deadline_unix_ms: Option, ) -> Result { + use std::fmt::Write as _; + // Stable local replay fingerprint of decoded protobuf fields. Maps use // BTreeMap in generated messages; neither clients nor the wire carry this. let envelope = RequestEnvelope { @@ -634,8 +637,12 @@ pub(crate) fn request_envelope_digest( request: request.clone(), }; let payload = crate::protobuf::encode(&envelope)?; - let digest = Sha256::digest(payload); - Ok(format!("{digest:x}")) + let digest = openshell_crypto::sha256(&payload)?; + let mut encoded = String::with_capacity(64); + for byte in digest { + write!(&mut encoded, "{byte:02x}").expect("writing to String cannot fail"); + } + Ok(encoded) } impl fmt::Debug for RequestEnvelope { @@ -1386,6 +1393,8 @@ where #[derive(Debug, thiserror::Error)] pub enum FrameError { + #[error("control frame cryptography failed: {0}")] + Crypto(#[from] openshell_crypto::CryptoError), #[error("invalid protobuf message: {0}")] Protobuf(String), #[error("control frame is truncated")] diff --git a/crates/openshell-sandbox-backend/src/runtime.rs b/crates/openshell-sandbox-backend/src/runtime.rs index 906d8f20d9..99c607902c 100644 --- a/crates/openshell-sandbox-backend/src/runtime.rs +++ b/crates/openshell-sandbox-backend/src/runtime.rs @@ -27,7 +27,6 @@ use openshell_isolation_interface::contract::{ MediationTiming, PendingDnsQuery, PendingTcpOpen, ProviderEnvironmentInstallation, ResolvedWorkloadIdentity, SandboxContext, TcpOpenDecision, TcpOpenDenial, }; -use sha2::{Digest as _, Sha256}; use tokio::io::{AsyncReadExt, AsyncWriteExt}; #[cfg(unix)] use tokio::net::UnixStream; @@ -1208,7 +1207,8 @@ impl BoundaryCredential { })?; // Epochs are monotonic; retry if authorization crossed an epoch change. if slot.credential_epoch() == Some(epoch) { - let fingerprint = Sha256::digest(authorization.as_encoded_bytes()).into(); + let fingerprint = openshell_crypto::sha256(authorization.as_encoded_bytes()) + .map_err(|error| BackendError::Unavailable(error.to_string()))?; return Ok(Self { epoch, authorization, diff --git a/crates/openshell-sandbox-backend/tests/crypto_dispatch.rs b/crates/openshell-sandbox-backend/tests/crypto_dispatch.rs new file mode 100644 index 0000000000..9ed5001260 --- /dev/null +++ b/crates/openshell-sandbox-backend/tests/crypto_dispatch.rs @@ -0,0 +1,107 @@ +// 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, pki, +}; +use openshell_sandbox_backend::boundary_protocol::{FrameError, Request, RequestEnvelope}; +use std::sync::atomic::{AtomicUsize, Ordering}; + +static FAILURE: AtomicUsize = AtomicUsize::new(0); +struct Backend(CryptoContext); +struct FailingDigest; +impl Digest for FailingDigest { + fn update(&mut self, _: &[u8]) -> Result<(), CryptoError> { + if FAILURE.load(Ordering::SeqCst) == 2 { + Err(CryptoError::Operation) + } else { + Ok(()) + } + } + fn finish(self: Box) -> Result<[u8; 32], CryptoError> { + assert_eq!( + FAILURE.load(Ordering::SeqCst), + 3, + "must not finalize a failed update" + ); + Err(CryptoError::Operation) + } +} +impl CryptoBackend for Backend { + fn capabilities(&self) -> Capabilities { + self.0.backend().capabilities() + } + fn fill_random(&self, bytes: &mut [u8]) -> Result<(), CryptoError> { + if FAILURE.load(Ordering::SeqCst) == 4 { + Err(CryptoError::Random) + } else { + self.0.backend().fill_random(bytes) + } + } + fn sha256_digest(&self) -> Result, CryptoError> { + match FAILURE.load(Ordering::SeqCst) { + 0 | 4 => self.0.backend().sha256_digest(), + 1 => Err(CryptoError::Operation), + _ => Ok(Box::new(FailingDigest)), + } + } + fn seal(&self, _: &[u8; 32], _: &[u8], _: &[u8]) -> Result { + unreachable!() + } + fn open(&self, _: &[u8; 32], _: &[u8], _: &[u8; 12], _: &[u8]) -> Result, CryptoError> { + unreachable!() + } +} +impl ProtocolBackend for Backend { + fn tls_provider(&self) -> rustls::crypto::CryptoProvider { + self.0.backend().tls_provider() + } + fn jwt_provider(&self) -> &'static jsonwebtoken::crypto::CryptoProvider { + self.0.backend().jwt_provider() + } + fn generate_keypair( + &self, + _: &'static rcgen::SignatureAlgorithm, + ) -> Result { + unreachable!() + } + fn import_keypair_pem(&self, _: &str) -> Result { + unreachable!() + } + fn import_keypair_der(&self, _: &[u8]) -> Result { + unreachable!() + } +} + +#[test] +fn request_envelope_uses_selected_digest_and_rejects_backend_failures() { + // Separate executable prevents process-global backend state leaking to other tests. + openshell_crypto::install_default_context(CryptoContext::new(Box::new(Backend( + CryptoContext::default(), + )))) + .unwrap(); + let request = || Request::Terminate { + process_id: "test".into(), + }; + let envelope = RequestEnvelope::new(request()).unwrap(); + assert_eq!( + envelope.payload_digest, + "12fa19027b624b79dacb71a241331c6b7a961ae5c8a5084df3559c097cf8ad76" + ); + for stage in 1..=3 { + FAILURE.store(stage, Ordering::SeqCst); + assert!(matches!( + RequestEnvelope::new(request()), + Err(FrameError::Crypto(CryptoError::Operation)) + )); + assert!(matches!( + envelope.validate_payload_digest(), + Err(FrameError::Crypto(CryptoError::Operation)) + )); + } + FAILURE.store(4, Ordering::SeqCst); + assert!(matches!( + RequestEnvelope::new(request()), + Err(FrameError::Crypto(CryptoError::Random)) + )); +} diff --git a/crates/openshell-server/src/auth/sandbox_jwt.rs b/crates/openshell-server/src/auth/sandbox_jwt.rs index 260a9a1d81..6cf0463751 100644 --- a/crates/openshell-server/src/auth/sandbox_jwt.rs +++ b/crates/openshell-server/src/auth/sandbox_jwt.rs @@ -164,7 +164,9 @@ impl SandboxSessionJwtAuthority { let token_metadata = identity .refresh_replay .as_ref() - .map(|replay| (replay.sandbox_token_id(), replay.issued_at)); + .map(|replay| replay.sandbox_token_id().map(|id| (id, replay.issued_at))) + .transpose() + .map_err(|error| Status::internal(error.to_string()))?; self.mint_launch_with_metadata( sandbox_id, identity.runtime_generation.clone(), diff --git a/crates/openshell-server/src/auth/sandbox_session.rs b/crates/openshell-server/src/auth/sandbox_session.rs index b3fcdf7abb..dc9e424240 100644 --- a/crates/openshell-server/src/auth/sandbox_session.rs +++ b/crates/openshell-server/src/auth/sandbox_session.rs @@ -8,7 +8,7 @@ use std::collections::HashMap; use openshell_core::jwt::{AuthenticatedSandboxSession, CredentialEpoch, SessionJwtError}; use openshell_core::proto::{Sandbox, SandboxPhase}; use openshell_core::sandbox_generation::SandboxGenerationId; -use sha2::{Digest as _, Sha256}; +use openshell_crypto::CryptoError; use tonic::Status; use uuid::Uuid; @@ -30,16 +30,15 @@ const REFRESH_ROTATION_ID_ANNOTATION: &str = "internal.openshell.ai/refresh-rota pub struct RefreshRequestHash(String); impl RefreshRequestHash { - #[must_use] - pub fn from_extension_services(names: &[String]) -> Self { - let mut digest = Sha256::new(); - digest.update(b"openshell-refresh-v1\0"); + pub fn from_extension_services(names: &[String]) -> Result { + let mut digest = openshell_crypto::sha256_digest()?; + digest.update(b"openshell-refresh-v1\0")?; for name in names { let length = u64::try_from(name.len()).unwrap_or(u64::MAX); - digest.update(length.to_be_bytes()); - digest.update(name.as_bytes()); + digest.update(&length.to_be_bytes())?; + digest.update(name.as_bytes())?; } - Self(hex::encode(digest.finalize())) + Ok(Self(hex::encode(digest.finish()?))) } fn parse(value: String) -> Result { @@ -66,13 +65,15 @@ pub struct GatewayRefreshReplay { } impl GatewayRefreshReplay { - #[must_use] - pub fn sandbox_token_id(&self) -> Uuid { + pub fn sandbox_token_id(&self) -> Result { derive_token_id(self.rotation_id, b"sandbox") } - #[must_use] - pub fn extension_token_id(&self, service_name: &str, audience: &str) -> Uuid { + pub fn extension_token_id( + &self, + service_name: &str, + audience: &str, + ) -> Result { let mut label = Vec::with_capacity(service_name.len() + audience.len() + 11); label.extend_from_slice(b"extension\0"); label.extend_from_slice(service_name.as_bytes()); @@ -82,15 +83,15 @@ impl GatewayRefreshReplay { } } -fn derive_token_id(rotation_id: Uuid, label: &[u8]) -> Uuid { - let mut digest = Sha256::new(); - digest.update(b"openshell-refresh-token-v1\0"); - digest.update(rotation_id.as_bytes()); - digest.update(label); - let digest = digest.finalize(); +fn derive_token_id(rotation_id: Uuid, label: &[u8]) -> Result { + let mut digest = openshell_crypto::sha256_digest()?; + digest.update(b"openshell-refresh-token-v1\0")?; + digest.update(rotation_id.as_bytes())?; + digest.update(label)?; + let digest = digest.finish()?; let mut bytes = [0_u8; 16]; bytes.copy_from_slice(&digest[..16]); - Uuid::from_bytes(bytes) + Ok(Uuid::from_bytes(bytes)) } /// The complete durable authorization identity for one sandbox runtime. @@ -223,18 +224,17 @@ impl PersistedSandboxIdentity { } } - #[must_use] pub fn next_gateway_token( &self, request_hash: RefreshRequestHash, issued_at: i64, replay_grace_seconds: i64, - ) -> Self { + ) -> Result { let rotation_id = Uuid::new_v4(); - Self { + Ok(Self { runtime_generation: self.runtime_generation.clone(), auth_epoch: self.auth_epoch, - gateway_token_id: derive_token_id(rotation_id, b"gateway"), + gateway_token_id: derive_token_id(rotation_id, b"gateway")?, refresh_replay: Some(GatewayRefreshReplay { previous_gateway_token_id: self.gateway_token_id, request_hash, @@ -242,7 +242,7 @@ impl PersistedSandboxIdentity { issued_at, rotation_id, }), - } + }) } } @@ -411,6 +411,36 @@ mod tests { use openshell_core::proto::datamodel::v1::ObjectMeta; use uuid::Uuid; + #[test] + fn refresh_hashes_and_token_ids_preserve_legacy_bytes() { + assert_eq!( + RefreshRequestHash::from_extension_services(&["alpha".into(), "beta".into()]) + .unwrap() + .to_string(), + "42627fafd657ebd41917ab717004cfd73b765d158e5c59404ba3af91ccc144e4" + ); + for (label, expected) in [ + ( + b"sandbox".as_slice(), + "8b5ad747-0e41-46d0-9c9c-c7df0be60b55", + ), + ( + b"extension\0svc\0aud".as_slice(), + "cc3d696b-f306-a46a-ea39-3186e5a4c4f3", + ), + ( + b"gateway".as_slice(), + "2ad443ec-b10d-6c85-9cc8-2d08d60ed022", + ), + ] { + assert_eq!( + derive_token_id(Uuid::from_u128(1), label) + .unwrap() + .to_string(), + expected + ); + } + } async fn persist_sandbox(store: &Store, phase: SandboxPhase) { let identity = PersistedSandboxIdentity { runtime_generation: SandboxGenerationId::parse("generation-a") @@ -521,11 +551,12 @@ mod tests { persist_sandbox(&store, SandboxPhase::Ready).await; let first = principal(1, Uuid::from_u128(1)); - let request_hash = RefreshRequestHash::from_extension_services(&[]); + let request_hash = RefreshRequestHash::from_extension_services(&[]).unwrap(); let expected = authorize_persisted(&store, &first) .await .expect("current identity") - .next_gateway_token(request_hash.clone(), 100, 30); + .next_gateway_token(request_hash.clone(), 100, 30) + .unwrap(); let next = rotate_gateway_token(&store, &first, &expected) .await .expect("rotate current gateway token"); diff --git a/crates/openshell-server/src/compute/rootfs_tar.rs b/crates/openshell-server/src/compute/rootfs_tar.rs index 544cdcafec..8af22680dd 100644 --- a/crates/openshell-server/src/compute/rootfs_tar.rs +++ b/crates/openshell-server/src/compute/rootfs_tar.rs @@ -18,7 +18,6 @@ use std::sync::Mutex; use std::time::{Duration, Instant}; use openshell_core::time::now_ms; -use rand::RngCore; use tonic::Status; use tracing::{info, warn}; @@ -220,6 +219,7 @@ impl RootfsTarStagingRegistry { // The directory name uses independent randomness so the token never // appears in a filesystem path, a directory listing, or a log field. + let token = new_staging_token()?; let dir = staging_root.join(format!("{STAGING_DIR_PREFIX}{}", uuid::Uuid::new_v4())); create_private_dir(&dir).map_err(|err| { Status::internal(format!( @@ -228,7 +228,6 @@ impl RootfsTarStagingRegistry { })?; let file = dir.join(&file_name); - let token = new_staging_token(); let expires_at = Instant::now() + self.ttl; let expires_at_ms = now_ms() + i64::try_from(self.ttl.as_millis()).unwrap_or(i64::MAX); @@ -361,10 +360,10 @@ impl RootfsTarStagingRegistry { } } -fn new_staging_token() -> String { - let mut raw = [0u8; 32]; - rand::rng().fill_bytes(&mut raw); - hex::encode(raw) +fn new_staging_token() -> Result { + let raw = openshell_crypto::random_bytes::<32>() + .map_err(|error| Status::internal(error.to_string()))?; + Ok(hex::encode(raw)) } /// Reject anything that would let `dir.join(file_name)` escape the request diff --git a/crates/openshell-server/src/grpc/auth_rpc.rs b/crates/openshell-server/src/grpc/auth_rpc.rs index 57b009b7a0..ea654503a7 100644 --- a/crates/openshell-server/src/grpc/auth_rpc.rs +++ b/crates/openshell-server/src/grpc/auth_rpc.rs @@ -257,7 +257,8 @@ pub async fn handle_refresh_sandbox_token( let request_hash = crate::auth::sandbox_session::RefreshRequestHash::from_extension_services( &requested_extension_services, - ); + ) + .map_err(|error| Status::internal(error.to_string()))?; let issued_at = current_unix_seconds(); let (principal, authorization) = authenticate_refresh( state, @@ -282,14 +283,16 @@ pub async fn handle_refresh_sandbox_token( })?; let (successor, should_rotate) = match authorization { crate::auth::sandbox_session::RefreshAuthorization::Current(identity) => ( - identity.next_gateway_token( - request_hash, - issued_at, - REFRESH_REPLAY_GRACE - .as_secs() - .try_into() - .unwrap_or(i64::MAX), - ), + identity + .next_gateway_token( + request_hash, + issued_at, + REFRESH_REPLAY_GRACE + .as_secs() + .try_into() + .unwrap_or(i64::MAX), + ) + .map_err(|error| Status::internal(error.to_string()))?, true, ), crate::auth::sandbox_session::RefreshAuthorization::Replay(identity) => (identity, false), @@ -454,7 +457,9 @@ fn mint_extension_credentials( Some(sandbox_id), ttl, replay.issued_at, - replay.extension_token_id(name, audience.as_str()), + replay + .extension_token_id(name, audience.as_str()) + .map_err(|error| Status::internal(error.to_string()))?, ) }, )?; From cee5f764dd9bad6e892c00f7ce599a6a1a00996e Mon Sep 17 00:00:00 2001 From: Varsha Prasad Narsing Date: Tue, 22 Sep 2026 21:14:32 -0700 Subject: [PATCH 12/25] chore(crypto): refresh lockfile after upstream rebase Signed-off-by: Varsha Prasad Narsing --- Cargo.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9cc957ed7d..c2b59ef065 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -216,7 +216,7 @@ dependencies = [ "nom", "num-traits", "rusticata-macros", - "thiserror 2.0.18", + "thiserror 2.0.20", "time", ] @@ -4426,7 +4426,7 @@ dependencies = [ "serde", "serde_json", "sqlx", - "thiserror 2.0.18", + "thiserror 2.0.20", "tonic", "x509-parser 0.18.1", ] @@ -9626,7 +9626,7 @@ dependencies = [ "nom", "oid-registry 0.8.1", "rusticata-macros", - "thiserror 2.0.18", + "thiserror 2.0.20", "time", ] From b5871a240815fa9cd124c39671a74def9fc36da4 Mon Sep 17 00:00:00 2001 From: Varsha Prasad Narsing Date: Thu, 24 Sep 2026 10:37:43 -0700 Subject: [PATCH 13/25] fix(crypto): route VM socket entropy through backend after rebase Signed-off-by: Varsha Prasad Narsing --- crates/openshell-crypto/README.md | 3 ++- crates/openshell-driver-vm/src/driver.rs | 34 +++++++++++++++++------- 2 files changed, 27 insertions(+), 10 deletions(-) diff --git a/crates/openshell-crypto/README.md b/crates/openshell-crypto/README.md index dfacc37851..fbe6889868 100644 --- a/crates/openshell-crypto/README.md +++ b/crates/openshell-crypto/README.md @@ -113,7 +113,8 @@ and deployment qualification belong in follow-up work. Runtime refresh replay hashes and derived token IDs, bearer-cache fingerprints, Sandbox Protocol request digests and request-ID entropy, Kubernetes/VM runtime -fence entropy, and rootfs staging-token entropy use the selected backend. +fence entropy, VM socket-directory entropy, and rootfs staging-token entropy use +the selected backend. These operations retain SHA-256, UUID v4 encoding where applicable, and existing hex encodings. Backend failures propagate; callers must not substitute another implementation or continue with a placeholder identity. diff --git a/crates/openshell-driver-vm/src/driver.rs b/crates/openshell-driver-vm/src/driver.rs index 990bcd5386..d54916caa5 100644 --- a/crates/openshell-driver-vm/src/driver.rs +++ b/crates/openshell-driver-vm/src/driver.rs @@ -6299,17 +6299,19 @@ fn sandbox_socket_dir(socket_root: &Path, sandbox_id: &str) -> PathBuf { fn allocate_socket_root() -> Result<(PathBuf, OwnedFd), std::io::Error> { let uid = rustix::process::geteuid().as_raw(); allocate_socket_root_with(Path::new("/tmp"), || { - let random: u128 = rand::random(); - format!("os-{uid}-{random:032x}") + let random = u128::from_ne_bytes( + openshell_crypto::random_bytes::<16>().map_err(std::io::Error::other)?, + ); + Ok(format!("os-{uid}-{random:032x}")) }) } fn allocate_socket_root_with( base: &Path, - mut gen_name: impl FnMut() -> String, + mut gen_name: impl FnMut() -> Result, ) -> Result<(PathBuf, OwnedFd), std::io::Error> { for _ in 0..SOCKET_ROOT_ALLOC_RETRIES { - let root = base.join(gen_name()); + let root = base.join(gen_name()?); match rustix::fs::mkdir(&root, rustix::fs::Mode::from_raw_mode(0o700)) { Ok(()) => { let fd = rustix::fs::open( @@ -7755,7 +7757,10 @@ mod tests { use tonic::Code; fn test_socket_root() -> (PathBuf, Arc) { - let dir = std::env::temp_dir().join(format!("os-test-{:016x}", rand::random::())); + let dir = std::env::temp_dir().join(format!( + "os-test-{:016x}", + u64::from_ne_bytes(openshell_crypto::random_bytes::<8>().expect("test entropy")) + )); std::fs::create_dir(&dir).expect("create test socket root"); std::fs::set_permissions(&dir, fs::Permissions::from_mode(0o700)) .expect("set test socket root permissions"); @@ -9738,12 +9743,12 @@ mod tests { let mut counter = 0u64; let (root_a, _fd_a) = allocate_socket_root_with(tmp.path(), || { counter += 1; - format!("root-{counter}") + Ok(format!("root-{counter}")) }) .unwrap(); let (root_b, _fd_b) = allocate_socket_root_with(tmp.path(), || { counter += 1; - format!("root-{counter}") + Ok(format!("root-{counter}")) }) .unwrap(); assert_ne!( @@ -9767,7 +9772,7 @@ mod tests { let call_count = AtomicUsize::new(0); let (root, _fd) = allocate_socket_root_with(tmp.path(), || { let n = call_count.fetch_add(1, Ordering::SeqCst); - format!("attempt-{n}") + Ok(format!("attempt-{n}")) }) .expect("should succeed after retries"); @@ -9793,13 +9798,24 @@ mod tests { ); } + #[test] + fn allocate_socket_root_propagates_name_generation_failure() { + let tmp = tempfile::tempdir().unwrap(); + let err = allocate_socket_root_with(tmp.path(), || { + Err(std::io::Error::other(openshell_crypto::CryptoError::Random)) + }) + .expect_err("entropy failure must stop allocation"); + assert_eq!(err.kind(), std::io::ErrorKind::Other); + assert_eq!(std::fs::read_dir(tmp.path()).unwrap().count(), 0); + } + #[test] fn allocate_socket_root_exhaustion_returns_error() { let tmp = tempfile::tempdir().unwrap(); let blocked = tmp.path().join("blocked"); std::fs::create_dir(&blocked).unwrap(); - let err = allocate_socket_root_with(tmp.path(), || "blocked".to_string()) + let err = allocate_socket_root_with(tmp.path(), || Ok("blocked".to_string())) .expect_err("should fail when all names are occupied"); assert_eq!(err.kind(), std::io::ErrorKind::AlreadyExists); } From 087aff248606307c12e73c0f2cc10f4c4cb23cf1 Mon Sep 17 00:00:00 2001 From: Varsha Prasad Narsing Date: Thu, 24 Sep 2026 12:22:16 -0700 Subject: [PATCH 14/25] docs(crypto): document architecture and contributor boundaries Signed-off-by: Varsha Prasad Narsing --- .agents/skills/build-from-issue/SKILL.md | 2 + .agents/skills/fix-security-issue/SKILL.md | 2 + .agents/skills/review-github-pr/SKILL.md | 1 + AGENTS.md | 1 + crates/openshell-crypto/CRYPTO.md | 82 ++++++++++++++++++++++ crates/openshell-crypto/README.md | 3 + 6 files changed, 91 insertions(+) create mode 100644 crates/openshell-crypto/CRYPTO.md diff --git a/.agents/skills/build-from-issue/SKILL.md b/.agents/skills/build-from-issue/SKILL.md index 16ef5bbd14..6e99e7e1b2 100644 --- a/.agents/skills/build-from-issue/SKILL.md +++ b/.agents/skills/build-from-issue/SKILL.md @@ -32,3 +32,5 @@ Use a single issue comment beginning with `> **🏗️ build-plan**` when a plan Every PR from this issue-backed workflow must have its own existing issue and use `Closes #` in its Related Issue section. For work needing multiple PRs, split the scope into a closable issue per PR. A high-level issue may track those issues but should not be closed by an incomplete PR. Report the implementation, verification, and any remaining limitation in the PR description, rather than copying earlier issue diagnostics. Do not apply acceptance or roadmap decisions on behalf of a maintainer. Do not introduce `agent:*` workflow labels. + +For first-party security-sensitive crypto, use `openshell-crypto` and extend its facade/backend contracts when needed. Follow the [crypto architecture](../../../crates/openshell-crypto/CRYPTO.md) for compatibility, failure handling, and explicit coverage exceptions. diff --git a/.agents/skills/fix-security-issue/SKILL.md b/.agents/skills/fix-security-issue/SKILL.md index 83a145c216..3391ed2690 100644 --- a/.agents/skills/fix-security-issue/SKILL.md +++ b/.agents/skills/fix-security-issue/SKILL.md @@ -16,3 +16,5 @@ Use this skill after an authorized `review-security-issue` review identifies an 5. Follow `create-github-pr` and use `Closes #` for the reviewed issue. Every PR from this issue-backed remediation workflow must close its own issue; split multi-PR remediations into separate issues in the authorized security workflow. Keep the PR description appropriately scoped to its disclosure venue. Begin any fix comments with `> **🔧 security-fix-agent**`. Do not change human disposition or introduce `agent:*` workflow labels. + +For first-party security-sensitive crypto, use `openshell-crypto` and extend its facade/backend contracts when needed. Follow the [crypto architecture](../../../crates/openshell-crypto/CRYPTO.md) for compatibility, failure handling, and explicit coverage exceptions. diff --git a/.agents/skills/review-github-pr/SKILL.md b/.agents/skills/review-github-pr/SKILL.md index d69c891281..9813402c76 100644 --- a/.agents/skills/review-github-pr/SKILL.md +++ b/.agents/skills/review-github-pr/SKILL.md @@ -153,6 +153,7 @@ Read through the full diff (and the PR description if available). Produce a summ suggested change. - Do not fabricate concerns or claim a behavioral regression without evidence for both the prior and proposed behavior. +- **Cryptographic boundaries**: For changed first-party security-sensitive crypto, verify use of `openshell-crypto`, backend dispatch, failure propagation without fallback, and protocol/storage compatibility. Missing operations belong in the facade/backend contracts. Check dependency-owned and non-security exceptions against the repository's [crypto architecture](../../../crates/openshell-crypto/CRYPTO.md); protocol/parsing types alone are not bypasses. Report undocumented bypasses or scope expansion under **Potential Concerns**. - **Agent infrastructure**: When the PR changes behavior, commands, or development workflows, use the `sync-agent-infra` maintenance map to check that related skills were updated. When it adds, removes, or renames skills or crates; changes workflow relationships or skill coverage; modifies issue or PR templates; or changes agent cross-references, apply the full consistency checklist. Report missing companion updates or drift under **Potential Concerns**. ## Step 5: Output diff --git a/AGENTS.md b/AGENTS.md index 7217f941b9..434d235b4a 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -236,6 +236,7 @@ When behavior, commands, or development workflows change, review the related age ## Security +- Route first-party security-sensitive cryptographic operations through `openshell-crypto`. If an operation is missing, extend the facade and backend implementation instead of adding a direct cryptographic implementation in an application crate. Preserve protocol compatibility and propagate backend failures without fallback. Protocol/parsing types and documented non-security or dependency-owned exceptions remain permitted; classify exceptions explicitly. Follow [Cryptography and FIPS](crates/openshell-crypto/CRYPTO.md). - Never commit secrets, API keys, or credentials. If a file looks like it contains secrets (`.env`, `credentials.json`, etc.), do not stage it. - Do not run destructive operations (force push, hard reset, database drops) without explicit human confirmation. - Scope changes to the issue at hand. Do not make unrelated changes in the same branch. diff --git a/crates/openshell-crypto/CRYPTO.md b/crates/openshell-crypto/CRYPTO.md new file mode 100644 index 0000000000..9887389ee0 --- /dev/null +++ b/crates/openshell-crypto/CRYPTO.md @@ -0,0 +1,82 @@ +# Cryptography and FIPS + +OpenShell routes first-party security-sensitive cryptography through +`openshell-crypto`. The workspace selects AWS-LC as the production backend. +The interface supports a future system-OpenSSL backend; the current production +implementation does not assert FIPS compliance, and strict posture requests fail +closed. + +## Backend boundary + +Application code owns protocol choices, authorization policy, and persisted +formats. The backend owns cryptographic implementations and key resources. +`CryptoBackend` provides randomness, incremental SHA-256, and AES-256-GCM; +`ProtocolBackend` adapts Rustls, certificate signing, key import/generation, and +JWT operations. Backend neutrality preserves explicit algorithm choices required +by existing protocols and stored data. + +Signing keys retain backend ownership and may refuse private-key export. +rcgen encodes certificates using those keys. Persisted CA metadata is parsed +without a cryptographic verification backend; parsing does not establish trust. +The proxy checks certificate/key matching through the selected TLS provider and +retains the original CA certificate in issued chains. + +Backend failures propagate to callers without selecting another implementation. +Authentication failures must not expose plaintext or secret-bearing diagnostics. +Existing ciphertext layouts, digest inputs, JWT algorithms, and protocol versions +remain compatibility constraints when adding or changing a backend. + +## Selection and initialization + +Consumer crates inherit the workspace's backend choice and enable integration +features on the facade. A build without the default backend must install a +context before facade use. Select the context before constructing clients, +listeners, or dependencies that initialize process-wide crypto providers. + +Explicit context selection controls first-party TLS builders even when a +dependency initialized Rustls first. Without explicit selection, those builders +preserve an embedder's installed provider. JWT adapters retain jsonwebtoken's +process-global provider constraints; that provider cannot be replaced safely. +Neither behavior redirects dependency-owned cryptography automatically. + +## Contributor rules and coverage + +Route new first-party security-sensitive hashing, randomness, encryption, +signing, verification, and TLS/PKI/JWT operations through `openshell-crypto`. +If an operation is missing, extend the facade and backend implementation rather +than calling an external cryptographic implementation from an application crate. +Test backend dispatch, failure handling, and any affected compatibility contract. + +Protocol and parsing types may remain in application code. Non-security uses +and dependency-owned operations require explicit classification; do not claim +that the selected backend covers them or silently expand an existing exception. +The [crate README](README.md#compatibility-and-exclusions) +records current coverage, including remaining artifact-integrity hashes, policy +cache fingerprints, UUID entropy, SSH, and other dependency-owned operations. +Review changes against that scope. Cargo features and contributor instructions +alone do not prove exclusive backend ownership. + +## OpenSSL and FIPS follow-up + +Backend capability reporting describes that backend's operations. A backend name, +successful operation, dynamic link, or clean dependency scan alone does not +establish deployment compliance. A production OpenSSL/FIPS profile requires: + +- A defined supported feature set and disposition for every security-sensitive + crypto path, including dependencies and all shipped processes. +- Dynamic linking to the intended system OpenSSL and provider packages in the + supported runtime image, with recorded versions and provenance. +- Separate evidence for provider ownership, effective provider policy, host + operating mode, and actual TLS configurations. A strict requirement must + reject missing evidence or unsupported operations without fallback. +- TLS policy validation for clients, listeners, and reload paths, including the + TLS 1.2 Extended Master Secret requirement for the intended FIPS profile. +- Checks of the selected build graph and shipped artifacts, including dynamic + dependencies, bundled crypto, and an accurate dependency manifest. Required + evidence must fail validation when unavailable. +- Tests in the qualified target environment covering TLS/mTLS, JWT, persisted CA + loading, credential encryption, and negative startup/algorithm cases. + +These are follow-up requirements, not guarantees of the current backend. +Implementation details and extension APIs live in the +[crypto crate README](README.md). diff --git a/crates/openshell-crypto/README.md b/crates/openshell-crypto/README.md index fbe6889868..9bc54e1996 100644 --- a/crates/openshell-crypto/README.md +++ b/crates/openshell-crypto/README.md @@ -1,5 +1,8 @@ # OpenShell crypto backend +See [Cryptography and FIPS](CRYPTO.md) for the architecture, +contributor rules, and production OpenSSL/FIPS follow-up requirements. + `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. From b48ae70996900e3f60e5c78540fa317b13be9174 Mon Sep 17 00:00:00 2001 From: Varsha Prasad Narsing Date: Thu, 24 Sep 2026 12:41:39 -0700 Subject: [PATCH 15/25] test(crypto): adapt upstream fixtures to backend facade Signed-off-by: Varsha Prasad Narsing --- crates/openshell-core/src/jwt.rs | 5 +++-- crates/openshell-driver-vm/src/driver.rs | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/crates/openshell-core/src/jwt.rs b/crates/openshell-core/src/jwt.rs index d360acabe1..c6b3d1b33a 100644 --- a/crates/openshell-core/src/jwt.rs +++ b/crates/openshell-core/src/jwt.rs @@ -1075,10 +1075,11 @@ mod tests { #[test] fn non_expiring_session_tokens_remain_usable() { - 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 issuer = SessionJwtIssuer::from_ed25519_pem( - key.serialize_pem().as_bytes(), + key.serialize_pem().unwrap().as_bytes(), "current", "test", None, diff --git a/crates/openshell-driver-vm/src/driver.rs b/crates/openshell-driver-vm/src/driver.rs index d54916caa5..025b8182ab 100644 --- a/crates/openshell-driver-vm/src/driver.rs +++ b/crates/openshell-driver-vm/src/driver.rs @@ -11417,7 +11417,7 @@ mod tests { let outside = Path::new("/tmp").join(format!( "openshell-vm-layer-test-{}-{:x}", std::process::id(), - rand::random::() + u64::from_ne_bytes(openshell_crypto::random_bytes::<8>().expect("test entropy")) )); fs::create_dir_all(&outside).unwrap(); fs::write(outside.join("sentinel"), "unchanged").unwrap(); From 4c7c661406e46c85592c887f61d6c9464ee719b7 Mon Sep 17 00:00:00 2001 From: Varsha Prasad Narsing Date: Mon, 28 Sep 2026 12:35:13 -0700 Subject: [PATCH 16/25] test(crypto): route relay TLS fixture through facade Signed-off-by: Varsha Prasad Narsing --- crates/openshell-supervisor-network/src/proxy/relay.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/crates/openshell-supervisor-network/src/proxy/relay.rs b/crates/openshell-supervisor-network/src/proxy/relay.rs index 363ef8868d..dad4b12633 100644 --- a/crates/openshell-supervisor-network/src/proxy/relay.rs +++ b/crates/openshell-supervisor-network/src/proxy/relay.rs @@ -466,14 +466,13 @@ mod tests { #[tokio::test] async fn tls_http_relay_reuses_then_sends_close_notify_after_complete_response() { use crate::l7::tls::{CertCache, ProxyTlsState, SandboxCa, tls_terminate_client}; - let _ = rustls::crypto::aws_lc_rs::default_provider().install_default(); let ca = SandboxCa::generate().unwrap(); let mut roots = rustls::RootCertStore::empty(); for cert in rustls_pemfile::certs(&mut ca.cert_pem().as_bytes()) { roots.add(cert.unwrap()).unwrap(); } let config = Arc::new( - rustls::ClientConfig::builder() + openshell_crypto::tls::client_builder() .with_root_certificates(roots) .with_no_client_auth(), ); From 73749e830cd18527c96f573d2a8da615a615debb Mon Sep 17 00:00:00 2001 From: Varsha Prasad Narsing Date: Wed, 30 Sep 2026 14:46:44 -0700 Subject: [PATCH 17/25] test(crypto): adapt service bearer TLS fixture after rebase Signed-off-by: Varsha Prasad Narsing --- e2e/rust/Cargo.toml | 4 ++-- e2e/rust/tests/service_bearer_passthrough.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/e2e/rust/Cargo.toml b/e2e/rust/Cargo.toml index 5cbfafc928..e75aa25ec2 100644 --- a/e2e/rust/Cargo.toml +++ b/e2e/rust/Cargo.toml @@ -264,14 +264,14 @@ sha1 = "0.10" sha2 = "0.10" hex = "0.4" rand = "0.9" -rustls = { version = "0.23", default-features = false, features = ["std", "logging", "tls12", "aws_lc_rs"] } +rustls = { version = "0.23", default-features = false, features = ["std", "logging", "tls12"] } rustls-pemfile = "2" serde = { version = "1", features = ["derive"] } serde_json = "1" serde_yml = { package = "noyalib", version = "0.0.53", default-features = false, features = ["std", "compat-serde-yaml"] } tonic = { version = "0.14", features = ["transport"] } tonic-prost = "0.14" -tokio-rustls = { version = "0.26", default-features = false, features = ["logging", "tls12", "aws_lc_rs"] } +tokio-rustls = { version = "0.26", default-features = false, features = ["logging", "tls12"] } tower = "0.5" url = "2" nix = { version = "0.29", features = ["process", "signal", "term", "user"] } diff --git a/e2e/rust/tests/service_bearer_passthrough.rs b/e2e/rust/tests/service_bearer_passthrough.rs index 3da8a60eb7..088607e1de 100644 --- a/e2e/rust/tests/service_bearer_passthrough.rs +++ b/e2e/rust/tests/service_bearer_passthrough.rs @@ -21,8 +21,8 @@ use hyper::{Request, StatusCode, header}; use hyper_util::rt::TokioIo; use openshell_e2e::harness::binary::openshell_cmd; use openshell_e2e::harness::sandbox::{E2E_WORKLOAD_IMAGE, SandboxGuard}; +use rustls::RootCertStore; use rustls::pki_types::{CertificateDer, PrivateKeyDer, ServerName}; -use rustls::{ClientConfig, RootCertStore}; use serde_json::Value; use tokio::io::{AsyncRead, AsyncWrite}; use tokio::net::TcpStream; @@ -158,7 +158,7 @@ fn e2e_tls_connector() -> Result { let client_certificates = load_certificates(&mtls_dir.join("tls.crt"), "client TLS certificate")?; let client_key = load_private_key(&mtls_dir.join("tls.key"))?; - let config = ClientConfig::builder() + let config = openshell_crypto::tls::client_builder() .with_root_certificates(roots) .with_client_auth_cert(client_certificates, client_key) .map_err(|error| format!("build e2e mTLS client configuration: {error}"))?; From 45055620bec73045c6e0a094ff43eca7429ab4b2 Mon Sep 17 00:00:00 2001 From: Varsha Prasad Narsing Date: Wed, 30 Sep 2026 16:13:45 -0700 Subject: [PATCH 18/25] fix(crypto): route provider profile TLS initialization through facade Signed-off-by: Varsha Prasad Narsing --- crates/openshell-cli/src/commands/provider.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/openshell-cli/src/commands/provider.rs b/crates/openshell-cli/src/commands/provider.rs index 4092137f8e..efc3d1bb12 100644 --- a/crates/openshell-cli/src/commands/provider.rs +++ b/crates/openshell-cli/src/commands/provider.rs @@ -2249,7 +2249,7 @@ async fn load_profile_import_items_with_url( "provider profile URL must end in .yaml, .yml, or .json" )); } - let _ = rustls::crypto::aws_lc_rs::default_provider().install_default(); + openshell_crypto::tls::ensure_default_provider(); let client = reqwest::Client::builder() .timeout(std::time::Duration::from_secs(15)) .build() From 82fa0cd7b8894e5e4663bf486083d6227024e39e Mon Sep 17 00:00:00 2001 From: Varsha Prasad Narsing Date: Mon, 5 Oct 2026 12:09:26 -0700 Subject: [PATCH 19/25] fix(crypto): adapt upstream VM and supervisor paths to facade Signed-off-by: Varsha Prasad Narsing --- crates/openshell-driver-vm/src/preparation.rs | 4 +++- crates/openshell-supervisor/src/backend_setup/tests.rs | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/crates/openshell-driver-vm/src/preparation.rs b/crates/openshell-driver-vm/src/preparation.rs index 3f6d0cc9ec..23c623f9ee 100644 --- a/crates/openshell-driver-vm/src/preparation.rs +++ b/crates/openshell-driver-vm/src/preparation.rs @@ -124,7 +124,9 @@ impl Attempt { pub fn create(cache_root: &Path) -> io::Result { let root = cache_root.join(ATTEMPTS_DIR); fs::create_dir_all(&root)?; - let name = format!("attempt-{:032x}", rand::random::()); + let random = + u128::from_ne_bytes(openshell_crypto::random_bytes::<16>().map_err(io::Error::other)?); + let name = format!("attempt-{random:032x}"); let directory = root.join(&name); let lease_path = root.join(format!("{name}.lease")); let mut lease = OpenOptions::new() diff --git a/crates/openshell-supervisor/src/backend_setup/tests.rs b/crates/openshell-supervisor/src/backend_setup/tests.rs index 1025860f7e..c291b42ef0 100644 --- a/crates/openshell-supervisor/src/backend_setup/tests.rs +++ b/crates/openshell-supervisor/src/backend_setup/tests.rs @@ -658,7 +658,7 @@ async fn shared_startup_uses_selected_backend_through_readiness_and_shutdown() { }; // Match the binary's process setup before exercising the shared library. - let _ = rustls::crypto::aws_lc_rs::default_provider().install_default(); + openshell_crypto::tls::ensure_default_provider(); let root = PathBuf::from(root); let rules = root.join("policy.rego"); let data = root.join("policy.yaml"); From 44091f505e30d46200ad0d440ad05a1271cbe22a Mon Sep 17 00:00:00 2001 From: Varsha Prasad Narsing Date: Mon, 5 Oct 2026 12:16:28 -0700 Subject: [PATCH 20/25] ci(crypto): enforce backend independence in branch checks Signed-off-by: Varsha Prasad Narsing --- .github/workflows/branch-checks.yml | 11 +++++++++++ crates/openshell-crypto/README.md | 4 +++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/.github/workflows/branch-checks.yml b/.github/workflows/branch-checks.yml index 41e1013d88..8fe743684c 100644 --- a/.github/workflows/branch-checks.yml +++ b/.github/workflows/branch-checks.yml @@ -307,6 +307,17 @@ jobs: cache-key: rust-checks-v2 save-cache: "true" + - name: Verify crypto backend independence + shell: nix develop -c bash -euo pipefail {0} + run: | + cargo tree --locked -p openshell-crypto --no-default-features --edges normal,build,dev --prefix none > /tmp/openshell-crypto-dependencies.txt + if grep -Eq '^(ring|aws-lc-rs|aws-lc-sys|aws-lc-fips-sys) v' /tmp/openshell-crypto-dependencies.txt; then + echo "ERROR: backend-free crypto build includes Ring or AWS-LC" >&2 + cat /tmp/openshell-crypto-dependencies.txt >&2 + exit 1 + fi + cargo test --locked -p openshell-crypto --no-default-features --test independent_backend + - name: Test shell: nix develop -c bash -euo pipefail {0} env: diff --git a/crates/openshell-crypto/README.md b/crates/openshell-crypto/README.md index 9bc54e1996..3a696ab915 100644 --- a/crates/openshell-crypto/README.md +++ b/crates/openshell-crypto/README.md @@ -168,7 +168,9 @@ 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`. +`cargo tree -p openshell-crypto --no-default-features --edges normal,build,dev`. +Branch Checks runs this test separately from workspace tests and rejects Ring or +AWS-LC in the dependency tree, including build and test dependencies. 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. From 6a47cb1ddc1934222c03849ff8899e14c38433e7 Mon Sep 17 00:00:00 2001 From: Varsha Prasad Narsing Date: Tue, 6 Oct 2026 09:14:59 -0700 Subject: [PATCH 21/25] test(crypto): adapt upstream token grant TLS fixture Signed-off-by: Varsha Prasad Narsing --- .../openshell-supervisor-network/src/l7/relay.rs | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/crates/openshell-supervisor-network/src/l7/relay.rs b/crates/openshell-supervisor-network/src/l7/relay.rs index b971805ee5..487b13ded9 100644 --- a/crates/openshell-supervisor-network/src/l7/relay.rs +++ b/crates/openshell-supervisor-network/src/l7/relay.rs @@ -5277,22 +5277,19 @@ network_policies: tokio_rustls::client::TlsStream, tokio_rustls::server::TlsStream, ) { - let _ = rustls::crypto::aws_lc_rs::default_provider().install_default(); - let key = rcgen::KeyPair::generate().unwrap(); - let cert = rcgen::CertificateParams::new(vec!["api.example.test".into()]) - .unwrap() - .self_signed(&key) - .unwrap(); - let server_config = rustls::ServerConfig::builder() + let key = openshell_crypto::pki::generate_keypair().unwrap(); + let params = rcgen::CertificateParams::new(vec!["api.example.test".into()]).unwrap(); + let cert = openshell_crypto::pki::self_signed(params, &key).unwrap(); + let server_config = openshell_crypto::tls::server_builder() .with_no_client_auth() .with_single_cert( vec![cert.der().clone()], - rustls::pki_types::PrivatePkcs8KeyDer::from(key.serialize_der()).into(), + rustls::pki_types::PrivatePkcs8KeyDer::from(key.serialize_der().unwrap()).into(), ) .unwrap(); let mut roots = rustls::RootCertStore::empty(); roots.add(cert.der().clone()).unwrap(); - let client_config = rustls::ClientConfig::builder() + let client_config = openshell_crypto::tls::client_builder() .with_root_certificates(roots) .with_no_client_auth(); let connector = tokio_rustls::TlsConnector::from(Arc::new(client_config)); From b18398275eb1c3f68c53515695d0294e040b349e Mon Sep 17 00:00:00 2001 From: Varsha Prasad Narsing Date: Fri, 9 Oct 2026 09:39:02 -0700 Subject: [PATCH 22/25] fix(crypto): avoid format collect in executable hashing Signed-off-by: Varsha Prasad Narsing --- crates/openshell-binary-identity/src/lib.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/crates/openshell-binary-identity/src/lib.rs b/crates/openshell-binary-identity/src/lib.rs index 091ecb3dc8..c5dc5696f3 100644 --- a/crates/openshell-binary-identity/src/lib.rs +++ b/crates/openshell-binary-identity/src/lib.rs @@ -364,6 +364,7 @@ fn executable_path(pid: u32) -> Result { #[cfg(target_os = "linux")] fn hash_executable(pid: u32, executable: &mut std::fs::File) -> Result { + use std::fmt::Write as _; use std::io::Read as _; let path = format!("/proc/{pid}/exe"); @@ -380,7 +381,10 @@ fn hash_executable(pid: u32, executable: &mut std::fs::File) -> Result Date: Fri, 9 Oct 2026 10:21:43 -0700 Subject: [PATCH 23/25] fix(crypto): address provider selection and decryption review Signed-off-by: Varsha Prasad Narsing --- Cargo.lock | 1 - crates/openshell-cli/Cargo.toml | 2 +- crates/openshell-cli/src/commands/gateway.rs | 2 +- crates/openshell-crypto/Cargo.toml | 4 +- crates/openshell-crypto/README.md | 19 +++++--- .../openshell-driver-db-credstore/src/lib.rs | 44 +++++++++++++++++-- crates/openshell-server/Cargo.toml | 2 +- e2e/rust/Cargo.lock | 1 - examples/governance-interceptor/Cargo.lock | 1 - .../Cargo.lock | 1 - tests/suites/features/Cargo.lock | 19 ++++---- 11 files changed, 65 insertions(+), 31 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c2b59ef065..7394a586f6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4416,7 +4416,6 @@ name = "openshell-crypto" version = "0.0.0" dependencies = [ "aws-lc-rs", - "hyper-rustls", "jsonwebtoken", "k8s-openapi", "kube", diff --git a/crates/openshell-cli/Cargo.toml b/crates/openshell-cli/Cargo.toml index 8338cf5762..a6cb1fc895 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 = { workspace = true, features = ["tls-hyper"] } +openshell-crypto = { workspace = true } 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/commands/gateway.rs b/crates/openshell-cli/src/commands/gateway.rs index ffb7dae76e..705976f7af 100644 --- a/crates/openshell-cli/src/commands/gateway.rs +++ b/crates/openshell-cli/src/commands/gateway.rs @@ -1473,7 +1473,7 @@ async fn http_health_check(server: &str, tls: &TlsOptions) -> Result Result, Status> { let nonce = decode_b64_array::("nonce", &encrypted.nonce)?; 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")) + openshell_crypto::aead::open(key_bytes, aad, &nonce, &ciphertext).map_err(decrypt_error_status) +} + +fn decrypt_error_status(error: openshell_crypto::CryptoError) -> Status { + let message = "failed to decrypt default credential storage value"; + match error { + openshell_crypto::CryptoError::Authentication => Status::data_loss(message), + _ => Status::internal(message), + } } fn dek_aad(id: &str, provider_name: &str, credential_key: &str) -> Vec { @@ -934,8 +941,37 @@ mod tests { assert_eq!(decrypt_bytes(&key, &aad, &encrypted).unwrap(), plaintext); 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()); + assert_eq!( + decrypt_bytes(&key, b"wrong-aad", &encrypted) + .unwrap_err() + .code(), + Code::DataLoss + ); + assert_eq!( + decrypt_bytes(&[0xff; KEY_LEN], &aad, &encrypted) + .unwrap_err() + .code(), + Code::DataLoss + ); + } + } + + #[test] + fn backend_decryption_failures_do_not_report_corrupt_credentials() { + use openshell_crypto::CryptoError; + + let authentication = decrypt_error_status(CryptoError::Authentication); + assert_eq!(authentication.code(), Code::DataLoss); + for error in [ + CryptoError::Operation, + CryptoError::Random, + CryptoError::ProviderConflict, + CryptoError::UnsupportedPosture, + ] { + let status = decrypt_error_status(error); + assert_eq!(status.code(), Code::Internal); + // Diagnostics stay opaque for every backend failure. + assert_eq!(status.message(), authentication.message()); } } diff --git a/crates/openshell-server/Cargo.toml b/crates/openshell-server/Cargo.toml index b5abaab0bf..3b8a6cf78b 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 = { workspace = true, features = ["tls-hyper", "tls-kube", "tls-sqlx"] } +openshell-crypto = { workspace = true, features = ["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/e2e/rust/Cargo.lock b/e2e/rust/Cargo.lock index 7df58aab90..f83216018d 100644 --- a/e2e/rust/Cargo.lock +++ b/e2e/rust/Cargo.lock @@ -1718,7 +1718,6 @@ name = "openshell-crypto" version = "0.0.0" dependencies = [ "aws-lc-rs", - "hyper-rustls", "jsonwebtoken", "kube", "pem 3.0.6", diff --git a/examples/governance-interceptor/Cargo.lock b/examples/governance-interceptor/Cargo.lock index d37416762d..37a26ec25b 100644 --- a/examples/governance-interceptor/Cargo.lock +++ b/examples/governance-interceptor/Cargo.lock @@ -1891,7 +1891,6 @@ name = "openshell-crypto" version = "0.0.0" dependencies = [ "aws-lc-rs", - "hyper-rustls", "jsonwebtoken", "kube", "pem 3.0.6", diff --git a/examples/supervisor-middleware-content-guard/Cargo.lock b/examples/supervisor-middleware-content-guard/Cargo.lock index 8aa96a3a9b..dc34936847 100644 --- a/examples/supervisor-middleware-content-guard/Cargo.lock +++ b/examples/supervisor-middleware-content-guard/Cargo.lock @@ -2045,7 +2045,6 @@ name = "openshell-crypto" version = "0.0.0" dependencies = [ "aws-lc-rs", - "hyper-rustls", "jsonwebtoken", "kube", "pem 3.0.6", diff --git a/tests/suites/features/Cargo.lock b/tests/suites/features/Cargo.lock index 31876064b5..aaa8274c73 100644 --- a/tests/suites/features/Cargo.lock +++ b/tests/suites/features/Cargo.lock @@ -1730,7 +1730,6 @@ name = "openshell-crypto" version = "0.0.0" dependencies = [ "aws-lc-rs", - "hyper-rustls", "jsonwebtoken", "kube", "pem 3.0.6", @@ -2183,15 +2182,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "rustls-pemfile" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" -dependencies = [ - "rustls-pki-types", -] - [[package]] name = "rustls-native-certs" version = "0.8.4" @@ -2204,6 +2194,15 @@ dependencies = [ "security-framework", ] +[[package]] +name = "rustls-pemfile" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" +dependencies = [ + "rustls-pki-types", +] + [[package]] name = "rustls-pki-types" version = "1.15.1" From 00c6acdbfae688ee82919fcf5c9c30ec9d6cabc7 Mon Sep 17 00:00:00 2001 From: Varsha Prasad Narsing Date: Mon, 12 Oct 2026 01:25:47 -0700 Subject: [PATCH 24/25] fix(crypto): adapt upstream operator TLS paths after rebase Signed-off-by: Varsha Prasad Narsing --- crates/openshell-crypto/README.md | 6 ++++-- .../src/grpc/provider_credentials_tests.rs | 8 ++++---- crates/openshell-server/src/lib.rs | 8 +++++++- crates/openshell-server/src/multiplex.rs | 14 ++++++++++---- 4 files changed, 25 insertions(+), 11 deletions(-) diff --git a/crates/openshell-crypto/README.md b/crates/openshell-crypto/README.md index d8af4a8fa0..68efe366e8 100644 --- a/crates/openshell-crypto/README.md +++ b/crates/openshell-crypto/README.md @@ -116,8 +116,9 @@ 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. -Runtime refresh replay hashes and derived token IDs, bearer-cache fingerprints, -Sandbox Protocol request digests and request-ID entropy, Kubernetes/VM runtime +Operator certificate fingerprints, runtime refresh replay hashes and derived token +IDs, bearer-cache fingerprints, Sandbox Protocol request digests and request-ID +entropy, Kubernetes/VM runtime fence entropy, VM socket-directory entropy, and rootfs staging-token entropy use the selected backend. These operations retain SHA-256, UUID v4 encoding where applicable, and existing @@ -136,6 +137,7 @@ not a whole-application crypto coverage claim: | UUID generation outside Sandbox Protocol request envelopes | Includes runtime identities, authentication nonces, and session identifiers as well as ordinary correlation IDs. These still use the UUID library's entropy source. They are not attested by context posture; a follow-up must classify each use and propagate entropy failure through currently infallible constructors. | | DNS policy contract fingerprints (`openshell-supervisor-network::policy_dns`) | These bind cached DNS state to policy and are security-relevant. They remain outside this migration; migrating the cache identity API and its failure handling is required for exclusive backend ownership. | | Credential-storage names (`credentials`, Kubernetes Secrets, Vault) | Deterministic namespace derivation, not encryption or proof of authorization. These retain their current hashing implementation and stored names; backend coverage is not asserted for them. | +| Provider-refresh advisory-lock keys | Deterministic database lock selection for coordinating refreshes, not authentication or encryption. These remain outside the selected-backend contract. | | Endpoint IDs and pagination fingerprints | Deterministic identification/request matching, not authentication. These remain outside the selected-backend contract. | | Debug token fingerprints | Diagnostic display only; direct hashing remains outside the contract even though the input is a credential. | | Schema compatibility tests, content-cache identities, retry jitter, test fixtures | Non-authentication uses remain unchanged. | diff --git a/crates/openshell-server/src/grpc/provider_credentials_tests.rs b/crates/openshell-server/src/grpc/provider_credentials_tests.rs index a29a3a44bc..c602e28461 100644 --- a/crates/openshell-server/src/grpc/provider_credentials_tests.rs +++ b/crates/openshell-server/src/grpc/provider_credentials_tests.rs @@ -754,7 +754,7 @@ async fn real_tls_operator_boundary_and_admin_capabilities() { tokio::spawn(async move { if let Ok(stream) = acceptor.accept(stream).await { let identity = extract_peer_identity(&stream); - let fingerprint = extract_peer_certificate_sha256(&stream); + let fingerprint = extract_peer_certificate_sha256(&stream).unwrap(); let _ = service .serve_with_verified_certificate( stream, @@ -785,11 +785,11 @@ async fn real_tls_operator_boundary_and_admin_capabilities() { .distinguished_name .push(rcgen::DnType::OrganizationalUnitName, role); params.extended_key_usages = vec![rcgen::ExtendedKeyUsagePurpose::ClientAuth]; - let key = rcgen::KeyPair::generate().unwrap(); - let cert = params.signed_by(&key, &ca, &ca_key).unwrap(); + let key = openshell_crypto::pki::generate_keypair().unwrap(); + let cert = openshell_crypto::pki::signed_by(params, &key, &ca, &ca_key).unwrap(); tls = tls.identity(tonic::transport::Identity::from_pem( cert.pem(), - key.serialize_pem(), + key.serialize_pem().unwrap(), )); } let channel = Endpoint::from_shared(format!("https://localhost:{}", address.port())) diff --git a/crates/openshell-server/src/lib.rs b/crates/openshell-server/src/lib.rs index 44dfc4945c..231c24c1a4 100644 --- a/crates/openshell-server/src/lib.rs +++ b/crates/openshell-server/src/lib.rs @@ -1192,7 +1192,13 @@ fn spawn_gateway_connection( Ok(tls_stream) => { let peer_identity = multiplex::extract_peer_identity(&tls_stream); let certificate_sha256 = - multiplex::extract_peer_certificate_sha256(&tls_stream); + match multiplex::extract_peer_certificate_sha256(&tls_stream) { + Ok(fingerprint) => fingerprint, + Err(e) => { + error!(error = %e, client = %addr, "Failed to fingerprint peer certificate"); + return; + } + }; if let Err(e) = service .serve_with_verified_certificate( tls_stream, diff --git a/crates/openshell-server/src/multiplex.rs b/crates/openshell-server/src/multiplex.rs index 909017609b..de6050a065 100644 --- a/crates/openshell-server/src/multiplex.rs +++ b/crates/openshell-server/src/multiplex.rs @@ -1453,10 +1453,16 @@ where /// Fingerprint of the leaf certificate verified during the TLS handshake. pub fn extract_peer_certificate_sha256( stream: &tokio_rustls::server::TlsStream, -) -> Option { - use sha2::{Digest, Sha256}; - let certificate = stream.get_ref().1.peer_certificates()?.first()?; - Some(format!("{:x}", Sha256::digest(certificate.as_ref()))) +) -> Result, openshell_crypto::CryptoError> { + let Some(certificate) = stream + .get_ref() + .1 + .peer_certificates() + .and_then(|certs| certs.first()) + else { + return Ok(None); + }; + openshell_crypto::sha256(certificate.as_ref()).map(|digest| Some(hex::encode(digest))) } /// Boxed body type for uniform handling. From ec548b289d3a0383fcb18b65062a0495bd68fd70 Mon Sep 17 00:00:00 2001 From: Varsha Prasad Narsing Date: Mon, 19 Oct 2026 10:32:57 -0700 Subject: [PATCH 25/25] fix(crypto): adapt upstream TLS fixtures and protocol tests Signed-off-by: Varsha Prasad Narsing --- Cargo.lock | 2 + crates/openshell-core/src/oauth.rs | 21 +- crates/openshell-driver-podman/Cargo.toml | 1 + crates/openshell-driver-podman/src/config.rs | 6 +- crates/openshell-otel-test-support/Cargo.toml | 1 + .../tests/common/mod.rs | 17 +- crates/openshell-sandbox-backend/Cargo.toml | 3 + .../src/runtime/test_support.rs | 3 +- .../tests/crypto_dispatch.rs | 4 +- .../src/l7/tls.rs | 2 +- examples/isolation-backend-v8/Cargo.lock | 1419 ++++++++++++++++- 11 files changed, 1426 insertions(+), 53 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7394a586f6..f2fb807752 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4583,6 +4583,7 @@ dependencies = [ "miette", "nix 0.29.0", "openshell-core", + "openshell-crypto", "openshell-isolation-interface", "openshell-otel", "openshell-otel-test-support", @@ -4796,6 +4797,7 @@ dependencies = [ name = "openshell-otel-test-support" version = "0.0.0" dependencies = [ + "openshell-crypto", "openshell-otel", "opentelemetry-proto", "rcgen", diff --git a/crates/openshell-core/src/oauth.rs b/crates/openshell-core/src/oauth.rs index 3b4bc5a120..dcf56cf5c6 100644 --- a/crates/openshell-core/src/oauth.rs +++ b/crates/openshell-core/src/oauth.rs @@ -523,22 +523,23 @@ mod tests { TokenGrantClient, tokio::task::JoinHandle, ) { - let _ = rustls::crypto::aws_lc_rs::default_provider().install_default(); let mut ca_params = rcgen::CertificateParams::new(Vec::::new()).expect("CA params"); ca_params.is_ca = rcgen::IsCa::Ca(rcgen::BasicConstraints::Unconstrained); - let ca_key = rcgen::KeyPair::generate().expect("CA key"); - let ca = ca_params.self_signed(&ca_key).expect("CA certificate"); - let key = rcgen::KeyPair::generate().expect("server key"); - let certificate = rcgen::CertificateParams::new(vec!["localhost".to_string()]) - .expect("server params") - .signed_by(&key, &ca, &ca_key) + let ca_key = openshell_crypto::pki::generate_keypair().expect("CA key"); + let ca = openshell_crypto::pki::self_signed(ca_params, &ca_key).expect("CA certificate"); + let key = openshell_crypto::pki::generate_keypair().expect("server key"); + let params = + rcgen::CertificateParams::new(vec!["localhost".to_string()]).expect("server params"); + let certificate = openshell_crypto::pki::signed_by(params, &key, &ca, &ca_key) .expect("server certificate"); - let config = rustls::ServerConfig::builder() + let config = openshell_crypto::tls::server_builder() .with_no_client_auth() .with_single_cert( vec![certificate.der().clone()], - rustls::pki_types::PrivateKeyDer::try_from(key.serialize_der()) - .expect("server key"), + rustls::pki_types::PrivateKeyDer::try_from( + key.serialize_der().expect("export server key"), + ) + .expect("server key"), ) .expect("server config"); let acceptor = tokio_rustls::TlsAcceptor::from(Arc::new(config)); diff --git a/crates/openshell-driver-podman/Cargo.toml b/crates/openshell-driver-podman/Cargo.toml index cd9b3cc570..b6c755e3fe 100644 --- a/crates/openshell-driver-podman/Cargo.toml +++ b/crates/openshell-driver-podman/Cargo.toml @@ -47,6 +47,7 @@ miette = { workspace = true } url = { workspace = true } [dev-dependencies] +openshell-crypto = { workspace = true } openshell-otel-test-support = { path = "../openshell-otel-test-support" } opentelemetry_sdk = { workspace = true, features = ["testing"] } prost-types = { workspace = true } diff --git a/crates/openshell-driver-podman/src/config.rs b/crates/openshell-driver-podman/src/config.rs index c00d83b016..2aa8b9c0d1 100644 --- a/crates/openshell-driver-podman/src/config.rs +++ b/crates/openshell-driver-podman/src/config.rs @@ -930,9 +930,11 @@ mod tests { /// Generate a real, valid self-signed CA certificate PEM for tests. fn generate_test_ca_pem() -> String { - let key_pair = rcgen::KeyPair::generate().unwrap(); + let key_pair = openshell_crypto::pki::generate_keypair().unwrap(); let params = rcgen::CertificateParams::new(Vec::new()).unwrap(); - params.self_signed(&key_pair).unwrap().pem() + openshell_crypto::pki::self_signed(params, &key_pair) + .unwrap() + .pem() } #[test] diff --git a/crates/openshell-otel-test-support/Cargo.toml b/crates/openshell-otel-test-support/Cargo.toml index d40f60ccb8..8e9cebd516 100644 --- a/crates/openshell-otel-test-support/Cargo.toml +++ b/crates/openshell-otel-test-support/Cargo.toml @@ -20,6 +20,7 @@ tracing = { workspace = true } tracing-subscriber = { workspace = true } [dev-dependencies] +openshell-crypto = { workspace = true } rcgen = { workspace = true } tempfile = "3" diff --git a/crates/openshell-otel-test-support/tests/common/mod.rs b/crates/openshell-otel-test-support/tests/common/mod.rs index 9a828a14a6..b289484122 100644 --- a/crates/openshell-otel-test-support/tests/common/mod.rs +++ b/crates/openshell-otel-test-support/tests/common/mod.rs @@ -3,19 +3,18 @@ //! Shared TLS export scenario for the one-test-per-binary TLS tests. +use openshell_crypto::pki::{self, Certificate, KeyPair}; use openshell_otel::{OtlpExportConfig, ServiceName, provider_for}; use openshell_otel_test_support::{OtlpTestServer, ReceivedTraces}; -use rcgen::{ - BasicConstraints, Certificate, CertificateParams, ExtendedKeyUsagePurpose, IsCa, KeyPair, -}; +use rcgen::{BasicConstraints, CertificateParams, ExtendedKeyUsagePurpose, IsCa}; use tonic::transport::Identity; use tracing_subscriber::layer::SubscriberExt as _; fn new_ca() -> (Certificate, KeyPair) { - let key = KeyPair::generate().unwrap(); + let key = pki::generate_keypair().unwrap(); let mut params = CertificateParams::new(Vec::::new()).unwrap(); params.is_ca = IsCa::Ca(BasicConstraints::Unconstrained); - (params.self_signed(&key).unwrap(), key) + (pki::self_signed(params, &key).unwrap(), key) } /// Export one gzip span to a TLS collector and return the flush outcome and @@ -35,12 +34,10 @@ pub async fn export_span_over_tls(server_trusted: bool) -> (bool, ReceivedTraces (&other_ca, &other_key) }; - let server_key = KeyPair::generate().unwrap(); + let server_key = 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, signer, signer_key) - .unwrap(); + let server_cert = pki::signed_by(server_params, &server_key, signer, signer_key).unwrap(); let roots = tempfile::NamedTempFile::new().unwrap(); std::fs::write(roots.path(), trusted_ca.pem()).unwrap(); @@ -52,7 +49,7 @@ pub async fn export_span_over_tls(server_trusted: bool) -> (bool, ReceivedTraces let collector = OtlpTestServer::start_tls(Identity::from_pem( server_cert.pem(), - server_key.serialize_pem(), + server_key.serialize_pem().unwrap(), )) .await; let (provider, error) = provider_for(Some(OtlpExportConfig { diff --git a/crates/openshell-sandbox-backend/Cargo.toml b/crates/openshell-sandbox-backend/Cargo.toml index 64c643790a..b6b092604b 100644 --- a/crates/openshell-sandbox-backend/Cargo.toml +++ b/crates/openshell-sandbox-backend/Cargo.toml @@ -45,5 +45,8 @@ libc = "0.2" [target.'cfg(target_os = "linux")'.dependencies] rustix = { workspace = true, features = ["fs", "process"] } +[dev-dependencies] +jsonwebtoken = { workspace = true } + [lints] workspace = true diff --git a/crates/openshell-sandbox-backend/src/runtime/test_support.rs b/crates/openshell-sandbox-backend/src/runtime/test_support.rs index 464bcc83bf..28aaf5cc2c 100644 --- a/crates/openshell-sandbox-backend/src/runtime/test_support.rs +++ b/crates/openshell-sandbox-backend/src/runtime/test_support.rs @@ -656,14 +656,13 @@ impl super::BoundaryTransportConnector for Connector { fn client(peer: Peer) -> Arc { let session_id = "550e8400-e29b-41d4-a716-446655440000".parse().unwrap(); let material = w::generate_sandbox_tls_material(session_id).unwrap(); - let _ = rustls::crypto::aws_lc_rs::default_provider().install_default(); let certs = rustls_pemfile::certs(&mut material.certificate_chain_pem.as_bytes()) .collect::, _>>() .unwrap(); let key = rustls_pemfile::private_key(&mut material.private_key_pem.as_bytes()) .unwrap() .unwrap(); - let mut config = rustls::ServerConfig::builder() + let mut config = openshell_crypto::tls::server_builder() .with_no_client_auth() .with_single_cert(certs, key) .unwrap(); diff --git a/crates/openshell-sandbox-backend/tests/crypto_dispatch.rs b/crates/openshell-sandbox-backend/tests/crypto_dispatch.rs index 9ed5001260..c532615504 100644 --- a/crates/openshell-sandbox-backend/tests/crypto_dispatch.rs +++ b/crates/openshell-sandbox-backend/tests/crypto_dispatch.rs @@ -84,9 +84,11 @@ fn request_envelope_uses_selected_digest_and_rejects_backend_failures() { process_id: "test".into(), }; let envelope = RequestEnvelope::new(request()).unwrap(); + // SHA-256 of protobuf RequestEnvelope { terminate: { process_id: "test" } } + // with an empty request ID: 9a 01 06 0a 04 74 65 73 74. assert_eq!( envelope.payload_digest, - "12fa19027b624b79dacb71a241331c6b7a961ae5c8a5084df3559c097cf8ad76" + "6c6d7215ecc2ea064ffeffcefb0a575b2c1387b41e488380c48f9cbcfec062e0" ); for stage in 1..=3 { FAILURE.store(stage, Ordering::SeqCst); diff --git a/crates/openshell-supervisor-network/src/l7/tls.rs b/crates/openshell-supervisor-network/src/l7/tls.rs index 6539b1061a..fe24afc90d 100644 --- a/crates/openshell-supervisor-network/src/l7/tls.rs +++ b/crates/openshell-supervisor-network/src/l7/tls.rs @@ -601,7 +601,7 @@ mod tests { let leaf = cert_cache.get_or_generate(hostname).unwrap(); let server_config = Arc::new( - ServerConfig::builder() + openshell_crypto::tls::server_builder() .with_no_client_auth() .with_single_cert(leaf.cert_chain.clone(), leaf.private_key.clone_key()) .unwrap(), diff --git a/examples/isolation-backend-v8/Cargo.lock b/examples/isolation-backend-v8/Cargo.lock index 988cb2a1b5..b6013b9cf8 100644 --- a/examples/isolation-backend-v8/Cargo.lock +++ b/examples/isolation-backend-v8/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" @@ -82,6 +101,57 @@ 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" @@ -115,6 +185,15 @@ dependencies = [ "syn 3.0.9", ] +[[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" @@ -194,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" @@ -224,6 +314,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 = "bindgen" version = "0.72.1" @@ -244,11 +340,23 @@ dependencies = [ "syn 2.0.119", ] +[[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" @@ -259,12 +367,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" @@ -314,6 +437,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 = "clang-sys" version = "1.9.1" @@ -374,6 +518,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" @@ -414,6 +564,30 @@ 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 = "crc32fast" version = "1.5.2" @@ -423,6 +597,21 @@ dependencies = [ "cfg-if", ] +[[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" @@ -433,6 +622,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.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03bb0e1cc970d482d121d9a1744999169b69a07470b3d644a7894e53fcaf4574" +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.9" @@ -445,8 +707,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]] @@ -492,17 +765,64 @@ dependencies = [ "syn 3.0.9", ] +[[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.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0e9c71c2167ca323c882b99918929403426e2373ea17242ff5653e0d5e1058be" +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.9", +] [[package]] name = "equivalent" @@ -520,6 +840,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" @@ -538,6 +888,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" @@ -550,6 +911,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" @@ -575,6 +942,20 @@ dependencies = [ "winapi", ] +[[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" @@ -582,6 +963,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1f9e3d69d39e4862ffed03ed071a76f9a13ba1d9109d355b0f0aa6b15e393c4" dependencies = [ "futures-core", + "futures-sink", ] [[package]] @@ -590,6 +972,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.9", +] + [[package]] name = "futures-sink" version = "0.3.34" @@ -608,8 +1029,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", ] @@ -635,6 +1061,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" @@ -643,7 +1081,8 @@ checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099" dependencies = [ "cfg-if", "libc", - "r-efi", + "r-efi 6.0.0", + "rand_core 0.10.1", ] [[package]] @@ -658,6 +1097,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 = "gzip-header" version = "1.1.0" @@ -692,7 +1143,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]] @@ -701,12 +1165,69 @@ 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.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc2700e3fe555c3310aa7286cac6167449f2c87e0eb58769c9208a1c58a1d106" +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" @@ -716,6 +1237,17 @@ 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" @@ -761,6 +1293,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.12.0" @@ -778,9 +1319,45 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "smallvec", + "smallvec", + "tokio", + "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", - "want", + "tokio-rustls", + "tower-service", +] + +[[package]] +name = "hyper-rustls" +version = "0.27.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfa8e654703247911e29c23fbeaa261834bd9bb74efba2f9acddc37bfb127f53" +dependencies = [ + "http", + "hyper", + "hyper-util", + "log", + "rustls", + "rustls-native-certs", + "tokio", + "tokio-rustls", + "tower-service", ] [[package]] @@ -967,6 +1544,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" @@ -1076,7 +1659,7 @@ dependencies = [ "rustls-pemfile", "serde", "serde_json", - "sha2", + "sha2 0.10.9", "tokio", "tokio-rustls", "tokio-stream", @@ -1098,6 +1681,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" @@ -1105,10 +1723,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", @@ -1116,6 +1734,135 @@ 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.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20870f649af7073d53e38067b2a84312175d56ea15217e1b15bc83506ec50afb" + [[package]] name = "libc" version = "0.2.190" @@ -1138,6 +1885,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.4.15" @@ -1177,6 +1935,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" @@ -1331,6 +2099,15 @@ dependencies = [ "memchr", ] +[[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" @@ -1348,12 +2125,13 @@ name = "openshell-core" version = "0.0.0" dependencies = [ "async-trait", - "base64", + "base64 0.22.1", "glob", "ipnet", "jsonwebtoken", "miette", "nix", + "openshell-crypto", "openshell-extension-core", "openshell-policy-schema", "prost", @@ -1364,7 +2142,7 @@ dependencies = [ "rustls-pemfile", "serde", "serde_json", - "sha2", + "sha2 0.10.9", "thiserror", "tokio", "tokio-stream", @@ -1378,6 +2156,23 @@ dependencies = [ "zeroize", ] +[[package]] +name = "openshell-crypto" +version = "0.0.0" +dependencies = [ + "aws-lc-rs", + "jsonwebtoken", + "kube", + "pem 3.0.6", + "rcgen", + "rustls", + "serde", + "sqlx", + "thiserror", + "tonic", + "x509-parser", +] + [[package]] name = "openshell-extension-core" version = "0.0.0" @@ -1397,7 +2192,7 @@ dependencies = [ "openshell-core", "serde", "serde_json", - "sha2", + "sha2 0.10.9", "tokio", ] @@ -1422,6 +2217,7 @@ dependencies = [ "hyper-util", "libc", "openshell-core", + "openshell-crypto", "openshell-isolation-interface", "prost", "prost-types", @@ -1431,7 +2227,6 @@ dependencies = [ "rustls-pemfile", "serde", "serde_json", - "sha2", "socket2", "thiserror", "tokio", @@ -1451,12 +2246,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" @@ -1492,7 +2302,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", ] @@ -1502,6 +2322,50 @@ version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" +[[package]] +name = "pest" +version = "2.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd47a460a9cbc3b3429c7e22bf0d76653e779319bae45a499ca010c9a990bb23" +dependencies = [ + "memchr", + "psm", + "stacker", + "ucd-trie", +] + +[[package]] +name = "pest_derive" +version = "2.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "203e46697708f7519ab1608393cf89239cafb46b8e6d08a8ffe359359b11ef44" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" +version = "2.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e84ae6340a458d3d6cfc73cf328cf3cfe90b2484cd0de25eb66aa954615ed4d5" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2", + "quote", + "syn 3.0.9", +] + +[[package]] +name = "pest_meta" +version = "2.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b57f92f32b3dbce6598fd8f5cdf1f06a6072570b8103fa21728fa9036923e710" +dependencies = [ + "pest", +] + [[package]] name = "petgraph" version = "0.8.3" @@ -1698,6 +2562,15 @@ version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "263a3f48f01e7309e857138bd47f785585b4a005e8e56c6d2824ce91195999c3" +[[package]] +name = "psm" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "200b9ff220857e53e184257720a14553b2f4aa02577d2ed9842d45d4b9654810" +dependencies = [ + "cc", +] + [[package]] name = "pulldown-cmark" version = "0.13.4" @@ -1727,12 +2600,29 @@ 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" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" +[[package]] +name = "rand" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65c9fb96cbc91e3478eaae79a69fcd3f1ae4ad052e471fe6732fff548984b4af" +dependencies = [ + "chacha20", + "getrandom 0.4.3", + "rand_core 0.10.1", +] + [[package]] name = "rand_core" version = "0.6.4" @@ -1742,16 +2632,23 @@ dependencies = [ "getrandom 0.2.17", ] +[[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", "yasna", ] @@ -1829,6 +2726,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 = "0.38.44" @@ -1918,6 +2824,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 = "schannel" version = "0.1.29" @@ -1927,12 +2839,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" @@ -1966,6 +2911,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" @@ -1979,11 +2934,22 @@ dependencies = [ name = "serde_derive" version = "1.0.229" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" +checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.9", +] + +[[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 3.0.9", + "syn 2.0.119", ] [[package]] @@ -2010,6 +2976,41 @@ dependencies = [ "serde_core", ] +[[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" @@ -2017,8 +3018,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.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47d7069beb7d6ac7b9acd1039986e73443f24234f41074da099d6f994ac9ad19" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.1", + "digest 0.11.3", ] [[package]] @@ -2049,7 +3061,7 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" dependencies = [ - "rand_core", + "rand_core 0.6.4", ] [[package]] @@ -2075,6 +3087,9 @@ name = "smallvec" version = "1.16.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b3dc8af474f516a851ff4bd12db780f948b9250ad37211e4eec0bccea54e01b" +dependencies = [ + "serde", +] [[package]] name = "socket2" @@ -2086,12 +3101,206 @@ 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.1", + "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.1", + "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 = "stacker" +version = "0.1.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "707f49d46706bacf8a2b00d51dace3f9de527c13eec3778f570c411f89e69967" +dependencies = [ + "cc", + "cfg-if", + "libc", + "psm", + "windows-sys 0.61.2", +] + [[package]] name = "strck" version = "1.0.0" @@ -2101,6 +3310,17 @@ dependencies = [ "unicode-ident", ] +[[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" @@ -2162,6 +3382,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" @@ -2313,6 +3544,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.3" @@ -2373,6 +3610,7 @@ dependencies = [ "futures-sink", "libc", "pin-project-lite", + "slab", "tokio", ] @@ -2384,7 +3622,7 @@ checksum = "ac2a5518c70fa84342385732db33fb3f44bc4cc748936eb5833d2df34d6445ef" dependencies = [ "async-trait", "axum", - "base64", + "base64 0.22.1", "bytes", "h2", "http", @@ -2476,6 +3714,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" @@ -2494,6 +3750,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", @@ -2531,18 +3788,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.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "357cc3acc6a036009fd6c973ed009037c732d60d0b4f6c673e9041497482a28f" +[[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.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2c754d6c33795a1c324727428e5a7dedb5b06195f9890bdbcba760d3e246563" +[[package]] +name = "unicode-normalization" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75cd3fb03d5288b3ba9a1ee103ac7e9cbb59f0b03d64f8ddfcc04dd42758a85d" +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" @@ -2555,6 +3839,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" @@ -2619,6 +3909,12 @@ dependencies = [ "which", ] +[[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" @@ -2640,6 +3936,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.129" @@ -2685,6 +3990,15 @@ 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 = "which" version = "6.0.3" @@ -2697,6 +4011,12 @@ dependencies = [ "winsafe", ] +[[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" @@ -2822,18 +4142,43 @@ version = "0.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904" +[[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" 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.5.2" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e17bb3549cc1321ae1296b9cdc2698e2b6cb1992adfa19a8c72e5b7a738f44cd" +checksum = "b5f6765e852b9b4dc8e2a76843e4d64d1cea8e79bcde0b6901aea8e7c7f08282" dependencies = [ + "bit-vec", "time", ] @@ -2857,7 +4202,27 @@ dependencies = [ "proc-macro2", "quote", "syn 3.0.9", - "synstructure", + "synstructure 0.14.0", +] + +[[package]] +name = "zerocopy" +version = "0.8.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5fe1f8f1b06191a00962174c61aa5005e0bb391a6d80d07e24d115c01a92ed8" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "863ad3ac83293fb4d740aedbfdc9240dd8d1a50c1099acd76ce80ce7c7230c7f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", ] [[package]] @@ -2878,7 +4243,7 @@ dependencies = [ "proc-macro2", "quote", "syn 3.0.9", - "synstructure", + "synstructure 0.14.0", ] [[package]]