1 //! Trust evaluation support.
2 
3 use core_foundation::array::CFArray;
4 use core_foundation::base::TCFType;
5 use core_foundation_sys::base::{Boolean, CFIndex};
6 
7 use security_framework_sys::trust::*;
8 use std::ptr;
9 
10 use crate::base::Result;
11 use crate::certificate::SecCertificate;
12 use crate::cvt;
13 use crate::key::SecKey;
14 use crate::policy::SecPolicy;
15 
16 /// The result of trust evaluation.
17 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
18 pub struct TrustResult(SecTrustResultType);
19 
20 impl TrustResult {
21     /// An invalid setting or result.
22     pub const INVALID: Self = Self(kSecTrustResultInvalid);
23 
24     /// You may proceed.
25     pub const PROCEED: Self = Self(kSecTrustResultProceed);
26 
27     /// Indicates a denial by the user, do not proceed.
28     pub const DENY: Self = Self(kSecTrustResultDeny);
29 
30     /// The certificate is implicitly trusted.
31     pub const UNSPECIFIED: Self = Self(kSecTrustResultUnspecified);
32 
33     /// Indicates a trust policy failure that the user can override.
34     pub const RECOVERABLE_TRUST_FAILURE: Self =
35         Self(kSecTrustResultRecoverableTrustFailure);
36 
37     /// Indicates a trust policy failure that the user cannot override.
38     pub const FATAL_TRUST_FAILURE: Self = Self(kSecTrustResultFatalTrustFailure);
39 
40     /// An error not related to trust validation.
41     pub const OTHER_ERROR: Self = Self(kSecTrustResultOtherError);
42 }
43 
44 impl TrustResult {
45     /// Returns true if the result is "successful" - specifically `PROCEED` or `UNSPECIFIED`.
success(self) -> bool46     pub fn success(self) -> bool {
47         match self {
48             Self::PROCEED | Self::UNSPECIFIED => true,
49             _ => false,
50         }
51     }
52 }
53 
54 declare_TCFType! {
55     /// A type representing a trust evaluation for a certificate.
56     SecTrust, SecTrustRef
57 }
58 impl_TCFType!(SecTrust, SecTrustRef, SecTrustGetTypeID);
59 
60 unsafe impl Sync for SecTrust {}
61 unsafe impl Send for SecTrust {}
62 
63 impl SecTrust {
64     /// Creates a SecTrustRef that is configured with a certificate chain, for validating
65     /// that chain against a collection of policies.
create_with_certificates( certs: &[SecCertificate], policies: &[SecPolicy], ) -> Result<Self>66     pub fn create_with_certificates(
67         certs: &[SecCertificate],
68         policies: &[SecPolicy],
69     ) -> Result<Self> {
70         let cert_array = CFArray::from_CFTypes(&certs);
71         let policy_array = CFArray::from_CFTypes(&policies);
72         let mut trust = ptr::null_mut();
73         unsafe {
74             cvt(SecTrustCreateWithCertificates(
75                 cert_array.as_CFTypeRef(),
76                 policy_array.as_CFTypeRef(),
77                 &mut trust,
78             ))?;
79             Ok(Self(trust))
80         }
81     }
82 
83     /// Sets additional anchor certificates used to validate trust.
set_anchor_certificates(&mut self, certs: &[SecCertificate]) -> Result<()>84     pub fn set_anchor_certificates(&mut self, certs: &[SecCertificate]) -> Result<()> {
85         let certs = CFArray::from_CFTypes(&certs);
86 
87         unsafe {
88             cvt(SecTrustSetAnchorCertificates(
89                 self.0,
90                 certs.as_concrete_TypeRef(),
91             ))
92         }
93     }
94 
95     /// If set to `true`, only the certificates specified by
96     /// `set_anchor_certificates` will be trusted, but not globally trusted
97     /// certificates.
set_trust_anchor_certificates_only(&mut self, only: bool) -> Result<()>98     pub fn set_trust_anchor_certificates_only(&mut self, only: bool) -> Result<()> {
99         unsafe { cvt(SecTrustSetAnchorCertificatesOnly(self.0, only as Boolean)) }
100     }
101 
102     /// Sets the policy used to evaluate trust.
set_policy(&mut self, policy: &SecPolicy) -> Result<()>103     pub fn set_policy(&mut self, policy: &SecPolicy) -> Result<()> {
104         unsafe { cvt(SecTrustSetPolicies(self.0, policy.as_CFTypeRef())) }
105     }
106 
107     /// Returns the public key for a leaf certificate after it has been evaluated.
copy_public_key(&mut self) -> Result<SecKey>108     pub fn copy_public_key(&mut self) -> Result<SecKey> {
109         unsafe {
110             Ok(SecKey::wrap_under_create_rule(SecTrustCopyPublicKey(
111                 self.0,
112             )))
113         }
114     }
115 
116     /// Evaluates trust.
117     // FIXME should return &mut self
evaluate(&self) -> Result<TrustResult>118     pub fn evaluate(&self) -> Result<TrustResult> {
119         unsafe {
120             let mut result = kSecTrustResultInvalid;
121             cvt(SecTrustEvaluate(self.0, &mut result))?;
122             Ok(TrustResult(result))
123         }
124     }
125 
126     /// Returns the number of certificates in an evaluated certificate chain.
127     ///
128     /// Note: evaluate must first be called on the SecTrust.
certificate_count(&self) -> CFIndex129     pub fn certificate_count(&self) -> CFIndex {
130         unsafe { SecTrustGetCertificateCount(self.0) }
131     }
132 
133     /// Returns a specific certificate from the certificate chain used to evaluate trust.
134     ///
135     /// Note: evaluate must first be called on the SecTrust.
certificate_at_index(&self, ix: CFIndex) -> Option<SecCertificate>136     pub fn certificate_at_index(&self, ix: CFIndex) -> Option<SecCertificate> {
137         unsafe {
138             if self.certificate_count() <= ix {
139                 None
140             } else {
141                 let certificate = SecTrustGetCertificateAtIndex(self.0, ix);
142                 Some(SecCertificate::wrap_under_get_rule(certificate as *mut _))
143             }
144         }
145     }
146 }
147 
148 #[cfg(test)]
149 mod test {
150     use crate::policy::SecPolicy;
151     use crate::secure_transport::SslProtocolSide;
152     use crate::test::certificate;
153     use crate::trust::SecTrust;
154 
155     #[test]
create_with_certificates()156     fn create_with_certificates() {
157         let cert = certificate();
158         let ssl_policy = SecPolicy::create_ssl(SslProtocolSide::CLIENT, Some("certifi.io"));
159         let trust = SecTrust::create_with_certificates(&[cert], &[ssl_policy]).unwrap();
160         assert_eq!(trust.evaluate().unwrap().success(), false)
161     }
162 
163     #[test]
certificate_count_and_at_index()164     fn certificate_count_and_at_index() {
165         let cert = certificate();
166         let ssl_policy = SecPolicy::create_ssl(SslProtocolSide::CLIENT, Some("certifi.io"));
167         let trust = SecTrust::create_with_certificates(&[cert], &[ssl_policy]).unwrap();
168         trust.evaluate().unwrap();
169 
170         let count = trust.certificate_count();
171         assert_eq!(count, 1);
172 
173         let cert_bytes = trust.certificate_at_index(0).unwrap().to_der();
174         assert_eq!(cert_bytes, certificate().to_der());
175     }
176 
177     #[test]
certificate_at_index_out_of_bounds()178     fn certificate_at_index_out_of_bounds() {
179         let cert = certificate();
180         let ssl_policy = SecPolicy::create_ssl(SslProtocolSide::CLIENT, Some("certifi.io"));
181         let trust = SecTrust::create_with_certificates(&[cert], &[ssl_policy]).unwrap();
182         trust.evaluate().unwrap();
183 
184         assert!(trust.certificate_at_index(1).is_none());
185     }
186 
187     #[test]
set_policy()188     fn set_policy() {
189         let cert = certificate();
190         let ssl_policy = SecPolicy::create_ssl(SslProtocolSide::CLIENT, Some("certifi.io.bogus"));
191         let mut trust = SecTrust::create_with_certificates(&[cert], &[ssl_policy]).unwrap();
192         let ssl_policy = SecPolicy::create_ssl(SslProtocolSide::CLIENT, Some("certifi.io"));
193         trust.set_policy(&ssl_policy).unwrap();
194         assert_eq!(trust.evaluate().unwrap().success(), false)
195     }
196 }
197