private static void ProcessResponse( Rfc3161RequestResponseStatus expectedStatus, Rfc3161TimestampRequest request, byte[] inputBytes, int paddingByteCount) { Rfc3161TimestampToken token; int bytesRead; Rfc3161RequestResponseStatus status; bool result = request.TryProcessResponse(inputBytes, out token, out status, out bytesRead); Assert.Equal(expectedStatus, status); if (expectedStatus == Rfc3161RequestResponseStatus.Accepted) { Assert.True(result, "request.TryProcessResponse return value"); } else { Assert.False(result, "request.TryProcessResponse return value"); } if (expectedStatus == Rfc3161RequestResponseStatus.DoesNotParse) { Assert.Equal(0, bytesRead); } else { Assert.Equal(inputBytes.Length - paddingByteCount, bytesRead); } switch (expectedStatus) { case Rfc3161RequestResponseStatus.Accepted: case Rfc3161RequestResponseStatus.HashMismatch: case Rfc3161RequestResponseStatus.NonceMismatch: case Rfc3161RequestResponseStatus.UnexpectedCertificates: case Rfc3161RequestResponseStatus.RequestedCertificatesMissing: case Rfc3161RequestResponseStatus.VersionTooNew: Assert.NotNull(token); break; default: Assert.Null(token); break; } if (result) { Rfc3161TimestampToken token2 = request.ProcessResponse(inputBytes, out int bytesRead2); Assert.Equal(bytesRead, bytesRead2); Assert.NotNull(token2); Assert.NotSame(token, token2); } else { Assert.Throws <CryptographicException>(() => request.ProcessResponse(inputBytes, out bytesRead)); } }
public static async Task <byte[]> SignWithRfc3161(byte[] bytesToSign, bool isDetached, X509Certificate2 certificate, Uri timeStampAuthorityUri) { // Sign our contents. var contentInfo = new ContentInfo(bytesToSign); var cms = new SignedCms(contentInfo, isDetached); var signer = new CmsSigner(certificate); // { IncludeOption = X509IncludeOption.WholeChain }; //X509IncludeOption.EndCertOnly; signer.SignedAttributes.Add(new Pkcs9SigningTime()); cms.ComputeSignature(signer, false); // Generate our nonce byte[] nonce = new byte[8]; using (var rng = RandomNumberGenerator.Create()) { rng.GetBytes(nonce); } // Get our signing information and create the RFC3161 request SignerInfo newSignerInfo = cms.SignerInfos[0]; // Now we generate our request for us to send to our RFC3161 signing authority. Rfc3161TimestampRequest request = Rfc3161TimestampRequest.CreateFromSignerInfo(newSignerInfo, HashAlgorithmName.SHA256, requestSignerCertificates: true, nonce: nonce); // You can use your own web request system, in this example we are just going to use a `HttpClient` class. var client = new HttpClient(); var content = new ReadOnlyMemoryContent(request.Encode()); content.Headers.ContentType = new MediaTypeHeaderValue("application/timestamp-query"); var httpResponse = await client.PostAsync(timeStampAuthorityUri, content).ConfigureAwait(false); // Process our response if (!httpResponse.IsSuccessStatusCode) { throw new CryptographicException("There was a error from the timestamp authority. It responded with {httpResponse.StatusCode} {(int)httpResponse.StatusCode}: {httpResponse.Content}"); } if (httpResponse.Content.Headers.ContentType.MediaType != "application/timestamp-reply") { throw new CryptographicException("The reply from the time stamp server was in a invalid format."); } var data = await httpResponse.Content.ReadAsByteArrayAsync().ConfigureAwait(false); var timestampToken = request.ProcessResponse(data, out _); // The RFC3161 sign certificate is separate to the contents that was signed, we need to add it to the unsigned attributes. newSignerInfo.UnsignedAttributes.Add(new AsnEncodedData(SignatureTimeStampOin, timestampToken.AsSignedCms().Encode())); return(cms.Encode()); }