DigiStamp - digital timestamp using C# www.digistamp.com Code examples to help you integrated RFC3161 Secure Digital Timestamp into you C# project. *** Create a timestamp, method 1 using Org.BouncyCastle.Tsp; using Org.BouncyCastle.Math; SHA1 sha1 = SHA1CryptoServiceProvider.Create(); byte[] hash = sha1.ComputeHash(Encoding.ASCII.GetBytes(data)); TimeStampRequestGenerator reqGen = new TimeStampRequestGenerator(); reqGen.SetCertReq(true); TimeStampRequest tsReq = reqGen.Generate(TspAlgorithms.Sha1, hash, BigInteger.ValueOf(100)); byte[] tsData = tsReq.GetEncoded(); HttpWebRequest req = (HttpWebRequest)WebRequest.Create("http://tsatest.digistamp.com"); req.Method = "POST"; req.ContentType = "application/timestamp-query"; req.Headers.Add("Authorization", "Basic " + Convert.ToBase64String(Encoding.ASCII.GetBytes("9024:yourPass"))); req.ContentLength = tsData.Length; Stream reqStream = req.GetRequestStream(); reqStream.Write(tsData, 0, tsData.Length); reqStream.Close(); HttpWebResponse res = (HttpWebResponse) req.GetResponse(); if (res == null) { return false; } else { Stream resStream = new BufferedStream(res.GetResponseStream()); TimeStampResponse tsRes = new TimeStampResponse(resStream); resStream.Close(); try { tsRes.Validate(tsReq); } catch (TspException e) { Console.WriteLine(e.Message); return false; } *** Create a timestamp, method 2 This is an alternative C# implementation that was developed by: Copyright (C) 2009-2010 Estonian Informatics Centre http://esteid.googlecode.com/svn-history/r2686/plugins/acrobat/trunk/EstEIDSigner/X509Utils.cs using Org.BouncyCastle.Tsp; static public byte[] GetTimestampToken(String tsaURL, string tsaUserName, string tsaPassword, byte[] imprint, ref string error) { TimeStampRequestGenerator tsqGenerator = new TimeStampRequestGenerator(); tsqGenerator.SetCertReq(true); BigInteger nonce = BigInteger.ValueOf(DateTime.Now.Ticks); TimeStampRequest request = tsqGenerator.Generate(X509ObjectIdentifiers.IdSha1.Id, imprint, nonce); byte[] requestBytes = request.GetEncoded(); byte[] responseBytes = GetTSAResponse(tsaURL, tsaUserName, tsaPassword, requestBytes); TimeStampResponse response = new TimeStampResponse(responseBytes); response.Validate(request); PkiFailureInfo failure = response.GetFailInfo(); int value = (failure == null) ? 0 : failure.IntValue; if (value != 0) { error = string.Format(Resources.TSA_URL_ERROR, tsaURL, value); return (null); } TimeStampToken tsToken = response.TimeStampToken; if (tsToken == null) { error = string.Format(Resources.TSA_READ_ERROR, tsaURL); return (null); } return tsToken.GetEncoded(); } static protected byte[] GetTSAResponse(String tsaURL, string tsaUserName, string tsaPassword, byte[] requestBytes) { Uri uri = new Uri(tsaURL); HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri); request.ContentType = "application/timestamp-query"; request.ContentLength = requestBytes.Length; request.Method = "POST"; if ((tsaUserName != null) && (tsaUserName != "")) { String userPassword = tsaUserName + ":" + tsaPassword; CredentialCache credCache = new CredentialCache(); credCache.Add(new Uri(tsaURL), "Basic", new NetworkCredential(tsaUserName, tsaPassword, tsaURL)); request.Credentials = credCache; } Stream requestStream = request.GetRequestStream(); requestStream.Write(requestBytes, 0, requestBytes.Length); requestStream.Close(); WebResponse response = request.GetResponse(); Stream resStream = response.GetResponseStream(); MemoryStream ms = new MemoryStream(); byte[] responseBytes; byte[] buffer = new byte[4096]; using (MemoryStream memoryStream = new MemoryStream()) { int count = 0; do { count = resStream.Read(buffer, 0, buffer.Length); memoryStream.Write(buffer, 0, count); } while (count != 0); responseBytes = memoryStream.ToArray(); } response.Close(); return responseBytes; } *** Save the time stamp to disk In TimeStampResponse.cs see method TimeStampToken tsToken = tsResp.TimeStampToken; Then in TimeStampToken.cs see method: public byte[] GetEncoded() It is the encode byte[] that you want to save. At a later time recreate the object from disk with: new TimeStampToken(new CMSSignedData(bytes))); *** Verifying a timestamp Please see Org.BouncyCastle.Tsp.Tests.TspTest The actual signature verification is In TimeStampToken.cs see method: public void Validate(X509Certificate cert) e.g. TimeStampToken tsToken = tsResp.TimeStampToken; tsToken.Validate(cert); *** Verifying a timestamp: finding the correct public key certificate You will need to retrieve the certificate from the time stamp: IX509Store respCerts = tsToken.GetCertificates("Collection"); ICollection certsColl = respCerts.GetMatches(null); /* * Find the certificate that was identified for verify this time stamp's * signature. DigiStamp return 2 certificates with the time stamp (assuming * your request had requested certificates be included). Only one of the * certificates is used to verify the signature on the time stamp. The other * certificate is used for certificate chaining to a root (more details at * our web site about certificate hierarchy). This code has not yet been * ported from Java to C#. As an initial and easier test you could just use * the 1st member in the collection. */ X509Certificate findCorrectCertificate(CMSTsToken cms, X509Certificate[] certs) throws ExceptionDgsEncode, CertificateEncodingException { boolean found = false; X509Certificate result = null; // It is possible for multiple certificates to be provide (a chain of // certs). Find the one certificate that is directly used to verify this // time stamp. SignerInfo aSignerInfo = cms.getSignerInfo(); byte[] neededEssCertID = aSignerInfo.getSignedAttrs().getESSCertIDs()[0] .getCertHash(); // The value of ESSCertID contained in SignAttributes must be equal to // sha1 of x.509 encoded certificate. byte[] calculatedESSCertID = null; for (int i = 0; i < certs.length && found == false; i++) { calculatedESSCertID = ToolkitUtility.digestSHA1(certs[i] .getEncoded()); if (ToolkitUtility.byteArraysEqual(neededEssCertID, calculatedESSCertID)) { result = certs[i]; found = true; } } if (found == true) { return result; } else { return null; } } Copyright © 2011 DigiStamp, Inc. All Rights Reserved