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