BasicOcspResponse ::= SEQUENCE { tbsResponseData ResponseData, signatureAlgorithm AlgorithmIdentifier, signature BIT STRING, certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL }
Inheritance: Org.BouncyCastle.X509.X509ExtensionBase
Ejemplo n.º 1
0
		/// <param name="ocspResp"></param>
		/// <returns></returns>
		public virtual bool Match(BasicOcspResp ocspResp)
		{
			try
			{
				IDigest digest = DigestUtilities.GetDigest(algorithm);
                byte[] oscpBytes;
				if (matchOnlyBasicOCSPResponse)
				{
                    oscpBytes = ocspResp.GetEncoded();					
				}
				else
				{
                    oscpBytes = OCSPUtils.FromBasicToResp(ocspResp).GetEncoded();					
				}
                digest.BlockUpdate(oscpBytes, 0, oscpBytes.Length);
				byte[] computedValue = DigestUtilities.DoFinal(digest);
				LOG.Info("Compare " + Hex.ToHexString(digestValue) + " to computed value " + 
					Hex.ToHexString(computedValue) + " of BasicOcspResp produced at " + ocspResp
					.ProducedAt);
				return Arrays.Equals(digestValue, computedValue);
			}
			catch (NoSuchAlgorithmException ex)
			{
				throw new RuntimeException("Maybe BouncyCastle provider is not installed ?", ex);
			}
			catch (IOException ex)
			{
				throw new RuntimeException(ex);
			}
		}
Ejemplo n.º 2
0
        public const int Unauthorized = 6;                      // Request unauthorized

        public OcspResp Generate(
            int status,
            object response)
        {
            if (response == null)
            {
                return(new OcspResp(new OcspResponse(new OcspResponseStatus(status), null)));
            }
            if (response is BasicOcspResp)
            {
                BasicOcspResp   r = (BasicOcspResp)response;
                Asn1OctetString octs;

                try
                {
                    octs = new DerOctetString(r.GetEncoded());
                }
                catch (Exception e)
                {
                    throw new OcspException("can't encode object.", e);
                }

                ResponseBytes rb = new ResponseBytes(
                    OcspObjectIdentifiers.PkixOcspBasic, octs);

                return(new OcspResp(new OcspResponse(
                                        new OcspResponseStatus(status), rb)));
            }

            throw new OcspException("unknown response object");
        }
Ejemplo n.º 3
0
        public override bool Equals(object obj)
        {
            if (obj == this)
            {
                return(true);
            }
            BasicOcspResp basicOcspResp = obj as BasicOcspResp;

            return(basicOcspResp != null && this.resp.Equals(basicOcspResp.resp));
        }
Ejemplo n.º 4
0
		/// <summary>Convert a BasicOcspResp in OcspResp (connection status is set to SUCCESSFUL).
		/// 	</summary>
		/// <remarks>Convert a BasicOcspResp in OcspResp (connection status is set to SUCCESSFUL).
		/// 	</remarks>
		/// <param name="basicOCSPResp"></param>
		/// <returns></returns>
		public static OcspResp FromBasicToResp(BasicOcspResp basicOCSPResp)
		{
			try
			{
				return FromBasicToResp(basicOCSPResp.GetEncoded());
			}
			catch (IOException e)
			{
				throw new RuntimeException(e);
			}
		}
Ejemplo n.º 5
0
        public BouncyCastleOCSP.BasicOcspResp getOCSPCertFromResponse()
        {
            if (ocspResponse == null)
            {
                return(null);
            }
            else
            {
                Org.BouncyCastle.Ocsp.OcspResp resp  = new BouncyCastleOCSP.OcspResp(ocspResponse);
                BouncyCastleOCSP.BasicOcspResp bresp = resp.GetResponseObject() as BouncyCastleOCSP.BasicOcspResp;

                return(bresp);
            }
        }
Ejemplo n.º 6
0
        public override bool Equals(object obj)
        {
            if (obj == this)
            {
                return(true);
            }
            BasicOcspResp basicOcspResp = obj as BasicOcspResp;

            if (basicOcspResp == null)
            {
                return(false);
            }
            return(resp.Equals(basicOcspResp.resp));
        }
