summary refs log tree commit diff
path: root/crypto/src/asn1/ASN1StreamParser.cs
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/src/asn1/ASN1StreamParser.cs')
-rw-r--r--crypto/src/asn1/ASN1StreamParser.cs289
1 files changed, 159 insertions, 130 deletions
diff --git a/crypto/src/asn1/ASN1StreamParser.cs b/crypto/src/asn1/ASN1StreamParser.cs
index 51af50728..6128c9b78 100644
--- a/crypto/src/asn1/ASN1StreamParser.cs
+++ b/crypto/src/asn1/ASN1StreamParser.cs
@@ -35,105 +35,36 @@ namespace Org.BouncyCastle.Asn1
             this.tmpBuffers = tmpBuffers;
         }
 
-        internal IAsn1Convertible ReadIndef(int tagNo)
-		{
-			// Note: INDEF => CONSTRUCTED
-
-			// TODO There are other tags that may be constructed (e.g. BIT_STRING)
-			switch (tagNo)
-			{
-			case Asn1Tags.External:
-				return new DerExternalParser(this);
-			case Asn1Tags.OctetString:
-				return new BerOctetStringParser(this);
-			case Asn1Tags.Sequence:
-				return new BerSequenceParser(this);
-			case Asn1Tags.Set:
-				return new BerSetParser(this);
-			default:
-				throw new Asn1Exception("unknown BER object encountered: 0x" + tagNo.ToString("X"));
-			}
-		}
-
-		internal IAsn1Convertible ReadImplicit(bool constructed, int tagNo)
-		{
-			if (_in is IndefiniteLengthInputStream)
-			{
-				if (!constructed)
-					throw new IOException("indefinite-length primitive encoding encountered");
-
-				return ReadIndef(tagNo);
-			}
-
-			if (constructed)
-			{
-				switch (tagNo)
-				{
-				case Asn1Tags.Set:
-					return new DerSetParser(this);
-				case Asn1Tags.Sequence:
-					return new DerSequenceParser(this);
-				case Asn1Tags.OctetString:
-					return new BerOctetStringParser(this);
-				}
-			}
-			else
-			{
-				switch (tagNo)
-				{
-				case Asn1Tags.Set:
-					throw new Asn1Exception("sequences must use constructed encoding (see X.690 8.9.1/8.10.1)");
-				case Asn1Tags.Sequence:
-					throw new Asn1Exception("sets must use constructed encoding (see X.690 8.11.1/8.12.1)");
-				case Asn1Tags.OctetString:
-					return new DerOctetStringParser((DefiniteLengthInputStream)_in);
-				}
-			}
-
-			throw new Asn1Exception("implicit tagging not implemented");
-		}
-
-		internal Asn1Object ReadTaggedObject(int tagClass, int tagNo, bool constructed)
-		{
-            if (!constructed)
-			{
-                // Note: !CONSTRUCTED => IMPLICIT
-                byte[] contentsOctets = ((DefiniteLengthInputStream)_in).ToArray();
-                return Asn1TaggedObject.CreatePrimitive(tagClass, tagNo, contentsOctets);
-			}
-
-            bool isIL = (_in is IndefiniteLengthInputStream);
-            Asn1EncodableVector contentsElements = ReadVector();
-            return Asn1TaggedObject.CreateConstructed(tagClass, tagNo, isIL, contentsElements);
-		}
-
 		public virtual IAsn1Convertible ReadObject()
 		{
 			int tagHdr = _in.ReadByte();
-			if (tagHdr == -1)
+			if (tagHdr < 0)
 				return null;
 
-			// turn off looking for "00" while we resolve the tag
-			Set00Check(false);
+            return ImplParseObject(tagHdr);
+        }
+
+        internal IAsn1Convertible ImplParseObject(int tagHdr)
+        {
+            // turn off looking for "00" while we resolve the tag
+            Set00Check(false);
 
 			//
 			// calculate tag number
 			//
 			int tagNo = Asn1InputStream.ReadTagNumber(_in, tagHdr);
 
-			bool isConstructed = (tagHdr & Asn1Tags.Constructed) != 0;
-
 			//
 			// calculate length
 			//
 			int length = Asn1InputStream.ReadLength(_in, _limit,
-                tagNo == Asn1Tags.OctetString || tagNo == Asn1Tags.Sequence || tagNo == Asn1Tags.Set ||
-                tagNo == Asn1Tags.External);
+                tagNo == Asn1Tags.BitString || tagNo == Asn1Tags.OctetString || tagNo == Asn1Tags.Sequence ||
+                tagNo == Asn1Tags.Set || tagNo == Asn1Tags.External);
 
 			if (length < 0) // indefinite-length method
 			{
-				if (!isConstructed)
-					throw new IOException("indefinite-length primitive encoding encountered");
+                if (0 == (tagHdr & Asn1Tags.Constructed))
+                    throw new IOException("indefinite-length primitive encoding encountered");
 
                 IndefiniteLengthInputStream indIn = new IndefiniteLengthInputStream(_in, _limit);
                 Asn1StreamParser sp = new Asn1StreamParser(indIn, _limit, tmpBuffers);
@@ -144,86 +75,184 @@ namespace Org.BouncyCastle.Asn1
                     if (Asn1Tags.Application == tagClass)
                         return new BerApplicationSpecificParser(tagNo, sp);
 
-                    return new BerTaggedObjectParser(tagClass, tagNo, true, sp);
+                    return new BerTaggedObjectParser(tagClass, tagNo, sp);
                 }
 
