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