1 // Copyright 2013 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/app/signature_validator_win.h" 6 7 #include <atlstr.h> 8 #include <softpub.h> 9 #include <wincrypt.h> 10 #include <windows.h> 11 #include <wintrust.h> 12 13 #include <algorithm> 14 15 #include "base/files/file_path.h" 16 #include "base/strings/string_number_conversions.h" 17 #include "base/strings/string_util.h" 18 #include "base/strings/utf_string_conversions.h" 19 #include "base/time/time.h" 20 #include "base/win/scoped_handle.h" 21 #include "crypto/sha2.h" 22 23 namespace { 24 25 bool ExtractPublicKeyHash(const CERT_CONTEXT* cert_context, 26 std::string* public_key_hash) { 27 public_key_hash->clear(); 28 29 CRYPT_BIT_BLOB crypt_blob = 30 cert_context->pCertInfo->SubjectPublicKeyInfo.PublicKey; 31 32 // Key blobs that are not an integral number of bytes are unsupported. 33 if (crypt_blob.cUnusedBits != 0) 34 return false; 35 36 uint8 hash[crypto::kSHA256Length] = {}; 37 38 base::StringPiece key_bytes(reinterpret_cast<char*>( 39 crypt_blob.pbData), crypt_blob.cbData); 40 crypto::SHA256HashString(key_bytes, hash, crypto::kSHA256Length); 41 42 *public_key_hash = StringToLowerASCII(base::HexEncode(hash, arraysize(hash))); 43 return true; 44 } 45 46 // The traits class for HCERTSTORE handles that can be closed via 47 // CertCloseStore() API. 48 class CertStoreHandleTraits { 49 public: 50 typedef HCERTSTORE Handle; 51 52 // Closes the handle. 53 static bool CloseHandle(HCERTSTORE handle) { 54 return CertCloseStore(handle, 0) != FALSE; 55 } 56 57 // Returns true if the handle value is valid. 58 static bool IsHandleValid(HCERTSTORE handle) { 59 return handle != NULL; 60 } 61 62 // Returns NULL handle value. 63 static HANDLE NullHandle() { 64 return NULL; 65 } 66 67 private: 68 DISALLOW_IMPLICIT_CONSTRUCTORS(CertStoreHandleTraits); 69 }; 70 71 typedef base::win::GenericScopedHandle<CertStoreHandleTraits, 72 base::win::DummyVerifierTraits> ScopedCertStoreHandle; 73 74 // Class: CertInfo 75 // 76 // CertInfo holds all sensible details of a certificate. During verification of 77 // a signature, one CertInfo object is made for each certificate encountered in 78 // the signature. 79 class CertInfo { 80 public: 81 explicit CertInfo(const CERT_CONTEXT* given_cert_context) 82 : cert_context_(NULL) { 83 if (given_cert_context) { 84 // CertDuplicateCertificateContext just increases reference count of a 85 // given CERT_CONTEXT. 86 cert_context_ = CertDuplicateCertificateContext(given_cert_context); 87 not_valid_before_ = cert_context_->pCertInfo->NotBefore; 88 not_valid_after_ = cert_context_->pCertInfo->NotAfter; 89 90 ExtractPublicKeyHash(cert_context_, &public_key_hash_); 91 } 92 } 93 94 ~CertInfo() { // Decrement reference count, if needed. 95 if (cert_context_) { 96 CertFreeCertificateContext(cert_context_); 97 cert_context_ = NULL; 98 } 99 } 100 101 // IsValidNow() functions returns true if this certificate is valid at this 102 // moment, based on the validity period specified in the certificate. 103 bool IsValidNow() const { 104 // we cannot directly get current time in FILETIME format. 105 // so first get it in SYSTEMTIME format and convert it into FILETIME. 106 base::Time now = base::Time::NowFromSystemTime(); 107 FILETIME filetime_now = now.ToFileTime(); 108 // CompareFileTime() is a windows function 109 return ((CompareFileTime(&filetime_now, ¬_valid_before_) > 0) && 110 (CompareFileTime(&filetime_now, ¬_valid_after_) < 0)); 111 } 112 113 std::string public_key_hash() const { 114 return public_key_hash_; 115 } 116 117 private: 118 // cert_context structure, defined by Crypto API, contains all the info 119 // about the certificate. 120 const CERT_CONTEXT* cert_context_; 121 122 // Lower-case hex SHA-256 hash of the certificate subject's public key. 123 std::string public_key_hash_; 124 125 // Validity period start-date 126 FILETIME not_valid_before_; 127 128 // Validity period end-date 129 FILETIME not_valid_after_; 130 }; 131 132 } // namespace 133 134 bool VerifyAuthenticodeSignature(const base::FilePath& signed_file) { 135 // Don't pop up any windows 136 const HWND window_mode = reinterpret_cast<HWND>(INVALID_HANDLE_VALUE); 137 138 // Verify file & certificates using the Microsoft Authenticode Policy 139 // Provider. 140 GUID verification_type = WINTRUST_ACTION_GENERIC_VERIFY_V2; 141 142 // Info for the file we're going to verify. 143 WINTRUST_FILE_INFO file_info = {}; 144 file_info.cbStruct = sizeof(file_info); 145 file_info.pcwszFilePath = signed_file.value().c_str(); 146 147 // Info for request to WinVerifyTrust. 148 WINTRUST_DATA trust_data = {}; 149 trust_data.cbStruct = sizeof(trust_data); 150 trust_data.dwUIChoice = WTD_UI_NONE; // no graphics 151 trust_data.fdwRevocationChecks = WTD_REVOKE_NONE; // no revocation checking 152 trust_data.dwUnionChoice = WTD_CHOICE_FILE; // check a file 153 trust_data.pFile = &file_info; // check this file 154 trust_data.dwProvFlags = WTD_REVOCATION_CHECK_NONE; 155 156 // From the WinVerifyTrust documentation: 157 // http://msdn2.microsoft.com/en-us/library/aa388208.aspx: 158 // "If the trust provider verifies that the subject is trusted 159 // for the specified action, the return value is zero. No other 160 // value besides zero should be considered a successful return." 161 LONG result = WinVerifyTrust(window_mode, &verification_type, &trust_data); 162 return !result; 163 } 164 165 bool VerifySignerIsGoogle(const base::FilePath& signed_file, 166 const std::string& subject_name, 167 const std::vector<std::string>& expected_hashes) { 168 if (signed_file.empty()) 169 return false; 170 171 // If successful, cert_store will be populated by a store containing all the 172 // certificates related to the file signature. 173 HCERTSTORE cert_store = NULL; 174 175 BOOL succeeded = CryptQueryObject( 176 CERT_QUERY_OBJECT_FILE, 177 signed_file.value().c_str(), 178 CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED, 179 CERT_QUERY_FORMAT_FLAG_ALL, 180 0, // Reserved: must be 0. 181 NULL, 182 NULL, 183 NULL, 184 &cert_store, 185 NULL, // Do not return the message. 186 NULL); // Do not return additional context. 187 188 ScopedCertStoreHandle scoped_cert_store(cert_store); 189 190 if (!succeeded || !scoped_cert_store.IsValid()) 191 return false; 192 193 PCCERT_CONTEXT cert_context_ptr = NULL; 194 cert_context_ptr = CertFindCertificateInStore( 195 cert_store, 196 X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 197 0, 198 CERT_FIND_SUBJECT_STR, 199 base::UTF8ToWide(subject_name).c_str(), 200 cert_context_ptr); 201 202 // No cert found with this subject, so stop here. 203 if (!cert_context_ptr) 204 return false; 205 206 CertInfo cert_info(cert_context_ptr); 207 208 CertFreeCertificateContext(cert_context_ptr); 209 cert_context_ptr = NULL; 210 211 // Check the hashes to make sure subject isn't being faked, and the time 212 // to make sure the cert is current. 213 std::vector<std::string>::const_iterator it = std::find( 214 expected_hashes.begin(), 215 expected_hashes.end(), 216 cert_info.public_key_hash()); 217 if (it == expected_hashes.end() || !cert_info.IsValidNow()) 218 return false; 219 220 return true; 221 } 222