/// <summary>
        /// Verifies that timestamp is valid.
        /// </summary>
        /// <returns>
        ///   <see cref="TimestampObject" />
        /// </returns>
        /// <exception cref="System.ArgumentNullException">
        /// Hash algorithm not provided.
        /// or
        /// Data for timestamping not provided.
        /// </exception>
        public TimestampObject Verify()
        {
            /* Check that everything has been provided */
            if (0 == this.hashAlgorithm)
            {
                throw new ArgumentNullException("Hash algorithm not provided.");
            }
            if (null == this.timestampData)
            {
                throw new ArgumentNullException("Data for timestamping not provided.");
            }
            if (null == this.timestampResponse)
            {
                throw new ArgumentNullException("Timestamp not provided.");
            }

            /* Get hashed data */
            byte[] hashedData = timestampData.GetHashedData(this.hashAlgorithm);

            /* Generate request */
            TimeStampRequestGenerator requestGenerator = new TimeStampRequestGenerator();

            TimeStampRequest request = requestGenerator.Generate(new Oid(this.hashAlgorithm.ToString()).Value, hashedData);

            /*
             * Check this response against to see if it a well formed response for
             * the passed in request. It validates message imprint digests and message imprint algorithms.
             *
             * @param request the request to be checked against
             * @throws TspException if the request can not match this response.
             */
            this.timestampResponse.Validate(request);

            TimeStampToken  token     = timestampResponse.TimeStampToken;
            TimestampObject timestamp = new TimestampObject();

            /* Validate certificate */
            X509Certificate2 certificate = ValidateCertificate(token, timestamp, minimumCertificateValidityPeriod);

            timestamp.HashAlgorithm = this.hashAlgorithm;
            timestamp.Timestamp     = this.timestampResponse.GetEncoded();

            return(timestamp);
        }
