summary refs log tree commit diff
path: root/crypto/src/asn1/Asn1Set.cs
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/src/asn1/Asn1Set.cs')
-rw-r--r--crypto/src/asn1/Asn1Set.cs129
1 files changed, 69 insertions, 60 deletions
diff --git a/crypto/src/asn1/Asn1Set.cs b/crypto/src/asn1/Asn1Set.cs
index 453627b7c..b1439be47 100644
--- a/crypto/src/asn1/Asn1Set.cs
+++ b/crypto/src/asn1/Asn1Set.cs
@@ -13,12 +13,9 @@ using Org.BouncyCastle.Utilities.Collections;
 
 namespace Org.BouncyCastle.Asn1
 {
-    abstract public class Asn1Set
+    public abstract class Asn1Set
         : Asn1Object, IEnumerable
     {
-        // NOTE: Only non-readonly to support LazyDerSet
-        internal Asn1Encodable[] elements;
-
         /**
          * return an ASN1Set from the given object.
          *
@@ -63,65 +60,52 @@ namespace Org.BouncyCastle.Asn1
          * dealing with implicitly tagged sets you really <b>should</b>
          * be using this method.
          *
-         * @param obj the tagged object.
-         * @param explicitly true if the object is meant to be explicitly tagged
+         * @param taggedObject the tagged object.
+         * @param declaredExplicit true if the object is meant to be explicitly tagged
          *          false otherwise.
          * @exception ArgumentException if the tagged object cannot
          *          be converted.
          */
-        public static Asn1Set GetInstance(
-            Asn1TaggedObject	obj,
-            bool				explicitly)
+        public static Asn1Set GetInstance(Asn1TaggedObject taggedObject, bool declaredExplicit)
         {
-            Asn1Object inner = obj.GetObject();
+            Asn1Object baseObject = taggedObject.GetObject();
 
-            if (explicitly)
+            if (declaredExplicit)
             {
-                if (!obj.IsExplicit())
+                if (!taggedObject.IsExplicit())
                     throw new ArgumentException("object implicit - explicit expected.");
 
-                return (Asn1Set) inner;
+                return (Asn1Set)baseObject;
             }
 
-            //
-            // constructed object which appears to be explicitly tagged
-            // and it's really implicit means we have to add the
-            // surrounding sequence.
-            //
-            if (obj.IsExplicit())
+            // If parsed as explicit though declared implicit, it should have been a set of one
+            if (taggedObject.IsExplicit())
             {
-                return new DerSet(inner);
-            }
+                if (taggedObject is BerTaggedObject)
+                    return new BerSet(baseObject);
 
-            if (inner is Asn1Set)
-            {
-                return (Asn1Set) inner;
+                return new DLSet(baseObject);
             }
 
-            //
-            // in this case the parser returns a sequence, convert it
-            // into a set.
-            //
-            if (inner is Asn1Sequence)
-            {
-                Asn1EncodableVector v = new Asn1EncodableVector();
-                Asn1Sequence s = (Asn1Sequence) inner;
+            if (baseObject is Asn1Set)
+                return (Asn1Set)baseObject;
 
-                foreach (Asn1Encodable ae in s)
-                {
-                    v.Add(ae);
-                }
-
-                // TODO Should be able to construct set directly from sequence?
-                return new DerSet(v, false);
-            }
+            // Parser assumes implicit constructed encodings are sequences
+            if (baseObject is Asn1Sequence)
+                return ((Asn1Sequence)baseObject).ToAsn1Set();
 
-            throw new ArgumentException("illegal object in GetInstance: " + Platform.GetTypeName(obj), "obj");
+            throw new ArgumentException("illegal object in GetInstance: " + Platform.GetTypeName(taggedObject),
+                "taggedObject");
         }
 
+        // NOTE: Only non-readonly to support LazyDLSet
+        internal Asn1Encodable[] elements;
+        internal bool isSorted;
+
         protected internal Asn1Set()
         {
             this.elements = Asn1EncodableVector.EmptyElements;
+            this.isSorted = true;
         }
 
         protected internal Asn1Set(Asn1Encodable element)
@@ -130,22 +114,47 @@ namespace Org.BouncyCastle.Asn1
                 throw new ArgumentNullException("element");
 
             this.elements = new Asn1Encodable[]{ element };
+            this.isSorted = true;
         }
 
-        protected internal Asn1Set(params Asn1Encodable[] elements)
+        protected internal Asn1Set(Asn1Encodable[] elements, bool doSort)
         {
             if (Arrays.IsNullOrContainsNull(elements))
                 throw new NullReferenceException("'elements' cannot be null, or contain null");
 
-            this.elements = Asn1EncodableVector.CloneElements(elements);
+            Asn1Encodable[] tmp = Asn1EncodableVector.CloneElements(elements);
+            if (doSort && tmp.Length >= 2)
+            {
+                tmp = Sort(tmp);
+            }
+
+            this.elements = tmp;
+            this.isSorted = doSort || tmp.Length < 2;
         }
 
-        protected internal Asn1Set(Asn1EncodableVector elementVector)
+        protected internal Asn1Set(Asn1EncodableVector elementVector, bool doSort)
         {
             if (null == elementVector)
                 throw new ArgumentNullException("elementVector");
 
-            this.elements = elementVector.TakeElements();
+            Asn1Encodable[] tmp;
+            if (doSort && elementVector.Count >= 2)
+            {
+                tmp = Sort(elementVector.CopyElements());
+            }
+            else
+            {
+                tmp = elementVector.TakeElements();
+            }
+
+            this.elements = tmp;
+            this.isSorted = doSort || tmp.Length < 2;
+        }
+
+        protected internal Asn1Set(bool isSorted, Asn1Encodable[] elements)
+        {
+            this.elements = elements;
+            this.isSorted = isSorted || elements.Length < 2;
         }
 
         public virtual IEnumerator GetEnumerator()
@@ -257,15 +266,24 @@ namespace Org.BouncyCastle.Asn1
             return true;
         }
 
-        protected internal void Sort()
+        internal override bool EncodeConstructed()
         {
-            // NOTE: Call Count here to 'force' a LazyDerSet
-            int count = Count;
+            return true;
+        }
+
+        public override string ToString()
+        {
+            return CollectionUtilities.ToString(elements);
+        }
+
+        private static Asn1Encodable[] Sort(Asn1Encodable[] elements)
+        {
+            int count = elements.Length;
             if (count < 2)
-                return;
+                return elements;
 
 #if PORTABLE
-            this.elements = elements
+            return elements
                 .Cast<Asn1Encodable>()
                 .Select(a => new { Item = a, Key = a.GetEncoded(Asn1Encodable.Der) })
                 .OrderBy(t => t.Key, new DerComparer())
@@ -278,19 +296,10 @@ namespace Org.BouncyCastle.Asn1
                 keys[i] = elements[i].GetEncoded(Der);
             }
             Array.Sort(keys, elements, new DerComparer());
+            return elements;
 #endif
         }
 
-        internal override bool EncodeConstructed()
-        {
-            return true;
-        }
-
-        public override string ToString()
-        {
-            return CollectionUtilities.ToString(elements);
-        }
-
 #if PORTABLE
         private class DerComparer
             : IComparer<byte[]>