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 }