Chromium Code Reviews| 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 |