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

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