Skip to content

Commit c072317

Browse files
committed
Implement 'sign[_final]_into()'
These '_into()' variants can be used when the caller knows the expected buffer size, and has allocated a buffer for the signature themselves. It requires fewer calls into the underlying library and can save on heap allocations. Signed-off-by: arya dradjica <arya@nlnetlabs.nl>
1 parent c3fc3bb commit c072317

1 file changed

Lines changed: 141 additions & 1 deletion

File tree

cryptoki/src/session/signing_macing.rs

Lines changed: 141 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,18 @@
33
//! Signing and authentication functions
44
55
use crate::context::Function;
6-
use crate::error::{Result, Rv};
6+
use crate::error::{Error, Result, Rv, RvError};
77
use crate::mechanism::Mechanism;
88
use crate::object::ObjectHandle;
99
use crate::session::Session;
1010
use cryptoki_sys::*;
1111
use std::convert::TryInto;
1212

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.
1318
impl Session {
1419
/// Sign data in single-part
1520
pub fn sign(&self, mechanism: &Mechanism, key: ObjectHandle, data: &[u8]) -> Result<Vec<u8>> {
@@ -56,6 +61,81 @@ impl Session {
5661
Ok(signature)
5762
}
5863

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+
59139
/// Starts new multi-part signing operation
60140
pub fn sign_init(&self, mechanism: &Mechanism, key: ObjectHandle) -> Result<()> {
61141
let mut mechanism: CK_MECHANISM = mechanism.into();
@@ -118,6 +198,66 @@ impl Session {
118198
Ok(signature)
119199
}
120200

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+
121261
/// Verify data in single-part
122262
pub fn verify(
123263
&self,

0 commit comments

Comments
 (0)