apple_security_framework/
policy.rs

1//! Security Policies support.
2use std::{fmt, ptr};
3
4#[cfg(any(feature = "OSX_10_9", target_os = "ios"))]
5use core_foundation::base::CFOptionFlags;
6use core_foundation::{base::TCFType, string::CFString};
7#[cfg(any(feature = "OSX_10_9", target_os = "ios"))]
8use security_framework_sys::base::errSecParam;
9use security_framework_sys::{base::SecPolicyRef, policy::*};
10
11use crate::secure_transport::SslProtocolSide;
12#[cfg(any(feature = "OSX_10_9", target_os = "ios"))]
13use crate::Error;
14
15declare_TCFType! {
16    /// A type representing a certificate validation policy.
17    SecPolicy, SecPolicyRef
18}
19impl_TCFType!(SecPolicy, SecPolicyRef, SecPolicyGetTypeID);
20
21unsafe impl Sync for SecPolicy {}
22unsafe impl Send for SecPolicy {}
23
24impl fmt::Debug for SecPolicy {
25    #[cold]
26    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
27        fmt.debug_struct("SecPolicy").finish()
28    }
29}
30
31#[cfg(any(feature = "OSX_10_9", target_os = "ios"))]
32bitflags::bitflags! {
33    /// The flags used to specify revocation policy options.
34    #[derive(Debug, Clone)]
35    pub struct RevocationPolicy: CFOptionFlags {
36        /// Perform revocation checking using OCSP (Online Certificate Status Protocol).
37        const OCSP_METHOD = kSecRevocationOCSPMethod;
38        /// Perform revocation checking using the CRL (Certification Revocation List) method.
39        const CRL_METHOD = kSecRevocationCRLMethod;
40        /// Prefer CRL revocation checking over OCSP; by default, OCSP is preferred.
41        const PREFER_CRL = kSecRevocationPreferCRL;
42        /// Require a positive response to pass the policy.
43        const REQUIRE_POSITIVE_RESPONSE = kSecRevocationRequirePositiveResponse;
44        /// Consult only locally cached replies; do not use network access.
45        const NETWORK_ACCESS_DISABLED = kSecRevocationNetworkAccessDisabled;
46        /// Perform either OCSP or CRL checking.
47        const USE_ANY_METHOD_AVAILABLE = kSecRevocationUseAnyAvailableMethod;
48    }
49}
50
51impl SecPolicy {
52    /// Creates a `SecPolicy` for evaluating SSL certificate chains.
53    ///
54    /// The side which you are evaluating should be provided (i.e. pass `SslSslProtocolSide::SERVER` if
55    /// you are a client looking to validate a server's certificate chain).
56    pub fn create_ssl(protocol_side: SslProtocolSide, hostname: Option<&str>) -> Self {
57        let hostname = hostname.map(CFString::new);
58        let hostname = hostname
59            .as_ref()
60            .map(|s| s.as_concrete_TypeRef())
61            .unwrap_or(ptr::null_mut());
62        let is_server = protocol_side == SslProtocolSide::SERVER;
63        unsafe {
64            let policy = SecPolicyCreateSSL(is_server as _, hostname);
65            Self::wrap_under_create_rule(policy)
66        }
67    }
68
69    #[cfg(any(feature = "OSX_10_9", target_os = "ios"))]
70    /// Creates a `SecPolicy` for checking revocation of certificates.
71    ///
72    /// If you do not specify this policy creating a `SecTrust` object, the system defaults
73    /// will be used during evaluation.
74    pub fn create_revocation(options: RevocationPolicy) -> crate::Result<Self> {
75        let policy = unsafe { SecPolicyCreateRevocation(options.bits()) };
76
77        if policy.is_null() {
78            Err(Error::from_code(errSecParam))
79        } else {
80            Ok(unsafe { Self::wrap_under_create_rule(policy) })
81        }
82    }
83
84    /// Returns a policy object for the default X.509 policy.
85    #[must_use]
86    pub fn create_x509() -> Self {
87        unsafe {
88            let policy = SecPolicyCreateBasicX509();
89            Self::wrap_under_create_rule(policy)
90        }
91    }
92}
93
94#[cfg(test)]
95mod test {
96    use crate::{policy::SecPolicy, secure_transport::SslProtocolSide};
97
98    #[test]
99    fn create_ssl() {
100        SecPolicy::create_ssl(SslProtocolSide::SERVER, Some("certifi.org"));
101    }
102}