summary refs log tree commit diff
path: root/crypto/src/tsp/TimeStampResponse.cs
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/src/tsp/TimeStampResponse.cs')
-rw-r--r--crypto/src/tsp/TimeStampResponse.cs184
1 files changed, 184 insertions, 0 deletions
diff --git a/crypto/src/tsp/TimeStampResponse.cs b/crypto/src/tsp/TimeStampResponse.cs
new file mode 100644
index 000000000..069521111
--- /dev/null
+++ b/crypto/src/tsp/TimeStampResponse.cs
@@ -0,0 +1,184 @@
+using System;
+using System.IO;
+using System.Text;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Cmp;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.Tsp;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Tsp
+{
+	/**
+	 * Base class for an RFC 3161 Time Stamp Response object.
+	 */
+	public class TimeStampResponse
+	{
+		private TimeStampResp	resp;
+		private TimeStampToken	timeStampToken;
+
+		public TimeStampResponse(
+			TimeStampResp resp)
+		{
+			this.resp = resp;
+
+			if (resp.TimeStampToken != null)
+			{
+				timeStampToken = new TimeStampToken(resp.TimeStampToken);
+			}
+		}
+
+		/**
+		* Create a TimeStampResponse from a byte array containing an ASN.1 encoding.
+		*
+		* @param resp the byte array containing the encoded response.
+		* @throws TspException if the response is malformed.
+		* @throws IOException if the byte array doesn't represent an ASN.1 encoding.
+		*/
+		public TimeStampResponse(
+			byte[] resp)
+			: this(readTimeStampResp(new Asn1InputStream(resp)))
+		{
+		}
+
+		/**
+		 * Create a TimeStampResponse from an input stream containing an ASN.1 encoding.
+		 *
+		 * @param input the input stream containing the encoded response.
+		 * @throws TspException if the response is malformed.
+		 * @throws IOException if the stream doesn't represent an ASN.1 encoding.
+		 */
+		public TimeStampResponse(
+			Stream input)
+			: this(readTimeStampResp(new Asn1InputStream(input)))
+		{
+		}
+
+		private static TimeStampResp readTimeStampResp(
+			Asn1InputStream input)
+		{
+			try
+			{
+				return TimeStampResp.GetInstance(input.ReadObject());
+			}
+			catch (ArgumentException e)
+			{
+				throw new TspException("malformed timestamp response: " + e, e);
+			}
+			catch (InvalidCastException e)
+			{
+				throw new TspException("malformed timestamp response: " + e, e);
+			}
+		}
+
+		public int Status
+		{
+			get { return resp.Status.Status.IntValue; }
+		}
+
+		public string GetStatusString()
+		{
+			if (resp.Status.StatusString == null)
+			{
+				return null;
+			}
+
+			StringBuilder statusStringBuf = new StringBuilder();
+			PkiFreeText text = resp.Status.StatusString;
+			for (int i = 0; i != text.Count; i++)
+			{
+				statusStringBuf.Append(text[i].GetString());
+			}
+
+			return statusStringBuf.ToString();
+		}
+
+		public PkiFailureInfo GetFailInfo()
+		{
+			if (resp.Status.FailInfo == null)
+			{
+				return null;
+			}
+
+			return new PkiFailureInfo(resp.Status.FailInfo);
+		}
+
+		public TimeStampToken TimeStampToken
+		{
+			get { return timeStampToken; }
+		}
+
+		/**
+		 * Check this response against to see if it a well formed response for
+		 * the passed in request. Validation will include checking the time stamp
+		 * token if the response status is GRANTED or GRANTED_WITH_MODS.
+		 *
+		 * @param request the request to be checked against
+		 * @throws TspException if the request can not match this response.
+		 */
+		public void Validate(
+			TimeStampRequest request)
+		{
+			TimeStampToken tok = this.TimeStampToken;
+
+			if (tok != null)
+			{
+				TimeStampTokenInfo tstInfo = tok.TimeStampInfo;
+
+				if (request.Nonce != null && !request.Nonce.Equals(tstInfo.Nonce))
+				{
+					throw new TspValidationException("response contains wrong nonce value.");
+				}
+
+				if (this.Status != (int) PkiStatus.Granted && this.Status != (int) PkiStatus.GrantedWithMods)
+				{
+					throw new TspValidationException("time stamp token found in failed request.");
+				}
+
+				if (!Arrays.ConstantTimeAreEqual(request.GetMessageImprintDigest(), tstInfo.GetMessageImprintDigest()))
+				{
+					throw new TspValidationException("response for different message imprint digest.");
+				}
+
+				if (!tstInfo.MessageImprintAlgOid.Equals(request.MessageImprintAlgOid))
+				{
+					throw new TspValidationException("response for different message imprint algorithm.");
+				}
+
+				Asn1.Cms.Attribute scV1 = tok.SignedAttributes[PkcsObjectIdentifiers.IdAASigningCertificate];
+				Asn1.Cms.Attribute scV2 = tok.SignedAttributes[PkcsObjectIdentifiers.IdAASigningCertificateV2];
+
+				if (scV1 == null && scV2 == null)
+				{
+					throw new TspValidationException("no signing certificate attribute present.");
+				}
+
+				if (scV1 != null && scV2 != null)
+				{
+					/*
+					 * RFC 5035 5.4. If both attributes exist in a single message,
+					 * they are independently evaluated. 
+					 */
+				}
+
+				if (request.ReqPolicy != null && !request.ReqPolicy.Equals(tstInfo.Policy))
+				{
+					throw new TspValidationException("TSA policy wrong for request.");
+				}
+			}
+			else if (this.Status == (int) PkiStatus.Granted || this.Status == (int) PkiStatus.GrantedWithMods)
+			{
+				throw new TspValidationException("no time stamp token found and one expected.");
+			}
+		}
+
+		/**
+		 * return the ASN.1 encoded representation of this object.
+		 */
+		public byte[] GetEncoded()
+		{
+			return resp.GetEncoded();
+		}
+	}
+}