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
);
42 *public_key_hash
= base::ToLowerASCII(base::HexEncode(hash
, arraysize(hash
)));
46 // The traits class for HCERTSTORE handles that can be closed via
47 // CertCloseStore() API.
48 class CertStoreHandleTraits
{
50 typedef HCERTSTORE Handle
;
53 static bool CloseHandle(HCERTSTORE handle
) {
54 return CertCloseStore(handle
, 0) != FALSE
;
57 // Returns true if the handle value is valid.
58 static bool IsHandleValid(HCERTSTORE handle
) {
59 return handle
!= NULL
;
62 // Returns NULL handle value.
63 static HANDLE
NullHandle() {
68 DISALLOW_IMPLICIT_CONSTRUCTORS(CertStoreHandleTraits
);
71 typedef base::win::GenericScopedHandle
<CertStoreHandleTraits
,
72 base::win::DummyVerifierTraits
> ScopedCertStoreHandle
;
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
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
;
90 ExtractPublicKeyHash(cert_context_
, &public_key_hash_
);
94 ~CertInfo() { // Decrement reference count, if needed.
96 CertFreeCertificateContext(cert_context_
);
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));
113 std::string
public_key_hash() const {
114 return public_key_hash_
;
118 // cert_context structure, defined by Crypto API, contains all the info
119 // about the certificate.
120 const CERT_CONTEXT
* cert_context_
;
122 // Lower-case hex SHA-256 hash of the certificate subject's public key.
123 std::string public_key_hash_
;
125 // Validity period start-date
126 FILETIME not_valid_before_
;
128 // Validity period end-date
129 FILETIME not_valid_after_
;
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
);
138 // Verify file & certificates using the Microsoft Authenticode Policy
140 GUID verification_type
= WINTRUST_ACTION_GENERIC_VERIFY_V2
;
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();
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
;
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
);
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())
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
;
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.
185 NULL
, // Do not return the message.
186 NULL
); // Do not return additional context.
188 ScopedCertStoreHandle
scoped_cert_store(cert_store
);
190 if (!succeeded
|| !scoped_cert_store
.IsValid())
193 PCCERT_CONTEXT cert_context_ptr
= NULL
;
194 cert_context_ptr
= CertFindCertificateInStore(
196 X509_ASN_ENCODING
| PKCS_7_ASN_ENCODING
,
198 CERT_FIND_SUBJECT_STR
,
199 base::UTF8ToWide(subject_name
).c_str(),
202 // No cert found with this subject, so stop here.
203 if (!cert_context_ptr
)
206 CertInfo
cert_info(cert_context_ptr
);
208 CertFreeCertificateContext(cert_context_ptr
);
209 cert_context_ptr
= NULL
;
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())