-                return sp.ReadIndef(tagNo);
+                return sp.ParseImplicitConstructedIL(tagNo);
 			}
 			else
 			{
 				DefiniteLengthInputStream defIn = new DefiniteLengthInputStream(_in, length, _limit);
 
+                if (0 == (tagHdr & Asn1Tags.Flags))
+                    return ParseImplicitPrimitive(tagNo, defIn);
+
+                Asn1StreamParser sp = new Asn1StreamParser(defIn, defIn.Remaining, tmpBuffers);
+
                 int tagClass = tagHdr & Asn1Tags.Private;
                 if (0 != tagClass)
                 {
-                    Asn1StreamParser sub = new Asn1StreamParser(defIn, defIn.Remaining, tmpBuffers);
+                    bool isConstructed = (tagHdr & Asn1Tags.Constructed) != 0;
 
+                    // TODO[asn1] Special handling can be removed once ASN1ApplicationSpecific types removed.
                     if (Asn1Tags.Application == tagClass)
-                        return (DLApplicationSpecific)sub.ReadTaggedObject(tagClass, tagNo, isConstructed);
-
-                    return new BerTaggedObjectParser(tagClass, tagNo, isConstructed, sub);
-                }
-
-                if (!isConstructed)
-                {
-                    // Some primitive encodings can be handled by parsers too...
-                    switch (tagNo)
                     {
-                    case Asn1Tags.OctetString:
-                        return new DerOctetStringParser(defIn);
+                        // This cast is ensuring the current user-expected return type.
+                        return (DLApplicationSpecific)sp.LoadTaggedDL(tagClass, tagNo, isConstructed);
                     }
 
-                    try
-                    {
-                        return Asn1InputStream.CreatePrimitiveDerObject(tagNo, defIn, tmpBuffers);
-                    }
-                    catch (ArgumentException e)
-                    {
-                        throw new Asn1Exception("corrupted stream detected", e);
-                    }
+                    return new DLTaggedObjectParser(tagClass, tagNo, isConstructed, sp);
                 }
 
-                Asn1StreamParser sp = new Asn1StreamParser(defIn, defIn.Remaining, tmpBuffers);
-
-                // TODO There are other tags that may be constructed (e.g. BitString)
-                switch (tagNo)
-				{
-				case Asn1Tags.OctetString:
-					return new BerOctetStringParser(sp);
-				case Asn1Tags.Sequence:
-					return new DerSequenceParser(sp);
-				case Asn1Tags.Set:
-					return new DerSetParser(sp);
-				case Asn1Tags.External:
-					return new DerExternalParser(sp);
-				default:
-                    throw new IOException("unknown tag " + tagNo + " encountered");
-                }
+                return sp.ParseImplicitConstructedDL(tagNo);
 			}
 		}
 
