summary refs log tree commit diff
diff options
context:
space:
mode:
authormw <megan@cryptoworkshop.com>2020-10-27 09:52:43 +1100
committermw <megan@cryptoworkshop.com>2020-10-27 09:52:43 +1100
commit6cc9728c5f463bbe786dd2bb192b16ea6ae2531e (patch)
treee8d446819327bb1256ea9c9d9fe8b2f724b8f661
parentUpdated TableGen2 to use IdAASigningCertificateV2 oid (diff)
downloadBouncyCastle.NET-ed25519-6cc9728c5f463bbe786dd2bb192b16ea6ae2531e.tar.xz
Added fractional time and new tests
-rw-r--r--crypto/src/tsp/TimeStampTokenGenerator.cs77
-rw-r--r--crypto/test/src/tsp/test/NewTspTest.cs551
2 files changed, 627 insertions, 1 deletions
diff --git a/crypto/src/tsp/TimeStampTokenGenerator.cs b/crypto/src/tsp/TimeStampTokenGenerator.cs
index ae4a0caeb..5badcfdd0 100644
--- a/crypto/src/tsp/TimeStampTokenGenerator.cs
+++ b/crypto/src/tsp/TimeStampTokenGenerator.cs
@@ -1,7 +1,9 @@
 using System;
 using System.Collections;
 using System.IO;
+using System.Text;
 using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Cms;
 using Org.BouncyCastle.Asn1.Ess;
 using Org.BouncyCastle.Asn1.Oiw;
 using Org.BouncyCastle.Asn1.Pkcs;
@@ -17,6 +19,11 @@ using Org.BouncyCastle.X509.Store;
 
 namespace Org.BouncyCastle.Tsp
 {
+    public enum Resolution
+    {
+        R_SECONDS, R_TENTHS_OF_SECONDS, R_HUNDREDTHS_OF_SECONDS, R_MILLISECONDS
+    }
+
     public class TimeStampTokenGenerator
     {
         private int accuracySeconds = -1;
@@ -31,6 +38,14 @@ namespace Org.BouncyCastle.Tsp
         private SignerInfoGenerator signerInfoGenerator;
         IDigestFactory digestCalculator;
 
+        private Resolution resolution = Resolution.R_SECONDS;
+      
+        public Resolution Resolution
+        {
+            get { return resolution; }
+            set { resolution = value; }
+        }
+
         /**
 		 * basic creation - only the default attributes will be included here.
 		 */
@@ -289,8 +304,18 @@ namespace Org.BouncyCastle.Tsp
                 tsaPolicy = new DerObjectIdentifier(request.ReqPolicy);
             }
 
+            DerGeneralizedTime generalizedTime;
+            if (resolution != Resolution.R_SECONDS)
+            {
+                generalizedTime = new DerGeneralizedTime(createGeneralizedTime(genTime));
+            } else
+            {
+                generalizedTime = new DerGeneralizedTime(genTime);
+            }
+
+
             TstInfo tstInfo = new TstInfo(tsaPolicy, messageImprint,
-                new DerInteger(serialNumber), new DerGeneralizedTime(genTime), accuracy,
+                new DerInteger(serialNumber), generalizedTime, accuracy,
                 derOrdering, nonce, tsa, request.Extensions);
 
             try
@@ -333,6 +358,56 @@ namespace Org.BouncyCastle.Tsp
             //			}
         }
 
