[win] Create utilities for helping to populate ModuleDatabase.
Further CLs will move (and test!) the rest of the enumerate_modules_model logic to this collection of helper functions.
BUG=662084
CQ_INCLUDE_TRYBOTS=master.tryserver.chromium.win:win10_chromium_x64_rel_ng
Review-Url: https://codereview.chromium.org/2653333002
Cr-Commit-Position: refs/heads/master@{#448536}
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 798c4d1..b3629c3 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -260,6 +260,8 @@
"conflicts/module_database_win.h",
"conflicts/module_event_sink_impl_win.cc",
"conflicts/module_event_sink_impl_win.h",
+ "conflicts/module_info_util_win.cc",
+ "conflicts/module_info_util_win.h",
"content_settings/chrome_content_settings_utils.cc",
"content_settings/chrome_content_settings_utils.h",
"content_settings/cookie_settings_factory.cc",
diff --git a/chrome/browser/conflicts/module_database_win.cc b/chrome/browser/conflicts/module_database_win.cc
index af71f6ee..c5a090f 100644
--- a/chrome/browser/conflicts/module_database_win.cc
+++ b/chrome/browser/conflicts/module_database_win.cc
@@ -340,10 +340,19 @@
mik.module_time_date_stamp);
}
+// ModuleDatabase::CertificateInfo ---------------------------------------------
+
+ModuleDatabase::CertificateInfo::CertificateInfo() : type(NO_CERTIFICATE) {}
+
// ModuleDatabase::ModuleInfoData ----------------------------------------------
ModuleDatabase::ModuleInfoData::ModuleInfoData() : process_types(0) {}
+ModuleDatabase::ModuleInfoData::ModuleInfoData(const ModuleInfoData& others) =
+ default;
+
+ModuleDatabase::ModuleInfoData::~ModuleInfoData() = default;
+
// ModuleDatabase::ProcessInfoKey ----------------------------------------------
ModuleDatabase::ProcessInfoKey::ProcessInfoKey(
diff --git a/chrome/browser/conflicts/module_database_win.h b/chrome/browser/conflicts/module_database_win.h
index 73725556..6fa87b8 100644
--- a/chrome/browser/conflicts/module_database_win.h
+++ b/chrome/browser/conflicts/module_database_win.h
@@ -22,6 +22,36 @@
// be set as the process-wide singleton via SetInstance.
class ModuleDatabase {
public:
+ // Used as a unique identifier for a module in a ModuleSet.
+ using ModuleId = int;
+
+ // The type of certificate found for the module.
+ enum CertificateType {
+ // The module is not signed.
+ NO_CERTIFICATE,
+ // The module is signed and the certificate is in the module.
+ CERTIFICATE_IN_FILE,
+ // The module is signed and the certificate is in an external catalog.
+ CERTIFICATE_IN_CATALOG,
+ };
+
+ // Structures for maintaining information about modules.
+ struct ModuleInfoKey;
+ struct CertificateInfo;
+ struct ModuleInfoData;
+ using ModuleMap = std::map<ModuleInfoKey, ModuleInfoData>;
+ using ModuleInfo = ModuleMap::value_type;
+
+ // Used for maintaing a list of modules loaded in a process. Maps module IDs
+ // to load addresses.
+ using ModuleLoadAddresses = std::vector<std::pair<ModuleId, uintptr_t>>;
+
+ // Structures for maintaining information about running processes.
+ struct ProcessInfoKey;
+ struct ProcessInfoData;
+ using ProcessMap = std::map<ProcessInfoKey, ProcessInfoData>;
+ using ProcessInfo = ProcessMap::value_type;
+
// A ModuleDatabase is by default bound to a provided sequenced task runner.
// All calls must be made in the context of this task runner, unless
// otherwise noted. For calls from other contexts this task runner is used to
@@ -79,25 +109,6 @@
// been found.
static constexpr size_t kInvalidIndex = ~0u;
- // Used as a unique identifier for a module in a ModuleSet.
- using ModuleId = int;
-
- // Structures for maintaining information about modules.
- struct ModuleInfoKey;
- struct ModuleInfoData;
- using ModuleMap = std::map<ModuleInfoKey, ModuleInfoData>;
- using ModuleInfo = ModuleMap::value_type;
-
- // Used for maintaing a list of modules loaded in a process. Maps module IDs
- // to load addresses.
- using ModuleLoadAddresses = std::vector<std::pair<ModuleId, uintptr_t>>;
-
- // Structures for maintaining information about running processes.
- struct ProcessInfoKey;
- struct ProcessInfoData;
- using ProcessMap = std::map<ProcessInfoKey, ProcessInfoData>;
- using ProcessInfo = ProcessMap::value_type;
-
// Converts a valid |process_type| to a bit for use in a bitmask of process
// values. Exposed in the header for testing.
static uint32_t ProcessTypeToBit(content::ProcessType process_type);
@@ -195,16 +206,59 @@
ModuleId module_id;
};
+// Information about the certificate of a file.
+struct ModuleDatabase::CertificateInfo {
+ CertificateInfo();
+
+ // The type of signature encountered.
+ CertificateType type;
+
+ // Path to the file containing the certificate. Empty if |type| is
+ // NO_CERTIFICATE.
+ base::FilePath path;
+
+ // The "Subject" name of the certificate. This is the signer (ie,
+ // "Google Inc." or "Microsoft Inc.").
+ base::string16 subject;
+};
+
// This is the mutable portion of the module information, and is the storage
// type in a std::map.
struct ModuleDatabase::ModuleInfoData {
ModuleInfoData();
+ ModuleInfoData(const ModuleInfoData& others);
+ ~ModuleInfoData();
// Set of all process types in which this module has been seen (may not be
// currently present in a process of that type). This is a conversion of
// ProcessType enumeration to a bitfield. See "ProcessTypeToBit" and
// "BitIndexToProcessType" for details.
uint32_t process_types;
+
+ // The following pieces of information are determined via a detailed
+ // inspection of the module. This is relatively expensive and uses blocking
+ // IO, so is performed in a background task.
+
+ // The module path, not including the basename. This is cleaned and normalized
+ // so that common paths are converted to their environment variable mappings
+ // (ie, %systemroot%). This makes i18n localized paths easily comparable.
+ base::string16 location;
+
+ // The basename of the module.
+ base::string16 basename;
+
+ // The name of the product the module belongs to.
+ base::string16 product_name;
+
+ // The module file description.
+ base::string16 description;
+
+ // The module version. This is usually in the form a.b.c.d (where a, b, c and
+ // d are integers), but may also have fewer than 4 components.
+ base::string16 version;
+
+ // The certificate info for the module.
+ CertificateInfo certificate_info;
};
// Information about a running process. This ties modules in a ModuleSet to
diff --git a/chrome/browser/conflicts/module_info_util_win.cc b/chrome/browser/conflicts/module_info_util_win.cc
new file mode 100644
index 0000000..2c6c599
--- /dev/null
+++ b/chrome/browser/conflicts/module_info_util_win.cc
@@ -0,0 +1,231 @@
+// Copyright 2017 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/conflicts/module_info_util_win.h"
+
+#include <tlhelp32.h>
+#include <wincrypt.h>
+#include <wintrust.h>
+
+// This must be after wincrypt and wintrust.
+#include <mscat.h>
+
+#include "base/scoped_generic.h"
+#include "base/win/scoped_handle.h"
+
+namespace {
+
+// Helper for scoped tracking an HCERTSTORE.
+struct ScopedHCERTSTORETraits {
+ static HCERTSTORE InvalidValue() { return nullptr; }
+ static void Free(HCERTSTORE store) { ::CertCloseStore(store, 0); }
+};
+using ScopedHCERTSTORE =
+ base::ScopedGeneric<HCERTSTORE, ScopedHCERTSTORETraits>;
+
+// Helper for scoped tracking an HCRYPTMSG.
+struct ScopedHCRYPTMSGTraits {
+ static HCRYPTMSG InvalidValue() { return nullptr; }
+ static void Free(HCRYPTMSG message) { ::CryptMsgClose(message); }
+};
+using ScopedHCRYPTMSG = base::ScopedGeneric<HCRYPTMSG, ScopedHCRYPTMSGTraits>;
+
+// Returns the "Subject" field from the digital signature in the provided
+// binary, if any is present. Returns an empty string on failure.
+base::string16 GetSubjectNameInFile(const base::FilePath& filename) {
+ ScopedHCERTSTORE store;
+ ScopedHCRYPTMSG message;
+
+ // Find the crypto message for this filename.
+ {
+ HCERTSTORE temp_store = nullptr;
+ HCRYPTMSG temp_message = nullptr;
+ bool result =
+ !!CryptQueryObject(CERT_QUERY_OBJECT_FILE, filename.value().c_str(),
+ CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED,
+ CERT_QUERY_FORMAT_FLAG_BINARY, 0, nullptr, nullptr,
+ nullptr, &temp_store, &temp_message, nullptr);
+ store.reset(temp_store);
+ message.reset(temp_message);
+ if (!result)
+ return base::string16();
+ }
+
+ // Determine the size of the signer info data.
+ DWORD signer_info_size = 0;
+ bool result = !!CryptMsgGetParam(message.get(), CMSG_SIGNER_INFO_PARAM, 0,
+ nullptr, &signer_info_size);
+ if (!result)
+ return base::string16();
+
+ // Allocate enough space to hold the signer info.
+ std::unique_ptr<BYTE[]> signer_info_buffer(new BYTE[signer_info_size]);
+ CMSG_SIGNER_INFO* signer_info =
+ reinterpret_cast<CMSG_SIGNER_INFO*>(signer_info_buffer.get());
+
+ // Obtain the signer info.
+ result = !!CryptMsgGetParam(message.get(), CMSG_SIGNER_INFO_PARAM, 0,
+ signer_info, &signer_info_size);
+ if (!result)
+ return base::string16();
+
+ // Search for the signer certificate.
+ CERT_INFO CertInfo = {0};
+ PCCERT_CONTEXT cert_context = nullptr;
+ CertInfo.Issuer = signer_info->Issuer;
+ CertInfo.SerialNumber = signer_info->SerialNumber;
+
+ cert_context = CertFindCertificateInStore(
+ store.get(), X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0,
+ CERT_FIND_SUBJECT_CERT, &CertInfo, nullptr);
+ if (!cert_context)
+ return base::string16();
+
+ // Determine the size of the Subject name.
+ DWORD subject_name_size = CertGetNameString(
+ cert_context, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, nullptr, nullptr, 0);
+ if (!subject_name_size)
+ return base::string16();
+
+ base::string16 subject_name;
+ subject_name.resize(subject_name_size);
+
+ // Get subject name.
+ if (!(CertGetNameString(cert_context, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0,
+ nullptr, const_cast<LPWSTR>(subject_name.c_str()),
+ subject_name_size))) {
+ return base::string16();
+ }
+
+ return subject_name;
+}
+
+// Helper for scoped tracking a catalog admin context.
+struct CryptCATContextScopedTraits {
+ static PVOID InvalidValue() { return nullptr; }
+ static void Free(PVOID context) { CryptCATAdminReleaseContext(context, 0); }
+};
+using ScopedCryptCATContext =
+ base::ScopedGeneric<PVOID, CryptCATContextScopedTraits>;
+
+// Helper for scoped tracking of a catalog context. A catalog context is only
+// valid with an associated admin context, so this is effectively a std::pair.
+// A custom operator!= is required in order for a null |catalog_context| but
+// non-null |context| to compare equal to the InvalidValue exposed by the
+// traits class.
+class CryptCATCatalogContext {
+ public:
+ CryptCATCatalogContext(PVOID context, PVOID catalog_context)
+ : context_(context), catalog_context_(catalog_context) {}
+
+ bool operator!=(const CryptCATCatalogContext& rhs) const {
+ return catalog_context_ != rhs.catalog_context_;
+ }
+
+ PVOID context() const { return context_; }
+ PVOID catalog_context() const { return catalog_context_; }
+
+ private:
+ PVOID context_;
+ PVOID catalog_context_;
+};
+
+struct CryptCATCatalogContextScopedTraits {
+ static CryptCATCatalogContext InvalidValue() {
+ return CryptCATCatalogContext(nullptr, nullptr);
+ }
+ static void Free(const CryptCATCatalogContext& c) {
+ CryptCATAdminReleaseCatalogContext(c.context(), c.catalog_context(), 0);
+ }
+};
+using ScopedCryptCATCatalogContext =
+ base::ScopedGeneric<CryptCATCatalogContext,
+ CryptCATCatalogContextScopedTraits>;
+
+// Extracts the subject name and catalog path if the provided file is present in
+// a catalog file.
+void GetCatalogCertificateInfo(const base::FilePath& filename,
+ ModuleDatabase::CertificateInfo* cert_info) {
+ // Get a crypt context for signature verification.
+ ScopedCryptCATContext context;
+ {
+ PVOID raw_context = nullptr;
+ if (!CryptCATAdminAcquireContext(&raw_context, nullptr, 0))
+ return;
+ context.reset(raw_context);
+ }
+
+ // Open the file of interest.
+ base::win::ScopedHandle file_handle(
+ CreateFileW(filename.value().c_str(), GENERIC_READ,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ nullptr, OPEN_EXISTING, 0, nullptr));
+ if (!file_handle.IsValid())
+ return;
+
+ // Get the size we need for our hash.
+ DWORD hash_size = 0;
+ CryptCATAdminCalcHashFromFileHandle(file_handle.Get(), &hash_size, nullptr,
+ 0);
+ if (hash_size == 0)
+ return;
+
+ // Calculate the hash. If this fails then bail.
+ std::vector<BYTE> buffer(hash_size);
+ if (!CryptCATAdminCalcHashFromFileHandle(file_handle.Get(), &hash_size,
+ buffer.data(), 0)) {
+ return;
+ }
+
+ // Get catalog for our context.
+ ScopedCryptCATCatalogContext catalog_context(CryptCATCatalogContext(
+ context.get(), CryptCATAdminEnumCatalogFromHash(
+ context.get(), buffer.data(), hash_size, 0, nullptr)));
+ if (!catalog_context.is_valid())
+ return;
+
+ // Get the catalog info. This includes the path to the catalog itself, which
+ // contains the signature of interest.
+ CATALOG_INFO catalog_info = {};
+ catalog_info.cbStruct = sizeof(catalog_info);
+ if (!CryptCATCatalogInfoFromContext(catalog_context.get().catalog_context(),
+ &catalog_info, 0)) {
+ return;
+ }
+
+ // Attempt to get the "Subject" field from the signature of the catalog file
+ // itself.
+ base::FilePath catalog_path(catalog_info.wszCatalogFile);
+ base::string16 subject = GetSubjectNameInFile(catalog_path);
+
+ if (subject.empty())
+ return;
+
+ cert_info->type = ModuleDatabase::CERTIFICATE_IN_CATALOG;
+ cert_info->path = catalog_path;
+ cert_info->subject = subject;
+}
+
+} // namespace
+
+// Extracts information about the certificate of the given file, if any is
+// found.
+void GetCertificateInfo(const base::FilePath& filename,
+ ModuleDatabase::CertificateInfo* cert_info) {
+ DCHECK_EQ(ModuleDatabase::NO_CERTIFICATE, cert_info->type);
+ DCHECK(cert_info->path.empty());
+ DCHECK(cert_info->subject.empty());
+
+ GetCatalogCertificateInfo(filename, cert_info);
+ if (cert_info->type == ModuleDatabase::CERTIFICATE_IN_CATALOG)
+ return;
+
+ base::string16 subject = GetSubjectNameInFile(filename);
+ if (subject.empty())
+ return;
+
+ cert_info->type = ModuleDatabase::CERTIFICATE_IN_FILE;
+ cert_info->path = filename;
+ cert_info->subject = subject;
+}
diff --git a/chrome/browser/conflicts/module_info_util_win.h b/chrome/browser/conflicts/module_info_util_win.h
new file mode 100644
index 0000000..ba754f6
--- /dev/null
+++ b/chrome/browser/conflicts/module_info_util_win.h
@@ -0,0 +1,15 @@
+// Copyright 2017 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.
+
+#ifndef CHROME_BROWSER_CONFLICTS_MODULE_INFO_UTIL_WIN_H_
+#define CHROME_BROWSER_CONFLICTS_MODULE_INFO_UTIL_WIN_H_
+
+#include "chrome/browser/conflicts/module_database_win.h"
+
+// Extracts information about the certificate of the given |file|, populating
+// |cert_info|. It is expected that |cert_info| be freshly constructed.
+void GetCertificateInfo(const base::FilePath& file,
+ ModuleDatabase::CertificateInfo* cert_info);
+
+#endif // CHROME_BROWSER_CONFLICTS_MODULE_INFO_UTIL_WIN_H_
diff --git a/chrome/browser/conflicts/module_info_util_win_unittest.cc b/chrome/browser/conflicts/module_info_util_win_unittest.cc
new file mode 100644
index 0000000..f713bd1
--- /dev/null
+++ b/chrome/browser/conflicts/module_info_util_win_unittest.cc
@@ -0,0 +1,39 @@
+// Copyright 2017 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/conflicts/module_info_util_win.h"
+
+#include <memory>
+
+#include "base/base_paths.h"
+#include "base/environment.h"
+#include "base/files/file_path.h"
+#include "base/path_service.h"
+#include "base/strings/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+TEST(ModuleInfoUtil, GetCertificateInfoUnsigned) {
+ base::FilePath path;
+ ASSERT_TRUE(base::PathService::Get(base::FILE_EXE, &path));
+ ModuleDatabase::CertificateInfo cert_info;
+ GetCertificateInfo(path, &cert_info);
+ EXPECT_EQ(ModuleDatabase::NO_CERTIFICATE, cert_info.type);
+ EXPECT_TRUE(cert_info.path.empty());
+ EXPECT_TRUE(cert_info.subject.empty());
+}
+
+TEST(ModuleInfoUtil, GetCertificateInfoSigned) {
+ std::unique_ptr<base::Environment> env = base::Environment::Create();
+ std::string sysroot;
+ ASSERT_TRUE(env->GetVar("SYSTEMROOT", &sysroot));
+
+ base::FilePath path =
+ base::FilePath::FromUTF8Unsafe(sysroot).Append(L"system32\\kernel32.dll");
+
+ ModuleDatabase::CertificateInfo cert_info;
+ GetCertificateInfo(path, &cert_info);
+ EXPECT_NE(ModuleDatabase::NO_CERTIFICATE, cert_info.type);
+ EXPECT_FALSE(cert_info.path.empty());
+ EXPECT_FALSE(cert_info.subject.empty());
+}
diff --git a/chrome/browser/win/enumerate_modules_model.cc b/chrome/browser/win/enumerate_modules_model.cc
index 98aaffa..641644b3 100644
--- a/chrome/browser/win/enumerate_modules_model.cc
+++ b/chrome/browser/win/enumerate_modules_model.cc
@@ -97,249 +97,8 @@
return false;
}
-// Helper for scoped tracking an HCERTSTORE.
-struct ScopedHCERTSTORETraits {
- static HCERTSTORE InvalidValue() { return nullptr; }
- static void Free(HCERTSTORE store) {
- ::CertCloseStore(store, 0);
- }
-};
-using ScopedHCERTSTORE =
- base::ScopedGeneric<HCERTSTORE, ScopedHCERTSTORETraits>;
-
-// Helper for scoped tracking an HCRYPTMSG.
-struct ScopedHCRYPTMSGTraits {
- static HCRYPTMSG InvalidValue() { return nullptr; }
- static void Free(HCRYPTMSG message) {
- ::CryptMsgClose(message);
- }
-};
-using ScopedHCRYPTMSG =
- base::ScopedGeneric<HCRYPTMSG, ScopedHCRYPTMSGTraits>;
-
-// Returns the "Subject" field from the digital signature in the provided
-// binary, if any is present. Returns an empty string on failure.
-base::string16 GetSubjectNameInFile(const base::FilePath& filename) {
- ScopedHCERTSTORE store;
- ScopedHCRYPTMSG message;
-
- // Find the crypto message for this filename.
- {
- HCERTSTORE temp_store = nullptr;
- HCRYPTMSG temp_message = nullptr;
- bool result = !!CryptQueryObject(CERT_QUERY_OBJECT_FILE,
- filename.value().c_str(),
- CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED,
- CERT_QUERY_FORMAT_FLAG_BINARY,
- 0,
- nullptr,
- nullptr,
- nullptr,
- &temp_store,
- &temp_message,
- nullptr);
- store.reset(temp_store);
- message.reset(temp_message);
- if (!result)
- return base::string16();
- }
-
- // Determine the size of the signer info data.
- DWORD signer_info_size = 0;
- bool result = !!CryptMsgGetParam(message.get(),
- CMSG_SIGNER_INFO_PARAM,
- 0,
- nullptr,
- &signer_info_size);
- if (!result)
- return base::string16();
-
- // Allocate enough space to hold the signer info.
- std::unique_ptr<BYTE[]> signer_info_buffer(new BYTE[signer_info_size]);
- CMSG_SIGNER_INFO* signer_info =
- reinterpret_cast<CMSG_SIGNER_INFO*>(signer_info_buffer.get());
-
- // Obtain the signer info.
- result = !!CryptMsgGetParam(message.get(),
- CMSG_SIGNER_INFO_PARAM,
- 0,
- signer_info,
- &signer_info_size);
- if (!result)
- return base::string16();
-
- // Search for the signer certificate.
- CERT_INFO CertInfo = {0};
- PCCERT_CONTEXT cert_context = nullptr;
- CertInfo.Issuer = signer_info->Issuer;
- CertInfo.SerialNumber = signer_info->SerialNumber;
-
- cert_context = CertFindCertificateInStore(
- store.get(),
- X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
- 0,
- CERT_FIND_SUBJECT_CERT,
- &CertInfo,
- nullptr);
- if (!cert_context)
- return base::string16();
-
- // Determine the size of the Subject name.
- DWORD subject_name_size = CertGetNameString(
- cert_context, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, nullptr, nullptr, 0);
- if (!subject_name_size)
- return base::string16();
-
- base::string16 subject_name;
- subject_name.resize(subject_name_size);
-
- // Get subject name.
- if (!(CertGetNameString(cert_context,
- CERT_NAME_SIMPLE_DISPLAY_TYPE,
- 0,
- nullptr,
- const_cast<LPWSTR>(subject_name.c_str()),
- subject_name_size))) {
- return base::string16();
- }
-
- return subject_name;
-}
-
-// Helper for scoped tracking a catalog admin context.
-struct CryptCATContextScopedTraits {
- static PVOID InvalidValue() { return nullptr; }
- static void Free(PVOID context) {
- CryptCATAdminReleaseContext(context, 0);
- }
-};
-using ScopedCryptCATContext =
- base::ScopedGeneric<PVOID, CryptCATContextScopedTraits>;
-
-// Helper for scoped tracking of a catalog context. A catalog context is only
-// valid with an associated admin context, so this is effectively a std::pair.
-// A custom operator!= is required in order for a null |catalog_context| but
-// non-null |context| to compare equal to the InvalidValue exposed by the
-// traits class.
-class CryptCATCatalogContext {
- public:
- CryptCATCatalogContext(PVOID context, PVOID catalog_context)
- : context_(context), catalog_context_(catalog_context) {}
-
- bool operator!=(const CryptCATCatalogContext& rhs) const {
- return catalog_context_ != rhs.catalog_context_;
- }
-
- PVOID context() const { return context_; }
- PVOID catalog_context() const { return catalog_context_; }
-
- private:
- PVOID context_;
- PVOID catalog_context_;
-};
-
-struct CryptCATCatalogContextScopedTraits {
- static CryptCATCatalogContext InvalidValue() {
- return CryptCATCatalogContext(nullptr, nullptr);
- }
- static void Free(const CryptCATCatalogContext& c) {
- CryptCATAdminReleaseCatalogContext(
- c.context(), c.catalog_context(), 0);
- }
-};
-using ScopedCryptCATCatalogContext = base::ScopedGeneric<
- CryptCATCatalogContext, CryptCATCatalogContextScopedTraits>;
-
-// Extracts the subject name and catalog path if the provided file is present in
-// a catalog file.
-void GetCatalogCertificateInfo(const base::FilePath& filename,
- ModuleEnumerator::CertificateInfo* cert_info) {
- // Get a crypt context for signature verification.
- ScopedCryptCATContext context;
- {
- PVOID raw_context = nullptr;
- if (!CryptCATAdminAcquireContext(&raw_context, nullptr, 0))
- return;
- context.reset(raw_context);
- }
-
- // Open the file of interest.
- base::win::ScopedHandle file_handle(CreateFileW(
- filename.value().c_str(), GENERIC_READ,
- FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
- nullptr, OPEN_EXISTING, 0, nullptr));
- if (!file_handle.IsValid())
- return;
-
- // Get the size we need for our hash.
- DWORD hash_size = 0;
- CryptCATAdminCalcHashFromFileHandle(
- file_handle.Get(), &hash_size, nullptr, 0);
- if (hash_size == 0)
- return;
-
- // Calculate the hash. If this fails then bail.
- std::vector<BYTE> buffer(hash_size);
- if (!CryptCATAdminCalcHashFromFileHandle(file_handle.Get(), &hash_size,
- buffer.data(), 0)) {
- return;
- }
-
- // Get catalog for our context.
- ScopedCryptCATCatalogContext catalog_context(CryptCATCatalogContext(
- context.get(),
- CryptCATAdminEnumCatalogFromHash(context.get(), buffer.data(), hash_size,
- 0, nullptr)));
- if (!catalog_context.is_valid())
- return;
-
- // Get the catalog info. This includes the path to the catalog itself, which
- // contains the signature of interest.
- CATALOG_INFO catalog_info = {};
- catalog_info.cbStruct = sizeof(catalog_info);
- if (!CryptCATCatalogInfoFromContext(
- catalog_context.get().catalog_context(), &catalog_info, 0)) {
- return;
- }
-
- // Attempt to get the "Subject" field from the signature of the catalog file
- // itself.
- base::FilePath catalog_path(catalog_info.wszCatalogFile);
- base::string16 subject = GetSubjectNameInFile(catalog_path);
-
- if (subject.empty())
- return;
-
- cert_info->type = ModuleEnumerator::CERTIFICATE_IN_CATALOG;
- cert_info->path = catalog_path;
- cert_info->subject = subject;
-}
-
-// Extracts information about the certificate of the given file, if any is
-// found.
-void GetCertificateInfo(const base::FilePath& filename,
- ModuleEnumerator::CertificateInfo* cert_info) {
- DCHECK_EQ(ModuleEnumerator::NO_CERTIFICATE, cert_info->type);
- DCHECK(cert_info->path.empty());
- DCHECK(cert_info->subject.empty());
-
- GetCatalogCertificateInfo(filename, cert_info);
- if (cert_info->type == ModuleEnumerator::CERTIFICATE_IN_CATALOG)
- return;
-
- base::string16 subject = GetSubjectNameInFile(filename);
- if (subject.empty())
- return;
-
- cert_info->type = ModuleEnumerator::CERTIFICATE_IN_FILE;
- cert_info->path = filename;
- cert_info->subject = subject;
-}
-
} // namespace
-ModuleEnumerator::CertificateInfo::CertificateInfo() : type(NO_CERTIFICATE) {}
-
ModuleEnumerator::Module::Module() {
}
@@ -709,10 +468,10 @@
size_t third_party_loaded = 0;
size_t third_party_not_loaded = 0;
for (const auto& module : *enumerated_modules_) {
- if (module.cert_info.type != ModuleEnumerator::NO_CERTIFICATE) {
+ if (module.cert_info.type != ModuleDatabase::NO_CERTIFICATE) {
++signed_modules;
- if (module.cert_info.type == ModuleEnumerator::CERTIFICATE_IN_CATALOG)
+ if (module.cert_info.type == ModuleDatabase::CERTIFICATE_IN_CATALOG)
++catalog_modules;
// The first time this certificate is encountered it will be inserted
diff --git a/chrome/browser/win/enumerate_modules_model.h b/chrome/browser/win/enumerate_modules_model.h
index 6a1265b8f..76ce022 100644
--- a/chrome/browser/win/enumerate_modules_model.h
+++ b/chrome/browser/win/enumerate_modules_model.h
@@ -15,6 +15,7 @@
#include "base/observer_list.h"
#include "base/strings/string16.h"
#include "base/timer/timer.h"
+#include "chrome/browser/conflicts/module_info_util_win.h"
#include "content/public/browser/browser_thread.h"
#include "url/gurl.h"
@@ -73,25 +74,6 @@
XP = 1 << 0,
};
- // The type of certificate found for the module.
- enum CertificateType {
- NO_CERTIFICATE,
- CERTIFICATE_IN_FILE,
- CERTIFICATE_IN_CATALOG,
- };
-
- // Information about the certificate of a file.
- struct CertificateInfo {
- CertificateInfo();
-
- // The type of signature encountered.
- CertificateType type;
- // Path to the file containing the certificate. Empty if NO_CERTIFICATE.
- base::FilePath path;
- // The "Subject" name of the certificate.
- base::string16 subject;
- };
-
// The structure we populate when enumerating modules.
struct Module {
Module();
@@ -126,7 +108,7 @@
// The duplicate count within each category of modules.
int duplicate_count;
// The certificate info for the module.
- CertificateInfo cert_info;
+ ModuleDatabase::CertificateInfo cert_info;
};
// A vector typedef of all modules enumerated.
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 97f0d6b..986afe79 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -3125,6 +3125,7 @@
"../browser/component_updater/sw_reporter_installer_win_unittest.cc",
"../browser/conflicts/module_database_win_unittest.cc",
"../browser/conflicts/module_event_sink_impl_win_unittest.cc",
+ "../browser/conflicts/module_info_util_win_unittest.cc",
"../browser/content_settings/content_settings_default_provider_unittest.cc",
"../browser/content_settings/content_settings_mock_observer.cc",
"../browser/content_settings/content_settings_mock_observer.h",