Repository: alex/rust-asn1 (language: rust)

Issue:
Support longer TLVs
In #318 we shortened supported TLVs to 65535, which turns out to have been a bad idea due to large CRLs (see https://github.com/pyca/cryptography/issues/7574). We should increase the length limit -- 3 bytes is probably a reasonable next length to try 😄 Traditionally I've assumed the Apple WWDRCA has the largest CRL, but looking at a recent cert it appears they've dropped CRL entirely so I'm not sure what the largest in-the-wild CRL is now. If we assume ~20 bytes per cert 2**24 would give us over 800k CRL entries, which will hopefully be enough.


Discussion / hints:

Fix patch:
diff --git a/Cargo.toml b/Cargo.toml
index e21ca2e..63ba655 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "asn1"
-version = "0.12.1"
+version = "0.12.2"
 authors = ["Alex Gaynor <alex.gaynor@gmail.com>"]
 repository = "https://github.com/alex/rust-asn1"
 keywords = ["asn1"]
@@ -17,7 +17,7 @@ derive = ["asn1_derive"]
 
 [dependencies]
 chrono = { version = "0.4.20", default-features = false, features = ["alloc"] }
-asn1_derive = { path = "asn1_derive/", version = "0.12.1", optional = true }
+asn1_derive = { path = "asn1_derive/", version = "0.12.2", optional = true }
 
 [dev-dependencies]
 libc = "0.2.11"
diff --git a/asn1_derive/Cargo.toml b/asn1_derive/Cargo.toml
index 7d5c558..beebbf4 100644
--- a/asn1_derive/Cargo.toml
+++ b/asn1_derive/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "asn1_derive"
-version = "0.12.1"
+version = "0.12.2"
 authors = ["Alex Gaynor <alex.gaynor@gmail.com>"]
 repository = "https://github.com/alex/rust-asn1"
 license = "BSD-3-Clause"
diff --git a/src/parser.rs b/src/parser.rs
index 282a602..df7980e 100644
--- a/src/parser.rs
+++ b/src/parser.rs
@@ -10,7 +10,7 @@ pub enum ParseErrorKind {
     /// not a tag's value being unexpected.
     InvalidTag,
     /// Something about the length was invalid. This can mean either a invalid
-    /// encoding, or that a TLV was longer than 65535, which is the maximum
+    /// encoding, or that a TLV was longer than 4GB, which is the maximum
     /// length that rust-asn1 supports.
     InvalidLength,
     /// An unexpected tag was encountered.
@@ -226,6 +226,27 @@ impl<'a> Parser<'a> {
                 }
                 Ok(length)
             }
+            0x83 => {
+                let length = usize::from(self.read_u8()?) << 16
+                    | usize::from(self.read_u8()?) << 8
+                    | usize::from(self.read_u8()?);
+                // Same thing as the 0x82 case
+                if length < 0x10000 {
+                    return Err(ParseError::new(ParseErrorKind::InvalidLength));
+                }
+                Ok(length)
+            }
+            0x84 => {
+                let length = usize::from(self.read_u8()?) << 24
+                    | usize::from(self.read_u8()?) << 16
+                    | usize::from(self.read_u8()?) << 8
+                    | usize::from(self.read_u8()?);
+                // Same thing as the 0x82 case
+                if length < 0x1000000 {
+                    return Err(ParseError::new(ParseErrorKind::InvalidLength));
+                }
+                Ok(length)
+            }
             // We only support two-byte lengths
             _ => Err(ParseError::new(ParseErrorKind::InvalidLength)),
         }
@@ -618,6 +639,9 @@ mod tests {
 
     #[test]
     fn test_parse_octet_string() {
+        let long_value = vec![b'a'; 70_000];
+        let really_long_value = vec![b'a'; 20_000_000];
+
         assert_parses::<&[u8]>(&[
             (Ok(b""), b"\x04\x00"),
             (Ok(b"\x01\x02\x03"), b"\x04\x03\x01\x02\x03"),
@@ -625,6 +649,14 @@ mod tests {
                 Ok(b"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"),
                 b"\x04\x81\x81aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
             ),
+            (
+                Ok(long_value.as_slice()),
+                [b"\x04\x83\x01\x11\x70", long_value.as_slice()].concat().as_slice()
+            ),
+            (
+                Ok(really_long_value.as_slice()),
+                [b"\x04\x84\x01\x31\x2d\x00", really_long_value.as_slice()].concat().as_slice()
+            ),
             (Err(ParseError::new(ParseErrorKind::InvalidLength)), b"\x04\x80"),
             (Err(ParseError::new(ParseErrorKind::InvalidLength)), b"\x04\x81\x00"),
             (Err(ParseError::new(ParseErrorKind::InvalidLength)), b"\x04\x81\x01\x09"),
@@ -635,6 +667,10 @@ mod tests {
             ),
             (Err(ParseError::new(ParseErrorKind::ShortData)), b"\x04\x03\x01\x02"),
             (Err(ParseError::new(ParseErrorKind::ShortData)), b"\x04\x82\xff\xff\xff\xff\xff\xff"),
+            // 3 byte length form with leading 0.
+            (Err(ParseError::new(ParseErrorKind::InvalidLength)), b"\x04\x83\x00\xff\xff"),
+            // 4 byte length form with leading 0.
+            (Err(ParseError::new(ParseErrorKind::InvalidLength)), b"\x04\x84\x00\xff\xff\xff"),
         ]);
     }
 


Test patch: