Index: net/cert/expect_staple_report.cc |
diff --git a/net/cert/expect_staple_report.cc b/net/cert/expect_staple_report.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..8d6e52a5c1376bf8c5d5f21b0ebf0ba7723fe46d |
--- /dev/null |
+++ b/net/cert/expect_staple_report.cc |
@@ -0,0 +1,126 @@ |
+// Copyright 2016 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "expect_staple_report.h" |
+ |
+#include "base/time/time.h" |
+#include "net/cert/internal/parse_ocsp.h" |
+#include "net/cert/x509_certificate.h" |
+#include "net/der/parse_values.h" |
+ |
+namespace net { |
+ |
+namespace { |
+ |
+der::GeneralizedTime ConvertBaseTime(const base::Time& time) { |
+ base::Time::Exploded exploded; |
+ time.UTCExplode(&exploded); |
+ |
+ der::GeneralizedTime result; |
+ result.year = exploded.year; |
+ result.month = exploded.month; |
+ result.day = exploded.day_of_month; |
+ result.hours = exploded.hour; |
+ result.minutes = exploded.minute; |
+ result.seconds = exploded.second; |
+ return result; |
+} |
+ |
+// Checks that thisUpdate <= verify_time < nextUpdate, and that thisUpdate >= |
+// verify_time - max_age. |
+bool CheckOCSPDateValid(const OCSPSingleResponse& response, |
+ const base::Time& verify_time, |
+ const base::TimeDelta& max_age) { |
+ if (response.has_next_update && |
+ (response.next_update <= response.this_update)) { |
+ return false; |
+ } |
+ |
+ // Place |verify_time| in the bounds. |
+ der::GeneralizedTime verify_time_der = ConvertBaseTime(verify_time); |
+ if (response.this_update > verify_time_der) |
+ return false; |
+ if (response.has_next_update && (response.next_update <= verify_time_der)) |
+ return false; |
+ |
+ // Enforce |max_age|. |
+ der::GeneralizedTime lower_bound = ConvertBaseTime(verify_time - max_age); |
+ if (response.this_update < lower_bound) |
+ return false; |
+ return true; |
+} |
+ |
+bool CompareCertIDToCertificate(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 serial == cert_id.serial_number; |
+} |
+ |
+} // namespace |
+ |
+ExpectStapleReport::ExpectStapleReport() : staple_error_(StapleError::OK) {} |
+ |
+ExpectStapleReport::~ExpectStapleReport() {} |
+ |
+// static |
+std::unique_ptr<ExpectStapleReport> ExpectStapleReport::FromRawOCSPResponse( |
+ const std::string& raw_response, |
+ const base::Time& verify_time, |
+ const base::TimeDelta& max_age, |
+ const X509Certificate& verified_certificate) { |
+ std::unique_ptr<ExpectStapleReport> out(new ExpectStapleReport); |
+ out->verify_time_ = verify_time; |
+ der::Input response_der(&raw_response); |
+ |
+ OCSPResponse response; |
+ if (!ParseOCSPResponse(response_der, &response)) { |
+ out->staple_error_ = StapleError::PARSE_RESPONSE; |
+ return out; |
+ } |
+ |
+ // If the OCSP response isn't status SUCCESSFUL, don't parse the rest of the |
+ // data. |
+ if (response.status != OCSPResponse::ResponseStatus::SUCCESSFUL) { |
+ out->staple_error_ = StapleError::BAD_RESPONSE; |
+ return out; |
+ } |
+ |
+ OCSPResponseData response_data; |
+ if (!ParseOCSPResponseData(response.data, &response_data)) { |
+ out->staple_error_ = StapleError::PARSE_RESPONSE_DATA; |
+ return out; |
+ } |
+ |
+ // TODO(svaldez): Unify with GetOCSPCertStatus. |
+ bool contains_correct_response = false; |
+ for (const auto& single_response_der : response_data.responses) { |
+ OCSPSingleResponse single_response; |
+ if (!ParseOCSPSingleResponse(single_response_der, &single_response)) |
+ continue; |
+ SingleResult single_result; |
+ single_result.status = single_response.cert_status.status; |
+ single_result.is_date_valid = |
+ CheckOCSPDateValid(single_response, verify_time, max_age); |
+ OCSPCertID cert_id; |
+ if (ParseOCSPCertID(single_response.cert_id_tlv, &cert_id)) { |
+ single_result.is_correct_certificate = |
+ CompareCertIDToCertificate(cert_id, verified_certificate); |
+ } |
+ if (single_result.is_date_valid && single_result.is_correct_certificate && |
+ single_result.status == OCSPCertStatus::Status::GOOD) { |
+ contains_correct_response = true; |
+ } |
+ out->stapled_responses_.push_back(single_result); |
+ } |
+ |
+ if (!contains_correct_response) { |
+ out->staple_error_ = StapleError::NO_MATCHING_RESPONSE; |
+ } else { |
+ out->staple_error_ = StapleError::OK; |
+ } |
+ return out; |
+} |
+ |
+} // namespace net |