-		private void Set00Check(
-			bool enabled)
-		{
-			if (_in is IndefiniteLengthInputStream)
-			{
-				((IndefiniteLengthInputStream) _in).SetEofOn00(enabled);
-			}
-		}
+        internal Asn1Object LoadTaggedDL(int tagClass, int tagNo, bool constructed)
+        {
+            if (!constructed)
+            {
+                byte[] contentsOctets = ((DefiniteLengthInputStream)_in).ToArray();
+                return Asn1TaggedObject.CreatePrimitive(tagClass, tagNo, contentsOctets);
+            }
+
+            Asn1EncodableVector contentsElements = ReadVector();
+            return Asn1TaggedObject.CreateConstructedDL(tagClass, tagNo, contentsElements);
+        }
+
+        internal Asn1Object LoadTaggedIL(int tagClass, int tagNo)
+        {
+            Asn1EncodableVector contentsElements = ReadVector();
+            return Asn1TaggedObject.CreateConstructedIL(tagClass, tagNo, contentsElements);
+        }
+
+        internal IAsn1Convertible ParseImplicitConstructedDL(int univTagNo)
+        {
+            switch (univTagNo)
+            {
+            // TODO[asn1] DLConstructedBitStringParser
+            //case Asn1Tags.BitString:
+            //    return new BerBitStringParser(this);
+            case Asn1Tags.External:
+                return new DerExternalParser(this);
+            case Asn1Tags.OctetString:
+                // TODO[asn1] DLConstructedOctetStringParser
+                return new BerOctetStringParser(this);
+            case Asn1Tags.Set:
+                return new DerSetParser(this);
+            case Asn1Tags.Sequence:
+                return new DerSequenceParser(this);
+            default:
+				throw new Asn1Exception("unknown DL object encountered: 0x" + univTagNo.ToString("X"));
+            }
+        }
+
+        internal IAsn1Convertible ParseImplicitConstructedIL(int univTagNo)
+        {
+            switch (univTagNo)
+            {
+            // TODO[asn1] BerBitStringParser
+            //case Asn1Tags.BitString:
+            //    return new BerBitStringParser(this);
+            case Asn1Tags.External:
+                // TODO[asn1] BERExternalParser
+                return new DerExternalParser(this);
+            case Asn1Tags.OctetString:
+                return new BerOctetStringParser(this);
+            case Asn1Tags.Sequence:
+                return new BerSequenceParser(this);
+            case Asn1Tags.Set:
+                return new BerSetParser(this);
+            default:
+                throw new Asn1Exception("unknown BER object encountered: 0x" + univTagNo.ToString("X"));
+            }
+        }
+
+        internal IAsn1Convertible ParseImplicitPrimitive(int univTagNo)
+        {
+            return ParseImplicitPrimitive(univTagNo, (DefiniteLengthInputStream)_in);
+        }
 
+        internal IAsn1Convertible ParseImplicitPrimitive(int univTagNo, DefiniteLengthInputStream defIn)
+        {
+            // Some primitive encodings can be handled by parsers too...
+            switch (univTagNo)
+            {
+            // TODO[asn1] DLBitStringParser
+            //case Asn1Tags.BitString:
+            //    return new DLBitStringParser(defIn);
+            case Asn1Tags.External:
+                throw new Asn1Exception("externals must use constructed encoding (see X.690 8.18)");
+            case Asn1Tags.OctetString:
+                return new DerOctetStringParser(defIn);
+			case Asn1Tags.Set:
+				throw new Asn1Exception("sequences must use constructed encoding (see X.690 8.9.1/8.10.1)");
+			case Asn1Tags.Sequence:
+				throw new Asn1Exception("sets must use constructed encoding (see X.690 8.11.1/8.12.1)");
+            }
+
+            try
+            {
+                return Asn1InputStream.CreatePrimitiveDerObject(univTagNo, defIn, tmpBuffers);
+            }
+            catch (ArgumentException e)
+            {
+                throw new Asn1Exception("corrupted stream detected", e);
+            }
+        }
+
+        internal IAsn1Convertible ParseObject(int univTagNo)
+        {
+            if (univTagNo < 0 || univTagNo > 30)
+                throw new ArgumentException("invalid universal tag number: " + univTagNo, "univTagNo");
+
+            int tagHdr = _in.ReadByte();
+            if (tagHdr < 0)
+                return null;
+
+            if ((tagHdr & ~Asn1Tags.Constructed) != univTagNo)
+                throw new IOException("unexpected identifier encountered: " + tagHdr);
+
+            return ImplParseObject(tagHdr);
+        }
+
+        internal Asn1TaggedObjectParser ParseTaggedObject()
+        {
+            int tagHdr = _in.ReadByte();
+            if (tagHdr< 0)
+                return null;
+
+            int tagClass = tagHdr & Asn1Tags.Private;
+            if (0 == tagClass)
+                throw new Asn1Exception("no tagged object found");
+
+            return (Asn1TaggedObjectParser)ImplParseObject(tagHdr);
+        }
+
+        // TODO[asn1] Prefer 'LoadVector'
         internal Asn1EncodableVector ReadVector()
         {
-            IAsn1Convertible obj = ReadObject();
-            if (null == obj)
+            int tagHdr = _in.ReadByte();
+            if (tagHdr < 0)
                 return new Asn1EncodableVector(0);
 
             Asn1EncodableVector v = new Asn1EncodableVector();
             do
             {
+                IAsn1Convertible obj = ImplParseObject(tagHdr);
+
                 v.Add(obj.ToAsn1Object());
             }
-            while ((obj = ReadObject()) != null);
+            while ((tagHdr = _in.ReadByte()) >= 0);
             return v;
         }
+
+		private void Set00Check(bool enabled)
+		{
+			if (_in is IndefiniteLengthInputStream)
+			{
+				((IndefiniteLengthInputStream)_in).SetEofOn00(enabled);
+			}
+		}
 	}
 }