summary refs log tree commit diff
path: root/crypto/src/asn1/ASN1StreamParser.cs
diff options
context:
space:
mode:
authorPeter Dettman <peter.dettman@bouncycastle.org>2021-11-11 19:13:58 +0700
committerPeter Dettman <peter.dettman@bouncycastle.org>2021-11-11 19:13:58 +0700
commit4c0a0bb815aa796c9765938434f756330663a76f (patch)
tree868a7018f8deb2df1c7773378cce6c0fc387d3e0 /crypto/src/asn1/ASN1StreamParser.cs
parentAdd DLTaggedObject and use from parser (diff)
downloadBouncyCastle.NET-ed25519-4c0a0bb815aa796c9765938434f756330663a76f.tar.xz
Improved parsing of tagged objects
Diffstat (limited to 'crypto/src/asn1/ASN1StreamParser.cs')
-rw-r--r--crypto/src/asn1/ASN1StreamParser.cs146
1 files changed, 78 insertions, 68 deletions
diff --git a/crypto/src/asn1/ASN1StreamParser.cs b/crypto/src/asn1/ASN1StreamParser.cs
index 55b5bc656..5c6854e1d 100644
--- a/crypto/src/asn1/ASN1StreamParser.cs
+++ b/crypto/src/asn1/ASN1StreamParser.cs
@@ -35,91 +35,102 @@ namespace Org.BouncyCastle.Asn1
             this.tmpBuffers = tmpBuffers;
         }
 
