tor-browser

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

backend_android.rs (8677B)


      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 use pkcs11_bindings::*;
      7 use rsclientcerts::cryptoki::*;
      8 use rsclientcerts::manager::{ClientCertsBackend, CryptokiObject, Sign};
      9 use rsclientcerts_util::error::{Error, ErrorType};
     10 use rsclientcerts_util::*;
     11 use std::ffi::{c_char, c_void, CString};
     12 
     13 type FindObjectsCallback = Option<
     14    unsafe extern "C" fn(
     15        typ: u8,
     16        data_len: usize,
     17        data: *const u8,
     18        extra_len: usize,
     19        extra: *const u8,
     20        ctx: *mut c_void,
     21    ),
     22 >;
     23 
     24 // Wrapper of C AndroidDoFindObject function implemented in nsNSSIOLayer.cpp
     25 fn AndroidDoFindObjectsWrapper(callback: FindObjectsCallback, ctx: &mut FindObjectsContext) {
     26    // `AndroidDoFindObjects` communicates with the
     27    // `ClientAuthCertificateManager` to find all available client
     28    // authentication certificates and corresponding keys and issuers.
     29    extern "C" {
     30        fn AndroidDoFindObjects(callback: FindObjectsCallback, ctx: *mut c_void);
     31    }
     32 
     33    unsafe {
     34        AndroidDoFindObjects(callback, ctx as *mut _ as *mut c_void);
     35    }
     36 }
     37 
     38 type SignCallback =
     39    Option<unsafe extern "C" fn(data_len: usize, data: *const u8, ctx: *mut c_void)>;
     40 
     41 // Wrapper of C AndroidDoSign function implemented in nsNSSIOLayer.cpp
     42 fn AndroidDoSignWrapper(
     43    cert_len: usize,
     44    cert: *const u8,
     45    data_len: usize,
     46    data: *const u8,
     47    algorithm: *const c_char,
     48    callback: SignCallback,
     49    ctx: &mut Vec<u8>,
     50 ) {
     51    // `AndroidDoSign` calls into `ClientAuthCertificateManager` to do the
     52    // actual work of creating signatures.
     53    extern "C" {
     54        fn AndroidDoSign(
     55            cert_len: usize,
     56            cert: *const u8,
     57            data_len: usize,
     58            data: *const u8,
     59            algorithm: *const c_char,
     60            callback: SignCallback,
     61            ctx: *mut c_void,
     62        );
     63    }
     64 
     65    unsafe {
     66        AndroidDoSign(
     67            cert_len,
     68            cert,
     69            data_len,
     70            data,
     71            algorithm,
     72            callback,
     73            ctx as *mut _ as *mut c_void,
     74        );
     75    }
     76 }
     77 
     78 fn new_cert(der: Vec<u8>) -> Result<CryptokiCert, Error> {
     79    CryptokiCert::new(der, b"android certificate".to_vec())
     80 }
     81 
     82 pub struct Key {
     83    cryptoki_key: CryptokiKey,
     84    cert: Vec<u8>,
     85 }
     86 
     87 impl Key {
     88    fn new(
     89        modulus: Option<Vec<u8>>,
     90        ec_params: Option<Vec<u8>>,
     91        cert: Vec<u8>,
     92    ) -> Result<Key, Error> {
     93        let (modulus, ec_params) = if modulus.is_some() {
     94            (modulus, None)
     95        } else if let Some(spki) = ec_params.as_ref() {
     96            // If this is an EC key, the frontend will have provided an SPKI.
     97            // Extract the parameters of the algorithm to get the curve.
     98            let ec_params = read_spki_algorithm_parameters(&spki)?;
     99            (None, Some(ec_params))
    100        } else {
    101            return Err(error_here!(ErrorType::LibraryFailure));
    102        };
    103        Ok(Key {
    104            cryptoki_key: CryptokiKey::new(modulus, ec_params, &cert)?,
    105            cert,
    106        })
    107    }
    108 }
    109 
    110 impl CryptokiObject for Key {
    111    fn matches(&self, attrs: &[(CK_ATTRIBUTE_TYPE, Vec<u8>)]) -> bool {
    112        self.cryptoki_key.matches(attrs)
    113    }
    114 
    115    fn get_attribute(&self, attribute: CK_ATTRIBUTE_TYPE) -> Option<&[u8]> {
    116        self.cryptoki_key.get_attribute(attribute)
    117    }
    118 }
    119 
    120 fn new_cstring(val: &str) -> Result<CString, Error> {
    121    CString::new(val).map_err(|_| error_here!(ErrorType::LibraryFailure))
    122 }
    123 
    124 impl Sign for Key {
    125    fn get_signature_length(
    126        &mut self,
    127        data: &[u8],
    128        params: &Option<CK_RSA_PKCS_PSS_PARAMS>,
    129    ) -> Result<usize, Error> {
    130        // Unfortunately we don't have a way of getting the length of a signature without creating
    131        // one.
    132        let dummy_signature_bytes = self.sign(data, params)?;
    133        Ok(dummy_signature_bytes.len())
    134    }
    135 
    136    fn sign(
    137        &mut self,
    138        data: &[u8],
    139        params: &Option<CK_RSA_PKCS_PSS_PARAMS>,
    140    ) -> Result<Vec<u8>, Error> {
    141        let (data, algorithm) = match params {
    142            Some(params) => {
    143                // `params` should only be `Some` if this is an RSA key.
    144                let Some(modulus) = self.cryptoki_key.modulus() else {
    145                    return Err(error_here!(ErrorType::LibraryFailure));
    146                };
    147                (
    148                    emsa_pss_encode(data, modulus_bit_length(modulus) - 1, &params)?,
    149                    new_cstring("raw")?,
    150                )
    151            }
    152            None if self.cryptoki_key.modulus().is_some() => {
    153                (data.to_vec(), new_cstring("NoneWithRSA")?)
    154            }
    155            None if self.cryptoki_key.ec_params().is_some() => {
    156                (data.to_vec(), new_cstring("NoneWithECDSA")?)
    157            }
    158            _ => return Err(error_here!(ErrorType::LibraryFailure)),
    159        };
    160        let mut signature = Vec::new();
    161        AndroidDoSignWrapper(
    162            self.cert.len(),
    163            self.cert.as_ptr(),
    164            data.len(),
    165            data.as_ptr(),
    166            algorithm.as_c_str().as_ptr(),
    167            Some(sign_callback),
    168            &mut signature,
    169        );
    170        if let KeyType::EC(coordinate_width) = self.cryptoki_key.key_type() {
    171            signature = der_ec_sig_to_raw(&signature, coordinate_width)?;
    172        }
    173        if signature.len() > 0 {
    174            Ok(signature)
    175        } else {
    176            Err(error_here!(ErrorType::LibraryFailure))
    177        }
    178    }
    179 }
    180 
    181 unsafe extern "C" fn sign_callback(data_len: usize, data: *const u8, ctx: *mut c_void) {
    182    let signature: &mut Vec<u8> = std::mem::transmute(ctx);
    183    signature.clear();
    184    if data_len != 0 {
    185        signature.extend_from_slice(std::slice::from_raw_parts(data, data_len));
    186    }
    187 }
    188 
    189 unsafe extern "C" fn find_objects_callback(
    190    typ: u8,
    191    data_len: usize,
    192    data: *const u8,
    193    extra_len: usize,
    194    extra: *const u8,
    195    ctx: *mut c_void,
    196 ) {
    197    let data = if data_len == 0 {
    198        &[]
    199    } else {
    200        std::slice::from_raw_parts(data, data_len)
    201    }
    202    .to_vec();
    203    let extra = if extra_len == 0 {
    204        &[]
    205    } else {
    206        std::slice::from_raw_parts(extra, extra_len)
    207    }
    208    .to_vec();
    209    let find_objects_context: &mut FindObjectsContext = std::mem::transmute(ctx);
    210    match typ {
    211        1 => match new_cert(data) {
    212            Ok(cert) => find_objects_context.certs.push(cert),
    213            Err(_) => {}
    214        },
    215        2 => match Key::new(Some(data), None, extra) {
    216            Ok(key) => find_objects_context.keys.push(key),
    217            Err(_) => {}
    218        },
    219        3 => match Key::new(None, Some(data), extra) {
    220            Ok(key) => find_objects_context.keys.push(key),
    221            Err(_) => {}
    222        },
    223        _ => {}
    224    }
    225 }
    226 
    227 struct FindObjectsContext {
    228    certs: Vec<CryptokiCert>,
    229    keys: Vec<Key>,
    230 }
    231 
    232 impl FindObjectsContext {
    233    fn new() -> FindObjectsContext {
    234        FindObjectsContext {
    235            certs: Vec::new(),
    236            keys: Vec::new(),
    237        }
    238    }
    239 }
    240 
    241 pub struct Backend {}
    242 
    243 impl Backend {
    244    pub fn new() -> Result<Backend, Error> {
    245        Ok(Backend {})
    246    }
    247 }
    248 
    249 const SLOT_DESCRIPTION_BYTES: &[u8; 64] =
    250    b"OS Client Cert Slot                                             ";
    251 const TOKEN_LABEL_BYTES: &[u8; 32] = b"OS Client Cert Token            ";
    252 const TOKEN_MODEL_BYTES: &[u8; 16] = b"osclientcerts   ";
    253 const TOKEN_SERIAL_NUMBER_BYTES: &[u8; 16] = b"0000000000000000";
    254 
    255 impl ClientCertsBackend for Backend {
    256    type Key = Key;
    257 
    258    fn find_objects(&mut self) -> Result<(Vec<CryptokiCert>, Vec<Key>), Error> {
    259        let mut find_objects_context = FindObjectsContext::new();
    260        AndroidDoFindObjectsWrapper(Some(find_objects_callback), &mut find_objects_context);
    261        Ok((find_objects_context.certs, find_objects_context.keys))
    262    }
    263 
    264    fn get_slot_info(&self) -> CK_SLOT_INFO {
    265        CK_SLOT_INFO {
    266            slotDescription: *SLOT_DESCRIPTION_BYTES,
    267            manufacturerID: *crate::MANUFACTURER_ID_BYTES,
    268            flags: CKF_TOKEN_PRESENT,
    269            ..Default::default()
    270        }
    271    }
    272 
    273    fn get_token_info(&self) -> CK_TOKEN_INFO {
    274        CK_TOKEN_INFO {
    275            label: *TOKEN_LABEL_BYTES,
    276            manufacturerID: *crate::MANUFACTURER_ID_BYTES,
    277            model: *TOKEN_MODEL_BYTES,
    278            serialNumber: *TOKEN_SERIAL_NUMBER_BYTES,
    279            ..Default::default()
    280        }
    281    }
    282 
    283    fn get_mechanism_list(&self) -> Vec<CK_MECHANISM_TYPE> {
    284        vec![CKM_ECDSA, CKM_RSA_PKCS, CKM_RSA_PKCS_PSS]
    285    }
    286 }