summary refs log tree commit diff
diff options
context:
space:
mode:
authorPeter Dettman <peter.dettman@bouncycastle.org>2023-07-18 18:29:42 +0700
committerPeter Dettman <peter.dettman@bouncycastle.org>2023-07-18 18:29:42 +0700
commit8119dba914a3aa08cd1ce7b24b757e95269d3aaf (patch)
tree26a50fe08c3d9aff219776675a0dd015f38f38e2
parentCustom encoding classes for tagged objects (diff)
downloadBouncyCastle.NET-ed25519-8119dba914a3aa08cd1ce7b24b757e95269d3aaf.tar.xz
Asn1.Tsp updates from bc-java
-rw-r--r--crypto/src/asn1/DerBitString.cs14
-rw-r--r--crypto/src/asn1/cms/Attributes.cs44
-rw-r--r--crypto/src/asn1/cms/OriginatorIdentifierOrKey.cs73
-rw-r--r--crypto/src/asn1/tsp/Accuracy.cs108
-rw-r--r--crypto/src/asn1/tsp/ArchiveTimeStamp.cs176
-rw-r--r--crypto/src/asn1/tsp/ArchiveTimeStampChain.cs86
-rw-r--r--crypto/src/asn1/tsp/ArchiveTimeStampSequence.cs93
-rw-r--r--crypto/src/asn1/tsp/CryptoInfos.cs43
-rw-r--r--crypto/src/asn1/tsp/EncryptionInfo.cs76
-rw-r--r--crypto/src/asn1/tsp/EvidenceRecord.cs217
-rw-r--r--crypto/src/asn1/tsp/MessageImprint.cs44
-rw-r--r--crypto/src/asn1/tsp/PartialHashtree.cs91
-rw-r--r--crypto/src/asn1/tsp/TSTInfo.cs163
-rw-r--r--crypto/src/asn1/tsp/TimeStampReq.cs102
-rw-r--r--crypto/src/asn1/tsp/TimeStampResp.cs45
15 files changed, 1032 insertions, 343 deletions
diff --git a/crypto/src/asn1/DerBitString.cs b/crypto/src/asn1/DerBitString.cs
index caa97933f..f543a968d 100644
--- a/crypto/src/asn1/DerBitString.cs
+++ b/crypto/src/asn1/DerBitString.cs
@@ -31,11 +31,6 @@ namespace Org.BouncyCastle.Asn1
         private static readonly char[] table
 			= { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
 
-        /**
-		 * return a Bit string from the passed in object
-		 *
-		 * @exception ArgumentException if the object cannot be converted.
-		 */
 		public static DerBitString GetInstance(object obj)
 		{
             if (obj == null)
@@ -65,15 +60,6 @@ namespace Org.BouncyCastle.Asn1
             throw new ArgumentException("illegal object in GetInstance: " + Platform.GetTypeName(obj));
 		}
 
-		/**
-		 * return a Bit string from a tagged object.
-		 *
-		 * @param obj the tagged object holding the object we want
-		 * @param explicitly true if the object is meant to be explicitly
-		 *              tagged false otherwise.
-		 * @exception ArgumentException if the tagged object cannot
-		 *               be converted.
-		 */
         public static DerBitString GetInstance(Asn1TaggedObject obj, bool isExplicit)
         {
             return (DerBitString)Meta.Instance.GetContextInstance(obj, isExplicit);
diff --git a/crypto/src/asn1/cms/Attributes.cs b/crypto/src/asn1/cms/Attributes.cs
index 5b6b13034..010684158 100644
--- a/crypto/src/asn1/cms/Attributes.cs
+++ b/crypto/src/asn1/cms/Attributes.cs
@@ -5,41 +5,34 @@ namespace Org.BouncyCastle.Asn1.Cms
     public class Attributes
         : Asn1Encodable
     {
-        private readonly Asn1Set attributes;
-
-        private Attributes(Asn1Set attributes)
+        public static Attributes GetInstance(object obj)
         {
-            this.attributes = attributes;
+            if (obj == null)
+                return null;
+            if (obj is Attributes attributes)
+                return attributes;
+            return new Attributes(Asn1Set.GetInstance(obj));
         }
 
-        public Attributes(Asn1EncodableVector v)
+        public static Attributes GetInstance(Asn1TaggedObject taggedObject, bool declaredExplicit)
         {
-            attributes = new BerSet(v);
+            return GetInstance(Asn1Set.GetInstance(taggedObject, declaredExplicit));
         }
 
-        public static Attributes GetInstance(object obj)
-        {
-            if (obj is Attributes)
-                return (Attributes)obj;
+        private readonly Asn1Set m_attributes;
 
-            if (obj != null)
-                return new Attributes(Asn1Set.GetInstance(obj));
-
-            return null;
+        private Attributes(Asn1Set attributes)
+        {
+            m_attributes = attributes;
         }
 
-        public virtual Attribute[] GetAttributes()
+        public Attributes(Asn1EncodableVector v)
         {
-            Attribute[] rv = new Attribute[attributes.Count];
-
-            for (int i = 0; i != rv.Length; i++)
-            {
-                rv[i] = Attribute.GetInstance(attributes[i]);
-            }
-
-            return rv;
+            m_attributes = new BerSet(v);
         }
 
+        public virtual Attribute[] GetAttributes() => m_attributes.MapElements(Attribute.GetInstance);
+
         /**
          * <pre>
          * Attributes ::=
@@ -47,9 +40,6 @@ namespace Org.BouncyCastle.Asn1.Cms
          * </pre>
          * @return
          */
-        public override Asn1Object ToAsn1Object()
-        {
-            return attributes;
-        }
+        public override Asn1Object ToAsn1Object() => m_attributes;
     }
 }
diff --git a/crypto/src/asn1/cms/OriginatorIdentifierOrKey.cs b/crypto/src/asn1/cms/OriginatorIdentifierOrKey.cs
index 6b4c0488e..12b1f518d 100644
--- a/crypto/src/asn1/cms/OriginatorIdentifierOrKey.cs
+++ b/crypto/src/asn1/cms/OriginatorIdentifierOrKey.cs
@@ -8,6 +8,35 @@ namespace Org.BouncyCastle.Asn1.Cms
     public class OriginatorIdentifierOrKey
         : Asn1Encodable, IAsn1Choice
     {
+        public static OriginatorIdentifierOrKey GetInstance(
+            object o)
+        {
+            if (o == null)
+                return null;
+
+            if (o is OriginatorIdentifierOrKey originatorIdentifierOrKey)
+                return originatorIdentifierOrKey;
+
+            if (o is IssuerAndSerialNumber issuerAndSerialNumber)
+                return new OriginatorIdentifierOrKey(issuerAndSerialNumber);
+
+            if (o is SubjectKeyIdentifier subjectKeyIdentifier)
+                return new OriginatorIdentifierOrKey(subjectKeyIdentifier);
+
+            if (o is OriginatorPublicKey originatorPublicKey)
+                return new OriginatorIdentifierOrKey(originatorPublicKey);
+
+            if (o is Asn1TaggedObject taggedObject)
+                return new OriginatorIdentifierOrKey(Asn1Utilities.CheckTagClass(taggedObject, Asn1Tags.ContextSpecific));
+
+            throw new ArgumentException("Invalid OriginatorIdentifierOrKey: " + Platform.GetTypeName(o));
+        }
+
+        public static OriginatorIdentifierOrKey GetInstance(Asn1TaggedObject o, bool explicitly)
+        {
+            return Asn1Utilities.GetInstanceFromChoice(o, explicitly, GetInstance);
+        }
+
         private readonly Asn1Encodable id;
 
         public OriginatorIdentifierOrKey(IssuerAndSerialNumber id)
@@ -31,50 +60,6 @@ namespace Org.BouncyCastle.Asn1.Cms
 			this.id = id;
 		}
 
-		/**
-         * return an OriginatorIdentifierOrKey object from a tagged object.
-         *
-         * @param o the tagged object holding the object we want.
-         * @param explicitly true if the object is meant to be explicitly
-         *              tagged false otherwise.
-         * @exception ArgumentException if the object held by the
-         *          tagged object cannot be converted.
-         */
-        public static OriginatorIdentifierOrKey GetInstance(Asn1TaggedObject o, bool explicitly)
-        {
-            return Asn1Utilities.GetInstanceFromChoice(o, explicitly, GetInstance);
-        }
-
-        /**
-         * return an OriginatorIdentifierOrKey object from the given object.
-         *
-         * @param o the object we want converted.
-         * @exception ArgumentException if the object cannot be converted.
-         */
-        public static OriginatorIdentifierOrKey GetInstance(
-            object o)
-        {
-            if (o == null)
-                return null;
-
-            if (o is OriginatorIdentifierOrKey originatorIdentifierOrKey)
-                return originatorIdentifierOrKey;
-
-			if (o is IssuerAndSerialNumber issuerAndSerialNumber)
-				return new OriginatorIdentifierOrKey(issuerAndSerialNumber);
-
-			if (o is SubjectKeyIdentifier subjectKeyIdentifier)
-				return new OriginatorIdentifierOrKey(subjectKeyIdentifier);
-
-			if (o is OriginatorPublicKey originatorPublicKey)
-				return new OriginatorIdentifierOrKey(originatorPublicKey);
-
-			if (o is Asn1TaggedObject taggedObject)
-				return new OriginatorIdentifierOrKey(Asn1Utilities.CheckTagClass(taggedObject, Asn1Tags.ContextSpecific));
-
-            throw new ArgumentException("Invalid OriginatorIdentifierOrKey: " + Platform.GetTypeName(o));
-        }
-
 		public Asn1Encodable ID
 		{
 			get { return id; }
diff --git a/crypto/src/asn1/tsp/Accuracy.cs b/crypto/src/asn1/tsp/Accuracy.cs
index f9cd88014..a4fd0443b 100644
--- a/crypto/src/asn1/tsp/Accuracy.cs
+++ b/crypto/src/asn1/tsp/Accuracy.cs
@@ -7,21 +7,31 @@ namespace Org.BouncyCastle.Asn1.Tsp
 	public class Accuracy
 		: Asn1Encodable
 	{
-		private readonly DerInteger seconds;
-		private readonly DerInteger millis;
-		private readonly DerInteger micros;
+        protected const int MinMillis = 1;
+        protected const int MaxMillis = 999;
+        protected const int MinMicros = 1;
+        protected const int MaxMicros = 999;
 
-		// constants
-		protected const int MinMillis = 1;
-		protected const int MaxMillis = 999;
-		protected const int MinMicros = 1;
-		protected const int MaxMicros = 999;
+        public static Accuracy GetInstance(object obj)
+        {
+            if (obj == null)
+                return null;
+            if (obj is Accuracy accuracy)
+                return accuracy;
+            return new Accuracy(Asn1Sequence.GetInstance(obj));
+        }
 
-		public Accuracy(
-			DerInteger seconds,
-			DerInteger millis,
-			DerInteger micros)
-		{
+        public static Accuracy GetInstance(Asn1TaggedObject taggedObject, bool declaredExplicit)
+        {
+            return new Accuracy(Asn1Sequence.GetInstance(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)
+        {
             if (null != millis)
             {
                 int millisValue = millis.IntValueExact;
@@ -35,22 +45,26 @@ namespace Org.BouncyCastle.Asn1.Tsp
                     throw new ArgumentException("Invalid micros field : not in (1..999)");
             }
 
-            this.seconds = seconds;
-            this.millis = millis;
-            this.micros = micros;
-		}
+            m_seconds = seconds;
+            m_millis = millis;
+            m_micros = micros;
+        }
+
+        private Accuracy(Asn1Sequence seq)
+        {
+            DerInteger seconds = null;
+            DerInteger millis = null;
+            DerInteger micros = null;
 
-		private Accuracy(Asn1Sequence seq)
-		{
-			for (int i = 0; i < seq.Count; ++i)
-			{
-				// seconds
-				if (seq[i] is DerInteger derInteger)
-				{
-					seconds = derInteger;
-				}
+            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:
@@ -68,35 +82,21 @@ namespace Org.BouncyCastle.Asn1.Tsp
                     default:
                         throw new ArgumentException("Invalid tag number");
                     }
-				}
-			}
-		}
+                }
+            }
 
-        public static Accuracy GetInstance(object obj)
-        {
-            if (obj is Accuracy)
-                return (Accuracy)obj;
-            if (obj == null)
-                return null;
-            return new Accuracy(Asn1Sequence.GetInstance(obj));
+            m_seconds = seconds;
+            m_millis = millis;
+            m_micros = micros;
         }
 
-        public DerInteger Seconds
-		{
-			get { return seconds; }
-		}
+        public DerInteger Seconds => m_seconds;
 
-		public DerInteger Millis
-		{
-			get { return millis; }
-		}
+        public DerInteger Millis => m_millis;
 
-		public DerInteger Micros
-		{
-			get { return micros; }
-		}
+        public DerInteger Micros => m_micros;
 
-		/**
+        /**
 		 * <pre>
 		 * Accuracy ::= SEQUENCE {
 		 *             seconds        INTEGER              OPTIONAL,
@@ -108,10 +108,10 @@ namespace Org.BouncyCastle.Asn1.Tsp
         public override Asn1Object ToAsn1Object()
         {
             Asn1EncodableVector v = new Asn1EncodableVector(3);
-            v.AddOptional(seconds);
-            v.AddOptionalTagged(false, 0, millis);
-            v.AddOptionalTagged(false, 1, micros);
+            v.AddOptional(m_seconds);
+            v.AddOptionalTagged(false, 0, m_millis);
+            v.AddOptionalTagged(false, 1, m_micros);
             return new DerSequence(v);
         }
-	}
+    }
 }
diff --git a/crypto/src/asn1/tsp/ArchiveTimeStamp.cs b/crypto/src/asn1/tsp/ArchiveTimeStamp.cs
new file mode 100644
index 000000000..57cc02138
--- /dev/null
+++ b/crypto/src/asn1/tsp/ArchiveTimeStamp.cs
@@ -0,0 +1,176 @@
+using System;
+
+using Org.BouncyCastle.Asn1.Cms;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Tsp
+{
+    /**
+     * Implementation of the Archive Timestamp type defined in RFC4998.
+     * @see <a href="https://tools.ietf.org/html/rfc4998">RFC 4998</a>
+     * <p>
+     * ASN.1 Archive Timestamp
+     * <p>
+     * ArchiveTimeStamp ::= SEQUENCE {
+     * digestAlgorithm [Ø] AlgorithmIdentifier OPTIONAL,
+     * attributes      [1] Attributes OPTIONAL,
+     * reducedHashtree [2] SEQUENCE OF PartialHashtree OPTIONAL,
+     * timeStamp       ContentInfo}
+     * <p>
+     * PartialHashtree ::= SEQUENCE OF OCTET STRING
+     * <p>
+     * Attributes ::= SET SIZE (1..MAX) OF Attribute
+     */
+    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)
+                return null;
+            if (obj is ArchiveTimeStamp archiveTimeStamp)
+                return archiveTimeStamp;
+            return new ArchiveTimeStamp(Asn1Sequence.GetInstance(obj));
+        }
+
+        public static ArchiveTimeStamp GetInstance(Asn1TaggedObject taggedObject, bool declaredExplicit)
+        {
+            return new ArchiveTimeStamp(Asn1Sequence.GetInstance(taggedObject, declaredExplicit));
+        }
+
+        private readonly AlgorithmIdentifier m_digestAlgorithm;
+        private readonly Attributes m_attributes;
+        private readonly Asn1Sequence m_reducedHashTree;
+        private readonly ContentInfo m_timeStamp;
+
+        public ArchiveTimeStamp(AlgorithmIdentifier digestAlgorithm, PartialHashtree[] reducedHashTree,
+            ContentInfo timeStamp)
+            : this(digestAlgorithm, null, reducedHashTree, timeStamp)
+        {
+        }
+
+        public ArchiveTimeStamp(ContentInfo timeStamp)
+            : this(null, null, null, timeStamp)
+        {
+        }
+
+        public ArchiveTimeStamp(AlgorithmIdentifier digestAlgorithm, Attributes attributes,
+            PartialHashtree[] reducedHashTree, ContentInfo timeStamp)
+        {
+            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]);
+        }
+
+        public virtual AlgorithmIdentifier GetDigestAlgorithmIdentifier() => m_digestAlgorithm
+            ?? GetTimeStampInfo().MessageImprint.HashAlgorithm;
+
+        public virtual byte[] GetTimeStampDigestValue() => GetTimeStampInfo().MessageImprint.GetHashedMessage();
+
+        private TstInfo GetTimeStampInfo()
+        {
+            if (!CmsObjectIdentifiers.SignedData.Equals(m_timeStamp.ContentType))
+                throw new InvalidOperationException("cannot identify algorithm identifier for digest");
+
+            SignedData tsData = SignedData.GetInstance(m_timeStamp.Content);
+            var contentInfo = tsData.EncapContentInfo;
+
+            if (!Asn1.Pkcs.PkcsObjectIdentifiers.IdCTTstInfo.Equals(contentInfo.ContentType))
+                throw new InvalidOperationException("cannot parse time stamp");
+
+            return TstInfo.GetInstance(Asn1OctetString.GetInstance(contentInfo.Content).GetOctets());
+        }
+
+        /**
+         * Return the contents of the digestAlgorithm field - null if not set.
+         *
+         * @return the contents of the digestAlgorithm field, or null if not set.
+         */
+        public virtual AlgorithmIdentifier DigestAlgorithm() => m_digestAlgorithm;
+
+        /**
+         * Return the first node in the reduced hash tree which contains the leaf node.
+         *
+         * @return the node containing the data hashes, null if no reduced hash tree is present.
+         */
+        public virtual PartialHashtree GetHashTreeLeaf()
+        {
+            if (m_reducedHashTree == null)
+                return null;
+
+            return PartialHashtree.GetInstance(m_reducedHashTree[0]);
+        }
+
+        public virtual PartialHashtree[] GetReducedHashTree()
+        {
+            if (m_reducedHashTree == null)
+                return null;
+
+            return m_reducedHashTree.MapElements(PartialHashtree.GetInstance);
+        }
+
+        public virtual ContentInfo TimeStamp => m_timeStamp;
+
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector(4);
+            v.AddOptionalTagged(false, 0, m_digestAlgorithm);
+            v.AddOptionalTagged(false, 1, m_attributes);
+            v.AddOptionalTagged(false, 2, m_reducedHashTree);
+            v.Add(m_timeStamp);
+            return new DerSequence(v);
+        }
+    }
+}
diff --git a/crypto/src/asn1/tsp/ArchiveTimeStampChain.cs b/crypto/src/asn1/tsp/ArchiveTimeStampChain.cs
new file mode 100644
index 000000000..13138d6f9
--- /dev/null
+++ b/crypto/src/asn1/tsp/ArchiveTimeStampChain.cs
@@ -0,0 +1,86 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Tsp
+{
+    /**
+     * Implementation of ArchiveTimeStampChain type, as defined in RFC4998 and RFC6283.
+     * <p>
+     * An ArchiveTimeStampChain corresponds to a SEQUENCE OF ArchiveTimeStamps, and has the following
+     * ASN.1 Syntax:
+     * <p>
+     * ArchiveTimeStampChain ::= SEQUENCE OF ArchiveTimeStamp
+     */
+    public class ArchiveTimeStampChain
+        : Asn1Encodable
+    {
+        /**
+         * Return an ArchiveTimeStampChain from the given object.
+         *
+         * @param obj the object we want converted.
+         * @return an ArchiveTimeStampChain instance, or null.
+         * @throws IllegalArgumentException if the object cannot be converted.
+         */
+        public static ArchiveTimeStampChain GetInstance(object obj)
+        {
+            if (obj == null)
+                return null;
+            if (obj is ArchiveTimeStampChain archiveTimeStampChain)
+                return archiveTimeStampChain;
+            return new ArchiveTimeStampChain(Asn1Sequence.GetInstance(obj));
+        }
+
+        public static ArchiveTimeStampChain GetInstance(Asn1TaggedObject taggedObject, bool declaredExplicit)
+        {
+            return new ArchiveTimeStampChain(Asn1Sequence.GetInstance(taggedObject, declaredExplicit));
+        }
+
+        private readonly Asn1Sequence m_archiveTimeStamps;
+
+        public ArchiveTimeStampChain(ArchiveTimeStamp archiveTimeStamp)
+        {
+            m_archiveTimeStamps = new DerSequence(archiveTimeStamp);
+        }
+
+        public ArchiveTimeStampChain(ArchiveTimeStamp[] archiveTimeStamps)
+        {
+            m_archiveTimeStamps = new DerSequence(archiveTimeStamps);
+        }
+
+        private ArchiveTimeStampChain(Asn1Sequence sequence)
+        {
+            Asn1EncodableVector vector = new Asn1EncodableVector(sequence.Count);
+
+            foreach (var element in sequence)
+            {
+                vector.Add(ArchiveTimeStamp.GetInstance(element));
+            }
+
+            m_archiveTimeStamps = new DerSequence(vector);
+        }
+
+        public virtual ArchiveTimeStamp[] GetArchiveTimestamps() =>
+            m_archiveTimeStamps.MapElements(ArchiveTimeStamp.GetInstance);
+
+        /**
+         * Adds an {@link ArchiveTimeStamp} object to the archive timestamp chain.
+         *
+         * @param archiveTimeStamp the {@link ArchiveTimeStamp} to add.
+         * @return returns the modified chain.
+         */
+        public virtual ArchiveTimeStampChain Append(ArchiveTimeStamp archiveTimeStamp)
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector(m_archiveTimeStamps.Count + 1);
+
+            foreach (var element in m_archiveTimeStamps)
+            {
+                v.Add(element);
+            }
+
+            v.Add(archiveTimeStamp);
+
+            return new ArchiveTimeStampChain(new DerSequence(v));
+        }
+
+        public override Asn1Object ToAsn1Object() => m_archiveTimeStamps;
+    }
+}
diff --git a/crypto/src/asn1/tsp/ArchiveTimeStampSequence.cs b/crypto/src/asn1/tsp/ArchiveTimeStampSequence.cs
new file mode 100644
index 000000000..766f6704c
--- /dev/null
+++ b/crypto/src/asn1/tsp/ArchiveTimeStampSequence.cs
@@ -0,0 +1,93 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Tsp
+{
+    /**
+     * Implementation of ArchiveTimeStampSequence type, as defined in RFC4998.
+     * <p>
+     * An ArchiveTimeStampSequence corresponds to a SEQUENCE OF ArchiveTimeStampChains and has the
+     * following ASN.1 Syntax:
+     * <p>
+     * ArchiveTimeStampSequence ::= SEQUENCE OF ArchiveTimeStampChain
+     */
+    public class ArchiveTimeStampSequence
+        : Asn1Encodable
+    {
+        /**
+         * Return an ArchiveTimestampSequence from the given object.
+         *
+         * @param obj the object we want converted.
+         * @return an ArchiveTimeStampSequence instance, or null.
+         * @throws IllegalArgumentException if the object cannot be converted.
+         */
+        public static ArchiveTimeStampSequence GetInstance(object obj)
+        {
+            if (obj == null)
+                return null;
+            if (obj is ArchiveTimeStampSequence archiveTimeStampSequence)
+                return archiveTimeStampSequence;
+            return new ArchiveTimeStampSequence(Asn1Sequence.GetInstance(obj));
+        }
+
+        public static ArchiveTimeStampSequence GetInstance(Asn1TaggedObject taggedObject, bool declaredExplicit)
+        {
+            return new ArchiveTimeStampSequence(Asn1Sequence.GetInstance(taggedObject, declaredExplicit));
+        }
+
+        private readonly Asn1Sequence m_archiveTimeStampChains;
+
+        private ArchiveTimeStampSequence(Asn1Sequence sequence)
+        {
+            Asn1EncodableVector vector = new Asn1EncodableVector(sequence.Count);
+
+            foreach (var element in sequence)
+            {
+                vector.Add(ArchiveTimeStampChain.GetInstance(element));
+            }
+
+            m_archiveTimeStampChains = new DerSequence(vector);
+        }
+
+        public ArchiveTimeStampSequence(ArchiveTimeStampChain archiveTimeStampChain)
+        {
+            m_archiveTimeStampChains = new DerSequence(archiveTimeStampChain);
+        }
+
+        public ArchiveTimeStampSequence(ArchiveTimeStampChain[] archiveTimeStampChains)
+        {
+            m_archiveTimeStampChains = new DerSequence(archiveTimeStampChains);
+        }
+
+        /**
+         * Returns the sequence of ArchiveTimeStamp chains that compose the ArchiveTimeStamp sequence.
+         *
+         * @return the {@link ASN1Sequence} containing the ArchiveTimeStamp chains.
+         */
+        public virtual ArchiveTimeStampChain[] GetArchiveTimeStampChains() =>
+            m_archiveTimeStampChains.MapElements(ArchiveTimeStampChain.GetInstance);
+
+        public virtual int Count => m_archiveTimeStampChains.Count;
+
+        /**
+         * Adds an {@link ArchiveTimeStampChain} to the ArchiveTimeStamp sequence.
+         *
+         * @param chain the {@link ArchiveTimeStampChain} to add
+         * @return returns the modified sequence.
+         */
+        public virtual ArchiveTimeStampSequence Append(ArchiveTimeStampChain chain)
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector(m_archiveTimeStampChains.Count + 1);
+
+            foreach (var element in m_archiveTimeStampChains)
+            {
+                v.Add(element);
+            }
+
+            v.Add(chain);
+
+            return new ArchiveTimeStampSequence(new DerSequence(v));
+        }
+
+        public override Asn1Object ToAsn1Object() => m_archiveTimeStampChains;
+    }
+}
diff --git a/crypto/src/asn1/tsp/CryptoInfos.cs b/crypto/src/asn1/tsp/CryptoInfos.cs
new file mode 100644
index 000000000..b0b84c014
--- /dev/null
+++ b/crypto/src/asn1/tsp/CryptoInfos.cs
@@ -0,0 +1,43 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Tsp
+{
+    /**
+     * Implementation of the CryptoInfos element defined in RFC 4998:
+     * <p>
+     * CryptoInfos ::= SEQUENCE SIZE (1..MAX) OF Attribute
+     */
+    public class CryptoInfos
+        : Asn1Encodable
+    {
+        public static CryptoInfos GetInstance(object obj)
+        {
+            if (obj == null)
+                return null;
+            if (obj is CryptoInfos cryptoInfos)
+                return cryptoInfos;
+            return new CryptoInfos(Asn1Sequence.GetInstance(obj));
+        }
+
+        public static CryptoInfos GetInstance(Asn1TaggedObject taggedObject, bool declaredExplicit)
+        {
+            return new CryptoInfos(Asn1Sequence.GetInstance(taggedObject, declaredExplicit));
+        }
+
+        private readonly Asn1Sequence m_attributes;
+
+        private CryptoInfos(Asn1Sequence attributes)
+        {
+            m_attributes = attributes;
+        }
+
+        public CryptoInfos(Asn1.Cms.Attribute[] attrs)
+        {
+            m_attributes = new DerSequence(attrs);
+        }
+
+        public virtual Asn1.Cms.Attribute[] GetAttributes() => m_attributes.MapElements(Asn1.Cms.Attribute.GetInstance);
+
+        public override Asn1Object ToAsn1Object() => m_attributes;
+    }
+}
diff --git a/crypto/src/asn1/tsp/EncryptionInfo.cs b/crypto/src/asn1/tsp/EncryptionInfo.cs
new file mode 100644
index 000000000..e712c6a00
--- /dev/null
+++ b/crypto/src/asn1/tsp/EncryptionInfo.cs
@@ -0,0 +1,76 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Tsp
+{
+    /**
+     * Implementation of the EncryptionInfo element defined in RFC 4998:
+     * <p>
+     * 1988 ASN.1 EncryptionInfo
+     * <p>
+     * EncryptionInfo       ::=     SEQUENCE {
+     * encryptionInfoType     OBJECT IDENTIFIER,
+     * encryptionInfoValue    ANY DEFINED BY encryptionInfoType
+     * }
+     * <p>
+     * 1997-ASN.1 EncryptionInfo
+     * <p>
+     * EncryptionInfo       ::=     SEQUENCE {
+     * encryptionInfoType   ENCINFO-TYPE.&amp;id
+     * ({SupportedEncryptionAlgorithms}),
+     * encryptionInfoValue  ENCINFO-TYPE.&amp;Type
+     * ({SupportedEncryptionAlgorithms}{&#064;encryptionInfoType})
+     * }
+     * <p>
+     * ENCINFO-TYPE ::= TYPE-IDENTIFIER
+     * <p>
+     * SupportedEncryptionAlgorithms ENCINFO-TYPE ::= {...}
+     */
+    public class EncryptionInfo
+        : Asn1Encodable
+    {
+        public static EncryptionInfo GetInstance(object obj)
+        {
+            if (obj == null)
+                return null;
+            if (obj is EncryptionInfo encryptionInfo)
+                return encryptionInfo;
+            return new EncryptionInfo(Asn1Sequence.GetInstance(obj));
+        }
+
+        public static EncryptionInfo GetInstance(Asn1TaggedObject taggedObject, bool declaredExplicit)
+        {
+            return new EncryptionInfo(Asn1Sequence.GetInstance(taggedObject, declaredExplicit));
+        }
+
+        /**
+         * The OID for EncryptionInfo type.
+         */
+        private readonly DerObjectIdentifier m_encryptionInfoType;
+
+        /**
+         * The value of EncryptionInfo
+         */
+        private readonly Asn1Encodable m_encryptionInfoValue;
+
+        private EncryptionInfo(Asn1Sequence sequence)
+        {
+            if (sequence.Count != 2)
+                throw new ArgumentException("wrong sequence size in constructor: " + sequence.Count, nameof(sequence));
+
+            m_encryptionInfoType = DerObjectIdentifier.GetInstance(sequence[0]);
+            m_encryptionInfoValue = sequence[1];
+        }
+
+        public EncryptionInfo(DerObjectIdentifier encryptionInfoType, Asn1Encodable encryptionInfoValue)
+        {
+            m_encryptionInfoType = encryptionInfoType;
+            m_encryptionInfoValue = encryptionInfoValue;
+        }
+
+        public virtual DerObjectIdentifier EncryptionInfoType => m_encryptionInfoType;
+
+        public virtual Asn1Encodable EncryptionInfoValue => m_encryptionInfoValue;
+
+        public override Asn1Object ToAsn1Object() => new DLSequence(m_encryptionInfoType, m_encryptionInfoValue);
+    }
+}
diff --git a/crypto/src/asn1/tsp/EvidenceRecord.cs b/crypto/src/asn1/tsp/EvidenceRecord.cs
new file mode 100644
index 000000000..42ec4bf16
--- /dev/null
+++ b/crypto/src/asn1/tsp/EvidenceRecord.cs
@@ -0,0 +1,217 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Tsp
+{
+    /**
+     * <a href="https://tools.ietf.org/html/rfc4998">RFC 4998</a>:
+     * Evidence Record Syntax (ERS)
+     * <p>
+     * <pre>
+     * EvidenceRecord ::= SEQUENCE {
+     *   version                   INTEGER { v1(1) } ,
+     *   digestAlgorithms          SEQUENCE OF AlgorithmIdentifier,
+     *   cryptoInfos               [0] CryptoInfos OPTIONAL,
+     *   encryptionInfo            [1] EncryptionInfo OPTIONAL,
+     *   archiveTimeStampSequence  ArchiveTimeStampSequence
+     * }
+     *
+     * CryptoInfos ::= SEQUENCE SIZE (1..MAX) OF Attribute
+     * </pre>
+     */
+    public class EvidenceRecord
+        : Asn1Encodable
+    {
+        /**
+         * ERS {iso(1) identified-organization(3) dod(6) internet(1) security(5) mechanisms(5) ltans(11)
+         * id-mod(0) id-mod-ers88(2) id-mod-ers88-v1(1) }
+         */
+        private static readonly DerObjectIdentifier Oid = new DerObjectIdentifier("1.3.6.1.5.5.11.0.2.1");
+
+        /**
+         * Return an EvidenceRecord from the given object.
+         *
+         * @param obj the object we want converted.
+         * @return an EvidenceRecord instance, or null.
+         * @throws IllegalArgumentException if the object cannot be converted.
+         */
+        public static EvidenceRecord GetInstance(object obj)
+        {
+            if (obj == null)
+                return null;
+            if (obj is EvidenceRecord evidenceRecord)
+                return evidenceRecord;
+            return new EvidenceRecord(Asn1Sequence.GetInstance(obj));
+        }
+
+        public static EvidenceRecord GetInstance(Asn1TaggedObject taggedObject, bool declaredExplicit)
+        {
+            return new EvidenceRecord(Asn1Sequence.GetInstance(taggedObject, declaredExplicit));
+        }
+
+        private readonly DerInteger m_version;
+        private readonly Asn1Sequence m_digestAlgorithms;
+        private readonly CryptoInfos m_cryptoInfos;
+        private readonly EncryptionInfo m_encryptionInfo;
+        private readonly ArchiveTimeStampSequence m_archiveTimeStampSequence;
+
+        private EvidenceRecord(EvidenceRecord evidenceRecord, ArchiveTimeStampSequence replacementSequence,
+            ArchiveTimeStamp newChainTimeStamp)
+        {
+            m_version = evidenceRecord.m_version;
+
+            // check the list of digest algorithms is correct.
+            if (newChainTimeStamp != null)
+            {
+                AlgorithmIdentifier algID = newChainTimeStamp.GetDigestAlgorithmIdentifier();
+                Asn1EncodableVector vector = new Asn1EncodableVector();
+
+                bool found = false;
+
+                foreach (var element in evidenceRecord.m_digestAlgorithms)
+                {
+                    AlgorithmIdentifier algorithmIdentifier = AlgorithmIdentifier.GetInstance(element);
+                    vector.Add(algorithmIdentifier);
+
+                    if (algorithmIdentifier.Equals(algID))
+                    {
+                        found = true;
+                        break;
+                    }
+                }
+
+                if (!found)
+                {
+                    vector.Add(algID);
+                    m_digestAlgorithms = new DerSequence(vector);
+                }
+                else
+                {
+                    m_digestAlgorithms = evidenceRecord.m_digestAlgorithms;
+                }
+            }
+            else
+            {
+                m_digestAlgorithms = evidenceRecord.m_digestAlgorithms;
+            }
+
+            m_cryptoInfos = evidenceRecord.m_cryptoInfos;
+            m_encryptionInfo = evidenceRecord.m_encryptionInfo;
+            m_archiveTimeStampSequence = replacementSequence;
+        }
+
+        /**
+         * Build a basic evidence record from an initial
+         * ArchiveTimeStamp.
+         * 
+         * @param cryptoInfos
+         * @param encryptionInfo
+         * @param archiveTimeStamp
+         */
+        public EvidenceRecord(CryptoInfos cryptoInfos, EncryptionInfo encryptionInfo, ArchiveTimeStamp archiveTimeStamp)
+        {
+            m_version = new DerInteger(1);
+            m_digestAlgorithms = new DerSequence(archiveTimeStamp.GetDigestAlgorithmIdentifier());
+            m_cryptoInfos = cryptoInfos;
+            m_encryptionInfo = encryptionInfo;
+            m_archiveTimeStampSequence = new ArchiveTimeStampSequence(new ArchiveTimeStampChain(archiveTimeStamp));
+        }
+
+        public EvidenceRecord(AlgorithmIdentifier[] digestAlgorithms, CryptoInfos cryptoInfos,
+            EncryptionInfo encryptionInfo, ArchiveTimeStampSequence archiveTimeStampSequence)
+        {
+            m_version = new DerInteger(1);
+            m_digestAlgorithms = new DerSequence(digestAlgorithms);
+            m_cryptoInfos = cryptoInfos;
+            m_encryptionInfo = encryptionInfo;
+            m_archiveTimeStampSequence = archiveTimeStampSequence;
+        }
+
+        private EvidenceRecord(Asn1Sequence sequence)
+        {
+            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");
+
+            m_version = versionNumber;
+
+            m_digestAlgorithms = Asn1Sequence.GetInstance(sequence[1]);
+            for (int i = 2; i != sequence.Count - 1; i++)
+            {
+                Asn1Encodable element = sequence[i];
+
+                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]);
+        }
+
+        public virtual AlgorithmIdentifier[] GetDigestAlgorithms() =>
+            m_digestAlgorithms.MapElements(AlgorithmIdentifier.GetInstance);
+
+        public virtual ArchiveTimeStampSequence ArchiveTimeStampSequence => m_archiveTimeStampSequence;
+
+        /**
+         * Return a new EvidenceRecord with an added ArchiveTimeStamp
+         *
+         * @param ats         the archive timestamp to add
+         * @param newChain states whether this new archive timestamp must be added as part of a
+         *                    new sequence (i.e. in the case of hashtree renewal) or not (i.e. in the case of timestamp
+         *                    renewal)
+         * @return the new EvidenceRecord
+         */
+        public virtual EvidenceRecord AddArchiveTimeStamp(ArchiveTimeStamp ats, bool newChain)
+        {
+            if (newChain)
+            {
+                ArchiveTimeStampChain chain = new ArchiveTimeStampChain(ats);
+
+                return new EvidenceRecord(this, m_archiveTimeStampSequence.Append(chain), ats);
+            }
+            else
+            {
+                ArchiveTimeStampChain[] chains = m_archiveTimeStampSequence.GetArchiveTimeStampChains();
+
+                AlgorithmIdentifier digAlg = chains[chains.Length - 1].GetArchiveTimestamps()[0]
+                    .GetDigestAlgorithmIdentifier();
+                if (!digAlg.Equals(ats.GetDigestAlgorithmIdentifier()))
+                    throw new ArgumentException("mismatch of digest algorithm in AddArchiveTimeStamp");
+
+                chains[chains.Length - 1] = chains[chains.Length - 1].Append(ats);
+                return new EvidenceRecord(this, new ArchiveTimeStampSequence(chains), null);
+            }
+        }
+
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector vector = new Asn1EncodableVector(5);
+            vector.Add(m_version);
+            vector.Add(m_digestAlgorithms);
+            vector.AddOptionalTagged(false, 0, m_cryptoInfos);
+            vector.AddOptionalTagged(false, 1, m_encryptionInfo);
+            vector.Add(m_archiveTimeStampSequence);
+            return new DerSequence(vector);
+        }
+    }
+}
diff --git a/crypto/src/asn1/tsp/MessageImprint.cs b/crypto/src/asn1/tsp/MessageImprint.cs
index cb728629c..0be856048 100644
--- a/crypto/src/asn1/tsp/MessageImprint.cs
+++ b/crypto/src/asn1/tsp/MessageImprint.cs
@@ -8,46 +8,42 @@ namespace Org.BouncyCastle.Asn1.Tsp
 	public class MessageImprint
 		: Asn1Encodable
 	{
-		private readonly AlgorithmIdentifier	hashAlgorithm;
-		private readonly byte[]					hashedMessage;
-
         public static MessageImprint GetInstance(object obj)
         {
-            if (obj is MessageImprint)
-                return (MessageImprint)obj;
             if (obj == null)
                 return null;
+            if (obj is MessageImprint messageImprint)
+                return messageImprint;
             return new MessageImprint(Asn1Sequence.GetInstance(obj));
         }
 
-        private MessageImprint(
-			Asn1Sequence seq)
+		public static MessageImprint GetInstance(Asn1TaggedObject taggedObject, bool declaredExplicit)
 		{
-			if (seq.Count != 2)
-				throw new ArgumentException("Wrong number of elements in sequence", "seq");
+            return new MessageImprint(Asn1Sequence.GetInstance(taggedObject, declaredExplicit));
+        }
 
-			this.hashAlgorithm = AlgorithmIdentifier.GetInstance(seq[0]);
-			this.hashedMessage = Asn1OctetString.GetInstance(seq[1]).GetOctets();
-		}
+        private readonly AlgorithmIdentifier m_hashAlgorithm;
+        private readonly byte[] m_hashedMessage;
 
