diff --git a/src/der.rs b/src/der.rs index 46354a03cf..debeac15a6 100644 --- a/src/der.rs +++ b/src/der.rs @@ -17,11 +17,14 @@ //! This module contains the foundational parts of an ASN.1 DER parser. use untrusted; -use error; pub const CONSTRUCTED: u8 = 1 << 5; pub const CONTEXT_SPECIFIC: u8 = 2 << 6; +/// An error in ASN1 parsing. +#[derive(Clone, Copy, Debug)] +pub struct ASN1Error; + #[derive(Clone, Copy, PartialEq)] #[repr(u8)] pub enum Tag { @@ -43,49 +46,49 @@ pub enum Tag { pub fn expect_tag_and_get_value<'a>(input: &mut untrusted::Reader<'a>, tag: Tag) -> Result, - error::Unspecified> { + ASN1Error> { let (actual_tag, inner) = try!(read_tag_and_get_value(input)); if (tag as usize) != (actual_tag as usize) { - return Err(error::Unspecified); + return Err(ASN1Error); } Ok(inner) } pub fn read_tag_and_get_value<'a>(input: &mut untrusted::Reader<'a>) -> Result<(u8, untrusted::Input<'a>), - error::Unspecified> { - let tag = try!(input.read_byte()); + ASN1Error> { + let tag = try!(read_expected_byte(input)); if (tag & 0x1F) == 0x1F { - return Err(error::Unspecified); // High tag number form is not allowed. + return Err(ASN1Error); // High tag number form is not allowed. } // If the high order bit of the first byte is set to zero then the length // is encoded in the seven remaining bits of that byte. Otherwise, those // seven bits represent the number of bytes used to encode the length. - let length = match try!(input.read_byte()) { + let length = match try!(read_expected_byte(input)) { n if (n & 0x80) == 0 => n as usize, 0x81 => { - let second_byte = try!(input.read_byte()); + let second_byte = try!(read_expected_byte(input)); if second_byte < 128 { - return Err(error::Unspecified); // Not the canonical encoding. + return Err(ASN1Error); // Not the canonical encoding. } second_byte as usize }, 0x82 => { - let second_byte = try!(input.read_byte()) as usize; - let third_byte = try!(input.read_byte()) as usize; + let second_byte = try!(read_expected_byte(input)) as usize; + let third_byte = try!(read_expected_byte(input)) as usize; let combined = (second_byte << 8) | third_byte; if combined < 256 { - return Err(error::Unspecified); // Not the canonical encoding. + return Err(ASN1Error); // Not the canonical encoding. } combined }, _ => { - return Err(error::Unspecified); // We don't support longer lengths. + return Err(ASN1Error); // We don't support longer lengths. }, }; - let inner = try!(input.skip_and_get_input(length)); + let inner = try!(input.skip_and_get_input(length).map_err(|_| ASN1Error)); Ok((tag, inner)) } @@ -100,15 +103,15 @@ pub fn nested<'a, F, R, E: Copy>(input: &mut untrusted::Reader<'a>, tag: Tag, } fn nonnegative_integer<'a>(input: &mut untrusted::Reader<'a>, min_value: u8) - -> Result, error::Unspecified> { + -> Result, ASN1Error> { // Verify that |input|, which has had any leading zero stripped off, is the // encoding of a value of at least |min_value|. fn check_minimum(input: untrusted::Input, min_value: u8) - -> Result<(), error::Unspecified> { - input.read_all(error::Unspecified, |input| { - let first_byte = try!(input.read_byte()); + -> Result<(), ASN1Error> { + input.read_all(ASN1Error, |input| { + let first_byte = try!(read_expected_byte(input)); if input.at_end() && first_byte < min_value { - return Err(error::Unspecified); + return Err(ASN1Error); } let _ = input.skip_to_end(); Ok(()) @@ -117,26 +120,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| { // Empty encodings are not allowed. - let first_byte = try!(input.read_byte()); + let first_byte = try!(read_expected_byte(input)); if first_byte == 0 { if input.at_end() { // |value| is the legal encoding of zero. if min_value > 0 { - return Err(error::Unspecified); + return Err(ASN1Error); } return Ok(value); } let r = input.skip_to_end(); - try!(r.read_all(error::Unspecified, |input| { - let second_byte = try!(input.read_byte()); + try!(r.read_all(ASN1Error, |input| { + let second_byte = try!(read_expected_byte(input)); if (second_byte & 0x80) == 0 { // A leading zero is only allowed when the value's high bit // is set. - return Err(error::Unspecified); + return Err(ASN1Error); } let _ = input.skip_to_end(); Ok(()) @@ -147,7 +150,7 @@ fn nonnegative_integer<'a>(input: &mut untrusted::Reader<'a>, min_value: u8) // Negative values are not allowed. if (first_byte & 0x80) != 0 { - return Err(error::Unspecified); + return Err(ASN1Error); } let _ = input.skip_to_end(); @@ -160,10 +163,10 @@ fn nonnegative_integer<'a>(input: &mut untrusted::Reader<'a>, min_value: u8) /// numeric value. This is typically used for parsing version numbers. #[inline] pub fn small_nonnegative_integer(input: &mut untrusted::Reader) - -> Result { + -> Result { let value = try!(nonnegative_integer(input, 0)); - value.read_all(error::Unspecified, |input| { - let r = try!(input.read_byte()); + value.read_all(ASN1Error, |input| { + let r = try!(read_expected_byte(input)); Ok(r) }) } @@ -172,28 +175,32 @@ pub fn small_nonnegative_integer(input: &mut untrusted::Reader) /// any leading zero byte. #[inline] pub fn positive_integer<'a>(input: &mut untrusted::Reader<'a>) - -> Result, error::Unspecified> { + -> Result, ASN1Error> { nonnegative_integer(input, 1) } +/// Maps EOF to ASN1Error as a convenience when EOF is not expected. +fn read_expected_byte<'a>(input: &mut untrusted::Reader<'a>) + -> Result{ + input.read_byte().map_err(|_| ASN1Error) +} #[cfg(test)] mod tests { - use error; use super::*; use untrusted; fn with_good_i(value: &[u8], f: F) where F: FnOnce(&mut untrusted::Reader) - -> Result { - let r = untrusted::Input::from(value).read_all(error::Unspecified, f); + -> Result { + let r = untrusted::Input::from(value).read_all(ASN1Error, f); assert!(r.is_ok()); } fn with_bad_i(value: &[u8], f: F) where F: FnOnce(&mut untrusted::Reader) - -> Result { - let r = untrusted::Input::from(value).read_all(error::Unspecified, f); + -> Result { + let r = untrusted::Input::from(value).read_all(ASN1Error, f); assert!(r.is_err()); } diff --git a/src/ec/suite_b/ops/ops.rs b/src/ec/suite_b/ops/ops.rs index f31f1d1b7b..021de88182 100644 --- a/src/ec/suite_b/ops/ops.rs +++ b/src/ec/suite_b/ops/ops.rs @@ -338,7 +338,7 @@ pub struct PublicScalarOps { impl PublicScalarOps { pub fn scalar_parse(&self, input: &mut untrusted::Reader) -> Result { - let encoded_value = try!(der::positive_integer(input)); + let encoded_value = try!(der::positive_integer(input).map_err(|_| error::Unspecified)); let limbs = try!(parse_big_endian_value_in_range( encoded_value, 1, &self.public_key_ops.common.n.limbs[ diff --git a/src/rsa/bigint.rs b/src/rsa/bigint.rs index 547de2b550..33aa3bb04a 100644 --- a/src/rsa/bigint.rs +++ b/src/rsa/bigint.rs @@ -88,7 +88,7 @@ impl Positive { // Parses a single ASN.1 DER-encoded `Integer`, which most be positive. pub fn from_der(input: &mut untrusted::Reader) -> Result { - Self::from_be_bytes(try!(der::positive_integer(input))) + Self::from_be_bytes(try!(der::positive_integer(input).map_err(|_| error::Unspecified))) } // Turns a sequence of big-endian bytes into a Positive Integer. diff --git a/src/rsa/rsa.rs b/src/rsa/rsa.rs index 3374a81cce..c74ab8c2e6 100644 --- a/src/rsa/rsa.rs +++ b/src/rsa/rsa.rs @@ -57,8 +57,8 @@ fn parse_public_key(input: untrusted::Input) error::Unspecified> { input.read_all(error::Unspecified, |input| { der::nested(input, der::Tag::Sequence, error::Unspecified, |input| { - let n = try!(der::positive_integer(input)); - let e = try!(der::positive_integer(input)); + let n = try!(der::positive_integer(input).map_err(|_| error::Unspecified)); + let e = try!(der::positive_integer(input).map_err(|_| error::Unspecified)); Ok((n, e)) }) }) diff --git a/src/rsa/signing.rs b/src/rsa/signing.rs index a1b6b7dfaa..a18f363dce 100644 --- a/src/rsa/signing.rs +++ b/src/rsa/signing.rs @@ -84,7 +84,8 @@ impl RSAKeyPair { -> Result { input.read_all(error::Unspecified, |input| { der::nested(input, der::Tag::Sequence, error::Unspecified, |input| { - let version = try!(der::small_nonnegative_integer(input)); + let version = try!(der::small_nonnegative_integer(input) + .map_err(|_| error::Unspecified)); if version != 0 { return Err(error::Unspecified); } diff --git a/src/rsa/verification.rs b/src/rsa/verification.rs index 8da3f5fa53..c33f85ad03 100644 --- a/src/rsa/verification.rs +++ b/src/rsa/verification.rs @@ -154,7 +154,7 @@ pub fn verify_rsa(params: &RSAParameters, mod tests { // We intentionally avoid `use super::*` so that we are sure to use only // the public API; this ensures that enough of the API is public. - use {der, error, signature, test}; + use {der, signature, test}; use untrusted; #[test] @@ -178,8 +178,8 @@ mod tests { // Sanity check that we correctly DER-encoded the originally- // provided separate (n, e) components. When we add test vectors // for improperly-encoded signatures, we'll have to revisit this. - assert!(public_key.read_all(error::Unspecified, |input| { - der::nested(input, der::Tag::Sequence, error::Unspecified, + assert!(public_key.read_all(der::ASN1Error, |input| { + der::nested(input, der::Tag::Sequence, der::ASN1Error, |input| { let _ = try!(der::positive_integer(input)); let _ = try!(der::positive_integer(input)); @@ -222,8 +222,8 @@ mod tests { // Sanity check that we correctly DER-encoded the originally- // provided separate (n, e) components. When we add test vectors // for improperly-encoded signatures, we'll have to revisit this. - assert!(public_key.read_all(error::Unspecified, |input| { - der::nested(input, der::Tag::Sequence, error::Unspecified, + assert!(public_key.read_all(der::ASN1Error, |input| { + der::nested(input, der::Tag::Sequence, der::ASN1Error, |input| { let _ = try!(der::positive_integer(input)); let _ = try!(der::positive_integer(input));