|
3 | 3 | //! Signing and authentication functions |
4 | 4 |
|
5 | 5 | use crate::context::Function; |
6 | | -use crate::error::{Result, Rv}; |
| 6 | +use crate::error::{Error, Result, Rv, RvError}; |
7 | 7 | use crate::mechanism::Mechanism; |
8 | 8 | use crate::object::ObjectHandle; |
9 | 9 | use crate::session::Session; |
10 | 10 | use cryptoki_sys::*; |
11 | 11 | use std::convert::TryInto; |
12 | 12 |
|
| 13 | +/// # Generating and Verifying Signatures |
| 14 | +/// |
| 15 | +/// Several functions are provided for signing data and verifying signatures. |
| 16 | +/// This includes message authentication codes (MACs). The signed data can be |
| 17 | +/// provided in one-shot and streaming modes. |
13 | 18 | impl Session { |
14 | 19 | /// Sign data in single-part |
15 | 20 | pub fn sign(&self, mechanism: &Mechanism, key: ObjectHandle, data: &[u8]) -> Result<Vec<u8>> { |
@@ -56,6 +61,81 @@ impl Session { |
56 | 61 | Ok(signature) |
57 | 62 | } |
58 | 63 |
|
| 64 | + /// Sign data into the given buffer. |
| 65 | + /// |
| 66 | + /// `data` should be a byte sequence representing the input message. It will |
| 67 | + /// be signed using the specified key, and the resulting signature will be |
| 68 | + /// written to the given output buffer. |
| 69 | + /// |
| 70 | + /// The output buffer should be large enough to store the signature. |
| 71 | + /// If it is large enough, the number of filled bytes is returned |
| 72 | + /// (i.e. `sig[0..size]` contains the prepared signature). Otherwise, |
| 73 | + /// [`Error::IncorrectBufferSize`] is returned. |
| 74 | + /// |
| 75 | + /// Use [`Self::sign()`] if (an upper bound for) the size of the signature |
| 76 | + /// is not known. Use [`Self::sign_init()`] etc. if the input data is being |
| 77 | + /// streamed (i.e. it is not all immediately available). |
| 78 | + pub fn sign_into( |
| 79 | + &mut self, |
| 80 | + mechanism: &Mechanism, |
| 81 | + key: ObjectHandle, |
| 82 | + data: &[u8], |
| 83 | + sig: &mut [u8], |
| 84 | + ) -> Result<usize> { |
| 85 | + let mut mechanism: CK_MECHANISM = mechanism.into(); |
| 86 | + |
| 87 | + // The size of the signature buffer, into which 'C_Sign' will write the |
| 88 | + // size of the generated signature. |
| 89 | + let sig_buf_len = sig.len().try_into()?; |
| 90 | + let mut sig_len = sig_buf_len; |
| 91 | + |
| 92 | + // Initialize the signing operation. |
| 93 | + unsafe { |
| 94 | + Rv::from(get_pkcs11!(self.client(), C_SignInit)( |
| 95 | + self.handle(), |
| 96 | + &mut mechanism as CK_MECHANISM_PTR, |
| 97 | + key.handle(), |
| 98 | + )) |
| 99 | + .into_result(Function::SignInit)?; |
| 100 | + } |
| 101 | + |
| 102 | + // Perform the actual signing. |
| 103 | + let res = unsafe { |
| 104 | + Rv::from(get_pkcs11!(self.client(), C_Sign)( |
| 105 | + self.handle(), |
| 106 | + data.as_ptr() as *mut u8, |
| 107 | + data.len().try_into()?, |
| 108 | + sig.as_mut_ptr(), |
| 109 | + &mut sig_len, |
| 110 | + )) |
| 111 | + }; |
| 112 | + |
| 113 | + // Check the result and buffer size. |
| 114 | + match res { |
| 115 | + Rv::Ok => { |
| 116 | + // TODO: Should this be an Error of some kind? |
| 117 | + assert!(sig_len <= sig_buf_len); |
| 118 | + |
| 119 | + // 'sig_len <= sig_buf_len <= usize::MAX'. |
| 120 | + Ok(sig_len as usize) |
| 121 | + } |
| 122 | + |
| 123 | + Rv::Error(RvError::BufferTooSmall) => { |
| 124 | + // TODO: Should this be an Error of some kind? |
| 125 | + assert!(sig_len > sig_buf_len); |
| 126 | + |
| 127 | + // All reasonable buffer sizes fit in 'usize'. |
| 128 | + let sig_len: usize = sig_len.try_into()?; |
| 129 | + |
| 130 | + Err(Error::IncorrectBufferSize(sig_len)) |
| 131 | + } |
| 132 | + |
| 133 | + // The error seems unrelated to the buffer size, so we don't check |
| 134 | + // what 'sig_len' has been set to (if anything). |
| 135 | + Rv::Error(err) => Err(Error::Pkcs11(err, Function::Sign)), |
| 136 | + } |
| 137 | + } |
| 138 | + |
59 | 139 | /// Starts new multi-part signing operation |
60 | 140 | pub fn sign_init(&self, mechanism: &Mechanism, key: ObjectHandle) -> Result<()> { |
61 | 141 | let mut mechanism: CK_MECHANISM = mechanism.into(); |
@@ -118,6 +198,66 @@ impl Session { |
118 | 198 | Ok(signature) |
119 | 199 | } |
120 | 200 |
|
| 201 | + /// Complete an ongoing multi-part signing operation, writing the signature |
| 202 | + /// into the given buffer. |
| 203 | + /// |
| 204 | + /// This must be preceded by [`Self::sign_init()`] and zero or more calls |
| 205 | + /// to [`Self::sign_update()`]. This method will terminate the multi-part |
| 206 | + /// signing operation. |
| 207 | + /// |
| 208 | + /// The output buffer should be large enough to store the signature. |
| 209 | + /// If it is large enough, the number of filled bytes is returned |
| 210 | + /// (i.e. `sig[0..size]` contains the prepared signature). Otherwise, |
| 211 | + /// [`Error::IncorrectBufferSize`] is returned. |
| 212 | + /// |
| 213 | + /// Use [`Self::sign_final()`] if (an upper bound for) the size of the |
| 214 | + /// signature is not known. Use [`Self::sign_into()`] if the input data |
| 215 | + /// is entirely available in a single buffer (i.e. does not have to be |
| 216 | + /// streamed). |
| 217 | + // |
| 218 | + // TODO: Is it possible to re-do this call if an incorrect buffer size |
| 219 | + // was passed in? I think so? |
| 220 | + pub fn sign_final_into(&mut self, sig: &mut [u8]) -> Result<usize> { |
| 221 | + // The size of the signature buffer, into which 'C_Sign' will write the |
| 222 | + // size of the generated signature. |
| 223 | + let sig_buf_len = sig.len().try_into()?; |
| 224 | + let mut sig_len = sig_buf_len; |
| 225 | + |
| 226 | + // Perform the underlying finalization. |
| 227 | + let res = unsafe { |
| 228 | + Rv::from(get_pkcs11!(self.client(), C_SignFinal)( |
| 229 | + self.handle(), |
| 230 | + sig.as_mut_ptr(), |
| 231 | + &mut sig_len, |
| 232 | + )) |
| 233 | + }; |
| 234 | + |
| 235 | + // Check the result and buffer size. |
| 236 | + match res { |
| 237 | + Rv::Ok => { |
| 238 | + // TODO: Should this be an Error of some kind? |
| 239 | + assert!(sig_len <= sig_buf_len); |
| 240 | + |
| 241 | + // 'sig_len <= sig_buf_len <= usize::MAX'. |
| 242 | + Ok(sig_len as usize) |
| 243 | + } |
| 244 | + |
| 245 | + Rv::Error(RvError::BufferTooSmall) => { |
| 246 | + // TODO: Should this be an Error of some kind? |
| 247 | + assert!(sig_len > sig_buf_len); |
| 248 | + |
| 249 | + // All reasonable buffer sizes fit in 'usize'. |
| 250 | + let sig_len: usize = sig_len.try_into()?; |
| 251 | + |
| 252 | + Err(Error::IncorrectBufferSize(sig_len)) |
| 253 | + } |
| 254 | + |
| 255 | + // The error seems unrelated to the buffer size, so we don't check |
| 256 | + // what 'sig_len' has been set to (if anything). |
| 257 | + Rv::Error(err) => Err(Error::Pkcs11(err, Function::Sign)), |
| 258 | + } |
| 259 | + } |
| 260 | + |
121 | 261 | /// Verify data in single-part |
122 | 262 | pub fn verify( |
123 | 263 | &self, |
|
0 commit comments