Ejemplo n.º 7
0
        /// <summary>
        /// Checks if the OCSP response from the OCSP responder. Returns the validity of the certificate used to sign the ocsp response and also
        /// if the client certificate is valid, revoked or unknown.
        /// </summary>
        /// <param name="clientCert">Client certificate</param>
        /// <param name="issuerCert">Issuer certificate of the client certificate</param>
        /// <param name="binaryResp">OCSP response</param>
        /// <returns>CertificateStatus</returns>
        private CertificateStatus CheckOcspResponse(X509Certificate clientCert, X509Certificate issuerCert, byte[] binaryResp)
        {
            BouncyCastleOCSP.OcspResp ocspResponse = new BouncyCastleOCSP.OcspResp(binaryResp);
            CertificateStatus         certStatus   = CertificateStatus.Unknown;


            switch (ocspResponse.Status)
            {
            case BouncyCastleOCSP.OcspRespStatus.Successful:
                BouncyCastleOCSP.BasicOcspResp response = (BouncyCastleOCSP.BasicOcspResp)ocspResponse.GetResponseObject();

                if (response.Responses.Length == 1)
                {
                    BouncyCastleOCSP.SingleResp singleResponse = response.Responses[0];

                    ValidateCertificateId(issuerCert, clientCert, singleResponse.GetCertID());
                    ValidateThisUpdate(singleResponse);
                    ValidateNextUpdate(singleResponse);

                    Object certificateStatus = singleResponse.GetCertStatus();

                    if (certificateStatus == Org.BouncyCastle.Ocsp.CertificateStatus.Good)
                    {
                        certStatus = CertificateStatus.Good;
                    }
                    else if (certificateStatus is Org.BouncyCastle.Ocsp.RevokedStatus)
                    {
                        certStatus = CertificateStatus.Revoked;
                    }
                    else if (certificateStatus is Org.BouncyCastle.Ocsp.UnknownStatus)
                    {
                        certStatus = CertificateStatus.Unknown;
                    }
                }
                break;

            default:
            {
                throw new BouncyCastleOCSP.OcspException("Error status: " + this.GetOCSPResponseStatus(ocspResponse.Status));
            }
            }

            return(certStatus);
        }
Ejemplo n.º 8
0
 public OcspResp Generate(int status, object response)
 {
     if (response == null)
     {
         return(new OcspResp(new OcspResponse(new OcspResponseStatus(status), null)));
     }
     if (response is BasicOcspResp)
     {
         BasicOcspResp   basicOcspResp = (BasicOcspResp)response;
         Asn1OctetString response2;
         try
         {
             response2 = new DerOctetString(basicOcspResp.GetEncoded());
         }
         catch (global::System.Exception e)
         {
             throw new OcspException("can't encode object.", e);
         }
         ResponseBytes responseBytes = new ResponseBytes(OcspObjectIdentifiers.PkixOcspBasic, response2);
         return(new OcspResp(new OcspResponse(new OcspResponseStatus(status), responseBytes)));
     }
     throw new OcspException("unknown response object");
 }