-        internal IAsn1Convertible ReadIndef(int tagValue)
+        internal IAsn1Convertible ReadIndef(int tagNo)
 		{
 			// Note: INDEF => CONSTRUCTED
 
 			// TODO There are other tags that may be constructed (e.g. BIT_STRING)
-			switch (tagValue)
+			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" + tagValue.ToString("X"));
+			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 tag)
+		internal IAsn1Convertible ReadImplicit(bool constructed, int tagNo)
 		{
 			if (_in is IndefiniteLengthInputStream)
 			{
 				if (!constructed)
 					throw new IOException("indefinite-length primitive encoding encountered");
 
-				return ReadIndef(tag);
+				return ReadIndef(tagNo);
 			}
 
 			if (constructed)
 			{
-				switch (tag)
+				switch (tagNo)
 				{
-					case Asn1Tags.Set:
-						return new DerSetParser(this);
-					case Asn1Tags.Sequence:
-						return new DerSequenceParser(this);
-					case Asn1Tags.OctetString:
-						return new BerOctetStringParser(this);
+				case Asn1Tags.Set:
+					return new DerSetParser(this);
+				case Asn1Tags.Sequence:
+					return new DerSequenceParser(this);
+				case Asn1Tags.OctetString:
+					return new BerOctetStringParser(this);
 				}
 			}
 			else
 			{
-				switch (tag)
+				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);
+				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(bool constructed, int tag)
+		internal Asn1Object ReadTaggedObject(int tagClass, int tagNo, bool constructed)
 		{
-			if (!constructed)
+            if (!constructed)
 			{
-				// Note: !CONSTRUCTED => IMPLICIT
-				DefiniteLengthInputStream defIn = (DefiniteLengthInputStream)_in;
-				return new DLTaggedObject(false, tag, new DerOctetString(defIn.ToArray()));
+                // Note: !CONSTRUCTED => IMPLICIT
+                DefiniteLengthInputStream defIn = (DefiniteLengthInputStream)_in;
+                byte[] contentsOctets = defIn.ToArray();
+
+                if (Asn1Tags.Application == tagClass)
+                    return new DerApplicationSpecific(false, tagNo, contentsOctets);
+
+                return new DLTaggedObject(false, tagNo, new DerOctetString(contentsOctets));
 			}
 
-			Asn1EncodableVector v = ReadVector();
+			Asn1EncodableVector contentsElements = ReadVector();
 
 			if (_in is IndefiniteLengthInputStream)
 			{
-				return v.Count == 1
-					?   new BerTaggedObject(true, tag, v[0])
-					:   new BerTaggedObject(false, tag, BerSequence.FromVector(v));
+                if (Asn1Tags.Application == tagClass)
+                    return new BerApplicationSpecific(tagNo, contentsElements);
+
+                return contentsElements.Count == 1
+					?   new BerTaggedObject(true, tagNo, contentsElements[0])
+					:   new BerTaggedObject(false, tagNo, BerSequence.FromVector(contentsElements));
 			}
 
-			return v.Count == 1
-				?   new DLTaggedObject(true, tag, v[0])
-				:   new DLTaggedObject(false, tag, DLSequence.FromVector(v));
+            if (Asn1Tags.Application == tagClass)
+                return new DerApplicationSpecific(tagNo, contentsElements);
+
+            return contentsElements.Count == 1
+				?   new DLTaggedObject(true, tagNo, contentsElements[0])
+				:   new DLTaggedObject(false, tagNo, DLSequence.FromVector(contentsElements));
 		}
 
 		public virtual IAsn1Convertible ReadObject()
 		{
-			int tag = _in.ReadByte();
-			if (tag == -1)
+			int tagHdr = _in.ReadByte();
+			if (tagHdr == -1)
 				return null;
 
 			// turn off looking for "00" while we resolve the tag
@@ -128,15 +139,16 @@ namespace Org.BouncyCastle.Asn1
 			//
 			// calculate tag number
 			//
-			int tagNo = Asn1InputStream.ReadTagNumber(_in, tag);
+			int tagNo = Asn1InputStream.ReadTagNumber(_in, tagHdr);
 
-			bool isConstructed = (tag & Asn1Tags.Constructed) != 0;
+			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.OctetString || tagNo == Asn1Tags.Sequence || tagNo == Asn1Tags.Set ||
+                tagNo == Asn1Tags.External);
 
 			if (length < 0) // indefinite-length method
 			{
@@ -146,13 +158,13 @@ namespace Org.BouncyCastle.Asn1
                 IndefiniteLengthInputStream indIn = new IndefiniteLengthInputStream(_in, _limit);
                 Asn1StreamParser sp = new Asn1StreamParser(indIn, _limit, tmpBuffers);
 
-                int tagClass = tag & Asn1Tags.Private;
+                int tagClass = tagHdr & Asn1Tags.Private;
                 if (0 != tagClass)
                 {
-                    if ((tag & Asn1Tags.Application) != 0)
+                    if (Asn1Tags.Application == tagClass)
                         return new BerApplicationSpecificParser(tagNo, sp);
 
-                    return new BerTaggedObjectParser(true, tagNo, sp);
+                    return new BerTaggedObjectParser(tagClass, tagNo, true, sp);
                 }
 
                 return sp.ReadIndef(tagNo);
@@ -161,14 +173,15 @@ namespace Org.BouncyCastle.Asn1
 			{
 				DefiniteLengthInputStream defIn = new DefiniteLengthInputStream(_in, length, _limit);
 
-                int tagClass = tag & Asn1Tags.Private;
+                int tagClass = tagHdr & Asn1Tags.Private;
                 if (0 != tagClass)
                 {
-                    if ((tag & Asn1Tags.Application) != 0)
-                        return new DerApplicationSpecific(isConstructed, tagNo, defIn.ToArray());
+                    Asn1StreamParser sub = new Asn1StreamParser(defIn, defIn.Remaining, tmpBuffers);
+
+                    if (Asn1Tags.Application == tagClass)
+                        return (DerApplicationSpecific)sub.ReadTaggedObject(tagClass, tagNo, isConstructed);
 
-                    return new BerTaggedObjectParser(isConstructed, tagNo,
-                        new Asn1StreamParser(defIn, defIn.Remaining, tmpBuffers));
+                    return new BerTaggedObjectParser(tagClass, tagNo, isConstructed, sub);
                 }
 
                 if (!isConstructed)
@@ -176,8 +189,8 @@ namespace Org.BouncyCastle.Asn1
                     // Some primitive encodings can be handled by parsers too...
                     switch (tagNo)
                     {
-                        case Asn1Tags.OctetString:
-                            return new DerOctetStringParser(defIn);
+                    case Asn1Tags.OctetString:
+                        return new DerOctetStringParser(defIn);
                     }
 
                     try
@@ -195,19 +208,16 @@ namespace Org.BouncyCastle.Asn1
                 // TODO There are other tags that may be constructed (e.g. BitString)
                 switch (tagNo)
 				{
-					case Asn1Tags.OctetString:
-						//
-						// yes, people actually do this...
-						//
-						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");
+				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");
                 }
 			}
 		}