+        private string createGeneralizedTime(DateTime genTime)
+        {
+            String format = "yyyyMMddHHmmss.fff";
+           
+            StringBuilder sBuild = new StringBuilder(genTime.ToString(format));
+            int dotIndex = sBuild.ToString().IndexOf(".");
+
+            if (dotIndex <0)
+            {
+                sBuild.Append("Z");
+                return sBuild.ToString();
+            }
+
+            switch(resolution)
+            {
+                case Resolution.R_TENTHS_OF_SECONDS:
+                    if (sBuild.Length > dotIndex + 2)
+                    {
+                        sBuild.Remove(dotIndex + 2, sBuild.Length-(dotIndex+2));
+                    }
+                    break;
+                case Resolution.R_HUNDREDTHS_OF_SECONDS:
+                    if (sBuild.Length > dotIndex + 3)
+                    {
+                        sBuild.Remove(dotIndex + 3, sBuild.Length-(dotIndex+3));
+                    }
+                    break;
+
+
+                case Resolution.R_SECONDS:
+                case Resolution.R_MILLISECONDS:
+                    // do nothing.
+                    break;
+             
+            }
+
+           
+            while (sBuild[sBuild.Length - 1] == '0')
+            {
+                sBuild.Remove(sBuild.Length - 1,1);
+            }
+
+            if (sBuild.Length - 1 == dotIndex)
+            {
+                sBuild.Remove(sBuild.Length - 1, 1);
+            }
+
+            sBuild.Append("Z");
+            return sBuild.ToString();
+        }
 
         private class TableGen : CmsAttributeTableGenerator
         {
diff --git a/crypto/test/src/tsp/test/NewTspTest.cs b/crypto/test/src/tsp/test/NewTspTest.cs
new file mode 100644
index 000000000..b12035928
--- /dev/null
+++ b/crypto/test/src/tsp/test/NewTspTest.cs
@@ -0,0 +1,551 @@
+using NUnit.Framework;
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Cmp;
+using Org.BouncyCastle.Asn1.Cms;
+using Org.BouncyCastle.Asn1.Ess;
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.Oiw;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Cms;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Operators;
+using Org.BouncyCastle.Crypto.Paddings;
+using Org.BouncyCastle.Crypto.Tls;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.X509;
+using Org.BouncyCastle.X509.Store;
+using System;
+using System.Collections;
+using System.IO;
+
+
+namespace Org.BouncyCastle.Tsp.Tests
+{
+
+
+	public class NewTspTest
+	{
+		private static DateTime UnixEpoch = new DateTime(1970, 1, 1, 0, 0, 0);
+
+
+		[Test]
+		public void TestGeneral()
+		{
+			string signDN = "O=Bouncy Castle, C=AU";
+			AsymmetricCipherKeyPair signKP = TspTestUtil.MakeKeyPair();
+			X509Certificate signCert = TspTestUtil.MakeCACertificate(signKP, signDN, signKP, signDN);
+
+			string origDN = "CN=Eric H. Echidna, E=eric@bouncycastle.org, O=Bouncy Castle, C=AU";
+			AsymmetricCipherKeyPair origKP = TspTestUtil.MakeKeyPair();
+			var privateKey = origKP.Private;
+
+			var cert = TspTestUtil.MakeCertificate(origKP, origDN, signKP, signDN);
+
+			IList certList = new ArrayList();
+			certList.Add(cert);
+			certList.Add(signCert);
+
+			var certs = X509StoreFactory.Create(
+				"Certificate/Collection",
+				new X509CollectionStoreParameters(certList));
+
+
+
+			basicTest(origKP.Private, cert, certs);
+			resolutionTest(origKP.Private, cert, certs, Resolution.R_SECONDS, "19700101000009Z");
+			resolutionTest(origKP.Private, cert, certs, Resolution.R_TENTHS_OF_SECONDS, "19700101000009.9Z");
+			resolutionTest(origKP.Private, cert, certs, Resolution.R_HUNDREDTHS_OF_SECONDS, "19700101000009.99Z");
+			resolutionTest(origKP.Private, cert, certs, Resolution.R_MILLISECONDS, "19700101000009.999Z");
+			basicSha256Test(origKP.Private, cert, certs);
+			basicTestWithTSA(origKP.Private, cert, certs);
+			overrideAttrsTest(origKP.Private, cert, certs);
+			responseValidationTest(origKP.Private, cert, certs);
+			incorrectHashTest(origKP.Private, cert, certs);
+			badAlgorithmTest(origKP.Private, cert, certs);
+			//timeNotAvailableTest(origKP.Private, cert, certs);
+
+
+		}
+
+        private void timeNotAvailableTest(AsymmetricKeyParameter privateKey, X509Certificate cert, IX509Store certs)
+        {
+			TimeStampTokenGenerator tsTokenGen = new TimeStampTokenGenerator(
+				   privateKey, cert, TspAlgorithms.Sha1, "1.2");
+
+			tsTokenGen.SetCertificates(certs);
+
+			TimeStampRequestGenerator reqGen = new TimeStampRequestGenerator();
+			TimeStampRequest request = reqGen.Generate(new DerObjectIdentifier("1.2.3.4.5"), new byte[20]);
+
+			TimeStampResponseGenerator tsRespGen = new TimeStampResponseGenerator(tsTokenGen, TspAlgorithms.Allowed);			
+
+			TimeStampResponse tsResp = null;
+
+			try
+			{
+				tsResp = tsRespGen.Generate(request, new BigInteger("23"), null);
+			}
+			catch (TspException e)
+			{
+				Console.WriteLine();
+			}
+
+			tsResp = new TimeStampResponse(tsResp.GetEncoded());
+
+			//TimeStampToken tsToken = tsResp.TimeStampToken;
+
+			//if (tsToken != null)
+			//{
+			//	fail("timeNotAvailable - token not null.");
+			//}
+
+			//PKIFailureInfo failInfo = tsResp.getFailInfo();
+
+			//if (failInfo == null)
+			//{
+			//	fail("timeNotAvailable - failInfo set to null.");
+			//}
+
+			//if (failInfo.intValue() != PKIFailureInfo.timeNotAvailable)
+			//{
+			//	fail("timeNotAvailable - wrong failure info returned.");
+			//}
+		}
+
+        private void badAlgorithmTest(AsymmetricKeyParameter privateKey, X509Certificate cert, IX509Store certs)
+        {
+			TimeStampTokenGenerator tsTokenGen = new TimeStampTokenGenerator(
+				   privateKey, cert, TspAlgorithms.Sha1, "1.2");
+
+			tsTokenGen.SetCertificates(certs);
+
+			TimeStampRequestGenerator reqGen = new TimeStampRequestGenerator();
+			TimeStampRequest request = reqGen.Generate(new DerObjectIdentifier("1.2.3.4.5"), new byte[21]);
+
+			TimeStampResponseGenerator tsRespGen = new TimeStampResponseGenerator(tsTokenGen, TspAlgorithms.Allowed);
+
+			TimeStampResponse tsResp = tsRespGen.Generate(request, BigInteger.ValueOf(23), DateTime.UtcNow);
+
+			tsResp = new TimeStampResponse(tsResp.GetEncoded());
+
+			TimeStampToken tsToken = tsResp.TimeStampToken;
+
+			if (tsToken != null)
+			{
+				Assert.Fail("badAlgorithm - token not null.");
+			}
+
+			PkiFailureInfo failInfo = tsResp.GetFailInfo();
+
+			if (failInfo == null)
+			{
+				Assert.Fail("badAlgorithm - failInfo set to null.");
+			}
+
+			if (failInfo.IntValue != PkiFailureInfo.BadAlg)
+			{
+				Assert.Fail("badAlgorithm - wrong failure info returned.");
+			}
+		}
+
+		private void incorrectHashTest(AsymmetricKeyParameter privateKey, X509Certificate cert, IX509Store certs)
+        {
+			TimeStampTokenGenerator tsTokenGen = new TimeStampTokenGenerator(
+				  privateKey, cert, TspAlgorithms.Sha1, "1.2");
+
+			tsTokenGen.SetCertificates(certs);
+
+			TimeStampRequestGenerator reqGen = new TimeStampRequestGenerator();
+			TimeStampRequest request = reqGen.Generate(TspAlgorithms.Sha1, new byte[16]);
+
+			TimeStampResponseGenerator tsRespGen = new TimeStampResponseGenerator(tsTokenGen, TspAlgorithms.Allowed);
+
+			TimeStampResponse tsResp = tsRespGen.Generate(request, BigInteger.ValueOf(23), DateTime.UtcNow);
+
+			tsResp = new TimeStampResponse(tsResp.GetEncoded());
+
+			TimeStampToken tsToken = tsResp.TimeStampToken;
+
+			Assert.IsNull(tsToken,"incorrect hash -- token not null");
+
+			PkiFailureInfo failInfo = tsResp.GetFailInfo();
+			if (failInfo == null)
+            {
+				Assert.Fail("incorrectHash - failInfo set to null.");
+            }
+
+			if (failInfo.IntValue != PkiFailureInfo.BadDataFormat)
+            {
+				Assert.Fail("incorrectHash - wrong failure info returned.");
+			}
+
+		}
+
+        private void responseValidationTest(AsymmetricKeyParameter privateKey, X509Certificate cert, IX509Store certs)
+        {
+			TimeStampTokenGenerator tsTokenGen = new TimeStampTokenGenerator(
+				 privateKey, cert, TspAlgorithms.MD5, "1.2");
+
+			tsTokenGen.SetCertificates(certs);
+			
+
+			TimeStampRequestGenerator reqGen = new TimeStampRequestGenerator();
+			TimeStampRequest request = reqGen.Generate(TspAlgorithms.Sha1, new byte[20], BigInteger.ValueOf(100));
+
+			TimeStampResponseGenerator tsRespGen = new TimeStampResponseGenerator(tsTokenGen, TspAlgorithms.Allowed);
+
+			TimeStampResponse tsResp = tsRespGen.Generate(request, BigInteger.ValueOf(23), DateTime.UtcNow);
+
+			tsResp = new TimeStampResponse(tsResp.GetEncoded());
+
+			TimeStampToken tsToken = tsResp.TimeStampToken;
+
+			tsToken.Validate(cert);
+
+
+			try
+			{
+				request = reqGen.Generate(TspAlgorithms.Sha1, new byte[20], BigInteger.ValueOf(101));
+
+				tsResp.Validate(request);
+
+				Assert.Fail("response validation failed on invalid nonce.");
+			}
+			catch (TspValidationException e)
+			{
+				// ignore
+			}
+
+			try
+			{
+				request = reqGen.Generate(TspAlgorithms.Sha1, new byte[22], BigInteger.ValueOf(100));
+
+				tsResp.Validate(request);
+
+				Assert.Fail("response validation failed on wrong digest.");
+			}
+			catch (TspValidationException e)
+			{
+				// ignore
+			}
+
+			try
+			{
+				request = reqGen.Generate(TspAlgorithms.MD5, new byte[20], BigInteger.ValueOf(100));
+
+				tsResp.Validate(request);
+
+				Assert.Fail("response validation failed on wrong digest.");
+			}
+			catch (TspValidationException e)
+			{
+				// ignore
+			}
+
+		}
+
+		private void overrideAttrsTest(AsymmetricKeyParameter privateKey, X509Certificate cert, IX509Store certs)
+		{
+			SignerInfoGeneratorBuilder signerInfoGenBuilder = new SignerInfoGeneratorBuilder();
+
+			IssuerSerial issuerSerial = new IssuerSerial(
+				new GeneralNames(
+					new GeneralName(
+						X509CertificateStructure.GetInstance(cert.GetEncoded()).Issuer)),
+				new DerInteger(cert.SerialNumber));
+
+			byte[] certHash256;
+			byte[] certHash;
+
+			{
+				Asn1DigestFactory digCalc = Asn1DigestFactory.Get(OiwObjectIdentifiers.IdSha1);
+				IStreamCalculator calc = digCalc.CreateCalculator();
+				using (Stream s = calc.Stream)
+				{
+					var crt = cert.GetEncoded();
+					s.Write(crt, 0, crt.Length);
+				}
+
+				certHash = ((SimpleBlockResult)calc.GetResult()).Collect();
+			}
+
+
+			{
+				Asn1DigestFactory digCalc = Asn1DigestFactory.Get(NistObjectIdentifiers.IdSha256);
+				IStreamCalculator calc = digCalc.CreateCalculator();
+				using (Stream s = calc.Stream)
+				{
+					var crt = cert.GetEncoded();
+					s.Write(crt, 0, crt.Length);
+				}
+
+				certHash256 = ((SimpleBlockResult)calc.GetResult()).Collect();
+			}
+
+
+			EssCertID essCertid = new EssCertID(certHash, issuerSerial);
+			EssCertIDv2 essCertidV2 = new EssCertIDv2(certHash256, issuerSerial);
+
+			signerInfoGenBuilder.WithSignedAttributeGenerator(new TestAttrGen()
+			{
+				EssCertID = essCertid,
+				EssCertIDv2 = essCertidV2
+			});
+
+
+			Asn1SignatureFactory sigfact = new Asn1SignatureFactory("SHA1WithRSA", privateKey);
+			SignerInfoGenerator
+				 signerInfoGenerator = signerInfoGenBuilder.Build(sigfact, cert);
+
+			TimeStampTokenGenerator tsTokenGen = new TimeStampTokenGenerator(
+				signerInfoGenerator,
+				Asn1DigestFactory.Get(OiwObjectIdentifiers.IdSha1), new DerObjectIdentifier("1.2"), true);
+
+
+			tsTokenGen.SetCertificates(certs);
+		
+
+			TimeStampRequestGenerator reqGen = new TimeStampRequestGenerator();
+			TimeStampRequest request = reqGen.Generate(TspAlgorithms.Sha1, new byte[20], BigInteger.ValueOf(100));
+
+			TimeStampResponseGenerator tsRespGen = new TimeStampResponseGenerator(tsTokenGen, TspAlgorithms.Allowed);
+
+			TimeStampResponse tsResp = tsRespGen.Generate(request, BigInteger.ValueOf(23), DateTime.UtcNow);
+
+			tsResp = new TimeStampResponse(tsResp.GetEncoded());
+
+			TimeStampToken tsToken = tsResp.TimeStampToken;
+
+			tsToken.Validate(cert);
+
+			Asn1.Cms.AttributeTable table = tsToken.SignedAttributes;
+
+			Assert.NotNull( table[PkcsObjectIdentifiers.IdAASigningCertificate], "no signingCertificate attribute found");
+			Assert.NotNull( table[PkcsObjectIdentifiers.IdAASigningCertificateV2], "no signingCertificateV2 attribute found");
+
+			SigningCertificate sigCert = SigningCertificate.GetInstance(table[PkcsObjectIdentifiers.IdAASigningCertificate].AttrValues[0]);
+
+			Assert.IsTrue(cert.CertificateStructure.Issuer.Equals( sigCert.GetCerts()[0].IssuerSerial.Issuer.GetNames()[0].Name));
+			Assert.IsTrue(cert.CertificateStructure.SerialNumber.Value.Equals( sigCert.GetCerts()[0].IssuerSerial.Serial.Value));
+			Assert.IsTrue(Arrays.AreEqual(certHash, sigCert.GetCerts()[0].GetCertHash()));
+
+			SigningCertificate sigCertV2 = SigningCertificate.GetInstance(table[PkcsObjectIdentifiers.IdAASigningCertificateV2].AttrValues[0]);
+
+			Assert.IsTrue(cert.CertificateStructure.Issuer.Equals(sigCertV2.GetCerts()[0].IssuerSerial.Issuer.GetNames()[0].Name));
+			Assert.IsTrue(cert.CertificateStructure.SerialNumber.Value.Equals(sigCertV2.GetCerts()[0].IssuerSerial.Serial.Value));
+			Assert.IsTrue(Arrays.AreEqual(certHash256, sigCertV2.GetCerts()[0].GetCertHash()));
+
+		}
+
+
+
+
+		private void basicTestWithTSA(AsymmetricKeyParameter privateKey, X509Certificate cert, IX509Store certs)
+		{
+			TimeStampTokenGenerator tsTokenGen = new TimeStampTokenGenerator(
+				 privateKey, cert, TspAlgorithms.Sha1, "1.2");
+
+			tsTokenGen.SetCertificates(certs);
+			tsTokenGen.SetTsa(new Asn1.X509.GeneralName(new X509Name("CN=Test")));
+
+			TimeStampRequestGenerator reqGen = new TimeStampRequestGenerator();
+			TimeStampRequest request = reqGen.Generate(TspAlgorithms.Sha1, new byte[20], BigInteger.ValueOf(100));
+
+			TimeStampResponseGenerator tsRespGen = new TimeStampResponseGenerator(tsTokenGen, TspAlgorithms.Allowed);
+
+			TimeStampResponse tsResp = tsRespGen.Generate(request, BigInteger.ValueOf(23), DateTime.UtcNow);
+
+			tsResp = new TimeStampResponse(tsResp.GetEncoded());
+
+			TimeStampToken tsToken = tsResp.TimeStampToken;
+
+			tsToken.Validate(cert);
+
+			Asn1.Cms.AttributeTable table = tsToken.SignedAttributes;
+
+			Assert.IsNotNull(table[PkcsObjectIdentifiers.IdAASigningCertificate], "no signingCertificate attribute found");
+
+		}
+
+		private void basicSha256Test(AsymmetricKeyParameter privateKey, X509Certificate cert, IX509Store certs)
+		{
+			var sInfoGenerator = makeInfoGenerator(privateKey, cert, TspAlgorithms.Sha256, null, null);
+			TimeStampTokenGenerator tsTokenGen = new TimeStampTokenGenerator(
+				sInfoGenerator,
+				Asn1DigestFactory.Get(NistObjectIdentifiers.IdSha256), new DerObjectIdentifier("1.2"), true);
+
+
+			tsTokenGen.SetCertificates(certs);
+
+			TimeStampRequestGenerator reqGen = new TimeStampRequestGenerator();
+			TimeStampRequest request = reqGen.Generate(TspAlgorithms.Sha256, new byte[32], BigInteger.ValueOf(100));
+
+			TimeStampResponseGenerator tsRespGen = new TimeStampResponseGenerator(tsTokenGen, TspAlgorithms.Allowed);
+
+			TimeStampResponse tsResp = tsRespGen.Generate(request, new BigInteger("23"), DateTime.Now);
+
+			Assert.AreEqual((int)PkiStatus.Granted, tsResp.Status);
+
+			tsResp = new TimeStampResponse(tsResp.GetEncoded());
+
+			TimeStampToken tsToken = tsResp.TimeStampToken;
+
+			tsToken.Validate(cert);
+
+			Asn1.Cms.AttributeTable table = tsToken.SignedAttributes;
+
+			Assert.NotNull(table[PkcsObjectIdentifiers.IdAASigningCertificateV2]);
+
+			Asn1DigestFactory digCalc = Asn1DigestFactory.Get(NistObjectIdentifiers.IdSha256);
+			IStreamCalculator calc = digCalc.CreateCalculator();
+			using (Stream s = calc.Stream)
+			{
+				var crt = cert.GetEncoded();
+				s.Write(crt, 0, crt.Length);
+			}
+
+			byte[] certHash = ((SimpleBlockResult)calc.GetResult()).Collect();
+
+			SigningCertificateV2 sigCertV2 = SigningCertificateV2.GetInstance(table[PkcsObjectIdentifiers.IdAASigningCertificateV2].AttrValues[0]);
+
+			Assert.IsTrue(Arrays.AreEqual(certHash, sigCertV2.GetCerts()[0].GetCertHash()));
+		}
+
+
+		private void resolutionTest(AsymmetricKeyParameter privateKey, X509.X509Certificate cert, IX509Store certs, Resolution resoution, string timeString)
+		{
+			TimeStampTokenGenerator tsTokenGen = new TimeStampTokenGenerator(
+			 privateKey, cert, TspAlgorithms.Sha1, "1.2");
+
+			tsTokenGen.Resolution = resoution;
+			tsTokenGen.SetCertificates(certs);
+
+			TimeStampRequestGenerator reqGen = new TimeStampRequestGenerator();
+			TimeStampRequest request = reqGen.Generate(TspAlgorithms.Sha1, new byte[20], BigInteger.ValueOf(100));
+
+			TimeStampResponseGenerator tsRespGen = new TimeStampResponseGenerator(tsTokenGen, TspAlgorithms.Allowed);
+
+			TimeStampResponse tsResp = tsRespGen.Generate(request, BigInteger.ValueOf(23), UnixEpoch.AddMilliseconds(9999));
+
+			tsResp = new TimeStampResponse(tsResp.GetEncoded());
+
+			TimeStampToken tsToken = tsResp.TimeStampToken;
+
+			// This done instead of relying on string comparison.
+			Assert.AreEqual(timeString, tsToken.TimeStampInfo.TstInfo.GenTime.TimeString);
+
+			tsResp = tsRespGen.Generate(request, new BigInteger("23"), UnixEpoch.AddMilliseconds(9000));
+			tsToken = tsResp.TimeStampToken;
+			Assert.AreEqual("19700101000009Z", tsToken.TimeStampInfo.TstInfo.GenTime.TimeString);
+
+			if ((int)resoution > (int)Resolution.R_HUNDREDTHS_OF_SECONDS)
+			{
+				tsResp = tsRespGen.Generate(request, new BigInteger("23"), UnixEpoch.AddMilliseconds(9990));
+				tsToken = tsResp.TimeStampToken;
+				Assert.AreEqual("19700101000009.99Z", tsToken.TimeStampInfo.TstInfo.GenTime.TimeString);
+			}
+
+			if ((int)resoution > (int)Resolution.R_TENTHS_OF_SECONDS)
+			{
+				tsResp = tsRespGen.Generate(request, new BigInteger("23"), UnixEpoch.AddMilliseconds(9900));
+				tsToken = tsResp.TimeStampToken;
+				Assert.AreEqual("19700101000009.9Z", tsToken.TimeStampInfo.TstInfo.GenTime.TimeString);
+			}
+
+
+		}
+
+		private void basicTest(AsymmetricKeyParameter privateKey, X509.X509Certificate cert, IX509Store certs)
+		{
+			TimeStampTokenGenerator tsTokenGen = new TimeStampTokenGenerator(
+				 privateKey, cert, TspAlgorithms.Sha1, "1.2");
+
+			tsTokenGen.SetCertificates(certs);
+
+			TimeStampRequestGenerator reqGen = new TimeStampRequestGenerator();
+			TimeStampRequest request = reqGen.Generate(TspAlgorithms.Sha1, new byte[20], BigInteger.ValueOf(100));
+
+			TimeStampResponseGenerator tsRespGen = new TimeStampResponseGenerator(tsTokenGen, TspAlgorithms.Allowed);
+
+			TimeStampResponse tsResp = tsRespGen.Generate(request, BigInteger.ValueOf(23), DateTime.UtcNow);
+
+			tsResp = new TimeStampResponse(tsResp.GetEncoded());
+
+			TimeStampToken tsToken = tsResp.TimeStampToken;
+
+			tsToken.Validate(cert);
+
+			Asn1.Cms.AttributeTable table = tsToken.SignedAttributes;
+
+			Assert.IsNotNull(table[PkcsObjectIdentifiers.IdAASigningCertificate], "no signingCertificate attribute found");
+
+
+		}
+
+		internal static SignerInfoGenerator makeInfoGenerator(
+		 AsymmetricKeyParameter key,
+		 X509Certificate cert,
+		 string digestOID,
+
+		 Asn1.Cms.AttributeTable signedAttr,
+		 Asn1.Cms.AttributeTable unsignedAttr)
+		{
+
+
+			TspUtil.ValidateCertificate(cert);
+
+			//
+			// Add the ESSCertID attribute
+			//
+			IDictionary signedAttrs;
+			if (signedAttr != null)
+			{
+				signedAttrs = signedAttr.ToDictionary();
+			}
+			else
+			{
+				signedAttrs = Platform.CreateHashtable();
+			}
+
+
+
+			string digestName = CmsSignedHelper.Instance.GetDigestAlgName(digestOID);
+			string signatureName = digestName + "with" + CmsSignedHelper.Instance.GetEncryptionAlgName(CmsSignedHelper.Instance.GetEncOid(key, digestOID));
+
+			Asn1SignatureFactory sigfact = new Asn1SignatureFactory(signatureName, key);
+			return new SignerInfoGeneratorBuilder()
+			 .WithSignedAttributeGenerator(
+				new DefaultSignedAttributeTableGenerator(
+					new Asn1.Cms.AttributeTable(signedAttrs)))
+			  .WithUnsignedAttributeGenerator(
+				new SimpleAttributeTableGenerator(unsignedAttr))
+				.Build(sigfact, cert);
+		}
+
+
+
+
+		private class TestAttrGen : CmsAttributeTableGenerator
+		{
+
+			public EssCertID EssCertID { get; set; }
+
+			public EssCertIDv2 EssCertIDv2 { get; set; }
+
+			public Asn1.Cms.AttributeTable GetAttributes(IDictionary parameters)
+			{
+				CmsAttributeTableGenerator attrGen = new DefaultSignedAttributeTableGenerator();
+
+				Asn1.Cms.AttributeTable table = attrGen.GetAttributes(parameters);
+				table = table.Add(PkcsObjectIdentifiers.IdAASigningCertificate, new SigningCertificate(EssCertID));
+				table = table.Add(PkcsObjectIdentifiers.IdAASigningCertificateV2, new SigningCertificateV2(new EssCertIDv2[] { EssCertIDv2 }));
+
+				return table;
+			}
+		}
+
+	}
+
+}