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/. */
5 
6 #![allow(non_upper_case_globals)]
7 
8 use libloading::{Library, Symbol};
9 use pkcs11::types::*;
10 use sha2::{Digest, Sha256};
11 use std::collections::BTreeMap;
12 use std::convert::TryInto;
13 use std::os::raw::c_void;
14 
15 use core_foundation::array::*;
16 use core_foundation::base::*;
17 use core_foundation::boolean::*;
18 use core_foundation::data::*;
19 use core_foundation::dictionary::*;
20 use core_foundation::error::*;
21 use core_foundation::number::*;
22 use core_foundation::string::*;
23 
24 // Normally we would generate this with a build script, but macos is
25 // cross-compiled on linux, and we'd have to figure out e.g. include paths,
26 // etc.. This is easier.
27 include!("bindings_macos.rs");
28 
29 use crate::manager::SlotType;
30 use crate::util::*;
31 
32 #[repr(C)]
33 pub struct __SecIdentity(c_void);
34 pub type SecIdentityRef = *const __SecIdentity;
35 declare_TCFType!(SecIdentity, SecIdentityRef);
36 impl_TCFType!(SecIdentity, SecIdentityRef, SecIdentityGetTypeID);
37 
38 #[repr(C)]
39 pub struct __SecCertificate(c_void);
40 pub type SecCertificateRef = *const __SecCertificate;
41 declare_TCFType!(SecCertificate, SecCertificateRef);
42 impl_TCFType!(SecCertificate, SecCertificateRef, SecCertificateGetTypeID);
43 
44 #[repr(C)]
45 pub struct __SecKey(c_void);
46 pub type SecKeyRef = *const __SecKey;
47 declare_TCFType!(SecKey, SecKeyRef);
48 impl_TCFType!(SecKey, SecKeyRef, SecKeyGetTypeID);
49 
50 #[repr(C)]
51 pub struct __SecPolicy(c_void);
52 pub type SecPolicyRef = *const __SecPolicy;
53 declare_TCFType!(SecPolicy, SecPolicyRef);
54 impl_TCFType!(SecPolicy, SecPolicyRef, SecPolicyGetTypeID);
55 
56 #[repr(C)]
57 pub struct __SecTrust(c_void);
58 pub type SecTrustRef = *const __SecTrust;
59 declare_TCFType!(SecTrust, SecTrustRef);
60 impl_TCFType!(SecTrust, SecTrustRef, SecTrustGetTypeID);
61 
62 type SecKeyCreateSignatureType =
63     unsafe extern "C" fn(SecKeyRef, SecKeyAlgorithm, CFDataRef, *mut CFErrorRef) -> CFDataRef;
64 type SecKeyCopyAttributesType = unsafe extern "C" fn(SecKeyRef) -> CFDictionaryRef;
65 type SecKeyCopyExternalRepresentationType =
66     unsafe extern "C" fn(SecKeyRef, *mut CFErrorRef) -> CFDataRef;
67 type SecCertificateCopyKeyType = unsafe extern "C" fn(SecCertificateRef) -> SecKeyRef;
68 type SecTrustEvaluateWithErrorType =
69     unsafe extern "C" fn(trust: SecTrustRef, error: *mut CFErrorRef) -> bool;
70 
71 #[derive(Ord, Eq, PartialOrd, PartialEq)]
72 enum SecStringConstant {
73     // These are available in macOS 10.12
74     SecKeyAlgorithmECDSASignatureDigestX962SHA1,
75     SecKeyAlgorithmECDSASignatureDigestX962SHA256,
76     SecKeyAlgorithmECDSASignatureDigestX962SHA384,
77     SecKeyAlgorithmECDSASignatureDigestX962SHA512,
78     SecKeyAlgorithmRSASignatureDigestPKCS1v15Raw,
79     SecKeyAlgorithmRSASignatureDigestPKCS1v15SHA256,
80     SecKeyAlgorithmRSASignatureDigestPKCS1v15SHA384,
81     SecKeyAlgorithmRSASignatureDigestPKCS1v15SHA512,
82     SecKeyAlgorithmRSASignatureDigestPKCS1v15SHA1,
83     SecAttrKeyTypeECSECPrimeRandom,
84     // These are available in macOS 10.13
85     SecKeyAlgorithmRSASignatureDigestPSSSHA1,
86     SecKeyAlgorithmRSASignatureDigestPSSSHA256,
87     SecKeyAlgorithmRSASignatureDigestPSSSHA384,
88     SecKeyAlgorithmRSASignatureDigestPSSSHA512,
89 }
90 
91 // NB: This is not meant to be used outside of this module. It has to be made public because
92 // `RentedSecurityFramework` must be public in the rental declaration.
93 pub struct SecurityFrameworkFunctions<'a> {
94     sec_key_create_signature: Symbol<'a, SecKeyCreateSignatureType>,
95     sec_key_copy_attributes: Symbol<'a, SecKeyCopyAttributesType>,
96     sec_key_copy_external_representation: Symbol<'a, SecKeyCopyExternalRepresentationType>,
97     sec_certificate_copy_key: Symbol<'a, SecCertificateCopyKeyType>,
98     sec_trust_evaluate_with_error: Symbol<'a, SecTrustEvaluateWithErrorType>,
99     sec_string_constants: BTreeMap<SecStringConstant, String>,
100 }
101 
102 rental! {
103     mod rent_libloading {
104         use super::*;
105 
106         #[rental]
107         pub struct RentedSecurityFramework {
108             library: Box<Library>, // Library needs to be StableDeref, hence the Box
109             functions: SecurityFrameworkFunctions<'library>,
110         }
111     }
112 }
113 
114 /// This implementation uses security framework functions and constants that
115 /// are not provided by the version of the SDK we build with. To work around
116 /// this, we attempt to open and dynamically load these functions and symbols
117 /// at runtime. Unfortunately this does mean that if a user is not on a new
118 /// enough version of macOS, they will not be able to use client certificates
119 /// from their keychain in Firefox until they upgrade.
120 struct SecurityFramework {
121     rental: Option<rent_libloading::RentedSecurityFramework>,
122 }
123 
124 impl SecurityFramework {
new() -> SecurityFramework125     fn new() -> SecurityFramework {
126         let library = match Library::new("/System/Library/Frameworks/Security.framework/Security") {
127             Ok(library) => library,
128             Err(_) => return SecurityFramework { rental: None },
129         };
130         match rent_libloading::RentedSecurityFramework::try_new::<_, ()>(
131             Box::new(library),
132             |library| unsafe {
133                 let sec_key_create_signature = library
134                     .get::<SecKeyCreateSignatureType>(b"SecKeyCreateSignature\0")
135                     .map_err(|_| ())?;
136                 let sec_key_copy_attributes = library
137                     .get::<SecKeyCopyAttributesType>(b"SecKeyCopyAttributes\0")
138                     .map_err(|_| ())?;
139                 let sec_key_copy_external_representation = library
140                     .get::<SecKeyCopyExternalRepresentationType>(
141                         b"SecKeyCopyExternalRepresentation\0",
142                     )
143                     .map_err(|_| ())?;
144                 let sec_certificate_copy_key = library
145                     .get::<SecCertificateCopyKeyType>(b"SecCertificateCopyKey\0")
146                     .map_err(|_| ())?;
147                 let sec_trust_evaluate_with_error = library
148                     .get::<SecTrustEvaluateWithErrorType>(b"SecTrustEvaluateWithError\0")
149                     .map_err(|_| ())?;
150                 let mut sec_string_constants = BTreeMap::new();
151                 let strings_to_load = vec![
152                     (
153                         b"kSecKeyAlgorithmECDSASignatureDigestX962SHA1\0".as_ref(),
154                         SecStringConstant::SecKeyAlgorithmECDSASignatureDigestX962SHA1,
155                     ),
156                     (
157                         b"kSecKeyAlgorithmECDSASignatureDigestX962SHA256\0".as_ref(),
158                         SecStringConstant::SecKeyAlgorithmECDSASignatureDigestX962SHA256,
159                     ),
160                     (
161                         b"kSecKeyAlgorithmECDSASignatureDigestX962SHA384\0".as_ref(),
162                         SecStringConstant::SecKeyAlgorithmECDSASignatureDigestX962SHA384,
163                     ),
164                     (
165                         b"kSecKeyAlgorithmECDSASignatureDigestX962SHA512\0".as_ref(),
166                         SecStringConstant::SecKeyAlgorithmECDSASignatureDigestX962SHA512,
167                     ),
168                     (
169                         b"kSecKeyAlgorithmRSASignatureDigestPKCS1v15Raw\0".as_ref(),
170                         SecStringConstant::SecKeyAlgorithmRSASignatureDigestPKCS1v15Raw,
171                     ),
172                     (
173                         b"kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA256\0".as_ref(),
174                         SecStringConstant::SecKeyAlgorithmRSASignatureDigestPKCS1v15SHA256,
175                     ),
176                     (
177                         b"kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA384\0".as_ref(),
178                         SecStringConstant::SecKeyAlgorithmRSASignatureDigestPKCS1v15SHA384,
179                     ),
180                     (
181                         b"kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA512\0".as_ref(),
182                         SecStringConstant::SecKeyAlgorithmRSASignatureDigestPKCS1v15SHA512,
183                     ),
184                     (
185                         b"kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA1\0".as_ref(),
186                         SecStringConstant::SecKeyAlgorithmRSASignatureDigestPKCS1v15SHA1,
187                     ),
188                     (
189                         b"kSecKeyAlgorithmRSASignatureDigestPSSSHA1\0".as_ref(),
190                         SecStringConstant::SecKeyAlgorithmRSASignatureDigestPSSSHA1,
191                     ),
192                     (
193                         b"kSecKeyAlgorithmRSASignatureDigestPSSSHA256\0".as_ref(),
194                         SecStringConstant::SecKeyAlgorithmRSASignatureDigestPSSSHA256,
195                     ),
196                     (
197                         b"kSecKeyAlgorithmRSASignatureDigestPSSSHA384\0".as_ref(),
198                         SecStringConstant::SecKeyAlgorithmRSASignatureDigestPSSSHA384,
199                     ),
200                     (
201                         b"kSecKeyAlgorithmRSASignatureDigestPSSSHA512\0".as_ref(),
202                         SecStringConstant::SecKeyAlgorithmRSASignatureDigestPSSSHA512,
203                     ),
204                     (
205                         b"kSecAttrKeyTypeECSECPrimeRandom\0".as_ref(),
206                         SecStringConstant::SecAttrKeyTypeECSECPrimeRandom,
207                     ),
208                 ];
209                 for (symbol_name, sec_string_constant) in strings_to_load {
210                     let cfstring_symbol = library
211                         .get::<*const CFStringRef>(symbol_name)
212                         .map_err(|_| ())?;
213                     let cfstring = CFString::wrap_under_create_rule(**cfstring_symbol);
214                     sec_string_constants.insert(sec_string_constant, cfstring.to_string());
215                 }
216                 Ok(SecurityFrameworkFunctions {
217                     sec_key_create_signature,
218                     sec_key_copy_attributes,
219                     sec_key_copy_external_representation,
220                     sec_certificate_copy_key,
221                     sec_trust_evaluate_with_error,
222                     sec_string_constants,
223                 })
224             },
225         ) {
226             Ok(rental) => SecurityFramework {
227                 rental: Some(rental),
228             },
229             Err(_) => SecurityFramework { rental: None },
230         }
231     }
232 
233     /// SecKeyCreateSignature is available in macOS 10.12
sec_key_create_signature( &self, key: &SecKey, algorithm: SecKeyAlgorithm, data_to_sign: &CFData, ) -> Result<CFData, ()>234     fn sec_key_create_signature(
235         &self,
236         key: &SecKey,
237         algorithm: SecKeyAlgorithm,
238         data_to_sign: &CFData,
239     ) -> Result<CFData, ()> {
240         match &self.rental {
241             Some(rental) => rental.rent(|framework| unsafe {
242                 let mut error = std::ptr::null_mut();
243                 let result = (framework.sec_key_create_signature)(
244                     key.as_concrete_TypeRef(),
245                     algorithm,
246                     data_to_sign.as_concrete_TypeRef(),
247                     &mut error,
248                 );
249                 if result.is_null() {
250                     let error = CFError::wrap_under_create_rule(error);
251                     error!("SecKeyCreateSignature failed: {}", error);
252                     return Err(());
253                 }
254                 Ok(CFData::wrap_under_create_rule(result))
255             }),
256             None => Err(()),
257         }
258     }
259 
260     /// SecKeyCopyAttributes is available in macOS 10.12
sec_key_copy_attributes<T>(&self, key: &SecKey) -> Result<CFDictionary<CFString, T>, ()>261     fn sec_key_copy_attributes<T>(&self, key: &SecKey) -> Result<CFDictionary<CFString, T>, ()> {
262         match &self.rental {
263             Some(rental) => rental.rent(|framework| unsafe {
264                 let result = (framework.sec_key_copy_attributes)(key.as_concrete_TypeRef());
265                 if result.is_null() {
266                     error!("SecKeyCopyAttributes failed");
267                     return Err(());
268                 }
269                 Ok(CFDictionary::wrap_under_create_rule(result))
270             }),
271             None => Err(()),
272         }
273     }
274 
275     /// SecKeyCopyExternalRepresentation is available in macOS 10.12
sec_key_copy_external_representation(&self, key: &SecKey) -> Result<CFData, ()>276     fn sec_key_copy_external_representation(&self, key: &SecKey) -> Result<CFData, ()> {
277         match &self.rental {
278             Some(rental) => rental.rent(|framework| unsafe {
279                 let mut error = std::ptr::null_mut();
280                 let result = (framework.sec_key_copy_external_representation)(
281                     key.as_concrete_TypeRef(),
282                     &mut error,
283                 );
284                 if result.is_null() {
285                     let error = CFError::wrap_under_create_rule(error);
286                     error!("SecKeyCopyExternalRepresentation failed: {}", error);
287                     return Err(());
288                 }
289                 Ok(CFData::wrap_under_create_rule(result))
290             }),
291             None => Err(()),
292         }
293     }
294 
295     /// SecCertificateCopyKey is available in macOS 10.14
sec_certificate_copy_key(&self, certificate: &SecCertificate) -> Result<SecKey, ()>296     fn sec_certificate_copy_key(&self, certificate: &SecCertificate) -> Result<SecKey, ()> {
297         match &self.rental {
298             Some(rental) => rental.rent(|framework| unsafe {
299                 let result =
300                     (framework.sec_certificate_copy_key)(certificate.as_concrete_TypeRef());
301                 if result.is_null() {
302                     error!("SecCertificateCopyKey failed");
303                     return Err(());
304                 }
305                 Ok(SecKey::wrap_under_create_rule(result))
306             }),
307             None => Err(()),
308         }
309     }
310 
311     /// SecTrustEvaluateWithError is available in macOS 10.14
sec_trust_evaluate_with_error(&self, trust: &SecTrust) -> Result<bool, ()>312     fn sec_trust_evaluate_with_error(&self, trust: &SecTrust) -> Result<bool, ()> {
313         match &self.rental {
314             Some(rental) => rental.rent(|framework| unsafe {
315                 Ok((framework.sec_trust_evaluate_with_error)(
316                     trust.as_concrete_TypeRef(),
317                     std::ptr::null_mut(),
318                 ))
319             }),
320             None => Err(()),
321         }
322     }
323 
get_sec_string_constant( &self, sec_string_constant: SecStringConstant, ) -> Result<CFString, ()>324     fn get_sec_string_constant(
325         &self,
326         sec_string_constant: SecStringConstant,
327     ) -> Result<CFString, ()> {
328         match &self.rental {
329             Some(rental) => rental.rent(|framework| {
330                 match framework.sec_string_constants.get(&sec_string_constant) {
331                     Some(string) => Ok(CFString::new(string)),
332                     None => Err(()),
333                 }
334             }),
335             None => Err(()),
336         }
337     }
338 }
339 
340 lazy_static! {
341     static ref SECURITY_FRAMEWORK: SecurityFramework = SecurityFramework::new();
342 }
343 
sec_identity_copy_certificate(identity: &SecIdentity) -> Result<SecCertificate, ()>344 fn sec_identity_copy_certificate(identity: &SecIdentity) -> Result<SecCertificate, ()> {
345     let mut certificate = std::ptr::null();
346     let status =
347         unsafe { SecIdentityCopyCertificate(identity.as_concrete_TypeRef(), &mut certificate) };
348     if status != errSecSuccess {
349         error!("SecIdentityCopyCertificate failed: {}", status);
350         return Err(());
351     }
352     if certificate.is_null() {
353         error!("couldn't get certificate from identity?");
354         return Err(());
355     }
356     Ok(unsafe { SecCertificate::wrap_under_create_rule(certificate) })
357 }
358 
sec_certificate_copy_subject_summary(certificate: &SecCertificate) -> Result<CFString, ()>359 fn sec_certificate_copy_subject_summary(certificate: &SecCertificate) -> Result<CFString, ()> {
360     let result = unsafe { SecCertificateCopySubjectSummary(certificate.as_concrete_TypeRef()) };
361     if result.is_null() {
362         error!("SecCertificateCopySubjectSummary failed");
363         return Err(());
364     }
365     Ok(unsafe { CFString::wrap_under_create_rule(result) })
366 }
367 
sec_certificate_copy_data(certificate: &SecCertificate) -> Result<CFData, ()>368 fn sec_certificate_copy_data(certificate: &SecCertificate) -> Result<CFData, ()> {
369     let result = unsafe { SecCertificateCopyData(certificate.as_concrete_TypeRef()) };
370     if result.is_null() {
371         error!("SecCertificateCopyData failed");
372         return Err(());
373     }
374     Ok(unsafe { CFData::wrap_under_create_rule(result) })
375 }
376 
sec_identity_copy_private_key(identity: &SecIdentity) -> Result<SecKey, ()>377 fn sec_identity_copy_private_key(identity: &SecIdentity) -> Result<SecKey, ()> {
378     let mut key = std::ptr::null();
379     let status = unsafe { SecIdentityCopyPrivateKey(identity.as_concrete_TypeRef(), &mut key) };
380     if status != errSecSuccess {
381         error!("SecIdentityCopyPrivateKey failed: {}", status);
382         return Err(());
383     }
384     if key.is_null() {
385         error!("SecIdentityCopyPrivateKey didn't set key?");
386         return Err(());
387     }
388     Ok(unsafe { SecKey::wrap_under_create_rule(key) })
389 }
390 
391 pub struct Cert {
392     class: Vec<u8>,
393     token: Vec<u8>,
394     id: Vec<u8>,
395     label: Vec<u8>,
396     value: Vec<u8>,
397     issuer: Vec<u8>,
398     serial_number: Vec<u8>,
399     subject: Vec<u8>,
400 }
401 
402 impl Cert {
new_from_identity(identity: &SecIdentity) -> Result<Cert, ()>403     fn new_from_identity(identity: &SecIdentity) -> Result<Cert, ()> {
404         let certificate = sec_identity_copy_certificate(identity)?;
405         Cert::new_from_certificate(&certificate)
406     }
407 
new_from_certificate(certificate: &SecCertificate) -> Result<Cert, ()>408     fn new_from_certificate(certificate: &SecCertificate) -> Result<Cert, ()> {
409         let label = sec_certificate_copy_subject_summary(certificate)?;
410         let der = sec_certificate_copy_data(certificate)?;
411         let der = der.bytes().to_vec();
412         let id = Sha256::digest(&der).to_vec();
413         let (serial_number, issuer, subject) = read_encoded_certificate_identifiers(&der)?;
414         Ok(Cert {
415             class: serialize_uint(CKO_CERTIFICATE)?,
416             token: serialize_uint(CK_TRUE)?,
417             id,
418             label: label.to_string().into_bytes(),
419             value: der,
420             issuer,
421             serial_number,
422             subject,
423         })
424     }
425 
class(&self) -> &[u8]426     fn class(&self) -> &[u8] {
427         &self.class
428     }
429 
token(&self) -> &[u8]430     fn token(&self) -> &[u8] {
431         &self.token
432     }
433 
id(&self) -> &[u8]434     pub fn id(&self) -> &[u8] {
435         &self.id
436     }
437 
label(&self) -> &[u8]438     fn label(&self) -> &[u8] {
439         &self.label
440     }
441 
value(&self) -> &[u8]442     fn value(&self) -> &[u8] {
443         &self.value
444     }
445 
issuer(&self) -> &[u8]446     fn issuer(&self) -> &[u8] {
447         &self.issuer
448     }
449 
serial_number(&self) -> &[u8]450     fn serial_number(&self) -> &[u8] {
451         &self.serial_number
452     }
453 
subject(&self) -> &[u8]454     fn subject(&self) -> &[u8] {
455         &self.subject
456     }
457 
matches(&self, attrs: &[(CK_ATTRIBUTE_TYPE, Vec<u8>)]) -> bool458     fn matches(&self, attrs: &[(CK_ATTRIBUTE_TYPE, Vec<u8>)]) -> bool {
459         for (attr_type, attr_value) in attrs {
460             let comparison = match *attr_type {
461                 CKA_CLASS => self.class(),
462                 CKA_TOKEN => self.token(),
463                 CKA_LABEL => self.label(),
464                 CKA_ID => self.id(),
465                 CKA_VALUE => self.value(),
466                 CKA_ISSUER => self.issuer(),
467                 CKA_SERIAL_NUMBER => self.serial_number(),
468                 CKA_SUBJECT => self.subject(),
469                 _ => return false,
470             };
471             if attr_value.as_slice() != comparison {
472                 return false;
473             }
474         }
475         true
476     }
477 
get_attribute(&self, attribute: CK_ATTRIBUTE_TYPE) -> Option<&[u8]>478     fn get_attribute(&self, attribute: CK_ATTRIBUTE_TYPE) -> Option<&[u8]> {
479         let result = match attribute {
480             CKA_CLASS => self.class(),
481             CKA_TOKEN => self.token(),
482             CKA_LABEL => self.label(),
483             CKA_ID => self.id(),
484             CKA_VALUE => self.value(),
485             CKA_ISSUER => self.issuer(),
486             CKA_SERIAL_NUMBER => self.serial_number(),
487             CKA_SUBJECT => self.subject(),
488             _ => return None,
489         };
490         Some(result)
491     }
492 }
493 
494 #[derive(Clone, Copy, Debug)]
495 pub enum KeyType {
496     EC(usize),
497     RSA,
498 }
499 
500 enum SignParams<'a> {
501     EC(CFString, &'a [u8]),
502     RSA(CFString, &'a [u8]),
503 }
504 
505 impl<'a> SignParams<'a> {
new( key_type: KeyType, data: &'a [u8], params: &Option<CK_RSA_PKCS_PSS_PARAMS>, ) -> Result<SignParams<'a>, ()>506     fn new(
507         key_type: KeyType,
508         data: &'a [u8],
509         params: &Option<CK_RSA_PKCS_PSS_PARAMS>,
510     ) -> Result<SignParams<'a>, ()> {
511         match key_type {
512             KeyType::EC(_) => SignParams::new_ec_params(data),
513             KeyType::RSA => SignParams::new_rsa_params(params, data),
514         }
515     }
516 
new_ec_params(data: &'a [u8]) -> Result<SignParams<'a>, ()>517     fn new_ec_params(data: &'a [u8]) -> Result<SignParams<'a>, ()> {
518         let algorithm_id = match data.len() {
519             20 => SecStringConstant::SecKeyAlgorithmECDSASignatureDigestX962SHA1,
520             32 => SecStringConstant::SecKeyAlgorithmECDSASignatureDigestX962SHA256,
521             48 => SecStringConstant::SecKeyAlgorithmECDSASignatureDigestX962SHA384,
522             64 => SecStringConstant::SecKeyAlgorithmECDSASignatureDigestX962SHA512,
523             _ => {
524                 error!(
525                     "Unexpected digested signature input length for ECDSA: {}",
526                     data.len()
527                 );
528                 return Err(());
529             }
530         };
531         let algorithm = SECURITY_FRAMEWORK.get_sec_string_constant(algorithm_id)?;
532         Ok(SignParams::EC(algorithm, data))
533     }
534 
new_rsa_params( params: &Option<CK_RSA_PKCS_PSS_PARAMS>, data: &'a [u8], ) -> Result<SignParams<'a>, ()>535     fn new_rsa_params(
536         params: &Option<CK_RSA_PKCS_PSS_PARAMS>,
537         data: &'a [u8],
538     ) -> Result<SignParams<'a>, ()> {
539         if let Some(pss_params) = params {
540             let algorithm = {
541                 let algorithm_id = match pss_params.hashAlg {
542                     CKM_SHA_1 => SecStringConstant::SecKeyAlgorithmRSASignatureDigestPSSSHA1,
543                     CKM_SHA256 => SecStringConstant::SecKeyAlgorithmRSASignatureDigestPSSSHA256,
544                     CKM_SHA384 => SecStringConstant::SecKeyAlgorithmRSASignatureDigestPSSSHA384,
545                     CKM_SHA512 => SecStringConstant::SecKeyAlgorithmRSASignatureDigestPSSSHA512,
546                     _ => {
547                         error!(
548                             "unsupported algorithm to use with RSA-PSS: {}",
549                             unsafe_packed_field_access!(pss_params.hashAlg)
550                         );
551                         return Err(());
552                     }
553                 };
554                 SECURITY_FRAMEWORK.get_sec_string_constant(algorithm_id)?
555             };
556             return Ok(SignParams::RSA(algorithm, data));
557         }
558 
559         // Handle the case where this is a TLS 1.0 MD5/SHA1 hash.
560         if data.len() == 36 {
561             let algorithm_id = SecStringConstant::SecKeyAlgorithmRSASignatureDigestPKCS1v15Raw;
562             let algorithm = SECURITY_FRAMEWORK.get_sec_string_constant(algorithm_id)?;
563             return Ok(SignParams::RSA(algorithm, data));
564         }
565         // Otherwise, `data` should be a DigestInfo.
566         let (digest_oid, hash) = read_digest_info(data)?;
567         let algorithm_id = if digest_oid == OID_BYTES_SHA_256 {
568             SecStringConstant::SecKeyAlgorithmRSASignatureDigestPKCS1v15SHA256
569         } else if digest_oid == OID_BYTES_SHA_384 {
570             SecStringConstant::SecKeyAlgorithmRSASignatureDigestPKCS1v15SHA384
571         } else if digest_oid == OID_BYTES_SHA_512 {
572             SecStringConstant::SecKeyAlgorithmRSASignatureDigestPKCS1v15SHA512
573         } else if digest_oid == OID_BYTES_SHA_1 {
574             SecStringConstant::SecKeyAlgorithmRSASignatureDigestPKCS1v15SHA1
575         } else {
576             error!("unsupported digest algorithm: {:?}", digest_oid);
577             return Err(());
578         };
579 
580         Ok(SignParams::RSA(
581             SECURITY_FRAMEWORK.get_sec_string_constant(algorithm_id)?,
582             hash,
583         ))
584     }
585 
get_algorithm(&self) -> SecKeyAlgorithm586     fn get_algorithm(&self) -> SecKeyAlgorithm {
587         match self {
588             SignParams::EC(algorithm, _) => algorithm.as_concrete_TypeRef(),
589             SignParams::RSA(algorithm, _) => algorithm.as_concrete_TypeRef(),
590         }
591     }
592 
get_data_to_sign(&self) -> &'a [u8]593     fn get_data_to_sign(&self) -> &'a [u8] {
594         match self {
595             SignParams::EC(_, data_to_sign) => data_to_sign,
596             SignParams::RSA(_, data_to_sign) => data_to_sign,
597         }
598     }
599 }
600 
601 pub struct Key {
602     identity: SecIdentity,
603     class: Vec<u8>,
604     token: Vec<u8>,
605     id: Vec<u8>,
606     private: Vec<u8>,
607     key_type: Vec<u8>,
608     modulus: Option<Vec<u8>>,
609     ec_params: Option<Vec<u8>>,
610     key_type_enum: KeyType,
611     key_handle: Option<SecKey>,
612 }
613 
614 impl Key {
new(identity: &SecIdentity) -> Result<Key, ()>615     fn new(identity: &SecIdentity) -> Result<Key, ()> {
616         let certificate = sec_identity_copy_certificate(identity)?;
617         let der = sec_certificate_copy_data(&certificate)?;
618         let id = Sha256::digest(der.bytes()).to_vec();
619         let key = SECURITY_FRAMEWORK.sec_certificate_copy_key(&certificate)?;
620         let key_type: CFString = get_key_attribute(&key, unsafe { kSecAttrKeyType })?;
621         let key_size_in_bits: CFNumber = get_key_attribute(&key, unsafe { kSecAttrKeySizeInBits })?;
622         let mut modulus = None;
623         let mut ec_params = None;
624         let sec_attr_key_type_ec = SECURITY_FRAMEWORK
625             .get_sec_string_constant(SecStringConstant::SecAttrKeyTypeECSECPrimeRandom)?;
626         let (key_type_enum, key_type_attribute) =
627             if key_type.as_concrete_TypeRef() == unsafe { kSecAttrKeyTypeRSA } {
628                 let public_key = SECURITY_FRAMEWORK.sec_key_copy_external_representation(&key)?;
629                 let modulus_value = read_rsa_modulus(public_key.bytes())?;
630                 modulus = Some(modulus_value);
631                 (KeyType::RSA, CKK_RSA)
632             } else if key_type == sec_attr_key_type_ec {
633                 // Assume all EC keys are secp256r1, secp384r1, or secp521r1. This
634                 // is wrong, but the API doesn't seem to give us a way to determine
635                 // which curve this key is on.
636                 // This might not matter in practice, because it seems all NSS uses
637                 // this for is to get the signature size.
638                 let key_size_in_bits = match key_size_in_bits.to_i64() {
639                     Some(value) => value,
640                     None => return Err(()),
641                 };
642                 match key_size_in_bits {
643                     256 => ec_params = Some(ENCODED_OID_BYTES_SECP256R1.to_vec()),
644                     384 => ec_params = Some(ENCODED_OID_BYTES_SECP384R1.to_vec()),
645                     521 => ec_params = Some(ENCODED_OID_BYTES_SECP521R1.to_vec()),
646                     _ => {
647                         error!("unsupported EC key");
648                         return Err(());
649                     }
650                 }
651                 let coordinate_width = (key_size_in_bits as usize + 7) / 8;
652                 (KeyType::EC(coordinate_width), CKK_EC)
653             } else {
654                 error!("unsupported key type");
655                 return Err(());
656             };
657 
658         Ok(Key {
659             identity: identity.clone(),
660             class: serialize_uint(CKO_PRIVATE_KEY)?,
661             token: serialize_uint(CK_TRUE)?,
662             id,
663             private: serialize_uint(CK_TRUE)?,
664             key_type: serialize_uint(key_type_attribute)?,
665             modulus,
666             ec_params,
667             key_type_enum,
668             key_handle: None,
669         })
670     }
671 
class(&self) -> &[u8]672     fn class(&self) -> &[u8] {
673         &self.class
674     }
675 
token(&self) -> &[u8]676     fn token(&self) -> &[u8] {
677         &self.token
678     }
679 
id(&self) -> &[u8]680     pub fn id(&self) -> &[u8] {
681         &self.id
682     }
683 
private(&self) -> &[u8]684     fn private(&self) -> &[u8] {
685         &self.private
686     }
687 
key_type(&self) -> &[u8]688     fn key_type(&self) -> &[u8] {
689         &self.key_type
690     }
691 
modulus(&self) -> Option<&[u8]>692     fn modulus(&self) -> Option<&[u8]> {
693         match &self.modulus {
694             Some(modulus) => Some(modulus.as_slice()),
695             None => None,
696         }
697     }
698 
ec_params(&self) -> Option<&[u8]>699     fn ec_params(&self) -> Option<&[u8]> {
700         match &self.ec_params {
701             Some(ec_params) => Some(ec_params.as_slice()),
702             None => None,
703         }
704     }
705 
matches(&self, attrs: &[(CK_ATTRIBUTE_TYPE, Vec<u8>)]) -> bool706     fn matches(&self, attrs: &[(CK_ATTRIBUTE_TYPE, Vec<u8>)]) -> bool {
707         for (attr_type, attr_value) in attrs {
708             let comparison = match *attr_type {
709                 CKA_CLASS => self.class(),
710                 CKA_TOKEN => self.token(),
711                 CKA_ID => self.id(),
712                 CKA_PRIVATE => self.private(),
713                 CKA_KEY_TYPE => self.key_type(),
714                 CKA_MODULUS => {
715                     if let Some(modulus) = self.modulus() {
716                         modulus
717                     } else {
718                         return false;
719                     }
720                 }
721                 CKA_EC_PARAMS => {
722                     if let Some(ec_params) = self.ec_params() {
723                         ec_params
724                     } else {
725                         return false;
726                     }
727                 }
728                 _ => return false,
729             };
730             if attr_value.as_slice() != comparison {
731                 return false;
732             }
733         }
734         true
735     }
736 
get_attribute(&self, attribute: CK_ATTRIBUTE_TYPE) -> Option<&[u8]>737     fn get_attribute(&self, attribute: CK_ATTRIBUTE_TYPE) -> Option<&[u8]> {
738         match attribute {
739             CKA_CLASS => Some(self.class()),
740             CKA_TOKEN => Some(self.token()),
741             CKA_ID => Some(self.id()),
742             CKA_PRIVATE => Some(self.private()),
743             CKA_KEY_TYPE => Some(self.key_type()),
744             CKA_MODULUS => self.modulus(),
745             CKA_EC_PARAMS => self.ec_params(),
746             _ => None,
747         }
748     }
749 
get_signature_length( &mut self, data: &[u8], params: &Option<CK_RSA_PKCS_PSS_PARAMS>, ) -> Result<usize, ()>750     pub fn get_signature_length(
751         &mut self,
752         data: &[u8],
753         params: &Option<CK_RSA_PKCS_PSS_PARAMS>,
754     ) -> Result<usize, ()> {
755         // Unfortunately we don't have a way of getting the length of a signature without creating
756         // one.
757         let dummy_signature_bytes = self.sign(data, params)?;
758         Ok(dummy_signature_bytes.len())
759     }
760 
761     // The input data is a hash. What algorithm we use depends on the size of the hash.
sign( &mut self, data: &[u8], params: &Option<CK_RSA_PKCS_PSS_PARAMS>, ) -> Result<Vec<u8>, ()>762     pub fn sign(
763         &mut self,
764         data: &[u8],
765         params: &Option<CK_RSA_PKCS_PSS_PARAMS>,
766     ) -> Result<Vec<u8>, ()> {
767         let result = self.sign_internal(data, params);
768         if result.is_ok() {
769             return result;
770         }
771         // Some devices appear to not work well when the key handle is held for too long or if a
772         // card is inserted/removed while Firefox is running. Try refreshing the key handle.
773         debug!("sign failed: refreshing key handle");
774         let _ = self.key_handle.take();
775         self.sign_internal(data, params)
776     }
777 
sign_internal( &mut self, data: &[u8], params: &Option<CK_RSA_PKCS_PSS_PARAMS>, ) -> Result<Vec<u8>, ()>778     fn sign_internal(
779         &mut self,
780         data: &[u8],
781         params: &Option<CK_RSA_PKCS_PSS_PARAMS>,
782     ) -> Result<Vec<u8>, ()> {
783         // If this key hasn't been used for signing yet, there won't be a cached key handle. Obtain
784         // and cache it if this is the case. Doing so can cause the underlying implementation to
785         // show an authentication or pin prompt to the user. Caching the handle can avoid causing
786         // multiple prompts to be displayed in some cases.
787         if self.key_handle.is_none() {
788             let _ = self
789                 .key_handle
790                 .replace(sec_identity_copy_private_key(&self.identity)?);
791         }
792         let key = match &self.key_handle {
793             Some(key) => key,
794             None => {
795                 error!("key_handle not set when it should have just been set?");
796                 return Err(());
797             }
798         };
799         let sign_params = SignParams::new(self.key_type_enum, data, params)?;
800         let signing_algorithm = sign_params.get_algorithm();
801         let data_to_sign = CFData::from_buffer(sign_params.get_data_to_sign());
802         let signature =
803             SECURITY_FRAMEWORK.sec_key_create_signature(&key, signing_algorithm, &data_to_sign)?;
804         let signature_value = match self.key_type_enum {
805             KeyType::EC(coordinate_width) => {
806                 // We need to convert the DER Ecdsa-Sig-Value to the
807                 // concatenation of r and s, the coordinates of the point on
808                 // the curve. r and s must be 0-padded to be coordinate_width
809                 // total bytes.
810                 let (r, s) = read_ec_sig_point(signature.bytes())?;
811                 if r.len() > coordinate_width || s.len() > coordinate_width {
812                     return Err(());
813                 }
814                 let mut signature_value = Vec::with_capacity(2 * coordinate_width);
815                 let r_padding = vec![0; coordinate_width - r.len()];
816                 signature_value.extend(r_padding);
817                 signature_value.extend_from_slice(r);
818                 let s_padding = vec![0; coordinate_width - s.len()];
819                 signature_value.extend(s_padding);
820                 signature_value.extend_from_slice(s);
821                 signature_value
822             }
823             KeyType::RSA => signature.bytes().to_vec(),
824         };
825         Ok(signature_value)
826     }
827 }
828 
829 pub enum Object {
830     Cert(Cert),
831     Key(Key),
832 }
833 
834 impl Object {
matches(&self, slot_type: SlotType, attrs: &[(CK_ATTRIBUTE_TYPE, Vec<u8>)]) -> bool835     pub fn matches(&self, slot_type: SlotType, attrs: &[(CK_ATTRIBUTE_TYPE, Vec<u8>)]) -> bool {
836         // The modern/legacy slot distinction in theory enables differentiation
837         // between keys that are from modules that can use modern cryptography
838         // (namely EC keys and RSA-PSS signatures) and those that cannot.
839         // However, the function that would enable this
840         // (SecKeyIsAlgorithmSupported) causes a password dialog to appear on
841         // our test machines, so this backend pretends that everything supports
842         // modern crypto for now.
843         if slot_type != SlotType::Modern {
844             return false;
845         }
846         match self {
847             Object::Cert(cert) => cert.matches(attrs),
848             Object::Key(key) => key.matches(attrs),
849         }
850     }
851 
get_attribute(&self, attribute: CK_ATTRIBUTE_TYPE) -> Option<&[u8]>852     pub fn get_attribute(&self, attribute: CK_ATTRIBUTE_TYPE) -> Option<&[u8]> {
853         match self {
854             Object::Cert(cert) => cert.get_attribute(attribute),
855             Object::Key(key) => key.get_attribute(attribute),
856         }
857     }
858 }
859 
860 pub const SUPPORTED_ATTRIBUTES: &[CK_ATTRIBUTE_TYPE] = &[
861     CKA_CLASS,
862     CKA_TOKEN,
863     CKA_LABEL,
864     CKA_ID,
865     CKA_VALUE,
866     CKA_ISSUER,
867     CKA_SERIAL_NUMBER,
868     CKA_SUBJECT,
869     CKA_PRIVATE,
870     CKA_KEY_TYPE,
871     CKA_MODULUS,
872     CKA_EC_PARAMS,
873 ];
874 
get_key_attribute<T: TCFType + Clone>(key: &SecKey, attr: CFStringRef) -> Result<T, ()>875 fn get_key_attribute<T: TCFType + Clone>(key: &SecKey, attr: CFStringRef) -> Result<T, ()> {
876     let attributes: CFDictionary<CFString, T> = SECURITY_FRAMEWORK.sec_key_copy_attributes(&key)?;
877     match attributes.find(attr as *const _) {
878         Some(value) => Ok((*value).clone()),
879         None => Err(()),
880     }
881 }
882 
883 // Given a SecIdentity, attempts to build as much of a path to a trust anchor as possible, gathers
884 // the CA certificates from that path, and returns them. The purpose of this function is not to
885 // validate the given certificate but to find CA certificates that gecko may need to do path
886 // building when filtering client certificates according to the acceptable CA list sent by the
887 // server during client authentication.
get_issuers(identity: &SecIdentity) -> Result<Vec<SecCertificate>, ()>888 fn get_issuers(identity: &SecIdentity) -> Result<Vec<SecCertificate>, ()> {
889     let certificate = sec_identity_copy_certificate(identity)?;
890     let policy = unsafe { SecPolicyCreateSSL(false, std::ptr::null()) };
891     if policy.is_null() {
892         error!("SecPolicyCreateSSL failed");
893         return Err(());
894     }
895     let policy = unsafe { SecPolicy::wrap_under_create_rule(policy) };
896     let mut trust = std::ptr::null();
897     // Each of SecTrustCreateWithCertificates' input arguments can be either single items or an
898     // array of items. Since we only want to specify one of each, we directly specify the arguments.
899     let status = unsafe {
900         SecTrustCreateWithCertificates(
901             certificate.as_concrete_TypeRef(),
902             policy.as_concrete_TypeRef(),
903             &mut trust,
904         )
905     };
906     if status != errSecSuccess {
907         error!("SecTrustCreateWithCertificates failed: {}", status);
908         return Err(());
909     }
910     if trust.is_null() {
911         error!("trust is null?");
912         return Err(());
913     }
914     let trust = unsafe { SecTrust::wrap_under_create_rule(trust) };
915     // Disable AIA fetching so that SecTrustEvaluateWithError doesn't result in network I/O.
916     let status = unsafe { SecTrustSetNetworkFetchAllowed(trust.as_concrete_TypeRef(), 0) };
917     if status != errSecSuccess {
918         error!("SecTrustSetNetworkFetchAllowed failed: {}", status);
919         return Err(());
920     }
921     // We ignore the return value here because we don't care if the certificate is trusted or not -
922     // we're only doing this to build its issuer chain as much as possible.
923     let _ = SECURITY_FRAMEWORK.sec_trust_evaluate_with_error(&trust)?;
924     let certificate_count = unsafe { SecTrustGetCertificateCount(trust.as_concrete_TypeRef()) };
925     let mut certificates = Vec::with_capacity(certificate_count.try_into().map_err(|_| ())?);
926     for i in 1..certificate_count {
927         let certificate = unsafe { SecTrustGetCertificateAtIndex(trust.as_concrete_TypeRef(), i) };
928         if certificate.is_null() {
929             error!("SecTrustGetCertificateAtIndex returned null certificate?");
930             continue;
931         }
932         let certificate = unsafe { SecCertificate::wrap_under_get_rule(certificate) };
933         certificates.push(certificate);
934     }
935     Ok(certificates)
936 }
937 
list_objects() -> Vec<Object>938 pub fn list_objects() -> Vec<Object> {
939     let mut objects = Vec::new();
940     let identities = unsafe {
941         let class_key = CFString::wrap_under_get_rule(kSecClass);
942         let class_value = CFString::wrap_under_get_rule(kSecClassIdentity);
943         let return_ref_key = CFString::wrap_under_get_rule(kSecReturnRef);
944         let return_ref_value = CFBoolean::wrap_under_get_rule(kCFBooleanTrue);
945         let match_key = CFString::wrap_under_get_rule(kSecMatchLimit);
946         let match_value = CFString::wrap_under_get_rule(kSecMatchLimitAll);
947         let vals = vec![
948             (class_key.as_CFType(), class_value.as_CFType()),
949             (return_ref_key.as_CFType(), return_ref_value.as_CFType()),
950             (match_key.as_CFType(), match_value.as_CFType()),
951         ];
952         let dict = CFDictionary::from_CFType_pairs(&vals);
953         let mut result = std::ptr::null();
954         let status = SecItemCopyMatching(dict.as_CFTypeRef() as CFDictionaryRef, &mut result);
955         if status != errSecSuccess {
956             error!("SecItemCopyMatching failed: {}", status);
957             return objects;
958         }
959         if result.is_null() {
960             debug!("no client certs?");
961             return objects;
962         }
963         CFArray::<SecIdentityRef>::wrap_under_create_rule(result as CFArrayRef)
964     };
965     for identity in identities.get_all_values().iter() {
966         let identity = unsafe { SecIdentity::wrap_under_get_rule(*identity as SecIdentityRef) };
967         let cert = Cert::new_from_identity(&identity);
968         let key = Key::new(&identity);
969         if let (Ok(cert), Ok(key)) = (cert, key) {
970             objects.push(Object::Cert(cert));
971             objects.push(Object::Key(key));
972         } else {
973             continue;
974         }
975         if let Ok(issuers) = get_issuers(&identity) {
976             for issuer in issuers {
977                 if let Ok(cert) = Cert::new_from_certificate(&issuer) {
978                     objects.push(Object::Cert(cert));
979                 }
980             }
981         }
982     }
983     objects
984 }
985