summary refs log tree commit diff
diff options
context:
space:
mode:
authorPeter Dettman <peter.dettman@bouncycastle.org>2019-08-01 20:30:22 +0700
committerPeter Dettman <peter.dettman@bouncycastle.org>2019-08-01 20:30:22 +0700
commitf06dc7c2f2e578c77bdb53ff981c578c3fe017eb (patch)
treeda2e616d2554028d0314681abacc5632aa523627
parentDon't create a SecureRandom unnecessarily (diff)
downloadBouncyCastle.NET-ed25519-f06dc7c2f2e578c77bdb53ff981c578c3fe017eb.tar.xz
Rewrite Asn1Sequence/Set to store elements as Asn1Encodable[]
-rw-r--r--crypto/src/asn1/Asn1Sequence.cs112
-rw-r--r--crypto/src/asn1/Asn1Set.cs156
-rw-r--r--crypto/src/asn1/BerSequence.cs26
-rw-r--r--crypto/src/asn1/BerSet.cs26
-rw-r--r--crypto/src/asn1/DerSequence.cs34
-rw-r--r--crypto/src/asn1/DerSet.cs48
-rw-r--r--crypto/src/asn1/LazyDERSequence.cs22
-rw-r--r--crypto/src/asn1/LazyDERSet.cs10
8 files changed, 170 insertions, 264 deletions
diff --git a/crypto/src/asn1/Asn1Sequence.cs b/crypto/src/asn1/Asn1Sequence.cs
index 849f5e308..854c81590 100644
--- a/crypto/src/asn1/Asn1Sequence.cs
+++ b/crypto/src/asn1/Asn1Sequence.cs
@@ -10,7 +10,8 @@ namespace Org.BouncyCastle.Asn1
     public abstract class Asn1Sequence
         : Asn1Object, IEnumerable
     {
-        private readonly IList seq;
+        // NOTE: Only non-readonly to support LazyDerSequence
+        internal Asn1Encodable[] elements;
 
         /**
          * return an Asn1Sequence from the given object.
@@ -106,21 +107,38 @@ namespace Org.BouncyCastle.Asn1
             throw new ArgumentException("Unknown object in GetInstance: " + Platform.GetTypeName(obj), "obj");
         }
 
-        protected internal Asn1Sequence(
-            int capacity)
+        protected internal Asn1Sequence()
         {
-            seq = Platform.CreateArrayList(capacity);
+            this.elements = Asn1EncodableVector.EmptyElements;
         }
 
-        public virtual IEnumerator GetEnumerator()
+        protected internal Asn1Sequence(Asn1Encodable element)
+        {
+            if (null == element)
+                throw new ArgumentNullException("element");
+
+            this.elements = new Asn1Encodable[]{ element };
+        }
+
+        protected internal Asn1Sequence(params Asn1Encodable[] elements)
         {
-            return seq.GetEnumerator();
+            if (Arrays.IsNullOrContainsNull(elements))
+                throw new NullReferenceException("'elements' cannot be null, or contain null");
+
+            this.elements = Asn1EncodableVector.CloneElements(elements);
         }
 
-        [Obsolete("Use GetEnumerator() instead")]
-        public IEnumerator GetObjects()
+        protected internal Asn1Sequence(Asn1EncodableVector elementVector)
         {
-            return GetEnumerator();
+            if (null == elementVector)
+                throw new ArgumentNullException("elementVector");
+
+            this.elements = elementVector.TakeElements();
+        }
+
+        public virtual IEnumerator GetEnumerator()
+        {
+            return elements.GetEnumerator();
         }
 
         private class Asn1SequenceParserImpl
@@ -176,93 +194,59 @@ namespace Org.BouncyCastle.Asn1
          */
         public virtual Asn1Encodable this[int index]
         {
-            get { return (Asn1Encodable) seq[index]; }
+            get { return elements[index]; }
         }
 
-        [Obsolete("Use 'object[index]' syntax instead")]
-        public Asn1Encodable GetObjectAt(
-            int index)
-        {
-             return this[index];
-        }
-
-        [Obsolete("Use 'Count' property instead")]
-        public int Size
+        public virtual int Count
         {
-            get { return Count; }
+            get { return elements.Length; }
         }
 
-        public virtual int Count
+        public virtual Asn1Encodable[] ToArray()
         {
-            get { return seq.Count; }
+            return Asn1EncodableVector.CloneElements(elements);
         }
 
         protected override int Asn1GetHashCode()
         {
-            int hc = Count;
+            //return Arrays.GetHashCode(elements);
+            int i = elements.Length;
+            int hc = i + 1;
 
-            foreach (object o in this)
+            while (--i >= 0)
             {
-                hc *= 17;
-                if (o == null)
-                {
-                    hc ^= DerNull.Instance.GetHashCode();
-                }
-                else
-                {
-                    hc ^= o.GetHashCode();
-                }
+                hc *= 257;
+                hc ^= elements[i].ToAsn1Object().CallAsn1GetHashCode();
             }
 
             return hc;
         }
 
-        protected override bool Asn1Equals(
-            Asn1Object asn1Object)
+        protected override bool Asn1Equals(Asn1Object asn1Object)
         {
-            Asn1Sequence other = asn1Object as Asn1Sequence;
-
-            if (other == null)
+            Asn1Sequence that = asn1Object as Asn1Sequence;
+            if (null == that)
                 return false;
 
-            if (Count != other.Count)
+            int count = this.Count;
+            if (that.Count != count)
                 return false;
 
-            IEnumerator s1 = GetEnumerator();
-            IEnumerator s2 = other.GetEnumerator();
-
-            while (s1.MoveNext() && s2.MoveNext())
+            for (int i = 0; i < count; ++i)
             {
-                Asn1Object o1 = GetCurrent(s1).ToAsn1Object();
-                Asn1Object o2 = GetCurrent(s2).ToAsn1Object();
+                Asn1Object o1 = this.elements[i].ToAsn1Object();
+                Asn1Object o2 = that.elements[i].ToAsn1Object();
 
-                if (!o1.Equals(o2))
+                if (o1 != o2 && !o1.CallAsn1Equals(o2))
                     return false;
             }
 
             return true;
         }
 
-        private Asn1Encodable GetCurrent(IEnumerator e)
-        {
-            Asn1Encodable encObj = (Asn1Encodable)e.Current;
-
-            // unfortunately null was allowed as a substitute for DER null
-            if (encObj == null)
-                return DerNull.Instance;
-
-            return encObj;
-        }
-
-        protected internal void AddObject(
-            Asn1Encodable obj)
-        {
-            seq.Add(obj);
-        }
-
         public override string ToString()
         {
-            return CollectionUtilities.ToString(seq);
+            return CollectionUtilities.ToString(elements);
         }
     }
 }