Ejemplo n.º 9
0
        /**
         * Verifies if an OCSP response is genuine
         *  If it doesn't verify against the issuer certificate and response's certificates, it may verify
         * using a trusted anchor or cert.
         * @param ocspResp	the OCSP response
         * @param issuerCert	the issuer certificate
         * @throws GeneralSecurityException
         * @throws IOException
         */
        virtual public void IsValidResponse(BasicOcspResp ocspResp, X509Certificate issuerCert) {
            //OCSP response might be signed by the issuer certificate or
            //the Authorized OCSP responder certificate containing the id-kp-OCSPSigning extended key usage extension
            X509Certificate responderCert = null;

            //first check if the issuer certificate signed the response
            //since it is expected to be the most common case
            if (IsSignatureValid(ocspResp, issuerCert)) {
                responderCert = issuerCert;
            }

            //if the issuer certificate didn't sign the ocsp response, look for authorized ocsp responses
            // from properties or from certificate chain received with response
            if (responderCert == null) {
                if (ocspResp.GetCerts() != null) {
                    //look for existence of Authorized OCSP responder inside the cert chain in ocsp response
                    X509Certificate[] certs = ocspResp.GetCerts();
                    foreach (X509Certificate cert in certs) {
                        X509Certificate tempCert;
                        try {
                            tempCert = cert;
                        } catch (Exception ex) {
                            continue;
                        }
                        IList keyPurposes = null;
                        try {
                            keyPurposes = tempCert.GetExtendedKeyUsage();
                            if ((keyPurposes != null) && keyPurposes.Contains(id_kp_OCSPSigning) && IsSignatureValid(ocspResp, tempCert)) {
                                responderCert = tempCert;
                                break;
                            }
                        } catch (CertificateParsingException ignored) {
                        }
                    }
                    // Certificate signing the ocsp response is not found in ocsp response's certificate chain received
                    // and is not signed by the issuer certificate.
                    if (responderCert == null) {
                        throw new VerificationException(issuerCert, "OCSP response could not be verified");
                    }
                } else {
                    //certificate chain is not present in response received
                    //try to verify using rootStore
                    if (certificates != null) {
                        foreach (X509Certificate anchor in certificates) {
                            try {
                                if (IsSignatureValid(ocspResp, anchor)) {
                                    responderCert = anchor;
                                    break;
                                }
                            } catch (GeneralSecurityException ignored) {
                            }
                        }
                    }

                    // OCSP Response does not contain certificate chain, and response is not signed by any
                    // of the rootStore or the issuer certificate.
                    if (responderCert == null) {
                        throw new VerificationException(issuerCert, "OCSP response could not be verified");
                    }
                }
            }

            //check "This certificate MUST be issued directly by the CA that issued the certificate in question".
            responderCert.Verify(issuerCert.GetPublicKey());

            // validating ocsp signers certificate
            // Check if responders certificate has id-pkix-ocsp-nocheck extension,
            // in which case we do not validate (perform revocation check on) ocsp certs for lifetime of certificate
            if (responderCert.GetExtensionValue(OcspObjectIdentifiers.PkixOcspNocheck.Id) == null) {
                X509Crl crl;
                try {
                    X509CrlParser crlParser = new X509CrlParser();
			        // Creates the CRL
		            Stream url = WebRequest.Create(CertificateUtil.GetCRLURL(responderCert)).GetResponse().GetResponseStream();
			        crl = crlParser.ReadCrl(url);
                } catch (Exception ignored) {
                    crl = null;
                }
                if (crl != null) {
                    CrlVerifier crlVerifier = new CrlVerifier(null, null);
                    crlVerifier.Certificates = certificates;
                    crlVerifier.OnlineCheckingAllowed = onlineCheckingAllowed;
                    crlVerifier.Verify(crl, responderCert, issuerCert, DateTime.UtcNow);
                    return;
                }
            }

            //check if lifetime of certificate is ok
            responderCert.CheckValidity();
	    }
Ejemplo n.º 10
0
        private static void CheckBasicOcspResp(CertID id, BasicOcspResp basicResp, OcesCertificate ocspCertificate, Ca ca)
        {
            DateTime nowInGmt = DateTime.Now.ToUniversalTime();

            /* check condition:
                 The certificate identified in a received response corresponds to
                 that which was identified in the corresponding request;
             */
            SingleResp[] responses = basicResp.Responses;
            if (responses.Length != 1)
            {
                throw new OcspException("unexpected number of responses received");
            }

            if (!id.SerialNumber.Value.Equals(responses[0].GetCertID().SerialNumber))
            {
                throw new OcspException("Serial number mismatch problem");
            }

            /* check condition
               The signature on the response is valid;
            */
            try
            {
                ChainVerifier.VerifyTrust(ocspCertificate.ExportCertificate(), ca);
            }
            catch(ChainVerificationException e)
            {
                throw new OcspException("OCSP response certificate chain is invalid", e);
            }

            /* check the signature on the ocsp response */
            var ocspBcCertificate =
                new X509CertificateParser().ReadCertificate(ocspCertificate.ExportCertificate().RawData);
            if (!basicResp.Verify(ocspBcCertificate.GetPublicKey()))
            {
                throw new OcspException("signature validation failed for ocsp response");
            }

            if (!CanSignOcspResponses(ocspBcCertificate))
            {
                throw new OcspException("ocsp signing certificate has not been cleared for ocsp response signing");
            }

            /* check expiry of the signing certificate */
            if (ocspCertificate.ValidityStatus() != CertificateStatus.Valid)
            {
                throw new OcspException("OCSP certificate expired or not yet valid");
            }

            /* check condition
               The time at which the status being indicated is known to be
               correct (thisUpdate) is sufficiently recent.
            */
            SingleResp response = responses[0];

            var diff = response.ThisUpdate - nowInGmt;
            if (diff > new TimeSpan(0, 1, 0))
            {
                throw new OcspException("OCSP response signature is from the future. Timestamp of thisUpdate field: "
                                        + response.ThisUpdate);
            }

            if (response.NextUpdate != null && response.NextUpdate.Value < nowInGmt)
            {
                throw new OcspException("OCSP response is no longer valid");
            }
        }
