summary refs log tree commit diff
diff options
context:
space:
mode:
authorPeter Dettman <peter.dettman@bouncycastle.org>2019-08-01 15:20:29 +0700
committerPeter Dettman <peter.dettman@bouncycastle.org>2019-08-01 15:20:29 +0700
commitabe0572ea59671d9444b61bf3ad4458518c2805d (patch)
treeec5fcb0c70214b941c036589be9656ca79d24a3b
parentRework some of the ImplSquare methods in custom binary curves (diff)
downloadBouncyCastle.NET-ed25519-abe0572ea59671d9444b61bf3ad4458518c2805d.tar.xz
Misc. ASN.1 updates from bc-java
-rw-r--r--crypto/src/asn1/Asn1Encodable.cs2
-rw-r--r--crypto/src/asn1/Asn1EncodableVector.cs248
-rw-r--r--crypto/src/asn1/Asn1TaggedObject.cs2
-rw-r--r--crypto/src/asn1/DerObjectIdentifier.cs30
-rw-r--r--crypto/src/asn1/cms/Evidence.cs38
-rw-r--r--crypto/src/util/Arrays.cs14
-rw-r--r--crypto/test/src/asn1/test/LinkedCertificateTest.cs2
7 files changed, 232 insertions, 104 deletions
diff --git a/crypto/src/asn1/Asn1Encodable.cs b/crypto/src/asn1/Asn1Encodable.cs
index e3dd9a14c..12628082d 100644
--- a/crypto/src/asn1/Asn1Encodable.cs
+++ b/crypto/src/asn1/Asn1Encodable.cs
@@ -70,7 +70,7 @@ namespace Org.BouncyCastle.Asn1
 			Asn1Object o1 = ToAsn1Object();
 			Asn1Object o2 = other.ToAsn1Object();
 
-			return o1 == o2 || o1.CallAsn1Equals(o2);
+			return o1 == o2 || (null != o2 && o1.CallAsn1Equals(o2));
 		}
 
 		public abstract Asn1Object ToAsn1Object();
diff --git a/crypto/src/asn1/Asn1EncodableVector.cs b/crypto/src/asn1/Asn1EncodableVector.cs
index 8a97e8b4f..987aa5298 100644
--- a/crypto/src/asn1/Asn1EncodableVector.cs
+++ b/crypto/src/asn1/Asn1EncodableVector.cs
@@ -1,101 +1,191 @@
 using System;
 using System.Collections;
 
