diff --git a/crypto/src/asn1/tsp/Accuracy.cs b/crypto/src/asn1/tsp/Accuracy.cs
new file mode 100644
index 000000000..a193f52ff
--- /dev/null
+++ b/crypto/src/asn1/tsp/Accuracy.cs
@@ -0,0 +1,149 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Tsp
+{
+ public class Accuracy
+ : Asn1Encodable
+ {
+ private readonly DerInteger seconds;
+ private readonly DerInteger millis;
+ private readonly DerInteger micros;
+
+ // constants
+ protected const int MinMillis = 1;
+ protected const int MaxMillis = 999;
+ protected const int MinMicros = 1;
+ protected const int MaxMicros = 999;
+
+ public Accuracy(
+ DerInteger seconds,
+ DerInteger millis,
+ DerInteger micros)
+ {
+ //Verifications
+ if (millis != null
+ && (millis.Value.IntValue < MinMillis
+ || millis.Value.IntValue > MaxMillis))
+ {
+ throw new ArgumentException(
+ "Invalid millis field : not in (1..999)");
+ }
+
+ if (micros != null
+ && (micros.Value.IntValue < MinMicros
+ || micros.Value.IntValue > MaxMicros))
+ {
+ throw new ArgumentException(
+ "Invalid micros field : not in (1..999)");
+ }
+
+ this.seconds = seconds;
+ this.millis = millis;
+ this.micros = micros;
+ }
+
+ private Accuracy(
+ Asn1Sequence seq)
+ {
+ for (int i = 0; i < seq.Count; ++i)
+ {
+ // seconds
+ if (seq[i] is DerInteger)
+ {
+ seconds = (DerInteger) seq[i];
+ }
+ else if (seq[i] is DerTaggedObject)
+ {
+ DerTaggedObject extra = (DerTaggedObject) seq[i];
+
+ switch (extra.TagNo)
+ {
+ case 0:
+ millis = DerInteger.GetInstance(extra, false);
+ if (millis.Value.IntValue < MinMillis
+ || millis.Value.IntValue > MaxMillis)
+ {
+ throw new ArgumentException(
+ "Invalid millis field : not in (1..999).");
+ }
+ break;
+ case 1:
+ micros = DerInteger.GetInstance(extra, false);
+ if (micros.Value.IntValue < MinMicros
+ || micros.Value.IntValue > MaxMicros)
+ {
+ throw new ArgumentException(
+ "Invalid micros field : not in (1..999).");
+ }
+ break;
+ default:
+ throw new ArgumentException("Invalig tag number");
+ }
+ }
+ }
+ }
+
+ public static Accuracy GetInstance(
+ object o)
+ {
+ if (o == null || o is Accuracy)
+ {
+ return (Accuracy) o;
+ }
+
+ if (o is Asn1Sequence)
+ {
+ return new Accuracy((Asn1Sequence) o);
+ }
+
+ throw new ArgumentException(
+ "Unknown object in 'Accuracy' factory: " + o.GetType().FullName);
+ }
+
+ public DerInteger Seconds
+ {
+ get { return seconds; }
+ }
+
+ public DerInteger Millis
+ {
+ get { return millis; }
+ }
+
+ public DerInteger Micros
+ {
+ get { return micros; }
+ }
+
+ /**
+ * <pre>
+ * Accuracy ::= SEQUENCE {
+ * seconds INTEGER OPTIONAL,
+ * millis [0] INTEGER (1..999) OPTIONAL,
+ * micros [1] INTEGER (1..999) OPTIONAL
+ * }
+ * </pre>
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector();
+
+ if (seconds != null)
+ {
+ v.Add(seconds);
+ }
+
+ if (millis != null)
+ {
+ v.Add(new DerTaggedObject(false, 0, millis));
+ }
+
+ if (micros != null)
+ {
+ v.Add(new DerTaggedObject(false, 1, micros));
+ }
+
+ return new DerSequence(v);
+ }
+ }
+}
diff --git a/crypto/src/asn1/tsp/MessageImprint.cs b/crypto/src/asn1/tsp/MessageImprint.cs
new file mode 100644
index 000000000..0933bae21
--- /dev/null
+++ b/crypto/src/asn1/tsp/MessageImprint.cs
@@ -0,0 +1,74 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Tsp
+{
+ public class MessageImprint
+ : Asn1Encodable
+ {
+ private readonly AlgorithmIdentifier hashAlgorithm;
+ private readonly byte[] hashedMessage;
+
+ /**
+ * @param o
+ * @return a MessageImprint object.
+ */
+ public static MessageImprint GetInstance(
+ object o)
+ {
+ if (o == null || o is MessageImprint)
+ {
+ return (MessageImprint) o;
+ }
+
+ if (o is Asn1Sequence)
+ {
+ return new MessageImprint((Asn1Sequence) o);
+ }
+
+ throw new ArgumentException(
+ "Unknown object in 'MessageImprint' factory: " + o.GetType().FullName);
+ }
+
+ private MessageImprint(
+ Asn1Sequence seq)
+ {
+ if (seq.Count != 2)
+ throw new ArgumentException("Wrong number of elements in sequence", "seq");
+
+ this.hashAlgorithm = AlgorithmIdentifier.GetInstance(seq[0]);
+ this.hashedMessage = Asn1OctetString.GetInstance(seq[1]).GetOctets();
+ }
+
+ public MessageImprint(
+ AlgorithmIdentifier hashAlgorithm,
+ byte[] hashedMessage)
+ {
+ this.hashAlgorithm = hashAlgorithm;
+ this.hashedMessage = hashedMessage;
+ }
+
+ public AlgorithmIdentifier HashAlgorithm
+ {
+ get { return hashAlgorithm; }
+ }
+
+ public byte[] GetHashedMessage()
+ {
+ return hashedMessage;
+ }
+
+ /**
+ * <pre>
+ * MessageImprint ::= SEQUENCE {
+ * hashAlgorithm AlgorithmIdentifier,
+ * hashedMessage OCTET STRING }
+ * </pre>
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ return new DerSequence(hashAlgorithm, new DerOctetString(hashedMessage));
+ }
+ }
+}
diff --git a/crypto/src/asn1/tsp/TSTInfo.cs b/crypto/src/asn1/tsp/TSTInfo.cs
new file mode 100644
index 000000000..61d5399c7
--- /dev/null
+++ b/crypto/src/asn1/tsp/TSTInfo.cs
@@ -0,0 +1,249 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1.X509;
+
+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 DerGeneralizedTime 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 o)
+ {
+ if (o == null || o is TstInfo)
+ {
+ return (TstInfo) o;
+ }
+
+ if (o is Asn1Sequence)
+ {
+ return new TstInfo((Asn1Sequence) o);
+ }
+
+ if (o is Asn1OctetString)
+ {
+ try
+ {
+ byte[] octets = ((Asn1OctetString)o).GetOctets();
+ return GetInstance(Asn1Object.FromByteArray(octets));
+ }
+ catch (IOException)
+ {
+ throw new ArgumentException(
+ "Bad object format in 'TstInfo' factory.");
+ }
+ }
+
+ throw new ArgumentException(
+ "Unknown object in 'TstInfo' factory: " + o.GetType().FullName);
+ }
+
+ private TstInfo(
+ Asn1Sequence seq)
+ {
+ IEnumerator e = seq.GetEnumerator();
+
+ // version
+ e.MoveNext();
+ version = DerInteger.GetInstance(e.Current);
+
+ // tsaPolicy
+ e.MoveNext();
+ tsaPolicyId = DerObjectIdentifier.GetInstance(e.Current);
+
+ // messageImprint
+ e.MoveNext();
+ messageImprint = MessageImprint.GetInstance(e.Current);
+
+ // serialNumber
+ e.MoveNext();
+ serialNumber = DerInteger.GetInstance(e.Current);
+
+ // genTime
+ e.MoveNext();
+ genTime = DerGeneralizedTime.GetInstance(e.Current);
+
+ // default for ordering
+ ordering = DerBoolean.False;
+
+ while (e.MoveNext())
+ {
+ Asn1Object o = (Asn1Object) e.Current;
+
+ if (o is Asn1TaggedObject)
+ {
+ DerTaggedObject tagged = (DerTaggedObject) o;
+
+ switch (tagged.TagNo)
+ {
+ case 0:
+ tsa = GeneralName.GetInstance(tagged, true);
+ break;
+ case 1:
+ extensions = X509Extensions.GetInstance(tagged, false);
+ break;
+ default:
+ throw new ArgumentException("Unknown tag value " + tagged.TagNo);
+ }
+ }
+
+ if (o is DerSequence)
+ {
+ accuracy = Accuracy.GetInstance(o);
+ }
+
+ if (o is DerBoolean)
+ {
+ ordering = DerBoolean.GetInstance(o);
+ }
+
+ if (o is DerInteger)
+ {
+ nonce = DerInteger.GetInstance(o);
+ }
+ }
+ }
+
+ public TstInfo(
+ DerObjectIdentifier tsaPolicyId,
+ MessageImprint messageImprint,
+ DerInteger serialNumber,
+ DerGeneralizedTime 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
+ {
+ get { return version; }
+ }
+
+ public MessageImprint MessageImprint
+ {
+ get { return messageImprint; }
+ }
+
+ public DerObjectIdentifier Policy
+ {
+ get { return tsaPolicyId; }
+ }
+
+ public DerInteger SerialNumber
+ {
+ get { return serialNumber; }
+ }
+
+ public Accuracy Accuracy
+ {
+ get { return accuracy; }
+ }
+
+ public DerGeneralizedTime GenTime
+ {
+ get { return genTime; }
+ }
+
+ public DerBoolean Ordering
+ {
+ get { return ordering; }
+ }
+
+ public DerInteger Nonce
+ {
+ get { return nonce; }
+ }
+
+ public GeneralName Tsa
+ {
+ get { return tsa; }
+ }
+
+ public X509Extensions Extensions
+ {
+ get { return extensions; }
+ }
+
+ /**
+ * <pre>
+ *
+ * TstInfo ::= SEQUENCE {
+ * version INTEGER { v1(1) },
+ * policy TSAPolicyId,
+ * messageImprint MessageImprint,
+ * -- MUST have the same value as the similar field in
+ * -- TimeStampReq
+ * serialNumber INTEGER,
+ * -- Time-Stamping users MUST be ready to accommodate integers
+ * -- up to 160 bits.
+ * genTime GeneralizedTime,
+ * accuracy Accuracy OPTIONAL,
+ * ordering BOOLEAN DEFAULT FALSE,
+ * nonce INTEGER OPTIONAL,
+ * -- MUST be present if the similar field was present
+ * -- in TimeStampReq. In that case it MUST have the same value.
+ * tsa [0] GeneralName OPTIONAL,
+ * extensions [1] IMPLICIT Extensions OPTIONAL }
+ *
+ * </pre>
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector(
+ version, tsaPolicyId, messageImprint, serialNumber, genTime);
+
+ if (accuracy != null)
+ {
+ v.Add(accuracy);
+ }
+
+ if (ordering != null && ordering.IsTrue)
+ {
+ v.Add(ordering);
+ }
+
+ if (nonce != null)
+ {
+ v.Add(nonce);
+ }
+
+ if (tsa != null)
+ {
+ v.Add(new DerTaggedObject(true, 0, tsa));
+ }
+
+ if (extensions != null)
+ {
+ v.Add(new DerTaggedObject(false, 1, extensions));
+ }
+
+ return new DerSequence(v);
+ }
+ }
+}
diff --git a/crypto/src/asn1/tsp/TimeStampReq.cs b/crypto/src/asn1/tsp/TimeStampReq.cs
new file mode 100644
index 000000000..55e973e76
--- /dev/null
+++ b/crypto/src/asn1/tsp/TimeStampReq.cs
@@ -0,0 +1,164 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+
+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;
+
+ public static TimeStampReq GetInstance(
+ object o)
+ {
+ if (o == null || o is TimeStampReq)
+ {
+ return (TimeStampReq) o;
+ }
+
+ if (o is Asn1Sequence)
+ {
+ return new TimeStampReq((Asn1Sequence) o);
+ }
+
+ throw new ArgumentException(
+ "Unknown object in 'TimeStampReq' factory: " + o.GetType().FullName);
+ }
+
+ private TimeStampReq(
+ Asn1Sequence seq)
+ {
+ int nbObjects = seq.Count;
+ int seqStart = 0;
+
+ // version
+ version = DerInteger.GetInstance(seq[seqStart++]);
+
+ // messageImprint
+ messageImprint = MessageImprint.GetInstance(seq[seqStart++]);
+
+ for (int opt = seqStart; opt < nbObjects; opt++)
+ {
+ // tsaPolicy
+ if (seq[opt] is DerObjectIdentifier)
+ {
+ tsaPolicy = DerObjectIdentifier.GetInstance(seq[opt]);
+ }
+ // nonce
+ else if (seq[opt] is DerInteger)
+ {
+ nonce = DerInteger.GetInstance(seq[opt]);
+ }
+ // certReq
+ else if (seq[opt] is DerBoolean)
+ {
+ certReq = DerBoolean.GetInstance(seq[opt]);
+ }
+ // extensions
+ else if (seq[opt] is Asn1TaggedObject)
+ {
+ Asn1TaggedObject tagged = (Asn1TaggedObject) seq[opt];
+ if (tagged.TagNo == 0)
+ {
+ 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 DerInteger Version
+ {
+ get { return version; }
+ }
+
+ public MessageImprint MessageImprint
+ {
+ get { return messageImprint; }
+ }
+
+ public DerObjectIdentifier ReqPolicy
+ {
+ get { return tsaPolicy; }
+ }
+
+ public DerInteger Nonce
+ {
+ get { return nonce; }
+ }
+
+ public DerBoolean CertReq
+ {
+ get { return certReq; }
+ }
+
+ public X509Extensions Extensions
+ {
+ get { return extensions; }
+ }
+
+ /**
+ * <pre>
+ * TimeStampReq ::= SEQUENCE {
+ * version INTEGER { v1(1) },
+ * messageImprint MessageImprint,
+ * --a hash algorithm OID and the hash value of the data to be
+ * --time-stamped
+ * reqPolicy TSAPolicyId OPTIONAL,
+ * nonce INTEGER OPTIONAL,
+ * certReq BOOLEAN DEFAULT FALSE,
+ * extensions [0] IMPLICIT Extensions OPTIONAL
+ * }
+ * </pre>
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector(
+ version, messageImprint);
+
+ if (tsaPolicy != null)
+ {
+ v.Add(tsaPolicy);
+ }
+
+ if (nonce != null)
+ {
+ v.Add(nonce);
+ }
+
+ if (certReq != null && certReq.IsTrue)
+ {
+ v.Add(certReq);
+ }
+
+ if (extensions != null)
+ {
+ v.Add(new DerTaggedObject(false, 0, extensions));
+ }
+
+ return new DerSequence(v);
+ }
+ }
+}
diff --git a/crypto/src/asn1/tsp/TimeStampResp.cs b/crypto/src/asn1/tsp/TimeStampResp.cs
new file mode 100644
index 000000000..f26fb30bd
--- /dev/null
+++ b/crypto/src/asn1/tsp/TimeStampResp.cs
@@ -0,0 +1,80 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1.Cmp;
+using Org.BouncyCastle.Asn1.Cms;
+
+namespace Org.BouncyCastle.Asn1.Tsp
+{
+ public class TimeStampResp
+ : Asn1Encodable
+ {
+ private readonly PkiStatusInfo pkiStatusInfo;
+ private readonly ContentInfo timeStampToken;
+
+ public static TimeStampResp GetInstance(
+ object o)
+ {
+ if (o == null || o is TimeStampResp)
+ {
+ return (TimeStampResp) o;
+ }
+
+ if (o is Asn1Sequence)
+ {
+ return new TimeStampResp((Asn1Sequence) o);
+ }
+
+ throw new ArgumentException(
+ "Unknown object in 'TimeStampResp' factory: " + o.GetType().FullName);
+ }
+
+ private TimeStampResp(
+ Asn1Sequence seq)
+ {
+ this.pkiStatusInfo = PkiStatusInfo.GetInstance(seq[0]);
+
+ if (seq.Count > 1)
+ {
+ this.timeStampToken = ContentInfo.GetInstance(seq[1]);
+ }
+ }
+
+ public TimeStampResp(
+ PkiStatusInfo pkiStatusInfo,
+ ContentInfo timeStampToken)
+ {
+ this.pkiStatusInfo = pkiStatusInfo;
+ this.timeStampToken = timeStampToken;
+ }
+
+ public PkiStatusInfo Status
+ {
+ get { return pkiStatusInfo; }
+ }
+
+ public ContentInfo TimeStampToken
+ {
+ get { return timeStampToken; }
+ }
+
+ /**
+ * <pre>
+ * TimeStampResp ::= SEQUENCE {
+ * status PkiStatusInfo,
+ * timeStampToken TimeStampToken OPTIONAL }
+ * </pre>
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector(pkiStatusInfo);
+
+ if (timeStampToken != null)
+ {
+ v.Add(timeStampToken);
+ }
+
+ return new DerSequence(v);
+ }
+ }
+}
|