summary refs log tree commit diff
path: root/crypto/src/asn1
diff options
context:
space:
mode:
authorPeter Dettman <peter.dettman@bouncycastle.org>2024-07-01 19:23:46 +0700
committerPeter Dettman <peter.dettman@bouncycastle.org>2024-07-01 19:23:46 +0700
commit4e97fa1cbee0072938c5ea33ca51f4e3964f2998 (patch)
tree0aad9c9bc277429ee733c8383672cb7c6aed329a /crypto/src/asn1
parentRefactoring in Asn1.Smime (diff)
downloadBouncyCastle.NET-ed25519-4e97fa1cbee0072938c5ea33ca51f4e3964f2998.tar.xz
Refactoring in Asn1.Tsp
Diffstat (limited to 'crypto/src/asn1')
-rw-r--r--crypto/src/asn1/cms/Attributes.cs9
-rw-r--r--crypto/src/asn1/tsp/Accuracy.cs105
-rw-r--r--crypto/src/asn1/tsp/ArchiveTimeStamp.cs79
-rw-r--r--crypto/src/asn1/tsp/ArchiveTimeStampChain.cs31
-rw-r--r--crypto/src/asn1/tsp/ArchiveTimeStampSequence.cs25
-rw-r--r--crypto/src/asn1/tsp/CryptoInfos.cs11
-rw-r--r--crypto/src/asn1/tsp/EncryptionInfo.cs24
-rw-r--r--crypto/src/asn1/tsp/EvidenceRecord.cs64
-rw-r--r--crypto/src/asn1/tsp/MessageImprint.cs34
-rw-r--r--crypto/src/asn1/tsp/PartialHashtree.cs9
-rw-r--r--crypto/src/asn1/tsp/TSTInfo.cs110
-rw-r--r--crypto/src/asn1/tsp/TimeStampReq.cs75
-rw-r--r--crypto/src/asn1/tsp/TimeStampResp.cs27
13 files changed, 245 insertions, 358 deletions
diff --git a/crypto/src/asn1/cms/Attributes.cs b/crypto/src/asn1/cms/Attributes.cs
index cdcada6dc..00f3b464f 100644
--- a/crypto/src/asn1/cms/Attributes.cs
+++ b/crypto/src/asn1/cms/Attributes.cs
@@ -14,10 +14,11 @@ namespace Org.BouncyCastle.Asn1.Cms
             return new Attributes(Asn1Set.GetInstance(obj));
         }
 
-        public static Attributes GetInstance(Asn1TaggedObject taggedObject, bool declaredExplicit)
-        {
-            return new Attributes(Asn1Set.GetInstance(taggedObject, declaredExplicit));
-        }
+        public static Attributes GetInstance(Asn1TaggedObject taggedObject, bool declaredExplicit) =>
+            new Attributes(Asn1Set.GetInstance(taggedObject, declaredExplicit));
+
+        public static Attributes GetTagged(Asn1TaggedObject taggedObject, bool declaredExplicit) =>
+            new Attributes(Asn1Set.GetTagged(taggedObject, declaredExplicit));
 
         public static Attributes GetOptional(Asn1Encodable element)
         {
diff --git a/crypto/src/asn1/tsp/Accuracy.cs b/crypto/src/asn1/tsp/Accuracy.cs
index a4fd0443b..a5c801c93 100644
--- a/crypto/src/asn1/tsp/Accuracy.cs
+++ b/crypto/src/asn1/tsp/Accuracy.cs
@@ -1,10 +1,8 @@
 using System;
 
-using Org.BouncyCastle.Utilities;
-
 namespace Org.BouncyCastle.Asn1.Tsp
 {
-	public class Accuracy
+    public class Accuracy
 		: Asn1Encodable
 	{
         protected const int MinMillis = 1;
@@ -21,73 +19,54 @@ namespace Org.BouncyCastle.Asn1.Tsp
             return new Accuracy(Asn1Sequence.GetInstance(obj));
         }
 
-        public static Accuracy GetInstance(Asn1TaggedObject taggedObject, bool declaredExplicit)
+        public static Accuracy GetInstance(Asn1TaggedObject taggedObject, bool declaredExplicit) =>
+            new Accuracy(Asn1Sequence.GetInstance(taggedObject, declaredExplicit));
+
+        public static Accuracy GetOptional(Asn1Encodable element)
         {
-            return new Accuracy(Asn1Sequence.GetInstance(taggedObject, declaredExplicit));
+            if (element == null)
+                throw new ArgumentNullException(nameof(element));
+
+            if (element is Accuracy accuracy)
+                return accuracy;
+
+            Asn1Sequence asn1Sequence = Asn1Sequence.GetOptional(element);
+            if (asn1Sequence != null)
+                return new Accuracy(asn1Sequence);
+
+            return null;
         }
 
+        public static Accuracy GetTagged(Asn1TaggedObject taggedObject, bool declaredExplicit) =>
+            new Accuracy(Asn1Sequence.GetTagged(taggedObject, declaredExplicit));
+
         private readonly DerInteger m_seconds;
         private readonly DerInteger m_millis;
         private readonly DerInteger m_micros;
 
-        public Accuracy(DerInteger seconds, DerInteger millis, DerInteger micros)
+        private Accuracy(Asn1Sequence seq)
         {
-            if (null != millis)
-            {
-                int millisValue = millis.IntValueExact;
-                if (millisValue < MinMillis || millisValue > MaxMillis)
-                    throw new ArgumentException("Invalid millis field : not in (1..999)");
-            }
-            if (null != micros)
-            {
-                int microsValue = micros.IntValueExact;
-                if (microsValue < MinMicros || microsValue > MaxMicros)
-                    throw new ArgumentException("Invalid micros field : not in (1..999)");
-            }
+            int count = seq.Count, pos = 0;
+            if (count < 0 || count > 3)
+                throw new ArgumentException("Bad sequence size: " + count, nameof(seq));
 
-            m_seconds = seconds;
-            m_millis = millis;
-            m_micros = micros;
-        }
+            m_seconds = Asn1Utilities.ReadOptional(seq, ref pos, DerInteger.GetOptional);
+            m_millis = Asn1Utilities.ReadOptionalContextTagged(seq, ref pos, 0, false, DerInteger.GetTagged);
+            m_micros = Asn1Utilities.ReadOptionalContextTagged(seq, ref pos, 1, false, DerInteger.GetTagged);
 
-        private Accuracy(Asn1Sequence seq)
-        {
-            DerInteger seconds = null;
-            DerInteger millis = null;
-            DerInteger micros = null;
+            if (pos != count)
+                throw new ArgumentException("Unexpected elements in sequence", nameof(seq));
 
-            for (int i = 0; i < seq.Count; ++i)
-            {
-                // seconds
-                if (seq[i] is DerInteger derInteger)
-                {
-                    seconds = derInteger;
-                }
-                else if (seq[i] is Asn1TaggedObject extra)
-                {
-                    switch (extra.TagNo)
-                    {
-                    case 0:
-                        millis = DerInteger.GetInstance(extra, false);
-                        int millisValue = millis.IntValueExact;
-                        if (millisValue < MinMillis || millisValue > MaxMillis)
-                            throw new ArgumentException("Invalid millis field : not in (1..999)");
-                        break;
-                    case 1:
-                        micros = DerInteger.GetInstance(extra, false);
-                        int microsValue = micros.IntValueExact;
-                        if (microsValue < MinMicros || microsValue > MaxMicros)
-                            throw new ArgumentException("Invalid micros field : not in (1..999)");
-                        break;
-                    default:
-                        throw new ArgumentException("Invalid tag number");
-                    }
-                }
-            }
+            Validate();
+        }
 
+        public Accuracy(DerInteger seconds, DerInteger millis, DerInteger micros)
+        {
             m_seconds = seconds;
             m_millis = millis;
             m_micros = micros;
+
+            Validate();
         }
 
         public DerInteger Seconds => m_seconds;
@@ -113,5 +92,21 @@ namespace Org.BouncyCastle.Asn1.Tsp
             v.AddOptionalTagged(false, 1, m_micros);
             return new DerSequence(v);
         }
+
+        private void Validate()
+        {
+            if (m_millis != null)
+            {
+                int millisValue = m_millis.IntValueExact;
+                if (millisValue < MinMillis || millisValue > MaxMillis)
+                    throw new ArgumentException("Invalid millis field : not in (1..999)");
+            }
+            if (m_micros != null)
+            {
+                int microsValue = m_micros.IntValueExact;
+                if (microsValue < MinMicros || microsValue > MaxMicros)
+                    throw new ArgumentException("Invalid micros field : not in (1..999)");
+            }
+        }
     }
 }