-using Org.BouncyCastle.Utilities;
-
 namespace Org.BouncyCastle.Asn1
 {
+    /**
+     * Mutable class for building ASN.1 constructed objects such as SETs or SEQUENCEs.
+     */
     public class Asn1EncodableVector
-		: IEnumerable
+        : IEnumerable
     {
-        private IList v = Platform.CreateArrayList();
-
-		public static Asn1EncodableVector FromEnumerable(
-			IEnumerable e)
-		{
-			Asn1EncodableVector v = new Asn1EncodableVector();
-			foreach (Asn1Encodable obj in e)
-			{
-				v.Add(obj);
-			}
-			return v;
-		}
-
-//		public Asn1EncodableVector()
-//		{
-//		}
-
-		public Asn1EncodableVector(
-			params Asn1Encodable[] v)
-		{
-			Add(v);
-		}
-
-//		public void Add(
-//			Asn1Encodable obj)
-//		{
-//			v.Add(obj);
-//		}
-
-		public void Add(
-			params Asn1Encodable[] objs)
-		{
-			foreach (Asn1Encodable obj in objs)
-			{
-				v.Add(obj);
-			}
-		}
-
-		public void AddOptional(
-			params Asn1Encodable[] objs)
-		{
-			if (objs != null)
-			{
-				foreach (Asn1Encodable obj in objs)
-				{
-					if (obj != null)
-					{
-						v.Add(obj);
-					}
-				}
-			}
-		}
+        internal static readonly Asn1Encodable[] EmptyElements = new Asn1Encodable[0];
+
+        private const int DefaultCapacity = 10;
+
+        private Asn1Encodable[] elements;
+        private int elementCount;
+        private bool copyOnWrite;
+
+        public static Asn1EncodableVector FromEnumerable(IEnumerable e)
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector();
+            foreach (Asn1Encodable obj in e)
+            {
+                v.Add(obj);
+            }
+            return v;
+        }
+
+        public Asn1EncodableVector()
+            : this(DefaultCapacity)
+        {
+        }
+
+        public Asn1EncodableVector(int initialCapacity)
+        {
+            if (initialCapacity < 0)
+                throw new ArgumentException("must not be negative", "initialCapacity");
+
+            this.elements = (initialCapacity == 0) ? EmptyElements : new Asn1Encodable[initialCapacity];
+            this.elementCount = 0;
+            this.copyOnWrite = false;
+        }
+
+        public Asn1EncodableVector(params Asn1Encodable[] v)
+            : this()
+        {
+            Add(v);
+        }
+
+        public void Add(Asn1Encodable element)
+        {
+            if (null == element)
+                throw new ArgumentNullException("element");
+
+            int capacity = elements.Length;
+            int minCapacity = elementCount + 1;
+            if ((minCapacity > capacity) | copyOnWrite)
+            {
+                Reallocate(minCapacity);
+            }
+
+            this.elements[elementCount] = element;
+            this.elementCount = minCapacity;
+        }
+
+        public void Add(params Asn1Encodable[] objs)
+        {
+            foreach (Asn1Encodable obj in objs)
+            {
+                Add(obj);
+            }
+        }
+
+        public void AddOptional(params Asn1Encodable[] objs)
+        {
+            if (objs != null)
+            {
+                foreach (Asn1Encodable obj in objs)
+                {
+                    if (obj != null)
+                    {
+                        Add(obj);
+                    }
+                }
+            }
+        }
 
         public void AddOptionalTagged(bool isExplicit, int tagNo, Asn1Encodable obj)
         {
             if (null != obj)
             {
-                v.Add(new DerTaggedObject(isExplicit, tagNo, obj));
+                Add(new DerTaggedObject(isExplicit, tagNo, obj));
             }
         }
 
-		public Asn1Encodable this[
-			int index]
-		{
-			get { return (Asn1Encodable) v[index]; }
-		}
+        public void AddAll(Asn1EncodableVector other)
+        {
+            if (null == other)
+                throw new ArgumentNullException("other");
 
-		[Obsolete("Use 'object[index]' syntax instead")]
-		public Asn1Encodable Get(
-            int index)
+            int otherElementCount = other.Count;
+            if (otherElementCount < 1)
+                return;
+
+            int capacity = elements.Length;
+            int minCapacity = elementCount + otherElementCount;
+            if ((minCapacity > capacity) | copyOnWrite)
+            {
+                Reallocate(minCapacity);
+            }
+
+            int i = 0;
+            do
+            {
+                Asn1Encodable otherElement = other[i];
+                if (null == otherElement)
+                    throw new NullReferenceException("'other' elements cannot be null");
+
+                this.elements[elementCount + i] = otherElement;
+            }
+            while (++i < otherElementCount);
+
+            this.elementCount = minCapacity;
+        }
+
+        public Asn1Encodable this[int index]
         {
-            return this[index];
+            get
+            {
+                if (index >= elementCount)
+                    throw new IndexOutOfRangeException(index + " >= " + elementCount);
+
+                return elements[index];
+            }
         }
 
-		[Obsolete("Use 'Count' property instead")]
-		public int Size
-		{
-			get { return v.Count; }
-		}
+        public int Count
+        {
+            get { return elementCount; }
+        }
 
-		public int Count
-		{
-			get { return v.Count; }
-		}
+        public IEnumerator GetEnumerator()
+        {
+            return CopyElements().GetEnumerator();
+        }
 
-		public IEnumerator GetEnumerator()
-		{
-			return v.GetEnumerator();
-		}
-	}
+        internal Asn1Encodable[] CopyElements()
+        {
+            if (0 == elementCount)
+                return EmptyElements;
+
+            Asn1Encodable[] copy = new Asn1Encodable[elementCount];
+            Array.Copy(elements, 0, copy, 0, elementCount);
+            return copy;
+        }
+
+        internal Asn1Encodable[] TakeElements()
+        {
+            if (0 == elementCount)
+                return EmptyElements;
+
+            if (elements.Length == elementCount)
+            {
+                this.copyOnWrite = true;
+                return elements;
+            }
+
+            Asn1Encodable[] copy = new Asn1Encodable[elementCount];
+            Array.Copy(elements, 0, copy, 0, elementCount);
+            return copy;
+        }
+
+        private void Reallocate(int minCapacity)
+        {
+            int oldCapacity = elements.Length;
+            int newCapacity = System.Math.Max(oldCapacity, minCapacity + (minCapacity >> 1));
+
+            Asn1Encodable[] copy = new Asn1Encodable[newCapacity];
+            Array.Copy(elements, 0, copy, 0, elementCount);
+
+            this.elements = copy;
+            this.copyOnWrite = false;
+        }
+
+        internal static Asn1Encodable[] CloneElements(Asn1Encodable[] elements)
+        {
+            return elements.Length < 1 ? EmptyElements : (Asn1Encodable[])elements.Clone();
+        }
+    }
 }
