cryptoki.rs (14110B)
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 byteorder::{NativeEndian, WriteBytesExt}; 7 use digest::{Digest, DynDigest}; 8 use pkcs11_bindings::*; 9 use rand::rngs::OsRng; 10 use rand::RngCore; 11 use rsclientcerts_util::error::{Error, ErrorType}; 12 use rsclientcerts_util::{error_here, read_encoded_certificate_identifiers}; 13 use std::convert::TryInto; 14 use std::iter::zip; 15 16 use crate::manager::CryptokiObject; 17 18 // The following ENCODED_OID_BYTES_* consist of the encoded bytes of an ASN.1 19 // OBJECT IDENTIFIER specifying the indicated OID (in other words, the full 20 // tag, length, and value). 21 pub const ENCODED_OID_BYTES_SECP256R1: &[u8] = 22 &[0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07]; 23 pub const ENCODED_OID_BYTES_SECP384R1: &[u8] = &[0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x22]; 24 pub const ENCODED_OID_BYTES_SECP521R1: &[u8] = &[0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x23]; 25 26 // This is a helper function to take a value and lay it out in memory how 27 // PKCS#11 is expecting it. 28 pub fn serialize_uint<T: TryInto<u64>>(value: T) -> Result<Vec<u8>, Error> { 29 let value_size = std::mem::size_of::<T>(); 30 let mut value_buf = Vec::with_capacity(value_size); 31 let value_as_u64 = value 32 .try_into() 33 .map_err(|_| error_here!(ErrorType::ValueTooLarge))?; 34 value_buf 35 .write_uint::<NativeEndian>(value_as_u64, value_size) 36 .map_err(|_| error_here!(ErrorType::LibraryFailure))?; 37 Ok(value_buf) 38 } 39 40 fn make_hasher(params: &CK_RSA_PKCS_PSS_PARAMS) -> Result<Box<dyn DynDigest>, Error> { 41 match params.hashAlg { 42 CKM_SHA256 => Ok(Box::new(sha2::Sha256::new())), 43 CKM_SHA384 => Ok(Box::new(sha2::Sha384::new())), 44 CKM_SHA512 => Ok(Box::new(sha2::Sha512::new())), 45 _ => Err(error_here!(ErrorType::LibraryFailure)), 46 } 47 } 48 49 // Implements MGF1 as per RFC 8017 appendix B.2.1. 50 fn mgf( 51 mgf_seed: &[u8], 52 mask_len: usize, 53 h_len: usize, 54 params: &CK_RSA_PKCS_PSS_PARAMS, 55 ) -> Result<Vec<u8>, Error> { 56 // 1. If maskLen > 2^32 hLen, output "mask too long" and stop. 57 // (in practice, `mask_len` is going to be much smaller than this, so use a 58 // smaller, fixed limit to avoid problems on systems where usize is 32 59 // bits) 60 if mask_len > 1 << 30 { 61 return Err(error_here!(ErrorType::LibraryFailure)); 62 } 63 // 2. Let T be the empty octet string. 64 let mut t = Vec::with_capacity(mask_len); 65 // 3. For counter from 0 to \ceil (maskLen / hLen) - 1, do the 66 // following: 67 for counter in 0..mask_len.div_ceil(h_len) { 68 // A. Convert counter to an octet string C of length 4 octets: 69 // C = I2OSP (counter, 4) 70 // (counter fits in u32 due to the length check earlier) 71 let c = u32::to_be_bytes(counter.try_into().unwrap()); 72 // B. Concatenate the hash of the seed mgfSeed and C to the octet 73 // string T: T = T || Hash(mgfSeed || C) 74 let mut hasher = make_hasher(params)?; 75 hasher.update(mgf_seed); 76 hasher.update(&c); 77 t.extend_from_slice(&mut hasher.finalize()); 78 } 79 // 4. Output the leading maskLen octets of T as the octet string mask. 80 t.truncate(mask_len); 81 Ok(t) 82 } 83 84 pub fn modulus_bit_length(modulus: &[u8]) -> usize { 85 let mut bit_length = modulus.len() * 8; 86 for byte in modulus { 87 if *byte != 0 { 88 // `byte` is a u8, so `leading_zeros()` will be at most 7. 89 let leading_zeros: usize = byte.leading_zeros().try_into().unwrap(); 90 bit_length -= leading_zeros; 91 return bit_length; 92 } 93 bit_length -= 8; 94 } 95 bit_length 96 } 97 98 // Implements EMSA-PSS-ENCODE as per RFC 8017 section 9.1.1. 99 // This is necessary because while Android does support RSA-PSS, it expects to 100 // be given the entire message to be signed, not just the hash of the message, 101 // which is what NSS gives us. 102 // Additionally, this is useful for tokens that do not support RSA-PSS. 103 pub fn emsa_pss_encode( 104 m_hash: &[u8], 105 em_bits: usize, 106 params: &CK_RSA_PKCS_PSS_PARAMS, 107 ) -> Result<Vec<u8>, Error> { 108 let em_len = em_bits.div_ceil(8); 109 let s_len: usize = params 110 .sLen 111 .try_into() 112 .map_err(|_| error_here!(ErrorType::LibraryFailure))?; 113 114 // 1. If the length of M is greater than the input limitation for 115 // the hash function (2^61 - 1 octets for SHA-1), output 116 // "message too long" and stop. 117 // 2. Let mHash = Hash(M), an octet string of length hLen. 118 119 // 1 and 2 can be skipped because the message is already hashed as m_hash. 120 121 // 3. If emLen < hLen + sLen + 2, output "encoding error" and stop. 122 if em_len < m_hash.len() + s_len + 2 { 123 return Err(error_here!(ErrorType::LibraryFailure)); 124 } 125 126 // 4. Generate a random octet string salt of length sLen; if sLen = 127 // 0, then salt is the empty string. 128 let salt = { 129 let mut salt = vec![0u8; s_len]; 130 OsRng.fill_bytes(&mut salt); 131 salt 132 }; 133 134 // 5. Let M' = (0x)00 00 00 00 00 00 00 00 || mHash || salt; 135 // M' is an octet string of length 8 + hLen + sLen with eight 136 // initial zero octets. 137 // 6. Let H = Hash(M'), an octet string of length hLen. 138 let mut hasher = make_hasher(params)?; 139 let h_len = hasher.output_size(); 140 hasher.update(&[0, 0, 0, 0, 0, 0, 0, 0]); 141 hasher.update(m_hash); 142 hasher.update(&salt); 143 let h = hasher.finalize().to_vec(); 144 145 // 7. Generate an octet string PS consisting of emLen - sLen - hLen 146 // - 2 zero octets. The length of PS may be 0. 147 // 8. Let DB = PS || 0x01 || salt; DB is an octet string of length 148 // emLen - hLen - 1. 149 // (7 and 8 are unnecessary as separate steps - see step 10) 150 151 // 9. Let dbMask = MGF(H, emLen - hLen - 1). 152 let mut db_mask = mgf(&h, em_len - h_len - 1, h_len, params)?; 153 154 // 10. Let maskedDB = DB \xor dbMask. 155 // (in practice, this means xoring `0x01 || salt` with the last `s_len + 1` 156 // bytes of `db_mask`) 157 let salt_index = db_mask.len() - s_len; 158 db_mask[salt_index - 1] ^= 1; 159 for (db_mask_byte, salt_byte) in zip(&mut db_mask[salt_index..], &salt) { 160 *db_mask_byte ^= salt_byte; 161 } 162 let mut masked_db = db_mask; 163 164 // 11. Set the leftmost 8emLen - emBits bits of the leftmost octet 165 // in maskedDB to zero. 166 // (bit_diff can only be 0 through 7, so it fits in u32) 167 let bit_diff: u32 = ((8 * em_len) - em_bits).try_into().unwrap(); 168 // (again, bit_diff can only b 0 through 7, so the shift is sound) 169 masked_db[0] &= 0xffu8.checked_shr(bit_diff).unwrap(); 170 171 // 12. Let EM = maskedDB || H || 0xbc. 172 let mut em = masked_db; 173 em.extend_from_slice(&h); 174 em.push(0xbc); 175 176 Ok(em) 177 } 178 179 /// A `CryptokiCert` holds all relevant information for a `CryptokiObject` with class 180 /// `CKO_CERTIFICATE`. 181 #[derive(Clone)] 182 pub struct CryptokiCert { 183 /// PKCS #11 object class. Will be `CKO_CERTIFICATE`. 184 class: Vec<u8>, 185 /// Whether or not this is on a token. Will be `CK_TRUE`. 186 token: Vec<u8>, 187 /// An identifier unique to this certificate. This must be the same as the ID for the private 188 /// key, so for simplicity, this will be the sha256 hash of the bytes of the certificate. 189 id: Vec<u8>, 190 /// The bytes of a human-readable label for this certificate. 191 label: Vec<u8>, 192 /// The DER bytes of the certificate. 193 value: Vec<u8>, 194 /// The DER bytes of the issuer distinguished name of the certificate. 195 issuer: Vec<u8>, 196 /// The DER bytes of the serial number of the certificate. 197 serial_number: Vec<u8>, 198 /// The DER bytes of the subject distinguished name of the certificate. 199 subject: Vec<u8>, 200 } 201 202 impl CryptokiCert { 203 pub fn new(der: Vec<u8>, label: Vec<u8>) -> Result<CryptokiCert, Error> { 204 let id = sha2::Sha256::digest(&der).to_vec(); 205 let (serial_number, issuer, subject) = read_encoded_certificate_identifiers(&der)?; 206 Ok(CryptokiCert { 207 class: serialize_uint(CKO_CERTIFICATE)?, 208 token: serialize_uint(CK_TRUE)?, 209 id, 210 label, 211 value: der, 212 issuer, 213 serial_number, 214 subject, 215 }) 216 } 217 } 218 219 impl CryptokiObject for CryptokiCert { 220 fn matches(&self, attrs: &[(CK_ATTRIBUTE_TYPE, Vec<u8>)]) -> bool { 221 for (attr_type, attr_value) in attrs { 222 let comparison = match *attr_type { 223 CKA_CLASS => &self.class, 224 CKA_TOKEN => &self.token, 225 CKA_LABEL => &self.label, 226 CKA_ID => &self.id, 227 CKA_VALUE => &self.value, 228 CKA_ISSUER => &self.issuer, 229 CKA_SERIAL_NUMBER => &self.serial_number, 230 CKA_SUBJECT => &self.subject, 231 _ => return false, 232 }; 233 if attr_value.as_slice() != comparison { 234 return false; 235 } 236 } 237 true 238 } 239 240 fn get_attribute(&self, attribute: CK_ATTRIBUTE_TYPE) -> Option<&[u8]> { 241 let result = match attribute { 242 CKA_CLASS => &self.class, 243 CKA_TOKEN => &self.token, 244 CKA_LABEL => &self.label, 245 CKA_ID => &self.id, 246 CKA_VALUE => &self.value, 247 CKA_ISSUER => &self.issuer, 248 CKA_SERIAL_NUMBER => &self.serial_number, 249 CKA_SUBJECT => &self.subject, 250 _ => return None, 251 }; 252 Some(result) 253 } 254 } 255 256 #[allow(clippy::upper_case_acronyms)] 257 #[derive(Clone, Copy, Debug)] 258 pub enum KeyType { 259 EC(usize), 260 RSA, 261 } 262 263 /// A `CryptokiKey` holds all relevant information for a `CryptokiObject` with class 264 /// `CKO_PRIVATE_KEY`. 265 #[derive(Clone)] 266 pub struct CryptokiKey { 267 /// PKCS #11 object class. Will be `CKO_PRIVATE_KEY`. 268 class: Vec<u8>, 269 /// Whether or not this is on a token. Will be `CK_TRUE`. 270 token: Vec<u8>, 271 /// An identifier unique to this key. This must be the same as the ID for a corresponding 272 /// certificate, so for simplicity, this will be the sha256 hash of the bytes of the 273 /// certificate. 274 id: Vec<u8>, 275 /// Whether or not this key is "private" (can it be exported?). Will be CK_TRUE (it can't be 276 /// exported). 277 private: Vec<u8>, 278 /// PKCS #11 key type. Will be `CKK_EC` for EC, and `CKK_RSA` for RSA. 279 key_type_attribute: Vec<u8>, 280 /// If this is an RSA key, this is the value of the modulus as an unsigned integer. 281 modulus: Option<Vec<u8>>, 282 /// If this is an EC key, this is the DER bytes of the OID identifying the curve the key is on. 283 ec_params: Option<Vec<u8>>, 284 /// An enum identifying this key's type. 285 key_type: KeyType, 286 } 287 288 impl CryptokiKey { 289 pub fn new( 290 modulus: Option<Vec<u8>>, 291 ec_params: Option<Vec<u8>>, 292 cert: &[u8], 293 ) -> Result<CryptokiKey, Error> { 294 let (key_type, key_type_attribute) = if modulus.is_some() { 295 (KeyType::RSA, CKK_RSA) 296 } else if let Some(ec_params) = ec_params.as_ref() { 297 // Only secp256r1, secp384r1, and secp521r1 are supported. 298 let coordinate_width = match ec_params.as_slice() { 299 ENCODED_OID_BYTES_SECP256R1 => 32, 300 ENCODED_OID_BYTES_SECP384R1 => 48, 301 ENCODED_OID_BYTES_SECP521R1 => 66, 302 _ => return Err(error_here!(ErrorType::UnsupportedInput)), 303 }; 304 (KeyType::EC(coordinate_width), CKK_EC) 305 } else { 306 return Err(error_here!(ErrorType::LibraryFailure)); 307 }; 308 let id = sha2::Sha256::digest(cert).to_vec(); 309 Ok(CryptokiKey { 310 class: serialize_uint(CKO_PRIVATE_KEY)?, 311 token: serialize_uint(CK_TRUE)?, 312 id, 313 private: serialize_uint(CK_TRUE)?, 314 key_type_attribute: serialize_uint(key_type_attribute)?, 315 modulus, 316 ec_params, 317 key_type, 318 }) 319 } 320 321 pub fn modulus(&self) -> &Option<Vec<u8>> { 322 &self.modulus 323 } 324 325 pub fn ec_params(&self) -> &Option<Vec<u8>> { 326 &self.ec_params 327 } 328 329 pub fn key_type(&self) -> KeyType { 330 self.key_type 331 } 332 } 333 334 impl CryptokiObject for CryptokiKey { 335 fn matches(&self, attrs: &[(CK_ATTRIBUTE_TYPE, Vec<u8>)]) -> bool { 336 for (attr_type, attr_value) in attrs { 337 let comparison = match *attr_type { 338 CKA_CLASS => &self.class, 339 CKA_TOKEN => &self.token, 340 CKA_ID => &self.id, 341 CKA_PRIVATE => &self.private, 342 CKA_KEY_TYPE => &self.key_type_attribute, 343 CKA_MODULUS => { 344 if let Some(modulus) = &self.modulus { 345 modulus 346 } else { 347 return false; 348 } 349 } 350 CKA_EC_PARAMS => { 351 if let Some(ec_params) = &self.ec_params { 352 ec_params 353 } else { 354 return false; 355 } 356 } 357 _ => return false, 358 }; 359 if attr_value.as_slice() != comparison { 360 return false; 361 } 362 } 363 true 364 } 365 366 fn get_attribute(&self, attribute: CK_ATTRIBUTE_TYPE) -> Option<&[u8]> { 367 match attribute { 368 CKA_CLASS => Some(&self.class), 369 CKA_TOKEN => Some(&self.token), 370 CKA_ID => Some(&self.id), 371 CKA_PRIVATE => Some(&self.private), 372 CKA_KEY_TYPE => Some(&self.key_type_attribute), 373 CKA_MODULUS => match &self.modulus { 374 Some(modulus) => Some(modulus.as_slice()), 375 None => None, 376 }, 377 CKA_EC_PARAMS => match &self.ec_params { 378 Some(ec_params) => Some(ec_params.as_slice()), 379 None => None, 380 }, 381 _ => None, 382 } 383 } 384 }