summary refs log tree commit diff
path: root/crypto/src/asn1/Asn1InputStream.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/Asn1InputStream.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/Asn1InputStream.cs')
-rw-r--r--crypto/src/asn1/Asn1InputStream.cs180
1 files changed, 90 insertions, 90 deletions
diff --git a/crypto/src/asn1/Asn1InputStream.cs b/crypto/src/asn1/Asn1InputStream.cs
index 27c583338..6e097e86d 100644
--- a/crypto/src/asn1/Asn1InputStream.cs
+++ b/crypto/src/asn1/Asn1InputStream.cs
@@ -1,5 +1,4 @@
 using System;
-using System.Diagnostics;
 using System.IO;
 
 using Org.BouncyCastle.Utilities;
@@ -74,23 +73,15 @@ namespace Org.BouncyCastle.Asn1
         /**
         * build an object given its tag and the number of bytes to construct it from.
         */
-        private Asn1Object BuildObject(
-            int	tag,
-            int	tagNo,
-            int	length)
+        private Asn1Object BuildObject(int tagHdr, int tagNo, int length)
         {
-            bool isConstructed = (tag & Asn1Tags.Constructed) != 0;
+            bool isConstructed = (tagHdr & Asn1Tags.Constructed) != 0;
 
             DefiniteLengthInputStream defIn = new DefiniteLengthInputStream(this, 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());
-
-                return new Asn1StreamParser(defIn, defIn.Remaining, tmpBuffers).ReadTaggedObject(isConstructed, tagNo);
-            }
+                return ReadTaggedObject(tagClass, tagNo, isConstructed, defIn);
 
             if (!isConstructed)
                 return CreatePrimitiveDerObject(tagNo, defIn, tmpBuffers);
@@ -98,16 +89,9 @@ namespace Org.BouncyCastle.Asn1
             switch (tagNo)
             {
             case Asn1Tags.BitString:
-            {
                 return BuildConstructedBitString(ReadVector(defIn));
-            }
             case Asn1Tags.OctetString:
-            {
-                //
-                // yes, people actually do this...
-                //
                 return BuildConstructedOctetString(ReadVector(defIn));
-            }
             case Asn1Tags.Sequence:
                 return CreateDLSequence(defIn);
             case Asn1Tags.Set:
@@ -119,6 +103,29 @@ namespace Org.BouncyCastle.Asn1
             }
         }
 
