-
Notifications
You must be signed in to change notification settings - Fork 711
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add signature::primitive::verify_rsa
#226
Conversation
From the old IRC conversation, my understanding is that there are two reasons we need such a function:
For #1, I suggest that instead we just add a new function For #2, I suggest that when we create a public key, we should create and store the ASN.1-encoded public key in a WDYT? |
Sounds good. Please review my implementation of #1. |
It looks like you forgot to |
Yeah... I've fixed it up now. |
Coverage increased (+0.5%) to 87.16% when pulling 3e473f2e4bd97e1e34f2d963c399a1cae52bb0e7 on djc:public-key-as-der into 97bb46a on briansmith:master. |
(n, e): (untrusted::Input, untrusted::Input)) | ||
-> Result<(), ()> { | ||
let n = n.as_slice_less_safe(); | ||
let e = e.as_slice_less_safe(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think instead we should change parse_public_key
so that it returns untrusted::Input
s and then have super::verify
take (n, e): (untrusted::Input, untrusted::Input)
. This removes the duplication of the as_slice_less_safe
and fits the pattern I'm trying to promote wherein we avoid using slices for untrusted inputs when possible.
We need to decide how/where we're going to expose the low-level primitives. My original suggestion was that we have Also, I think we need to update the module-level documentation of |
Ah, sorry if I implemented the API wrong. I'm not yet well-versed in the intricacies of Rust's module system and how it interacts with public APIs. Will try to rejigger so that it exposes |
Suggestion: do |
This should be better, let me know what you think! |
Coverage increased (+0.09%) to 87.474% when pulling c50f1683897da8287ebb780ac98012277d5b8d6a on djc:public-key-as-der into 752c8c6 on briansmith:master. |
Coverage increased (+0.03%) to 87.863% when pulling 9f7dd3f6ef0f15f9377938abad96d06350700389 on djc:public-key-as-der into e4e175d on briansmith:master. |
rsa::primitive::verify
signature: untrusted::Input, | ||
(n, e): (untrusted::Input, untrusted::Input)) | ||
-> Result<(), ()> { | ||
super::verify(padding, msg, signature, (n, e), 2048) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please see my comments in the other PR where you renamed RSA_PKCS1_2048_8192_SHA*_VERIFY
to RSA_PKCS1_SHA*_2048_8192
. I had landed that change, and then I saw this change and decided to revert that change because this helped me see that we're going in the wrong direction.
As discussed previously, our goal is to eventually develop an API that treats ECDSA, RSA, etc. uniformly or at least as similarly as possible. In ECDSA, the only parameters you have are curve and digest algorithm. In RSA, you have min bits, max bits, digest algorithm, exponent, and padding scheme. In ring, I've chosen to use the following mapping:
ECDSA | RSA | EdDSA |
---|---|---|
Algorithm = ECDSA | Algorithm = (RSA, Padding Scheme) | Algorithm = EdDSA |
Curve | modulus min bits, modulus max bits, exponent min bits, exponent max bits) | Curve |
Digest Alg. | Digest Alg. | implicit |
Encoding (ASN.1, PKCS#11/WebCrypto) | implicit | implicit |
Note that the exponent range is fixed at (2 bits, 33 bits). But, I'm thinking of changing that so that for the 3072-8192 variant (Suite B), at least, the minimum exponent length will be 16 bits.
So, anyway, I'm a little unsure how important it is to be explicit about the allowed exponent range, but at least this new primitive API should allow the caller to be explicit about the modulus range--at least the minimum modulus length.
Going back to your other PR, the issue you had was that RSAPadding
s are named RSA_<padding_scheme>_<digest_alg>
but RSA SignatureAlgorithm
s are named similarly, but they put <min_modulus_bits>_<max_modulus_bits> in between. And, that affects this API because it takes RSAPadding
as a parameter. But, maybe this API shouldn't take RSAPadding
.
Ideally, this API should take RSA_PKCS1_2048_8192_SHA256
, etc. as parameters instead, like verify()
does, but with a type that isn't VerificationAlgorithm
but instead something like RSAParameters
or something. After all, this API is exactly like verify
except that it takes its public key argument pre-parsed.
But, I'm not sure how to do that without making VerificationAlgorithm
a trait, which I don't want to do for the reasons I explained before. If I have to choose between the main verify
API forcing people to use
traits or the primitive
API forcing people to use
traits, I'd prefer to put that inconvenience on the primitive
API.
Maybe it is possible to change the type of RSA_PKCS1_2048_8192_SHA256
et al. from &'static VerificationAlgorithm
to &'static <VerificationAlgorithm + RSAParameters>
and make RSAParameters
a trait? I've never tried to do that before so i'm not sure.
Or, if that's all too complicated, then we can punt on trying to create a really uniform API and just, at least, make the minimum key size a parameter of this new function. The main thing I want to avoid doing is making the key size implicit like it is in this patch, because one of the most important design goals for ring is to avoid such implicit security-critical parameters.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So we just have RSAParameters
that carries a reference to an RSAPadding
, and then a SignatureVerificationAlgorithm
that carries a reference to an RSAParameters
? For now, RSAParameters
can also carry min_bits
, and then you could add more stuff later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So we just have RSAParameters that carries a reference to an RSAPadding, and then a SignatureVerificationAlgorithm that carries a reference to an RSAParameters? For now, RSAParameters can also carry min_bits, and then you could add more stuff later.
That seems like one reasonable way of doing it. TBH, it's a little hard for me to tell w/o seeing some code for it.
@samscott89 Your work on PSS might benefit from looking at this. |
Pushed the latest version for reference. |
Coverage increased (+0.02%) to 89.463% when pulling 7b614c64a3b6a11f1513fb5e88cefb5545a2b8da on djc:public-key-as-der into 0ab853a on briansmith:master. |
impl signature::VerificationAlgorithm for RSAParameters { | ||
fn verify(&self, public_key: untrusted::Input, msg: untrusted::Input, | ||
signature: untrusted::Input) -> Result<(), ()> { | ||
verify(self, msg, signature, public_key) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The arguments to the new verify
function should be in the same order as the arguments to the existing verify
functions: "public_key, msg, signature".
@@ -90,6 +89,8 @@ | |||
while_true, | |||
)] | |||
|
|||
#![cfg_attr(not(feature = "nightly"), deny(drop_with_repr_extern))] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't see this until I'd already written a different patch. This is smarter than what I did. I don't think we need to do this though, because in 6 weeks we'd have to remove it. Thanks though!
I updated https://github.com/briansmith/ring/commits/public-key-as-der with your patches rebased on top of the previous version and on top of the current master. |
I agree to license my contributions to each file under the terms given at the top of each file I changed.
I agree to license my contributions to each file under the terms given at the top of each file I changed.
8ecb0d1
to
96437b9
Compare
The latest should address all your comments, and has your comment extension folded in. I hope we're converging! |
Coverage decreased (-2.8%) to 88.783% when pulling 96437b9d24faa306efed62fb7c03174a70af35de on djc:public-key-as-der into fcbf905 on briansmith:master. |
So my change to diff --git a/src/rsa/rsa.rs b/src/rsa/rsa.rs
index f540c3b..7d2870e 100644
--- a/src/rsa/rsa.rs
+++ b/src/rsa/rsa.rs
@@ -126,8 +126,14 @@ impl PositiveInteger {
fn from_der(input: &mut untrusted::Reader)
-> Result<PositiveInteger, error::Unspecified> {
let bytes = try!(der::positive_integer(input)).as_slice_less_safe();
+ let raw_bytes = if bytes[0] == 0 {
+ &bytes[1..]
+ } else {
+ &bytes[..]
+ };
let res = unsafe {
- GFp_BN_bin2bn(bytes.as_ptr(), bytes.len(), core::ptr::null_mut())
+ GFp_BN_bin2bn(raw_bytes.as_ptr(), raw_bytes.len(),
+ core::ptr::null_mut())
};
if res.is_null() {
return Err(error::Unspecified); |
But, also, the point of this PR is to completely bypass the need for DER decoding in the first place, right? I think instead we need to add the leading zero detection within
Note that |
Well, the problem doesn't show up for verification, only for signing, so I'm not sure it makes sense to add something to |
Moves the conversion from untrusted::Input (via slice) to BIGNUM from C to Rust using the PositiveInteger struct we already use for signing. Adds a check to error out when encountering a number that starts with zero. I agree to license my contributions to each file under the terms given at the top of each file I changed.
I agree to license my contributions to each file under the terms given at the top of each file I changed.
I agree to license my contributions to each file under the terms given at the top of each file I changed.
…ication. I agree to license my contributions to each file under the terms given at the top of each file I changed.
96437b9
to
5da946f
Compare
I followed through on your suggestion, in 18fdc13. The result seems sane, and passes the tests for me even with |
2 similar comments
This looks good. I made some adjustments for the new |
It looks good to me. So you want tests for both the low-level and higher-level APIs, even if the lower-level API is covered by tests for the higher-level one? What's the merit of Also, note that "indention" is an archaic word for "indentation". When this is merged, would you mind bumping ring on crates.io? |
I try to add tests where they are helpful, without getting carried away. In this case, I think there was a bug where
:) Too late, I guess. Thanks though.
Sure! |
https://crates.io/crates/ring/0.4.1 5778edb 0.4.1 release. Thanks a lot for contributing this! |
I agree to license my contributions to each file under the terms given
at the top of each file I changed.