/// <summary> /// Check if the response is too old. /// </summary> /// <param name="resp">OCSP response</param> private void ValidateThisUpdate(BouncyCastleOCSP.SingleResp resp) { if (Math.Abs(resp.ThisUpdate.Ticks - DateTime.Now.Ticks) > MaxClockSkew) { throw new HttpException(401, "Resonpse too old."); } }
/// <summary> /// Checks if Next Update value is not null. If not null next update must not be older then current time. /// </summary> /// <param name="resp">OCSP response</param> private void ValidateNextUpdate(BouncyCastleOCSP.SingleResp resp) { if (resp.NextUpdate != null && resp.NextUpdate.Value != null && resp.NextUpdate.Value.Ticks <= DateTime.Now.Ticks) { //log.LogError(Logger.LogLevel.ERROR, "ValidateNextUpdate", "Invalid Next Update"); throw new HttpException(401, "Invalid Next Update"); } }
public SingleResp[] GetResponses() { Asn1Sequence responses = this.data.Responses; SingleResp[] array = new SingleResp[responses.Count]; for (int num = 0; num != array.Length; num++) { array[num] = new SingleResp(SingleResponse.GetInstance(responses[num])); } return(array); }
public SingleResp[] GetResponses() { Asn1Sequence responses = data.Responses; SingleResp[] array = new SingleResp[responses.Count]; for (int i = 0; i != array.Length; i++) { array[i] = new SingleResp(SingleResponse.GetInstance(responses[i])); } return(array); }
public SingleResp[] GetResponses() { Asn1Sequence s = data.Responses; SingleResp[] rs = new SingleResp[s.Count]; for (int i = 0; i != rs.Length; i++) { rs[i] = new SingleResp(SingleResponse.GetInstance(s[i])); } return rs; }
public SingleResp[] GetResponses() { Asn1Sequence s = data.Responses; SingleResp[] rs = new SingleResp[s.Count]; for (int i = 0; i != rs.Length; i++) { rs[i] = new SingleResp(SingleResponse.GetInstance(s[i])); } return(rs); }
/// <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); }
//5. The time at which the status being indicated is known to be //correct (thisUpdate) is sufficiently recent. private void ValidateThisUpdate(SingleResp resp) { if (Math.Abs(resp.ThisUpdate.Ticks - DateTime.Now.Ticks) > MaxClockSkew) { throw new Exception("Max clock skew reached."); } }
//6. When available, the time at or before which newer information will //be available about the status of the certificate (nextUpdate) is //greater than the current time. private void ValidateNextUpdate(SingleResp resp) { if( resp.NextUpdate != null && resp.NextUpdate.Value != null && resp.NextUpdate.Value.Ticks <= DateTime.Now.Ticks) { throw new Exception("Invalid next update."); } }
/// <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); }