Conversation
Signed-off-by: arya dradjica <arya@nlnetlabs.nl>
3c1d3ff to
bfba84a
Compare
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>
|
I see working with |
hug-dev
left a comment
There was a problem hiding this comment.
Thank you!
Really like the added documentation, I think that's good! My only suggestion is to simplify and return the original error as is :)
For testing I think it's fine trying one or a few variants. You can for example use the same one which is done in the test currently for the sign operation!
| /// | ||
| /// `data` should be a byte sequence representing the input message. It will | ||
| /// be signed using the specified key, and the resulting signature will be | ||
| /// written to the given output buffer. |
There was a problem hiding this comment.
maybe add the name of that output buffer to mirror how you did it with data, ie sig.
| match res { | ||
| Rv::Ok => { | ||
| // TODO: Should this be an Error of some kind? | ||
| assert!(sig_len <= sig_buf_len); | ||
|
|
||
| // 'sig_len <= sig_buf_len <= usize::MAX'. | ||
| Ok(sig_len as usize) | ||
| } | ||
|
|
||
| Rv::Error(RvError::BufferTooSmall) => { | ||
| // TODO: Should this be an Error of some kind? | ||
| assert!(sig_len > sig_buf_len); | ||
|
|
||
| // All reasonable buffer sizes fit in 'usize'. | ||
| let sig_len: usize = sig_len.try_into()?; | ||
|
|
||
| Err(Error::IncorrectBufferSize(sig_len)) | ||
| } | ||
|
|
||
| // The error seems unrelated to the buffer size, so we don't check | ||
| // what 'sig_len' has been set to (if anything). | ||
| Rv::Error(err) => Err(Error::Pkcs11(err, Function::Sign)), | ||
| } |
There was a problem hiding this comment.
My personal opinion is that we can simply return return res as is, without the new error IncorrectBufferSize. I think the original PKCS11 error code BufferTooSmall is explicit enough for the caller 😸 Same for the multi steps variant!
If needed, we could also add a new method which would return the size of a signature with this specific key and mechanism!
There was a problem hiding this comment.
Right, I had originally added IncorrectBufferSize because I wanted to enforce that the caller had provided exactly the right size (and not one that was too big). Since that is no longer the case, the error is not necessary. Good catch, I'll remove it.
wiktor-k
left a comment
There was a problem hiding this comment.
Looks great, a couple of nitpicks/clarifications. Thanks for your contribution! 🙇
| /// | ||
| /// The buffer may be too small or too large. The expected size (in bytes) | ||
| /// is returned. | ||
| IncorrectBufferSize(usize), |
There was a problem hiding this comment.
I think I'd make it a bit more explicit:
| IncorrectBufferSize(usize), | |
| IncorrectBufferSize { | |
| expected_size: usize | |
| }, |
| use cryptoki_sys::*; | ||
| use std::convert::TryInto; | ||
|
|
||
| /// # Generating and Verifying Signatures |
There was a problem hiding this comment.
Hmm... are these docs rendered anywhere? If not I'd move the docs to the bottom of docs for struct Session
| /// (i.e. `sig[0..size]` contains the prepared signature). Otherwise, | ||
| /// [`Error::IncorrectBufferSize`] is returned. | ||
| /// | ||
| /// Use [`Self::sign()`] if (an upper bound for) the size of the signature |
There was a problem hiding this comment.
I'm not sure if these parens are working 🤔
| /// Use [`Self::sign()`] if (an upper bound for) the size of the signature | |
| /// Use [`Self::sign`] if (an upper bound for) the size of the signature |
| // Check the result and buffer size. | ||
| match res { | ||
| Rv::Ok => { | ||
| // TODO: Should this be an Error of some kind? |
There was a problem hiding this comment.
I don't think so, we promise in the docs to write only up to sig_len size so the assert is fine here. I'd add a little bit of docs to the assert...
| match res { | ||
| Rv::Ok => { | ||
| // TODO: Should this be an Error of some kind? | ||
| assert!(sig_len <= sig_buf_len); |
There was a problem hiding this comment.
A random suggestion:
| assert!(sig_len <= sig_buf_len); | |
| assert!(sig_len <= sig_buf_len, "Signature size is bigger than the buffer size but the PKCS#11 module returned OK, this is not right."); |
| } | ||
|
|
||
| Rv::Error(RvError::BufferTooSmall) => { | ||
| // TODO: Should this be an Error of some kind? |
There was a problem hiding this comment.
Similarly to the case above with some clever wording :)
I think it looks fine as it is 👌
No pressure to add more, this may grow organically as use-cases appear. If you feel like doing additional work I'm not stopping you though 😅
Yep, ideally the tests should exercise all paths, including error ones and check if returned errors match what we expect. Choosing one algo for tests is sufficient. (Ideally it should be implemented by both softhsm and kryoptic but I don't think you'll use anything exotic). Thanks! 👋 |
| /// The output buffer should be large enough to store the signature. | ||
| /// If it is large enough, the number of filled bytes is returned | ||
| /// (i.e. `sig[0..size]` contains the prepared signature). Otherwise, | ||
| /// [`Error::IncorrectBufferSize`] is returned. |
There was a problem hiding this comment.
might make sense to be explicit here too that the returned IncorrectBufferSize has the expected size.
| // | ||
| // TODO: Is it possible to re-do this call if an incorrect buffer size | ||
| // was passed in? I think so? | ||
| pub fn sign_final_into(&mut self, sig: &mut [u8]) -> Result<usize> { |
There was a problem hiding this comment.
Is there a way to reuse the sign_final() we have? Or reuse this in the existing sign_final() function? It has a lot of duplicated code.
Similarly for the sign_into().
Starts addressing #346.
Question for the reviewers:
What do you think of the added documentation? Is it too much? Or should I add more to the related
sign()functions for consistency?I don't have a strict need to implement this for more operations, but I'm happy to do one or two sets more. Are there any in particular you'd like to see? I'm leaning towards key generation (which I need, but is not performance-sensitive) and encryption (which I guess more people would want to use).
Would you have any tips for adding these methods to the test suite? It'll have to be a bit algorithm-specific.