Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(207)

Side by Side Diff: chrome/browser/conflicts/module_info_util_win.cc

Issue 2653333002: [win] Create utilities for helping to populate ModuleDatabase. (Closed)
Patch Set: Address review comments. Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/conflicts/module_info_util_win.h"
6
7 #include <mscat.h> // NOLINT: This must be after wincrypt and wintrust.
Patrick Monette 2017/02/06 19:05:23 Did you inadvertently moved this?
chrisha 2017/02/06 20:54:45 Ah, that would be "git cl format" doing this for m
8 #include <tlhelp32.h>
9 #include <wincrypt.h>
10 #include <wintrust.h>
11
12 #include "base/scoped_generic.h"
13 #include "base/win/scoped_handle.h"
14
15 namespace {
16
17 // Helper for scoped tracking an HCERTSTORE.
18 struct ScopedHCERTSTORETraits {
19 static HCERTSTORE InvalidValue() { return nullptr; }
20 static void Free(HCERTSTORE store) { ::CertCloseStore(store, 0); }
21 };
22 using ScopedHCERTSTORE =
23 base::ScopedGeneric<HCERTSTORE, ScopedHCERTSTORETraits>;
24
25 // Helper for scoped tracking an HCRYPTMSG.
26 struct ScopedHCRYPTMSGTraits {
27 static HCRYPTMSG InvalidValue() { return nullptr; }
28 static void Free(HCRYPTMSG message) { ::CryptMsgClose(message); }
29 };
30 using ScopedHCRYPTMSG = base::ScopedGeneric<HCRYPTMSG, ScopedHCRYPTMSGTraits>;
31
32 // Returns the "Subject" field from the digital signature in the provided
33 // binary, if any is present. Returns an empty string on failure.
34 base::string16 GetSubjectNameInFile(const base::FilePath& filename) {
35 ScopedHCERTSTORE store;
36 ScopedHCRYPTMSG message;
37
38 // Find the crypto message for this filename.
39 {
40 HCERTSTORE temp_store = nullptr;
41 HCRYPTMSG temp_message = nullptr;
42 bool result =
43 !!CryptQueryObject(CERT_QUERY_OBJECT_FILE, filename.value().c_str(),
44 CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED,
45 CERT_QUERY_FORMAT_FLAG_BINARY, 0, nullptr, nullptr,
46 nullptr, &temp_store, &temp_message, nullptr);
47 store.reset(temp_store);
48 message.reset(temp_message);
49 if (!result)
50 return base::string16();
51 }
52
53 // Determine the size of the signer info data.
54 DWORD signer_info_size = 0;
55 bool result = !!CryptMsgGetParam(message.get(), CMSG_SIGNER_INFO_PARAM, 0,
56 nullptr, &signer_info_size);
57 if (!result)
58 return base::string16();
59
60 // Allocate enough space to hold the signer info.
61 std::unique_ptr<BYTE[]> signer_info_buffer(new BYTE[signer_info_size]);
62 CMSG_SIGNER_INFO* signer_info =
63 reinterpret_cast<CMSG_SIGNER_INFO*>(signer_info_buffer.get());
64
65 // Obtain the signer info.
66 result = !!CryptMsgGetParam(message.get(), CMSG_SIGNER_INFO_PARAM, 0,
67 signer_info, &signer_info_size);
68 if (!result)
69 return base::string16();
70
71 // Search for the signer certificate.
72 CERT_INFO CertInfo = {0};
73 PCCERT_CONTEXT cert_context = nullptr;
74 CertInfo.Issuer = signer_info->Issuer;
75 CertInfo.SerialNumber = signer_info->SerialNumber;
76
77 cert_context = CertFindCertificateInStore(
78 store.get(), X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0,
79 CERT_FIND_SUBJECT_CERT, &CertInfo, nullptr);
80 if (!cert_context)
81 return base::string16();
82
83 // Determine the size of the Subject name.
84 DWORD subject_name_size = CertGetNameString(
85 cert_context, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, nullptr, nullptr, 0);
86 if (!subject_name_size)
87 return base::string16();
88
89 base::string16 subject_name;
90 subject_name.resize(subject_name_size);
91
92 // Get subject name.
93 if (!(CertGetNameString(cert_context, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0,
94 nullptr, const_cast<LPWSTR>(subject_name.c_str()),
95 subject_name_size))) {
96 return base::string16();
97 }
98
99 return subject_name;
100 }
101
102 // Helper for scoped tracking a catalog admin context.
103 struct CryptCATContextScopedTraits {
104 static PVOID InvalidValue() { return nullptr; }
105 static void Free(PVOID context) { CryptCATAdminReleaseContext(context, 0); }
106 };
107 using ScopedCryptCATContext =
108 base::ScopedGeneric<PVOID, CryptCATContextScopedTraits>;
109
110 // Helper for scoped tracking of a catalog context. A catalog context is only
111 // valid with an associated admin context, so this is effectively a std::pair.
112 // A custom operator!= is required in order for a null |catalog_context| but
113 // non-null |context| to compare equal to the InvalidValue exposed by the
114 // traits class.
115 class CryptCATCatalogContext {
116 public:
117 CryptCATCatalogContext(PVOID context, PVOID catalog_context)
118 : context_(context), catalog_context_(catalog_context) {}
119
120 bool operator!=(const CryptCATCatalogContext& rhs) const {
121 return catalog_context_ != rhs.catalog_context_;
122 }
123
124 PVOID context() const { return context_; }
125 PVOID catalog_context() const { return catalog_context_; }
126
127 private:
128 PVOID context_;
129 PVOID catalog_context_;
130 };
131
132 struct CryptCATCatalogContextScopedTraits {
133 static CryptCATCatalogContext InvalidValue() {
134 return CryptCATCatalogContext(nullptr, nullptr);
135 }
136 static void Free(const CryptCATCatalogContext& c) {
137 CryptCATAdminReleaseCatalogContext(c.context(), c.catalog_context(), 0);
138 }
139 };
140 using ScopedCryptCATCatalogContext =
141 base::ScopedGeneric<CryptCATCatalogContext,
142 CryptCATCatalogContextScopedTraits>;
143
144 // Extracts the subject name and catalog path if the provided file is present in
145 // a catalog file.
146 void GetCatalogCertificateInfo(const base::FilePath& filename,
147 ModuleDatabase::CertificateInfo* cert_info) {
148 // Get a crypt context for signature verification.
149 ScopedCryptCATContext context;
150 {
151 PVOID raw_context = nullptr;
152 if (!CryptCATAdminAcquireContext(&raw_context, nullptr, 0))
153 return;
154 context.reset(raw_context);
155 }
156
157 // Open the file of interest.
158 base::win::ScopedHandle file_handle(
159 CreateFileW(filename.value().c_str(), GENERIC_READ,
160 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
161 nullptr, OPEN_EXISTING, 0, nullptr));
162 if (!file_handle.IsValid())
163 return;
164
165 // Get the size we need for our hash.
166 DWORD hash_size = 0;
167 CryptCATAdminCalcHashFromFileHandle(file_handle.Get(), &hash_size, nullptr,
168 0);
169 if (hash_size == 0)
170 return;
171
172 // Calculate the hash. If this fails then bail.
173 std::vector<BYTE> buffer(hash_size);
174 if (!CryptCATAdminCalcHashFromFileHandle(file_handle.Get(), &hash_size,
175 buffer.data(), 0)) {
176 return;
177 }
178
179 // Get catalog for our context.
180 ScopedCryptCATCatalogContext catalog_context(CryptCATCatalogContext(
181 context.get(), CryptCATAdminEnumCatalogFromHash(
182 context.get(), buffer.data(), hash_size, 0, nullptr)));
183 if (!catalog_context.is_valid())
184 return;
185
186 // Get the catalog info. This includes the path to the catalog itself, which
187 // contains the signature of interest.
188 CATALOG_INFO catalog_info = {};
189 catalog_info.cbStruct = sizeof(catalog_info);
190 if (!CryptCATCatalogInfoFromContext(catalog_context.get().catalog_context(),
191 &catalog_info, 0)) {
192 return;
193 }
194
195 // Attempt to get the "Subject" field from the signature of the catalog file
196 // itself.
197 base::FilePath catalog_path(catalog_info.wszCatalogFile);
198 base::string16 subject = GetSubjectNameInFile(catalog_path);
199
200 if (subject.empty())
201 return;
202
203 cert_info->type = ModuleDatabase::CERTIFICATE_IN_CATALOG;
204 cert_info->path = catalog_path;
205 cert_info->subject = subject;
206 }
207
208 } // namespace
209
210 // Extracts information about the certificate of the given file, if any is
211 // found.
212 void GetCertificateInfo(const base::FilePath& filename,
213 ModuleDatabase::CertificateInfo* cert_info) {
214 DCHECK_EQ(ModuleDatabase::NO_CERTIFICATE, cert_info->type);
215 DCHECK(cert_info->path.empty());
216 DCHECK(cert_info->subject.empty());
217
218 GetCatalogCertificateInfo(filename, cert_info);
219 if (cert_info->type == ModuleDatabase::CERTIFICATE_IN_CATALOG)
220 return;
221
222 base::string16 subject = GetSubjectNameInFile(filename);
223 if (subject.empty())
224 return;
225
226 cert_info->type = ModuleDatabase::CERTIFICATE_IN_FILE;
227 cert_info->path = filename;
228 cert_info->subject = subject;
229 }
OLDNEW
« no previous file with comments | « chrome/browser/conflicts/module_info_util_win.h ('k') | chrome/browser/conflicts/module_info_util_win_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698