Ejemplo n.º 11
0
 //2. The signature on the response is valid;
 private void ValidateResponseSignature(BasicOcspResp or, Org.BouncyCastle.Crypto.AsymmetricKeyParameter asymmetricKeyParameter)
 {
     if (!or.Verify(asymmetricKeyParameter))
     {
         throw new Exception("Invalid OCSP signature");
     }
 }
Ejemplo n.º 12
0
 /// <summary>The default constructor for OCSPRespCertificateSource.</summary>
 /// <remarks>The default constructor for OCSPRespCertificateSource.</remarks>
 public OCSPRespCertificateSource(BasicOcspResp ocspResp)
 {
     this.ocspResp = ocspResp;
 }
Ejemplo n.º 13
0
        virtual public bool VerifyResponse(BasicOcspResp ocspResp, X509Certificate issuerCert) {
            try {
                IsValidResponse(ocspResp, issuerCert);
                return true;
            } catch (Exception e) {
                return false;
            }
	    }
Ejemplo n.º 14
0
 private void ValidateResponse(BasicOcspResp or, X509Certificate issuerCert)
 {
     ValidateResponseSignature(or, issuerCert.GetPublicKey());
     ValidateSignerAuthorization(issuerCert, or.GetCerts()[0]);
 }
Ejemplo n.º 15
0
		/// <summary>The default constructor for OCSPRespToken.</summary>
		/// <remarks>The default constructor for OCSPRespToken.</remarks>
		/// <param name="ocspResp"></param>
		public OCSPRespToken(BasicOcspResp ocspResp)
		{
			this.ocspResp = ocspResp;
		}
Ejemplo n.º 16
0
		public override IList<BasicOcspResp> GetOCSPResponsesFromSignature()
		{
			IList<BasicOcspResp> list = new AList<BasicOcspResp>();
			// Add certificates in CAdES-XL certificate-values inside SignerInfo attribute if present
			SignerInformation si = cmsSignedData.GetSignerInfos().GetFirstSigner(signerId);
			if (si != null && si.UnsignedAttributes != null && si.UnsignedAttributes[PkcsObjectIdentifiers.IdAAEtsRevocationValues] != null)
			{
				RevocationValues revValues = RevocationValues.GetInstance(si.UnsignedAttributes[PkcsObjectIdentifiers.IdAAEtsRevocationValues].AttrValues[0]);
				foreach (BasicOcspResponse ocspObj in revValues.GetOcspVals())
				{
					BasicOcspResp bOcspObj = new BasicOcspResp(ocspObj);
					list.AddItem(bOcspObj);
				}
			}
			return list;
		}
Ejemplo n.º 17
0
	    /**
	     * Checks if an OCSP response is genuine
	     * @param ocspResp	the OCSP response
	     * @param responderCert	the responder certificate
	     * @return	true if the OCSP response verifies against the responder certificate
	     */
        public bool IsSignatureValid(BasicOcspResp ocspResp, X509Certificate responderCert) {
		    try {
			    return ocspResp.Verify(responderCert.GetPublicKey());
		    } catch (OcspException) {
			    return false;
		    }
	    }
Ejemplo n.º 18
0
	    /**
	     * Verifies if an OCSP response is genuine
	     * @param ocspResp	the OCSP response
	     * @param issuerCert	the issuer certificate
	     * @throws GeneralSecurityException
	     * @throws IOException
	     */
	    public void IsValidResponse(BasicOcspResp ocspResp, X509Certificate issuerCert) {
		    // by default the OCSP responder certificate is the issuer certificate
		    X509Certificate responderCert = issuerCert;
		    // check if there's a responder certificate
		    X509Certificate[] certs = ocspResp.GetCerts();
		    if (certs.Length > 0) {
			    responderCert = certs[0];
			    try {
				    responderCert.Verify(issuerCert.GetPublicKey());
			    }
			    catch (GeneralSecurityException) {
				    if (base.Verify(responderCert, issuerCert, DateTime.MaxValue).Count == 0)
                        throw new VerificationException(responderCert, String.Format("{0} Responder certificate couldn't be verified", responderCert));
			    }
		    }
		    // verify if the signature of the response is valid
		    if (!VerifyResponse(ocspResp, responderCert))
                throw new VerificationException(responderCert, String.Format("{0} OCSP response could not be verified", responderCert));
	    }