diff --git a/crypto/src/asn1/tsp/ArchiveTimeStamp.cs b/crypto/src/asn1/tsp/ArchiveTimeStamp.cs
index e1be303b7..82dcd4621 100644
--- a/crypto/src/asn1/tsp/ArchiveTimeStamp.cs
+++ b/crypto/src/asn1/tsp/ArchiveTimeStamp.cs
@@ -24,13 +24,6 @@ namespace Org.BouncyCastle.Asn1.Tsp
     public class ArchiveTimeStamp
         : Asn1Encodable
     {
-        /**
-         * Return an ArchiveTimestamp from the given object.
-         *
-         * @param obj the object we want converted.
-         * @return an ArchiveTimestamp instance, or null.
-         * @throws IllegalArgumentException if the object cannot be converted.
-         */
         public static ArchiveTimeStamp GetInstance(object obj)
         {
             if (obj == null)
@@ -40,16 +33,32 @@ namespace Org.BouncyCastle.Asn1.Tsp
             return new ArchiveTimeStamp(Asn1Sequence.GetInstance(obj));
         }
 
-        public static ArchiveTimeStamp GetInstance(Asn1TaggedObject taggedObject, bool declaredExplicit)
-        {
-            return new ArchiveTimeStamp(Asn1Sequence.GetInstance(taggedObject, declaredExplicit));
-        }
+        public static ArchiveTimeStamp GetInstance(Asn1TaggedObject taggedObject, bool declaredExplicit) =>
+            new ArchiveTimeStamp(Asn1Sequence.GetInstance(taggedObject, declaredExplicit));
+
+        public static ArchiveTimeStamp GetTagged(Asn1TaggedObject taggedObject, bool declaredExplicit) =>
+            new ArchiveTimeStamp(Asn1Sequence.GetTagged(taggedObject, declaredExplicit));
 
         private readonly AlgorithmIdentifier m_digestAlgorithm;
         private readonly Attributes m_attributes;
         private readonly Asn1Sequence m_reducedHashTree;
         private readonly ContentInfo m_timeStamp;
 
+        private ArchiveTimeStamp(Asn1Sequence seq)
+        {
+            int count = seq.Count, pos = 0;
+            if (count < 1 || count > 4)
+                throw new ArgumentException("Bad sequence size: " + count, nameof(seq));
+
+            m_digestAlgorithm = Asn1Utilities.ReadOptionalContextTagged(seq, ref pos, 0, false, AlgorithmIdentifier.GetTagged);
+            m_attributes = Asn1Utilities.ReadOptionalContextTagged(seq, ref pos, 1, false, Attributes.GetTagged);
+            m_reducedHashTree = Asn1Utilities.ReadOptionalContextTagged(seq, ref pos, 2, false, Asn1Sequence.GetTagged);
+            m_timeStamp = ContentInfo.GetInstance(seq[pos++]);
+
+            if (pos != count)
+                throw new ArgumentException("Unexpected elements in sequence", nameof(seq));
+        }
+
         public ArchiveTimeStamp(AlgorithmIdentifier digestAlgorithm, PartialHashtree[] reducedHashTree,
             ContentInfo timeStamp)
             : this(digestAlgorithm, null, reducedHashTree, timeStamp)
@@ -66,52 +75,8 @@ namespace Org.BouncyCastle.Asn1.Tsp
         {
             m_digestAlgorithm = digestAlgorithm;
             m_attributes = attributes;
-            if (reducedHashTree != null)
-            {
-                m_reducedHashTree = new DerSequence(reducedHashTree);
-            }
-            else
-            {
-                m_reducedHashTree = null;
-            }
-            m_timeStamp = timeStamp;
-        }
-
-        private ArchiveTimeStamp(Asn1Sequence sequence)
-        {
-            if (sequence.Count < 1 || sequence.Count > 4)
-                throw new ArgumentException("wrong sequence size in constructor: " + sequence.Count, nameof(sequence));
-
-            AlgorithmIdentifier digAlg = null;
-            Attributes attrs = null;
-            Asn1Sequence rHashTree = null;
-            for (int i = 0; i < sequence.Count - 1; i++)
-            {
-                Asn1Encodable obj = sequence[i];
-
-                if (obj is Asn1TaggedObject taggedObject)
-                {
-                    switch (taggedObject.TagNo)
-                    {
-                    case 0:
-                        digAlg = AlgorithmIdentifier.GetInstance(taggedObject, false);
-                        break;
-                    case 1:
-                        attrs = Attributes.GetInstance(taggedObject, false);
-                        break;
-                    case 2:
-                        rHashTree = Asn1Sequence.GetInstance(taggedObject, false);
-                        break;
-                    default:
-                        throw new ArgumentException("invalid tag no in constructor: " + taggedObject.TagNo);
-                    }
-                }
-            }
-
-            m_digestAlgorithm = digAlg;
-            m_attributes = attrs;
-            m_reducedHashTree = rHashTree;
-            m_timeStamp = ContentInfo.GetInstance(sequence[sequence.Count - 1]);
+            m_reducedHashTree = reducedHashTree == null ? null : new DerSequence(reducedHashTree);
+            m_timeStamp = timeStamp ?? throw new ArgumentNullException(nameof(timeStamp));
         }
 
         public virtual AlgorithmIdentifier GetDigestAlgorithmIdentifier() => m_digestAlgorithm
diff --git a/crypto/src/asn1/tsp/ArchiveTimeStampChain.cs b/crypto/src/asn1/tsp/ArchiveTimeStampChain.cs
index 6d274cf58..91aa6426e 100644
--- a/crypto/src/asn1/tsp/ArchiveTimeStampChain.cs
+++ b/crypto/src/asn1/tsp/ArchiveTimeStampChain.cs
@@ -29,33 +29,27 @@ namespace Org.BouncyCastle.Asn1.Tsp
             return new ArchiveTimeStampChain(Asn1Sequence.GetInstance(obj));
         }
 
