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..3c3b6065c0f01e398f857e108e4a761eb53e7de9 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,91 @@ bool IsPastSHA1DeprecationDate(const X509Certificate& cert) { |
return start >= kSHA1DeprecationDate; |
} |
+bool CheckCertIDMatchesCertificate(const OCSPCertID& cert_id, |
Ryan Sleevi
2016/07/18 20:08:08
Document
dadrian
2016/07/18 22:23:32
Done.
|
+ 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, |
Ryan Sleevi
2016/07/18 20:08:08
Document
dadrian
2016/07/18 22:23:32
Done.
|
+ CertVerifyResult* verify_result) { |
Ryan Sleevi
2016/07/18 20:08:08
Is CertVerifyResult really the right dependency? I
dadrian
2016/07/18 22:23:31
Done.
|
+ verify_result->ocsp.Reset(); |
Ryan Sleevi
2016/07/18 20:08:08
Do we need an explicit reset? Can't you just do a
dadrian
2016/07/18 22:23:32
Done.
|
+ |
+ if (raw_response.empty()) { |
+ verify_result->ocsp.response_status = OCSPVerifyResult::MISSING; |
+ return; |
+ } |
+ der::Input response_der(&raw_response); |
Ryan Sleevi
2016/07/18 20:08:08
move the newline from 204 to 203 :)
dadrian
2016/07/18 22:23:31
Done.
|
+ |
+ OCSPResponse response; |
+ if (!ParseOCSPResponse(response_der, &response)) { |
+ verify_result->ocsp.response_status = OCSPVerifyResult::PARSE_RESPONSE; |
Ryan Sleevi
2016/07/18 20:08:07
Is PARSE_RESPONSE a good name for the enum? How do
dadrian
2016/07/18 22:23:32
I changed it to PARSE_RESPONSE_ERROR and PARSE_RES
|
+ return; |
+ } |
+ |
+ // If the OCSP response isn't status SUCCESSFUL, don't parse the rest of the |
+ // data. |
Ryan Sleevi
2016/07/18 20:08:07
Could you explain the "why" more? Why is this a 'b
dadrian
2016/07/18 22:23:32
Done.
|
+ if (response.status != OCSPResponse::ResponseStatus::SUCCESSFUL) { |
+ verify_result->ocsp.response_status = OCSPVerifyResult::BAD_RESPONSE; |
+ return; |
+ } |
+ |
+ OCSPResponseData response_data; |
+ if (!ParseOCSPResponseData(response.data, &response_data)) { |
Ryan Sleevi
2016/07/18 20:08:07
This could benefit from documentation, because Par
dadrian
2016/07/18 22:23:32
Done.
|
+ 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)) { |
Ryan Sleevi
2016/07/18 20:08:08
Just to make sure I understand: We parse the certi
dadrian
2016/07/18 22:23:32
Aren't computers great? :)
The other option woul
|
+ 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. |
Ryan Sleevi
2016/07/18 20:08:08
Is there a Bug #?
dadrian
2016/07/18 22:23:32
There is now. https://crbug.com/629249
|
+ base::Time verify_time = base::Time::Now(); |
+ base::TimeDelta max_age = base::TimeDelta::FromDays(7); |
Ryan Sleevi
2016/07/18 20:08:08
Should this be a function-level static constant so
dadrian
2016/07/18 22:23:31
Sure? Not sure what the rules are here, but this i
|
+ verify_result->ocsp.response_status = OCSPVerifyResult::NO_MATCHING_RESPONSE; |
+ for (const auto& single_response_der : response_data.responses) { |
Ryan Sleevi
2016/07/18 20:08:07
You could do with some high-level documentation ab
dadrian
2016/07/18 22:23:32
Done.
|
+ 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) |
Ryan Sleevi
2016/07/18 20:08:07
This could benefit from documentation
dadrian
2016/07/18 22:23:32
Done.
|
+ verify_result->ocsp.response_status = OCSPVerifyResult::INVALID_DATE; |
+ continue; |
+ } |
+ verify_result->ocsp.response_status = OCSPVerifyResult::PROVIDED; |
+ |
+ OCSPRevocationStatus current_status = |
+ verify_result->ocsp.revocation_status.value_or( |
+ OCSPRevocationStatus::GOOD); |
+ // In the case that we receive multiple responses, we keep only the |
Ryan Sleevi
2016/07/18 20:08:08
Avoid "we" in comments, especially new code.
// I
dadrian
2016/07/18 22:23:32
Done.
|
+ // strictest status (REVOKED > UNKNOWN > GOOD). |
+ if (current_status == OCSPRevocationStatus::GOOD || |
+ single_response.cert_status.status == OCSPRevocationStatus::REVOKED) { |
+ verify_result->ocsp.revocation_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 +346,8 @@ int CertVerifyProc::Verify(X509Certificate* cert, |
verify_result->common_name_fallback_used); |
} |
+ 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)) { |