Chromium Code Reviews| Index: chrome/browser/safe_browsing/signature_util_win.cc |
| diff --git a/chrome/browser/safe_browsing/signature_util_win.cc b/chrome/browser/safe_browsing/signature_util_win.cc |
| index 148e75ac36ff493f7daed5482a6a2904d291f4be..b4758bbb11e76cd9c104f905e49478487712450a 100644 |
| --- a/chrome/browser/safe_browsing/signature_util_win.cc |
| +++ b/chrome/browser/safe_browsing/signature_util_win.cc |
| @@ -6,152 +6,25 @@ |
| #include <windows.h> |
| #include <softpub.h> |
| -#include <wincrypt.h> |
| #include <wintrust.h> |
| #include "base/file_path.h" |
| #include "base/logging.h" |
| -#include "base/scoped_ptr.h" |
| -#include "crypto/scoped_capi_types.h" |
| #include "chrome/common/safe_browsing/csd.pb.h" |
| -#pragma comment(lib, "crypt32.lib") |
| #pragma comment(lib, "wintrust.lib") |
| namespace safe_browsing { |
| -namespace { |
| -using crypto::ScopedCAPIHandle; |
| -using crypto::CAPIDestroyer; |
| -using crypto::CAPIDestroyerWithFlags; |
| -// Free functors for scoped_ptr_malloc. |
| -class FreeConstCertContext { |
| - public: |
| - void operator()(const CERT_CONTEXT* cert_context) const { |
| - if (cert_context) { |
| - CertFreeCertificateContext(cert_context); |
| - } |
| - } |
| -}; |
| +SignatureUtil::SignatureUtil() {} |
| -class FreeConstCertChainContext { |
| - public: |
| - void operator()(const CERT_CHAIN_CONTEXT* cert_chain_context) const { |
| - if (cert_chain_context) { |
| - CertFreeCertificateChain(cert_chain_context); |
| - } |
| - } |
| -}; |
| +SignatureUtil::~SignatureUtil() {} |
| -// Tries to extract the signing certificate from |file_path|. On success, |
| -// the |certificate_contents| field of |signature_info| is populated with the |
| -// DER-encoded X.509 certificate. |
| -void GetCertificateContents( |
| +void SignatureUtil::CheckSignature( |
| const FilePath& file_path, |
| ClientDownloadRequest_SignatureInfo* signature_info) { |
| - // Largely based on http://support.microsoft.com/kb/323809 |
| - // Get message handle and store handle from the signed file. |
| - typedef CAPIDestroyer<HCRYPTMSG, CryptMsgClose> CryptMsgDestroyer; |
| - ScopedCAPIHandle<HCRYPTMSG, CryptMsgDestroyer> crypt_msg; |
| - typedef CAPIDestroyerWithFlags< |
| - HCERTSTORE, CertCloseStore, 0> CertStoreDestroyer; |
| - ScopedCAPIHandle<HCERTSTORE, CertStoreDestroyer> cert_store; |
| - |
| - VLOG(2) << "Looking for signature in: " << file_path.value(); |
| - if (!CryptQueryObject(CERT_QUERY_OBJECT_FILE, |
| - file_path.value().c_str(), |
| - CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED, |
| - CERT_QUERY_FORMAT_FLAG_BINARY, |
| - 0, // flags |
| - NULL, // encoding |
| - NULL, // content type |
| - NULL, // format type |
| - cert_store.receive(), |
| - crypt_msg.receive(), |
| - NULL)) { // context |
| - VLOG(2) << "No signature found."; |
| - return; |
| - } |
| - |
| - // Get the signer information size. |
| - DWORD signer_info_size; |
| - if (!CryptMsgGetParam(crypt_msg.get(), |
| - CMSG_SIGNER_INFO_PARAM, |
| - 0, // index |
| - NULL, // no buffer when checking the size |
| - &signer_info_size)) { |
| - VLOG(2) << "Failed to get signer info size"; |
| - return; |
| - } |
| - |
| - // Get the signer information. |
| - scoped_array<BYTE> signer_info_buffer(new BYTE[signer_info_size]); |
| - CMSG_SIGNER_INFO* signer_info = |
| - reinterpret_cast<CMSG_SIGNER_INFO*>(signer_info_buffer.get()); |
| - if (!CryptMsgGetParam(crypt_msg.get(), |
| - CMSG_SIGNER_INFO_PARAM, |
| - 0, // index |
| - signer_info, |
| - &signer_info_size)) { |
| - VLOG(2) << "Failed to get signer info"; |
| - return; |
| - } |
| - |
| - // Search for the signer certificate in the temporary certificate store. |
| - CERT_INFO cert_info; |
| - cert_info.Issuer = signer_info->Issuer; |
| - cert_info.SerialNumber = signer_info->SerialNumber; |
| - |
| - scoped_ptr_malloc<const CERT_CONTEXT, FreeConstCertContext> cert_context( |
| - CertFindCertificateInStore( |
| - cert_store.get(), |
| - X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, |
| - 0, // flags |
| - CERT_FIND_SUBJECT_CERT, |
| - &cert_info, |
| - NULL)); // no previous context |
| - if (!cert_context.get()) { |
| - VLOG(2) << "Failed to get CERT_CONTEXT"; |
| - return; |
| - } |
| - |
| - // Follow the chain of certificates to a trusted root. |
| - CERT_CHAIN_PARA cert_chain_params; |
| - memset(&cert_chain_params, 0, sizeof(cert_chain_params)); |
| - cert_chain_params.cbSize = sizeof(cert_chain_params); |
| + VLOG(2) << "Checking signature for " << file_path.value(); |
| - const CERT_CHAIN_CONTEXT* cert_chain_context = NULL; |
| - if (!CertGetCertificateChain(NULL, // default chain engine |
| - cert_context.get(), |
| - // TODO(bryner): should this verify at the |
| - // executable's embedded timestamp? |
| - NULL, // verify at the current time |
| - NULL, // no additional store |
| - &cert_chain_params, |
| - 0, // default flags |
| - NULL, // reserved parameter |
| - &cert_chain_context)) { |
| - VLOG(2) << "Failed to get certificate chain."; |
| - return; |
| - } |
| - |
| - typedef scoped_ptr_malloc<const CERT_CHAIN_CONTEXT, |
| - FreeConstCertChainContext> ScopedCertChainContext; |
| - ScopedCertChainContext scoped_cert_chain_context(cert_chain_context); |
| - for (size_t i = 0; i < cert_chain_context->cChain; ++i) { |
| - CERT_SIMPLE_CHAIN* simple_chain = cert_chain_context->rgpChain[i]; |
| - ClientDownloadRequest_CertificateChain* chain = |
| - signature_info->add_certificate_chain(); |
| - for (size_t j = 0; j < simple_chain->cElement; ++j) { |
| - CERT_CHAIN_ELEMENT* element = simple_chain->rgpElement[j]; |
| - chain->add_element()->set_certificate( |
| - element->pCertContext->pbCertEncoded, |
| - element->pCertContext->cbCertEncoded); |
| - } |
| - } |
| -} |
| - |
| -bool CheckTrust(const FilePath& file_path) { |
| WINTRUST_FILE_INFO file_info; |
| file_info.cbStruct = sizeof(file_info); |
| file_info.pcwszFilePath = file_path.value().c_str(); |
| @@ -166,7 +39,7 @@ bool CheckTrust(const FilePath& file_path) { |
| wintrust_data.fdwRevocationChecks = WTD_REVOKE_NONE; |
| wintrust_data.dwUnionChoice = WTD_CHOICE_FILE; |
| wintrust_data.pFile = &file_info; |
| - wintrust_data.dwStateAction = WTD_STATEACTION_IGNORE; |
| + wintrust_data.dwStateAction = WTD_STATEACTION_VERIFY; |
| wintrust_data.hWVTStateData = NULL; |
| wintrust_data.pwszURLReference = NULL; |
| wintrust_data.dwProvFlags = 0; // don't set any flags |
|
Ryan Sleevi
2011/11/15 00:27:12
FWIW, you could also considere adding WTD_CACHE_ON
Brian Ryner
2011/11/15 01:05:37
Done, but I have a question. The docs for this (
Ryan Sleevi
2011/11/15 01:20:02
To be honest, I don't recall, it's been a while si
|
| @@ -177,21 +50,35 @@ bool CheckTrust(const FilePath& file_path) { |
| // sign code. |
| GUID policy_guid = WINTRUST_ACTION_GENERIC_VERIFY_V2; |
| - return (WinVerifyTrust(static_cast<HWND>(INVALID_HANDLE_VALUE), |
| - &policy_guid, |
| - &wintrust_data) == ERROR_SUCCESS); |
| -} |
| -} // namespace |
| - |
| -SignatureUtil::SignatureUtil() {} |
| - |
| -SignatureUtil::~SignatureUtil() {} |
| + signature_info->set_trusted( |
|
noelutz
2011/11/15 00:29:47
Should we not set trusted at all if the file has n
Brian Ryner
2011/11/15 01:05:37
Sure, done.
noelutz
2011/11/15 01:12:43
SGTM
|
| + WinVerifyTrust(static_cast<HWND>(INVALID_HANDLE_VALUE), |
| + &policy_guid, |
| + &wintrust_data) == ERROR_SUCCESS); |
| + |
| + CRYPT_PROVIDER_DATA* prov_data = WTHelperProvDataFromStateData( |
| + wintrust_data.hWVTStateData); |
| + if (prov_data) { |
| + for (size_t i = 0; i < prov_data->csSigners; ++i) { |
|
Ryan Sleevi
2011/11/15 00:27:12
nit: DWORD
Brian Ryner
2011/11/15 01:05:37
Done.
|
| + const CERT_CHAIN_CONTEXT* cert_chain_context = |
| + prov_data->pasSigners[i].pChainContext; |
| + for (size_t j = 0; j < cert_chain_context->cChain; ++j) { |
|
Ryan Sleevi
2011/11/15 00:27:12
nit: DWORD
Brian Ryner
2011/11/15 01:05:37
Done.
|
| + CERT_SIMPLE_CHAIN* simple_chain = cert_chain_context->rgpChain[j]; |
| + ClientDownloadRequest_CertificateChain* chain = |
| + signature_info->add_certificate_chain(); |
| + for (size_t k = 0; k < simple_chain->cElement; ++k) { |
|
Ryan Sleevi
2011/11/15 00:27:12
nit: DWORD
Brian Ryner
2011/11/15 01:05:37
Done.
|
| + CERT_CHAIN_ELEMENT* element = simple_chain->rgpElement[k]; |
| + chain->add_element()->set_certificate( |
| + element->pCertContext->pbCertEncoded, |
| + element->pCertContext->cbCertEncoded); |
| + } |
| + } |
| + } |
| -void SignatureUtil::CheckSignature( |
| - const FilePath& file_path, |
| - ClientDownloadRequest_SignatureInfo* signature_info) { |
| - GetCertificateContents(file_path, signature_info); |
| - signature_info->set_trusted(CheckTrust(file_path)); |
| + // Free the provider data. |
| + wintrust_data.dwStateAction = WTD_STATEACTION_CLOSE; |
| + WinVerifyTrust(static_cast<HWND>(INVALID_HANDLE_VALUE), |
| + &policy_guid, &wintrust_data); |
| + } |
| } |
| } // namespace safe_browsing |