diff --git a/crypto/src/asn1/Asn1TaggedObject.cs b/crypto/src/asn1/Asn1TaggedObject.cs
index a6d4b2c28..14b1bc65f 100644
--- a/crypto/src/asn1/Asn1TaggedObject.cs
+++ b/crypto/src/asn1/Asn1TaggedObject.cs
@@ -33,7 +33,7 @@ namespace Org.BouncyCastle.Asn1
         {
             if (explicitly)
             {
-                return (Asn1TaggedObject) obj.GetObject();
+                return GetInstance(obj.GetObject());
             }
 
             throw new ArgumentException("implicitly tagged tagged object");
diff --git a/crypto/src/asn1/DerObjectIdentifier.cs b/crypto/src/asn1/DerObjectIdentifier.cs
index 1c8032f45..fb38d5f05 100644
--- a/crypto/src/asn1/DerObjectIdentifier.cs
+++ b/crypto/src/asn1/DerObjectIdentifier.cs
@@ -210,36 +210,36 @@ namespace Org.BouncyCastle.Asn1
             return identifier;
         }
 
-        private static bool IsValidBranchID(
-            string branchID, int start)
+        private static bool IsValidBranchID(string branchID, int start)
         {
-            bool periodAllowed = false;
+            int digitCount = 0;
 
             int pos = branchID.Length;
             while (--pos >= start)
             {
                 char ch = branchID[pos];
 
-                // TODO Leading zeroes?
-                if ('0' <= ch && ch <= '9')
-                {
-                    periodAllowed = true;
-                    continue;
-                }
-
                 if (ch == '.')
                 {
-                    if (!periodAllowed)
+                    if (0 == digitCount || (digitCount > 1 && branchID[pos + 1] == '0'))
                         return false;
 
-                    periodAllowed = false;
-                    continue;
+                    digitCount = 0;
+                }
+                else if ('0' <= ch && ch <= '9')
+                {
+                    ++digitCount;
                 }
+                else
+                {
+                    return false;
+                }
+            }
 
+            if (0 == digitCount || (digitCount > 1 && branchID[pos + 1] == '0'))
                 return false;
-            }
 
-            return periodAllowed;
+            return true;
         }
 
         private static bool IsValidIdentifier(string identifier)
