OLD | NEW |
---|---|
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/safe_browsing/signature_util.h" | 5 #include "chrome/browser/safe_browsing/signature_util.h" |
6 | 6 |
7 #include <windows.h> | 7 #include <windows.h> |
8 #include <softpub.h> | 8 #include <softpub.h> |
9 #include <wincrypt.h> | 9 #include <wincrypt.h> |
10 #include <wintrust.h> | 10 #include <wintrust.h> |
11 | 11 |
12 #include "base/file_path.h" | 12 #include "base/file_path.h" |
13 #include "base/logging.h" | 13 #include "base/logging.h" |
14 #include "base/scoped_ptr.h" | 14 #include "base/scoped_ptr.h" |
15 #include "crypto/scoped_capi_types.h" | 15 #include "crypto/scoped_capi_types.h" |
16 #include "chrome/common/safe_browsing/csd.pb.h" | 16 #include "chrome/common/safe_browsing/csd.pb.h" |
17 | 17 |
18 #pragma comment(lib, "crypt32.lib") | 18 #pragma comment(lib, "crypt32.lib") |
19 #pragma comment(lib, "wintrust.lib") | 19 #pragma comment(lib, "wintrust.lib") |
20 | 20 |
21 namespace safe_browsing { | 21 namespace safe_browsing { |
22 namespace { | 22 namespace { |
23 using crypto::ScopedCAPIHandle; | 23 using crypto::ScopedCAPIHandle; |
24 using crypto::CAPIDestroyer; | 24 using crypto::CAPIDestroyer; |
25 using crypto::CAPIDestroyerWithFlags; | 25 using crypto::CAPIDestroyerWithFlags; |
26 | 26 |
27 // Free functor for scoped_ptr_malloc. | 27 // Free functors for scoped_ptr_malloc. |
28 class FreeConstCertContext { | 28 class FreeConstCertContext { |
29 public: | 29 public: |
30 void operator()(const CERT_CONTEXT* cert_context) const { | 30 void operator()(const CERT_CONTEXT* cert_context) const { |
31 CertFreeCertificateContext(cert_context); | 31 if (cert_context) { |
32 CertFreeCertificateContext(cert_context); | |
33 } | |
34 } | |
35 }; | |
36 | |
37 class FreeConstCertChainContext { | |
38 public: | |
39 void operator()(const CERT_CHAIN_CONTEXT* cert_chain_context) const { | |
40 if (cert_chain_context) { | |
41 CertFreeCertificateChain(cert_chain_context); | |
42 } | |
32 } | 43 } |
33 }; | 44 }; |
34 | 45 |
35 // Tries to extract the signing certificate from |file_path|. On success, | 46 // Tries to extract the signing certificate from |file_path|. On success, |
36 // the |certificate_contents| field of |signature_info| is populated with the | 47 // the |certificate_contents| field of |signature_info| is populated with the |
37 // DER-encoded X.509 certificate. | 48 // DER-encoded X.509 certificate. |
38 void GetCertificateContents( | 49 void GetCertificateContents( |
39 const FilePath& file_path, | 50 const FilePath& file_path, |
40 ClientDownloadRequest_SignatureInfo* signature_info) { | 51 ClientDownloadRequest_SignatureInfo* signature_info) { |
41 // Largely based on http://support.microsoft.com/kb/323809 | 52 // Largely based on http://support.microsoft.com/kb/323809 |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
97 X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, | 108 X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, |
98 0, // flags | 109 0, // flags |
99 CERT_FIND_SUBJECT_CERT, | 110 CERT_FIND_SUBJECT_CERT, |
100 &cert_info, | 111 &cert_info, |
101 NULL)); // no previous context | 112 NULL)); // no previous context |
102 if (!cert_context.get()) { | 113 if (!cert_context.get()) { |
103 VLOG(2) << "Failed to get CERT_CONTEXT"; | 114 VLOG(2) << "Failed to get CERT_CONTEXT"; |
104 return; | 115 return; |
105 } | 116 } |
106 | 117 |
107 signature_info->set_certificate_contents(cert_context->pbCertEncoded, | 118 // Follow the chain of certificates to a trusted root. |
108 cert_context->cbCertEncoded); | 119 CERT_CHAIN_PARA cert_chain_params; |
109 VLOG(2) << "Successfully extracted cert"; | 120 memset(&cert_chain_params, 0, sizeof(cert_chain_params)); |
121 cert_chain_params.cbSize = sizeof(cert_chain_params); | |
122 | |
123 const CERT_CHAIN_CONTEXT* cert_chain_context = NULL; | |
124 if (!CertGetCertificateChain(NULL, // default chain engine | |
125 cert_context.get(), | |
126 // TODO(bryner): should this verify at the | |
127 // executable's embedded timestamp? | |
128 NULL, // verify at the current time | |
129 NULL, // no additional store | |
130 &cert_chain_params, | |
131 0, // default flags | |
132 NULL, // reserved parameter | |
133 &cert_chain_context)) { | |
134 VLOG(2) << "Failed to get certificate chain."; | |
135 return; | |
136 } | |
137 | |
138 typedef scoped_ptr_malloc<const CERT_CHAIN_CONTEXT, | |
139 FreeConstCertChainContext> ScopedCertChainContext; | |
140 ScopedCertChainContext scoped_cert_chain_context(cert_chain_context); | |
141 for (size_t i = 0; i < cert_chain_context->cChain; ++i) { | |
142 CERT_SIMPLE_CHAIN* simple_chain = cert_chain_context->rgpChain[i]; | |
143 ClientDownloadRequest_CertificateChain* chain = | |
144 signature_info->add_certificate_chain(); | |
145 for (size_t j = 0; j < simple_chain->cElement; ++j) { | |
146 CERT_CHAIN_ELEMENT* element = simple_chain->rgpElement[j]; | |
147 chain->add_element()->set_certificate( | |
148 element->pCertContext->pbCertEncoded, | |
149 element->pCertContext->cbCertEncoded); | |
150 } | |
151 } | |
110 } | 152 } |
111 | 153 |
112 bool CheckTrust(const FilePath& file_path) { | 154 bool CheckTrust(const FilePath& file_path) { |
113 WINTRUST_FILE_INFO file_info; | 155 WINTRUST_FILE_INFO file_info; |
114 file_info.cbStruct = sizeof(file_info); | 156 file_info.cbStruct = sizeof(file_info); |
115 file_info.pcwszFilePath = file_path.value().c_str(); | 157 file_info.pcwszFilePath = file_path.value().c_str(); |
116 file_info.hFile = NULL; | 158 file_info.hFile = NULL; |
117 file_info.pgKnownSubject = NULL; | 159 file_info.pgKnownSubject = NULL; |
118 | 160 |
119 WINTRUST_DATA wintrust_data; | 161 WINTRUST_DATA wintrust_data; |
120 wintrust_data.cbStruct = sizeof(wintrust_data); | 162 wintrust_data.cbStruct = sizeof(wintrust_data); |
121 wintrust_data.pPolicyCallbackData = NULL; | 163 wintrust_data.pPolicyCallbackData = NULL; |
122 wintrust_data.pSIPClientData = NULL; | 164 wintrust_data.pSIPClientData = NULL; |
123 wintrust_data.dwUIChoice = WTD_UI_NONE; | 165 wintrust_data.dwUIChoice = WTD_UI_NONE; |
124 wintrust_data.fdwRevocationChecks = WTD_REVOKE_NONE; | 166 wintrust_data.fdwRevocationChecks = WTD_REVOKE_NONE; |
125 wintrust_data.dwUnionChoice = WTD_CHOICE_FILE; | 167 wintrust_data.dwUnionChoice = WTD_CHOICE_FILE; |
126 wintrust_data.pFile = &file_info; | 168 wintrust_data.pFile = &file_info; |
127 wintrust_data.dwStateAction = WTD_STATEACTION_IGNORE; | 169 wintrust_data.dwStateAction = WTD_STATEACTION_IGNORE; |
Ryan Sleevi
2011/11/12 22:06:17
FWIW, you could save yourself the chain extraction
| |
128 wintrust_data.hWVTStateData = NULL; | 170 wintrust_data.hWVTStateData = NULL; |
129 wintrust_data.pwszURLReference = NULL; | 171 wintrust_data.pwszURLReference = NULL; |
130 wintrust_data.dwProvFlags = 0; // don't set any flags | 172 wintrust_data.dwProvFlags = 0; // don't set any flags |
131 wintrust_data.dwUIContext = WTD_UICONTEXT_EXECUTE; | 173 wintrust_data.dwUIContext = WTD_UICONTEXT_EXECUTE; |
132 | 174 |
133 // The WINTRUST_ACTION_GENERIC_VERIFY_V2 policy verifies that the certificate | 175 // The WINTRUST_ACTION_GENERIC_VERIFY_V2 policy verifies that the certificate |
134 // chains up to a trusted root CA, and that it has appropriate permission to | 176 // chains up to a trusted root CA, and that it has appropriate permission to |
135 // sign code. | 177 // sign code. |
136 GUID policy_guid = WINTRUST_ACTION_GENERIC_VERIFY_V2; | 178 GUID policy_guid = WINTRUST_ACTION_GENERIC_VERIFY_V2; |
137 | 179 |
138 return (WinVerifyTrust(static_cast<HWND>(INVALID_HANDLE_VALUE), | 180 return (WinVerifyTrust(static_cast<HWND>(INVALID_HANDLE_VALUE), |
139 &policy_guid, | 181 &policy_guid, |
140 &wintrust_data) == ERROR_SUCCESS); | 182 &wintrust_data) == ERROR_SUCCESS); |
141 } | 183 } |
142 } // namespace | 184 } // namespace |
143 | 185 |
144 SignatureUtil::SignatureUtil() {} | 186 SignatureUtil::SignatureUtil() {} |
145 | 187 |
146 SignatureUtil::~SignatureUtil() {} | 188 SignatureUtil::~SignatureUtil() {} |
147 | 189 |
148 void SignatureUtil::CheckSignature( | 190 void SignatureUtil::CheckSignature( |
149 const FilePath& file_path, | 191 const FilePath& file_path, |
150 ClientDownloadRequest_SignatureInfo* signature_info) { | 192 ClientDownloadRequest_SignatureInfo* signature_info) { |
151 GetCertificateContents(file_path, signature_info); | 193 GetCertificateContents(file_path, signature_info); |
152 signature_info->set_trusted(CheckTrust(file_path)); | 194 signature_info->set_trusted(CheckTrust(file_path)); |
153 } | 195 } |
154 | 196 |
155 } // namespace safe_browsing | 197 } // namespace safe_browsing |
OLD | NEW |