-        public static ArchiveTimeStampChain GetInstance(Asn1TaggedObject taggedObject, bool declaredExplicit)
-        {
-            return new ArchiveTimeStampChain(Asn1Sequence.GetInstance(taggedObject, declaredExplicit));
-        }
+        public static ArchiveTimeStampChain GetInstance(Asn1TaggedObject taggedObject, bool declaredExplicit) =>
+            new ArchiveTimeStampChain(Asn1Sequence.GetInstance(taggedObject, declaredExplicit));
+
+        public static ArchiveTimeStampChain GetTagged(Asn1TaggedObject taggedObject, bool declaredExplicit) =>
+            new ArchiveTimeStampChain(Asn1Sequence.GetTagged(taggedObject, declaredExplicit));
 
         private readonly Asn1Sequence m_archiveTimeStamps;
 
-        public ArchiveTimeStampChain(ArchiveTimeStamp archiveTimeStamp)
+        private ArchiveTimeStampChain(Asn1Sequence seq)
         {
-            m_archiveTimeStamps = new DerSequence(archiveTimeStamp);
+            m_archiveTimeStamps = DerSequence.FromElements(seq.MapElements(ArchiveTimeStamp.GetInstance));
         }
 
-        public ArchiveTimeStampChain(ArchiveTimeStamp[] archiveTimeStamps)
+        public ArchiveTimeStampChain(ArchiveTimeStamp archiveTimeStamp)
         {
-            m_archiveTimeStamps = new DerSequence(archiveTimeStamps);
+            m_archiveTimeStamps = new DerSequence(archiveTimeStamp);
         }
 
-        private ArchiveTimeStampChain(Asn1Sequence sequence)
+        public ArchiveTimeStampChain(ArchiveTimeStamp[] archiveTimeStamps)
         {
-            Asn1EncodableVector vector = new Asn1EncodableVector(sequence.Count);
-
-            foreach (var element in sequence)
-            {
-                vector.Add(ArchiveTimeStamp.GetInstance(element));
-            }
-
-            m_archiveTimeStamps = new DerSequence(vector);
+            m_archiveTimeStamps = DerSequence.FromElements(archiveTimeStamps);
         }
 
         public virtual ArchiveTimeStamp[] GetArchiveTimestamps() =>
@@ -69,6 +63,9 @@ namespace Org.BouncyCastle.Asn1.Tsp
          */
         public virtual ArchiveTimeStampChain Append(ArchiveTimeStamp archiveTimeStamp)
         {
+            if (archiveTimeStamp == null)
+                throw new ArgumentNullException(nameof(archiveTimeStamp));
+
             Asn1EncodableVector v = new Asn1EncodableVector(m_archiveTimeStamps.Count + 1);
 
             foreach (var element in m_archiveTimeStamps)
diff --git a/crypto/src/asn1/tsp/ArchiveTimeStampSequence.cs b/crypto/src/asn1/tsp/ArchiveTimeStampSequence.cs
index 3c5d963e6..3ddeed4dd 100644
--- a/crypto/src/asn1/tsp/ArchiveTimeStampSequence.cs
+++ b/crypto/src/asn1/tsp/ArchiveTimeStampSequence.cs
@@ -29,23 +29,17 @@ namespace Org.BouncyCastle.Asn1.Tsp
             return new ArchiveTimeStampSequence(Asn1Sequence.GetInstance(obj));
         }
 
-        public static ArchiveTimeStampSequence GetInstance(Asn1TaggedObject taggedObject, bool declaredExplicit)
-        {
-            return new ArchiveTimeStampSequence(Asn1Sequence.GetInstance(taggedObject, declaredExplicit));
-        }
+        public static ArchiveTimeStampSequence GetInstance(Asn1TaggedObject taggedObject, bool declaredExplicit) =>
+            new ArchiveTimeStampSequence(Asn1Sequence.GetInstance(taggedObject, declaredExplicit));
+
+        public static ArchiveTimeStampSequence GetTagged(Asn1TaggedObject taggedObject, bool declaredExplicit) =>
+            new ArchiveTimeStampSequence(Asn1Sequence.GetTagged(taggedObject, declaredExplicit));
 
         private readonly Asn1Sequence m_archiveTimeStampChains;
 
-        private ArchiveTimeStampSequence(Asn1Sequence sequence)
+        private ArchiveTimeStampSequence(Asn1Sequence seq)
         {
-            Asn1EncodableVector vector = new Asn1EncodableVector(sequence.Count);
-
-            foreach (var element in sequence)
-            {
-                vector.Add(ArchiveTimeStampChain.GetInstance(element));
-            }
-
-            m_archiveTimeStampChains = new DerSequence(vector);
+            m_archiveTimeStampChains = DerSequence.FromElements(seq.MapElements(ArchiveTimeStampChain.GetInstance));
         }
 
         public ArchiveTimeStampSequence(ArchiveTimeStampChain archiveTimeStampChain)