+        internal Asn1Object ReadTaggedObject(int tagClass, int tagNo, bool constructed, DefiniteLengthInputStream defIn)
+        {
+            if (!constructed)
+            {
+                // Note: !CONSTRUCTED => IMPLICIT
+                byte[] contentsOctets = defIn.ToArray();
+
+                if (Asn1Tags.Application == tagClass)
+                    return new DerApplicationSpecific(false, tagNo, contentsOctets);
+
+                return new DLTaggedObject(false, tagNo, new DerOctetString(contentsOctets));
+            }
+
+            Asn1EncodableVector contentsElements = ReadVector(defIn);
+
+            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));
+        }
+
         internal virtual Asn1EncodableVector ReadVector()
         {
             Asn1Object o = ReadObject();
@@ -155,16 +162,16 @@ namespace Org.BouncyCastle.Asn1
 
         public Asn1Object ReadObject()
         {
-            int tag = ReadByte();
-            if (tag <= 0)
+            int tagHdr = ReadByte();
+            if (tagHdr <= 0)
             {
-                if (tag == 0)
+                if (tagHdr == 0)
                     throw new IOException("unexpected end-of-contents marker");
 
                 return null;
             }
 
-            int tagNo = ReadTagNumber(this, tag);
+            int tagNo = ReadTagNumber(this, tagHdr);
             int length = ReadLength(this, limit, false);
 
             if (length >= 0)
@@ -172,7 +179,7 @@ namespace Org.BouncyCastle.Asn1
                 // definite-length
                 try
                 {
-                    return BuildObject(tag, tagNo, length);
+                    return BuildObject(tagHdr, tagNo, length);
                 }
                 catch (ArgumentException e)
                 {
@@ -182,20 +189,15 @@ namespace Org.BouncyCastle.Asn1
 
             // indefinite-length
 
-            if (0 == (tag & Asn1Tags.Constructed))
+            if (0 == (tagHdr & Asn1Tags.Constructed))
                 throw new IOException("indefinite-length primitive encoding encountered");
 
             IndefiniteLengthInputStream indIn = new IndefiniteLengthInputStream(this, 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)
-                    return new BerApplicationSpecificParser(tagNo, sp).ToAsn1Object();
-
-                return new BerTaggedObjectParser(true, tagNo, sp).ToAsn1Object();
-            }
+                return sp.ReadTaggedObject(tagClass, tagNo, true);
 
             // TODO There are other tags that may be constructed (e.g. BitString)
             switch (tagNo)
@@ -254,9 +256,9 @@ namespace Org.BouncyCastle.Asn1
             get { return limit; }
         }
 
-        internal static int ReadTagNumber(Stream s, int tag)
+        internal static int ReadTagNumber(Stream s, int tagHdr)
         {
-            int tagNo = tag & 0x1f;
+            int tagNo = tagHdr & 0x1f;
 
             //
             // with tagged object tag number is bottom 5 bits, or stored at the start of the content
@@ -403,71 +405,69 @@ namespace Org.BouncyCastle.Asn1
             return str;
         }
 
-        internal static Asn1Object CreatePrimitiveDerObject(
-            int                         tagNo,
-            DefiniteLengthInputStream   defIn,
-            byte[][]                    tmpBuffers)
+        internal static Asn1Object CreatePrimitiveDerObject(int tagNo, DefiniteLengthInputStream defIn,
+            byte[][] tmpBuffers)
         {
             switch (tagNo)
             {
-                case Asn1Tags.BmpString:
-                    return new DerBmpString(GetBmpCharBuffer(defIn));
-                case Asn1Tags.Boolean:
-                    return DerBoolean.FromOctetString(GetBuffer(defIn, tmpBuffers));
-                case Asn1Tags.Enumerated:
-                    return DerEnumerated.FromOctetString(GetBuffer(defIn, tmpBuffers));
-                case Asn1Tags.ObjectIdentifier:
-                    // TODO Ideally only clone if we used a buffer
-                    return DerObjectIdentifier.CreatePrimitive(GetBuffer(defIn, tmpBuffers), true);
+            case Asn1Tags.BmpString:
+                return new DerBmpString(GetBmpCharBuffer(defIn));
+            case Asn1Tags.Boolean:
+                return DerBoolean.FromOctetString(GetBuffer(defIn, tmpBuffers));
+            case Asn1Tags.Enumerated:
+                return DerEnumerated.FromOctetString(GetBuffer(defIn, tmpBuffers));
+            case Asn1Tags.ObjectIdentifier:
+                // TODO Ideally only clone if we used a buffer
+                return DerObjectIdentifier.CreatePrimitive(GetBuffer(defIn, tmpBuffers), true);
             }
 
             byte[] bytes = defIn.ToArray();
 
             switch (tagNo)
             {
-                case Asn1Tags.BitString:
-                    return DerBitString.CreatePrimitive(bytes);
-                case Asn1Tags.GeneralizedTime:
-                    return new DerGeneralizedTime(bytes);
-                case Asn1Tags.GeneralString:
-                    return new DerGeneralString(bytes);
-                case Asn1Tags.GraphicString:
-                    return DerGraphicString.CreatePrimitive(bytes);
-                case Asn1Tags.IA5String:
-                    return new DerIA5String(bytes);
-                case Asn1Tags.Integer:
-                    return new DerInteger(bytes, false);
-                case Asn1Tags.Null:
-                {
-                    if (0 != bytes.Length)
-                        throw new InvalidOperationException("malformed NULL encoding encountered");
+            case Asn1Tags.BitString:
+                return DerBitString.CreatePrimitive(bytes);
+            case Asn1Tags.GeneralizedTime:
+                return new DerGeneralizedTime(bytes);
+            case Asn1Tags.GeneralString:
+                return new DerGeneralString(bytes);
+            case Asn1Tags.GraphicString:
+                return DerGraphicString.CreatePrimitive(bytes);
+            case Asn1Tags.IA5String:
+                return new DerIA5String(bytes);
+            case Asn1Tags.Integer:
+                return new DerInteger(bytes, false);
+            case Asn1Tags.Null:
+            {
+                if (0 != bytes.Length)
+                    throw new InvalidOperationException("malformed NULL encoding encountered");
 
-                    return DerNull.Instance;
-                }
-                case Asn1Tags.NumericString:
-                    return new DerNumericString(bytes);
-                case Asn1Tags.ObjectDescriptor:
-                    return Asn1ObjectDescriptor.CreatePrimitive(bytes);
-                case Asn1Tags.OctetString:
-                    return new DerOctetString(bytes);
-                case Asn1Tags.PrintableString:
-                    return new DerPrintableString(bytes);
-                case Asn1Tags.RelativeOid:
-                    return Asn1RelativeOid.CreatePrimitive(bytes, false);
-                case Asn1Tags.T61String:
-                    return new DerT61String(bytes);
-                case Asn1Tags.UniversalString:
-                    return new DerUniversalString(bytes);
-                case Asn1Tags.UtcTime:
-                    return new DerUtcTime(bytes);
-                case Asn1Tags.Utf8String:
-                    return new DerUtf8String(bytes);
-                case Asn1Tags.VideotexString:
-                    return new DerVideotexString(bytes);
-                case Asn1Tags.VisibleString:
-                    return new DerVisibleString(bytes);
-                default:
-                    throw new IOException("unknown tag " + tagNo + " encountered");
+                return DerNull.Instance;
+            }
+            case Asn1Tags.NumericString:
+                return new DerNumericString(bytes);
+            case Asn1Tags.ObjectDescriptor:
+                return Asn1ObjectDescriptor.CreatePrimitive(bytes);
+            case Asn1Tags.OctetString:
+                return new DerOctetString(bytes);
+            case Asn1Tags.PrintableString:
+                return new DerPrintableString(bytes);
+            case Asn1Tags.RelativeOid:
+                return Asn1RelativeOid.CreatePrimitive(bytes, false);
+            case Asn1Tags.T61String:
+                return new DerT61String(bytes);
+            case Asn1Tags.UniversalString:
+                return new DerUniversalString(bytes);
+            case Asn1Tags.UtcTime:
+                return new DerUtcTime(bytes);
+            case Asn1Tags.Utf8String:
+                return new DerUtf8String(bytes);
+            case Asn1Tags.VideotexString:
+                return new DerVideotexString(bytes);
+            case Asn1Tags.VisibleString:
+                return new DerVisibleString(bytes);
+            default:
+                throw new IOException("unknown tag " + tagNo + " encountered");
             }
         }
     }