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 <windows.h>
6#include <atlstr.h>
7#include <wincrypt.h>
8#include <wintrust.h>
9
10#include "base/base_paths.h"
11#include "base/basictypes.h"
12#include "base/compiler_specific.h"
13#include "base/files/file_path.h"
14#include "base/files/file_util.h"
15#include "base/logging.h"
16#include "base/path_service.h"
17#include "base/strings/string_number_conversions.h"
18#include "base/strings/string_piece.h"
19#include "base/strings/string_util.h"
20#include "chrome/app/signature_validator_win.h"
21#include "crypto/sha2.h"
22#include "net/cert/test_root_certs.h"
23#include "testing/gtest/include/gtest/gtest.h"
24
25namespace {
26
27const char kGoogleCertIssuer[] = "Google Inc";
28const int CERT_BUFFER_SIZE = 1024;
29
30const base::FilePath::CharType kCertificateRelativePath[] =
31    FILE_PATH_LITERAL("chrome\\app\\test_data\\certificates\\");
32const base::FilePath::CharType kDLLRelativePath[] =
33    FILE_PATH_LITERAL("chrome\\app\\test_data\\dlls\\");
34
35class SignatureValidatorTest : public testing::Test {
36 protected:
37  SignatureValidatorTest() {}
38
39  void SetUp() OVERRIDE {
40    test_roots_ = net::TestRootCerts::GetInstance();
41    base::FilePath cert_path =
42        GetTestCertsDirectory().Append(L"AuthorityCert.cer");
43    base::FilePath other_cert_path =
44        GetTestCertsDirectory().Append(L"OtherAuthorityCert.cer");
45    test_roots_->AddFromFile(cert_path);
46    test_roots_->AddFromFile(other_cert_path);
47    EXPECT_FALSE(test_roots_->IsEmpty());
48
49    SetExpectedHash(GetTestCertsDirectory().Append(L"ValidCert.cer"));
50  }
51
52  void TearDown() OVERRIDE {
53    test_roots_->Clear();
54    EXPECT_TRUE(test_roots_->IsEmpty());
55  }
56
57  base::FilePath GetTestCertsDirectory() {
58    base::FilePath src_root;
59    PathService::Get(base::DIR_SOURCE_ROOT, &src_root);
60    return src_root.Append(kCertificateRelativePath);
61  }
62
63  base::FilePath GetTestDLLsDirectory() {
64    base::FilePath src_root;
65    PathService::Get(base::DIR_SOURCE_ROOT, &src_root);
66    return src_root.Append(kDLLRelativePath);
67  }
68
69  void SetExpectedHash(const base::FilePath& cert_path) {
70    char cert_buffer[CERT_BUFFER_SIZE];
71    base::ReadFile(cert_path, cert_buffer, CERT_BUFFER_SIZE);
72
73    PCCERT_CONTEXT cert = CertCreateCertificateContext(X509_ASN_ENCODING,
74        reinterpret_cast<byte*>(&cert_buffer),
75        CERT_BUFFER_SIZE);
76
77    CRYPT_BIT_BLOB blob = cert->pCertInfo->SubjectPublicKeyInfo.PublicKey;
78    size_t public_key_length = blob.cbData;
79    uint8* public_key = blob.pbData;
80
81    uint8 hash[crypto::kSHA256Length] = {0};
82
83    base::StringPiece key_bytes(reinterpret_cast<char*>(public_key),
84                                public_key_length);
85    crypto::SHA256HashString(key_bytes, hash, crypto::kSHA256Length);
86
87    std::string public_key_hash =
88        base::StringToLowerASCII(base::HexEncode(hash, arraysize(hash)));
89    expected_hashes_.push_back(public_key_hash);
90  }
91
92  void RunTest(const wchar_t* dll_filename, bool isValid, bool isGoogle) {
93    base::FilePath full_dll_path = GetTestDLLsDirectory().Append(dll_filename);
94    ASSERT_EQ(isValid, VerifyAuthenticodeSignature(full_dll_path));
95    ASSERT_EQ(isGoogle, VerifySignerIsGoogle(full_dll_path, kGoogleCertIssuer,
96                                             expected_hashes_));
97  }
98
99 private:
100  net::TestRootCerts* test_roots_;
101  std::vector<std::string> expected_hashes_;
102};
103
104}  // namespace
105
106TEST_F(SignatureValidatorTest, ValidSigTest) {
107  RunTest(L"valid_sig.dll", true, true);
108}
109
110TEST_F(SignatureValidatorTest, SelfSignedTest) {
111  RunTest(L"self_signed.dll", false, false);
112}
113
114TEST_F(SignatureValidatorTest, NotSignedTest) {
115  RunTest(L"not_signed.dll", false, false);
116}
117
118TEST_F(SignatureValidatorTest, NotGoogleTest) {
119  RunTest(L"not_google.dll", true, false);
120}
121
122TEST_F(SignatureValidatorTest, CertPinningTest) {
123  RunTest(L"different_hash.dll", true, false);
124}
125
126TEST_F(SignatureValidatorTest, ExpiredCertTest) {
127  //TODO(caitkp): Figure out how to sign a dll with an expired cert.
128  RunTest(L"expired.dll", false, false);
129}
130
131
132