Ejemplo n.º 19
0
 private void FindOcsp(Asn1Sequence seq) {
     basicResp = null;
     bool ret = false;
     while (true) {
         if ((seq[0] is DerObjectIdentifier) 
             && ((DerObjectIdentifier)seq[0]).Id.Equals(OcspObjectIdentifiers.PkixOcspBasic.Id)) {
             break;
         }
         ret = true;
         for (int k = 0; k < seq.Count; ++k) {
             if (seq[k] is Asn1Sequence) {
                 seq = (Asn1Sequence)seq[0];
                 ret = false;
                 break;
             }
             if (seq[k] is Asn1TaggedObject) {
                 Asn1TaggedObject tag = (Asn1TaggedObject)seq[k];
                 if (tag.GetObject() is Asn1Sequence) {
                     seq = (Asn1Sequence)tag.GetObject();
                     ret = false;
                     break;
                 }
                 else
                     return;
             }
         }
         if (ret)
             return;
     }
     DerOctetString os = (DerOctetString)seq[1];
     Asn1InputStream inp = new Asn1InputStream(os.GetOctets());
     BasicOcspResponse resp = BasicOcspResponse.GetInstance(inp.ReadObject());
     basicResp = new BasicOcspResp(resp);
 }
Ejemplo n.º 20
0
 static bool SerialNumberInResponseIsNotRevoked(BasicOcspResp response, string serialNumber)
 {
     var responseElements = new List<SingleResp>(response.Responses);
     return responseElements
         .Exists(r => r.GetCertStatus() == null &&
                      r.GetCertID().SerialNumber.ToString() == serialNumber);
 }
Ejemplo n.º 21
0
        static void CheckValidityOfResponse(CertID id, BasicOcspResp responseObject, Ca ca)
        {
            var inputStream = new MemoryStream(responseObject.GetEncoded());
            var asn1Sequence = (Asn1Sequence)new Asn1InputStream(inputStream).ReadObject();

            var response = BasicOcspResponse.GetInstance(asn1Sequence);

            var ocspChain = CreateOcspCertificateChain(ca);
            if(ocspChain.Length == 0)
            {
                throw new OcspException("OCSP certificate chain is invalid");
            }
            var ocesOcspCertificate = OcesCertificateFactory.Instance.Generate(CompleteOcspChain(response, ocspChain));
            CheckBasicOcspResp(id, responseObject, ocesOcspCertificate, ca);

            var signingCertificate = new X509CertificateParser().ReadCertificate(response.Certs[0].GetEncoded());
            var issuingCertificate = new X509CertificateParser().ReadCertificate(ocspChain[0].GetRawCertData());
            signingCertificate.Verify(issuingCertificate.GetPublicKey());
            if (!responseObject.Verify(signingCertificate.GetPublicKey()))
            {
                throw new OcspException("Signature is invalid");
            }
        }
Ejemplo n.º 22
0
	    /**
	     * Verifies a certificate against a single OCSP response
	     * @param ocspResp	the OCSP response
	     * @param issuerCert
	     * @param signDate
	     * @return
	     * @throws GeneralSecurityException
	     * @throws IOException
	     */
	    public bool Verify(BasicOcspResp ocspResp, X509Certificate signCert, X509Certificate issuerCert, DateTime signDate) {
		    if (ocspResp == null)
			    return false;
		    // Getting the responses
		    SingleResp[] resp = ocspResp.Responses;
		    for (int i = 0; i < resp.Length; ++i) {
			    // check if the serial number corresponds
			    if (!signCert.SerialNumber.Equals(resp[i].GetCertID().SerialNumber))
				    continue;
			    // check if the issuer matches
			    try {
                    if (issuerCert == null) issuerCert = signCert;
                    if (!resp[i].GetCertID().MatchesIssuer(issuerCert)) {
					    LOGGER.Info("OCSP: Issuers doesn't match.");
					    continue;
				    }
			    } catch (OcspException) {
				    continue;
			    }
			    // check if the OCSP response was valid at the time of signing
			    if (signDate.CompareTo(resp[i].NextUpdate.Value) > 0) {
				    LOGGER.Info(String.Format("OCSP no longer valid: {0} after {1}", signDate, resp[i].NextUpdate));
				    continue;
			    }
			    // check the status of the certificate
			    Object status = resp[i].GetCertStatus();
			    if (status == CertificateStatus.Good) {
				    // check if the OCSP response was genuine
				    IsValidResponse(ocspResp, issuerCert);
				    return true;
			    }
		    }
		    return false;
	    }
