apple_security/
policy.rs

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