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
This commit is contained in:
Fini 2026-08-09 01:17:29 +08:00
parent 30b11f3584
commit 310f40083d
4 changed files with 72 additions and 19 deletions

View file

@ -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"

View file

@ -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";

View file

@ -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<Arguments> {
let mut arguments = env::args().skip(1);
let command = match arguments.next().as_deref() {
@ -118,6 +127,7 @@ fn parse_arguments() -> SignerResult<Arguments> {
Ok(Arguments { command, config })
}
#[cfg(unix)]
fn usage() -> SignerError {
SignerError::Config(
"usage: op-collab-relay-locator-hsm <serve|check|public> --config PATH; \
@ -126,6 +136,7 @@ fn usage() -> SignerError {
)
}
#[cfg(unix)]
fn init_tracing() {
let filter = env::var("OPENPENCIL_LOCATOR_HSM_LOG")
.ok()

View file

@ -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};