Ejemplo n.º 23
0
 private void ValidarResponseSignature(BasicOcspResp in_OcspResp, Org.BouncyCastle.Crypto.AsymmetricKeyParameter in_PublicKey)
 {
     if (!in_OcspResp.Verify(in_PublicKey))
     {
         throw new Exception("Firma OCSP Invalida");
     }
 }
Ejemplo n.º 24
0
	    /**
	     * Verifies if the signature of the response is valid.
	     * If it doesn't verify against the responder certificate, it may verify
	     * using a trusted anchor.
	     * @param ocspResp	the response object
	     * @param responderCert	the certificate that may be used to sign the response
	     * @return	true if the response can be trusted
	     */
	    public bool VerifyResponse(BasicOcspResp ocspResp, X509Certificate responderCert) {
		    // testing using the responder certificate
		    if (IsSignatureValid(ocspResp, responderCert))
			    return true;
		    // testing using trusted anchors
		    if (certificates == null)
			    return false;
		    try {
			    // loop over the certificates in the root store
        	    foreach (X509Certificate anchor in certificates) {
                    try {
                        if (IsSignatureValid(ocspResp, anchor))
	                        return true;
				    } catch (GeneralSecurityException) {}
        	    }
		    }
            catch (GeneralSecurityException) {
        	    return false;
            }
		    return false;
	    }
Ejemplo n.º 25
0
 private void ValidateResponse(BasicOcspResp in_OcspResp, X509Certificate in_CertificadoEmisor)
 {
     ValidarResponseSignature(in_OcspResp, in_CertificadoEmisor.GetPublicKey());
     ValidarSignerAuthorization(in_CertificadoEmisor, in_OcspResp.GetCerts()[0]);
 }
 /**
  * Verifies an OCSP response against a KeyStore.
  * @param ocsp the OCSP response
  * @param keystore the <CODE>KeyStore</CODE>
  * @param provider the provider or <CODE>null</CODE> to use the BouncyCastle provider
  * @return <CODE>true</CODE> is a certificate was found
  */
 public static bool VerifyOcspCertificates(BasicOcspResp ocsp, ICollection<X509Certificate> keystore)
 {
     try {
         foreach (X509Certificate certStoreX509 in keystore) {
             try {
                 if (ocsp.Verify(certStoreX509.GetPublicKey()))
                     return true;
             }
             catch {
             }
         }
     }
     catch {
     }
     return false;
 }
