Home | History | Annotate | Download | only in app
      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, &not_valid_before_) > 0) &&
    110             (CompareFileTime(&filetime_now, &not_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