Index: base/signaturevalidator.cc |
diff --git a/base/signaturevalidator.cc b/base/signaturevalidator.cc |
deleted file mode 100644 |
index c845e34048d65992294ed397c12610944b39d9d0..0000000000000000000000000000000000000000 |
--- a/base/signaturevalidator.cc |
+++ /dev/null |
@@ -1,521 +0,0 @@ |
-// Copyright 2002-2009 Google Inc. |
-// |
-// Licensed under the Apache License, Version 2.0 (the "License"); |
-// you may not use this file except in compliance with the License. |
-// You may obtain a copy of the License at |
-// |
-// http://www.apache.org/licenses/LICENSE-2.0 |
-// |
-// Unless required by applicable law or agreed to in writing, software |
-// distributed under the License is distributed on an "AS IS" BASIS, |
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
-// See the License for the specific language governing permissions and |
-// limitations under the License. |
-// ======================================================================== |
- |
- |
-#include "omaha/base/signaturevalidator.h" |
- |
-#include <atltime.h> |
-#include <softpub.h> |
-#include <wincrypt.h> |
-#include <wintrust.h> |
-#pragma warning(push) |
-// C4100: unreferenced formal parameter |
-// C4310: cast truncates constant value |
-// C4548: expression before comma has no effect |
-#pragma warning(disable : 4100 4310 4548) |
-#include "base/basictypes.h" |
-#pragma warning(pop) |
-#include "omaha/base/constants.h" |
-#include "omaha/base/error.h" |
- |
-namespace omaha { |
- |
-namespace { |
- |
-const LPCTSTR kEmptyStr = _T(""); |
-const DWORD kCertificateEncoding = X509_ASN_ENCODING | PKCS_7_ASN_ENCODING; |
- |
-// Gets a handle to the certificate store and optionally the cryptographic |
-// message from the specified file. |
-// The caller is responsible for closing the store and message. |
-// message can be NULL if the handle is not needed. |
-HRESULT GetCertStoreFromFile(const wchar_t* signed_file, |
- HCERTSTORE* cert_store, |
- HCRYPTMSG* message) { |
- if (!signed_file || !cert_store) { |
- return E_INVALIDARG; |
- } |
- |
- // Get message handle and store handle from the signed file. |
- if (!::CryptQueryObject(CERT_QUERY_OBJECT_FILE, |
- signed_file, |
- CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED, |
- CERT_QUERY_FORMAT_FLAG_BINARY, |
- 0, // reserved, must be 0 |
- NULL, // pdwMsgAndCertEncodingType |
- NULL, // pdwContentType |
- NULL, // pdwFormatType |
- cert_store, |
- message, |
- NULL)) { // ppvContext |
- return HRESULT_FROM_WIN32(::GetLastError()); |
- } |
- |
- return S_OK; |
-} |
- |
-// Gets the signer info from the crypt message. |
-// The caller is responsible for freeing the signer info using LocalFree. |
-HRESULT GetSignerInfo(HCRYPTMSG message, PCMSG_SIGNER_INFO* signer_info) { |
- if (!signer_info) { |
- return E_INVALIDARG; |
- } |
- *signer_info = NULL; |
- |
- DWORD info_size = 0; |
- if (!::CryptMsgGetParam(message, |
- CMSG_SIGNER_INFO_PARAM, |
- 0, |
- NULL, |
- &info_size)) { |
- return HRESULT_FROM_WIN32(::GetLastError()); |
- } |
- |
- *signer_info = static_cast<PCMSG_SIGNER_INFO>(::LocalAlloc(LPTR, info_size)); |
- if (!*signer_info) { |
- return HRESULT_FROM_WIN32(::GetLastError()); |
- } |
- |
- if (!::CryptMsgGetParam(message, |
- CMSG_SIGNER_INFO_PARAM, |
- 0, |
- *signer_info, |
- &info_size)) { |
- return HRESULT_FROM_WIN32(::GetLastError()); |
- } |
- |
- return S_OK; |
-} |
- |
-// Gets the signer info for the time stamp signature in the specified signature. |
-HRESULT GetTimeStampSignerInfo(PCMSG_SIGNER_INFO signer_info, |
- PCMSG_SIGNER_INFO* countersigner_info) { |
- if (!signer_info || !countersigner_info) { |
- return E_INVALIDARG; |
- } |
- *countersigner_info = NULL; |
- |
- PCRYPT_ATTRIBUTE attr = NULL; |
- |
- // The countersigner info is contained in the unauthenticated attributes and |
- // indicated by the szOID_RSA_counterSign OID. |
- for (size_t i = 0; i < signer_info->UnauthAttrs.cAttr; ++i) { |
- if (lstrcmpA(szOID_RSA_counterSign, |
- signer_info->UnauthAttrs.rgAttr[i].pszObjId) == 0) { |
- attr = &signer_info->UnauthAttrs.rgAttr[i]; |
- break; |
- } |
- } |
- |
- if (!attr) { |
- return E_FAIL; |
- } |
- |
- // Decode and get CMSG_SIGNER_INFO structure for the timestamp certificate. |
- DWORD data_size = 0; |
- if (!::CryptDecodeObject(kCertificateEncoding, |
- PKCS7_SIGNER_INFO, |
- attr->rgValue[0].pbData, |
- attr->rgValue[0].cbData, |
- 0, |
- NULL, |
- &data_size)) { |
- return HRESULT_FROM_WIN32(::GetLastError()); |
- } |
- |
- *countersigner_info = |
- static_cast<PCMSG_SIGNER_INFO>(::LocalAlloc(LPTR, data_size)); |
- if (!*countersigner_info) { |
- return HRESULT_FROM_WIN32(::GetLastError()); |
- } |
- |
- if (!::CryptDecodeObject(kCertificateEncoding, |
- PKCS7_SIGNER_INFO, |
- attr->rgValue[0].pbData, |
- attr->rgValue[0].cbData, |
- 0, |
- *countersigner_info, |
- &data_size)) { |
- return HRESULT_FROM_WIN32(::GetLastError()); |
- } |
- |
- return S_OK; |
-} |
- |
-// Gets the time of the date stamp for the specified signature. |
-// The time is in UTC. |
-HRESULT GetDateOfTimeStamp(PCMSG_SIGNER_INFO signer_info, |
- SYSTEMTIME* system_time) { |
- if (!signer_info || !system_time) { |
- return E_INVALIDARG; |
- } |
- |
- PCRYPT_ATTRIBUTE attr = NULL; |
- |
- // The signing time is contained in the authenticated attributes and |
- // indicated by the szOID_RSA_signingTime OID. |
- for (size_t i = 0; i < signer_info->AuthAttrs.cAttr; ++i) { |
- if (lstrcmpA(szOID_RSA_signingTime, |
- signer_info->AuthAttrs.rgAttr[i].pszObjId) == 0) { |
- attr = &signer_info->AuthAttrs.rgAttr[i]; |
- break; |
- } |
- } |
- |
- if (!attr) { |
- return E_FAIL; |
- } |
- |
- FILETIME file_time = {0}; |
- |
- // Decode and get FILETIME structure. |
- DWORD data_size = sizeof(file_time); |
- if (!::CryptDecodeObject(kCertificateEncoding, |
- szOID_RSA_signingTime, |
- attr->rgValue[0].pbData, |
- attr->rgValue[0].cbData, |
- 0, |
- &file_time, |
- &data_size)) { |
- return HRESULT_FROM_WIN32(::GetLastError()); |
- } |
- |
- if (!::FileTimeToSystemTime(&file_time, system_time)) { |
- return HRESULT_FROM_WIN32(::GetLastError()); |
- } |
- |
- return S_OK; |
-} |
- |
-} // namespace |
- |
-CertInfo::CertInfo(const CERT_CONTEXT* given_cert_context) |
- : cert_context_(NULL) { |
- if (given_cert_context) { |
- // CertDuplicateCertificateContext just increases reference count of a given |
- // CERT_CONTEXT. |
- cert_context_ = CertDuplicateCertificateContext(given_cert_context); |
- not_valid_before_ = cert_context_->pCertInfo->NotBefore; |
- not_valid_after_ = cert_context_->pCertInfo->NotAfter; |
- // Extract signed party details. |
- ExtractIssuerInfo(cert_context_, |
- &issuing_company_name_, |
- &issuing_dept_name_, |
- &trust_authority_name_); |
- } |
-} |
- |
-CertInfo::~CertInfo() { |
- // Decrement reference count, if needed. |
- if (cert_context_) |
- CertFreeCertificateContext(cert_context_); |
-} |
- |
- |
-bool CertInfo::IsValidNow() const { |
- // we cannot directly get current time in FILETIME format. |
- // so first get it in SYSTEMTIME format and convert it into FILETIME. |
- SYSTEMTIME now; |
- GetSystemTime(&now); |
- FILETIME filetime_now; |
- SystemTimeToFileTime(&now, &filetime_now); |
- // CompareFileTime() is a windows function |
- return ((CompareFileTime(&filetime_now, ¬_valid_before_) > 0) |
- && (CompareFileTime(&filetime_now, ¬_valid_after_) < 0)); |
-} |
- |
- |
-CString CertInfo::FileTimeToString(const FILETIME* ft) { |
- if (ft == NULL) |
- return _T(""); |
- SYSTEMTIME st; |
- if (!FileTimeToSystemTime(ft, &st)) |
- return _T(""); |
- |
- // Build a string showing the date and time. |
- CString time_str; |
- time_str.Format(_T("%02d/%02d/%d %02d:%02d"), st.wDay, st.wMonth, st.wYear, |
- st.wHour, st.wMinute); |
- return time_str; |
-} |
- |
- |
-bool CertInfo::ExtractField(const CERT_CONTEXT* cert_context, |
- const char* field_name, |
- CString* field_value) { |
- if ((!cert_context) || (!field_name) || (!field_value)) { |
- return false; |
- } |
- |
- field_value->Empty(); |
- |
- DWORD num_chars = ::CertGetNameString(cert_context, |
- CERT_NAME_ATTR_TYPE, |
- 0, |
- const_cast<char*>(field_name), |
- NULL, |
- 0); |
- if (num_chars > 1) { |
- num_chars = ::CertGetNameString(cert_context, |
- CERT_NAME_ATTR_TYPE, |
- 0, |
- const_cast<char*>(field_name), |
- CStrBuf(*field_value, num_chars), |
- num_chars); |
- } |
- |
- return num_chars > 1 ? true : false; |
-} |
- |
- |
-bool CertInfo::ExtractIssuerInfo(const CERT_CONTEXT* cert_context, |
- CString* orgn_name, |
- CString* orgn_dept_name, |
- CString* trust_authority) { |
- // trust-authority is optional, so no check. |
- if ((!orgn_name) || (!orgn_dept_name)) { |
- return false; |
- } |
- |
- ExtractField(cert_context, szOID_COMMON_NAME, orgn_name); |
- ExtractField(cert_context, szOID_ORGANIZATIONAL_UNIT_NAME, orgn_dept_name); |
- if (trust_authority != NULL) { |
- ExtractField(cert_context, szOID_ORGANIZATION_NAME, trust_authority); |
- } |
- |
- return true; |
-} |
- |
- |
-void CertList::FindFirstCert(CertInfo** result_cert_info, |
- const CString &company_name_to_match, |
- const CString &orgn_unit_to_match, |
- const CString &trust_authority_to_match, |
- bool allow_test_variant, |
- bool check_cert_is_valid_now) { |
- if (!result_cert_info) |
- return; |
- (*result_cert_info) = NULL; |
- |
- for (CertInfoList::const_iterator cert_iter = cert_list_.begin(); |
- cert_iter != cert_list_.end(); |
- ++cert_iter) { |
- // If any of the criteria does not match, continue on to next certificate |
- if (!company_name_to_match.IsEmpty()) { |
- const TCHAR* certificate_company_name = |
- (*cert_iter)->issuing_company_name_; |
- bool names_match = company_name_to_match == certificate_company_name; |
- if (!names_match && allow_test_variant) { |
- CString test_variant = company_name_to_match; |
- test_variant += _T(" (TEST)"); |
- names_match = test_variant == certificate_company_name; |
- } |
- if (!names_match) |
- continue; |
- } |
- if (!orgn_unit_to_match.IsEmpty() && |
- orgn_unit_to_match != (*cert_iter)->issuing_dept_name_) |
- continue; |
- if (!trust_authority_to_match.IsEmpty() && |
- trust_authority_to_match != (*cert_iter)->trust_authority_name_) |
- continue; |
- // All the criteria matched. But, add only if it is a valid certificate. |
- if (!check_cert_is_valid_now || (*cert_iter)->IsValidNow()) { |
- (*result_cert_info) = (*cert_iter); |
- return; |
- } |
- } |
-} |
- |
- |
-void ExtractAllCertificatesFromSignature(const wchar_t* signed_file, |
- CertList* cert_list) { |
- if ((!signed_file) || (!cert_list)) |
- return; |
- |
- DWORD encoding_type = 0, content_type = 0, format_type = 0; |
- // If successful, cert_store will be populated by |
- // a store containing all the certificates related to the file signature. |
- HCERTSTORE cert_store = NULL; |
- BOOL succeeded = CryptQueryObject(CERT_QUERY_OBJECT_FILE, |
- signed_file, |
- CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED, |
- CERT_QUERY_FORMAT_FLAG_ALL, |
- 0, // has to be zero as documentation says |
- &encoding_type, // DWORD *pdwMsgAndCertEncodingType, |
- &content_type, // DWORD *pdwContentType, |
- &format_type, // DWORD *pdwFormatType, |
- &cert_store, // HCERTSTORE *phCertStore, |
- NULL, // HCRYPTMSG *phMsg, |
- NULL); // const void** pvContext |
- |
- if (succeeded && (cert_store != NULL)) { |
- PCCERT_CONTEXT cert_context_ptr = NULL; |
- while ((cert_context_ptr = |
- CertEnumCertificatesInStore(cert_store, cert_context_ptr)) |
- != NULL) { |
- CertInfo* cert_info = new CertInfo(cert_context_ptr); |
- cert_list->AddCertificate(cert_info); |
- } |
- } |
- if (cert_store) { |
- CertCloseStore(cert_store, 0); |
- } |
- return; |
-} |
- |
-// Only check the CN. The OU can change. |
-// TODO(omaha): A better way to implement the valid now check would be to add |
-// a parameter to VerifySignature that adds WTD_LIFETIME_SIGNING_FLAG. |
-bool VerifySigneeIsGoogleInternal(const wchar_t* signed_file, |
- bool check_cert_is_valid_now) { |
- CertList cert_list; |
- ExtractAllCertificatesFromSignature(signed_file, &cert_list); |
- if (cert_list.size() > 0) { |
- CertInfo* required_cert = NULL; |
- // now, see if one of the certificates in the signature belongs to Google. |
- cert_list.FindFirstCert(&required_cert, |
- kCertificateSubjectName, |
- CString(), |
- CString(), |
- true, |
- check_cert_is_valid_now); |
- if (required_cert != NULL) { |
- return true; |
- } |
- } |
- return false; |
-} |
- |
-// Does not verify that the certificate is currently valid. |
-// VerifySignature verifies that the certificate was valid at signing time as |
-// part of the normal signature verification. |
-bool VerifySigneeIsGoogle(const wchar_t* signed_file) { |
- return VerifySigneeIsGoogleInternal(signed_file, false); |
-} |
- |
-HRESULT VerifySignature(const wchar_t* signed_file, bool allow_network_check) { |
- // Don't pop up any windows |
- HWND const kWindowMode = reinterpret_cast<HWND>(INVALID_HANDLE_VALUE); |
- |
- // Verify file & certificates |
- GUID verification_type = WINTRUST_ACTION_GENERIC_VERIFY_V2; |
- |
- // Info for the file we're going to verify |
- WINTRUST_FILE_INFO file_info = {0}; |
- file_info.cbStruct = sizeof(file_info); |
- file_info.pcwszFilePath = signed_file; |
- |
- // Info for request to WinVerifyTrust |
- WINTRUST_DATA trust_data; |
- ZeroMemory(&trust_data, sizeof(trust_data)); |
- trust_data.cbStruct = sizeof(trust_data); |
- trust_data.dwUIChoice = WTD_UI_NONE; // no graphics |
- // No additional revocation checking -- note that this flag does not |
- // cancel the flag we set in dwProvFlags; it specifies that no -additional- |
- // checks are to be performed beyond the provider-specified ones. |
- trust_data.fdwRevocationChecks = WTD_REVOKE_NONE; |
- trust_data.dwProvFlags = WTD_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT; |
- |
- if (!allow_network_check) |
- trust_data.dwProvFlags |= WTD_CACHE_ONLY_URL_RETRIEVAL; |
- |
- trust_data.dwUnionChoice = WTD_CHOICE_FILE; // check a file |
- trust_data.pFile = &file_info; // check this file |
- |
- // If the trust provider verifies that the subject is trusted for the |
- // specified action, the return value is zero. No other value besides zero |
- // should be considered a successful return. |
- LONG result = ::WinVerifyTrust(kWindowMode, &verification_type, &trust_data); |
- if (result != 0) { |
- return FAILED(result) ? result : HRESULT_FROM_WIN32(result); |
- } |
- return S_OK; |
-} |
- |
-// This method must not return until the end to avoid leaking memory. |
-// More info on Authenticode Signatures Time Stamping can be found at |
-// http://msdn2.microsoft.com/en-us/library/bb931395.aspx. |
-HRESULT GetSigningTime(const wchar_t* signed_file, SYSTEMTIME* signing_time) { |
- if (!signed_file || !signing_time) { |
- return E_INVALIDARG; |
- } |
- |
- HCERTSTORE cert_store = NULL; |
- HCRYPTMSG message = NULL; |
- PCMSG_SIGNER_INFO signer_info = NULL; |
- PCMSG_SIGNER_INFO countersigner_info = NULL; |
- |
- HRESULT hr = GetCertStoreFromFile(signed_file, &cert_store, &message); |
- |
- if (SUCCEEDED(hr)) { |
- hr = GetSignerInfo(message, &signer_info); |
- } |
- |
- if (SUCCEEDED(hr)) { |
- hr = GetTimeStampSignerInfo(signer_info, &countersigner_info); |
- } |
- |
- if (SUCCEEDED(hr)) { |
- hr = GetDateOfTimeStamp(countersigner_info, signing_time); |
- } |
- |
- if (cert_store) { |
- ::CertCloseStore(cert_store, 0); |
- } |
- if (message) { |
- ::CryptMsgClose(message); |
- } |
- ::LocalFree(signer_info); |
- ::LocalFree(countersigner_info); |
- |
- return hr; |
-} |
- |
-HRESULT VerifyFileSignedWithinDays(const wchar_t* signed_file, int days) { |
- if (!signed_file || days <= 0) { |
- return E_INVALIDARG; |
- } |
- |
- SYSTEMTIME signing_time = {0}; |
- HRESULT hr = GetSigningTime(signed_file, &signing_time); |
- if (FAILED(hr)) { |
- return hr; |
- } |
- |
- // Use the Win32 API instead of CTime::GetCurrentTime() because the latter |
- // is broken in VS 2003 and 2005 and doesn't account for the timezone. |
- SYSTEMTIME current_system_time = {0}; |
- ::GetSystemTime(¤t_system_time); |
- |
- CTime signed_time(signing_time); |
- CTime current_time(current_system_time); |
- |
- if (current_time <= signed_time) { |
- return TRUST_E_TIME_STAMP; |
- } |
- |
- CTimeSpan time_since_signed = current_time - signed_time; |
- CTimeSpan max_duration(days, 0, 0, 0); |
- |
- if (max_duration < time_since_signed) { |
- return TRUST_E_TIME_STAMP; |
- } |
- |
- return S_OK; |
-} |
- |
-} // namespace omaha |
- |