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