Skip to main content

hardware_enclave/internal/core/
signing.rs

1// Copyright 2026 Jay Gowdy
2// SPDX-License-Identifier: MIT
3
4//! Cross-platform binary signing detection and app_name enforcement.
5//!
6//! Ensures unsigned (development/test) binaries can never use the same
7//! identifiers as signed release binaries for ANY storage operation —
8//! keychain, file paths, backend markers, keys directories, etc.
9#![allow(dead_code, unused_imports, unused_qualifications, unreachable_patterns)]
10
11use std::sync::OnceLock;
12
13const UNSIGNED_SUFFIX: &str = "-unsigned";
14
15/// Returns true iff the current binary is considered "signed" for
16/// identity purposes.
17///
18/// Detection logic:
19/// 1. If the exe path contains `/target/` or `\target\`, it's a cargo
20///    build → unsigned.
21/// 2. On macOS: runs `codesign --verify --no-strict` — exit 0 means signed.
22/// 3. On other platforms: if not in `/target/`, assumed signed (there's
23///    no platform-equivalent ACL coupling concern on Windows/Linux, but
24///    we still separate namespaces for development builds).
25///
26/// Result is cached for the process lifetime.
27pub fn is_binary_signed() -> bool {
28    static RESULT: OnceLock<bool> = OnceLock::new();
29    *RESULT.get_or_init(|| {
30        let Ok(exe) = std::env::current_exe() else {
31            return false;
32        };
33        let path = exe.to_string_lossy();
34        if path.contains("/target/") || path.contains("\\target\\") {
35            return false;
36        }
37        is_codesigned(&exe)
38    })
39}
40
41#[cfg(target_os = "macos")]
42fn is_codesigned(exe: &std::path::Path) -> bool {
43    std::process::Command::new("codesign")
44        .args(["--verify", "--no-strict"])
45        .arg(exe)
46        .output()
47        .map(|o| o.status.success())
48        .unwrap_or(false)
49}
50
51#[cfg(not(target_os = "macos"))]
52fn is_codesigned(_exe: &std::path::Path) -> bool {
53    true
54}
55
56/// Ensures the app_name is safe for the current binary's signing state.
57///
58/// - **Unsigned binary**: forcibly appends `-unsigned` if not already present.
59/// - **Signed binary**: returns as-is.
60///
61/// This function is idempotent — calling it multiple times will never
62/// double-suffix.
63pub fn ensure_safe_app_name(app_name: &str) -> String {
64    if is_binary_signed() || app_name.ends_with(UNSIGNED_SUFFIX) {
65        app_name.to_string()
66    } else {
67        format!("{app_name}{UNSIGNED_SUFFIX}")
68    }
69}
70
71#[cfg(test)]
72mod tests {
73    use super::*;
74
75    #[test]
76    fn unsigned_binary_gets_suffix() {
77        assert_eq!(ensure_safe_app_name("gocode-dev"), "gocode-dev-unsigned");
78        assert_eq!(ensure_safe_app_name("sshenc"), "sshenc-unsigned");
79    }
80
81    #[test]
82    fn already_suffixed_not_doubled() {
83        assert_eq!(
84            ensure_safe_app_name("gocode-dev-unsigned"),
85            "gocode-dev-unsigned"
86        );
87    }
88
89    #[test]
90    fn is_binary_signed_false_in_tests() {
91        assert!(!is_binary_signed());
92    }
93}