radrootsd

JSON-RPC bridge for Radroots event publishing
git clone https://radroots.dev/git/radrootsd.git
Log | Files | Refs | README | LICENSE

rshr_202_step_303_platform.rs (4116B)


      1 use std::fs;
      2 use std::path::Path;
      3 use std::process::Command;
      4 
      5 use serde_json::{Value, json};
      6 use sha2::{Digest, Sha256};
      7 
      8 const APPLE_TOOLCHAIN_IDENTITY_SHA256: &str =
      9     "fd9bb9af273d0a834c2abff36910edf25f3e5b60c36fcc23b45b738c5c8b2d08";
     10 const PROBE_SOURCE_PATH: &str =
     11     "tools/radroots_scripts/src/radroots_scripts/verify/rshr_200_series.py";
     12 const PROBE_SOURCE_SHA256: &str =
     13     "add949c6c20a037123808230625dfd09dd6fa6c5afe5a856400227191f5de5b5";
     14 const REQUEST_PATH: &str = ".git/rshr-step-303-platform-request-sha256";
     15 
     16 fn root() -> &'static Path {
     17     Path::new(env!("CARGO_MANIFEST_DIR"))
     18         .parent()
     19         .and_then(Path::parent)
     20         .expect("xtask must remain under tools/xtask")
     21 }
     22 
     23 fn canonical(value: &Value) -> Result<Vec<u8>, String> {
     24     serde_json::to_vec(value).map_err(|_| "Step 303 platform JSON encoding failed".to_owned())
     25 }
     26 
     27 fn sha256(bytes: &[u8]) -> String {
     28     hex::encode(Sha256::digest(bytes))
     29 }
     30 
     31 fn uname(flag: &str) -> Result<String, String> {
     32     let output = Command::new("/usr/bin/uname")
     33         .arg(flag)
     34         .output()
     35         .map_err(|_| "Step 303 platform probe could not start uname".to_owned())?;
     36     if !output.status.success() || !output.stderr.is_empty() {
     37         return Err("Step 303 platform probe uname failed".to_owned());
     38     }
     39     let value = std::str::from_utf8(&output.stdout)
     40         .map_err(|_| "Step 303 platform probe uname output is not UTF-8".to_owned())?
     41         .strip_suffix('\n')
     42         .ok_or_else(|| "Step 303 platform probe uname output differs".to_owned())?;
     43     if value.is_empty() || value.contains('\n') || value.contains('\r') {
     44         return Err("Step 303 platform probe uname output differs".to_owned());
     45     }
     46     Ok(value.to_owned())
     47 }
     48 
     49 pub(crate) fn run() -> Result<(), String> {
     50     let request_bytes = fs::read(root().join(REQUEST_PATH))
     51         .map_err(|_| "Step 303 platform execution request is unavailable".to_owned())?;
     52     let raw_request = std::str::from_utf8(&request_bytes)
     53         .map_err(|_| "Step 303 platform execution request is not UTF-8".to_owned())?;
     54     let execution_request_sha256 = raw_request.strip_suffix('\n').unwrap_or(raw_request);
     55     if execution_request_sha256.len() != 64
     56         || !execution_request_sha256
     57             .bytes()
     58             .all(|byte| byte.is_ascii_hexdigit() && !byte.is_ascii_uppercase())
     59     {
     60         return Err("Step 303 platform execution request differs".to_owned());
     61     }
     62 
     63     let kernel_name = uname("-s")?;
     64     let kernel_release = uname("-r")?;
     65     let kernel_version = uname("-v")?;
     66     if kernel_name != "Darwin" || std::env::consts::ARCH != "aarch64" {
     67         return Err("Step 303 platform identity differs".to_owned());
     68     }
     69 
     70     let os_build = json!({
     71         "kernel_name": kernel_name,
     72         "kernel_release": kernel_release,
     73         "kernel_version": kernel_version,
     74     });
     75     let result = json!({
     76         "schema": "radroots.services-hardening.rshr-200-platform-result.v1",
     77         "platform": "macos_aarch64",
     78         "system": "aarch64-darwin",
     79         "os_family": "macos",
     80         "architecture": "aarch64",
     81         "kernel_name": os_build["kernel_name"],
     82         "kernel_release": os_build["kernel_release"],
     83         "os_build_sha256": sha256(&canonical(&os_build)?),
     84         "runner_kind": "host",
     85         "runner_image_sha256": "none",
     86         "apple_toolchain_identity_sha256": APPLE_TOOLCHAIN_IDENTITY_SHA256,
     87         "probe_source_path": PROBE_SOURCE_PATH,
     88         "probe_source_sha256": PROBE_SOURCE_SHA256,
     89         "execution_request_sha256": execution_request_sha256,
     90         "assertion": [
     91             {"id": "os_family", "result": "pass"},
     92             {"id": "architecture", "result": "pass"},
     93             {"id": "kernel_identity", "result": "pass"},
     94             {"id": "runner_identity", "result": "pass"},
     95             {"id": "apple_identity", "result": "pass"},
     96         ],
     97         "result": "available",
     98     });
     99     let mut bytes = canonical(&result)?;
    100     bytes.push(b'\n');
    101     std::io::Write::write_all(&mut std::io::stdout().lock(), &bytes)
    102         .map_err(|_| "Step 303 platform result write failed".to_owned())
    103 }