Example #2
0
        /// <summary>
        /// Creates timestamp from provided data.
        /// </summary>
        /// <returns>
        ///   <see cref="TimestampObject" />
        /// </returns>
        /// <exception cref="System.ArgumentNullException">
        /// Hash algorithm not provided.
        /// or
        /// TSA URL not provided.
        /// or
        /// Timestamp output format not provided.
        /// or
        /// Data for timestamping not provided.</exception>
        /// <exception cref="AbsoluteTimestamp.TimestampException">Cannot connect to TSA server.</exception>
        /// <exception cref="TspValidationException"></exception>
        public TimestampObject CreateTimestamp()
        {
            /* Check that everything has been provided */
            if (0 == this.hashAlgorithm)
            {
                throw new ArgumentNullException("Hash algorithm not provided.");
            }
            if (String.IsNullOrWhiteSpace(this.tsaPrimaryUrl) && String.IsNullOrWhiteSpace(this.tsaSecondaryUrl))
            {
                throw new ArgumentNullException("TSA URL not provided.");
            }
            if (0 == this.outputFormat)
            {
                throw new ArgumentNullException("Timestamp output format not provided.");
            }
            if (null == this.timestampData)
            {
                throw new ArgumentNullException("Data for timestamping not provided.");
            }

            /* Get hashed data */
            byte[] hashedData = this.timestampData.GetHashedData(this.hashAlgorithm);

            /* Generate request */
            TimeStampRequestGenerator requestGenerator = new TimeStampRequestGenerator();

            requestGenerator.SetCertReq(true);

            TimeStampRequest request = requestGenerator.Generate(new Oid(this.hashAlgorithm.ToString()).Value, hashedData);

            /* Get response */
            TimeStampResponse response = GetTimeStampResponse(request);

            /* Validate response */
            if (!(response.Status == 0 || response.Status == 1))
            {
                throw new TspValidationException(
                          string.Format("Invalid response, response status={0}, response status string={1}, response failure info={2}",
                                        response.Status, response.GetStatusString(), response.GetFailInfo().IntValue));
            }

            /*
             * Check this response against to see if it a well formed response for
             * the passed in request. It validates message imprint digests and message imprint algorithms.
             *
             * @param request the request to be checked against
             * @throws TspException if the request can not match this response.
             */
            response.Validate(request);

            TimeStampToken   token       = response.TimeStampToken;
            X509Certificate2 certificate = null;

            TimestampObject timestamp = new TimestampObject();

            /* Validate certificate */
            certificate = TimestampVerifier.ValidateCertificate(token, timestamp, minimumCertificateValidityPeriod);

            timestamp.HashAlgorithm = this.hashAlgorithm;
            timestamp.Timestamp     = Utils.GetTimestampForOutput(response, this.outputFormat, this.timestampData);

            return(timestamp);
        }
        /// <summary>
        /// Extracts and validates the certificate from token.
        /// </summary>
        /// <param name="token">The token.</param>
        /// <param name="timestamp">The timestamp.</param>
        /// <param name="validityPeriod">Required certificate validity</param>
        /// <returns><see cref="X509Certificate2" /></returns>
        /// <exception cref="TspValidationException">Invalid response, more than one certificate found</exception>
        /// <exception cref="System.Security.Cryptography.CryptographicException">Certificate chain validation failed.</exception>
        public static X509Certificate2 ValidateCertificate(TimeStampToken token, TimestampObject timestamp, int validityPeriod)
        {
            X509Certificate2 tsaCertificate = null;
            SignerID         signer         = token.SignerID;

            ICollection certificates = token.GetCertificates("Collection").GetMatches(signer);

            if (certificates.Count > 1)
            {
                throw new TspValidationException("Invalid response, more than one certificate found");
            }
            foreach (Org.BouncyCastle.X509.X509Certificate cert in certificates)
            {
                /*
                 * Validate the time stamp token.
                 * <p>
                 * To be valid the token must be signed by the passed in certificate and
                 * the certificate must be the one referred to by the SigningCertificate
                 * attribute included in the hashed attributes of the token. The
                 * certificate must also have the ExtendedKeyUsageExtension with only
                 * KeyPurposeID.IdKPTimeStamping and have been valid at the time the
                 * timestamp was created.
                 * </p>
                 * <p>
                 * A successful call to validate means all the above are true.
                 * </p>
                 */
                token.Validate(cert);

                /// <summary>
                /// Return true if the nominated time is within the start and end times nominated on the certificate.
                /// </summary>
                /// <param name="time">The time to test validity against.</param>
                /// <returns>True if certificate is valid for nominated time.</returns>
                if (!cert.IsValid(token.TimeStampInfo.GenTime))
                {
                    throw new TspValidationException("Certificate is not valid at the time of timestamp creation.");
                }

                /* Set warning if signing certificate is expired or is about to expire */
                if (!cert.IsValidNow)
                {
                    timestamp.Warning = "Signing certificate expired.";
                }
                else if (validityPeriod > 0)
                {
                    int expireDays = (cert.NotAfter - DateTime.Now).Days;
                    if (expireDays <= validityPeriod)
                    {
                        timestamp.Warning = string.Format("Signing certificate is going to expire in {0} days on {1}.", expireDays, cert.NotAfter);
                    }
                }

                /*
                 * verify that the given certificate successfully handles and confirms
                 * the signature associated with this signer and, if a signingTime
                 * attribute is available, that the certificate was valid at the time the
                 * signature was generated.
                 */
                token.ToCmsSignedData().GetSignerInfos().GetFirstSigner(signer).Verify(cert);

                tsaCertificate = new X509Certificate2(cert.GetEncoded());

                /* Microsoft validation */
                X509Chain chain = new X509Chain();
                chain.ChainPolicy.VerificationTime = token.TimeStampInfo.GenTime;

                if (!chain.Build(tsaCertificate))
                {
                    /* Search for revoked certificate */
                    bool allRevokedCertificatesAreValid = true;
                    foreach (X509ChainElement element in chain.ChainElements)
                    {
                        if (IsRevoked(element) && !IsValidAfterRevocation(element.Certificate, token.TimeStampInfo.GenTime))
                        {
                            allRevokedCertificatesAreValid = false;
                            break;
                        }
                    }

                    string failReason = "";
                    foreach (X509ChainStatus status in chain.ChainStatus)
                    {
                        if (status.Status != X509ChainStatusFlags.Revoked || !allRevokedCertificatesAreValid)
                        {
                            failReason += status.Status + ": " + status.StatusInformation;
                        }
                    }
                    if (failReason != "")
                    {
                        throw new CryptographicException("Certificate chain validation failed.\n" + failReason);
                    }
                }
            }

            timestamp.Time           = token.TimeStampInfo.GenTime;
            timestamp.TsaIssuer      = token.SignerID.Issuer.ToString();
            timestamp.TsaCertificate = tsaCertificate;
            timestamp.MessageImprint = BitConverter.ToString(token.TimeStampInfo.TstInfo.MessageImprint.GetHashedMessage());
            return(tsaCertificate);
        }