security_framework/
policy.rs

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