diff --git a/crypto/src/asn1/cms/Evidence.cs b/crypto/src/asn1/cms/Evidence.cs
index 8374aed55..b12f090a9 100644
--- a/crypto/src/asn1/cms/Evidence.cs
+++ b/crypto/src/asn1/cms/Evidence.cs
@@ -8,6 +8,7 @@ namespace Org.BouncyCastle.Asn1.Cms
 		: Asn1Encodable, IAsn1Choice
 	{
 		private TimeStampTokenEvidence tstEvidence;
+        private Asn1Sequence otherEvidence;
 
 		public Evidence(TimeStampTokenEvidence tstEvidence)
 		{
@@ -16,11 +17,23 @@ namespace Org.BouncyCastle.Asn1.Cms
 
 		private Evidence(Asn1TaggedObject tagged)
 		{
-			if (tagged.TagNo == 0)
-			{
-				this.tstEvidence = TimeStampTokenEvidence.GetInstance(tagged, false);
-			}
-		}
+            if (tagged.TagNo == 0)
+            {
+                this.tstEvidence = TimeStampTokenEvidence.GetInstance(tagged, false);
+            }
+            //else if (tagged.TagNo == 1)
+            //{
+            //    this.ersEvidence = EvidenceRecord.GetInstance(tagged, false);
+            //}
+            else if (tagged.TagNo == 2)
+            {
+                this.otherEvidence = Asn1Sequence.GetInstance(tagged, false);
+            }
+            else
+            {
+                throw new ArgumentException("unknown tag in Evidence", "tagged");
+            }
+        }
 
 		public static Evidence GetInstance(object obj)
 		{
@@ -33,17 +46,28 @@ namespace Org.BouncyCastle.Asn1.Cms
 			throw new ArgumentException("Unknown object in GetInstance: " + Platform.GetTypeName(obj), "obj");
 		}
 
+        public static Evidence GetInstance(Asn1TaggedObject obj, bool isExplicit)
+        {
+            return GetInstance(obj.GetObject()); // must be explicitly tagged
+        }
+
 		public virtual TimeStampTokenEvidence TstEvidence
 		{
 			get { return tstEvidence; }
 		}
 
+        //public EvidenceRecord ErsEvidence
+        //{
+        //    get { return ersEvidence; }
+        //}
+
 		public override Asn1Object ToAsn1Object()
 		{
 			if (tstEvidence != null)
 				return new DerTaggedObject(false, 0, tstEvidence);
-
-			return null;
+            //if (ersEvidence != null)
+            //    return new DerTaggedObject(false, 1, ersEvidence);
+            return new DerTaggedObject(false, 2, otherEvidence);
 		}
 	}
 }
diff --git a/crypto/src/util/Arrays.cs b/crypto/src/util/Arrays.cs
index aa8d31df4..5d62d7174 100644
--- a/crypto/src/util/Arrays.cs
+++ b/crypto/src/util/Arrays.cs
@@ -721,5 +721,19 @@ namespace Org.BouncyCastle.Utilities
 
             return result;
         }
+
+        public static bool IsNullOrContainsNull(object[] array)
+        {
+            if (null == array)
+                return true;
+
+            int count = array.Length;
+            for (int i = 0; i < count; ++i)
+            {
+                if (null == array[i])
+                    return true;
+            }
+            return false;
+        }
     }
 }
diff --git a/crypto/test/src/asn1/test/LinkedCertificateTest.cs b/crypto/test/src/asn1/test/LinkedCertificateTest.cs
index 416c048c0..1ac5ab0fd 100644
--- a/crypto/test/src/asn1/test/LinkedCertificateTest.cs
+++ b/crypto/test/src/asn1/test/LinkedCertificateTest.cs
@@ -48,7 +48,7 @@ namespace Org.BouncyCastle.Asn1.Tests
 
                 Fail("getInstance() failed to detect bad object.");
             }
-            catch (ArgumentException e)
+            catch (ArgumentException)
             {
                 // expected
             }