diff --git a/crypto/src/asn1/Asn1Set.cs b/crypto/src/asn1/Asn1Set.cs
index 7fa072c0d..07605f5e1 100644
--- a/crypto/src/asn1/Asn1Set.cs
+++ b/crypto/src/asn1/Asn1Set.cs
@@ -16,7 +16,8 @@ namespace Org.BouncyCastle.Asn1
     abstract public class Asn1Set
         : Asn1Object, IEnumerable
     {
-        private readonly IList _set;
+        // NOTE: Only non-readonly to support LazyDerSequence
+        internal Asn1Encodable[] elements;
 
         /**
          * return an ASN1Set from the given object.
@@ -125,21 +126,38 @@ namespace Org.BouncyCastle.Asn1
             throw new ArgumentException("Unknown object in GetInstance: " + Platform.GetTypeName(obj), "obj");
         }
 
-        protected internal Asn1Set(
-            int capacity)
+        protected internal Asn1Set()
         {
-            _set = Platform.CreateArrayList(capacity);
+            this.elements = Asn1EncodableVector.EmptyElements;
         }
 
-        public virtual IEnumerator GetEnumerator()
+        protected internal Asn1Set(Asn1Encodable element)
+        {
+            if (null == element)
+                throw new ArgumentNullException("element");
+
+            this.elements = new Asn1Encodable[]{ element };
+        }
+
+        protected internal Asn1Set(params Asn1Encodable[] elements)
         {
-            return _set.GetEnumerator();
+            if (Arrays.IsNullOrContainsNull(elements))
+                throw new NullReferenceException("'elements' cannot be null, or contain null");
+
+            this.elements = Asn1EncodableVector.CloneElements(elements);
         }
 
-        [Obsolete("Use GetEnumerator() instead")]
-        public IEnumerator GetObjects()
+        protected internal Asn1Set(Asn1EncodableVector elementVector)
+        {
+            if (null == elementVector)
+                throw new ArgumentNullException("elementVector");
+
+            this.elements = elementVector.TakeElements();
+        }
+
+        public virtual IEnumerator GetEnumerator()
         {
-            return GetEnumerator();
+            return elements.GetEnumerator();
         }
 
         /**
@@ -150,35 +168,17 @@ namespace Org.BouncyCastle.Asn1
          */
         public virtual Asn1Encodable this[int index]
         {
-            get { return (Asn1Encodable) _set[index]; }
-        }
-
-        [Obsolete("Use 'object[index]' syntax instead")]
-        public Asn1Encodable GetObjectAt(
-            int index)
-        {
-             return this[index];
-        }
-
-        [Obsolete("Use 'Count' property instead")]
-        public int Size
-        {
-            get { return Count; }
+            get { return elements[index]; }
         }
 
         public virtual int Count
         {
-            get { return _set.Count; }
+            get { return elements.Length; }
         }
 
         public virtual Asn1Encodable[] ToArray()
         {
-            Asn1Encodable[] values = new Asn1Encodable[this.Count];
-            for (int i = 0; i < this.Count; ++i)
-            {
-                values[i] = this[i];
-            }
-            return values;
+            return Asn1EncodableVector.CloneElements(elements);
         }
 
         private class Asn1SetParserImpl
@@ -227,107 +227,67 @@ namespace Org.BouncyCastle.Asn1
 
         protected override int Asn1GetHashCode()
         {
-            int hc = Count;
+            //return Arrays.GetHashCode(elements);
+            int i = elements.Length;
+            int hc = i + 1;
 
-            foreach (object o in this)
+            while (--i >= 0)
             {
-                hc *= 17;
-                if (o == null)
-                {
-                    hc ^= DerNull.Instance.GetHashCode();
-                }
-                else
-                {
-                    hc ^= o.GetHashCode();
-                }
+                hc *= 257;
+                hc ^= elements[i].ToAsn1Object().CallAsn1GetHashCode();
             }
 
             return hc;
         }
 
-        protected override bool Asn1Equals(
-            Asn1Object asn1Object)
+        protected override bool Asn1Equals(Asn1Object asn1Object)
         {
-            Asn1Set other = asn1Object as Asn1Set;
-
-            if (other == null)
+            Asn1Set that = asn1Object as Asn1Set;
+            if (null == that)
                 return false;
 
-            if (Count != other.Count)
-            {
+            int count = this.Count;
+            if (that.Count != count)
                 return false;
-            }
-
-            IEnumerator s1 = GetEnumerator();
-            IEnumerator s2 = other.GetEnumerator();
 
-            while (s1.MoveNext() && s2.MoveNext())
+            for (int i = 0; i < count; ++i)
             {
-                Asn1Object o1 = GetCurrent(s1).ToAsn1Object();
-                Asn1Object o2 = GetCurrent(s2).ToAsn1Object();
+                Asn1Object o1 = this.elements[i].ToAsn1Object();
+                Asn1Object o2 = that.elements[i].ToAsn1Object();
 
-                if (!o1.Equals(o2))
+                if (o1 != o2 && !o1.CallAsn1Equals(o2))
                     return false;
             }
 
             return true;
         }
 
-        private Asn1Encodable GetCurrent(IEnumerator e)
-        {
-            Asn1Encodable encObj = (Asn1Encodable)e.Current;
-
-            // unfortunately null was allowed as a substitute for DER null
-            if (encObj == null)
-                return DerNull.Instance;
-
-            return encObj;
-        }
-
         protected internal void Sort()
         {
-            if (_set.Count < 2)
+            if (elements.Length < 2)
                 return;
 
 #if PORTABLE
-            var sorted = _set.Cast<Asn1Encodable>()
-                             .Select(a => new { Item = a, Key = a.GetEncoded(Asn1Encodable.Der) })
-                             .OrderBy(t => t.Key, new DerComparer())
-                             .Select(t => t.Item)
-                             .ToList();
-
-            for (int i = 0; i < _set.Count; ++i)
-            {
-                _set[i] = sorted[i];
-            }
+            this.elements = elements
+                .Cast<Asn1Encodable>()
+                .Select(a => new { Item = a, Key = a.GetEncoded(Asn1Encodable.Der) })
+                .OrderBy(t => t.Key, new DerComparer())
+                .Select(t => t.Item)
+                .ToArray();
 #else
-            Asn1Encodable[] items = new Asn1Encodable[_set.Count];
-            byte[][] keys = new byte[_set.Count][];
-
-            for (int i = 0; i < _set.Count; ++i)
-            {
-                Asn1Encodable item = (Asn1Encodable)_set[i];
-                items[i] = item;
-                keys[i] = item.GetEncoded(Asn1Encodable.Der);
-            }
-
-            Array.Sort(keys, items, new DerComparer());
-
-            for (int i = 0; i < _set.Count; ++i)
+            int count = elements.Length;
+            byte[][] keys = new byte[count][];
+            for (int i = 0; i < count; ++i)
             {
-                _set[i] = items[i];
+                keys[i] = elements[i].GetEncoded(Asn1Encodable.Der);
             }
+            Array.Sort(keys, elements, new DerComparer());
 #endif
         }
 
-        protected internal void AddObject(Asn1Encodable obj)
-        {
-            _set.Add(obj);
-        }
-
         public override string ToString()
         {
-            return CollectionUtilities.ToString(_set);
+            return CollectionUtilities.ToString(elements);
         }
 
 #if PORTABLE
diff --git a/crypto/src/asn1/BerSequence.cs b/crypto/src/asn1/BerSequence.cs
index 70b43fc79..55c93a72e 100644
--- a/crypto/src/asn1/BerSequence.cs
+++ b/crypto/src/asn1/BerSequence.cs
@@ -5,47 +5,41 @@ namespace Org.BouncyCastle.Asn1
 	{
 		public static new readonly BerSequence Empty = new BerSequence();
 
-		public static new BerSequence FromVector(
-			Asn1EncodableVector v)
+		public static new BerSequence FromVector(Asn1EncodableVector elementVector)
 		{
-			return v.Count < 1 ? Empty : new BerSequence(v);
+            return elementVector.Count < 1 ? Empty : new BerSequence(elementVector);
 		}
 
 		/**
 		 * create an empty sequence
 		 */
 		public BerSequence()
+            : base()
 		{
 		}
 
 		/**
 		 * create a sequence containing one object
 		 */
-		public BerSequence(
-			Asn1Encodable obj)
-			: base(obj)
+		public BerSequence(Asn1Encodable element)
+            : base(element)
 		{
 		}
 
-		public BerSequence(
-			params Asn1Encodable[] v)
-			: base(v)
+		public BerSequence(params Asn1Encodable[] elements)
+            : base(elements)
 		{
 		}
 
 		/**
 		 * create a sequence containing a vector of objects.
 		 */
-		public BerSequence(
-			Asn1EncodableVector v)
-			: base(v)
+		public BerSequence(Asn1EncodableVector elementVector)
+            : base(elementVector)
 		{
 		}
 
-		/*
-		 */
-		internal override void Encode(
-			DerOutputStream derOut)
+        internal override void Encode(DerOutputStream derOut)
 		{
 			if (derOut is Asn1OutputStream || derOut is BerOutputStream)
 			{
diff --git a/crypto/src/asn1/BerSet.cs b/crypto/src/asn1/BerSet.cs
index a181e172d..6209e71a8 100644
--- a/crypto/src/asn1/BerSet.cs
+++ b/crypto/src/asn1/BerSet.cs
@@ -5,48 +5,46 @@ namespace Org.BouncyCastle.Asn1
     {
 		public static new readonly BerSet Empty = new BerSet();
 
-		public static new BerSet FromVector(
-			Asn1EncodableVector v)
+		public static new BerSet FromVector(Asn1EncodableVector elementVector)
 		{
-			return v.Count < 1 ? Empty : new BerSet(v);
+            return elementVector.Count < 1 ? Empty : new BerSet(elementVector);
 		}
 
-		internal static new BerSet FromVector(
-			Asn1EncodableVector v,
-			bool				needsSorting)
+        internal static new BerSet FromVector(Asn1EncodableVector elementVector, bool needsSorting)
 		{
-			return v.Count < 1 ? Empty : new BerSet(v, needsSorting);
+            return elementVector.Count < 1 ? Empty : new BerSet(elementVector, needsSorting);
 		}
 
 		/**
          * create an empty sequence
          */
         public BerSet()
+            : base()
         {
         }
 
         /**
          * create a set containing one object
          */
-        public BerSet(Asn1Encodable obj) : base(obj)
+        public BerSet(Asn1Encodable element)
+            : base(element)
         {
         }
 
         /**
          * create a set containing a vector of objects.
          */
-        public BerSet(Asn1EncodableVector v) : base(v, false)
+        public BerSet(Asn1EncodableVector elementVector)
+            : base(elementVector, false)
         {
         }
 
-        internal BerSet(Asn1EncodableVector v, bool needsSorting) : base(v, needsSorting)
+        internal BerSet(Asn1EncodableVector elementVector, bool needsSorting)
+            : base(elementVector, needsSorting)
         {
         }
 
-        /*
-         */
-        internal override void Encode(
-            DerOutputStream derOut)
+        internal override void Encode(DerOutputStream derOut)
         {
             if (derOut is Asn1OutputStream || derOut is BerOutputStream)
             {
diff --git a/crypto/src/asn1/DerSequence.cs b/crypto/src/asn1/DerSequence.cs
index a76cf2882..823fa869b 100644
--- a/crypto/src/asn1/DerSequence.cs
+++ b/crypto/src/asn1/DerSequence.cs
@@ -11,51 +11,38 @@ namespace Org.BouncyCastle.Asn1
 	{
 		public static readonly DerSequence Empty = new DerSequence();
 
-		public static DerSequence FromVector(
-			Asn1EncodableVector v)
+		public static DerSequence FromVector(Asn1EncodableVector elementVector)
 		{
-			return v.Count < 1 ? Empty : new DerSequence(v);
+            return elementVector.Count < 1 ? Empty : new DerSequence(elementVector);
 		}
 
 		/**
 		 * create an empty sequence
 		 */
 		public DerSequence()
-			: base(0)
+			: base()
 		{
 		}
 
 		/**
 		 * create a sequence containing one object
 		 */
-		public DerSequence(
-			Asn1Encodable obj)
-			: base(1)
+		public DerSequence(Asn1Encodable element)
+			: base(element)
 		{
-			AddObject(obj);
 		}
 
-		public DerSequence(
-			params Asn1Encodable[] v)
-			: base(v.Length)
+		public DerSequence(params Asn1Encodable[] elements)
+            : base(elements)
 		{
-			foreach (Asn1Encodable ae in v)
-			{
-				AddObject(ae);
-			}
 		}
 
 		/**
 		 * create a sequence containing a vector of objects.
 		 */
-		public DerSequence(
-			Asn1EncodableVector v)
-			: base(v.Count)
+		public DerSequence(Asn1EncodableVector elementVector)
+            : base(elementVector)
 		{
-			foreach (Asn1Encodable ae in v)
-			{
-				AddObject(ae);
-			}
 		}
 
 		/*
@@ -66,8 +53,7 @@ namespace Org.BouncyCastle.Asn1
 		 * ASN.1 descriptions given. Rather than just outputing Sequence,
 		 * we also have to specify Constructed, and the objects length.
 		 */
-		internal override void Encode(
-			DerOutputStream derOut)
+		internal override void Encode(DerOutputStream derOut)
 		{
 			// TODO Intermediate buffer could be avoided if we could calculate expected length
 			MemoryStream bOut = new MemoryStream();
diff --git a/crypto/src/asn1/DerSet.cs b/crypto/src/asn1/DerSet.cs
index 3df1a6766..d4c242778 100644
--- a/crypto/src/asn1/DerSet.cs
+++ b/crypto/src/asn1/DerSet.cs
@@ -13,68 +13,49 @@ namespace Org.BouncyCastle.Asn1
 	{
 		public static readonly DerSet Empty = new DerSet();
 
-		public static DerSet FromVector(
-			Asn1EncodableVector v)
+		public static DerSet FromVector(Asn1EncodableVector elementVector)
 		{
-			return v.Count < 1 ? Empty : new DerSet(v);
+            return elementVector.Count < 1 ? Empty : new DerSet(elementVector);
 		}
 
-		internal static DerSet FromVector(
-			Asn1EncodableVector	v,
-			bool				needsSorting)
+		internal static DerSet FromVector(Asn1EncodableVector elementVector, bool needsSorting)
 		{
-			return v.Count < 1 ? Empty : new DerSet(v, needsSorting);
+            return elementVector.Count < 1 ? Empty : new DerSet(elementVector, needsSorting);
 		}
 
 		/**
 		 * create an empty set
 		 */
 		public DerSet()
-			: base(0)
+			: base()
 		{
 		}
 
 		/**
 		 * @param obj - a single object that makes up the set.
 		 */
-		public DerSet(
-			Asn1Encodable obj)
-			: base(1)
+		public DerSet(Asn1Encodable element)
+			: base(element)
 		{
-			AddObject(obj);
 		}
 
-		public DerSet(
-			params Asn1Encodable[] v)
-			: base(v.Length)
+		public DerSet(params Asn1Encodable[] elements)
+			: base(elements)
 		{
-			foreach (Asn1Encodable o in v)
-			{
-				AddObject(o);
-			}
-
 			Sort();
 		}
 
 		/**
 		 * @param v - a vector of objects making up the set.
 		 */
-		public DerSet(
-			Asn1EncodableVector v)
-			: this(v, true)
+		public DerSet(Asn1EncodableVector elementVector)
+			: this(elementVector, true)
 		{
 		}
 
-		internal DerSet(
-			Asn1EncodableVector	v,
-			bool				needsSorting)
-			: base(v.Count)
+		internal DerSet(Asn1EncodableVector	elementVector, bool needsSorting)
+			: base(elementVector)
 		{
-			foreach (Asn1Encodable o in v)
-			{
-				AddObject(o);
-			}
-
 			if (needsSorting)
 			{
 				Sort();
@@ -89,8 +70,7 @@ namespace Org.BouncyCastle.Asn1
 		 * ASN.1 descriptions given. Rather than just outputing Set,
 		 * we also have to specify Constructed, and the objects length.
 		 */
-		internal override void Encode(
-			DerOutputStream derOut)
+		internal override void Encode(DerOutputStream derOut)
 		{
 			// TODO Intermediate buffer could be avoided if we could calculate expected length
 			MemoryStream bOut = new MemoryStream();
diff --git a/crypto/src/asn1/LazyDERSequence.cs b/crypto/src/asn1/LazyDERSequence.cs
index 7301bc158..8fa7a0792 100644
--- a/crypto/src/asn1/LazyDERSequence.cs
+++ b/crypto/src/asn1/LazyDERSequence.cs
@@ -19,18 +19,20 @@ namespace Org.BouncyCastle.Asn1
 		{
 			lock (this)
 			{
-				if (encoded != null)
-				{
-					Asn1InputStream e = new LazyAsn1InputStream(encoded);
+                if (null != encoded)
+                {
+                    Asn1EncodableVector v = new Asn1EncodableVector();
+                    Asn1InputStream e = new LazyAsn1InputStream(encoded);
 
-					Asn1Object o;
-					while ((o = e.ReadObject()) != null)
-					{
-						AddObject(o);
-					}
+                    Asn1Object o;
+                    while ((o = e.ReadObject()) != null)
+                    {
+                        v.Add(o);
+                    }
 
-					encoded = null;
-				}
+                    this.elements = v.TakeElements();
+                    this.encoded = null;
+                }
 			}
 		}
 
diff --git a/crypto/src/asn1/LazyDERSet.cs b/crypto/src/asn1/LazyDERSet.cs
index e6c9319dd..eac64cbbe 100644
--- a/crypto/src/asn1/LazyDERSet.cs
+++ b/crypto/src/asn1/LazyDERSet.cs
@@ -21,16 +21,18 @@ namespace Org.BouncyCastle.Asn1
 			{
 				if (encoded != null)
 				{
-					Asn1InputStream e = new LazyAsn1InputStream(encoded);
+                    Asn1EncodableVector v = new Asn1EncodableVector();
+                    Asn1InputStream e = new LazyAsn1InputStream(encoded);
 
 					Asn1Object o;
 					while ((o = e.ReadObject()) != null)
 					{
-						AddObject(o);
+						v.Add(o);
 					}
 
-					encoded = null;
-				}
+                    this.elements = v.TakeElements();
+                    this.encoded = null;
+                }
 			}
 		}