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/. */
6 use pkcs11_bindings::*;
7 use rsclientcerts::error::{Error, ErrorType};
8 use rsclientcerts::manager::{ClientCertsBackend, CryptokiObject, Sign, SlotType};
9 use rsclientcerts::util::*;
10 use sha2::{Digest, Sha256};
13 use crate::FindObjectsFunction;
14 use crate::SignFunction;
23 serial_number: Vec<u8>,
29 fn new(der: &[u8], slot_type: SlotType) -> Result<Cert, Error> {
30 let (serial_number, issuer, subject) = read_encoded_certificate_identifiers(der)?;
31 let id = Sha256::digest(der).to_vec();
33 class: serialize_uint(CKO_CERTIFICATE)?,
34 token: serialize_uint(CK_TRUE)?,
36 label: b"IPC certificate".to_vec(),
45 fn class(&self) -> &[u8] {
49 fn token(&self) -> &[u8] {
53 fn id(&self) -> &[u8] {
57 fn label(&self) -> &[u8] {
61 fn value(&self) -> &[u8] {
65 fn issuer(&self) -> &[u8] {
69 fn serial_number(&self) -> &[u8] {
73 fn subject(&self) -> &[u8] {
78 impl CryptokiObject for Cert {
79 fn matches(&self, slot_type: SlotType, attrs: &[(CK_ATTRIBUTE_TYPE, Vec<u8>)]) -> bool {
80 if self.slot_type != slot_type {
83 for (attr_type, attr_value) in attrs {
84 let comparison = match *attr_type {
85 CKA_CLASS => self.class(),
86 CKA_TOKEN => self.token(),
87 CKA_LABEL => self.label(),
89 CKA_VALUE => self.value(),
90 CKA_ISSUER => self.issuer(),
91 CKA_SERIAL_NUMBER => self.serial_number(),
92 CKA_SUBJECT => self.subject(),
95 if attr_value.as_slice() != comparison {
102 fn get_attribute(&self, attribute: CK_ATTRIBUTE_TYPE) -> Option<&[u8]> {
103 let result = match attribute {
104 CKA_CLASS => self.class(),
105 CKA_TOKEN => self.token(),
106 CKA_LABEL => self.label(),
108 CKA_VALUE => self.value(),
109 CKA_ISSUER => self.issuer(),
110 CKA_SERIAL_NUMBER => self.serial_number(),
111 CKA_SUBJECT => self.subject(),
125 modulus: Option<Vec<u8>>,
126 ec_params: Option<Vec<u8>>,
133 modulus: Option<&[u8]>,
134 ec_params: Option<&[u8]>,
138 ) -> Result<Key, Error> {
139 let id = Sha256::digest(cert).to_vec();
140 let key_type = if modulus.is_some() { CKK_RSA } else { CKK_EC };
143 class: serialize_uint(CKO_PRIVATE_KEY)?,
144 token: serialize_uint(CK_TRUE)?,
146 private: serialize_uint(CK_TRUE)?,
147 key_type: serialize_uint(key_type)?,
148 modulus: modulus.map(|b| b.to_vec()),
149 ec_params: ec_params.map(|b| b.to_vec()),
155 fn class(&self) -> &[u8] {
159 fn token(&self) -> &[u8] {
163 pub fn id(&self) -> &[u8] {
167 fn private(&self) -> &[u8] {
171 fn key_type(&self) -> &[u8] {
175 fn modulus(&self) -> Option<&[u8]> {
176 match &self.modulus {
177 Some(modulus) => Some(modulus.as_slice()),
182 fn ec_params(&self) -> Option<&[u8]> {
183 match &self.ec_params {
184 Some(ec_params) => Some(ec_params.as_slice()),
190 impl CryptokiObject for Key {
191 fn matches(&self, slot_type: SlotType, attrs: &[(CK_ATTRIBUTE_TYPE, Vec<u8>)]) -> bool {
192 if self.slot_type != slot_type {
195 for (attr_type, attr_value) in attrs {
196 let comparison = match *attr_type {
197 CKA_CLASS => self.class(),
198 CKA_TOKEN => self.token(),
200 CKA_PRIVATE => self.private(),
201 CKA_KEY_TYPE => self.key_type(),
203 if let Some(modulus) = self.modulus() {
210 if let Some(ec_params) = self.ec_params() {
218 if attr_value.as_slice() != comparison {
225 fn get_attribute(&self, attribute: CK_ATTRIBUTE_TYPE) -> Option<&[u8]> {
227 CKA_CLASS => Some(self.class()),
228 CKA_TOKEN => Some(self.token()),
229 CKA_ID => Some(self.id()),
230 CKA_PRIVATE => Some(self.private()),
231 CKA_KEY_TYPE => Some(self.key_type()),
232 CKA_MODULUS => self.modulus(),
233 CKA_EC_PARAMS => self.ec_params(),
240 fn get_signature_length(
243 params: &Option<CK_RSA_PKCS_PSS_PARAMS>,
244 ) -> Result<usize, Error> {
245 // Unfortunately we don't have a way of getting the length of a signature without creating
247 let dummy_signature_bytes = self.sign(data, params)?;
248 Ok(dummy_signature_bytes.len())
254 params: &Option<CK_RSA_PKCS_PSS_PARAMS>,
255 ) -> Result<Vec<u8>, Error> {
256 let mut signature = Vec::new();
257 let (params_len, params) = match params {
259 std::mem::size_of::<CK_RSA_PKCS_PSS_PARAMS>(),
260 params as *const _ as *const u8,
262 None => (0, std::ptr::null()),
272 &mut signature as *mut _ as *mut c_void,
274 if signature.len() > 0 {
277 Err(error_here!(ErrorType::LibraryFailure))
282 unsafe extern "C" fn sign_callback(data_len: usize, data: *const u8, ctx: *mut c_void) {
283 let signature: &mut Vec<u8> = std::mem::transmute(ctx);
286 signature.extend_from_slice(std::slice::from_raw_parts(data, data_len));
290 unsafe extern "C" fn find_objects_callback(
299 let data = if data_len == 0 {
302 std::slice::from_raw_parts(data, data_len)
304 let extra = if extra_len == 0 {
307 std::slice::from_raw_parts(extra, extra_len)
309 let slot_type = match slot_type {
310 1 => SlotType::Modern,
311 2 => SlotType::Legacy,
314 let find_objects_context: &mut FindObjectsContext = std::mem::transmute(ctx);
316 1 => match Cert::new(data, slot_type) {
317 Ok(cert) => find_objects_context.certs.push(cert),
325 find_objects_context.sign,
327 Ok(key) => find_objects_context.keys.push(key),
335 find_objects_context.sign,
337 Ok(key) => find_objects_context.keys.push(key),
344 struct FindObjectsContext {
350 impl FindObjectsContext {
351 fn new(sign: SignFunction) -> FindObjectsContext {
361 find_objects: FindObjectsFunction,
366 pub fn new(find_objects: FindObjectsFunction, sign: SignFunction) -> Backend {
367 Backend { find_objects, sign }
371 impl ClientCertsBackend for Backend {
375 fn find_objects(&self) -> Result<(Vec<Cert>, Vec<Key>), Error> {
376 let mut find_objects_context = FindObjectsContext::new(self.sign);
378 Some(find_objects_callback),
379 &mut find_objects_context as *mut _ as *mut c_void,
381 Ok((find_objects_context.certs, find_objects_context.keys))