tor-browser

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

lib.rs (7882B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 extern crate hashlink;
      6 
      7 use hashlink::LruCache;
      8 
      9 use std::sync::Mutex;
     10 
     11 const SHA512_LENGTH_IN_BYTES: usize = 64;
     12 
     13 /// SignatureCache is a simple least-recently-used cache. The input is a sha512
     14 /// hash representing the parameters defining a signature. A hit in the cache
     15 /// indicates that the signature previously verified successfully.
     16 pub struct SignatureCache {
     17    cache: Mutex<LruCache<[u8; SHA512_LENGTH_IN_BYTES], ()>>,
     18 }
     19 
     20 impl SignatureCache {
     21    /// Make a new SignatureCache with the specified number of slots.
     22    fn new(capacity: u16) -> SignatureCache {
     23        SignatureCache {
     24            cache: Mutex::new(LruCache::new(capacity as usize)),
     25        }
     26    }
     27 
     28    /// Look up a signature hash in the cache. Returns true if the signature
     29    /// previously verified correctly, and false otherwise.
     30    fn get(&mut self, sha512_hash: &[u8; SHA512_LENGTH_IN_BYTES]) -> bool {
     31        let Ok(mut cache) = self.cache.lock() else {
     32            return false;
     33        };
     34        cache.get(sha512_hash).is_some()
     35    }
     36 
     37    /// Insert a signature hash into the cache.
     38    fn insert(&self, sha512_hash: [u8; SHA512_LENGTH_IN_BYTES]) {
     39        let Ok(mut cache) = self.cache.lock() else {
     40            return;
     41        };
     42        let _ = cache.insert(sha512_hash, ());
     43    }
     44 }
     45 
     46 /// Create a new SignatureCache.
     47 #[no_mangle]
     48 pub extern "C" fn signature_cache_new(capacity: u16) -> *mut SignatureCache {
     49    // This pattern returns a SignatureCache that will be owned by the caller.
     50    // That is, the SignatureCache will live until `signature_cache_free` is
     51    // called on it.
     52    Box::into_raw(Box::new(SignatureCache::new(capacity)))
     53 }
     54 
     55 /// Free a SignatureCache.
     56 ///
     57 /// # Safety
     58 ///
     59 /// This function must only be called with a null pointer or a pointer returned from
     60 /// `signature_cache_new`.
     61 #[no_mangle]
     62 pub unsafe extern "C" fn signature_cache_free(signature_cache: *mut SignatureCache) {
     63    if signature_cache.is_null() {
     64        return;
     65    }
     66    // This takes a SignatureCache that was created by calling
     67    // `signature_cache_new` and ensures its resources are destroyed.
     68    let _ = Box::from_raw(signature_cache);
     69 }
     70 
     71 /// Look up a signature parameter hash in a SignatureCache.
     72 ///
     73 /// # Safety
     74 ///
     75 /// This function must only be called with a pointer returned from
     76 /// `signature_cache_new` and a pointer to `SHA512_LENGTH_IN_BYTES` bytes.
     77 #[no_mangle]
     78 pub unsafe extern "C" fn signature_cache_get(
     79    signature_cache: *mut SignatureCache,
     80    sha512_hash: *const u8,
     81 ) -> bool {
     82    if signature_cache.is_null() || sha512_hash.is_null() {
     83        return false;
     84    }
     85    let sha512_hash = std::slice::from_raw_parts(sha512_hash, SHA512_LENGTH_IN_BYTES);
     86    let Ok(sha512_hash) = sha512_hash.try_into() else {
     87        return false;
     88    };
     89    let signature_cache = &mut *signature_cache;
     90    signature_cache.get(&sha512_hash)
     91 }
     92 
     93 /// Add a signature parameter hash to a SignatureCache.
     94 ///
     95 /// # Safety
     96 ///
     97 /// This function must only be called with a pointer returned from
     98 /// `signature_cache_new` and a pointer to `SHA512_LENGTH_IN_BYTES` bytes.
     99 #[no_mangle]
    100 pub unsafe extern "C" fn signature_cache_insert(
    101    signature_cache: *mut SignatureCache,
    102    sha512_hash: *const u8,
    103 ) {
    104    if signature_cache.is_null() || sha512_hash.is_null() {
    105        return;
    106    }
    107    let sha512_hash = std::slice::from_raw_parts(sha512_hash, SHA512_LENGTH_IN_BYTES);
    108    let Ok(sha512_hash) = sha512_hash.try_into() else {
    109        return;
    110    };
    111    let signature_cache = &mut *signature_cache;
    112    signature_cache.insert(sha512_hash);
    113 }
    114 
    115 /// TrustCache is a simple least-recently-used cache. The input is a sha512
    116 /// hash representing the parameters involved in a certificate trust lookup
    117 /// (trust category (i.e. TLS or email signing), end-entity or CA, policy,
    118 /// etc.), which maps to a mozilla::pkix::TrustLevel value represented as a u8.
    119 pub struct TrustCache {
    120    cache: Mutex<LruCache<[u8; SHA512_LENGTH_IN_BYTES], u8>>,
    121 }
    122 
    123 impl TrustCache {
    124    /// Make a new TrustCache with the specified number of slots.
    125    fn new(capacity: u16) -> TrustCache {
    126        TrustCache {
    127            cache: Mutex::new(LruCache::new(capacity as usize)),
    128        }
    129    }
    130 
    131    /// Look up a trust hash in the cache. Returns `None` if there is no cached
    132    /// trust information. Otherwise, returns `Some(trust)`, where `trust` is
    133    /// the previously-cached TrustLevel.
    134    fn get(&mut self, sha512_hash: &[u8; SHA512_LENGTH_IN_BYTES]) -> Option<u8> {
    135        let Ok(mut cache) = self.cache.lock() else {
    136            return None;
    137        };
    138        cache.get(sha512_hash).cloned()
    139    }
    140 
    141    /// Insert a trust hash into the cache.
    142    fn insert(&self, sha512_hash: [u8; SHA512_LENGTH_IN_BYTES], trust: u8) {
    143        let Ok(mut cache) = self.cache.lock() else {
    144            return;
    145        };
    146        let _ = cache.insert(sha512_hash, trust);
    147    }
    148 
    149    /// Clear the cache, removing all entries.
    150    fn clear(&mut self) {
    151        let Ok(mut cache) = self.cache.lock() else {
    152            return;
    153        };
    154        cache.clear();
    155    }
    156 }
    157 
    158 /// Create a new TrustCache.
    159 #[no_mangle]
    160 pub extern "C" fn trust_cache_new(capacity: u16) -> *mut TrustCache {
    161    // This pattern returns a TrustCache that will be owned by the caller.
    162    // That is, the TrustCache will live until `trust_cache_free` is
    163    // called on it.
    164    Box::into_raw(Box::new(TrustCache::new(capacity)))
    165 }
    166 
    167 /// Free a TrustCache.
    168 ///
    169 /// # Safety
    170 ///
    171 /// This function must only be called with a null pointer or a pointer returned from
    172 /// `trust_cache_new`.
    173 #[no_mangle]
    174 pub unsafe extern "C" fn trust_cache_free(trust_cache: *mut TrustCache) {
    175    if trust_cache.is_null() {
    176        return;
    177    }
    178    // This takes a TrustCache that was created by calling
    179    // `trust_cache_new` and ensures its resources are destroyed.
    180    let _ = Box::from_raw(trust_cache);
    181 }
    182 
    183 /// Look up a trust hash in a TrustCache.
    184 ///
    185 /// # Safety
    186 ///
    187 /// This function must only be called with a pointer returned from
    188 /// `trust_cache_new` and a pointer to `SHA512_LENGTH_IN_BYTES` bytes.
    189 #[no_mangle]
    190 pub unsafe extern "C" fn trust_cache_get(
    191    trust_cache: *mut TrustCache,
    192    sha512_hash: *const u8,
    193    trust: *mut u8,
    194 ) -> bool {
    195    if trust_cache.is_null() || sha512_hash.is_null() || trust.is_null() {
    196        return false;
    197    }
    198    let sha512_hash = std::slice::from_raw_parts(sha512_hash, SHA512_LENGTH_IN_BYTES);
    199    let Ok(sha512_hash) = sha512_hash.try_into() else {
    200        return false;
    201    };
    202    let trust_cache = &mut *trust_cache;
    203    let Some(cached_trust) = trust_cache.get(&sha512_hash) else {
    204        return false;
    205    };
    206    *trust = cached_trust;
    207    true
    208 }
    209 
    210 /// Add a trust hash to a TrustCache.
    211 ///
    212 /// # Safety
    213 ///
    214 /// This function must only be called with a pointer returned from
    215 /// `trust_cache_new` and a pointer to `SHA512_LENGTH_IN_BYTES` bytes.
    216 #[no_mangle]
    217 pub unsafe extern "C" fn trust_cache_insert(
    218    trust_cache: *mut TrustCache,
    219    sha512_hash: *const u8,
    220    trust: u8,
    221 ) {
    222    if trust_cache.is_null() || sha512_hash.is_null() {
    223        return;
    224    }
    225    let sha512_hash = std::slice::from_raw_parts(sha512_hash, SHA512_LENGTH_IN_BYTES);
    226    let Ok(sha512_hash) = sha512_hash.try_into() else {
    227        return;
    228    };
    229    let trust_cache = &mut *trust_cache;
    230    trust_cache.insert(sha512_hash, trust);
    231 }
    232 
    233 /// Clear a trust cache, removing all entries.
    234 ///
    235 /// # Safety
    236 ///
    237 /// This function must only be called with a pointer returned from
    238 /// `trust_cache_new`.
    239 #[no_mangle]
    240 pub unsafe extern "C" fn trust_cache_clear(trust_cache: *mut TrustCache) {
    241    if trust_cache.is_null() {
    242        return;
    243    }
    244    let trust_cache = &mut *trust_cache;
    245    trust_cache.clear();
    246 }