1 /* -*- Mode: rust; rust-indent-offset: 4 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #![allow(non_upper_case_globals)]
8 use core_foundation::array::*;
9 use core_foundation::base::*;
10 use core_foundation::boolean::*;
11 use core_foundation::data::*;
12 use core_foundation::dictionary::*;
13 use core_foundation::error::*;
14 use core_foundation::number::*;
15 use core_foundation::string::*;
16 use libloading::{Library, Symbol};
17 use pkcs11_bindings::*;
18 use rsclientcerts::error::{Error, ErrorType};
19 use rsclientcerts::manager::{ClientCertsBackend, CryptokiObject, Sign, SlotType};
20 use rsclientcerts::util::*;
21 use sha2::{Digest, Sha256};
22 use std::collections::BTreeMap;
23 use std::convert::TryInto;
24 use std::os::raw::c_void;
26 // Normally we would generate this with a build script, but macos is
27 // cross-compiled on linux, and we'd have to figure out e.g. include paths,
28 // etc.. This is easier.
29 include!("bindings_macos.rs");
32 pub struct __SecIdentity(c_void);
33 pub type SecIdentityRef = *const __SecIdentity;
34 declare_TCFType!(SecIdentity, SecIdentityRef);
35 impl_TCFType!(SecIdentity, SecIdentityRef, SecIdentityGetTypeID);
38 pub struct __SecCertificate(c_void);
39 pub type SecCertificateRef = *const __SecCertificate;
40 declare_TCFType!(SecCertificate, SecCertificateRef);
41 impl_TCFType!(SecCertificate, SecCertificateRef, SecCertificateGetTypeID);
44 pub struct __SecKey(c_void);
45 pub type SecKeyRef = *const __SecKey;
46 declare_TCFType!(SecKey, SecKeyRef);
47 impl_TCFType!(SecKey, SecKeyRef, SecKeyGetTypeID);
50 pub struct __SecPolicy(c_void);
51 pub type SecPolicyRef = *const __SecPolicy;
52 declare_TCFType!(SecPolicy, SecPolicyRef);
53 impl_TCFType!(SecPolicy, SecPolicyRef, SecPolicyGetTypeID);
56 pub struct __SecTrust(c_void);
57 pub type SecTrustRef = *const __SecTrust;
58 declare_TCFType!(SecTrust, SecTrustRef);
59 impl_TCFType!(SecTrust, SecTrustRef, SecTrustGetTypeID);
61 type SecCertificateCopyKeyType = unsafe extern "C" fn(SecCertificateRef) -> SecKeyRef;
62 type SecTrustEvaluateWithErrorType =
63 unsafe extern "C" fn(trust: SecTrustRef, error: *mut CFErrorRef) -> bool;
65 #[derive(Ord, Eq, PartialOrd, PartialEq)]
66 enum SecStringConstant {
67 // These are available in macOS 10.13
68 SecKeyAlgorithmRSASignatureDigestPSSSHA1,
69 SecKeyAlgorithmRSASignatureDigestPSSSHA256,
70 SecKeyAlgorithmRSASignatureDigestPSSSHA384,
71 SecKeyAlgorithmRSASignatureDigestPSSSHA512,
74 /// This implementation uses security framework functions and constants that
75 /// are not provided by the version of the SDK we build with. To work around
76 /// this, we attempt to open and dynamically load these functions and symbols
77 /// at runtime. Unfortunately this does mean that if a user is not on a new
78 /// enough version of macOS, they will not be able to use client certificates
79 /// from their keychain in Firefox until they upgrade.
80 struct SecurityFramework<'a> {
81 sec_certificate_copy_key: Symbol<'a, SecCertificateCopyKeyType>,
82 sec_trust_evaluate_with_error: Symbol<'a, SecTrustEvaluateWithErrorType>,
83 sec_string_constants: BTreeMap<SecStringConstant, String>,
87 static ref SECURITY_LIBRARY: Result<Library, String> = unsafe {
88 Library::new("/System/Library/Frameworks/Security.framework/Security")
89 .map_err(|e| e.to_string())
93 impl<'a> SecurityFramework<'a> {
94 fn new() -> Result<SecurityFramework<'a>, Error> {
95 let library = match &*SECURITY_LIBRARY {
96 Ok(library) => library,
97 Err(e) => return Err(error_here!(ErrorType::ExternalError, e.clone())),
99 let sec_certificate_copy_key = unsafe {
101 .get::<SecCertificateCopyKeyType>(b"SecCertificateCopyKey\0")
102 .map_err(|e| error_here!(ErrorType::ExternalError, e.to_string()))?
104 let sec_trust_evaluate_with_error = unsafe {
106 .get::<SecTrustEvaluateWithErrorType>(b"SecTrustEvaluateWithError\0")
107 .map_err(|e| error_here!(ErrorType::ExternalError, e.to_string()))?
109 let mut sec_string_constants = BTreeMap::new();
110 let strings_to_load = vec![
112 b"kSecKeyAlgorithmRSASignatureDigestPSSSHA1\0".as_ref(),
113 SecStringConstant::SecKeyAlgorithmRSASignatureDigestPSSSHA1,
116 b"kSecKeyAlgorithmRSASignatureDigestPSSSHA256\0".as_ref(),
117 SecStringConstant::SecKeyAlgorithmRSASignatureDigestPSSSHA256,
120 b"kSecKeyAlgorithmRSASignatureDigestPSSSHA384\0".as_ref(),
121 SecStringConstant::SecKeyAlgorithmRSASignatureDigestPSSSHA384,
124 b"kSecKeyAlgorithmRSASignatureDigestPSSSHA512\0".as_ref(),
125 SecStringConstant::SecKeyAlgorithmRSASignatureDigestPSSSHA512,
128 for (symbol_name, sec_string_constant) in strings_to_load {
129 let cfstring_symbol = unsafe {
131 .get::<*const CFStringRef>(symbol_name)
132 .map_err(|e| error_here!(ErrorType::ExternalError, e.to_string()))?
134 let cfstring = unsafe { CFString::wrap_under_create_rule(**cfstring_symbol) };
135 sec_string_constants.insert(sec_string_constant, cfstring.to_string());
137 Ok(SecurityFramework {
138 sec_certificate_copy_key,
139 sec_trust_evaluate_with_error,
140 sec_string_constants,
145 struct SecurityFrameworkHolder<'a> {
146 framework: Result<SecurityFramework<'a>, Error>,
149 impl<'a> SecurityFrameworkHolder<'a> {
150 fn new() -> SecurityFrameworkHolder<'a> {
151 SecurityFrameworkHolder {
152 framework: SecurityFramework::new(),
156 /// SecCertificateCopyKey is available in macOS 10.14
157 fn sec_certificate_copy_key(&self, certificate: &SecCertificate) -> Result<SecKey, Error> {
158 match &self.framework {
159 Ok(framework) => unsafe {
161 (framework.sec_certificate_copy_key)(certificate.as_concrete_TypeRef());
162 if result.is_null() {
163 return Err(error_here!(ErrorType::ExternalError));
165 Ok(SecKey::wrap_under_create_rule(result))
167 Err(e) => Err(e.clone()),
171 /// SecTrustEvaluateWithError is available in macOS 10.14
172 fn sec_trust_evaluate_with_error(&self, trust: &SecTrust) -> Result<bool, Error> {
173 match &self.framework {
174 Ok(framework) => unsafe {
175 Ok((framework.sec_trust_evaluate_with_error)(
176 trust.as_concrete_TypeRef(),
177 std::ptr::null_mut(),
180 Err(e) => Err(e.clone()),
184 fn get_sec_string_constant(
186 sec_string_constant: SecStringConstant,
187 ) -> Result<CFString, Error> {
188 match &self.framework {
189 Ok(framework) => match framework.sec_string_constants.get(&sec_string_constant) {
190 Some(string) => Ok(CFString::new(string)),
191 None => Err(error_here!(ErrorType::ExternalError)),
193 Err(e) => Err(e.clone()),
199 static ref SECURITY_FRAMEWORK: SecurityFrameworkHolder<'static> =
200 SecurityFrameworkHolder::new();
203 fn sec_key_create_signature(
205 algorithm: SecKeyAlgorithm,
207 ) -> Result<CFData, Error> {
208 let mut error = std::ptr::null_mut();
209 let signature = unsafe {
210 SecKeyCreateSignature(
211 key.as_concrete_TypeRef(),
213 data.as_concrete_TypeRef(),
217 if signature.is_null() {
218 let error = unsafe { CFError::wrap_under_create_rule(error) };
219 return Err(error_here!(
220 ErrorType::ExternalError,
221 error.description().to_string()
224 Ok(unsafe { CFData::wrap_under_create_rule(signature) })
227 fn sec_key_copy_attributes<T: TCFType>(key: &SecKey) -> CFDictionary<CFString, T> {
228 unsafe { CFDictionary::wrap_under_create_rule(SecKeyCopyAttributes(key.as_concrete_TypeRef())) }
231 fn sec_key_copy_external_representation(key: &SecKey) -> Result<CFData, Error> {
232 let mut error = std::ptr::null_mut();
234 unsafe { SecKeyCopyExternalRepresentation(key.as_concrete_TypeRef(), &mut error) };
235 if representation.is_null() {
236 let error = unsafe { CFError::wrap_under_create_rule(error) };
237 return Err(error_here!(
238 ErrorType::ExternalError,
239 error.description().to_string()
242 Ok(unsafe { CFData::wrap_under_create_rule(representation) })
245 fn sec_identity_copy_certificate(identity: &SecIdentity) -> Result<SecCertificate, Error> {
246 let mut certificate = std::ptr::null();
248 unsafe { SecIdentityCopyCertificate(identity.as_concrete_TypeRef(), &mut certificate) };
249 if status != errSecSuccess {
250 return Err(error_here!(ErrorType::ExternalError, status.to_string()));
252 if certificate.is_null() {
253 return Err(error_here!(ErrorType::ExternalError));
255 Ok(unsafe { SecCertificate::wrap_under_create_rule(certificate) })
258 fn sec_certificate_copy_subject_summary(certificate: &SecCertificate) -> Result<CFString, Error> {
259 let result = unsafe { SecCertificateCopySubjectSummary(certificate.as_concrete_TypeRef()) };
260 if result.is_null() {
261 return Err(error_here!(ErrorType::ExternalError));
263 Ok(unsafe { CFString::wrap_under_create_rule(result) })
266 fn sec_certificate_copy_data(certificate: &SecCertificate) -> Result<CFData, Error> {
267 let result = unsafe { SecCertificateCopyData(certificate.as_concrete_TypeRef()) };
268 if result.is_null() {
269 return Err(error_here!(ErrorType::ExternalError));
271 Ok(unsafe { CFData::wrap_under_create_rule(result) })
274 fn sec_identity_copy_private_key(identity: &SecIdentity) -> Result<SecKey, Error> {
275 let mut key = std::ptr::null();
276 let status = unsafe { SecIdentityCopyPrivateKey(identity.as_concrete_TypeRef(), &mut key) };
277 if status != errSecSuccess {
278 return Err(error_here!(ErrorType::ExternalError));
281 return Err(error_here!(ErrorType::ExternalError));
283 Ok(unsafe { SecKey::wrap_under_create_rule(key) })
293 serial_number: Vec<u8>,
298 fn new_from_identity(identity: &SecIdentity) -> Result<Cert, Error> {
299 let certificate = sec_identity_copy_certificate(identity)?;
300 Cert::new_from_certificate(&certificate)
303 fn new_from_certificate(certificate: &SecCertificate) -> Result<Cert, Error> {
304 let label = sec_certificate_copy_subject_summary(certificate)?;
305 let der = sec_certificate_copy_data(certificate)?;
306 let der = der.bytes().to_vec();
307 let id = Sha256::digest(&der).to_vec();
308 let (serial_number, issuer, subject) = read_encoded_certificate_identifiers(&der)?;
310 class: serialize_uint(CKO_CERTIFICATE)?,
311 token: serialize_uint(CK_TRUE)?,
313 label: label.to_string().into_bytes(),
321 fn class(&self) -> &[u8] {
325 fn token(&self) -> &[u8] {
329 fn id(&self) -> &[u8] {
333 fn label(&self) -> &[u8] {
337 fn value(&self) -> &[u8] {
341 fn issuer(&self) -> &[u8] {
345 fn serial_number(&self) -> &[u8] {
349 fn subject(&self) -> &[u8] {
354 impl CryptokiObject for Cert {
355 fn matches(&self, slot_type: SlotType, attrs: &[(CK_ATTRIBUTE_TYPE, Vec<u8>)]) -> bool {
356 // The modern/legacy slot distinction in theory enables differentiation
357 // between keys that are from modules that can use modern cryptography
358 // (namely EC keys and RSA-PSS signatures) and those that cannot.
359 // However, the function that would enable this
360 // (SecKeyIsAlgorithmSupported) causes a password dialog to appear on
361 // our test machines, so this backend pretends that everything supports
362 // modern crypto for now.
363 if slot_type != SlotType::Modern {
366 for (attr_type, attr_value) in attrs {
367 let comparison = match *attr_type {
368 CKA_CLASS => self.class(),
369 CKA_TOKEN => self.token(),
370 CKA_LABEL => self.label(),
372 CKA_VALUE => self.value(),
373 CKA_ISSUER => self.issuer(),
374 CKA_SERIAL_NUMBER => self.serial_number(),
375 CKA_SUBJECT => self.subject(),
378 if attr_value.as_slice() != comparison {
385 fn get_attribute(&self, attribute: CK_ATTRIBUTE_TYPE) -> Option<&[u8]> {
386 let result = match attribute {
387 CKA_CLASS => self.class(),
388 CKA_TOKEN => self.token(),
389 CKA_LABEL => self.label(),
391 CKA_VALUE => self.value(),
392 CKA_ISSUER => self.issuer(),
393 CKA_SERIAL_NUMBER => self.serial_number(),
394 CKA_SUBJECT => self.subject(),
401 #[allow(clippy::upper_case_acronyms)]
402 #[derive(Clone, Copy, Debug)]
408 #[allow(clippy::upper_case_acronyms)]
409 enum SignParams<'a> {
410 EC(CFString, &'a [u8]),
411 RSA(CFString, &'a [u8]),
414 impl<'a> SignParams<'a> {
418 params: &Option<CK_RSA_PKCS_PSS_PARAMS>,
419 ) -> Result<SignParams<'a>, Error> {
421 KeyType::EC(_) => SignParams::new_ec_params(data),
422 KeyType::RSA => SignParams::new_rsa_params(params, data),
426 fn new_ec_params(data: &'a [u8]) -> Result<SignParams<'a>, Error> {
427 let algorithm = unsafe {
428 CFString::wrap_under_get_rule(match data.len() {
429 20 => kSecKeyAlgorithmECDSASignatureDigestX962SHA1,
430 32 => kSecKeyAlgorithmECDSASignatureDigestX962SHA256,
431 48 => kSecKeyAlgorithmECDSASignatureDigestX962SHA384,
432 64 => kSecKeyAlgorithmECDSASignatureDigestX962SHA512,
434 return Err(error_here!(ErrorType::UnsupportedInput));
438 Ok(SignParams::EC(algorithm, data))
442 params: &Option<CK_RSA_PKCS_PSS_PARAMS>,
444 ) -> Result<SignParams<'a>, Error> {
445 if let Some(pss_params) = params {
447 let algorithm_id = match pss_params.hashAlg {
448 CKM_SHA_1 => SecStringConstant::SecKeyAlgorithmRSASignatureDigestPSSSHA1,
449 CKM_SHA256 => SecStringConstant::SecKeyAlgorithmRSASignatureDigestPSSSHA256,
450 CKM_SHA384 => SecStringConstant::SecKeyAlgorithmRSASignatureDigestPSSSHA384,
451 CKM_SHA512 => SecStringConstant::SecKeyAlgorithmRSASignatureDigestPSSSHA512,
453 return Err(error_here!(ErrorType::UnsupportedInput));
456 SECURITY_FRAMEWORK.get_sec_string_constant(algorithm_id)?
458 return Ok(SignParams::RSA(algorithm, data));
461 // Handle the case where this is a TLS 1.0 MD5/SHA1 hash.
462 if data.len() == 36 {
463 let algorithm = unsafe {
464 CFString::wrap_under_get_rule(kSecKeyAlgorithmRSASignatureDigestPKCS1v15Raw)
466 return Ok(SignParams::RSA(algorithm, data));
468 // Otherwise, `data` should be a DigestInfo.
469 let (digest_oid, hash) = read_digest_info(data)?;
470 let algorithm = unsafe {
471 CFString::wrap_under_create_rule(match digest_oid {
472 OID_BYTES_SHA_256 => kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA256,
473 OID_BYTES_SHA_384 => kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA384,
474 OID_BYTES_SHA_512 => kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA512,
475 OID_BYTES_SHA_1 => kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA1,
476 _ => return Err(error_here!(ErrorType::UnsupportedInput)),
480 Ok(SignParams::RSA(algorithm, hash))
483 fn get_algorithm(&self) -> SecKeyAlgorithm {
485 SignParams::EC(algorithm, _) => algorithm.as_concrete_TypeRef(),
486 SignParams::RSA(algorithm, _) => algorithm.as_concrete_TypeRef(),
490 fn get_data_to_sign(&self) -> &'a [u8] {
492 SignParams::EC(_, data_to_sign) => data_to_sign,
493 SignParams::RSA(_, data_to_sign) => data_to_sign,
499 identity: SecIdentity,
505 modulus: Option<Vec<u8>>,
506 ec_params: Option<Vec<u8>>,
507 key_type_enum: KeyType,
508 key_handle: Option<SecKey>,
512 fn new(identity: &SecIdentity) -> Result<Key, Error> {
513 let certificate = sec_identity_copy_certificate(identity)?;
514 let der = sec_certificate_copy_data(&certificate)?;
515 let id = Sha256::digest(der.bytes()).to_vec();
516 let key = SECURITY_FRAMEWORK.sec_certificate_copy_key(&certificate)?;
517 let key_type: CFString = get_key_attribute(&key, unsafe { kSecAttrKeyType })?;
518 let key_size_in_bits: CFNumber = get_key_attribute(&key, unsafe { kSecAttrKeySizeInBits })?;
519 let mut modulus = None;
520 let mut ec_params = None;
521 let sec_attr_key_type_ec =
522 unsafe { CFString::wrap_under_create_rule(kSecAttrKeyTypeECSECPrimeRandom) };
523 let (key_type_enum, key_type_attribute) =
524 if key_type.as_concrete_TypeRef() == unsafe { kSecAttrKeyTypeRSA } {
525 let public_key = sec_key_copy_external_representation(&key)?;
526 let modulus_value = read_rsa_modulus(public_key.bytes())?;
527 modulus = Some(modulus_value);
528 (KeyType::RSA, CKK_RSA)
529 } else if key_type == sec_attr_key_type_ec {
530 // Assume all EC keys are secp256r1, secp384r1, or secp521r1. This
531 // is wrong, but the API doesn't seem to give us a way to determine
532 // which curve this key is on.
533 // This might not matter in practice, because it seems all NSS uses
534 // this for is to get the signature size.
535 let key_size_in_bits = match key_size_in_bits.to_i64() {
536 Some(value) => value,
537 None => return Err(error_here!(ErrorType::ValueTooLarge)),
539 match key_size_in_bits {
540 256 => ec_params = Some(ENCODED_OID_BYTES_SECP256R1.to_vec()),
541 384 => ec_params = Some(ENCODED_OID_BYTES_SECP384R1.to_vec()),
542 521 => ec_params = Some(ENCODED_OID_BYTES_SECP521R1.to_vec()),
543 _ => return Err(error_here!(ErrorType::UnsupportedInput)),
545 let coordinate_width = (key_size_in_bits as usize + 7) / 8;
546 (KeyType::EC(coordinate_width), CKK_EC)
548 return Err(error_here!(ErrorType::LibraryFailure));
552 identity: identity.clone(),
553 class: serialize_uint(CKO_PRIVATE_KEY)?,
554 token: serialize_uint(CK_TRUE)?,
556 private: serialize_uint(CK_TRUE)?,
557 key_type: serialize_uint(key_type_attribute)?,
565 fn class(&self) -> &[u8] {
569 fn token(&self) -> &[u8] {
573 fn id(&self) -> &[u8] {
577 fn private(&self) -> &[u8] {
581 fn key_type(&self) -> &[u8] {
585 fn modulus(&self) -> Option<&[u8]> {
586 match &self.modulus {
587 Some(modulus) => Some(modulus.as_slice()),
592 fn ec_params(&self) -> Option<&[u8]> {
593 match &self.ec_params {
594 Some(ec_params) => Some(ec_params.as_slice()),
602 params: &Option<CK_RSA_PKCS_PSS_PARAMS>,
603 ) -> Result<Vec<u8>, Error> {
604 // If this key hasn't been used for signing yet, there won't be a cached key handle. Obtain
605 // and cache it if this is the case. Doing so can cause the underlying implementation to
606 // show an authentication or pin prompt to the user. Caching the handle can avoid causing
607 // multiple prompts to be displayed in some cases.
608 if self.key_handle.is_none() {
611 .replace(sec_identity_copy_private_key(&self.identity)?);
613 let key = match &self.key_handle {
615 None => return Err(error_here!(ErrorType::LibraryFailure)),
617 let sign_params = SignParams::new(self.key_type_enum, data, params)?;
618 let signing_algorithm = sign_params.get_algorithm();
619 let data_to_sign = CFData::from_buffer(sign_params.get_data_to_sign());
620 let signature = sec_key_create_signature(key, signing_algorithm, &data_to_sign)?;
621 let signature_value = match self.key_type_enum {
622 KeyType::EC(coordinate_width) => {
623 // We need to convert the DER Ecdsa-Sig-Value to the
624 // concatenation of r and s, the coordinates of the point on
625 // the curve. r and s must be 0-padded to be coordinate_width
627 let (r, s) = read_ec_sig_point(signature.bytes())?;
628 if r.len() > coordinate_width || s.len() > coordinate_width {
629 return Err(error_here!(ErrorType::InvalidInput));
631 let mut signature_value = Vec::with_capacity(2 * coordinate_width);
632 let r_padding = vec![0; coordinate_width - r.len()];
633 signature_value.extend(r_padding);
634 signature_value.extend_from_slice(r);
635 let s_padding = vec![0; coordinate_width - s.len()];
636 signature_value.extend(s_padding);
637 signature_value.extend_from_slice(s);
640 KeyType::RSA => signature.bytes().to_vec(),
646 impl CryptokiObject for Key {
647 fn matches(&self, slot_type: SlotType, attrs: &[(CK_ATTRIBUTE_TYPE, Vec<u8>)]) -> bool {
648 // The modern/legacy slot distinction in theory enables differentiation
649 // between keys that are from modules that can use modern cryptography
650 // (namely EC keys and RSA-PSS signatures) and those that cannot.
651 // However, the function that would enable this
652 // (SecKeyIsAlgorithmSupported) causes a password dialog to appear on
653 // our test machines, so this backend pretends that everything supports
654 // modern crypto for now.
655 if slot_type != SlotType::Modern {
658 for (attr_type, attr_value) in attrs {
659 let comparison = match *attr_type {
660 CKA_CLASS => self.class(),
661 CKA_TOKEN => self.token(),
663 CKA_PRIVATE => self.private(),
664 CKA_KEY_TYPE => self.key_type(),
666 if let Some(modulus) = self.modulus() {
673 if let Some(ec_params) = self.ec_params() {
681 if attr_value.as_slice() != comparison {
688 fn get_attribute(&self, attribute: CK_ATTRIBUTE_TYPE) -> Option<&[u8]> {
690 CKA_CLASS => Some(self.class()),
691 CKA_TOKEN => Some(self.token()),
692 CKA_ID => Some(self.id()),
693 CKA_PRIVATE => Some(self.private()),
694 CKA_KEY_TYPE => Some(self.key_type()),
695 CKA_MODULUS => self.modulus(),
696 CKA_EC_PARAMS => self.ec_params(),
703 fn get_signature_length(
706 params: &Option<CK_RSA_PKCS_PSS_PARAMS>,
707 ) -> Result<usize, Error> {
708 // Unfortunately we don't have a way of getting the length of a signature without creating
710 let dummy_signature_bytes = self.sign(data, params)?;
711 Ok(dummy_signature_bytes.len())
714 // The input data is a hash. What algorithm we use depends on the size of the hash.
718 params: &Option<CK_RSA_PKCS_PSS_PARAMS>,
719 ) -> Result<Vec<u8>, Error> {
720 let result = self.sign_internal(data, params);
724 // Some devices appear to not work well when the key handle is held for too long or if a
725 // card is inserted/removed while Firefox is running. Try refreshing the key handle.
726 let _ = self.key_handle.take();
727 self.sign_internal(data, params)
731 fn get_key_attribute<T: TCFType + Clone>(key: &SecKey, attr: CFStringRef) -> Result<T, Error> {
732 let attributes: CFDictionary<CFString, T> = sec_key_copy_attributes(key);
733 match attributes.find(attr as *const _) {
734 Some(value) => Ok((*value).clone()),
735 None => Err(error_here!(ErrorType::ExternalError)),
739 // Given a SecIdentity, attempts to build as much of a path to a trust anchor as possible, gathers
740 // the CA certificates from that path, and returns them. The purpose of this function is not to
741 // validate the given certificate but to find CA certificates that gecko may need to do path
742 // building when filtering client certificates according to the acceptable CA list sent by the
743 // server during client authentication.
744 fn get_issuers(identity: &SecIdentity) -> Result<Vec<SecCertificate>, Error> {
745 let certificate = sec_identity_copy_certificate(identity)?;
746 let policy = unsafe { SecPolicyCreateSSL(false, std::ptr::null()) };
747 if policy.is_null() {
748 return Err(error_here!(ErrorType::ExternalError));
750 let policy = unsafe { SecPolicy::wrap_under_create_rule(policy) };
751 let mut trust = std::ptr::null();
752 // Each of SecTrustCreateWithCertificates' input arguments can be either single items or an
753 // array of items. Since we only want to specify one of each, we directly specify the arguments.
754 let status = unsafe {
755 SecTrustCreateWithCertificates(
756 certificate.as_concrete_TypeRef(),
757 policy.as_concrete_TypeRef(),
761 if status != errSecSuccess {
762 return Err(error_here!(ErrorType::ExternalError));
765 return Err(error_here!(ErrorType::ExternalError));
767 let trust = unsafe { SecTrust::wrap_under_create_rule(trust) };
768 // Disable AIA fetching so that SecTrustEvaluateWithError doesn't result in network I/O.
769 let status = unsafe { SecTrustSetNetworkFetchAllowed(trust.as_concrete_TypeRef(), 0) };
770 if status != errSecSuccess {
771 return Err(error_here!(ErrorType::ExternalError));
773 // We ignore the return value here because we don't care if the certificate is trusted or not -
774 // we're only doing this to build its issuer chain as much as possible.
775 let _ = SECURITY_FRAMEWORK.sec_trust_evaluate_with_error(&trust)?;
776 let certificate_count = unsafe { SecTrustGetCertificateCount(trust.as_concrete_TypeRef()) };
777 let mut certificates = Vec::with_capacity(
780 .map_err(|_| error_here!(ErrorType::ValueTooLarge))?,
782 for i in 1..certificate_count {
783 let certificate = unsafe { SecTrustGetCertificateAtIndex(trust.as_concrete_TypeRef(), i) };
784 if certificate.is_null() {
785 error!("SecTrustGetCertificateAtIndex returned null certificate?");
788 let certificate = unsafe { SecCertificate::wrap_under_get_rule(certificate) };
789 certificates.push(certificate);
794 pub struct Backend {}
796 impl ClientCertsBackend for Backend {
800 fn find_objects(&self) -> Result<(Vec<Cert>, Vec<Key>), Error> {
801 let mut certs = Vec::new();
802 let mut keys = Vec::new();
803 let identities = unsafe {
804 let class_key = CFString::wrap_under_get_rule(kSecClass);
805 let class_value = CFString::wrap_under_get_rule(kSecClassIdentity);
806 let return_ref_key = CFString::wrap_under_get_rule(kSecReturnRef);
807 let return_ref_value = CFBoolean::wrap_under_get_rule(kCFBooleanTrue);
808 let match_key = CFString::wrap_under_get_rule(kSecMatchLimit);
809 let match_value = CFString::wrap_under_get_rule(kSecMatchLimitAll);
811 (class_key.as_CFType(), class_value.as_CFType()),
812 (return_ref_key.as_CFType(), return_ref_value.as_CFType()),
813 (match_key.as_CFType(), match_value.as_CFType()),
815 let dict = CFDictionary::from_CFType_pairs(&vals);
816 let mut result = std::ptr::null();
817 let status = SecItemCopyMatching(dict.as_CFTypeRef() as CFDictionaryRef, &mut result);
818 if status == errSecItemNotFound {
819 return Ok((certs, keys));
821 if status != errSecSuccess {
822 return Err(error_here!(ErrorType::ExternalError, status.to_string()));
824 if result.is_null() {
825 return Err(error_here!(ErrorType::ExternalError));
827 CFArray::<SecIdentityRef>::wrap_under_create_rule(result as CFArrayRef)
829 for identity in identities.get_all_values().iter() {
830 let identity = unsafe { SecIdentity::wrap_under_get_rule(*identity as SecIdentityRef) };
831 let cert = Cert::new_from_identity(&identity);
832 let key = Key::new(&identity);
833 if let (Ok(cert), Ok(key)) = (cert, key) {
839 if let Ok(issuers) = get_issuers(&identity) {
840 for issuer in issuers {
841 if let Ok(cert) = Cert::new_from_certificate(&issuer) {