summary refs log tree commit diff
path: root/crypto/src/asn1
diff options
context:
space:
mode:
authorPeter Dettman <peter.dettman@bouncycastle.org>2021-10-15 01:18:46 +0700
committerPeter Dettman <peter.dettman@bouncycastle.org>2021-10-15 01:18:46 +0700
commitd3fd5f9580f7f9d5f2d63f86e8e08d22ad18654c (patch)
treeae679455ccc8aae2c64a0a23823b1a7ee9f12469 /crypto/src/asn1
parentAdd utility methods (diff)
downloadBouncyCastle.NET-ed25519-d3fd5f9580f7f9d5f2d63f86e8e08d22ad18654c.tar.xz
ASN1InputStream updates from bc-java
- improve tag validation
- improve handling of long form definite-length
Diffstat (limited to 'crypto/src/asn1')
-rw-r--r--crypto/src/asn1/Asn1InputStream.cs79
1 files changed, 46 insertions, 33 deletions
diff --git a/crypto/src/asn1/Asn1InputStream.cs b/crypto/src/asn1/Asn1InputStream.cs
index 1791e5356..6bb6311e1 100644
--- a/crypto/src/asn1/Asn1InputStream.cs
+++ b/crypto/src/asn1/Asn1InputStream.cs
@@ -242,9 +242,7 @@ namespace Org.BouncyCastle.Asn1
             get { return limit; }
         }
 
-        internal static int ReadTagNumber(
-            Stream	s,
-            int		tag)
+        internal static int ReadTagNumber(Stream s, int tag)
         {
             int tagNo = tag & 0x1f;
 
@@ -256,23 +254,32 @@ namespace Org.BouncyCastle.Asn1
                 tagNo = 0;
 
                 int b = s.ReadByte();
+                if (b < 31)
+                {
+                    if (b < 0)
+                        throw new EndOfStreamException("EOF found inside tag value.");
+
+                    throw new IOException("corrupted stream - high tag number < 31 found");
+                }
 
                 // X.690-0207 8.1.2.4.2
                 // "c) bits 7 to 1 of the first subsequent octet shall not all be zero."
-                if ((b & 0x7f) == 0) // Note: -1 will pass
+                if ((b & 0x7f) == 0)
                     throw new IOException("corrupted stream - invalid high tag number found");
 
-                while ((b >= 0) && ((b & 0x80) != 0))
+                while ((b & 0x80) != 0)
                 {
-                    tagNo |= (b & 0x7f);
+                    if (((uint)tagNo >> 24) != 0U)
+                        throw new IOException("Tag number more than 31 bits");
+
+                    tagNo |= b & 0x7f;
                     tagNo <<= 7;
                     b = s.ReadByte();
+                    if (b < 0)
+                        throw new EndOfStreamException("EOF found inside tag value.");
                 }
 
-                if (b < 0)
-                    throw new EndOfStreamException("EOF found inside tag value.");
-
-                tagNo |= (b & 0x7f);
+                tagNo |= b & 0x7f;
             }
 
             return tagNo;
@@ -281,37 +288,43 @@ namespace Org.BouncyCastle.Asn1
         internal static int ReadLength(Stream s, int limit, bool isParsing)
         {
             int length = s.ReadByte();
+            if (0U == ((uint)length >> 7))
+            {
+                // definite-length short form 
+                return length;
+            }
+            if (0x80 == length)
+            {
+                // indefinite-length
+                return -1;
+            }
             if (length < 0)
+            {
                 throw new EndOfStreamException("EOF found when length expected");
-
-            if (length == 0x80)
-                return -1;      // indefinite-length encoding
-
-            if (length > 127)
+            }
+            if (0xFF == length)
             {
-                int size = length & 0x7f;
-
-                // Note: The invalid long form "0xff" (see X.690 8.1.3.5c) will be caught here
-                if (size > 4)
-                    throw new IOException("DER length more than 4 bytes: " + size);
-
-                length = 0;
-                for (int i = 0; i < size; i++)
-                {
-                    int next = s.ReadByte();
+                throw new IOException("invalid long form definite-length 0xFF");
+            }
 
-                    if (next < 0)
-                        throw new EndOfStreamException("EOF found reading length");
+            int octetsCount = length & 0x7F, octetsPos = 0;
 
-                    length = (length << 8) + next;
-                }
+            length = 0;
+            do
+            {
+                int octet = s.ReadByte();
+                if (octet < 0)
+                    throw new EndOfStreamException("EOF found reading length");
 
-                if (length < 0)
-                    throw new IOException("corrupted stream - negative length found");
+                if (((uint)length >> 23) != 0U)
+                    throw new IOException("long form definite-length more than 31 bits");
 
-                if (length >= limit && !isParsing)   // after all we must have read at least 1 byte
-                    throw new IOException("corrupted stream - out of bounds length found: " + length + " >= " + limit);
+                length = (length << 8) + octet;
             }
+            while (++octetsPos < octetsCount);
+
+            if (length >= limit && !isParsing)   // after all we must have read at least 1 byte
+                throw new IOException("corrupted stream - out of bounds length found: " + length + " >= " + limit);
 
             return length;
         }