@@ -55,7 +49,7 @@ namespace Org.BouncyCastle.Asn1.Tsp
 
         public ArchiveTimeStampSequence(ArchiveTimeStampChain[] archiveTimeStampChains)
         {
-            m_archiveTimeStampChains = new DerSequence(archiveTimeStampChains);
+            m_archiveTimeStampChains = DerSequence.FromElements(archiveTimeStampChains);
         }
 
         /**
@@ -76,6 +70,9 @@ namespace Org.BouncyCastle.Asn1.Tsp
          */
         public virtual ArchiveTimeStampSequence Append(ArchiveTimeStampChain chain)
         {
+            if (chain == null)
+                throw new ArgumentNullException(nameof(chain));
+
             Asn1EncodableVector v = new Asn1EncodableVector(m_archiveTimeStampChains.Count + 1);
 
             foreach (var element in m_archiveTimeStampChains)
diff --git a/crypto/src/asn1/tsp/CryptoInfos.cs b/crypto/src/asn1/tsp/CryptoInfos.cs
index b99afad76..44b3cdbc8 100644
--- a/crypto/src/asn1/tsp/CryptoInfos.cs
+++ b/crypto/src/asn1/tsp/CryptoInfos.cs
@@ -19,10 +19,11 @@ namespace Org.BouncyCastle.Asn1.Tsp
             return new CryptoInfos(Asn1Sequence.GetInstance(obj));
         }
 
-        public static CryptoInfos GetInstance(Asn1TaggedObject taggedObject, bool declaredExplicit)
-        {
-            return new CryptoInfos(Asn1Sequence.GetInstance(taggedObject, declaredExplicit));
-        }
+        public static CryptoInfos GetInstance(Asn1TaggedObject taggedObject, bool declaredExplicit) =>
+            new CryptoInfos(Asn1Sequence.GetInstance(taggedObject, declaredExplicit));
+
+        public static CryptoInfos GetTagged(Asn1TaggedObject taggedObject, bool declaredExplicit) =>
+            new CryptoInfos(Asn1Sequence.GetTagged(taggedObject, declaredExplicit));
 
         private readonly Asn1Sequence m_attributes;
 
@@ -33,7 +34,7 @@ namespace Org.BouncyCastle.Asn1.Tsp
 
         public CryptoInfos(Asn1.Cms.Attribute[] attrs)
         {
-            m_attributes = new DerSequence(attrs);
+            m_attributes = DerSequence.FromElements(attrs);
         }
 
         public virtual Asn1.Cms.Attribute[] GetAttributes() => m_attributes.MapElements(Asn1.Cms.Attribute.GetInstance);
diff --git a/crypto/src/asn1/tsp/EncryptionInfo.cs b/crypto/src/asn1/tsp/EncryptionInfo.cs
index d8e285a0c..af3741ca9 100644
--- a/crypto/src/asn1/tsp/EncryptionInfo.cs
+++ b/crypto/src/asn1/tsp/EncryptionInfo.cs
@@ -37,10 +37,11 @@ namespace Org.BouncyCastle.Asn1.Tsp
             return new EncryptionInfo(Asn1Sequence.GetInstance(obj));
         }
 
-        public static EncryptionInfo GetInstance(Asn1TaggedObject taggedObject, bool declaredExplicit)
-        {
-            return new EncryptionInfo(Asn1Sequence.GetInstance(taggedObject, declaredExplicit));
-        }
+        public static EncryptionInfo GetInstance(Asn1TaggedObject taggedObject, bool declaredExplicit) =>
+            new EncryptionInfo(Asn1Sequence.GetInstance(taggedObject, declaredExplicit));
+
+        public static EncryptionInfo GetTagged(Asn1TaggedObject taggedObject, bool declaredExplicit) =>
+            new EncryptionInfo(Asn1Sequence.GetTagged(taggedObject, declaredExplicit));
 
         /**
          * The OID for EncryptionInfo type.
@@ -52,19 +53,20 @@ namespace Org.BouncyCastle.Asn1.Tsp
          */
         private readonly Asn1Encodable m_encryptionInfoValue;
 
-        private EncryptionInfo(Asn1Sequence sequence)
+        private EncryptionInfo(Asn1Sequence seq)
         {
-            if (sequence.Count != 2)
-                throw new ArgumentException("wrong sequence size in constructor: " + sequence.Count, nameof(sequence));
+            int count = seq.Count;
+            if (count != 2)
+                throw new ArgumentException("Bad sequence size: " + count, nameof(seq));
 
-            m_encryptionInfoType = DerObjectIdentifier.GetInstance(sequence[0]);
-            m_encryptionInfoValue = sequence[1];
+            m_encryptionInfoType = DerObjectIdentifier.GetInstance(seq[0]);
+            m_encryptionInfoValue = seq[1];
         }
 
         public EncryptionInfo(DerObjectIdentifier encryptionInfoType, Asn1Encodable encryptionInfoValue)
         {
-            m_encryptionInfoType = encryptionInfoType;
-            m_encryptionInfoValue = encryptionInfoValue;
+            m_encryptionInfoType = encryptionInfoType ?? throw new ArgumentNullException(nameof(encryptionInfoType));
+            m_encryptionInfoValue = encryptionInfoValue ?? throw new ArgumentNullException(nameof(encryptionInfoValue));
         }
 
         public virtual DerObjectIdentifier EncryptionInfoType => m_encryptionInfoType;
diff --git a/crypto/src/asn1/tsp/EvidenceRecord.cs b/crypto/src/asn1/tsp/EvidenceRecord.cs
index 9957b1050..681bd4028 100644
--- a/crypto/src/asn1/tsp/EvidenceRecord.cs
+++ b/crypto/src/asn1/tsp/EvidenceRecord.cs
@@ -1,7 +1,6 @@
 using System;
 
 using Org.BouncyCastle.Asn1.X509;
-using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Asn1.Tsp
 {
@@ -46,10 +45,11 @@ namespace Org.BouncyCastle.Asn1.Tsp
             return new EvidenceRecord(Asn1Sequence.GetInstance(obj));
         }
 
