diff options
| author | mo khan <mo@mokhan.ca> | 2025-07-15 16:37:08 -0600 |
|---|---|---|
| committer | mo khan <mo@mokhan.ca> | 2025-07-17 16:30:22 -0600 |
| commit | 45df4d0d9b577fecee798d672695fe24ff57fb1b (patch) | |
| tree | 1b99bf645035b58e0d6db08c7a83521f41f7a75b /vendor/security-framework/src/os/macos/code_signing.rs | |
| parent | f94f79608393d4ab127db63cc41668445ef6b243 (diff) | |
feat: migrate from Cedar to SpiceDB authorization system
This is a major architectural change that replaces the Cedar policy-based
authorization system with SpiceDB's relation-based authorization.
Key changes:
- Migrate from Rust to Go implementation
- Replace Cedar policies with SpiceDB schema and relationships
- Switch from envoy `ext_authz` with Cedar to SpiceDB permission checks
- Update build system and dependencies for Go ecosystem
- Maintain Envoy integration for external authorization
This change enables more flexible permission modeling through SpiceDB's
Google Zanzibar inspired relation-based system, supporting complex
hierarchical permissions that were difficult to express in Cedar.
Breaking change: Existing Cedar policies and Rust-based configuration
will no longer work and need to be migrated to SpiceDB schema.
Diffstat (limited to 'vendor/security-framework/src/os/macos/code_signing.rs')
| -rw-r--r-- | vendor/security-framework/src/os/macos/code_signing.rs | 486 |
1 files changed, 0 insertions, 486 deletions
diff --git a/vendor/security-framework/src/os/macos/code_signing.rs b/vendor/security-framework/src/os/macos/code_signing.rs deleted file mode 100644 index b42917c1..00000000 --- a/vendor/security-framework/src/os/macos/code_signing.rs +++ /dev/null @@ -1,486 +0,0 @@ -//! Code signing services. - -use std::{fmt::Debug, mem::MaybeUninit, str::FromStr}; - -use core_foundation::{ - base::{TCFType, TCFTypeRef, ToVoid}, - data::CFDataRef, - dictionary::CFMutableDictionary, - number::CFNumber, - string::{CFString, CFStringRef}, - url::CFURL, -}; -use libc::pid_t; -use security_framework_sys::code_signing::{ - kSecCSBasicValidateOnly, kSecCSCheckAllArchitectures, kSecCSCheckGatekeeperArchitectures, - kSecCSCheckNestedCode, kSecCSCheckTrustedAnchors, kSecCSConsiderExpiration, - kSecCSDoNotValidateExecutable, kSecCSDoNotValidateResources, kSecCSEnforceRevocationChecks, - kSecCSFullReport, kSecCSNoNetworkAccess, kSecCSQuickCheck, kSecCSReportProgress, - kSecCSRestrictSidebandData, kSecCSRestrictSymlinks, kSecCSRestrictToAppLike, - kSecCSSingleThreaded, kSecCSStrictValidate, kSecCSUseSoftwareSigningCert, kSecCSValidatePEH, - kSecGuestAttributeAudit, kSecGuestAttributePid, SecCodeCheckValidity, - SecCodeCopyGuestWithAttributes, SecCodeCopyPath, SecCodeCopySelf, SecCodeGetTypeID, SecCodeRef, - SecRequirementCreateWithString, SecRequirementGetTypeID, SecRequirementRef, - SecStaticCodeCheckValidity, SecStaticCodeCreateWithPath, SecStaticCodeGetTypeID, - SecStaticCodeRef, -}; - -use crate::{cvt, Result}; - -bitflags::bitflags! { - - /// Values that can be used in the flags parameter to most code signing - /// functions. - #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] - pub struct Flags: u32 { - /// Use the default behaviour. - const NONE = 0; - - /// For multi-architecture (universal) Mach-O programs, validate all - /// architectures included. - const CHECK_ALL_ARCHITECTURES = kSecCSCheckAllArchitectures; - - /// Do not validate the contents of the main executable. - const DO_NOT_VALIDATE_EXECUTABLE = kSecCSDoNotValidateExecutable; - - /// Do not validate the presence and contents of all bundle resources - /// if any. - const DO_NOT_VALIDATE_RESOURCES = kSecCSDoNotValidateResources; - - /// Do not validate either the main executable or the bundle resources, - /// if any. - const BASIC_VALIDATE_ONLY = kSecCSBasicValidateOnly; - - /// For code in bundle form, locate and recursively check embedded code. - const CHECK_NESTED_CODE = kSecCSCheckNestedCode; - - /// Perform additional checks to ensure the validity of code in bundle - /// form. - const STRICT_VALIDATE = kSecCSStrictValidate; - - /// Apple have not documented this flag. - const FULL_REPORT = kSecCSFullReport; - - /// Apple have not documented this flag. - const CHECK_GATEKEEPER_ARCHITECTURES = kSecCSCheckGatekeeperArchitectures; - - /// Apple have not documented this flag. - const RESTRICT_SYMLINKS = kSecCSRestrictSymlinks; - - /// Apple have not documented this flag. - const RESTRICT_TO_APP_LIKE = kSecCSRestrictToAppLike; - - /// Apple have not documented this flag. - const RESTRICT_SIDEBAND_DATA = kSecCSRestrictSidebandData; - - /// Apple have not documented this flag. - const USE_SOFTWARE_SIGNING_CERT = kSecCSUseSoftwareSigningCert; - - /// Apple have not documented this flag. - const VALIDATE_PEH = kSecCSValidatePEH; - - /// Apple have not documented this flag. - const SINGLE_THREADED = kSecCSSingleThreaded; - - /// Apple have not documented this flag. - const QUICK_CHECK = kSecCSQuickCheck; - - /// Apple have not documented this flag. - const CHECK_TRUSTED_ANCHORS = kSecCSCheckTrustedAnchors; - - /// Apple have not documented this flag. - const REPORT_PROGRESS = kSecCSReportProgress; - - /// Apple have not documented this flag. - const NO_NETWORK_ACCESS = kSecCSNoNetworkAccess; - - /// Apple have not documented this flag. - const ENFORCE_REVOCATION_CHECKS = kSecCSEnforceRevocationChecks; - - /// Apple have not documented this flag. - const CONSIDER_EXPIRATION = kSecCSConsiderExpiration; - } -} - -impl Default for Flags { - #[inline(always)] - fn default() -> Self { - Self::NONE - } -} - -/// A helper to create guest attributes, which are normally passed as a -/// `CFDictionary` with varying types. -pub struct GuestAttributes { - inner: CFMutableDictionary, -} - -impl GuestAttributes { - // Not implemented: - // - architecture - // - canonical - // - dynamic code - // - dynamic code info plist - // - hash - // - mach port - // - sub-architecture - - /// Creates a new, empty `GuestAttributes`. You must add values to it in - /// order for it to be of any use. - #[must_use] - pub fn new() -> Self { - Self { - inner: CFMutableDictionary::new(), - } - } - - /// The guest's audit token. - pub fn set_audit_token(&mut self, token: CFDataRef) { - let key = unsafe { CFString::wrap_under_get_rule(kSecGuestAttributeAudit) }; - self.inner.add(&key.as_CFTypeRef(), &token.to_void()); - } - - /// The guest's pid. - pub fn set_pid(&mut self, pid: pid_t) { - let key = unsafe { CFString::wrap_under_get_rule(kSecGuestAttributePid) }; - let pid = CFNumber::from(pid); - self.inner.add(&key.as_CFTypeRef(), &pid.as_CFTypeRef()); - } - - /// Support for arbirtary guest attributes. - pub fn set_other<V: ToVoid<V>>(&mut self, key: CFStringRef, value: V) { - self.inner.add(&key.as_void_ptr(), &value.to_void()); - } -} - -impl Default for GuestAttributes { - fn default() -> Self { - Self::new() - } -} - -declare_TCFType! { - /// A code object representing signed code running on the system. - SecRequirement, SecRequirementRef -} -impl_TCFType!(SecRequirement, SecRequirementRef, SecRequirementGetTypeID); - -impl FromStr for SecRequirement { - type Err = crate::base::Error; - - fn from_str(s: &str) -> Result<Self, Self::Err> { - let text = CFString::new(s); - let mut requirement = MaybeUninit::uninit(); - - unsafe { - cvt(SecRequirementCreateWithString( - text.as_concrete_TypeRef(), - 0, - requirement.as_mut_ptr(), - ))?; - - Ok(Self::wrap_under_create_rule(requirement.assume_init())) - } - } -} - -declare_TCFType! { - /// A code object representing signed code running on the system. - SecCode, SecCodeRef -} -impl_TCFType!(SecCode, SecCodeRef, SecCodeGetTypeID); - -impl Debug for SecCode { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.write_str("SecCode") - } -} - -impl SecCode { - /// Retrieves the code object for the code making the call. - pub fn for_self(flags: Flags) -> Result<Self> { - let mut code = MaybeUninit::uninit(); - - unsafe { - cvt(SecCodeCopySelf(flags.bits(), code.as_mut_ptr()))?; - Ok(Self::wrap_under_create_rule(code.assume_init())) - } - } - - /// Performs dynamic validation of signed code. - pub fn check_validity(&self, flags: Flags, requirement: &SecRequirement) -> Result<()> { - unsafe { - cvt(SecCodeCheckValidity( - self.as_concrete_TypeRef(), - flags.bits(), - requirement.as_concrete_TypeRef(), - )) - } - } - - /// Asks a code host to identify one of its guests given - /// the type and value of specific attributes of the guest code. - /// - /// If `host` is `None` then the code signing root of trust (currently, the - // system kernel) should be used as the code host. - pub fn copy_guest_with_attribues( - host: Option<&SecCode>, - attrs: &GuestAttributes, - flags: Flags, - ) -> Result<SecCode> { - let mut code = MaybeUninit::uninit(); - - let host = match host { - Some(host) => host.as_concrete_TypeRef(), - None => std::ptr::null_mut(), - }; - - unsafe { - cvt(SecCodeCopyGuestWithAttributes( - host, - attrs.inner.as_concrete_TypeRef(), - flags.bits(), - code.as_mut_ptr(), - ))?; - - Ok(SecCode::wrap_under_create_rule(code.assume_init())) - } - } - - /// Retrieves the location on disk of signed code, given a code or static - /// code object. - pub fn path(&self, flags: Flags) -> Result<CFURL> { - let mut url = MaybeUninit::uninit(); - - // The docs say we can pass a SecCodeRef instead of a SecStaticCodeRef. - unsafe { - cvt(SecCodeCopyPath( - self.as_CFTypeRef() as _, - flags.bits(), - url.as_mut_ptr(), - ))?; - - Ok(CFURL::wrap_under_create_rule(url.assume_init())) - } - } -} - -declare_TCFType! { - /// A static code object representing signed code on disk. - SecStaticCode, SecStaticCodeRef -} -impl_TCFType!(SecStaticCode, SecStaticCodeRef, SecStaticCodeGetTypeID); - -impl SecStaticCode { - /// Creates a static code object representing the code at a specified file - /// system path. - pub fn from_path(path: &CFURL, flags: Flags) -> Result<Self> { - let mut code = MaybeUninit::uninit(); - - unsafe { - cvt(SecStaticCodeCreateWithPath( - path.as_concrete_TypeRef(), - flags.bits(), - code.as_mut_ptr(), - ))?; - - Ok(Self::wrap_under_create_rule(code.assume_init())) - } - } - - /// Retrieves the location on disk of signed code, given a code or static - /// code object. - pub fn path(&self, flags: Flags) -> Result<CFURL> { - let mut url = MaybeUninit::uninit(); - - // The docs say we can pass a SecCodeRef instead of a SecStaticCodeRef. - unsafe { - cvt(SecCodeCopyPath( - self.as_concrete_TypeRef(), - flags.bits(), - url.as_mut_ptr(), - ))?; - - Ok(CFURL::wrap_under_create_rule(url.assume_init())) - } - } - - /// Performs dynamic validation of signed code. - pub fn check_validity(&self, flags: Flags, requirement: &SecRequirement) -> Result<()> { - unsafe { - cvt(SecStaticCodeCheckValidity( - self.as_concrete_TypeRef(), - flags.bits(), - requirement.as_concrete_TypeRef(), - )) - } - } -} - -#[cfg(test)] -mod test { - use super::*; - use core_foundation::data::CFData; - use libc::{c_uint, c_void, KERN_SUCCESS}; - - #[test] - fn path_to_static_code_and_back() { - let path = CFURL::from_path("/bin/bash", false).unwrap(); - let code = SecStaticCode::from_path(&path, Flags::NONE).unwrap(); - assert_eq!(code.path(Flags::NONE).unwrap(), path); - } - - #[test] - fn self_to_path() { - let path = CFURL::from_path(std::env::current_exe().unwrap(), false).unwrap(); - let code = SecCode::for_self(Flags::NONE).unwrap(); - assert_eq!(code.path(Flags::NONE).unwrap(), path); - } - - #[test] - fn bash_is_signed_by_apple() { - let path = CFURL::from_path("/bin/bash", false).unwrap(); - let code = SecStaticCode::from_path(&path, Flags::NONE).unwrap(); - let requirement: SecRequirement = "anchor apple".parse().unwrap(); - code.check_validity(Flags::NONE, &requirement).unwrap(); - } - - #[cfg(target_arch = "aarch64")] - #[test] - fn self_is_not_signed_by_apple() { - let code = SecCode::for_self(Flags::NONE).unwrap(); - let requirement: SecRequirement = "anchor apple".parse().unwrap(); - - assert_eq!( - code.check_validity(Flags::NONE, &requirement) - .unwrap_err() - .code(), - // "code failed to satisfy specified code requirement(s)" - -67050 - ); - } - - #[cfg(not(target_arch = "aarch64"))] - #[test] - fn self_is_not_signed_by_apple() { - let code = SecCode::for_self(Flags::NONE).unwrap(); - let requirement: SecRequirement = "anchor apple".parse().unwrap(); - - assert_eq!( - code.check_validity(Flags::NONE, &requirement) - .unwrap_err() - .code(), - // "code object is not signed at all" - -67062 - ); - } - - #[test] - fn copy_kernel_guest_with_launchd_pid() { - let mut attrs = GuestAttributes::new(); - attrs.set_pid(1); - - assert_eq!( - SecCode::copy_guest_with_attribues(None, &attrs, Flags::NONE) - .unwrap() - .path(Flags::NONE) - .unwrap() - .get_string() - .to_string(), - "file:///sbin/launchd" - ); - } - - #[test] - fn copy_current_guest_with_launchd_pid() { - let host_code = SecCode::for_self(Flags::NONE).unwrap(); - - let mut attrs = GuestAttributes::new(); - attrs.set_pid(1); - - assert_eq!( - SecCode::copy_guest_with_attribues(Some(&host_code), &attrs, Flags::NONE) - .unwrap_err() - .code(), - // "host has no guest with the requested attributes" - -67065 - ); - } - - #[test] - fn copy_kernel_guest_with_unmatched_pid() { - let mut attrs = GuestAttributes::new(); - attrs.set_pid(999_999_999); - - assert_eq!( - SecCode::copy_guest_with_attribues(None, &attrs, Flags::NONE) - .unwrap_err() - .code(), - // "UNIX[No such process]" - 100003 - ); - } - - #[test] - fn copy_kernel_guest_with_current_token() { - let mut token: [u8; 32] = [0; 32]; - let mut token_len = 32u32; - - enum OpaqueTaskName {} - - extern "C" { - fn mach_task_self() -> *const OpaqueTaskName; - fn task_info( - task_name: *const OpaqueTaskName, - task_flavor: u32, - out: *mut c_void, - out_len: *mut u32, - ) -> i32; - } - - const TASK_AUDIT_TOKEN: c_uint = 15; - - let result = unsafe { - task_info( - mach_task_self(), - TASK_AUDIT_TOKEN, - token.as_mut_ptr().cast::<c_void>(), - &mut token_len, - ) - }; - - assert_eq!(result, KERN_SUCCESS); - - let token_data = CFData::from_buffer(&token); - - let mut attrs = GuestAttributes::new(); - attrs.set_audit_token(token_data.as_concrete_TypeRef()); - - assert_eq!( - SecCode::copy_guest_with_attribues(None, &attrs, Flags::NONE) - .unwrap() - .path(Flags::NONE) - .unwrap() - .to_path() - .unwrap(), - std::env::current_exe().unwrap() - ); - } - - #[test] - fn copy_kernel_guest_with_unmatched_token() { - let token: [u8; 32] = [0; 32]; - let token_data = CFData::from_buffer(&token); - - let mut attrs = GuestAttributes::new(); - attrs.set_audit_token(token_data.as_concrete_TypeRef()); - - assert_eq!( - SecCode::copy_guest_with_attribues(None, &attrs, Flags::NONE) - .unwrap_err() - .code(), - // "UNIX[No such process]" - 100003 - ); - } -} |
