| Index: net/cert/cert_verify_proc.cc
|
| diff --git a/net/cert/cert_verify_proc.cc b/net/cert/cert_verify_proc.cc
|
| index 49a170d3cb55b929e0659e6757b6f7089c3086ad..6cedd8bd022f916070465193557ad91d842d063c 100644
|
| --- a/net/cert/cert_verify_proc.cc
|
| +++ b/net/cert/cert_verify_proc.cc
|
| @@ -23,7 +23,10 @@
|
| #include "net/cert/cert_verify_proc_whitelist.h"
|
| #include "net/cert/cert_verify_result.h"
|
| #include "net/cert/crl_set.h"
|
| +#include "net/cert/internal/parse_ocsp.h"
|
| +#include "net/cert/ocsp_revocation_status.h"
|
| #include "net/cert/x509_certificate.h"
|
| +#include "net/der/encode_values.h"
|
| #include "url/url_canon.h"
|
|
|
| #if defined(USE_NSS_CERTS)
|
| @@ -182,6 +185,89 @@ bool IsPastSHA1DeprecationDate(const X509Certificate& cert) {
|
| return start >= kSHA1DeprecationDate;
|
| }
|
|
|
| +bool CheckCertIDMatchesCertificate(const OCSPCertID& cert_id,
|
| + const X509Certificate& certificate) {
|
| + // TODO(dadrian): Verify name and key hashes. https://crbug.com/620005
|
| + der::Input serial(&certificate.serial_number());
|
| + return cert_id.serial_number == serial;
|
| +}
|
| +
|
| +void CheckOCSP(const std::string& raw_response,
|
| + CertVerifyResult* verify_result) {
|
| + verify_result->ocsp.Reset();
|
| +
|
| + if (raw_response.empty()) {
|
| + verify_result->ocsp.response_status = OCSPVerifyResult::MISSING;
|
| + return;
|
| + }
|
| + der::Input response_der(&raw_response);
|
| +
|
| + OCSPResponse response;
|
| + if (!ParseOCSPResponse(response_der, &response)) {
|
| + verify_result->ocsp.response_status = OCSPVerifyResult::PARSE_RESPONSE;
|
| + return;
|
| + }
|
| +
|
| + // If the OCSP response isn't status SUCCESSFUL, don't parse the rest of the
|
| + // data.
|
| + if (response.status != OCSPResponse::ResponseStatus::SUCCESSFUL) {
|
| + verify_result->ocsp.response_status = OCSPVerifyResult::BAD_RESPONSE;
|
| + return;
|
| + }
|
| +
|
| + OCSPResponseData response_data;
|
| + if (!ParseOCSPResponseData(response.data, &response_data)) {
|
| + verify_result->ocsp.response_status = OCSPVerifyResult::PARSE_RESPONSE_DATA;
|
| + return;
|
| + }
|
| +
|
| + // If producedAt is outside of the certificate validity period, reject the
|
| + // response.
|
| + der::GeneralizedTime not_before, not_after;
|
| + if (!der::EncodeTimeAsGeneralizedTime(
|
| + verify_result->verified_cert->valid_start(), ¬_before) ||
|
| + !der::EncodeTimeAsGeneralizedTime(
|
| + verify_result->verified_cert->valid_expiry(), ¬_after)) {
|
| + verify_result->ocsp.response_status = OCSPVerifyResult::BAD_PRODUCED_AT;
|
| + return;
|
| + }
|
| + if (response_data.produced_at < not_before ||
|
| + response_data.produced_at > not_after) {
|
| + verify_result->ocsp.response_status = OCSPVerifyResult::BAD_PRODUCED_AT;
|
| + return;
|
| + }
|
| +
|
| + // TODO(svaldez): Unify with GetOCSPCertStatus.
|
| + base::Time verify_time = base::Time::Now();
|
| + base::TimeDelta max_age = base::TimeDelta::FromDays(7);
|
| + verify_result->ocsp.response_status = OCSPVerifyResult::NO_MATCHING_RESPONSE;
|
| + for (const auto& single_response_der : response_data.responses) {
|
| + OCSPSingleResponse single_response;
|
| + if (!ParseOCSPSingleResponse(single_response_der, &single_response))
|
| + continue;
|
| + OCSPCertID cert_id;
|
| + if (!ParseOCSPCertID(single_response.cert_id_tlv, &cert_id))
|
| + continue;
|
| + if (!CheckCertIDMatchesCertificate(cert_id, *verify_result->verified_cert))
|
| + continue;
|
| + if (!CheckOCSPDateValid(single_response, verify_time, max_age)) {
|
| + if (verify_result->ocsp.response_status != OCSPVerifyResult::PROVIDED)
|
| + verify_result->ocsp.response_status = OCSPVerifyResult::INVALID_DATE;
|
| + continue;
|
| + }
|
| + verify_result->ocsp.response_status = OCSPVerifyResult::PROVIDED;
|
| +
|
| + OCSPRevocationStatus current_status =
|
| + verify_result->ocsp.cert_status.value_or(OCSPRevocationStatus::GOOD);
|
| + // In the case that we receive multiple responses, we keep only the
|
| + // strictest status (REVOKED > UNKNOWN > GOOD).
|
| + if (current_status == OCSPRevocationStatus::GOOD ||
|
| + single_response.cert_status.status == OCSPRevocationStatus::REVOKED) {
|
| + verify_result->ocsp.cert_status = single_response.cert_status.status;
|
| + }
|
| + }
|
| +}
|
| +
|
| // Comparison functor used for binary searching whether a given HashValue,
|
| // which MUST be a SHA-256 hash, is contained with an array of SHA-256
|
| // hashes.
|
| @@ -258,6 +344,9 @@ int CertVerifyProc::Verify(X509Certificate* cert,
|
| verify_result->common_name_fallback_used);
|
| }
|
|
|
| + // Check OCSP information
|
| + CheckOCSP(ocsp_response, verify_result);
|
| +
|
| // This check is done after VerifyInternal so that VerifyInternal can fill
|
| // in the list of public key hashes.
|
| if (IsPublicKeyBlacklisted(verify_result->public_key_hashes)) {
|
|
|