-        public static EvidenceRecord GetInstance(Asn1TaggedObject taggedObject, bool declaredExplicit)
-        {
-            return new EvidenceRecord(Asn1Sequence.GetInstance(taggedObject, declaredExplicit));
-        }
+        public static EvidenceRecord GetInstance(Asn1TaggedObject taggedObject, bool declaredExplicit) =>
+            new EvidenceRecord(Asn1Sequence.GetInstance(taggedObject, declaredExplicit));
+
+        public static EvidenceRecord GetTagged(Asn1TaggedObject taggedObject, bool declaredExplicit) =>
+            new EvidenceRecord(Asn1Sequence.GetTagged(taggedObject, declaredExplicit));
 
         private readonly DerInteger m_version;
         private readonly Asn1Sequence m_digestAlgorithms;
@@ -129,47 +129,34 @@ namespace Org.BouncyCastle.Asn1.Tsp
             m_archiveTimeStampSequence = archiveTimeStampSequence;
         }
 
-        private EvidenceRecord(Asn1Sequence sequence)
+        private EvidenceRecord(Asn1Sequence seq)
         {
-            if (sequence.Count < 3 && sequence.Count > 5)
-                throw new ArgumentException("wrong sequence size in constructor: " + sequence.Count, nameof(sequence));
-
-            DerInteger versionNumber = DerInteger.GetInstance(sequence[0]);
-            if (!versionNumber.HasValue(1))
-                throw new ArgumentException("incompatible version");
+            int count = seq.Count, pos = 0;
+            if (count < 3 || count > 5)
+                throw new ArgumentException("Bad sequence size: " + count, nameof(seq));
 
-            m_version = versionNumber;
+            m_version = DerInteger.GetInstance(seq[pos++]);
+            m_digestAlgorithms = Asn1Sequence.GetInstance(seq[pos++]);
+            m_cryptoInfos = Asn1Utilities.ReadContextTagged(seq, ref pos, 0, false, CryptoInfos.GetTagged);
+            m_encryptionInfo = Asn1Utilities.ReadContextTagged(seq, ref pos, 1, false, EncryptionInfo.GetTagged);
+            m_archiveTimeStampSequence = ArchiveTimeStampSequence.GetInstance(seq[pos++]);
 
-            m_digestAlgorithms = Asn1Sequence.GetInstance(sequence[1]);
-            for (int i = 2; i != sequence.Count - 1; i++)
-            {
-                Asn1Encodable element = sequence[i];
+            if (pos != count)
+                throw new ArgumentException("Unexpected elements in sequence", nameof(seq));
 
-                if (element is Asn1TaggedObject asn1TaggedObject)
-                {
-                    switch (asn1TaggedObject.TagNo)
-                    {
-                    case 0:
-                        m_cryptoInfos = CryptoInfos.GetInstance(asn1TaggedObject, false);
-                        break;
-                    case 1:
-                        m_encryptionInfo = EncryptionInfo.GetInstance(asn1TaggedObject, false);
-                        break;
-                    default:
-                        throw new ArgumentException("unknown tag in GetInstance: " + asn1TaggedObject.TagNo);
-                    }
-                }
-                else
-                {
-                    throw new ArgumentException("unknown object in GetInstance: " + Platform.GetTypeName(element));
-                }
-            }
-            m_archiveTimeStampSequence = ArchiveTimeStampSequence.GetInstance(sequence[sequence.Count - 1]);
+            if (!m_version.HasValue(1))
+                throw new ArgumentException("incompatible version");
         }
 
+        public virtual DerInteger Version => m_version;
+
         public virtual AlgorithmIdentifier[] GetDigestAlgorithms() =>
             m_digestAlgorithms.MapElements(AlgorithmIdentifier.GetInstance);
 
+        public virtual CryptoInfos CryptoInfos => m_cryptoInfos;
+
+        public virtual EncryptionInfo EncryptionInfo => m_encryptionInfo;
+
         public virtual ArchiveTimeStampSequence ArchiveTimeStampSequence => m_archiveTimeStampSequence;
 
         /**
@@ -206,8 +193,7 @@ namespace Org.BouncyCastle.Asn1.Tsp
         public override Asn1Object ToAsn1Object()
         {
             Asn1EncodableVector vector = new Asn1EncodableVector(5);
-            vector.Add(m_version);
-            vector.Add(m_digestAlgorithms);
+            vector.Add(m_version, m_digestAlgorithms);
             vector.AddOptionalTagged(false, 0, m_cryptoInfos);
             vector.AddOptionalTagged(false, 1, m_encryptionInfo);
             vector.Add(m_archiveTimeStampSequence);
diff --git a/crypto/src/asn1/tsp/MessageImprint.cs b/crypto/src/asn1/tsp/MessageImprint.cs
index 0be856048..403bed09a 100644
--- a/crypto/src/asn1/tsp/MessageImprint.cs
+++ b/crypto/src/asn1/tsp/MessageImprint.cs
@@ -1,11 +1,10 @@
 using System;
 
 using Org.BouncyCastle.Asn1.X509;
-using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Asn1.Tsp
 {
-	public class MessageImprint
+    public class MessageImprint
 		: Asn1Encodable
 	{
         public static MessageImprint GetInstance(object obj)
@@ -17,32 +16,36 @@ namespace Org.BouncyCastle.Asn1.Tsp
             return new MessageImprint(Asn1Sequence.GetInstance(obj));
         }
 
-		public static MessageImprint GetInstance(Asn1TaggedObject taggedObject, bool declaredExplicit)
-		{
-            return new MessageImprint(Asn1Sequence.GetInstance(taggedObject, declaredExplicit));
-        }
+		public static MessageImprint GetInstance(Asn1TaggedObject taggedObject, bool declaredExplicit) =>
+            new MessageImprint(Asn1Sequence.GetInstance(taggedObject, declaredExplicit));
+
+        public static MessageImprint GetTagged(Asn1TaggedObject taggedObject, bool declaredExplicit) =>
+            new MessageImprint(Asn1Sequence.GetTagged(taggedObject, declaredExplicit));
 
         private readonly AlgorithmIdentifier m_hashAlgorithm;
-        private readonly byte[] m_hashedMessage;
+        private readonly Asn1OctetString m_hashedMessage;
 
         private MessageImprint(Asn1Sequence seq)
 		{
-			if (seq.Count != 2)
-				throw new ArgumentException("Wrong number of elements in sequence", nameof(seq));
+            int count = seq.Count;
+            if (count != 2)
+                throw new ArgumentException("Bad sequence size: " + count, nameof(seq));
 
 			m_hashAlgorithm = AlgorithmIdentifier.GetInstance(seq[0]);
-			m_hashedMessage = Asn1OctetString.GetInstance(seq[1]).GetOctets();
+			m_hashedMessage = Asn1OctetString.GetInstance(seq[1]);
 		}
 
 		public MessageImprint(AlgorithmIdentifier hashAlgorithm, byte[] hashedMessage)
 		{
-			m_hashAlgorithm = hashAlgorithm;
-			m_hashedMessage = hashedMessage;
+			m_hashAlgorithm = hashAlgorithm ?? throw new ArgumentNullException(nameof(hashAlgorithm));
+			m_hashedMessage = new DerOctetString(hashedMessage);
 		}
 
 		public AlgorithmIdentifier HashAlgorithm => m_hashAlgorithm;
 
-		public byte[] GetHashedMessage() => m_hashedMessage;
+		public Asn1OctetString HashedMessage => m_hashedMessage;
+
+		public byte[] GetHashedMessage() => m_hashedMessage.GetOctets();
 
 		/**
 		 * <pre>
@@ -51,9 +54,6 @@ namespace Org.BouncyCastle.Asn1.Tsp
 		 *       hashedMessage                OCTET STRING  }
 		 * </pre>
 		 */
