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/certificate.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/certificate.rs')
| -rw-r--r-- | vendor/security-framework/src/certificate.rs | 320 |
1 files changed, 0 insertions, 320 deletions
diff --git a/vendor/security-framework/src/certificate.rs b/vendor/security-framework/src/certificate.rs deleted file mode 100644 index 15fa297f..00000000 --- a/vendor/security-framework/src/certificate.rs +++ /dev/null @@ -1,320 +0,0 @@ -//! Certificate support. - -use core_foundation::array::{CFArray, CFArrayRef}; -use core_foundation::base::{TCFType, ToVoid}; -use core_foundation::data::CFData; -use core_foundation::dictionary::CFMutableDictionary; -use core_foundation::string::CFString; -use core_foundation_sys::base::kCFAllocatorDefault; -#[cfg(any(target_os = "ios", target_os = "tvos", target_os = "watchos", target_os = "visionos"))] -use security_framework_sys::base::{errSecNotTrusted, errSecSuccess}; -use security_framework_sys::base::{errSecParam, SecCertificateRef}; -use security_framework_sys::certificate::*; -use security_framework_sys::keychain_item::SecItemDelete; -use std::fmt; -use std::ptr; - -use crate::base::{Error, Result}; -use crate::cvt; -#[cfg(any(feature = "OSX_10_12", target_os = "ios", target_os = "tvos", target_os = "watchos", target_os = "visionos"))] -use crate::key; -#[cfg(target_os = "macos")] -use crate::os::macos::keychain::SecKeychain; -#[cfg(any(feature = "OSX_10_12", target_os = "ios", target_os = "tvos", target_os = "watchos", target_os = "visionos"))] -use core_foundation::base::FromVoid; -#[cfg(any(feature = "OSX_10_13", target_os = "ios", target_os = "tvos", target_os = "watchos", target_os = "visionos"))] -use core_foundation::error::{CFError, CFErrorRef}; -#[cfg(any(feature = "OSX_10_12", target_os = "ios", target_os = "tvos", target_os = "watchos", target_os = "visionos"))] -use core_foundation::number::CFNumber; -#[cfg(feature = "serial-number-bigint")] -use num_bigint::BigUint; -use security_framework_sys::item::kSecValueRef; -#[cfg(any(feature = "OSX_10_12", target_os = "ios", target_os = "tvos", target_os = "watchos", target_os = "visionos"))] -use std::ops::Deref; - -declare_TCFType! { - /// A type representing a certificate. - SecCertificate, SecCertificateRef -} -impl_TCFType!(SecCertificate, SecCertificateRef, SecCertificateGetTypeID); - -unsafe impl Sync for SecCertificate {} -unsafe impl Send for SecCertificate {} - -impl fmt::Debug for SecCertificate { - #[cold] - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt.debug_struct("SecCertificate") - .field("subject", &self.subject_summary()) - .finish() - } -} - -impl SecCertificate { - /// Creates a `SecCertificate` from DER encoded certificate data. - pub fn from_der(der_data: &[u8]) -> Result<Self> { - let der_data = CFData::from_buffer(der_data); - unsafe { - let certificate = - SecCertificateCreateWithData(kCFAllocatorDefault, der_data.as_concrete_TypeRef()); - if certificate.is_null() { - Err(Error::from_code(errSecParam)) - } else { - Ok(Self::wrap_under_create_rule(certificate)) - } - } - } - - /// Returns DER encoded data describing this certificate. - #[must_use] - pub fn to_der(&self) -> Vec<u8> { - unsafe { - let der_data = SecCertificateCopyData(self.0); - CFData::wrap_under_create_rule(der_data).to_vec() - } - } - - /// Adds a certificate to a keychain. - #[cfg(target_os="macos")] - pub fn add_to_keychain(&self, keychain: Option<SecKeychain>) -> Result<()> { - let kch = match keychain { - Some(kch) => kch, - _ => SecKeychain::default()?, - }; - cvt(unsafe { - SecCertificateAddToKeychain(self.as_CFTypeRef() as *mut _, kch.as_CFTypeRef() as *mut _) - }) - } - - /// Returns a human readable summary of this certificate. - #[must_use] - pub fn subject_summary(&self) -> String { - unsafe { - let summary = SecCertificateCopySubjectSummary(self.0); - CFString::wrap_under_create_rule(summary).to_string() - } - } - - /// Returns a vector of email addresses for the subject of the certificate. - pub fn email_addresses(&self) -> Result<Vec<String>, Error> { - let mut array: CFArrayRef = ptr::null(); - unsafe { - cvt(SecCertificateCopyEmailAddresses( - self.as_concrete_TypeRef(), - &mut array, - ))?; - - let array = CFArray::<CFString>::wrap_under_create_rule(array); - Ok(array.into_iter().map(|p| p.to_string()).collect()) - } - } - - #[cfg(any(feature = "OSX_10_12", target_os = "ios", target_os = "tvos", target_os = "watchos", target_os = "visionos"))] - /// Returns DER encoded X.509 distinguished name of the certificate issuer. - #[must_use] - pub fn issuer(&self) -> Vec<u8> { - unsafe { - let issuer = SecCertificateCopyNormalizedIssuerSequence(self.0); - CFData::wrap_under_create_rule(issuer).to_vec() - } - } - - #[cfg(any(feature = "OSX_10_12", target_os = "ios", target_os = "tvos", target_os = "watchos", target_os = "visionos"))] - /// Returns DER encoded X.509 distinguished name of the certificate subject. - #[must_use] - pub fn subject(&self) -> Vec<u8> { - unsafe { - let subject = SecCertificateCopyNormalizedSubjectSequence(self.0); - CFData::wrap_under_create_rule(subject).to_vec() - } - } - - #[cfg(any(feature = "OSX_10_13", target_os = "ios", target_os = "tvos", target_os = "watchos", target_os = "visionos"))] - /// Returns DER encoded serial number of the certificate. - pub fn serial_number_bytes(&self) -> Result<Vec<u8>, CFError> { - unsafe { - let mut error: CFErrorRef = ptr::null_mut(); - let serial_number = SecCertificateCopySerialNumberData(self.0, &mut error); - if error.is_null() { - Ok(CFData::wrap_under_create_rule(serial_number).to_vec()) - } else { - Err(CFError::wrap_under_create_rule(error)) - } - } - } - - /// Use `BigUint::from_bytes_be(serial_number_bytes())` instead - #[deprecated(note = "use serial_number_bytes()")] - #[cfg(feature = "serial-number-bigint")] - pub fn serial_number(&self) -> Result<BigUint, CFError> { - Ok(BigUint::from_bytes_be(&self.serial_number_bytes()?)) - } - - #[cfg(any(feature = "OSX_10_12", target_os = "ios", target_os = "tvos", target_os = "watchos", target_os = "visionos"))] - /// Returns DER encoded subjectPublicKeyInfo of certificate if available. This can be used - /// for certificate pinning. - pub fn public_key_info_der(&self) -> Result<Option<Vec<u8>>> { - // Imported from TrustKit - // https://github.com/datatheorem/TrustKit/blob/master/TrustKit/Pinning/TSKSPKIHashCache.m - let public_key = self.public_key()?; - Ok(self.pk_to_der(public_key)) - } - - #[cfg(any(feature = "OSX_10_12", target_os = "ios", target_os = "tvos", target_os = "watchos", target_os = "visionos"))] - #[must_use] - fn pk_to_der(&self, public_key: key::SecKey) -> Option<Vec<u8>> { - use security_framework_sys::item::kSecAttrKeyType; - use security_framework_sys::item::kSecAttrKeySizeInBits; - - let public_key_attributes = public_key.attributes(); - let public_key_type = public_key_attributes - .find(unsafe { kSecAttrKeyType }.cast::<std::os::raw::c_void>())?; - let public_keysize = public_key_attributes - .find(unsafe { kSecAttrKeySizeInBits }.cast::<std::os::raw::c_void>())?; - let public_keysize = unsafe { CFNumber::from_void(*public_keysize.deref()) }; - let public_keysize_val = public_keysize.to_i64()? as u32; - let hdr_bytes = get_asn1_header_bytes( - unsafe { CFString::wrap_under_get_rule(*public_key_type.deref() as _) }, - public_keysize_val, - )?; - let public_key_data = public_key.external_representation()?; - let mut out = Vec::with_capacity(hdr_bytes.len() + public_key_data.len() as usize); - out.extend_from_slice(hdr_bytes); - out.extend_from_slice(public_key_data.bytes()); - Some(out) - } - - #[cfg(any(feature = "OSX_10_12", target_os = "ios", target_os = "tvos", target_os = "watchos", target_os = "visionos"))] - /// Get public key from certificate - pub fn public_key(&self) -> Result<key::SecKey> { - use crate::policy::SecPolicy; - use crate::trust::SecTrust; - use std::slice::from_ref; - - let policy = SecPolicy::create_x509(); - let mut trust = SecTrust::create_with_certificates(from_ref(self), from_ref(&policy))?; - #[allow(deprecated)] - #[cfg(not(any(target_os = "ios", target_os = "tvos", target_os = "watchos", target_os = "visionos")))] - trust.evaluate()?; - #[cfg(any(target_os = "ios", target_os = "tvos", target_os = "watchos", target_os = "visionos"))] - cvt(match trust.evaluate_with_error() { - Ok(_) => errSecSuccess, - Err(_) => errSecNotTrusted, - })?; - trust.copy_public_key() - } - - /// Translates to `SecItemDelete`, passing in the `SecCertificateRef` - pub fn delete(&self) -> Result<(), Error> { - let query = CFMutableDictionary::from_CFType_pairs(&[( - unsafe { kSecValueRef }.to_void(), - self.to_void(), - )]); - - cvt(unsafe { SecItemDelete(query.as_concrete_TypeRef()) }) - } -} - -#[cfg(any(feature = "OSX_10_12", target_os = "ios", target_os = "tvos", target_os = "watchos", target_os = "visionos"))] -fn get_asn1_header_bytes(pkt: CFString, ksz: u32) -> Option<&'static [u8]> { - use security_framework_sys::item::kSecAttrKeyTypeRSA; - use security_framework_sys::item::kSecAttrKeyTypeECSECPrimeRandom; - - if pkt == unsafe { CFString::wrap_under_get_rule(kSecAttrKeyTypeRSA) } && ksz == 2048 { - return Some(&RSA_2048_ASN1_HEADER); - } - if pkt == unsafe { CFString::wrap_under_get_rule(kSecAttrKeyTypeRSA) } && ksz == 4096 { - return Some(&RSA_4096_ASN1_HEADER); - } - if pkt == unsafe { CFString::wrap_under_get_rule(kSecAttrKeyTypeECSECPrimeRandom) } - && ksz == 256 - { - return Some(&EC_DSA_SECP_256_R1_ASN1_HEADER); - } - if pkt == unsafe { CFString::wrap_under_get_rule(kSecAttrKeyTypeECSECPrimeRandom) } - && ksz == 384 - { - return Some(&EC_DSA_SECP_384_R1_ASN1_HEADER); - } - None -} - -#[cfg(any(feature = "OSX_10_12", target_os = "ios", target_os = "tvos", target_os = "watchos", target_os = "visionos"))] -const RSA_2048_ASN1_HEADER: [u8; 24] = [ - 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, - 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, -]; - -#[cfg(any(feature = "OSX_10_12", target_os = "ios", target_os = "tvos", target_os = "watchos", target_os = "visionos"))] -const RSA_4096_ASN1_HEADER: [u8; 24] = [ - 0x30, 0x82, 0x02, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, - 0x01, 0x05, 0x00, 0x03, 0x82, 0x02, 0x0f, 0x00, -]; - -#[cfg(any(feature = "OSX_10_12", target_os = "ios", target_os = "tvos", target_os = "watchos", target_os = "visionos"))] -const EC_DSA_SECP_256_R1_ASN1_HEADER: [u8; 26] = [ - 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, - 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, -]; - -#[cfg(any(feature = "OSX_10_12", target_os = "ios", target_os = "tvos", target_os = "watchos", target_os = "visionos"))] -const EC_DSA_SECP_384_R1_ASN1_HEADER: [u8; 23] = [ - 0x30, 0x76, 0x30, 0x10, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x05, 0x2b, - 0x81, 0x04, 0x00, 0x22, 0x03, 0x62, 0x00, -]; - -#[cfg(test)] -mod test { - use crate::test::certificate; - #[cfg(feature = "serial-number-bigint")] - use num_bigint::BigUint; - #[cfg(any(feature = "OSX_10_12", target_os = "ios", target_os = "tvos", target_os = "watchos", target_os = "visionos"))] - use x509_parser::prelude::*; - - #[test] - fn subject_summary() { - let cert = certificate(); - assert_eq!("foobar.com", cert.subject_summary()); - } - - #[test] - fn email_addresses() { - let cert = certificate(); - assert_eq!(Vec::<String>::new(), cert.email_addresses().unwrap()); - } - - #[test] - #[cfg(any(feature = "OSX_10_12", target_os = "ios", target_os = "tvos", target_os = "watchos", target_os = "visionos"))] - fn issuer() { - let cert = certificate(); - let issuer = cert.issuer(); - let (_, name) = X509Name::from_der(&issuer).unwrap(); - let name_str = name.to_string_with_registry(oid_registry()).unwrap(); - assert_eq!( - "C=US, ST=CALIFORNIA, L=PALO ALTO, O=FOOBAR LLC, OU=DEV LAND, CN=FOOBAR.COM", - name_str - ); - } - - #[test] - #[cfg(any(feature = "OSX_10_12", target_os = "ios", target_os = "tvos", target_os = "watchos", target_os = "visionos"))] - fn subject() { - let cert = certificate(); - let subject = cert.subject(); - let (_, name) = X509Name::from_der(&subject).unwrap(); - let name_str = name.to_string_with_registry(oid_registry()).unwrap(); - assert_eq!( - "C=US, ST=CALIFORNIA, L=PALO ALTO, O=FOOBAR LLC, OU=DEV LAND, CN=FOOBAR.COM", - name_str - ); - } - - #[test] - #[cfg(feature = "serial-number-bigint")] - #[allow(deprecated)] - fn serial_number() { - let cert = certificate(); - let serial_number = cert.serial_number().unwrap(); - assert_eq!(BigUint::from(16452297291294946383_u128), serial_number); - } -} |
