/// <summary>
        /// Saves an audit register of the operation
        /// </summary>
        /// <param name="timeStampRequest"><see cref="TimeStampRequest"/></param>
        /// <param name="timeStampToken"><see cref="TimeStampToken"/></param>
        /// <param name="tsaCertificate"><see cref="X509Certificate"/></param>
        /// <returns></returns>
        private Task SaveAuditLog(TimeStampRequest timeStampRequest, TimeStampToken timeStampToken, X509Certificate tsaCertificate)
        {
            var audit = new TimeStampAudit
            {
                HashAlgorithm = timeStampRequest.MessageImprintAlgOid,
                HashMessage   = timeStampRequest.GetMessageImprintDigest(),
                Policy        = BcTimeStampResponderRepository.GetPolicyOid(),
                Serial        = timeStampToken.TimeStampInfo.SerialNumber.ToString(),
                SignedTime    = timeStampToken.TimeStampInfo.GenTime,
                TsaSerial     = tsaCertificate.SerialNumber.ToString()
            };

            return(BcTimeStampResponderRepository.SaveAuditLog(audit));
        }
        /// <summary>
        /// Gets the <see cref="ContentInfo"/> meaning the time stamp token
        /// </summary>
        /// <param name="timeStampRequest"><see cref="TimeStampRequest"/></param>
        /// <returns><see cref="ContentInfo"/></returns>
        private async Task <ContentInfo> GetTimeStampToken(TimeStampRequest timeStampRequest)
        {
            var tsaCertificate = await BcTimeStampResponderRepository.GetCertificate();

            var tokenGenerator = new TimeStampTokenGenerator(
                await BcTimeStampResponderRepository.GetPrivateKey(),
                tsaCertificate,
                NistObjectIdentifiers.IdSha512.Id,
                BcTimeStampResponderRepository.GetPolicyOid()
                );

            var certs = X509StoreFactory.Create("Certificate/Collection",
                                                new X509CollectionStoreParameters(
                                                    new List <X509Certificate> {
                tsaCertificate
            }));

            tokenGenerator.SetCertificates(certs);

            tokenGenerator.SetTsa(new GeneralName(new X509Name(tsaCertificate.SubjectDN.ToString())));

            var timeStampToken = tokenGenerator.Generate(
                timeStampRequest,
                BcTimeStampResponderRepository.GetNextSerialNumber(),
                BcTimeStampResponderRepository.GetTimeToSign());

            try
            {
                using (var stream = new Asn1InputStream(timeStampToken.ToCmsSignedData().GetEncoded()))
                {
                    var contentInfo = ContentInfo.GetInstance(stream.ReadObject());
                    await SaveAuditLog(timeStampRequest, timeStampToken, tsaCertificate);

                    return(contentInfo);
                }
            }
            catch (Exception e)
            {
                throw new TspException("Timestamp token cannot be converted to ContentInfo", e);
            }
        }
        /// <summary>
        /// Retrieves the <see cref="TimeStampRequest"/> from the <see cref="TspHttpRequest"/>
        /// </summary>
        /// <param name="tspHttpRequest"><see cref="TspHttpRequest"/></param>
        /// <returns><see cref="TspReqResult"/> containing the <see cref="TimeStampRequest"/> and the <see cref="PkiStatusInfo"/></returns>
        private TspReqResult GetTimeStampRequest(TspHttpRequest tspHttpRequest)
        {
            // Validates the header of the request
            if (tspHttpRequest.MediaType != "application/timestamp-query")
            {
                var pkiStatusInfo = new PkiStatusInfo(
                    (int)PkiStatus.Rejection,
                    new PkiFreeText(new DerUtf8String("Content type is not 'application/timestamp-query'.")),
                    new PkiFailureInfo(PkiFailureInfo.BadRequest));

                return(new TspReqResult
                {
                    PkiStatusInfo = pkiStatusInfo
                });
            }

            // Try to create  the TimeStampRequest from the http request
            TimeStampRequest timeStampRequest;

            try
            {
                timeStampRequest = new TimeStampRequest(tspHttpRequest.Content);
            }
            catch (Exception)
            {
                var pkiStatusInfo = new PkiStatusInfo(
                    (int)PkiStatus.Rejection,
                    new PkiFreeText(new DerUtf8String("Query in bad format")),
                    new PkiFailureInfo(PkiFailureInfo.BadDataFormat));

                return(new TspReqResult
                {
                    PkiStatusInfo = pkiStatusInfo
                });
            }

            // Validates whether the request uses accepted hash algorithms
            if (AcceptedAlgorithms.All(algorithm => algorithm.Id != timeStampRequest.MessageImprintAlgOid))
            {
                var pkiStatusInfo = new PkiStatusInfo(
                    (int)PkiStatus.Rejection,
                    new PkiFreeText(new DerUtf8String("Hash Algorithm is not accepted.")),
                    new PkiFailureInfo(PkiFailureInfo.BadAlg));

                return(new TspReqResult
                {
                    PkiStatusInfo = pkiStatusInfo
                });
            }

            // Validates whether the hashed message length matches the digest length of the hash algorithm
            if (timeStampRequest.GetMessageImprintDigest().Length != TspAlgorithmUtil.GetDigestLength(new DerObjectIdentifier(timeStampRequest.MessageImprintAlgOid)))
            {
                var pkiStatusInfo = new PkiStatusInfo(
                    (int)PkiStatus.Rejection,
                    new PkiFreeText(new DerUtf8String("Digest length is not equal the message imprint length.")),
                    new PkiFailureInfo(PkiFailureInfo.BadDataFormat));

                return(new TspReqResult
                {
                    PkiStatusInfo = pkiStatusInfo
                });
            }

            // Validates whether the TSA accepts the policy for stamping
            if (timeStampRequest.ReqPolicy != null && timeStampRequest.ReqPolicy != BcTimeStampResponderRepository.GetPolicyOid())
            {
                var pkiStatusInfo = new PkiStatusInfo(
                    (int)PkiStatus.Rejection,
                    new PkiFreeText(new DerUtf8String("TSP policy is unknown.")),
                    new PkiFailureInfo(PkiFailureInfo.UnacceptedPolicy));

                return(new TspReqResult
                {
                    PkiStatusInfo = pkiStatusInfo
                });
            }

            // Validates whether the TSA accepts the extensions
            if (timeStampRequest.HasExtensions)
            {
                var acceptedExtensions = BcTimeStampResponderRepository.GetAcceptedExtensions();
                var extensions         = timeStampRequest.GetExtensionOids()
                                         .Cast <DerObjectIdentifier>()
                                         .Select(oid => timeStampRequest.GetExtension(oid));

                if (extensions.Any(e => !acceptedExtensions.Any(a => a.IsCritical == e.IsCritical && Equals(a.Value, e.Value))))
                {
                    var pkiStatusInfo = new PkiStatusInfo(
                        (int)PkiStatus.Rejection,
                        new PkiFreeText(new DerUtf8String("TSP does not recognizes any extensions")),
                        new PkiFailureInfo(PkiFailureInfo.UnacceptedExtension));

                    return(new TspReqResult
                    {
                        PkiStatusInfo = pkiStatusInfo
                    });
                }
            }

            // returns the time stamp request with granted status
            return(new TspReqResult
            {
                PkiStatusInfo = new PkiStatusInfo((int)PkiStatus.Granted),
                TimeStampRequest = timeStampRequest
            });
        }