-		public override Asn1Object ToAsn1Object()
-		{
-			return new DerSequence(m_hashAlgorithm, new DerOctetString(m_hashedMessage));
-		}
+		public override Asn1Object ToAsn1Object() => new DerSequence(m_hashAlgorithm, m_hashedMessage);
 	}
 }
diff --git a/crypto/src/asn1/tsp/PartialHashtree.cs b/crypto/src/asn1/tsp/PartialHashtree.cs
index dea7c9e37..cfc8b18bd 100644
--- a/crypto/src/asn1/tsp/PartialHashtree.cs
+++ b/crypto/src/asn1/tsp/PartialHashtree.cs
@@ -31,10 +31,11 @@ namespace Org.BouncyCastle.Asn1.Tsp
             return new PartialHashtree(Asn1Sequence.GetInstance(obj));
         }
 
-        public static PartialHashtree GetInstance(Asn1TaggedObject taggedObject, bool declaredExplicit)
-        {
-            return new PartialHashtree(Asn1Sequence.GetInstance(taggedObject, declaredExplicit));
-        }
+        public static PartialHashtree GetInstance(Asn1TaggedObject taggedObject, bool declaredExplicit) =>
+            new PartialHashtree(Asn1Sequence.GetInstance(taggedObject, declaredExplicit));
+
+        public static PartialHashtree GetTagged(Asn1TaggedObject taggedObject, bool declaredExplicit) =>
+            new PartialHashtree(Asn1Sequence.GetTagged(taggedObject, declaredExplicit));
 
         /**
          * Hash values that constitute the hash tree, as ASN.1 Octet Strings.
diff --git a/crypto/src/asn1/tsp/TSTInfo.cs b/crypto/src/asn1/tsp/TSTInfo.cs
index 80302975f..14fac55c7 100644
--- a/crypto/src/asn1/tsp/TSTInfo.cs
+++ b/crypto/src/asn1/tsp/TSTInfo.cs
@@ -4,7 +4,7 @@ using Org.BouncyCastle.Asn1.X509;
 
 namespace Org.BouncyCastle.Asn1.Tsp
 {
-	public class TstInfo
+    public class TstInfo
 		: Asn1Encodable
 	{
         public static TstInfo GetInstance(object obj)
@@ -16,13 +16,14 @@ namespace Org.BouncyCastle.Asn1.Tsp
             return new TstInfo(Asn1Sequence.GetInstance(obj));
         }
 
-        public static TstInfo GetInstance(Asn1TaggedObject taggedObject, bool declaredExplicit)
-        {
-            return new TstInfo(Asn1Sequence.GetInstance(taggedObject, declaredExplicit));
-        }
+        public static TstInfo GetInstance(Asn1TaggedObject taggedObject, bool declaredExplicit) =>
+            new TstInfo(Asn1Sequence.GetInstance(taggedObject, declaredExplicit));
+
+        public static TstInfo GetTagged(Asn1TaggedObject taggedObject, bool declaredExplicit) =>
+            new TstInfo(Asn1Sequence.GetTagged(taggedObject, declaredExplicit));
 
         private readonly DerInteger m_version;
-		private readonly DerObjectIdentifier m_tsaPolicyID;
+		private readonly DerObjectIdentifier m_policy;
 		private readonly MessageImprint m_messageImprint;
 		private readonly DerInteger m_serialNumber;
 		private readonly Asn1GeneralizedTime m_genTime;
@@ -34,78 +35,37 @@ namespace Org.BouncyCastle.Asn1.Tsp
 
 		private TstInfo(Asn1Sequence seq)
 		{
-			var e = seq.GetEnumerator();
-
-			// version
-			e.MoveNext();
-			m_version = DerInteger.GetInstance(e.Current);
-
-			// tsaPolicy
-			e.MoveNext();
-			m_tsaPolicyID = DerObjectIdentifier.GetInstance(e.Current);
-
-			// messageImprint
-			e.MoveNext();
-			m_messageImprint = MessageImprint.GetInstance(e.Current);
-
-			// serialNumber
-			e.MoveNext();
-			m_serialNumber = DerInteger.GetInstance(e.Current);
-
-			// genTime
-			e.MoveNext();
-			m_genTime = Asn1GeneralizedTime.GetInstance(e.Current);
-
-			// default for ordering
-			m_ordering = DerBoolean.False;
-
-			while (e.MoveNext())
-			{
-				Asn1Object o = (Asn1Object) e.Current;
-
-				if (o is Asn1TaggedObject tagged)
-				{
-					switch (tagged.TagNo)
-					{
-					case 0:
-						m_tsa = GeneralName.GetInstance(tagged, true);
-						break;
-					case 1:
-						m_extensions = X509Extensions.GetInstance(tagged, false);
-						break;
-					default:
-						throw new ArgumentException("Unknown tag value " + tagged.TagNo);
-					}
-				}
-
-				if (o is Asn1Sequence)
-				{
-					m_accuracy = Accuracy.GetInstance(o);
-				}
-
-				if (o is DerBoolean)
-				{
-					m_ordering = DerBoolean.GetInstance(o);
-				}
-
-				if (o is DerInteger)
-				{
-					m_nonce = DerInteger.GetInstance(o);
-				}
-			}
-		}
+            int count = seq.Count, pos = 0;
+            if (count < 5 || count > 10)
+                throw new ArgumentException("Bad sequence size: " + count, nameof(seq));
+
+            m_version = DerInteger.GetInstance(seq[pos++]);
+            m_policy = DerObjectIdentifier.GetInstance(seq[pos++]);
+            m_messageImprint = MessageImprint.GetInstance(seq[pos++]);
+            m_serialNumber = DerInteger.GetInstance(seq[pos++]);
+            m_genTime = Asn1GeneralizedTime.GetInstance(seq[pos++]);
+            m_accuracy = Asn1Utilities.ReadOptional(seq, ref pos, Accuracy.GetOptional);
+            m_ordering = Asn1Utilities.ReadOptional(seq, ref pos, DerBoolean.GetOptional) ?? DerBoolean.False;
+            m_nonce = Asn1Utilities.ReadOptional(seq, ref pos, DerInteger.GetOptional);
+            m_tsa = Asn1Utilities.ReadOptionalContextTagged(seq, ref pos, 0, true, GeneralName.GetTagged); // CHOICE
+            m_extensions = Asn1Utilities.ReadOptionalContextTagged(seq, ref pos, 1, false, X509Extensions.GetTagged);
+
+            if (pos != count)
+                throw new ArgumentException("Unexpected elements in sequence", nameof(seq));
+        }
 
+        // TODO[api] 'tsaPolicyId' => 'policy'
         public TstInfo(DerObjectIdentifier tsaPolicyId, MessageImprint messageImprint, DerInteger serialNumber,
             Asn1GeneralizedTime genTime, Accuracy accuracy, DerBoolean ordering, DerInteger nonce, GeneralName tsa,
             X509Extensions extensions)
         {
             m_version = DerInteger.One;
-            m_tsaPolicyID = tsaPolicyId;
-            m_messageImprint = messageImprint;
-            m_serialNumber = serialNumber;
-            m_genTime = genTime;
+            m_policy = tsaPolicyId ?? throw new ArgumentNullException(nameof(tsaPolicyId));
+            m_messageImprint = messageImprint ?? throw new ArgumentNullException(nameof(messageImprint));
+            m_serialNumber = serialNumber ?? throw new ArgumentNullException(nameof(serialNumber));
+            m_genTime = genTime ?? throw new ArgumentNullException(nameof(genTime));
             m_accuracy = accuracy;
-            m_ordering = ordering;
+            m_ordering = ordering ?? DerBoolean.False;
             m_nonce = nonce;
             m_tsa = tsa;
             m_extensions = extensions;
@@ -115,7 +75,7 @@ namespace Org.BouncyCastle.Asn1.Tsp
 
         public MessageImprint MessageImprint => m_messageImprint;
 
-        public DerObjectIdentifier Policy => m_tsaPolicyID;
+        public DerObjectIdentifier Policy => m_policy;
 
         public DerInteger SerialNumber => m_serialNumber;
 
@@ -157,16 +117,16 @@ namespace Org.BouncyCastle.Asn1.Tsp
         public override Asn1Object ToAsn1Object()
         {
             Asn1EncodableVector v = new Asn1EncodableVector(10);
-            v.Add(m_version, m_tsaPolicyID, m_messageImprint, m_serialNumber, m_genTime);
+            v.Add(m_version, m_policy, m_messageImprint, m_serialNumber, m_genTime);
             v.AddOptional(m_accuracy);
 
-            if (m_ordering != null && m_ordering.IsTrue)
+            if (m_ordering.IsTrue)
             {
                 v.Add(m_ordering);
             }
 
             v.AddOptional(m_nonce);
-            v.AddOptionalTagged(true, 0, m_tsa);
+            v.AddOptionalTagged(true, 0, m_tsa); // CHOICE
             v.AddOptionalTagged(false, 1, m_extensions);
             return new DerSequence(v);
         }
diff --git a/crypto/src/asn1/tsp/TimeStampReq.cs b/crypto/src/asn1/tsp/TimeStampReq.cs
index aa9621007..e87b24087 100644
--- a/crypto/src/asn1/tsp/TimeStampReq.cs
+++ b/crypto/src/asn1/tsp/TimeStampReq.cs
@@ -1,16 +1,15 @@
 using System;
 
 using Org.BouncyCastle.Asn1.X509;
-using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Asn1.Tsp
 {
-	public class TimeStampReq
+    public class TimeStampReq
 		: Asn1Encodable
 	{
 		private readonly DerInteger m_version;
 		private readonly MessageImprint m_messageImprint;
-		private readonly DerObjectIdentifier m_tsaPolicy;
+		private readonly DerObjectIdentifier m_reqPolicy;
 		private readonly DerInteger m_nonce;
 		private readonly DerBoolean m_certReq;
 		private readonly X509Extensions m_extensions;
@@ -24,60 +23,40 @@ namespace Org.BouncyCastle.Asn1.Tsp
             return new TimeStampReq(Asn1Sequence.GetInstance(obj));
         }
 
-		public static TimeStampReq GetInstance(Asn1TaggedObject taggedObject, bool declaredExplicit)
-		{
-            return new TimeStampReq(Asn1Sequence.GetInstance(taggedObject, declaredExplicit));
-        }
+		public static TimeStampReq GetInstance(Asn1TaggedObject taggedObject, bool declaredExplicit) =>
+            new TimeStampReq(Asn1Sequence.GetInstance(taggedObject, declaredExplicit));
+
+        public static TimeStampReq GetTagged(Asn1TaggedObject taggedObject, bool declaredExplicit) =>
+            new TimeStampReq(Asn1Sequence.GetTagged(taggedObject, declaredExplicit));
 
         private TimeStampReq(Asn1Sequence seq)
 		{
-			int nbObjects = seq.Count;
-			int seqStart = 0;
-
-			// version
-			m_version = DerInteger.GetInstance(seq[seqStart++]);
-
-			// messageImprint
-			m_messageImprint = MessageImprint.GetInstance(seq[seqStart++]);
-
-			for (int opt = seqStart; opt < nbObjects; opt++)
-			{
-				// tsaPolicy
-				if (seq[opt] is DerObjectIdentifier oid)
-				{
-					m_tsaPolicy = oid;
-				}
-				// nonce
-				else if (seq[opt] is DerInteger derInteger)
-				{
-					m_nonce = derInteger;
-				}
-				// certReq
-				else if (seq[opt] is DerBoolean derBoolean)
-				{
-					m_certReq = derBoolean;
-				}
-				// extensions
-				else if (seq[opt] is Asn1TaggedObject tagged)
-				{
-					if (tagged.TagNo == 0)
-					{
-						m_extensions = X509Extensions.GetInstance(tagged, false);
-					}
-				}
-			}
+            int count = seq.Count, pos = 0;
+            if (count < 2 || count > 6)
+                throw new ArgumentException("Bad sequence size: " + count, nameof(seq));
+
+			m_version = DerInteger.GetInstance(seq[pos++]);
+			m_messageImprint = MessageImprint.GetInstance(seq[pos++]);
+			m_reqPolicy = Asn1Utilities.ReadOptional(seq, ref pos, DerObjectIdentifier.GetOptional);
+            m_nonce = Asn1Utilities.ReadOptional(seq, ref pos, DerInteger.GetOptional);
+            m_certReq = Asn1Utilities.ReadOptional(seq, ref pos, DerBoolean.GetOptional) ?? DerBoolean.False;
+			m_extensions = Asn1Utilities.ReadOptionalContextTagged(seq, ref pos, 0, false, X509Extensions.GetTagged);
+
+            if (pos != count)
+                throw new ArgumentException("Unexpected elements in sequence", nameof(seq));
 		}
 
+		// TODO[api] 'tsaPolicy' => 'reqPolicy'
         public TimeStampReq(MessageImprint messageImprint, DerObjectIdentifier tsaPolicy, DerInteger nonce,
             DerBoolean certReq, X509Extensions extensions)
         {
             // default
             m_version = DerInteger.One;
 
-            m_messageImprint = messageImprint;
-            m_tsaPolicy = tsaPolicy;
+            m_messageImprint = messageImprint ?? throw new ArgumentNullException(nameof(messageImprint));
+            m_reqPolicy = tsaPolicy;
             m_nonce = nonce;
-            m_certReq = certReq;
+            m_certReq = certReq ?? DerBoolean.False;
             m_extensions = extensions;
         }
 
@@ -85,7 +64,7 @@ namespace Org.BouncyCastle.Asn1.Tsp
 
 		public MessageImprint MessageImprint => m_messageImprint;
 
-		public DerObjectIdentifier ReqPolicy => m_tsaPolicy;
+		public DerObjectIdentifier ReqPolicy => m_reqPolicy;
 
 		public DerInteger Nonce => m_nonce;
 
@@ -111,9 +90,9 @@ namespace Org.BouncyCastle.Asn1.Tsp
         {
             Asn1EncodableVector v = new Asn1EncodableVector(6);
 			v.Add(m_version, m_messageImprint);
-            v.AddOptional(m_tsaPolicy, m_nonce);
+            v.AddOptional(m_reqPolicy, m_nonce);
 
-            if (m_certReq != null && m_certReq.IsTrue)
+            if (m_certReq.IsTrue)
             {
                 v.Add(m_certReq);
             }
diff --git a/crypto/src/asn1/tsp/TimeStampResp.cs b/crypto/src/asn1/tsp/TimeStampResp.cs
index cc9c2ed4d..3d8fb63f9 100644
--- a/crypto/src/asn1/tsp/TimeStampResp.cs
+++ b/crypto/src/asn1/tsp/TimeStampResp.cs
@@ -2,11 +2,10 @@ using System;
 
 using Org.BouncyCastle.Asn1.Cmp;
 using Org.BouncyCastle.Asn1.Cms;
-using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Asn1.Tsp
 {
-	public class TimeStampResp
+    public class TimeStampResp
 		: Asn1Encodable
 	{
         public static TimeStampResp GetInstance(object obj)
@@ -18,17 +17,22 @@ namespace Org.BouncyCastle.Asn1.Tsp
             return new TimeStampResp(Asn1Sequence.GetInstance(obj));
         }
 
-		public static TimeStampResp GetInstance(Asn1TaggedObject taggedObject, bool declaredExplicit)
-		{
-            return new TimeStampResp(Asn1Sequence.GetInstance(taggedObject, declaredExplicit));
-        }
+		public static TimeStampResp GetInstance(Asn1TaggedObject taggedObject, bool declaredExplicit) =>
+            new TimeStampResp(Asn1Sequence.GetInstance(taggedObject, declaredExplicit));
+
+        public static TimeStampResp GetTagged(Asn1TaggedObject taggedObject, bool declaredExplicit) =>
+            new TimeStampResp(Asn1Sequence.GetTagged(taggedObject, declaredExplicit));
 
         private readonly PkiStatusInfo m_pkiStatusInfo;
         private readonly ContentInfo m_timeStampToken;
 
         private TimeStampResp(Asn1Sequence seq)
 		{
-			m_pkiStatusInfo = PkiStatusInfo.GetInstance(seq[0]);
+            int count = seq.Count;
+            if (count < 1 || count > 2)
+                throw new ArgumentException("Bad sequence size: " + count, nameof(seq));
+
+            m_pkiStatusInfo = PkiStatusInfo.GetInstance(seq[0]);
 
 			if (seq.Count > 1)
 			{
@@ -38,7 +42,7 @@ namespace Org.BouncyCastle.Asn1.Tsp
 
 		public TimeStampResp(PkiStatusInfo pkiStatusInfo, ContentInfo timeStampToken)
 		{
-			m_pkiStatusInfo = pkiStatusInfo;
+			m_pkiStatusInfo = pkiStatusInfo ?? throw new ArgumentNullException(nameof(pkiStatusInfo));
 			m_timeStampToken = timeStampToken;
 		}
 
@@ -55,10 +59,9 @@ namespace Org.BouncyCastle.Asn1.Tsp
 		 */
         public override Asn1Object ToAsn1Object()
         {
-            Asn1EncodableVector v = new Asn1EncodableVector(2);
-			v.Add(m_pkiStatusInfo);
-            v.AddOptional(m_timeStampToken);
-            return new DerSequence(v);
+            return m_timeStampToken == null
+                ?  new DerSequence(m_pkiStatusInfo)
+                :  new DerSequence(m_pkiStatusInfo, m_timeStampToken);
         }
 	}
 }