Ejemplo n.º 27
0
        /// <summary>
        /// Validates the cert with the provided ocsp responses.
        /// </summary>
        /// <param name="certificate">The cert to validate</param>
        /// <param name="issuer">The issuer of the cert to validate</param>
        /// <param name="validationTime">The time on which the cert was needed to validated</param>
        /// <param name="ocspResponses">The list of ocsp responses to use</param>
        /// <returns>The OCSP response that was used, <c>null</c> if none was found</returns>
        /// <exception cref="RevocationException{T}">When the certificate was revoked on the provided time</exception>
        /// <exception cref="RevocationUnknownException">When the certificate (or the OCSP) can't be validated</exception>
        public static BCAO.BasicOcspResponse Verify(this X509Certificate2 certificate, X509Certificate2 issuer, DateTime validationTime, IList <BCAO.BasicOcspResponse> ocspResponses)
        {
            DateTime minTime = validationTime - ClockSkewness;
            DateTime maxTime = validationTime + ClockSkewness;

            BCX.X509Certificate certificateBC = DotNetUtilities.FromX509Certificate(certificate);
            BCX.X509Certificate issuerBC      = DotNetUtilities.FromX509Certificate(issuer);

            ValueWithRef <BCO.SingleResp, ValueWithRef <BCO.BasicOcspResp, BCAO.BasicOcspResponse> > singleOcspRespLeaf = ocspResponses
                                                                                                                          .Select((rsp) => new ValueWithRef <BCO.BasicOcspResp, BCAO.BasicOcspResponse>(new BCO.BasicOcspResp(rsp), rsp))                                         //convert, but keep the original
                                                                                                                          .SelectMany((r) => r.Value.Responses.Select(sr => new ValueWithRef <BCO.SingleResp, ValueWithRef <BCO.BasicOcspResp, BCAO.BasicOcspResponse> >(sr, r))) //get the single respononses, but keep the parent
                                                                                                                          .Where((sr) => sr.Value.GetCertID().SerialNumber.Equals(certificateBC.SerialNumber) && sr.Value.GetCertID().MatchesIssuer(issuerBC))                    //is it for this cert?
                                                                                                                          .Where((sr) => sr.Value.ThisUpdate >= minTime || (sr.Value.NextUpdate != null && sr.Value.NextUpdate.Value >= minTime))                                 //was it issued on time?
                                                                                                                          .OrderByDescending((sr) => sr.Value.ThisUpdate)                                                                                                         //newest first
                                                                                                                          .FirstOrDefault();

            if (singleOcspRespLeaf == null)
            {
                return(null);
            }

            BCO.SingleResp         singleOcspResp    = singleOcspRespLeaf.Value;
            BCO.BasicOcspResp      basicOcspResp     = singleOcspRespLeaf.Reference.Value;
            BCAO.BasicOcspResponse basicOcspResponse = singleOcspRespLeaf.Reference.Reference;

            //get the signer name
            BCAX.X509Name responderName = basicOcspResp.ResponderId.ToAsn1Object().Name;
            if (responderName == null)
            {
                trace.TraceEvent(TraceEventType.Error, 0, "OCSP response for {0} does not have a ResponderID", certificate.Subject);
                throw new RevocationUnknownException("OCSP response for {0} does not have a ResponderID");
            }

            //Get the signer certificate
            var selector = new BCS.X509CertStoreSelector();

            selector.Subject = responderName;
            BCX.X509Certificate ocspSignerBc = (BCX.X509Certificate)basicOcspResp
                                               .GetCertificates("Collection").GetMatches(selector)
                                               .Cast <BCX.X509Certificate>().FirstOrDefault();
            if (ocspSignerBc == null)
            {
                throw new RevocationUnknownException("The OCSP is signed by a unknown certificate");
            }

            //verify the response signature
            if (!basicOcspResp.Verify(ocspSignerBc.GetPublicKey()))
            {
                throw new RevocationUnknownException("The OCSP has an invalid signature");
            }


            //OCSP must be issued by same issuer an the certificate that it validates.
            try
            {
                if (!ocspSignerBc.IssuerDN.Equals(issuerBC.SubjectDN))
                {
                    throw new ApplicationException();
                }
                ocspSignerBc.Verify(issuerBC.GetPublicKey());
            }
            catch (Exception e)
            {
                throw new RevocationUnknownException("The OCSP signer was not issued by the proper CA", e);
            }

            //verify if the OCSP signer certificate is stil valid
            if (!ocspSignerBc.IsValid(basicOcspResp.ProducedAt))
            {
                throw new RevocationUnknownException("The OCSP signer was not valid at the time the ocsp was issued");
            }


            //check if the signer may issue OCSP
            IList ocspSignerExtKeyUsage = ocspSignerBc.GetExtendedKeyUsage();

            if (!ocspSignerExtKeyUsage.Contains("1.3.6.1.5.5.7.3.9"))
            {
                throw new RevocationUnknownException("The OCSP is signed by a certificate that isn't allowed to sign OCSP");
            }

            //finally, check if the certificate is revoked or not
            var revokedStatus = (BCO.RevokedStatus)singleOcspResp.GetCertStatus();

            if (revokedStatus != null)
            {
                trace.TraceEvent(TraceEventType.Verbose, 0, "OCSP response for {0} indicates that the certificate is revoked on {1}", certificate.Subject, revokedStatus.RevocationTime);
                if (maxTime >= revokedStatus.RevocationTime)
                {
                    throw new RevocationException <BCAO.BasicOcspResponse>(basicOcspResponse, "The certificate was revoked on " + revokedStatus.RevocationTime.ToString("o"));
                }
            }

            return(basicOcspResponse);
        }