From 310f40083d3ba7953012ba883ce0ce5cec2bf6b8 Mon Sep 17 00:00:00 2001 From: Fini Date: Sun, 9 Aug 2026 01:17:29 +0800 Subject: [PATCH] fix(collab): make the hsm relay locator unix-only The signer daemon's whole security surface (SO_PEERCRED caller authentication, socket-file mode/owner checks, O_NOFOLLOW opens, flock single-instance) is unix semantics; config.rs paths are POSIX too, so windows targets got fifty-five compile errors and a runtime test failure. Gate the crate at the root with a stub main instead of porting checks nobody consumes, and move the deps under cfg(unix) so windows builds stop resolving the PKCS#11 stack entirely. Claude-Session: https://claude.ai/code/session_01FqKQqNj8exYwopGDpYUU7x --- crates/op-collab-relay-locator-hsm/Cargo.toml | 9 ++++- crates/op-collab-relay-locator-hsm/src/lib.rs | 40 +++++++++++++++++-- .../op-collab-relay-locator-hsm/src/main.rs | 39 +++++++++++------- .../tests/softhsm.rs | 3 ++ 4 files changed, 72 insertions(+), 19 deletions(-) diff --git a/crates/op-collab-relay-locator-hsm/Cargo.toml b/crates/op-collab-relay-locator-hsm/Cargo.toml index 9bc978a8c..5ae1e1ddc 100644 --- a/crates/op-collab-relay-locator-hsm/Cargo.toml +++ b/crates/op-collab-relay-locator-hsm/Cargo.toml @@ -8,7 +8,12 @@ repository.workspace = true description = "PKCS#11-backed OPLS signer for OpenPencil relay locators" publish = false -[dependencies] +# Every dependency is Unix-gated because the crate itself is: on other platforms +# the library compiles to nothing and the binary is a stub that exits with an +# unsupported-platform error. Keeping the dependencies out of the non-Unix graph +# means a Windows `cargo build --workspace` neither resolves nor builds the +# PKCS#11 and crypto stack for code that cannot run there. +[target.'cfg(unix)'.dependencies] base64 = "0.22" cryptoki = "0.12" ed25519-dalek = { version = "2.2", default-features = false, features = ["std"] } @@ -21,5 +26,5 @@ tracing.workspace = true tracing-subscriber.workspace = true zeroize = "1" -[dev-dependencies] +[target.'cfg(unix)'.dev-dependencies] tempfile = "3" diff --git a/crates/op-collab-relay-locator-hsm/src/lib.rs b/crates/op-collab-relay-locator-hsm/src/lib.rs index 912f35579..3d88d1b3b 100644 --- a/crates/op-collab-relay-locator-hsm/src/lib.rs +++ b/crates/op-collab-relay-locator-hsm/src/lib.rs @@ -1,15 +1,49 @@ +//! PKCS#11-backed OPLS signer for OpenPencil relay locators. +//! +//! This is a Unix-only daemon. Every guarantee it makes rests on a POSIX +//! primitive for which no audited Windows equivalent is implemented here: +//! +//! * callers are authenticated by Unix-domain-socket peer credentials +//! (`SO_PEERCRED` on Linux, `getpeereid` on the BSDs), never by anything the +//! request payload asserts about itself; +//! * the config and PIN files are accepted only after their owner, mode, and +//! link count are verified, and are opened with `O_NOFOLLOW` so a swapped +//! symlink cannot redirect the read; +//! * the listening socket, its `flock` lock file, and its heartbeat file are +//! created with explicit modes and re-validated against uid/gid/mode +//! expectations before the signer serves a single request; +//! * even the config schema is POSIX-shaped — it carries the expected client +//! uid/gid and a socket path bounded by the `sun_path` limit. +//! +//! Building this on Windows would mean either compiling those checks out, which +//! leaves a signer that still looks functional after its file-ownership and +//! peer-identity guarantees are gone, or inventing an unaudited ACL-based +//! substitute for them. Both are worse than not shipping the daemon there, so +//! the entire crate is gated on `cfg(unix)` and the binary exits with an +//! explicit unsupported-platform error elsewhere. + +#[cfg(unix)] pub mod config; +#[cfg(unix)] pub mod error; +#[cfg(unix)] pub mod pkcs11; +#[cfg(unix)] pub mod protocol; -// The signer daemon speaks over a permission-checked Unix domain socket and -// enforces unix file modes on its secrets; there is no Windows deployment -// target, so the socket server and secure-file layers are unix-only. #[cfg(unix)] pub mod secure_file; #[cfg(unix)] pub mod server; +#[cfg(unix)] pub use config::{KeyConfig, Region, SignerConfig}; +#[cfg(unix)] pub use error::{SignerError, SignerResult}; +#[cfg(unix)] pub use pkcs11::KeyStore; + +/// Reported by the binary on platforms where the signer cannot run. +#[cfg(not(unix))] +pub const UNSUPPORTED_PLATFORM: &str = "the OpenPencil relay locator HSM signer requires a Unix \ +host: it authenticates callers with Unix-domain-socket peer credentials and guards its config \ +and PIN files with POSIX ownership, mode, and link-count checks"; diff --git a/crates/op-collab-relay-locator-hsm/src/main.rs b/crates/op-collab-relay-locator-hsm/src/main.rs index 6f479270b..5f38e6382 100644 --- a/crates/op-collab-relay-locator-hsm/src/main.rs +++ b/crates/op-collab-relay-locator-hsm/src/main.rs @@ -1,14 +1,28 @@ -// The signer only deploys on unix (permission-checked unix socket); other -// hosts get a stub main so workspace-wide checks still build the target. -#![cfg_attr(not(unix), allow(dead_code))] - -use std::{env, path::PathBuf, process::ExitCode}; +use std::process::ExitCode; #[cfg(unix)] -use op_collab_relay_locator_hsm::{secure_file, server, KeyStore, SignerConfig}; -use op_collab_relay_locator_hsm::{SignerError, SignerResult}; +use std::{env, path::PathBuf}; + +#[cfg(unix)] +use op_collab_relay_locator_hsm::{ + secure_file, server, KeyStore, SignerConfig, SignerError, SignerResult, +}; +#[cfg(unix)] use tracing_subscriber::EnvFilter; +// The signer's security model is POSIX-only; see the crate-level documentation +// in lib.rs for why there is no Windows implementation rather than a Windows +// build with the ownership and peer-credential checks compiled out. +#[cfg(not(unix))] +fn main() -> ExitCode { + eprintln!( + "locator HSM signer failed: {}", + op_collab_relay_locator_hsm::UNSUPPORTED_PLATFORM + ); + ExitCode::FAILURE +} + +#[cfg(unix)] enum Command { Serve, Check, @@ -17,6 +31,7 @@ enum Command { Initialize { so_pin_file: PathBuf }, } +#[cfg(unix)] struct Arguments { command: Command, config: PathBuf, @@ -34,13 +49,6 @@ fn main() -> ExitCode { } } -#[cfg(not(unix))] -fn main() -> ExitCode { - init_tracing(); - eprintln!("locator HSM signer requires a unix host"); - ExitCode::FAILURE -} - #[cfg(unix)] fn run() -> SignerResult<()> { let arguments = parse_arguments()?; @@ -79,6 +87,7 @@ fn run() -> SignerResult<()> { } } +#[cfg(unix)] fn parse_arguments() -> SignerResult { let mut arguments = env::args().skip(1); let command = match arguments.next().as_deref() { @@ -118,6 +127,7 @@ fn parse_arguments() -> SignerResult { Ok(Arguments { command, config }) } +#[cfg(unix)] fn usage() -> SignerError { SignerError::Config( "usage: op-collab-relay-locator-hsm --config PATH; \ @@ -126,6 +136,7 @@ fn usage() -> SignerError { ) } +#[cfg(unix)] fn init_tracing() { let filter = env::var("OPENPENCIL_LOCATOR_HSM_LOG") .ok() diff --git a/crates/op-collab-relay-locator-hsm/tests/softhsm.rs b/crates/op-collab-relay-locator-hsm/tests/softhsm.rs index 4f44bf287..ad4fae8c7 100644 --- a/crates/op-collab-relay-locator-hsm/tests/softhsm.rs +++ b/crates/op-collab-relay-locator-hsm/tests/softhsm.rs @@ -1,3 +1,6 @@ +// The crate under test only exists on Unix; see its lib.rs for why. +#![cfg(unix)] + use std::{env, path::PathBuf}; use ed25519_dalek::{Signature, VerifyingKey};