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, ¶ms)?, 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 }