no bug - Import translations from android-l10n r=release a=l10n CLOSED TREE
[gecko.git] / security / manager / ssl / osclientcerts / src / backend_windows.rs
blob2a80ff83541325dbc3517f7f2b761ba7db3daed8
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_camel_case_types)]
8 use pkcs11_bindings::*;
9 use rsclientcerts::error::{Error, ErrorType};
10 use rsclientcerts::manager::{ClientCertsBackend, CryptokiObject, Sign, SlotType};
11 use rsclientcerts::util::*;
12 use sha2::{Digest, Sha256};
13 use std::convert::TryInto;
14 use std::ffi::{c_void, CStr, CString};
15 use std::ops::Deref;
16 use std::slice;
17 use winapi::shared::bcrypt::*;
18 use winapi::shared::minwindef::{DWORD, PBYTE};
19 use winapi::um::errhandlingapi::GetLastError;
20 use winapi::um::ncrypt::*;
21 use winapi::um::wincrypt::{HCRYPTHASH, HCRYPTPROV, *};
23 // winapi has some support for ncrypt.h, but not for this function.
24 extern "system" {
25     fn NCryptSignHash(
26         hKey: NCRYPT_KEY_HANDLE,
27         pPaddingInfo: *mut c_void,
28         pbHashValue: PBYTE,
29         cbHashValue: DWORD,
30         pbSignature: PBYTE,
31         cbSignature: DWORD,
32         pcbResult: *mut DWORD,
33         dwFlags: DWORD,
34     ) -> SECURITY_STATUS;
37 /// Given a `CERT_INFO`, tries to return the bytes of the subject distinguished name as formatted by
38 /// `CertNameToStrA` using the flag `CERT_SIMPLE_NAME_STR`. This is used as the label for the
39 /// certificate.
40 fn get_cert_subject_dn(cert_info: &CERT_INFO) -> Result<Vec<u8>, Error> {
41     let mut cert_info_subject = cert_info.Subject;
42     let subject_dn_len = unsafe {
43         CertNameToStrA(
44             X509_ASN_ENCODING,
45             &mut cert_info_subject,
46             CERT_SIMPLE_NAME_STR,
47             std::ptr::null_mut(),
48             0,
49         )
50     };
51     // subject_dn_len includes the terminating null byte.
52     let mut subject_dn_string_bytes: Vec<u8> = vec![0; subject_dn_len as usize];
53     let subject_dn_len = unsafe {
54         CertNameToStrA(
55             X509_ASN_ENCODING,
56             &mut cert_info_subject,
57             CERT_SIMPLE_NAME_STR,
58             subject_dn_string_bytes.as_mut_ptr() as *mut i8,
59             subject_dn_string_bytes
60                 .len()
61                 .try_into()
62                 .map_err(|_| error_here!(ErrorType::ValueTooLarge))?,
63         )
64     };
65     if subject_dn_len as usize != subject_dn_string_bytes.len() {
66         return Err(error_here!(ErrorType::ExternalError));
67     }
68     Ok(subject_dn_string_bytes)
71 /// Represents a certificate for which there exists a corresponding private key.
72 pub struct Cert {
73     /// PKCS #11 object class. Will be `CKO_CERTIFICATE`.
74     class: Vec<u8>,
75     /// Whether or not this is on a token. Will be `CK_TRUE`.
76     token: Vec<u8>,
77     /// An identifier unique to this certificate. Must be the same as the ID for the private key.
78     id: Vec<u8>,
79     /// The bytes of a human-readable label for this certificate. Will be the subject DN.
80     label: Vec<u8>,
81     /// The DER bytes of the certificate.
82     value: Vec<u8>,
83     /// The DER bytes of the issuer distinguished name of the certificate.
84     issuer: Vec<u8>,
85     /// The DER bytes of the serial number of the certificate.
86     serial_number: Vec<u8>,
87     /// The DER bytes of the subject distinguished name of the certificate.
88     subject: Vec<u8>,
89     /// Which slot this certificate should be exposed on.
90     slot_type: SlotType,
93 impl Cert {
94     fn new(cert_context: PCCERT_CONTEXT) -> Result<Cert, Error> {
95         let cert = unsafe { &*cert_context };
96         let cert_info = unsafe { &*cert.pCertInfo };
97         let value =
98             unsafe { slice::from_raw_parts(cert.pbCertEncoded, cert.cbCertEncoded as usize) };
99         let value = value.to_vec();
100         let id = Sha256::digest(&value).to_vec();
101         let label = get_cert_subject_dn(cert_info)?;
102         let (serial_number, issuer, subject) = read_encoded_certificate_identifiers(&value)?;
103         Ok(Cert {
104             class: serialize_uint(CKO_CERTIFICATE)?,
105             token: serialize_uint(CK_TRUE)?,
106             id,
107             label,
108             value,
109             issuer,
110             serial_number,
111             subject,
112             slot_type: SlotType::Modern,
113         })
114     }
116     fn class(&self) -> &[u8] {
117         &self.class
118     }
120     fn token(&self) -> &[u8] {
121         &self.token
122     }
124     fn id(&self) -> &[u8] {
125         &self.id
126     }
128     fn label(&self) -> &[u8] {
129         &self.label
130     }
132     fn value(&self) -> &[u8] {
133         &self.value
134     }
136     fn issuer(&self) -> &[u8] {
137         &self.issuer
138     }
140     fn serial_number(&self) -> &[u8] {
141         &self.serial_number
142     }
144     fn subject(&self) -> &[u8] {
145         &self.subject
146     }
149 impl CryptokiObject for Cert {
150     fn matches(&self, slot_type: SlotType, attrs: &[(CK_ATTRIBUTE_TYPE, Vec<u8>)]) -> bool {
151         if slot_type != self.slot_type {
152             return false;
153         }
154         for (attr_type, attr_value) in attrs {
155             let comparison = match *attr_type {
156                 CKA_CLASS => self.class(),
157                 CKA_TOKEN => self.token(),
158                 CKA_LABEL => self.label(),
159                 CKA_ID => self.id(),
160                 CKA_VALUE => self.value(),
161                 CKA_ISSUER => self.issuer(),
162                 CKA_SERIAL_NUMBER => self.serial_number(),
163                 CKA_SUBJECT => self.subject(),
164                 _ => return false,
165             };
166             if attr_value.as_slice() != comparison {
167                 return false;
168             }
169         }
170         true
171     }
173     fn get_attribute(&self, attribute: CK_ATTRIBUTE_TYPE) -> Option<&[u8]> {
174         let result = match attribute {
175             CKA_CLASS => self.class(),
176             CKA_TOKEN => self.token(),
177             CKA_LABEL => self.label(),
178             CKA_ID => self.id(),
179             CKA_VALUE => self.value(),
180             CKA_ISSUER => self.issuer(),
181             CKA_SERIAL_NUMBER => self.serial_number(),
182             CKA_SUBJECT => self.subject(),
183             _ => return None,
184         };
185         Some(result)
186     }
189 struct CertContext(PCCERT_CONTEXT);
191 impl CertContext {
192     fn new(cert: PCCERT_CONTEXT) -> CertContext {
193         CertContext(unsafe { CertDuplicateCertificateContext(cert) })
194     }
197 impl Drop for CertContext {
198     fn drop(&mut self) {
199         unsafe {
200             CertFreeCertificateContext(self.0);
201         }
202     }
205 impl Deref for CertContext {
206     type Target = PCCERT_CONTEXT;
208     fn deref(&self) -> &Self::Target {
209         &self.0
210     }
213 enum KeyHandle {
214     NCrypt(NCRYPT_KEY_HANDLE),
215     CryptoAPI(HCRYPTPROV, DWORD),
218 impl KeyHandle {
219     fn from_cert(cert: &CertContext) -> Result<KeyHandle, Error> {
220         let mut key_handle = 0;
221         let mut key_spec = 0;
222         let mut must_free = 0;
223         unsafe {
224             if CryptAcquireCertificatePrivateKey(
225                 **cert,
226                 CRYPT_ACQUIRE_PREFER_NCRYPT_KEY_FLAG,
227                 std::ptr::null_mut(),
228                 &mut key_handle,
229                 &mut key_spec,
230                 &mut must_free,
231             ) != 1
232             {
233                 return Err(error_here!(
234                     ErrorType::ExternalError,
235                     GetLastError().to_string()
236                 ));
237             }
238         }
239         if must_free == 0 {
240             return Err(error_here!(ErrorType::ExternalError));
241         }
242         if key_spec == CERT_NCRYPT_KEY_SPEC {
243             Ok(KeyHandle::NCrypt(key_handle as NCRYPT_KEY_HANDLE))
244         } else {
245             Ok(KeyHandle::CryptoAPI(key_handle as HCRYPTPROV, key_spec))
246         }
247     }
249     fn sign(
250         &self,
251         data: &[u8],
252         params: &Option<CK_RSA_PKCS_PSS_PARAMS>,
253         do_signature: bool,
254         key_type: KeyType,
255     ) -> Result<Vec<u8>, Error> {
256         match &self {
257             KeyHandle::NCrypt(ncrypt_handle) => {
258                 sign_ncrypt(ncrypt_handle, data, params, do_signature, key_type)
259             }
260             KeyHandle::CryptoAPI(hcryptprov, key_spec) => {
261                 sign_cryptoapi(hcryptprov, key_spec, data, params, do_signature)
262             }
263         }
264     }
267 impl Drop for KeyHandle {
268     fn drop(&mut self) {
269         match self {
270             KeyHandle::NCrypt(ncrypt_handle) => unsafe {
271                 let _ = NCryptFreeObject(*ncrypt_handle);
272             },
273             KeyHandle::CryptoAPI(hcryptprov, _) => unsafe {
274                 let _ = CryptReleaseContext(*hcryptprov, 0);
275             },
276         }
277     }
280 fn sign_ncrypt(
281     ncrypt_handle: &NCRYPT_KEY_HANDLE,
282     data: &[u8],
283     params: &Option<CK_RSA_PKCS_PSS_PARAMS>,
284     do_signature: bool,
285     key_type: KeyType,
286 ) -> Result<Vec<u8>, Error> {
287     let mut sign_params = SignParams::new(key_type, params)?;
288     let params_ptr = sign_params.params_ptr();
289     let flags = sign_params.flags();
290     let mut data = data.to_vec();
291     let mut signature_len = 0;
292     // We call NCryptSignHash twice: the first time to get the size of the buffer we need to
293     // allocate and then again to actually sign the data, if `do_signature` is `true`.
294     let status = unsafe {
295         NCryptSignHash(
296             *ncrypt_handle,
297             params_ptr,
298             data.as_mut_ptr(),
299             data.len()
300                 .try_into()
301                 .map_err(|_| error_here!(ErrorType::ValueTooLarge))?,
302             std::ptr::null_mut(),
303             0,
304             &mut signature_len,
305             flags,
306         )
307     };
308     // 0 is "ERROR_SUCCESS" (but "ERROR_SUCCESS" is unsigned, whereas SECURITY_STATUS is signed)
309     if status != 0 {
310         return Err(error_here!(ErrorType::ExternalError, status.to_string()));
311     }
312     let mut signature = vec![0; signature_len as usize];
313     if !do_signature {
314         return Ok(signature);
315     }
316     let mut final_signature_len = signature_len;
317     let status = unsafe {
318         NCryptSignHash(
319             *ncrypt_handle,
320             params_ptr,
321             data.as_mut_ptr(),
322             data.len()
323                 .try_into()
324                 .map_err(|_| error_here!(ErrorType::ValueTooLarge))?,
325             signature.as_mut_ptr(),
326             signature_len,
327             &mut final_signature_len,
328             flags,
329         )
330     };
331     if status != 0 {
332         return Err(error_here!(ErrorType::ExternalError, status.to_string()));
333     }
334     if final_signature_len != signature_len {
335         return Err(error_here!(ErrorType::ExternalError));
336     }
337     Ok(signature)
340 fn sign_cryptoapi(
341     hcryptprov: &HCRYPTPROV,
342     key_spec: &DWORD,
343     data: &[u8],
344     params: &Option<CK_RSA_PKCS_PSS_PARAMS>,
345     do_signature: bool,
346 ) -> Result<Vec<u8>, Error> {
347     if params.is_some() {
348         return Err(error_here!(ErrorType::LibraryFailure));
349     }
350     // data will be an encoded DigestInfo, which specifies the hash algorithm and bytes of the hash
351     // to sign. However, CryptoAPI requires directly specifying the bytes of the hash, so it must
352     // be extracted first.
353     let (_, hash_bytes) = read_digest_info(data)?;
354     let hash = HCryptHash::new(hcryptprov, hash_bytes)?;
355     let mut signature_len = 0;
356     if unsafe {
357         CryptSignHashW(
358             *hash,
359             *key_spec,
360             std::ptr::null_mut(),
361             0,
362             std::ptr::null_mut(),
363             &mut signature_len,
364         )
365     } != 1
366     {
367         return Err(error_here!(
368             ErrorType::ExternalError,
369             unsafe { GetLastError() }.to_string()
370         ));
371     }
372     let mut signature = vec![0; signature_len as usize];
373     if !do_signature {
374         return Ok(signature);
375     }
376     let mut final_signature_len = signature_len;
377     if unsafe {
378         CryptSignHashW(
379             *hash,
380             *key_spec,
381             std::ptr::null_mut(),
382             0,
383             signature.as_mut_ptr(),
384             &mut final_signature_len,
385         )
386     } != 1
387     {
388         return Err(error_here!(
389             ErrorType::ExternalError,
390             unsafe { GetLastError() }.to_string()
391         ));
392     }
393     if final_signature_len != signature_len {
394         return Err(error_here!(ErrorType::ExternalError));
395     }
396     // CryptoAPI returns the signature with the most significant byte last (little-endian),
397     // whereas PKCS#11 expects the most significant byte first (big-endian).
398     signature.reverse();
399     Ok(signature)
402 struct HCryptHash(HCRYPTHASH);
404 impl HCryptHash {
405     fn new(hcryptprov: &HCRYPTPROV, hash_bytes: &[u8]) -> Result<HCryptHash, Error> {
406         let alg = match hash_bytes.len() {
407             20 => CALG_SHA1,
408             32 => CALG_SHA_256,
409             48 => CALG_SHA_384,
410             64 => CALG_SHA_512,
411             _ => {
412                 return Err(error_here!(ErrorType::UnsupportedInput));
413             }
414         };
415         let mut hash: HCRYPTHASH = 0;
416         if unsafe { CryptCreateHash(*hcryptprov, alg, 0, 0, &mut hash) } != 1 {
417             return Err(error_here!(
418                 ErrorType::ExternalError,
419                 unsafe { GetLastError() }.to_string()
420             ));
421         }
422         if unsafe { CryptSetHashParam(hash, HP_HASHVAL, hash_bytes.as_ptr(), 0) } != 1 {
423             return Err(error_here!(
424                 ErrorType::ExternalError,
425                 unsafe { GetLastError() }.to_string()
426             ));
427         }
428         Ok(HCryptHash(hash))
429     }
432 impl Drop for HCryptHash {
433     fn drop(&mut self) {
434         unsafe {
435             CryptDestroyHash(self.0);
436         }
437     }
440 impl Deref for HCryptHash {
441     type Target = HCRYPTHASH;
443     fn deref(&self) -> &Self::Target {
444         &self.0
445     }
448 // In some cases, the ncrypt API takes a pointer to a null-terminated wide-character string as a way
449 // of specifying an algorithm. The "right" way to do this would be to take the corresponding
450 // &'static str constant provided by the winapi crate, create an OsString from it, encode it as wide
451 // characters, and collect it into a Vec<u16>. However, since the implementation that provides this
452 // functionality isn't constant, we would have to manage the memory this creates and uses. Since
453 // rust structures generally can't be self-referrential, this memory would have to live elsewhere,
454 // and the nice abstractions we've created for this implementation start to break down. It's much
455 // simpler to hard-code the identifiers we support, since there are only four of them.
456 // The following arrays represent the identifiers "SHA1", "SHA256", "SHA384", and "SHA512",
457 // respectively.
458 const SHA1_ALGORITHM_STRING: &[u16] = &[83, 72, 65, 49, 0];
459 const SHA256_ALGORITHM_STRING: &[u16] = &[83, 72, 65, 50, 53, 54, 0];
460 const SHA384_ALGORITHM_STRING: &[u16] = &[83, 72, 65, 51, 56, 52, 0];
461 const SHA512_ALGORITHM_STRING: &[u16] = &[83, 72, 65, 53, 49, 50, 0];
463 enum SignParams {
464     EC,
465     RSA_PKCS1(BCRYPT_PKCS1_PADDING_INFO),
466     RSA_PSS(BCRYPT_PSS_PADDING_INFO),
469 impl SignParams {
470     fn new(
471         key_type: KeyType,
472         params: &Option<CK_RSA_PKCS_PSS_PARAMS>,
473     ) -> Result<SignParams, Error> {
474         // EC is easy, so handle that first.
475         match key_type {
476             KeyType::EC => return Ok(SignParams::EC),
477             KeyType::RSA => {}
478         }
479         // If `params` is `Some`, we're doing RSA-PSS. If it is `None`, we're doing RSA-PKCS1.
480         let pss_params = match params {
481             Some(pss_params) => pss_params,
482             None => {
483                 // The hash algorithm should be encoded in the data to be signed, so we don't have to
484                 // (and don't want to) specify a particular algorithm here.
485                 return Ok(SignParams::RSA_PKCS1(BCRYPT_PKCS1_PADDING_INFO {
486                     pszAlgId: std::ptr::null(),
487                 }));
488             }
489         };
490         let algorithm_string = match pss_params.hashAlg {
491             CKM_SHA_1 => SHA1_ALGORITHM_STRING,
492             CKM_SHA256 => SHA256_ALGORITHM_STRING,
493             CKM_SHA384 => SHA384_ALGORITHM_STRING,
494             CKM_SHA512 => SHA512_ALGORITHM_STRING,
495             _ => {
496                 return Err(error_here!(ErrorType::UnsupportedInput));
497             }
498         };
499         Ok(SignParams::RSA_PSS(BCRYPT_PSS_PADDING_INFO {
500             pszAlgId: algorithm_string.as_ptr(),
501             cbSalt: pss_params.sLen,
502         }))
503     }
505     fn params_ptr(&mut self) -> *mut std::ffi::c_void {
506         match self {
507             SignParams::EC => std::ptr::null_mut(),
508             SignParams::RSA_PKCS1(params) => {
509                 params as *mut BCRYPT_PKCS1_PADDING_INFO as *mut std::ffi::c_void
510             }
511             SignParams::RSA_PSS(params) => {
512                 params as *mut BCRYPT_PSS_PADDING_INFO as *mut std::ffi::c_void
513             }
514         }
515     }
517     fn flags(&self) -> u32 {
518         match *self {
519             SignParams::EC => 0,
520             SignParams::RSA_PKCS1(_) => NCRYPT_PAD_PKCS1_FLAG,
521             SignParams::RSA_PSS(_) => NCRYPT_PAD_PSS_FLAG,
522         }
523     }
526 /// A helper enum to identify a private key's type. We support EC and RSA.
527 #[allow(clippy::upper_case_acronyms)]
528 #[derive(Clone, Copy, Debug)]
529 pub enum KeyType {
530     EC,
531     RSA,
534 /// Represents a private key for which there exists a corresponding certificate.
535 pub struct Key {
536     /// A handle on the OS mechanism that represents the certificate for this key.
537     cert: CertContext,
538     /// PKCS #11 object class. Will be `CKO_PRIVATE_KEY`.
539     class: Vec<u8>,
540     /// Whether or not this is on a token. Will be `CK_TRUE`.
541     token: Vec<u8>,
542     /// An identifier unique to this key. Must be the same as the ID for the certificate.
543     id: Vec<u8>,
544     /// Whether or not this key is "private" (can it be exported?). Will be CK_TRUE (it can't be
545     /// exported).
546     private: Vec<u8>,
547     /// PKCS #11 key type. Will be `CKK_EC` for EC, and `CKK_RSA` for RSA.
548     key_type: Vec<u8>,
549     /// If this is an RSA key, this is the value of the modulus as an unsigned integer.
550     modulus: Option<Vec<u8>>,
551     /// If this is an EC key, this is the DER bytes of the OID identifying the curve the key is on.
552     ec_params: Option<Vec<u8>>,
553     /// An enum identifying this key's type.
554     key_type_enum: KeyType,
555     /// Which slot this key should be exposed on.
556     slot_type: SlotType,
557     /// A handle on the OS mechanism that represents this key.
558     key_handle: Option<KeyHandle>,
561 impl Key {
562     fn new(cert_context: PCCERT_CONTEXT) -> Result<Key, Error> {
563         let cert = unsafe { *cert_context };
564         let cert_der =
565             unsafe { slice::from_raw_parts(cert.pbCertEncoded, cert.cbCertEncoded as usize) };
566         let id = Sha256::digest(cert_der).to_vec();
567         let id = id.to_vec();
568         let cert_info = unsafe { &*cert.pCertInfo };
569         let mut modulus = None;
570         let mut ec_params = None;
571         let spki = &cert_info.SubjectPublicKeyInfo;
572         let algorithm_oid = unsafe { CStr::from_ptr(spki.Algorithm.pszObjId) }
573             .to_str()
574             .map_err(|_| error_here!(ErrorType::ExternalError))?;
575         let (key_type_enum, key_type_attribute) = if algorithm_oid == szOID_RSA_RSA {
576             if spki.PublicKey.cUnusedBits != 0 {
577                 return Err(error_here!(ErrorType::ExternalError));
578             }
579             let public_key_bytes = unsafe {
580                 std::slice::from_raw_parts(spki.PublicKey.pbData, spki.PublicKey.cbData as usize)
581             };
582             let modulus_value = read_rsa_modulus(public_key_bytes)?;
583             modulus = Some(modulus_value);
584             (KeyType::RSA, CKK_RSA)
585         } else if algorithm_oid == szOID_ECC_PUBLIC_KEY {
586             let params = &spki.Algorithm.Parameters;
587             ec_params = Some(
588                 unsafe { std::slice::from_raw_parts(params.pbData, params.cbData as usize) }
589                     .to_vec(),
590             );
591             (KeyType::EC, CKK_EC)
592         } else {
593             return Err(error_here!(ErrorType::LibraryFailure));
594         };
595         let cert = CertContext::new(cert_context);
596         Ok(Key {
597             cert,
598             class: serialize_uint(CKO_PRIVATE_KEY)?,
599             token: serialize_uint(CK_TRUE)?,
600             id,
601             private: serialize_uint(CK_TRUE)?,
602             key_type: serialize_uint(key_type_attribute)?,
603             modulus,
604             ec_params,
605             key_type_enum,
606             slot_type: SlotType::Modern,
607             key_handle: None,
608         })
609     }
611     fn class(&self) -> &[u8] {
612         &self.class
613     }
615     fn token(&self) -> &[u8] {
616         &self.token
617     }
619     fn id(&self) -> &[u8] {
620         &self.id
621     }
623     fn private(&self) -> &[u8] {
624         &self.private
625     }
627     fn key_type(&self) -> &[u8] {
628         &self.key_type
629     }
631     fn modulus(&self) -> Option<&[u8]> {
632         match &self.modulus {
633             Some(modulus) => Some(modulus.as_slice()),
634             None => None,
635         }
636     }
638     fn ec_params(&self) -> Option<&[u8]> {
639         match &self.ec_params {
640             Some(ec_params) => Some(ec_params.as_slice()),
641             None => None,
642         }
643     }
645     fn sign_with_retry(
646         &mut self,
647         data: &[u8],
648         params: &Option<CK_RSA_PKCS_PSS_PARAMS>,
649         do_signature: bool,
650     ) -> Result<Vec<u8>, Error> {
651         let result = self.sign_internal(data, params, do_signature);
652         if result.is_ok() {
653             return result;
654         }
655         // Some devices appear to not work well when the key handle is held for too long or if a
656         // card is inserted/removed while Firefox is running. Try refreshing the key handle.
657         debug!("sign failed: refreshing key handle");
658         let _ = self.key_handle.take();
659         self.sign_internal(data, params, do_signature)
660     }
662     /// data: the data to sign
663     /// do_signature: if true, actually perform the signature. Otherwise, return a `Vec<u8>` of the
664     /// length the signature would be, if performed.
665     fn sign_internal(
666         &mut self,
667         data: &[u8],
668         params: &Option<CK_RSA_PKCS_PSS_PARAMS>,
669         do_signature: bool,
670     ) -> Result<Vec<u8>, Error> {
671         // If this key hasn't been used for signing yet, there won't be a cached key handle. Obtain
672         // and cache it if this is the case. Doing so can cause the underlying implementation to
673         // show an authentication or pin prompt to the user. Caching the handle can avoid causing
674         // multiple prompts to be displayed in some cases.
675         if self.key_handle.is_none() {
676             let _ = self.key_handle.replace(KeyHandle::from_cert(&self.cert)?);
677         }
678         let key = match &self.key_handle {
679             Some(key) => key,
680             None => return Err(error_here!(ErrorType::LibraryFailure)),
681         };
682         key.sign(data, params, do_signature, self.key_type_enum)
683     }
686 impl CryptokiObject for Key {
687     fn matches(&self, slot_type: SlotType, attrs: &[(CK_ATTRIBUTE_TYPE, Vec<u8>)]) -> bool {
688         if slot_type != self.slot_type {
689             return false;
690         }
691         for (attr_type, attr_value) in attrs {
692             let comparison = match *attr_type {
693                 CKA_CLASS => self.class(),
694                 CKA_TOKEN => self.token(),
695                 CKA_ID => self.id(),
696                 CKA_PRIVATE => self.private(),
697                 CKA_KEY_TYPE => self.key_type(),
698                 CKA_MODULUS => {
699                     if let Some(modulus) = self.modulus() {
700                         modulus
701                     } else {
702                         return false;
703                     }
704                 }
705                 CKA_EC_PARAMS => {
706                     if let Some(ec_params) = self.ec_params() {
707                         ec_params
708                     } else {
709                         return false;
710                     }
711                 }
712                 _ => return false,
713             };
714             if attr_value.as_slice() != comparison {
715                 return false;
716             }
717         }
718         true
719     }
721     fn get_attribute(&self, attribute: CK_ATTRIBUTE_TYPE) -> Option<&[u8]> {
722         match attribute {
723             CKA_CLASS => Some(self.class()),
724             CKA_TOKEN => Some(self.token()),
725             CKA_ID => Some(self.id()),
726             CKA_PRIVATE => Some(self.private()),
727             CKA_KEY_TYPE => Some(self.key_type()),
728             CKA_MODULUS => self.modulus(),
729             CKA_EC_PARAMS => self.ec_params(),
730             _ => None,
731         }
732     }
735 impl Sign for Key {
736     fn get_signature_length(
737         &mut self,
738         data: &[u8],
739         params: &Option<CK_RSA_PKCS_PSS_PARAMS>,
740     ) -> Result<usize, Error> {
741         match self.sign_with_retry(data, params, false) {
742             Ok(dummy_signature_bytes) => Ok(dummy_signature_bytes.len()),
743             Err(e) => Err(e),
744         }
745     }
747     fn sign(
748         &mut self,
749         data: &[u8],
750         params: &Option<CK_RSA_PKCS_PSS_PARAMS>,
751     ) -> Result<Vec<u8>, Error> {
752         self.sign_with_retry(data, params, true)
753     }
756 struct CertStore {
757     handle: HCERTSTORE,
760 impl Drop for CertStore {
761     fn drop(&mut self) {
762         if !self.handle.is_null() {
763             unsafe {
764                 CertCloseStore(self.handle, 0);
765             }
766         }
767     }
770 impl Deref for CertStore {
771     type Target = HCERTSTORE;
773     fn deref(&self) -> &Self::Target {
774         &self.handle
775     }
778 impl CertStore {
779     fn new(handle: HCERTSTORE) -> CertStore {
780         CertStore { handle }
781     }
784 // Given a pointer to a CERT_CHAIN_CONTEXT, enumerates each chain in the context and each element
785 // in each chain to gather every CERT_CONTEXT pointed to by the CERT_CHAIN_CONTEXT.
786 // https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/ns-wincrypt-cert_chain_context says
787 // that the 0th element of the 0th chain will be the end-entity certificate. This certificate (if
788 // present), will be the 0th element of the returned Vec.
789 fn gather_cert_contexts(cert_chain_context: *const CERT_CHAIN_CONTEXT) -> Vec<*const CERT_CONTEXT> {
790     let mut cert_contexts = Vec::new();
791     if cert_chain_context.is_null() {
792         return cert_contexts;
793     }
794     let cert_chain_context = unsafe { &*cert_chain_context };
795     let cert_chains = unsafe {
796         std::slice::from_raw_parts(
797             cert_chain_context.rgpChain,
798             cert_chain_context.cChain as usize,
799         )
800     };
801     for cert_chain in cert_chains {
802         // First dereference the borrow.
803         let cert_chain = *cert_chain;
804         if cert_chain.is_null() {
805             continue;
806         }
807         // Then dereference the pointer.
808         let cert_chain = unsafe { &*cert_chain };
809         let chain_elements = unsafe {
810             std::slice::from_raw_parts(cert_chain.rgpElement, cert_chain.cElement as usize)
811         };
812         for chain_element in chain_elements {
813             let chain_element = *chain_element; // dereference borrow
814             if chain_element.is_null() {
815                 continue;
816             }
817             let chain_element = unsafe { &*chain_element }; // dereference pointer
818             cert_contexts.push(chain_element.pCertContext);
819         }
820     }
821     cert_contexts
824 pub struct Backend {}
826 impl ClientCertsBackend for Backend {
827     type Cert = Cert;
828     type Key = Key;
830     /// Attempts to enumerate certificates with private keys exposed by the OS. Currently only looks in
831     /// the "My" cert store of the current user. In the future this may look in more locations.
832     fn find_objects(&self) -> Result<(Vec<Cert>, Vec<Key>), Error> {
833         let mut certs = Vec::new();
834         let mut keys = Vec::new();
835         let location_flags = CERT_SYSTEM_STORE_CURRENT_USER
836             | CERT_STORE_OPEN_EXISTING_FLAG
837             | CERT_STORE_READONLY_FLAG;
838         let store_name = match CString::new("My") {
839             Ok(store_name) => store_name,
840             Err(_) => return Err(error_here!(ErrorType::LibraryFailure)),
841         };
842         let store = CertStore::new(unsafe {
843             CertOpenStore(
844                 CERT_STORE_PROV_SYSTEM_REGISTRY_A,
845                 0,
846                 0,
847                 location_flags,
848                 store_name.as_ptr() as *const winapi::ctypes::c_void,
849             )
850         });
851         if store.is_null() {
852             return Err(error_here!(ErrorType::ExternalError));
853         }
854         let find_params = CERT_CHAIN_FIND_ISSUER_PARA {
855             cbSize: std::mem::size_of::<CERT_CHAIN_FIND_ISSUER_PARA>() as u32,
856             pszUsageIdentifier: std::ptr::null(),
857             dwKeySpec: 0,
858             dwAcquirePrivateKeyFlags: 0,
859             cIssuer: 0,
860             rgIssuer: std::ptr::null_mut(),
861             pfnFindCallback: None,
862             pvFindArg: std::ptr::null_mut(),
863             pdwIssuerChainIndex: std::ptr::null_mut(),
864             pdwIssuerElementIndex: std::ptr::null_mut(),
865         };
866         let mut cert_chain_context: PCCERT_CHAIN_CONTEXT = std::ptr::null_mut();
867         loop {
868             // CertFindChainInStore finds all certificates with private keys in the store. It also
869             // attempts to build a verified certificate chain to a trust anchor for each certificate.
870             // We gather and hold onto these extra certificates so that gecko can use them when
871             // filtering potential client certificates according to the acceptable CAs list sent by
872             // servers when they request client certificates.
873             cert_chain_context = unsafe {
874                 CertFindChainInStore(
875                     *store,
876                     X509_ASN_ENCODING,
877                     CERT_CHAIN_FIND_BY_ISSUER_CACHE_ONLY_FLAG
878                         | CERT_CHAIN_FIND_BY_ISSUER_CACHE_ONLY_URL_FLAG,
879                     CERT_CHAIN_FIND_BY_ISSUER,
880                     &find_params as *const CERT_CHAIN_FIND_ISSUER_PARA
881                         as *const winapi::ctypes::c_void,
882                     cert_chain_context,
883                 )
884             };
885             if cert_chain_context.is_null() {
886                 break;
887             }
888             let cert_contexts = gather_cert_contexts(cert_chain_context);
889             // The 0th CERT_CONTEXT is the end-entity (i.e. the certificate with the private key we're
890             // after).
891             match cert_contexts.get(0) {
892                 Some(cert_context) => {
893                     let key = match Key::new(*cert_context) {
894                         Ok(key) => key,
895                         Err(_) => continue,
896                     };
897                     let cert = match Cert::new(*cert_context) {
898                         Ok(cert) => cert,
899                         Err(_) => continue,
900                     };
901                     certs.push(cert);
902                     keys.push(key);
903                 }
904                 None => {}
905             };
906             for cert_context in cert_contexts.iter().skip(1) {
907                 if let Ok(cert) = Cert::new(*cert_context) {
908                     certs.push(cert);
909                 }
910             }
911         }
912         Ok((certs, keys))
913     }