-		public MessageImprint(
-			AlgorithmIdentifier	hashAlgorithm,
-			byte[]				hashedMessage)
+        private MessageImprint(Asn1Sequence seq)
 		{
-			this.hashAlgorithm = hashAlgorithm;
-			this.hashedMessage = hashedMessage;
-		}
+			if (seq.Count != 2)
+				throw new ArgumentException("Wrong number of elements in sequence", nameof(seq));
 
-		public AlgorithmIdentifier HashAlgorithm
-		{
-			get { return hashAlgorithm; }
+			m_hashAlgorithm = AlgorithmIdentifier.GetInstance(seq[0]);
+			m_hashedMessage = Asn1OctetString.GetInstance(seq[1]).GetOctets();
 		}
 
-		public byte[] GetHashedMessage()
+		public MessageImprint(AlgorithmIdentifier hashAlgorithm, byte[] hashedMessage)
 		{
-			return hashedMessage;
+			m_hashAlgorithm = hashAlgorithm;
+			m_hashedMessage = hashedMessage;
 		}
 
+		public AlgorithmIdentifier HashAlgorithm => m_hashAlgorithm;
+
+		public byte[] GetHashedMessage() => m_hashedMessage;
+
 		/**
 		 * <pre>
 		 *    MessageImprint ::= SEQUENCE  {
@@ -57,7 +53,7 @@ namespace Org.BouncyCastle.Asn1.Tsp
 		 */
 		public override Asn1Object ToAsn1Object()
 		{
-			return new DerSequence(hashAlgorithm, new DerOctetString(hashedMessage));
+			return new DerSequence(m_hashAlgorithm, new DerOctetString(m_hashedMessage));
 		}
 	}
 }
