Index: chrome/browser/safe_browsing/incident_reporting/binary_integrity_analyzer_mac_unittest.cc |
diff --git a/chrome/browser/safe_browsing/incident_reporting/binary_integrity_analyzer_mac_unittest.cc b/chrome/browser/safe_browsing/incident_reporting/binary_integrity_analyzer_mac_unittest.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..4f2831dd33540668e3b40d280a2ece5d3b79cfc3 |
--- /dev/null |
+++ b/chrome/browser/safe_browsing/incident_reporting/binary_integrity_analyzer_mac_unittest.cc |
@@ -0,0 +1,145 @@ |
+// Copyright 2015 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 "chrome/browser/safe_browsing/incident_reporting/binary_integrity_analyzer.h" |
+ |
+#include <stdio.h> |
+#include <stdlib.h> |
+ |
+#include "base/bind.h" |
+#include "base/files/file_util.h" |
+#include "base/files/scoped_temp_dir.h" |
+#include "base/memory/scoped_ptr.h" |
+#include "base/path_service.h" |
+#include "base/test/scoped_path_override.h" |
+#include "chrome/browser/safe_browsing/incident_reporting/incident.h" |
+#include "chrome/browser/safe_browsing/incident_reporting/mock_incident_receiver.h" |
+#include "chrome/common/chrome_paths.h" |
+#include "chrome/common/safe_browsing/csd.pb.h" |
+#include "testing/gmock/include/gmock/gmock.h" |
+#include "testing/gtest/include/gtest/gtest.h" |
+ |
+using ::testing::_; |
+using ::testing::StrictMock; |
+ |
+namespace safe_browsing { |
+ |
+namespace { |
+const char kBundleBase[] = "test-bundle.app"; |
+const char kBundleURL[] = "test-bundle.app/Contents/MacOS/test-bundle"; |
+ |
+// Helper function to corrupt the content of a binary to make sure the signature |
+// verification will fail. |
+bool CorruptFileContent(const base::FilePath& file_path) { |
+ FILE* file = base::OpenFile(file_path, "r+"); |
Robert Sesek
2015/10/05 22:19:07
base/files/file.h is probably a better interface t
Greg K
2015/10/07 22:54:29
Done.
|
+ |
+ if (file == NULL) |
+ return false; |
+ |
+ if (fseek(file, 0x1F90, SEEK_SET) == -1) |
+ return false; |
+ |
+ char vec[] = {0xAA}; |
+ size_t written = fwrite(vec, sizeof(char), 1, file); |
+ return base::CloseFile(file) && written == sizeof(char); |
+} |
+} // namespace |
+ |
+class BinaryIntegrityAnalyzerMacTest : public ::testing::Test { |
+ public: |
+ BinaryIntegrityAnalyzerMacTest(); |
+ |
+ protected: |
+ base::FilePath test_data_dir_; |
+ scoped_ptr<base::ScopedPathOverride> exe_dir_override_; |
+ scoped_ptr<base::ScopedPathOverride> exe_override_; |
+ base::ScopedTempDir temp_dir_; |
+}; |
+ |
+BinaryIntegrityAnalyzerMacTest::BinaryIntegrityAnalyzerMacTest() { |
+ // Retrieve DIR_TEST_DATA here because it is based on DIR_EXE and we are |
+ // about to override the path to the latter. |
+ CHECK(PathService::Get(chrome::DIR_TEST_DATA, &test_data_dir_)); |
Robert Sesek
2015/10/05 22:19:07
Don't CHECK in tests. Use ASSERT_TRUE instead.
Greg K
2015/10/07 22:54:29
Done.
|
+ test_data_dir_ = test_data_dir_.Append("safe_browsing/mach_o/"); |
+ |
+ // Set up the temp directory to copy the bundle to. |
+ CHECK(temp_dir_.CreateUniqueTempDir()); |
Robert Sesek
2015/10/05 22:19:07
Same, no CHECK.
Greg K
2015/10/07 22:54:29
Done.
|
+ base::FilePath exe_path = temp_dir_.path().AppendASCII(kBundleURL); |
+ |
+ // Copy the signed bundle to the temp directory. |
+ base::FilePath signed_bundle_path(test_data_dir_); |
+ signed_bundle_path = signed_bundle_path.Append(kBundleBase); |
Robert Sesek
2015/10/05 22:19:07
It's typical to chain the Append calls:
base::F
Greg K
2015/10/07 22:54:29
Done.
|
+ base::FilePath copied_bundle_path(temp_dir_.path()); |
+ copied_bundle_path = copied_bundle_path.Append(kBundleBase); |
+ CHECK(base::CopyDirectory(signed_bundle_path, copied_bundle_path, true)); |
Robert Sesek
2015/10/05 22:19:07
No CHECK.
Greg K
2015/10/07 22:54:29
Done.
|
+ |
+ // Now setup the path service overrides. |
+ exe_dir_override_.reset( |
+ new base::ScopedPathOverride(base::DIR_EXE, temp_dir_.path())); |
+ exe_override_.reset(new base::ScopedPathOverride(base::FILE_EXE, exe_path)); |
+} |
+ |
+TEST_F(BinaryIntegrityAnalyzerMacTest, GetCriticalPathsAndRequirements) { |
+ // Expected paths and requirement strings. |
+ std::vector<std::pair<base::FilePath, std::string>> |
+ paths_and_requirements_expected; |
+ |
+ base::FilePath exe_path = temp_dir_.path().AppendASCII(kBundleURL); |
+ char resolved_name[PATH_MAX]; |
+ ASSERT_NE(realpath(exe_path.value().c_str(), resolved_name), nullptr); |
+ |
+ std::string expected_req = |
+ "anchor apple generic and certificate 1[field.1.2.840.113635.100.6.2.6] " |
+ "exists and certificate leaf[field.1.2.840.113635.100.6.1.13] exists and " |
+ "certificate leaf[subject.OU]=\"EQHXZ8M8AV\" and " |
+ "(identifier=\"com.google.Chrome\" or " |
+ "identifier=\"com.google.Chrome.canary\")"; |
+ paths_and_requirements_expected.push_back( |
+ std::make_pair(std::string(resolved_name), expected_req)); |
+ |
+ std::vector<std::pair<base::FilePath, std::string>> paths_and_requirements = |
+ GetCriticalPathsAndRequirements(); |
+ ASSERT_THAT(paths_and_requirements, |
+ ::testing::ContainerEq(paths_and_requirements_expected)); |
+} |
+ |
+TEST_F(BinaryIntegrityAnalyzerMacTest, VerifyBinaryIntegrityHelper) { |
+ scoped_ptr<MockIncidentReceiver> mock_receiver( |
+ new StrictMock<MockIncidentReceiver>()); |
+ base::FilePath exe; |
+ ASSERT_TRUE(PathService::Get(base::FILE_EXE, &exe)); |
+ std::string requirement( |
+ "certificate leaf[subject.CN]=\"untrusted@goat.local\""); |
+ VerifyBinaryIntegrityHelper(mock_receiver.Pass(), exe, requirement); |
+ |
+ base::FilePath exe_path; |
+ ASSERT_TRUE(PathService::Get(base::FILE_EXE, &exe_path)); |
+ ASSERT_TRUE(CorruptFileContent(exe_path)); |
+ |
+ mock_receiver.reset(new MockIncidentReceiver()); |
+ scoped_ptr<Incident> incident; |
+ EXPECT_CALL(*mock_receiver, DoAddIncidentForProcess(_)) |
+ .WillOnce(TakeIncident(&incident)); |
+ |
+ VerifyBinaryIntegrityHelper(mock_receiver.Pass(), exe, requirement); |
Greg K
2015/10/07 22:54:29
This should be .get()
|
+ |
+ // Verify that theincident report contains the expected data. |
+ scoped_ptr<ClientIncidentReport_IncidentData> incident_data( |
+ incident->TakePayload()); |
+ |
+ ASSERT_TRUE(incident_data->has_osx_incident()); |
+ ASSERT_TRUE(incident_data->osx_incident().has_file_basename()); |
+ ASSERT_EQ("test-bundle", incident_data->osx_incident().file_basename()); |
+ ASSERT_TRUE(incident_data->osx_incident().has_sec_error()); |
+ ASSERT_EQ(-67061, incident_data->osx_incident().sec_error()); |
+ ASSERT_EQ(1, incident_data->osx_incident().sub_incident_size()); |
+ |
+ const auto& sub_incident = incident_data->osx_incident().sub_incident(0); |
+ ASSERT_TRUE(sub_incident.has_file_basename()); |
+ ASSERT_EQ("test-bundle", sub_incident.file_basename()); |
+ ASSERT_TRUE(sub_incident.has_signature()); |
+ ASSERT_TRUE(sub_incident.signature().signed_data_size() > 0); |
+} |
+ |
+} // namespace safe_browsing |