Skip to content

Commit cbf4015

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 f5a650d commit cbf4015

1 file changed

Lines changed: 131 additions & 15 deletions

File tree

cryptoki/src/session/signing_macing.rs

Lines changed: 131 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,29 +3,38 @@
33
//! Signing and authentication functions
44
55
use crate::context::Function;
6+
#[cfg(doc)]
7+
use crate::error::RvError;
68
use crate::error::{Result, Rv};
79
use crate::mechanism::Mechanism;
810
use crate::object::ObjectHandle;
911
use crate::session::Session;
1012
use cryptoki_sys::*;
1113
use std::convert::TryInto;
1214

15+
/// # Generating and Verifying Signatures
16+
///
17+
/// Several functions are provided for signing data and verifying signatures.
18+
/// This includes message authentication codes (MACs). The signed data can be
19+
/// provided in one-shot and streaming modes.
1320
impl Session {
14-
/// Sign data in single-part
21+
/// Sign data in one-shot mode.
22+
///
23+
/// `data` should be a byte sequence representing the input message. It will
24+
/// be signed using the specified key, and the resulting signature will be
25+
/// returned in a `Vec`.
26+
///
27+
/// Use [`Self::sign_into()`] if (an upper bound for) the size of the
28+
/// signature is known, to avoid the heap allocation of `Vec`. Use
29+
/// [`Self::sign_init()`] etc. if the input data is being streamed (i.e. it
30+
/// is not all immediately available).
1531
pub fn sign(&self, mechanism: &Mechanism, key: ObjectHandle, data: &[u8]) -> Result<Vec<u8>> {
16-
let mut mechanism: CK_MECHANISM = mechanism.into();
1732
let mut signature_len = 0;
1833

19-
unsafe {
20-
Rv::from(get_pkcs11!(self.client(), C_SignInit)(
21-
self.handle(),
22-
&mut mechanism as CK_MECHANISM_PTR,
23-
key.handle(),
24-
))
25-
.into_result(Function::SignInit)?;
26-
}
34+
// Initialize the signing operation.
35+
self.sign_init(mechanism, key)?;
2736

28-
// Get the output buffer length
37+
// Get the output buffer length.
2938
unsafe {
3039
Rv::from(get_pkcs11!(self.client(), C_Sign)(
3140
self.handle(),
@@ -37,9 +46,10 @@ impl Session {
3746
.into_result(Function::Sign)?;
3847
}
3948

49+
// Allocate the output buffer.
4050
let mut signature = vec![0; signature_len.try_into()?];
4151

42-
//TODO: we should add a new error instead of those unwrap!
52+
// Perform the actual signing.
4353
unsafe {
4454
Rv::from(get_pkcs11!(self.client(), C_Sign)(
4555
self.handle(),
@@ -51,11 +61,62 @@ impl Session {
5161
.into_result(Function::Sign)?;
5262
}
5363

64+
// Limit the output buffer to the size of the generated signature.
5465
signature.truncate(signature_len.try_into()?);
5566

5667
Ok(signature)
5768
}
5869

70+
/// Sign data into the given buffer.
71+
///
72+
/// `data` should be a byte sequence representing the input message. It will
73+
/// be signed using the specified key, and the resulting signature will be
74+
/// written to the given output buffer.
75+
///
76+
/// The output buffer should be large enough to store the signature.
77+
/// If it is large enough, the number of filled bytes is returned
78+
/// (i.e. `sig[0..size]` contains the prepared signature). Otherwise,
79+
/// [`RvError::BufferTooSmall`] will be returned.
80+
///
81+
/// Use [`Self::sign()`] if (an upper bound for) the size of the signature
82+
/// is not known. Use [`Self::sign_init()`] etc. if the input data is being
83+
/// streamed (i.e. it is not all immediately available).
84+
pub fn sign_into(
85+
&mut self,
86+
mechanism: &Mechanism,
87+
key: ObjectHandle,
88+
data: &[u8],
89+
sig: &mut [u8],
90+
) -> Result<usize> {
91+
// The size of the signature buffer, into which 'C_Sign' will write the
92+
// size of the generated signature.
93+
let sig_buf_len = sig.len().try_into()?;
94+
let mut sig_len = sig_buf_len;
95+
96+
// Initialize the signing operation.
97+
self.sign_init(mechanism, key)?;
98+
99+
// Perform the actual signing.
100+
unsafe {
101+
Rv::from(get_pkcs11!(self.client(), C_Sign)(
102+
self.handle(),
103+
data.as_ptr() as *mut u8,
104+
data.len().try_into()?,
105+
sig.as_mut_ptr(),
106+
&mut sig_len,
107+
))
108+
.into_result(Function::Sign)?;
109+
}
110+
111+
assert!(
112+
sig_len <= sig_buf_len,
113+
"'C_Sign' succeeded but increased 'sig_len', possibly indicating out-of-bounds accesses"
114+
);
115+
116+
// NOTE: As checked above, 'sig_len <= sig_buf_len <= usize::MAX'.
117+
Ok(sig_len as usize)
118+
}
119+
59120
/// Starts new multi-part signing operation
60121
pub fn sign_init(&self, mechanism: &Mechanism, key: ObjectHandle) -> Result<()> {
61122
let mut mechanism: CK_MECHANISM = mechanism.into();
@@ -87,12 +148,20 @@ impl Session {
87148
Ok(())
88149
}
89150

90-
/// Finalizes ongoing multi-part signing operation,
91-
/// returning the signature
151+
/// Complete an ongoing streaming signing operation.
152+
///
153+
/// This must be preceded by [`Self::sign_init()`] and zero or more calls
154+
/// to [`Self::sign_update()`]. This method will terminate the multi-part
155+
/// signing operation. The resulting signature will be returned in a `Vec`.
156+
///
157+
/// Use [`Self::sign_final_into()`] if (an upper bound for) the size of
158+
/// the signature is known, to avoid the heap allocation of `Vec`. Use
159+
/// [`Self::sign()`] if the input data is entirely available in a single
160+
/// buffer (i.e. does not have to be streamed).
92161
pub fn sign_final(&self) -> Result<Vec<u8>> {
93162
let mut signature_len = 0;
94163

95-
// Get the output buffer length
164+
// Get the output buffer length.
96165
unsafe {
97166
Rv::from(get_pkcs11!(self.client(), C_SignFinal)(
98167
self.handle(),
@@ -102,8 +171,10 @@ impl Session {
102171
.into_result(Function::SignFinal)?;
103172
}
104173

174+
// Allocate the output buffer.
105175
let mut signature = vec![0; signature_len.try_into()?];
106176

177+
// Perform the actual signing.
107178
unsafe {
108179
Rv::from(get_pkcs11!(self.client(), C_SignFinal)(
109180
self.handle(),
@@ -113,11 +184,56 @@ impl Session {
113184
.into_result(Function::SignFinal)?;
114185
}
115186

187+
// Limit the output buffer to the size of the generated signature.
116188
signature.truncate(signature_len.try_into()?);
117189

118190
Ok(signature)
119191
}
120192

193+
/// Complete an ongoing multi-part signing operation, writing the signature
194+
/// into the given buffer.
195+
///
196+
/// This must be preceded by [`Self::sign_init()`] and zero or more calls
197+
/// to [`Self::sign_update()`]. This method will terminate the multi-part
198+
/// signing operation.
199+
///
200+
/// The output buffer should be large enough to store the signature.
201+
/// If it is large enough, the number of filled bytes is returned
202+
/// (i.e. `sig[0..size]` contains the prepared signature). Otherwise,
203+
/// [`RvError::BufferTooSmall`] will be returned.
204+
///
205+
/// Use [`Self::sign_final()`] if (an upper bound for) the size of the
206+
/// signature is not known. Use [`Self::sign_into()`] if the input data
207+
/// is entirely available in a single buffer (i.e. does not have to be
208+
/// streamed).
209+
//
210+
// TODO: Is it possible to re-do this call if an incorrect buffer size
211+
// was passed in? I think so?
212+
pub fn sign_final_into(&mut self, sig: &mut [u8]) -> Result<usize> {
213+
// The size of the signature buffer, into which 'C_SignFinal' will write
214+
// the size of the generated signature.
215+
let sig_buf_len = sig.len().try_into()?;
216+
let mut sig_len = sig_buf_len;
217+
218+
// Perform the underlying finalization.
219+
unsafe {
220+
Rv::from(get_pkcs11!(self.client(), C_SignFinal)(
221+
self.handle(),
222+
sig.as_mut_ptr(),
223+
&mut sig_len,
224+
))
225+
.into_result(Function::SignFinal)?;
226+
}
227+
228+
assert!(
229+
sig_len <= sig_buf_len,
230+
"'C_SignFinal' succeeded but increased 'sig_len', possibly indicating out-of-bounds accesses"
231+
);
232+
233+
// NOTE: As checked above, 'sig_len <= sig_buf_len <= usize::MAX'.
234+
Ok(sig_len as usize)
235+
}
236+
121237
/// Verify data in single-part
122238
pub fn verify(
123239
&self,

0 commit comments

Comments
 (0)