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