tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

backend_windows.rs (29400B)


      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_camel_case_types)]
      7 
      8 use pkcs11_bindings::*;
      9 use rsclientcerts::cryptoki::*;
     10 use rsclientcerts::manager::{ClientCertsBackend, CryptokiObject, Sign};
     11 use rsclientcerts_util::*;
     12 use rsclientcerts_util::error::{Error, ErrorType};
     13 use std::convert::TryInto;
     14 use std::ffi::{c_void, CStr, CString};
     15 use std::ops::Deref;
     16 use std::slice;
     17 use std::time::{Duration, Instant};
     18 use winapi::shared::bcrypt::*;
     19 use winapi::shared::minwindef::{DWORD, PBYTE};
     20 use winapi::um::errhandlingapi::GetLastError;
     21 use winapi::um::ncrypt::*;
     22 use winapi::um::wincrypt::{HCRYPTHASH, HCRYPTPROV, *};
     23 use xpcom::interfaces::nsIEventTarget;
     24 use xpcom::{RefPtr, XpCom};
     25 
     26 // winapi has some support for ncrypt.h, but not for this function.
     27 extern "system" {
     28    fn NCryptSignHash(
     29        hKey: NCRYPT_KEY_HANDLE,
     30        pPaddingInfo: *mut c_void,
     31        pbHashValue: PBYTE,
     32        cbHashValue: DWORD,
     33        pbSignature: PBYTE,
     34        cbSignature: DWORD,
     35        pcbResult: *mut DWORD,
     36        dwFlags: DWORD,
     37    ) -> SECURITY_STATUS;
     38 }
     39 
     40 /// Given a `CERT_INFO`, tries to return the bytes of the subject distinguished name as formatted by
     41 /// `CertNameToStrA` using the flag `CERT_SIMPLE_NAME_STR`. This is used as the label for the
     42 /// certificate.
     43 fn get_cert_subject_dn(cert_info: &CERT_INFO) -> Result<Vec<u8>, Error> {
     44    let mut cert_info_subject = cert_info.Subject;
     45    let subject_dn_len = unsafe {
     46        CertNameToStrA(
     47            X509_ASN_ENCODING,
     48            &mut cert_info_subject,
     49            CERT_SIMPLE_NAME_STR,
     50            std::ptr::null_mut(),
     51            0,
     52        )
     53    };
     54    // subject_dn_len includes the terminating null byte.
     55    let mut subject_dn_string_bytes: Vec<u8> = vec![0; subject_dn_len as usize];
     56    let subject_dn_len = unsafe {
     57        CertNameToStrA(
     58            X509_ASN_ENCODING,
     59            &mut cert_info_subject,
     60            CERT_SIMPLE_NAME_STR,
     61            subject_dn_string_bytes.as_mut_ptr() as *mut i8,
     62            subject_dn_string_bytes
     63                .len()
     64                .try_into()
     65                .map_err(|_| error_here!(ErrorType::ValueTooLarge))?,
     66        )
     67    };
     68    if subject_dn_len as usize != subject_dn_string_bytes.len() {
     69        return Err(error_here!(ErrorType::ExternalError));
     70    }
     71    Ok(subject_dn_string_bytes)
     72 }
     73 
     74 fn new_cert(cert: PCCERT_CONTEXT) -> Result<CryptokiCert, Error> {
     75    let der =
     76        unsafe { slice::from_raw_parts((*cert).pbCertEncoded, (*cert).cbCertEncoded as usize) };
     77    let cert_info = unsafe { &*(*cert).pCertInfo };
     78    let label = get_cert_subject_dn(cert_info)?;
     79    CryptokiCert::new(der.to_vec(), label)
     80 }
     81 
     82 struct CertContext(PCCERT_CONTEXT);
     83 
     84 impl CertContext {
     85    fn new(cert: PCCERT_CONTEXT) -> CertContext {
     86        CertContext(unsafe { CertDuplicateCertificateContext(cert) })
     87    }
     88 }
     89 
     90 impl Drop for CertContext {
     91    fn drop(&mut self) {
     92        unsafe {
     93            CertFreeCertificateContext(self.0);
     94        }
     95    }
     96 }
     97 
     98 impl Deref for CertContext {
     99    type Target = PCCERT_CONTEXT;
    100 
    101    fn deref(&self) -> &Self::Target {
    102        &self.0
    103    }
    104 }
    105 
    106 /// Safety: strictly speaking, it isn't safe to send `CertContext` across threads. The
    107 /// implementation handles this by wrapping `CertContext` in `ThreadSpecificHandles`. However, in
    108 /// order to implement `Drop` for `ThreadSpecificHandles`, the `CertContext` it holds must be sent
    109 /// to the appropriate thread, hence this impl.
    110 unsafe impl Send for CertContext {}
    111 
    112 enum KeyHandle {
    113    NCrypt(NCRYPT_KEY_HANDLE),
    114    CryptoAPI(HCRYPTPROV, DWORD),
    115 }
    116 
    117 impl KeyHandle {
    118    fn from_cert(cert: &CertContext) -> Result<KeyHandle, Error> {
    119        let mut key_handle = 0;
    120        let mut key_spec = 0;
    121        let mut must_free = 0;
    122        unsafe {
    123            if CryptAcquireCertificatePrivateKey(
    124                **cert,
    125                CRYPT_ACQUIRE_PREFER_NCRYPT_KEY_FLAG,
    126                std::ptr::null_mut(),
    127                &mut key_handle,
    128                &mut key_spec,
    129                &mut must_free,
    130            ) != 1
    131            {
    132                return Err(error_here!(
    133                    ErrorType::ExternalError,
    134                    GetLastError().to_string()
    135                ));
    136            }
    137        }
    138        if must_free == 0 {
    139            return Err(error_here!(ErrorType::ExternalError));
    140        }
    141        if key_spec == CERT_NCRYPT_KEY_SPEC {
    142            Ok(KeyHandle::NCrypt(key_handle as NCRYPT_KEY_HANDLE))
    143        } else {
    144            Ok(KeyHandle::CryptoAPI(key_handle as HCRYPTPROV, key_spec))
    145        }
    146    }
    147 
    148    fn sign(
    149        &self,
    150        data: &[u8],
    151        params: &Option<CK_RSA_PKCS_PSS_PARAMS>,
    152        do_signature: bool,
    153        key_type: KeyType,
    154    ) -> Result<Vec<u8>, Error> {
    155        match &self {
    156            KeyHandle::NCrypt(ncrypt_handle) => {
    157                sign_ncrypt(ncrypt_handle, data, params, do_signature, key_type)
    158            }
    159            KeyHandle::CryptoAPI(hcryptprov, key_spec) => {
    160                sign_cryptoapi(hcryptprov, key_spec, data, params, do_signature)
    161            }
    162        }
    163    }
    164 }
    165 
    166 impl Drop for KeyHandle {
    167    fn drop(&mut self) {
    168        match self {
    169            KeyHandle::NCrypt(ncrypt_handle) => unsafe {
    170                let _ = NCryptFreeObject(*ncrypt_handle);
    171            },
    172            KeyHandle::CryptoAPI(hcryptprov, _) => unsafe {
    173                let _ = CryptReleaseContext(*hcryptprov, 0);
    174            },
    175        }
    176    }
    177 }
    178 
    179 /// Safety: see the comment for the `Send` impl for `CertContext`.
    180 unsafe impl Send for KeyHandle {}
    181 
    182 fn sign_ncrypt(
    183    ncrypt_handle: &NCRYPT_KEY_HANDLE,
    184    data: &[u8],
    185    params: &Option<CK_RSA_PKCS_PSS_PARAMS>,
    186    do_signature: bool,
    187    key_type: KeyType,
    188 ) -> Result<Vec<u8>, Error> {
    189    let mut sign_params = SignParams::new(key_type, params)?;
    190    let params_ptr = sign_params.params_ptr();
    191    let flags = sign_params.flags();
    192    let mut data = data.to_vec();
    193    let mut signature_len = 0;
    194    // We call NCryptSignHash twice: the first time to get the size of the buffer we need to
    195    // allocate and then again to actually sign the data, if `do_signature` is `true`.
    196    let status = unsafe {
    197        NCryptSignHash(
    198            *ncrypt_handle,
    199            params_ptr,
    200            data.as_mut_ptr(),
    201            data.len()
    202                .try_into()
    203                .map_err(|_| error_here!(ErrorType::ValueTooLarge))?,
    204            std::ptr::null_mut(),
    205            0,
    206            &mut signature_len,
    207            flags,
    208        )
    209    };
    210    // 0 is "ERROR_SUCCESS" (but "ERROR_SUCCESS" is unsigned, whereas SECURITY_STATUS is signed)
    211    if status != 0 {
    212        return Err(error_here!(ErrorType::ExternalError, status.to_string()));
    213    }
    214    let mut signature = vec![0; signature_len as usize];
    215    if !do_signature {
    216        return Ok(signature);
    217    }
    218    let mut final_signature_len = signature_len;
    219    let status = unsafe {
    220        NCryptSignHash(
    221            *ncrypt_handle,
    222            params_ptr,
    223            data.as_mut_ptr(),
    224            data.len()
    225                .try_into()
    226                .map_err(|_| error_here!(ErrorType::ValueTooLarge))?,
    227            signature.as_mut_ptr(),
    228            signature_len,
    229            &mut final_signature_len,
    230            flags,
    231        )
    232    };
    233    if status != 0 {
    234        return Err(error_here!(ErrorType::ExternalError, status.to_string()));
    235    }
    236    if final_signature_len != signature_len {
    237        return Err(error_here!(ErrorType::ExternalError));
    238    }
    239    Ok(signature)
    240 }
    241 
    242 fn sign_cryptoapi(
    243    hcryptprov: &HCRYPTPROV,
    244    key_spec: &DWORD,
    245    data: &[u8],
    246    params: &Option<CK_RSA_PKCS_PSS_PARAMS>,
    247    do_signature: bool,
    248 ) -> Result<Vec<u8>, Error> {
    249    if params.is_some() {
    250        return Err(error_here!(ErrorType::LibraryFailure));
    251    }
    252    // data will be an encoded DigestInfo, which specifies the hash algorithm and bytes of the hash
    253    // to sign. However, CryptoAPI requires directly specifying the bytes of the hash, so it must
    254    // be extracted first.
    255    let (_, hash_bytes) = read_digest_info(data)?;
    256    let hash = HCryptHash::new(hcryptprov, hash_bytes)?;
    257    let mut signature_len = 0;
    258    if unsafe {
    259        CryptSignHashW(
    260            *hash,
    261            *key_spec,
    262            std::ptr::null_mut(),
    263            0,
    264            std::ptr::null_mut(),
    265            &mut signature_len,
    266        )
    267    } != 1
    268    {
    269        return Err(error_here!(
    270            ErrorType::ExternalError,
    271            unsafe { GetLastError() }.to_string()
    272        ));
    273    }
    274    let mut signature = vec![0; signature_len as usize];
    275    if !do_signature {
    276        return Ok(signature);
    277    }
    278    let mut final_signature_len = signature_len;
    279    if unsafe {
    280        CryptSignHashW(
    281            *hash,
    282            *key_spec,
    283            std::ptr::null_mut(),
    284            0,
    285            signature.as_mut_ptr(),
    286            &mut final_signature_len,
    287        )
    288    } != 1
    289    {
    290        return Err(error_here!(
    291            ErrorType::ExternalError,
    292            unsafe { GetLastError() }.to_string()
    293        ));
    294    }
    295    if final_signature_len != signature_len {
    296        return Err(error_here!(ErrorType::ExternalError));
    297    }
    298    // CryptoAPI returns the signature with the most significant byte last (little-endian),
    299    // whereas PKCS#11 expects the most significant byte first (big-endian).
    300    signature.reverse();
    301    Ok(signature)
    302 }
    303 
    304 struct HCryptHash(HCRYPTHASH);
    305 
    306 impl HCryptHash {
    307    fn new(hcryptprov: &HCRYPTPROV, hash_bytes: &[u8]) -> Result<HCryptHash, Error> {
    308        let alg = match hash_bytes.len() {
    309            20 => CALG_SHA1,
    310            32 => CALG_SHA_256,
    311            48 => CALG_SHA_384,
    312            64 => CALG_SHA_512,
    313            _ => {
    314                return Err(error_here!(ErrorType::UnsupportedInput));
    315            }
    316        };
    317        let mut hash: HCRYPTHASH = 0;
    318        if unsafe { CryptCreateHash(*hcryptprov, alg, 0, 0, &mut hash) } != 1 {
    319            return Err(error_here!(
    320                ErrorType::ExternalError,
    321                unsafe { GetLastError() }.to_string()
    322            ));
    323        }
    324        if unsafe { CryptSetHashParam(hash, HP_HASHVAL, hash_bytes.as_ptr(), 0) } != 1 {
    325            return Err(error_here!(
    326                ErrorType::ExternalError,
    327                unsafe { GetLastError() }.to_string()
    328            ));
    329        }
    330        Ok(HCryptHash(hash))
    331    }
    332 }
    333 
    334 impl Drop for HCryptHash {
    335    fn drop(&mut self) {
    336        unsafe {
    337            CryptDestroyHash(self.0);
    338        }
    339    }
    340 }
    341 
    342 impl Deref for HCryptHash {
    343    type Target = HCRYPTHASH;
    344 
    345    fn deref(&self) -> &Self::Target {
    346        &self.0
    347    }
    348 }
    349 
    350 // In some cases, the ncrypt API takes a pointer to a null-terminated wide-character string as a way
    351 // of specifying an algorithm. The "right" way to do this would be to take the corresponding
    352 // &'static str constant provided by the winapi crate, create an OsString from it, encode it as wide
    353 // characters, and collect it into a Vec<u16>. However, since the implementation that provides this
    354 // functionality isn't constant, we would have to manage the memory this creates and uses. Since
    355 // rust structures generally can't be self-referrential, this memory would have to live elsewhere,
    356 // and the nice abstractions we've created for this implementation start to break down. It's much
    357 // simpler to hard-code the identifiers we support, since there are only four of them.
    358 // The following arrays represent the identifiers "SHA1", "SHA256", "SHA384", and "SHA512",
    359 // respectively.
    360 const SHA1_ALGORITHM_STRING: &[u16] = &[83, 72, 65, 49, 0];
    361 const SHA256_ALGORITHM_STRING: &[u16] = &[83, 72, 65, 50, 53, 54, 0];
    362 const SHA384_ALGORITHM_STRING: &[u16] = &[83, 72, 65, 51, 56, 52, 0];
    363 const SHA512_ALGORITHM_STRING: &[u16] = &[83, 72, 65, 53, 49, 50, 0];
    364 
    365 enum SignParams {
    366    EC,
    367    RSA_PKCS1(BCRYPT_PKCS1_PADDING_INFO),
    368    RSA_PSS(BCRYPT_PSS_PADDING_INFO),
    369 }
    370 
    371 impl SignParams {
    372    fn new(
    373        key_type: KeyType,
    374        params: &Option<CK_RSA_PKCS_PSS_PARAMS>,
    375    ) -> Result<SignParams, Error> {
    376        // EC is easy, so handle that first.
    377        match key_type {
    378            KeyType::EC(_) => return Ok(SignParams::EC),
    379            KeyType::RSA => {}
    380        }
    381        // If `params` is `Some`, we're doing RSA-PSS. If it is `None`, we're doing RSA-PKCS1.
    382        let pss_params = match params {
    383            Some(pss_params) => pss_params,
    384            None => {
    385                // The hash algorithm should be encoded in the data to be signed, so we don't have to
    386                // (and don't want to) specify a particular algorithm here.
    387                return Ok(SignParams::RSA_PKCS1(BCRYPT_PKCS1_PADDING_INFO {
    388                    pszAlgId: std::ptr::null(),
    389                }));
    390            }
    391        };
    392        let algorithm_string = match pss_params.hashAlg {
    393            CKM_SHA_1 => SHA1_ALGORITHM_STRING,
    394            CKM_SHA256 => SHA256_ALGORITHM_STRING,
    395            CKM_SHA384 => SHA384_ALGORITHM_STRING,
    396            CKM_SHA512 => SHA512_ALGORITHM_STRING,
    397            _ => {
    398                return Err(error_here!(ErrorType::UnsupportedInput));
    399            }
    400        };
    401        Ok(SignParams::RSA_PSS(BCRYPT_PSS_PADDING_INFO {
    402            pszAlgId: algorithm_string.as_ptr(),
    403            cbSalt: pss_params.sLen,
    404        }))
    405    }
    406 
    407    fn params_ptr(&mut self) -> *mut std::ffi::c_void {
    408        match self {
    409            SignParams::EC => std::ptr::null_mut(),
    410            SignParams::RSA_PKCS1(params) => {
    411                params as *mut BCRYPT_PKCS1_PADDING_INFO as *mut std::ffi::c_void
    412            }
    413            SignParams::RSA_PSS(params) => {
    414                params as *mut BCRYPT_PSS_PADDING_INFO as *mut std::ffi::c_void
    415            }
    416        }
    417    }
    418 
    419    fn flags(&self) -> u32 {
    420        match *self {
    421            SignParams::EC => 0,
    422            SignParams::RSA_PKCS1(_) => NCRYPT_PAD_PKCS1_FLAG,
    423            SignParams::RSA_PSS(_) => NCRYPT_PAD_PSS_FLAG,
    424        }
    425    }
    426 }
    427 
    428 /// Helper struct to hold onto OS-specific handles that must only be used on a particular thread.
    429 struct ThreadSpecificHandles {
    430    /// The only thread that these handles may be used on.
    431    thread: RefPtr<nsIEventTarget>,
    432    /// A handle on the OS mechanism that represents the certificate for a key.
    433    cert: Option<CertContext>,
    434    /// A handle on the OS mechanism that represents a key.
    435    key: Option<KeyHandle>,
    436 }
    437 
    438 impl ThreadSpecificHandles {
    439    fn new(cert: CertContext, thread: &nsIEventTarget) -> ThreadSpecificHandles {
    440        ThreadSpecificHandles {
    441            thread: RefPtr::new(thread),
    442            cert: Some(cert),
    443            key: None,
    444        }
    445    }
    446 
    447    fn sign_or_get_signature_length(
    448        &mut self,
    449        key_type: KeyType,
    450        data: &[u8],
    451        params: &Option<CK_RSA_PKCS_PSS_PARAMS>,
    452        do_signature: bool,
    453    ) -> Result<Vec<u8>, Error> {
    454        let Some(cert) = self.cert.take() else {
    455            return Err(error_here!(ErrorType::LibraryFailure));
    456        };
    457        let mut maybe_key = self.key.take();
    458        let thread = self.thread.clone();
    459        let data = data.to_vec();
    460        let params = params.clone();
    461        let task = moz_task::spawn_onto("sign", &thread, async move {
    462            let result = sign_internal(
    463                &cert,
    464                &mut maybe_key,
    465                key_type,
    466                &data,
    467                &params,
    468                do_signature,
    469            );
    470            if result.is_ok() {
    471                return (result, cert, maybe_key);
    472            }
    473            // Some devices appear to not work well when the key handle is held for too long or if a
    474            // card is inserted/removed while Firefox is running. Try refreshing the key handle.
    475            let _ = maybe_key.take();
    476            (
    477                sign_internal(
    478                    &cert,
    479                    &mut maybe_key,
    480                    key_type,
    481                    &data,
    482                    &params,
    483                    do_signature,
    484                ),
    485                cert,
    486                maybe_key,
    487            )
    488        });
    489        let (signature_result, cert, maybe_key) = futures_executor::block_on(task);
    490        self.cert = Some(cert);
    491        self.key = maybe_key;
    492        signature_result
    493    }
    494 }
    495 
    496 /// data: the data to sign
    497 /// do_signature: if true, actually perform the signature. Otherwise, return a `Vec<u8>` of the
    498 /// length the signature would be, if performed.
    499 fn sign_internal(
    500    cert: &CertContext,
    501    maybe_key: &mut Option<KeyHandle>,
    502    key_type: KeyType,
    503    data: &[u8],
    504    params: &Option<CK_RSA_PKCS_PSS_PARAMS>,
    505    do_signature: bool,
    506 ) -> Result<Vec<u8>, Error> {
    507    // If this key hasn't been used for signing yet, there won't be a cached key handle. Obtain
    508    // and cache it if this is the case. Doing so can cause the underlying implementation to
    509    // show an authentication or pin prompt to the user. Caching the handle can avoid causing
    510    // multiple prompts to be displayed in some cases.
    511    if maybe_key.is_none() {
    512        let _ = maybe_key.replace(KeyHandle::from_cert(cert)?);
    513    }
    514    let Some(key) = maybe_key.as_ref() else {
    515        return Err(error_here!(ErrorType::LibraryFailure));
    516    };
    517    key.sign(data, params, do_signature, key_type)
    518 }
    519 
    520 impl Drop for ThreadSpecificHandles {
    521    fn drop(&mut self) {
    522        // Ensure any OS handles are dropped on the appropriate thread.
    523        let cert = self.cert.take();
    524        let key = self.key.take();
    525        let thread = self.thread.clone();
    526        // It is possible that we're already on the appropriate thread (e.g. if an error was
    527        // encountered in `find_objects` and these handles are being released shortly after being
    528        // created).
    529        if moz_task::is_on_current_thread(&thread) {
    530            drop(cert);
    531            drop(key);
    532        } else {
    533            let task = moz_task::spawn_onto("drop", &thread, async move {
    534                drop(cert);
    535                drop(key);
    536            });
    537            futures_executor::block_on(task)
    538        }
    539    }
    540 }
    541 
    542 /// Represents a private key for which there exists a corresponding certificate.
    543 pub struct Key {
    544    /// The OS handles for this key. May only be used on the thread they were created on.
    545    handles: ThreadSpecificHandles,
    546    /// The decoded information about the key.
    547    cryptoki_key: CryptokiKey,
    548 }
    549 
    550 impl Key {
    551    fn new(cert_context: PCCERT_CONTEXT, thread: &nsIEventTarget) -> Result<Key, Error> {
    552        let cert = unsafe { *cert_context };
    553        let cert_der =
    554            unsafe { slice::from_raw_parts(cert.pbCertEncoded, cert.cbCertEncoded as usize) };
    555        let cert_info = unsafe { &*cert.pCertInfo };
    556        let spki = &cert_info.SubjectPublicKeyInfo;
    557        let algorithm_oid = unsafe { CStr::from_ptr(spki.Algorithm.pszObjId) }
    558            .to_str()
    559            .map_err(|_| error_here!(ErrorType::ExternalError))?;
    560        let (modulus, ec_params) = if algorithm_oid == szOID_RSA_RSA {
    561            if spki.PublicKey.cUnusedBits != 0 {
    562                return Err(error_here!(ErrorType::ExternalError));
    563            }
    564            let public_key_bytes = unsafe {
    565                std::slice::from_raw_parts(spki.PublicKey.pbData, spki.PublicKey.cbData as usize)
    566            };
    567            let modulus = read_rsa_modulus(public_key_bytes)?;
    568            (Some(modulus), None)
    569        } else if algorithm_oid == szOID_ECC_PUBLIC_KEY {
    570            let params = &spki.Algorithm.Parameters;
    571            let ec_params =
    572                unsafe { std::slice::from_raw_parts(params.pbData, params.cbData as usize) }
    573                    .to_vec();
    574            (None, Some(ec_params))
    575        } else {
    576            return Err(error_here!(ErrorType::LibraryFailure));
    577        };
    578        let cert = CertContext::new(cert_context);
    579        Ok(Key {
    580            handles: ThreadSpecificHandles::new(cert, thread),
    581            cryptoki_key: CryptokiKey::new(modulus, ec_params, cert_der)?,
    582        })
    583    }
    584 
    585    fn sign_or_get_signature_length(
    586        &mut self,
    587        data: &[u8],
    588        params: &Option<CK_RSA_PKCS_PSS_PARAMS>,
    589        do_signature: bool,
    590    ) -> Result<Vec<u8>, Error> {
    591        self.handles.sign_or_get_signature_length(
    592            self.cryptoki_key.key_type(),
    593            data,
    594            params,
    595            do_signature,
    596        )
    597    }
    598 }
    599 
    600 impl Sign for Key {
    601    fn get_signature_length(
    602        &mut self,
    603        data: &[u8],
    604        params: &Option<CK_RSA_PKCS_PSS_PARAMS>,
    605    ) -> Result<usize, Error> {
    606        self.sign_or_get_signature_length(data, params, false)
    607            .map(|signature| signature.len())
    608    }
    609 
    610    fn sign(
    611        &mut self,
    612        data: &[u8],
    613        params: &Option<CK_RSA_PKCS_PSS_PARAMS>,
    614    ) -> Result<Vec<u8>, Error> {
    615        self.sign_or_get_signature_length(data, params, true)
    616    }
    617 }
    618 
    619 impl CryptokiObject for Key {
    620    fn matches(&self, attrs: &[(CK_ATTRIBUTE_TYPE, Vec<u8>)]) -> bool {
    621        self.cryptoki_key.matches(attrs)
    622    }
    623 
    624    fn get_attribute(&self, attribute: CK_ATTRIBUTE_TYPE) -> Option<&[u8]> {
    625        self.cryptoki_key.get_attribute(attribute)
    626    }
    627 }
    628 
    629 struct CertStore {
    630    handle: HCERTSTORE,
    631 }
    632 
    633 impl Drop for CertStore {
    634    fn drop(&mut self) {
    635        if !self.handle.is_null() {
    636            unsafe {
    637                CertCloseStore(self.handle, 0);
    638            }
    639        }
    640    }
    641 }
    642 
    643 impl Deref for CertStore {
    644    type Target = HCERTSTORE;
    645 
    646    fn deref(&self) -> &Self::Target {
    647        &self.handle
    648    }
    649 }
    650 
    651 impl CertStore {
    652    fn new(handle: HCERTSTORE) -> CertStore {
    653        CertStore { handle }
    654    }
    655 }
    656 
    657 // Given a pointer to a CERT_CHAIN_CONTEXT, enumerates each chain in the context and each element
    658 // in each chain to gather every CERT_CONTEXT pointed to by the CERT_CHAIN_CONTEXT.
    659 // https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/ns-wincrypt-cert_chain_context says
    660 // that the 0th element of the 0th chain will be the end-entity certificate. This certificate (if
    661 // present), will be the 0th element of the returned Vec.
    662 fn gather_cert_contexts(cert_chain_context: *const CERT_CHAIN_CONTEXT) -> Vec<*const CERT_CONTEXT> {
    663    let mut cert_contexts = Vec::new();
    664    if cert_chain_context.is_null() {
    665        return cert_contexts;
    666    }
    667    let cert_chain_context = unsafe { &*cert_chain_context };
    668    let cert_chains = unsafe {
    669        std::slice::from_raw_parts(
    670            cert_chain_context.rgpChain,
    671            cert_chain_context.cChain as usize,
    672        )
    673    };
    674    for cert_chain in cert_chains {
    675        // First dereference the borrow.
    676        let cert_chain = *cert_chain;
    677        if cert_chain.is_null() {
    678            continue;
    679        }
    680        // Then dereference the pointer.
    681        let cert_chain = unsafe { &*cert_chain };
    682        let chain_elements = unsafe {
    683            std::slice::from_raw_parts(cert_chain.rgpElement, cert_chain.cElement as usize)
    684        };
    685        for chain_element in chain_elements {
    686            let chain_element = *chain_element; // dereference borrow
    687            if chain_element.is_null() {
    688                continue;
    689            }
    690            let chain_element = unsafe { &*chain_element }; // dereference pointer
    691            cert_contexts.push(chain_element.pCertContext);
    692        }
    693    }
    694    cert_contexts
    695 }
    696 
    697 pub struct Backend {
    698    /// A background thread that all OS API calls will be done on. This is to prevent issues with
    699    /// modules or implementations using thread-local state.
    700    thread: RefPtr<nsIEventTarget>,
    701    /// The last time a call to `find_objects` finished, to avoid searching for objects more than
    702    /// once every 3 seconds.
    703    last_scan_finished: Option<Instant>,
    704 }
    705 
    706 impl Backend {
    707    pub fn new() -> Result<Backend, Error> {
    708        let thread = moz_task::create_thread("osclientcerts").map_err(|nsresult| {
    709            error_here!(ErrorType::LibraryFailure, nsresult.error_name().to_string())
    710        })?;
    711        Ok(Backend {
    712            thread: thread
    713                .query_interface::<nsIEventTarget>()
    714                .ok_or(error_here!(ErrorType::LibraryFailure))?,
    715            last_scan_finished: None,
    716        })
    717    }
    718 }
    719 
    720 const SLOT_DESCRIPTION_BYTES: &[u8; 64] =
    721    b"OS Client Cert Slot                                             ";
    722 const TOKEN_LABEL_BYTES: &[u8; 32] = b"OS Client Cert Token            ";
    723 const TOKEN_MODEL_BYTES: &[u8; 16] = b"osclientcerts   ";
    724 const TOKEN_SERIAL_NUMBER_BYTES: &[u8; 16] = b"0000000000000000";
    725 
    726 impl ClientCertsBackend for Backend {
    727    type Key = Key;
    728 
    729    fn find_objects(&mut self) -> Result<(Vec<CryptokiCert>, Vec<Key>), Error> {
    730        match self.last_scan_finished {
    731            Some(last_scan_finished) => {
    732                if Instant::now().duration_since(last_scan_finished) < Duration::new(3, 0) {
    733                    return Ok((Vec::new(), Vec::new()));
    734                }
    735            }
    736            None => {}
    737        }
    738 
    739        let thread = self.thread.clone();
    740        let task = moz_task::spawn_onto("find_objects", &self.thread, async move {
    741            find_objects(&thread)
    742        });
    743        let result = futures_executor::block_on(task);
    744        self.last_scan_finished = Some(Instant::now());
    745        result
    746    }
    747 
    748    fn get_slot_info(&self) -> CK_SLOT_INFO {
    749        CK_SLOT_INFO {
    750            slotDescription: *SLOT_DESCRIPTION_BYTES,
    751            manufacturerID: *crate::MANUFACTURER_ID_BYTES,
    752            flags: CKF_TOKEN_PRESENT,
    753            ..Default::default()
    754        }
    755    }
    756 
    757    fn get_token_info(&self) -> CK_TOKEN_INFO {
    758        CK_TOKEN_INFO {
    759            label: *TOKEN_LABEL_BYTES,
    760            manufacturerID: *crate::MANUFACTURER_ID_BYTES,
    761            model: *TOKEN_MODEL_BYTES,
    762            serialNumber: *TOKEN_SERIAL_NUMBER_BYTES,
    763            ..Default::default()
    764        }
    765    }
    766 
    767    fn get_mechanism_list(&self) -> Vec<CK_MECHANISM_TYPE> {
    768        vec![CKM_ECDSA, CKM_RSA_PKCS, CKM_RSA_PKCS_PSS]
    769    }
    770 }
    771 
    772 /// Attempts to enumerate certificates with private keys exposed by the OS. Currently only looks in
    773 /// the "My" cert store of the current user. In the future this may look in more locations.
    774 fn find_objects(thread: &nsIEventTarget) -> Result<(Vec<CryptokiCert>, Vec<Key>), Error> {
    775    let mut certs = Vec::new();
    776    let mut keys = Vec::new();
    777    let location_flags =
    778        CERT_SYSTEM_STORE_CURRENT_USER | CERT_STORE_OPEN_EXISTING_FLAG | CERT_STORE_READONLY_FLAG;
    779    let store_name = match CString::new("My") {
    780        Ok(store_name) => store_name,
    781        Err(_) => return Err(error_here!(ErrorType::LibraryFailure)),
    782    };
    783    let store = CertStore::new(unsafe {
    784        CertOpenStore(
    785            CERT_STORE_PROV_SYSTEM_REGISTRY_A,
    786            0,
    787            0,
    788            location_flags,
    789            store_name.as_ptr() as *const winapi::ctypes::c_void,
    790        )
    791    });
    792    if store.is_null() {
    793        return Err(error_here!(ErrorType::ExternalError));
    794    }
    795    let find_params = CERT_CHAIN_FIND_ISSUER_PARA {
    796        cbSize: std::mem::size_of::<CERT_CHAIN_FIND_ISSUER_PARA>() as u32,
    797        pszUsageIdentifier: std::ptr::null(),
    798        dwKeySpec: 0,
    799        dwAcquirePrivateKeyFlags: 0,
    800        cIssuer: 0,
    801        rgIssuer: std::ptr::null_mut(),
    802        pfnFindCallback: None,
    803        pvFindArg: std::ptr::null_mut(),
    804        pdwIssuerChainIndex: std::ptr::null_mut(),
    805        pdwIssuerElementIndex: std::ptr::null_mut(),
    806    };
    807    let mut cert_chain_context: PCCERT_CHAIN_CONTEXT = std::ptr::null_mut();
    808    loop {
    809        // CertFindChainInStore finds all certificates with private keys in the store. It also
    810        // attempts to build a verified certificate chain to a trust anchor for each certificate.
    811        // We gather and hold onto these extra certificates so that gecko can use them when
    812        // filtering potential client certificates according to the acceptable CAs list sent by
    813        // servers when they request client certificates.
    814        cert_chain_context = unsafe {
    815            CertFindChainInStore(
    816                *store,
    817                X509_ASN_ENCODING,
    818                CERT_CHAIN_FIND_BY_ISSUER_CACHE_ONLY_FLAG
    819                    | CERT_CHAIN_FIND_BY_ISSUER_CACHE_ONLY_URL_FLAG,
    820                CERT_CHAIN_FIND_BY_ISSUER,
    821                &find_params as *const CERT_CHAIN_FIND_ISSUER_PARA as *const winapi::ctypes::c_void,
    822                cert_chain_context,
    823            )
    824        };
    825        if cert_chain_context.is_null() {
    826            break;
    827        }
    828        let cert_contexts = gather_cert_contexts(cert_chain_context);
    829        // The 0th CERT_CONTEXT is the end-entity (i.e. the certificate with the private key we're
    830        // after).
    831        match cert_contexts.get(0) {
    832            Some(cert_context) => {
    833                let key = match Key::new(*cert_context, thread) {
    834                    Ok(key) => key,
    835                    Err(_) => continue,
    836                };
    837                let cert = match new_cert(*cert_context) {
    838                    Ok(cert) => cert,
    839                    Err(_) => continue,
    840                };
    841                certs.push(cert);
    842                keys.push(key);
    843            }
    844            None => {}
    845        };
    846        for cert_context in cert_contexts.iter().skip(1) {
    847            if let Ok(cert) = new_cert(*cert_context) {
    848                certs.push(cert);
    849            }
    850        }
    851    }
    852    Ok((certs, keys))
    853 }