no bug - Import translations from android-l10n r=release a=l10n CLOSED TREE
[gecko.git] / security / manager / ssl / osclientcerts / src / backend_macos.rs
blob34386371aa1ef8416e2455887e38ce33b4e41d15
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");
31 #[repr(C)]
32 pub struct __SecIdentity(c_void);
33 pub type SecIdentityRef = *const __SecIdentity;
34 declare_TCFType!(SecIdentity, SecIdentityRef);
35 impl_TCFType!(SecIdentity, SecIdentityRef, SecIdentityGetTypeID);
37 #[repr(C)]
38 pub struct __SecCertificate(c_void);
39 pub type SecCertificateRef = *const __SecCertificate;
40 declare_TCFType!(SecCertificate, SecCertificateRef);
41 impl_TCFType!(SecCertificate, SecCertificateRef, SecCertificateGetTypeID);
43 #[repr(C)]
44 pub struct __SecKey(c_void);
45 pub type SecKeyRef = *const __SecKey;
46 declare_TCFType!(SecKey, SecKeyRef);
47 impl_TCFType!(SecKey, SecKeyRef, SecKeyGetTypeID);
49 #[repr(C)]
50 pub struct __SecPolicy(c_void);
51 pub type SecPolicyRef = *const __SecPolicy;
52 declare_TCFType!(SecPolicy, SecPolicyRef);
53 impl_TCFType!(SecPolicy, SecPolicyRef, SecPolicyGetTypeID);
55 #[repr(C)]
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>,
86 lazy_static! {
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())
90     };
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())),
98         };
99         let sec_certificate_copy_key = unsafe {
100             library
101                 .get::<SecCertificateCopyKeyType>(b"SecCertificateCopyKey\0")
102                 .map_err(|e| error_here!(ErrorType::ExternalError, e.to_string()))?
103         };
104         let sec_trust_evaluate_with_error = unsafe {
105             library
106                 .get::<SecTrustEvaluateWithErrorType>(b"SecTrustEvaluateWithError\0")
107                 .map_err(|e| error_here!(ErrorType::ExternalError, e.to_string()))?
108         };
109         let mut sec_string_constants = BTreeMap::new();
110         let strings_to_load = vec![
111             (
112                 b"kSecKeyAlgorithmRSASignatureDigestPSSSHA1\0".as_ref(),
113                 SecStringConstant::SecKeyAlgorithmRSASignatureDigestPSSSHA1,
114             ),
115             (
116                 b"kSecKeyAlgorithmRSASignatureDigestPSSSHA256\0".as_ref(),
117                 SecStringConstant::SecKeyAlgorithmRSASignatureDigestPSSSHA256,
118             ),
119             (
120                 b"kSecKeyAlgorithmRSASignatureDigestPSSSHA384\0".as_ref(),
121                 SecStringConstant::SecKeyAlgorithmRSASignatureDigestPSSSHA384,
122             ),
123             (
124                 b"kSecKeyAlgorithmRSASignatureDigestPSSSHA512\0".as_ref(),
125                 SecStringConstant::SecKeyAlgorithmRSASignatureDigestPSSSHA512,
126             ),
127         ];
128         for (symbol_name, sec_string_constant) in strings_to_load {
129             let cfstring_symbol = unsafe {
130                 library
131                     .get::<*const CFStringRef>(symbol_name)
132                     .map_err(|e| error_here!(ErrorType::ExternalError, e.to_string()))?
133             };
134             let cfstring = unsafe { CFString::wrap_under_create_rule(**cfstring_symbol) };
135             sec_string_constants.insert(sec_string_constant, cfstring.to_string());
136         }
137         Ok(SecurityFramework {
138             sec_certificate_copy_key,
139             sec_trust_evaluate_with_error,
140             sec_string_constants,
141         })
142     }
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(),
153         }
154     }
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 {
160                 let result =
161                     (framework.sec_certificate_copy_key)(certificate.as_concrete_TypeRef());
162                 if result.is_null() {
163                     return Err(error_here!(ErrorType::ExternalError));
164                 }
165                 Ok(SecKey::wrap_under_create_rule(result))
166             },
167             Err(e) => Err(e.clone()),
168         }
169     }
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(),
178                 ))
179             },
180             Err(e) => Err(e.clone()),
181         }
182     }
184     fn get_sec_string_constant(
185         &self,
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)),
192             },
193             Err(e) => Err(e.clone()),
194         }
195     }
198 lazy_static! {
199     static ref SECURITY_FRAMEWORK: SecurityFrameworkHolder<'static> =
200         SecurityFrameworkHolder::new();
203 fn sec_key_create_signature(
204     key: &SecKey,
205     algorithm: SecKeyAlgorithm,
206     data: &CFData,
207 ) -> Result<CFData, Error> {
208     let mut error = std::ptr::null_mut();
209     let signature = unsafe {
210         SecKeyCreateSignature(
211             key.as_concrete_TypeRef(),
212             algorithm,
213             data.as_concrete_TypeRef(),
214             &mut error,
215         )
216     };
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()
222         ));
223     }
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();
233     let representation =
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()
240         ));
241     }
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();
247     let status =
248         unsafe { SecIdentityCopyCertificate(identity.as_concrete_TypeRef(), &mut certificate) };
249     if status != errSecSuccess {
250         return Err(error_here!(ErrorType::ExternalError, status.to_string()));
251     }
252     if certificate.is_null() {
253         return Err(error_here!(ErrorType::ExternalError));
254     }
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));
262     }
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));
270     }
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));
279     }
280     if key.is_null() {
281         return Err(error_here!(ErrorType::ExternalError));
282     }
283     Ok(unsafe { SecKey::wrap_under_create_rule(key) })
286 pub struct Cert {
287     class: Vec<u8>,
288     token: Vec<u8>,
289     id: Vec<u8>,
290     label: Vec<u8>,
291     value: Vec<u8>,
292     issuer: Vec<u8>,
293     serial_number: Vec<u8>,
294     subject: Vec<u8>,
297 impl Cert {
298     fn new_from_identity(identity: &SecIdentity) -> Result<Cert, Error> {
299         let certificate = sec_identity_copy_certificate(identity)?;
300         Cert::new_from_certificate(&certificate)
301     }
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)?;
309         Ok(Cert {
310             class: serialize_uint(CKO_CERTIFICATE)?,
311             token: serialize_uint(CK_TRUE)?,
312             id,
313             label: label.to_string().into_bytes(),
314             value: der,
315             issuer,
316             serial_number,
317             subject,
318         })
319     }
321     fn class(&self) -> &[u8] {
322         &self.class
323     }
325     fn token(&self) -> &[u8] {
326         &self.token
327     }
329     fn id(&self) -> &[u8] {
330         &self.id
331     }
333     fn label(&self) -> &[u8] {
334         &self.label
335     }
337     fn value(&self) -> &[u8] {
338         &self.value
339     }
341     fn issuer(&self) -> &[u8] {
342         &self.issuer
343     }
345     fn serial_number(&self) -> &[u8] {
346         &self.serial_number
347     }
349     fn subject(&self) -> &[u8] {
350         &self.subject
351     }
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 {
364             return false;
365         }
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(),
371                 CKA_ID => self.id(),
372                 CKA_VALUE => self.value(),
373                 CKA_ISSUER => self.issuer(),
374                 CKA_SERIAL_NUMBER => self.serial_number(),
375                 CKA_SUBJECT => self.subject(),
376                 _ => return false,
377             };
378             if attr_value.as_slice() != comparison {
379                 return false;
380             }
381         }
382         true
383     }
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(),
390             CKA_ID => self.id(),
391             CKA_VALUE => self.value(),
392             CKA_ISSUER => self.issuer(),
393             CKA_SERIAL_NUMBER => self.serial_number(),
394             CKA_SUBJECT => self.subject(),
395             _ => return None,
396         };
397         Some(result)
398     }
401 #[allow(clippy::upper_case_acronyms)]
402 #[derive(Clone, Copy, Debug)]
403 pub enum KeyType {
404     EC(usize),
405     RSA,
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> {
415     fn new(
416         key_type: KeyType,
417         data: &'a [u8],
418         params: &Option<CK_RSA_PKCS_PSS_PARAMS>,
419     ) -> Result<SignParams<'a>, Error> {
420         match key_type {
421             KeyType::EC(_) => SignParams::new_ec_params(data),
422             KeyType::RSA => SignParams::new_rsa_params(params, data),
423         }
424     }
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,
433                 _ => {
434                     return Err(error_here!(ErrorType::UnsupportedInput));
435                 }
436             })
437         };
438         Ok(SignParams::EC(algorithm, data))
439     }
441     fn new_rsa_params(
442         params: &Option<CK_RSA_PKCS_PSS_PARAMS>,
443         data: &'a [u8],
444     ) -> Result<SignParams<'a>, Error> {
445         if let Some(pss_params) = params {
446             let algorithm = {
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,
452                     _ => {
453                         return Err(error_here!(ErrorType::UnsupportedInput));
454                     }
455                 };
456                 SECURITY_FRAMEWORK.get_sec_string_constant(algorithm_id)?
457             };
458             return Ok(SignParams::RSA(algorithm, data));
459         }
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)
465             };
466             return Ok(SignParams::RSA(algorithm, data));
467         }
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)),
477             })
478         };
480         Ok(SignParams::RSA(algorithm, hash))
481     }
483     fn get_algorithm(&self) -> SecKeyAlgorithm {
484         match self {
485             SignParams::EC(algorithm, _) => algorithm.as_concrete_TypeRef(),
486             SignParams::RSA(algorithm, _) => algorithm.as_concrete_TypeRef(),
487         }
488     }
490     fn get_data_to_sign(&self) -> &'a [u8] {
491         match self {
492             SignParams::EC(_, data_to_sign) => data_to_sign,
493             SignParams::RSA(_, data_to_sign) => data_to_sign,
494         }
495     }
498 pub struct Key {
499     identity: SecIdentity,
500     class: Vec<u8>,
501     token: Vec<u8>,
502     id: Vec<u8>,
503     private: Vec<u8>,
504     key_type: Vec<u8>,
505     modulus: Option<Vec<u8>>,
506     ec_params: Option<Vec<u8>>,
507     key_type_enum: KeyType,
508     key_handle: Option<SecKey>,
511 impl Key {
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)),
538                 };
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)),
544                 }
545                 let coordinate_width = (key_size_in_bits as usize + 7) / 8;
546                 (KeyType::EC(coordinate_width), CKK_EC)
547             } else {
548                 return Err(error_here!(ErrorType::LibraryFailure));
549             };
551         Ok(Key {
552             identity: identity.clone(),
553             class: serialize_uint(CKO_PRIVATE_KEY)?,
554             token: serialize_uint(CK_TRUE)?,
555             id,
556             private: serialize_uint(CK_TRUE)?,
557             key_type: serialize_uint(key_type_attribute)?,
558             modulus,
559             ec_params,
560             key_type_enum,
561             key_handle: None,
562         })
563     }
565     fn class(&self) -> &[u8] {
566         &self.class
567     }
569     fn token(&self) -> &[u8] {
570         &self.token
571     }
573     fn id(&self) -> &[u8] {
574         &self.id
575     }
577     fn private(&self) -> &[u8] {
578         &self.private
579     }
581     fn key_type(&self) -> &[u8] {
582         &self.key_type
583     }
585     fn modulus(&self) -> Option<&[u8]> {
586         match &self.modulus {
587             Some(modulus) => Some(modulus.as_slice()),
588             None => None,
589         }
590     }
592     fn ec_params(&self) -> Option<&[u8]> {
593         match &self.ec_params {
594             Some(ec_params) => Some(ec_params.as_slice()),
595             None => None,
596         }
597     }
599     fn sign_internal(
600         &mut self,
601         data: &[u8],
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() {
609             let _ = self
610                 .key_handle
611                 .replace(sec_identity_copy_private_key(&self.identity)?);
612         }
613         let key = match &self.key_handle {
614             Some(key) => key,
615             None => return Err(error_here!(ErrorType::LibraryFailure)),
616         };
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
626                 // total bytes.
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));
630                 }
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);
638                 signature_value
639             }
640             KeyType::RSA => signature.bytes().to_vec(),
641         };
642         Ok(signature_value)
643     }
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 {
656             return false;
657         }
658         for (attr_type, attr_value) in attrs {
659             let comparison = match *attr_type {
660                 CKA_CLASS => self.class(),
661                 CKA_TOKEN => self.token(),
662                 CKA_ID => self.id(),
663                 CKA_PRIVATE => self.private(),
664                 CKA_KEY_TYPE => self.key_type(),
665                 CKA_MODULUS => {
666                     if let Some(modulus) = self.modulus() {
667                         modulus
668                     } else {
669                         return false;
670                     }
671                 }
672                 CKA_EC_PARAMS => {
673                     if let Some(ec_params) = self.ec_params() {
674                         ec_params
675                     } else {
676                         return false;
677                     }
678                 }
679                 _ => return false,
680             };
681             if attr_value.as_slice() != comparison {
682                 return false;
683             }
684         }
685         true
686     }
688     fn get_attribute(&self, attribute: CK_ATTRIBUTE_TYPE) -> Option<&[u8]> {
689         match attribute {
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(),
697             _ => None,
698         }
699     }
702 impl Sign for Key {
703     fn get_signature_length(
704         &mut self,
705         data: &[u8],
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
709         // one.
710         let dummy_signature_bytes = self.sign(data, params)?;
711         Ok(dummy_signature_bytes.len())
712     }
714     // The input data is a hash. What algorithm we use depends on the size of the hash.
715     fn sign(
716         &mut self,
717         data: &[u8],
718         params: &Option<CK_RSA_PKCS_PSS_PARAMS>,
719     ) -> Result<Vec<u8>, Error> {
720         let result = self.sign_internal(data, params);
721         if result.is_ok() {
722             return result;
723         }
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)
728     }
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)),
736     }
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));
749     }
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(),
758             &mut trust,
759         )
760     };
761     if status != errSecSuccess {
762         return Err(error_here!(ErrorType::ExternalError));
763     }
764     if trust.is_null() {
765         return Err(error_here!(ErrorType::ExternalError));
766     }
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));
772     }
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(
778         certificate_count
779             .try_into()
780             .map_err(|_| error_here!(ErrorType::ValueTooLarge))?,
781     );
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?");
786             continue;
787         }
788         let certificate = unsafe { SecCertificate::wrap_under_get_rule(certificate) };
789         certificates.push(certificate);
790     }
791     Ok(certificates)
794 pub struct Backend {}
796 impl ClientCertsBackend for Backend {
797     type Cert = Cert;
798     type Key = Key;
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);
810             let vals = vec![
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()),
814             ];
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));
820             }
821             if status != errSecSuccess {
822                 return Err(error_here!(ErrorType::ExternalError, status.to_string()));
823             }
824             if result.is_null() {
825                 return Err(error_here!(ErrorType::ExternalError));
826             }
827             CFArray::<SecIdentityRef>::wrap_under_create_rule(result as CFArrayRef)
828         };
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) {
834                 certs.push(cert);
835                 keys.push(key);
836             } else {
837                 continue;
838             }
839             if let Ok(issuers) = get_issuers(&identity) {
840                 for issuer in issuers {
841                     if let Ok(cert) = Cert::new_from_certificate(&issuer) {
842                         certs.push(cert);
843                     }
844                 }
845             }
846         }
847         Ok((certs, keys))
848     }