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};
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.
26 hKey: NCRYPT_KEY_HANDLE,
27 pPaddingInfo: *mut c_void,
32 pcbResult: *mut DWORD,
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
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 {
45 &mut cert_info_subject,
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 {
56 &mut cert_info_subject,
58 subject_dn_string_bytes.as_mut_ptr() as *mut i8,
59 subject_dn_string_bytes
62 .map_err(|_| error_here!(ErrorType::ValueTooLarge))?,
65 if subject_dn_len as usize != subject_dn_string_bytes.len() {
66 return Err(error_here!(ErrorType::ExternalError));
68 Ok(subject_dn_string_bytes)
71 /// Represents a certificate for which there exists a corresponding private key.
73 /// PKCS #11 object class. Will be `CKO_CERTIFICATE`.
75 /// Whether or not this is on a token. Will be `CK_TRUE`.
77 /// An identifier unique to this certificate. Must be the same as the ID for the private key.
79 /// The bytes of a human-readable label for this certificate. Will be the subject DN.
81 /// The DER bytes of the certificate.
83 /// The DER bytes of the issuer distinguished name of the certificate.
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.
89 /// Which slot this certificate should be exposed on.
94 fn new(cert_context: PCCERT_CONTEXT) -> Result<Cert, Error> {
95 let cert = unsafe { &*cert_context };
96 let cert_info = unsafe { &*cert.pCertInfo };
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)?;
104 class: serialize_uint(CKO_CERTIFICATE)?,
105 token: serialize_uint(CK_TRUE)?,
112 slot_type: SlotType::Modern,
116 fn class(&self) -> &[u8] {
120 fn token(&self) -> &[u8] {
124 fn id(&self) -> &[u8] {
128 fn label(&self) -> &[u8] {
132 fn value(&self) -> &[u8] {
136 fn issuer(&self) -> &[u8] {
140 fn serial_number(&self) -> &[u8] {
144 fn subject(&self) -> &[u8] {
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 {
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(),
160 CKA_VALUE => self.value(),
161 CKA_ISSUER => self.issuer(),
162 CKA_SERIAL_NUMBER => self.serial_number(),
163 CKA_SUBJECT => self.subject(),
166 if attr_value.as_slice() != comparison {
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(),
179 CKA_VALUE => self.value(),
180 CKA_ISSUER => self.issuer(),
181 CKA_SERIAL_NUMBER => self.serial_number(),
182 CKA_SUBJECT => self.subject(),
189 struct CertContext(PCCERT_CONTEXT);
192 fn new(cert: PCCERT_CONTEXT) -> CertContext {
193 CertContext(unsafe { CertDuplicateCertificateContext(cert) })
197 impl Drop for CertContext {
200 CertFreeCertificateContext(self.0);
205 impl Deref for CertContext {
206 type Target = PCCERT_CONTEXT;
208 fn deref(&self) -> &Self::Target {
214 NCrypt(NCRYPT_KEY_HANDLE),
215 CryptoAPI(HCRYPTPROV, DWORD),
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;
224 if CryptAcquireCertificatePrivateKey(
226 CRYPT_ACQUIRE_PREFER_NCRYPT_KEY_FLAG,
227 std::ptr::null_mut(),
233 return Err(error_here!(
234 ErrorType::ExternalError,
235 GetLastError().to_string()
240 return Err(error_here!(ErrorType::ExternalError));
242 if key_spec == CERT_NCRYPT_KEY_SPEC {
243 Ok(KeyHandle::NCrypt(key_handle as NCRYPT_KEY_HANDLE))
245 Ok(KeyHandle::CryptoAPI(key_handle as HCRYPTPROV, key_spec))
252 params: &Option<CK_RSA_PKCS_PSS_PARAMS>,
255 ) -> Result<Vec<u8>, Error> {
257 KeyHandle::NCrypt(ncrypt_handle) => {
258 sign_ncrypt(ncrypt_handle, data, params, do_signature, key_type)
260 KeyHandle::CryptoAPI(hcryptprov, key_spec) => {
261 sign_cryptoapi(hcryptprov, key_spec, data, params, do_signature)
267 impl Drop for KeyHandle {
270 KeyHandle::NCrypt(ncrypt_handle) => unsafe {
271 let _ = NCryptFreeObject(*ncrypt_handle);
273 KeyHandle::CryptoAPI(hcryptprov, _) => unsafe {
274 let _ = CryptReleaseContext(*hcryptprov, 0);
281 ncrypt_handle: &NCRYPT_KEY_HANDLE,
283 params: &Option<CK_RSA_PKCS_PSS_PARAMS>,
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 {
301 .map_err(|_| error_here!(ErrorType::ValueTooLarge))?,
302 std::ptr::null_mut(),
308 // 0 is "ERROR_SUCCESS" (but "ERROR_SUCCESS" is unsigned, whereas SECURITY_STATUS is signed)
310 return Err(error_here!(ErrorType::ExternalError, status.to_string()));
312 let mut signature = vec![0; signature_len as usize];
314 return Ok(signature);
316 let mut final_signature_len = signature_len;
317 let status = unsafe {
324 .map_err(|_| error_here!(ErrorType::ValueTooLarge))?,
325 signature.as_mut_ptr(),
327 &mut final_signature_len,
332 return Err(error_here!(ErrorType::ExternalError, status.to_string()));
334 if final_signature_len != signature_len {
335 return Err(error_here!(ErrorType::ExternalError));
341 hcryptprov: &HCRYPTPROV,
344 params: &Option<CK_RSA_PKCS_PSS_PARAMS>,
346 ) -> Result<Vec<u8>, Error> {
347 if params.is_some() {
348 return Err(error_here!(ErrorType::LibraryFailure));
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;
360 std::ptr::null_mut(),
362 std::ptr::null_mut(),
367 return Err(error_here!(
368 ErrorType::ExternalError,
369 unsafe { GetLastError() }.to_string()
372 let mut signature = vec![0; signature_len as usize];
374 return Ok(signature);
376 let mut final_signature_len = signature_len;
381 std::ptr::null_mut(),
383 signature.as_mut_ptr(),
384 &mut final_signature_len,
388 return Err(error_here!(
389 ErrorType::ExternalError,
390 unsafe { GetLastError() }.to_string()
393 if final_signature_len != signature_len {
394 return Err(error_here!(ErrorType::ExternalError));
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).
402 struct HCryptHash(HCRYPTHASH);
405 fn new(hcryptprov: &HCRYPTPROV, hash_bytes: &[u8]) -> Result<HCryptHash, Error> {
406 let alg = match hash_bytes.len() {
412 return Err(error_here!(ErrorType::UnsupportedInput));
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()
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()
432 impl Drop for HCryptHash {
435 CryptDestroyHash(self.0);
440 impl Deref for HCryptHash {
441 type Target = HCRYPTHASH;
443 fn deref(&self) -> &Self::Target {
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",
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];
465 RSA_PKCS1(BCRYPT_PKCS1_PADDING_INFO),
466 RSA_PSS(BCRYPT_PSS_PADDING_INFO),
472 params: &Option<CK_RSA_PKCS_PSS_PARAMS>,
473 ) -> Result<SignParams, Error> {
474 // EC is easy, so handle that first.
476 KeyType::EC => return Ok(SignParams::EC),
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,
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(),
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,
496 return Err(error_here!(ErrorType::UnsupportedInput));
499 Ok(SignParams::RSA_PSS(BCRYPT_PSS_PADDING_INFO {
500 pszAlgId: algorithm_string.as_ptr(),
501 cbSalt: pss_params.sLen,
505 fn params_ptr(&mut self) -> *mut std::ffi::c_void {
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
511 SignParams::RSA_PSS(params) => {
512 params as *mut BCRYPT_PSS_PADDING_INFO as *mut std::ffi::c_void
517 fn flags(&self) -> u32 {
520 SignParams::RSA_PKCS1(_) => NCRYPT_PAD_PKCS1_FLAG,
521 SignParams::RSA_PSS(_) => NCRYPT_PAD_PSS_FLAG,
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)]
534 /// Represents a private key for which there exists a corresponding certificate.
536 /// A handle on the OS mechanism that represents the certificate for this key.
538 /// PKCS #11 object class. Will be `CKO_PRIVATE_KEY`.
540 /// Whether or not this is on a token. Will be `CK_TRUE`.
542 /// An identifier unique to this key. Must be the same as the ID for the certificate.
544 /// Whether or not this key is "private" (can it be exported?). Will be CK_TRUE (it can't be
547 /// PKCS #11 key type. Will be `CKK_EC` for EC, and `CKK_RSA` for RSA.
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.
557 /// A handle on the OS mechanism that represents this key.
558 key_handle: Option<KeyHandle>,
562 fn new(cert_context: PCCERT_CONTEXT) -> Result<Key, Error> {
563 let cert = unsafe { *cert_context };
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) }
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));
579 let public_key_bytes = unsafe {
580 std::slice::from_raw_parts(spki.PublicKey.pbData, spki.PublicKey.cbData as usize)
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;
588 unsafe { std::slice::from_raw_parts(params.pbData, params.cbData as usize) }
591 (KeyType::EC, CKK_EC)
593 return Err(error_here!(ErrorType::LibraryFailure));
595 let cert = CertContext::new(cert_context);
598 class: serialize_uint(CKO_PRIVATE_KEY)?,
599 token: serialize_uint(CK_TRUE)?,
601 private: serialize_uint(CK_TRUE)?,
602 key_type: serialize_uint(key_type_attribute)?,
606 slot_type: SlotType::Modern,
611 fn class(&self) -> &[u8] {
615 fn token(&self) -> &[u8] {
619 fn id(&self) -> &[u8] {
623 fn private(&self) -> &[u8] {
627 fn key_type(&self) -> &[u8] {
631 fn modulus(&self) -> Option<&[u8]> {
632 match &self.modulus {
633 Some(modulus) => Some(modulus.as_slice()),
638 fn ec_params(&self) -> Option<&[u8]> {
639 match &self.ec_params {
640 Some(ec_params) => Some(ec_params.as_slice()),
648 params: &Option<CK_RSA_PKCS_PSS_PARAMS>,
650 ) -> Result<Vec<u8>, Error> {
651 let result = self.sign_internal(data, params, do_signature);
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)
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.
668 params: &Option<CK_RSA_PKCS_PSS_PARAMS>,
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)?);
678 let key = match &self.key_handle {
680 None => return Err(error_here!(ErrorType::LibraryFailure)),
682 key.sign(data, params, do_signature, self.key_type_enum)
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 {
691 for (attr_type, attr_value) in attrs {
692 let comparison = match *attr_type {
693 CKA_CLASS => self.class(),
694 CKA_TOKEN => self.token(),
696 CKA_PRIVATE => self.private(),
697 CKA_KEY_TYPE => self.key_type(),
699 if let Some(modulus) = self.modulus() {
706 if let Some(ec_params) = self.ec_params() {
714 if attr_value.as_slice() != comparison {
721 fn get_attribute(&self, attribute: CK_ATTRIBUTE_TYPE) -> Option<&[u8]> {
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(),
736 fn get_signature_length(
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()),
750 params: &Option<CK_RSA_PKCS_PSS_PARAMS>,
751 ) -> Result<Vec<u8>, Error> {
752 self.sign_with_retry(data, params, true)
760 impl Drop for CertStore {
762 if !self.handle.is_null() {
764 CertCloseStore(self.handle, 0);
770 impl Deref for CertStore {
771 type Target = HCERTSTORE;
773 fn deref(&self) -> &Self::Target {
779 fn new(handle: HCERTSTORE) -> CertStore {
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;
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,
801 for cert_chain in cert_chains {
802 // First dereference the borrow.
803 let cert_chain = *cert_chain;
804 if cert_chain.is_null() {
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)
812 for chain_element in chain_elements {
813 let chain_element = *chain_element; // dereference borrow
814 if chain_element.is_null() {
817 let chain_element = unsafe { &*chain_element }; // dereference pointer
818 cert_contexts.push(chain_element.pCertContext);
824 pub struct Backend {}
826 impl ClientCertsBackend for Backend {
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)),
842 let store = CertStore::new(unsafe {
844 CERT_STORE_PROV_SYSTEM_REGISTRY_A,
848 store_name.as_ptr() as *const winapi::ctypes::c_void,
852 return Err(error_here!(ErrorType::ExternalError));
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(),
858 dwAcquirePrivateKeyFlags: 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(),
866 let mut cert_chain_context: PCCERT_CHAIN_CONTEXT = std::ptr::null_mut();
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(
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,
885 if cert_chain_context.is_null() {
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
891 match cert_contexts.get(0) {
892 Some(cert_context) => {
893 let key = match Key::new(*cert_context) {
897 let cert = match Cert::new(*cert_context) {
906 for cert_context in cert_contexts.iter().skip(1) {
907 if let Ok(cert) = Cert::new(*cert_context) {