diff --git a/crypto/src/asn1/tsp/PartialHashtree.cs b/crypto/src/asn1/tsp/PartialHashtree.cs
new file mode 100644
index 000000000..a32a9f18b
--- /dev/null
+++ b/crypto/src/asn1/tsp/PartialHashtree.cs
@@ -0,0 +1,91 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Asn1.Tsp
+{
+    /**
+     * Implementation of PartialHashtree, as defined in RFC 4998.
+     * <p>
+     * The ASN.1 notation for a PartialHashTree is:
+     * <p>
+     * PartialHashtree ::= SEQUENCE OF OCTET STRING
+     */
+    public class PartialHashtree
+        : Asn1Encodable
+    {
+        /**
+         * Return a PartialHashtree from the given object.
+         *
+         * @param obj the object we want converted.
+         * @return a PartialHashtree instance, or null.
+         * @throws IllegalArgumentException if the object cannot be converted.
+         */
+        public static PartialHashtree GetInstance(object obj)
+        {
+            if (obj == null)
+                return null;
+            if (obj is PartialHashtree partialHashtree)
+                return partialHashtree;
+            return new PartialHashtree(Asn1Sequence.GetInstance(obj));
+        }
+
+        public static PartialHashtree GetInstance(Asn1TaggedObject taggedObject, bool declaredExplicit)
+        {
+            return new PartialHashtree(Asn1Sequence.GetInstance(taggedObject, declaredExplicit));
+        }
+
+        /**
+         * Hash values that constitute the hash tree, as ASN.1 Octet Strings.
+         */
+        private readonly Asn1Sequence m_values;
+
+        private PartialHashtree(Asn1Sequence values)
+        {
+            for (int i = 0; i != values.Count; i++)
+            {
+                if (!(values[i] is Asn1OctetString))
+                    throw new ArgumentException("unknown object in constructor: " + Platform.GetTypeName(values[i]));
+            }
+            m_values = values;
+        }
+
+        public PartialHashtree(byte[] value)
+        {
+            m_values = new DerSequence(new DerOctetString(Arrays.Clone(value)));
+        }
+
+        public PartialHashtree(byte[][] values)
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector(values.Length);
+
+            for (int i = 0; i != values.Length; i++)
+            {
+                v.Add(new DerOctetString(Arrays.Clone(values[i])));
+            }
+
+            m_values = new DerSequence(v);
+        }
+
+        public virtual int ValueCount => m_values.Count;
+
+        public virtual byte[][] GetValues() => m_values.MapElements(
+            element => Arrays.Clone(Asn1OctetString.GetInstance(element).GetOctets()));
+
+        public virtual bool ContainsHash(byte[] hash)
+        {
+            foreach (Asn1OctetString octetString in m_values)
+            {
+                byte[] currentHash = octetString.GetOctets();
+
+                if (Arrays.FixedTimeEquals(hash, currentHash))
+                    return true;
+            }
+
+            return false;
+        }
+
+        public override Asn1Object ToAsn1Object() => m_values;
+    }
+}
diff --git a/crypto/src/asn1/tsp/TSTInfo.cs b/crypto/src/asn1/tsp/TSTInfo.cs
index a8e166cbc..8aefe6159 100644
--- a/crypto/src/asn1/tsp/TSTInfo.cs
+++ b/crypto/src/asn1/tsp/TSTInfo.cs
@@ -7,25 +7,30 @@ namespace Org.BouncyCastle.Asn1.Tsp
 	public class TstInfo
 		: Asn1Encodable
 	{
-		private readonly DerInteger				version;
-		private readonly DerObjectIdentifier	tsaPolicyId;
-		private readonly MessageImprint			messageImprint;
-		private readonly DerInteger				serialNumber;
-		private readonly Asn1GeneralizedTime	genTime;
-		private readonly Accuracy				accuracy;
-		private readonly DerBoolean				ordering;
-		private readonly DerInteger				nonce;
-		private readonly GeneralName			tsa;
-		private readonly X509Extensions			extensions;
-
-		public static TstInfo GetInstance(object obj)
-		{
-            if (obj is TstInfo)
-                return (TstInfo)obj;
+        public static TstInfo GetInstance(object obj)
+        {
             if (obj == null)
                 return null;
+            if (obj is TstInfo tstInfo)
+                return tstInfo;
             return new TstInfo(Asn1Sequence.GetInstance(obj));
-		}
+        }
+
+        public static TstInfo GetInstance(Asn1TaggedObject taggedObject, bool declaredExplicit)
+        {
+            return new TstInfo(Asn1Sequence.GetInstance(taggedObject, declaredExplicit));
+        }
+
+        private readonly DerInteger m_version;
+		private readonly DerObjectIdentifier m_tsaPolicyID;
+		private readonly MessageImprint m_messageImprint;
+		private readonly DerInteger m_serialNumber;
+		private readonly Asn1GeneralizedTime m_genTime;
+		private readonly Accuracy m_accuracy;
+		private readonly DerBoolean m_ordering;
+		private readonly DerInteger m_nonce;
+		private readonly GeneralName m_tsa;
+		private readonly X509Extensions m_extensions;
 
 		private TstInfo(Asn1Sequence seq)
 		{
@@ -33,26 +38,26 @@ namespace Org.BouncyCastle.Asn1.Tsp
 
 			// version
 			e.MoveNext();
-			version = DerInteger.GetInstance(e.Current);
+			m_version = DerInteger.GetInstance(e.Current);
 
 			// tsaPolicy
 			e.MoveNext();
-			tsaPolicyId = DerObjectIdentifier.GetInstance(e.Current);
+			m_tsaPolicyID = DerObjectIdentifier.GetInstance(e.Current);
 
 			// messageImprint
 			e.MoveNext();
-			messageImprint = MessageImprint.GetInstance(e.Current);
+			m_messageImprint = MessageImprint.GetInstance(e.Current);
 
 			// serialNumber
 			e.MoveNext();
-			serialNumber = DerInteger.GetInstance(e.Current);
+			m_serialNumber = DerInteger.GetInstance(e.Current);
 
 			// genTime
 			e.MoveNext();
-			genTime = Asn1GeneralizedTime.GetInstance(e.Current);
+			m_genTime = Asn1GeneralizedTime.GetInstance(e.Current);
 
 			// default for ordering
-			ordering = DerBoolean.False;
+			m_ordering = DerBoolean.False;
 
 			while (e.MoveNext())
 			{
@@ -63,10 +68,10 @@ namespace Org.BouncyCastle.Asn1.Tsp
 					switch (tagged.TagNo)
 					{
 					case 0:
-						tsa = GeneralName.GetInstance(tagged, true);
+						m_tsa = GeneralName.GetInstance(tagged, true);
 						break;
 					case 1:
-						extensions = X509Extensions.GetInstance(tagged, false);
+						m_extensions = X509Extensions.GetInstance(tagged, false);
 						break;
 					default:
 						throw new ArgumentException("Unknown tag value " + tagged.TagNo);
@@ -75,95 +80,58 @@ namespace Org.BouncyCastle.Asn1.Tsp
 
 				if (o is Asn1Sequence)
 				{
-					accuracy = Accuracy.GetInstance(o);
+					m_accuracy = Accuracy.GetInstance(o);
 				}
 
 				if (o is DerBoolean)
 				{
-					ordering = DerBoolean.GetInstance(o);
+					m_ordering = DerBoolean.GetInstance(o);
 				}
 
 				if (o is DerInteger)
 				{
-					nonce = DerInteger.GetInstance(o);
+					m_nonce = DerInteger.GetInstance(o);
 				}
 			}
 		}
 
-		public TstInfo(
-			DerObjectIdentifier	tsaPolicyId,
-			MessageImprint		messageImprint,
-			DerInteger			serialNumber,
-            Asn1GeneralizedTime genTime,
-			Accuracy			accuracy,
-			DerBoolean			ordering,
-			DerInteger			nonce,
-			GeneralName			tsa,
-			X509Extensions		extensions)
-		{
-			this.version = new DerInteger(1);
-			this.tsaPolicyId = tsaPolicyId;
-			this.messageImprint = messageImprint;
-			this.serialNumber = serialNumber;
-			this.genTime = genTime;
-			this.accuracy = accuracy;
-			this.ordering = ordering;
-			this.nonce = nonce;
-			this.tsa = tsa;
-			this.extensions = extensions;
-		}
-
-        public DerInteger Version
+        public TstInfo(DerObjectIdentifier tsaPolicyId, MessageImprint messageImprint, DerInteger serialNumber,
+            Asn1GeneralizedTime genTime, Accuracy accuracy, DerBoolean ordering, DerInteger nonce, GeneralName tsa,
+            X509Extensions extensions)
         {
-            get { return version; }
+            m_version = new DerInteger(1);
+            m_tsaPolicyID = tsaPolicyId;
+            m_messageImprint = messageImprint;
+            m_serialNumber = serialNumber;
+            m_genTime = genTime;
+            m_accuracy = accuracy;
+            m_ordering = ordering;
+            m_nonce = nonce;
+            m_tsa = tsa;
+            m_extensions = extensions;
         }
 
-		public MessageImprint MessageImprint
-		{
-			get { return messageImprint; }
-		}
+        public DerInteger Version => m_version;
 
-		public DerObjectIdentifier Policy
-		{
-			get { return tsaPolicyId; }
-		}
+        public MessageImprint MessageImprint => m_messageImprint;
 
-		public DerInteger SerialNumber
-		{
-			get { return serialNumber; }
-		}
+        public DerObjectIdentifier Policy => m_tsaPolicyID;
 
-		public Accuracy Accuracy
-		{
-			get { return accuracy; }
-		}
+        public DerInteger SerialNumber => m_serialNumber;
 
-		public Asn1GeneralizedTime GenTime
-		{
-			get { return genTime; }
-		}
+        public Accuracy Accuracy => m_accuracy;
 
-		public DerBoolean Ordering
-		{
-			get { return ordering; }
-		}
+        public Asn1GeneralizedTime GenTime => m_genTime;
 
-		public DerInteger Nonce
-		{
-			get { return nonce; }
-		}
+        public DerBoolean Ordering => m_ordering;
 
-		public GeneralName Tsa
-		{
-			get { return tsa; }
-		}
+        public DerInteger Nonce => m_nonce;
 
-		public X509Extensions Extensions
-		{
-			get { return extensions; }
-		}
+        public GeneralName Tsa => m_tsa;
+
+        public X509Extensions Extensions => m_extensions;
 
-		/**
+        /**
 		 * <pre>
 		 *
 		 *     TstInfo ::= SEQUENCE  {
@@ -188,18 +156,19 @@ namespace Org.BouncyCastle.Asn1.Tsp
 		 */
         public override Asn1Object ToAsn1Object()
         {
-            Asn1EncodableVector v = new Asn1EncodableVector(version, tsaPolicyId, messageImprint, serialNumber, genTime);
-            v.AddOptional(accuracy);
+            Asn1EncodableVector v = new Asn1EncodableVector(10);
+            v.Add(m_version, m_tsaPolicyID, m_messageImprint, m_serialNumber, m_genTime);
+            v.AddOptional(m_accuracy);
 
-            if (ordering != null && ordering.IsTrue)
+            if (m_ordering != null && m_ordering.IsTrue)
             {
-                v.Add(ordering);
+                v.Add(m_ordering);
             }
 
-            v.AddOptional(nonce);
-            v.AddOptionalTagged(true, 0, tsa);
-            v.AddOptionalTagged(false, 1, extensions);
+            v.AddOptional(m_nonce);
+            v.AddOptionalTagged(true, 0, m_tsa);
+            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 027c0a45b..6b3afd553 100644
--- a/crypto/src/asn1/tsp/TimeStampReq.cs
+++ b/crypto/src/asn1/tsp/TimeStampReq.cs
@@ -8,107 +8,90 @@ namespace Org.BouncyCastle.Asn1.Tsp
 	public class TimeStampReq
 		: Asn1Encodable
 	{
-		private readonly DerInteger				version;
-		private readonly MessageImprint			messageImprint;
-		private readonly DerObjectIdentifier	tsaPolicy;
-		private readonly DerInteger				nonce;
-		private readonly DerBoolean				certReq;
-		private readonly X509Extensions			extensions;
+		private readonly DerInteger m_version;
+		private readonly MessageImprint m_messageImprint;
+		private readonly DerObjectIdentifier m_tsaPolicy;
+		private readonly DerInteger m_nonce;
+		private readonly DerBoolean m_certReq;
+		private readonly X509Extensions m_extensions;
 
         public static TimeStampReq GetInstance(object obj)
         {
-            if (obj is TimeStampReq)
-                return (TimeStampReq)obj;
             if (obj == null)
                 return null;
+            if (obj is TimeStampReq timeStampReq)
+                return timeStampReq;
             return new TimeStampReq(Asn1Sequence.GetInstance(obj));
         }
 
+		public static TimeStampReq GetInstance(Asn1TaggedObject taggedObject, bool declaredExplicit)
+		{
+            return new TimeStampReq(Asn1Sequence.GetInstance(taggedObject, declaredExplicit));
+        }
+
         private TimeStampReq(Asn1Sequence seq)
 		{
 			int nbObjects = seq.Count;
 			int seqStart = 0;
 
 			// version
-			version = DerInteger.GetInstance(seq[seqStart++]);
+			m_version = DerInteger.GetInstance(seq[seqStart++]);
 
 			// messageImprint
-			messageImprint = MessageImprint.GetInstance(seq[seqStart++]);
+			m_messageImprint = MessageImprint.GetInstance(seq[seqStart++]);
 
 			for (int opt = seqStart; opt < nbObjects; opt++)
 			{
 				// tsaPolicy
 				if (seq[opt] is DerObjectIdentifier oid)
 				{
-					tsaPolicy = oid;
+					m_tsaPolicy = oid;
 				}
 				// nonce
 				else if (seq[opt] is DerInteger derInteger)
 				{
-					nonce = derInteger;
+					m_nonce = derInteger;
 				}
 				// certReq
 				else if (seq[opt] is DerBoolean derBoolean)
 				{
-					certReq = derBoolean;
+					m_certReq = derBoolean;
 				}
 				// extensions
 				else if (seq[opt] is Asn1TaggedObject tagged)
 				{
 					if (tagged.TagNo == 0)
 					{
-						extensions = X509Extensions.GetInstance(tagged, false);
+						m_extensions = X509Extensions.GetInstance(tagged, false);
 					}
 				}
 			}
 		}
 
-		public TimeStampReq(
-			MessageImprint		messageImprint,
-			DerObjectIdentifier	tsaPolicy,
-			DerInteger			nonce,
-			DerBoolean			certReq,
-			X509Extensions		extensions)
-		{
-			// default
-			this.version = new DerInteger(1);
-
-			this.messageImprint = messageImprint;
-			this.tsaPolicy = tsaPolicy;
-			this.nonce = nonce;
-			this.certReq = certReq;
-			this.extensions = extensions;
-		}
+        public TimeStampReq(MessageImprint messageImprint, DerObjectIdentifier tsaPolicy, DerInteger nonce,
+            DerBoolean certReq, X509Extensions extensions)
+        {
+            // default
+            m_version = new DerInteger(1);
+
+            m_messageImprint = messageImprint;
+            m_tsaPolicy = tsaPolicy;
+            m_nonce = nonce;
+            m_certReq = certReq;
+            m_extensions = extensions;
+        }
 
-		public DerInteger Version
-		{
-			get { return version; }
-		}
+		public DerInteger Version => m_version;
 
-		public MessageImprint MessageImprint
-		{
-			get { return messageImprint; }
-		}
+		public MessageImprint MessageImprint => m_messageImprint;
 
-		public DerObjectIdentifier ReqPolicy
-		{
-			get { return tsaPolicy; }
-		}
+		public DerObjectIdentifier ReqPolicy => m_tsaPolicy;
 
-		public DerInteger Nonce
-		{
-			get { return nonce; }
-		}
+		public DerInteger Nonce => m_nonce;
 
-		public DerBoolean CertReq
-		{
-			get { return certReq; }
-		}
+		public DerBoolean CertReq => m_certReq;
 
-		public X509Extensions Extensions
-		{
-			get { return extensions; }
-		}
+		public X509Extensions Extensions => m_extensions;
 
 		/**
 		 * <pre>
@@ -126,15 +109,16 @@ namespace Org.BouncyCastle.Asn1.Tsp
 		 */
         public override Asn1Object ToAsn1Object()
         {
-            Asn1EncodableVector v = new Asn1EncodableVector(version, messageImprint);
-            v.AddOptional(tsaPolicy, nonce);
+            Asn1EncodableVector v = new Asn1EncodableVector(6);
+			v.Add(m_version, m_messageImprint);
+            v.AddOptional(m_tsaPolicy, m_nonce);
 
-            if (certReq != null && certReq.IsTrue)
+            if (m_certReq != null && m_certReq.IsTrue)
             {
-                v.Add(certReq);
+                v.Add(m_certReq);
             }
 
-            v.AddOptionalTagged(false, 0, extensions);
+            v.AddOptionalTagged(false, 0, m_extensions);
             return new DerSequence(v);
         }
 	}
diff --git a/crypto/src/asn1/tsp/TimeStampResp.cs b/crypto/src/asn1/tsp/TimeStampResp.cs
index 3dde0dfce..cc9c2ed4d 100644
--- a/crypto/src/asn1/tsp/TimeStampResp.cs
+++ b/crypto/src/asn1/tsp/TimeStampResp.cs
@@ -9,46 +9,42 @@ namespace Org.BouncyCastle.Asn1.Tsp
 	public class TimeStampResp
 		: Asn1Encodable
 	{
-		private readonly PkiStatusInfo	pkiStatusInfo;
-		private readonly ContentInfo	timeStampToken;
-
         public static TimeStampResp GetInstance(object obj)
         {
-            if (obj is TimeStampResp)
-                return (TimeStampResp)obj;
             if (obj == null)
                 return null;
+            if (obj is TimeStampResp timeStampResp)
+                return timeStampResp;
             return new TimeStampResp(Asn1Sequence.GetInstance(obj));
         }
 
-        private TimeStampResp(
-			Asn1Sequence seq)
+		public static TimeStampResp GetInstance(Asn1TaggedObject taggedObject, bool declaredExplicit)
+		{
+            return new TimeStampResp(Asn1Sequence.GetInstance(taggedObject, declaredExplicit));
+        }
+
+        private readonly PkiStatusInfo m_pkiStatusInfo;
+        private readonly ContentInfo m_timeStampToken;
+
+        private TimeStampResp(Asn1Sequence seq)
 		{
-			this.pkiStatusInfo = PkiStatusInfo.GetInstance(seq[0]);
+			m_pkiStatusInfo = PkiStatusInfo.GetInstance(seq[0]);
 
 			if (seq.Count > 1)
 			{
-				this.timeStampToken = ContentInfo.GetInstance(seq[1]);
+				m_timeStampToken = ContentInfo.GetInstance(seq[1]);
 			}
 		}
 
-		public TimeStampResp(
-			PkiStatusInfo	pkiStatusInfo,
-			ContentInfo		timeStampToken)
+		public TimeStampResp(PkiStatusInfo pkiStatusInfo, ContentInfo timeStampToken)
 		{
-			this.pkiStatusInfo = pkiStatusInfo;
-			this.timeStampToken = timeStampToken;
+			m_pkiStatusInfo = pkiStatusInfo;
+			m_timeStampToken = timeStampToken;
 		}
 
-		public PkiStatusInfo Status
-		{
-			get { return pkiStatusInfo; }
-		}
+		public PkiStatusInfo Status => m_pkiStatusInfo;
 
-		public ContentInfo TimeStampToken
-		{
-			get { return timeStampToken; }
-		}
+		public ContentInfo TimeStampToken => m_timeStampToken;
 
 		/**
 		 * <pre>
@@ -59,8 +55,9 @@ namespace Org.BouncyCastle.Asn1.Tsp
 		 */
         public override Asn1Object ToAsn1Object()
         {
-            Asn1EncodableVector v = new Asn1EncodableVector(pkiStatusInfo);
-            v.AddOptional(timeStampToken);
+            Asn1EncodableVector v = new Asn1EncodableVector(2);
+			v.Add(m_pkiStatusInfo);
+            v.AddOptional(m_timeStampToken);
             return new DerSequence(v);
         }
 	}