Skip to content
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

Use a more specific error instead of unspecified::Error for DER encoding errors, as per #379 #384

Conversation

marshallpierce
Copy link
Contributor

I agree to license my contributions to each file under the terms given
at the top of each file I changed.

@@ -338,7 +338,7 @@ pub struct PublicScalarOps {
impl PublicScalarOps {
pub fn scalar_parse(&self, input: &mut untrusted::Reader)
-> Result<Scalar, error::Unspecified> {
let encoded_value = try!(der::positive_integer(input));
let encoded_value = try!(der::positive_integer(input).map_err(|_| error::Unspecified));
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There were only a few places that needed to map_err so I chose to not implement From<ASN1Error>, but I can do that if you prefer.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's OK to punt on that for now.

src/der.rs Outdated
/// An error in ASN1 parsing. Normal hygiene applies: if parsing secret
/// DER, do not differentiate this from any other error.
#[derive(Clone, Copy)]
pub struct ASN1Error;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Asn1Error? DerError?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think ASN1Error is fine even because I can't stand Asn1Error or similar capitalization of acronyms.

@coveralls
Copy link

coveralls commented Dec 21, 2016

Coverage Status

Coverage increased (+0.001%) to 93.24% when pulling 29b459c2926e94effa245d32dbe90fcf8deaa6ea on marshallpierce:more-specific-error-for-der into 8596c78 on briansmith:master.

@briansmith briansmith added this to the 0.7.1 milestone Dec 22, 2016
@coveralls
Copy link

coveralls commented Dec 22, 2016

Coverage Status

Coverage decreased (-0.3%) to 92.952% when pulling 607e5520c9f1f9d36aab70c6121eb84cb7287403 on marshallpierce:more-specific-error-for-der into 98b46d8 on briansmith:master.

@coveralls
Copy link

coveralls commented Dec 24, 2016

Coverage Status

Coverage increased (+0.001%) to 92.884% when pulling 22c57624c635d2a5cbe50a79de54d26ca7fcf228 on marshallpierce:more-specific-error-for-der into e3a804a on briansmith:master.

@marshallpierce
Copy link
Contributor Author

Does appveyor normally take this long? It's been a day and they still haven't run their builds.

@marshallpierce
Copy link
Contributor Author

I think appveyor is stuck; is there a way to trigger new builds without pushing a bogus commit?

Copy link
Owner

@briansmith briansmith left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add the contributor's statement from https://github.com/briansmith/ring#contributing to the end of each commit. Also, please rebase the changes on top of the new changes in #378. (It may make sense to wait for #378 to land first).

src/der.rs Outdated

pub const CONSTRUCTED: u8 = 1 << 5;
pub const CONTEXT_SPECIFIC: u8 = 2 << 6;

/// An error in ASN1 parsing. Normal hygiene applies: if parsing secret
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should the “Normal hygiene applies...” comment. There's no API that we expose that applies to secret ASN.1 data being parsed anyway.

src/der.rs Outdated
/// An error in ASN1 parsing. Normal hygiene applies: if parsing secret
/// DER, do not differentiate this from any other error.
#[derive(Clone, Copy)]
pub struct ASN1Error;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think ASN1Error is fine even because I can't stand Asn1Error or similar capitalization of acronyms.

src/der.rs Outdated

pub const CONSTRUCTED: u8 = 1 << 5;
pub const CONTEXT_SPECIFIC: u8 = 2 << 6;

/// An error in ASN1 parsing. Normal hygiene applies: if parsing secret
/// DER, do not differentiate this from any other error.
#[derive(Clone, Copy)]
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we derive Debug as well?

src/der.rs Outdated

impl From<untrusted::EndOfInput> for ASN1Error {
fn from(_: untrusted::EndOfInput) -> Self { ASN1Error }
}
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this is correct. It is true that in this module, any time we encounter end-of-input, it's because of bad ASN.1. But, in generally it doesn't make sense to convert any or all EndOfInput errors to ASN1Error. Instead it has to be decided on a case-by-case basis.

Instead, we probably need to create wrapper functions around Reader::read_byte() and friends that map EndOfInput to ASN1Error, and use them here instead of using Input's methods directly.

@@ -117,26 +125,26 @@ fn nonnegative_integer<'a>(input: &mut untrusted::Reader<'a>, min_value: u8)

let value = try!(expect_tag_and_get_value(input, Tag::Integer));

value.read_all(error::Unspecified, |input| {
value.read_all(ASN1Error, |input| {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think all the errors returned by this function are ASN.1 decoding errors. Some of them are value-out-of-range errors. Since the point of this PR is to allow us to differentiate different kinds of errors, it seems like we should differentiate out-of-range vs. bad-DER. WDYT?

The end-goal of this specific PR is to make it possible to rebase the webpki crate on top of the new version of ring that has #378 integrated, right? Presumably, in the future we'll change some public APIs in ring to return more specific errors, by extending the changes in this PR, but that's not a goal of the present PR, right?

Or is the purpose different? The intended purpose matters as far as this review is concerned because (1) this change may not be necessary for rebasing webpki on top of #378 and/or (2) this PR may not be sufficient for solving the intended problem if it doesn't differentiate bad-DER from other kinds of errors.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since the point of this PR is to allow us to differentiate different kinds of errors, it seems like we should differentiate out-of-range vs. bad-DER. WDYT?

I would love to; the only reason I didn't do so was to hew more closely to the "expose as little as possible" goal. More on this below.

The end-goal of this specific PR is to make it possible to rebase the webpki crate on top of the new version of ring that has #378 integrated, right?

It would be possible, though a trifle code-smelly, to use this (plus #378) in webpki. The issue is the, ahem, approximate error handling like this, which is currently residing in #378:

            try!(der::expect_tag_and_get_value(input, der::Tag::Sequence)
                .map_err(|_| ParseSPKIError::BadDER)); 

It would be nice to not map Unspecified to BadDER just because it seems like that's probably what's going on... and sure enough, webpki has its own way of doing this:

#[inline(always)]
pub fn expect_tag_and_get_value<'a>(input: &mut untrusted::Reader<'a>,
                                    tag: Tag) ->
                                    Result<untrusted::Input<'a>, Error> {
    ring::der::expect_tag_and_get_value(input, tag).map_err(|_| Error::BadDER)
}

Mapping Unspecified to BadDER may be correct, but it doesn't feel very good.

Anyway, consider webpki's parse_spki_value:

fn parse_spki_value(input: untrusted::Input)
                    -> Result<SubjectPublicKeyInfo, Error> {
    input.read_all(Error::BadDER, |input| {
        let algorithm_id_value =
                try!(der::expect_tag_and_get_value(input, der::Tag::Sequence));
        let key_value = try!(der::bit_string_with_no_unused_bits(input));
...

In practice, the only Error variant this will return is BadDER. So, when webpki uses ring for its spki parsing needs and effectively replaces that function, it could quite neatly map ParseSPKIError::BadDER to Error::BadDER and call it a day, with or without a better breakdown of ASN.1 errors that would presumably all get mapped to ParseSPKIError::BadDER (maybe with a field in that variant to store which specific ASN1Error it was?).

In summary: no, I don't think we need more detailed errors to make it possible to use this in webpki. However, I wholeheartedly agree that it is not a very nice state of the world to report an value-out-of-bounds error the same way as an unexpected EOF, so I would happily make ASN1Error an enum with UnexpectedEOF, ValueOutOfBounds, etc variants if you're OK with that (or some other error scheme, though that's what came to mind). Based on your other comments, it sounds like parsing ASN.1 is not itself considered sensitive, so more detailed information about its parsing should not be a problem, and you know how much I love building to allow testability... :)

…ing errors, as per briansmith#379

I agree to license my contributions to each file under the terms given
at the top of each file I changed.
implementing From<untrusted::EndOfInput>. Also, other minor PR feedback.

I agree to license my contributions to each file under the terms given
at the top of each file I changed.
},
};

let inner = try!(input.skip_and_get_input(length));
let inner = try!(input.skip_and_get_input(length).map_err(|_| ASN1Error));
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There was only one usage of skip_and_get_input so I just mapped the error inline rather than with a wrapper function.

@coveralls
Copy link

coveralls commented Feb 13, 2017

Coverage Status

Coverage decreased (-0.006%) to 93.565% when pulling 66b8e6b on marshallpierce:more-specific-error-for-der into 191fcd2 on briansmith:master.

@coveralls
Copy link

coveralls commented Feb 13, 2017

Coverage Status

Coverage decreased (-0.006%) to 93.565% when pulling 66b8e6b on marshallpierce:more-specific-error-for-der into 191fcd2 on briansmith:master.

@briansmith
Copy link
Owner

@marshallpierce Only now have I had time to return to this. Are you interested in bringing this PR up to date? If so, I would be able to review and merge the updated PR right away.

FWIW, I have decided to start using the Asn1 vs. ASN1 capitalization like everybody else. I already modified RSA key loading to report more specific errors in 9968baa.

@marshallpierce
Copy link
Contributor Author

I'm interested, but pretty busy. I'll get to it but it might be months...

@briansmith
Copy link
Owner

Thanks @marshallpierce. I have a branch that does this that we can use instead. It was a mistake not to merge your PR before. Sorry!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants