1// Copyright 2014 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 <string>
6#include <vector>
7
8#include "base/base64.h"
9#include "base/files/file_path.h"
10#include "base/files/file_util.h"
11#include "base/path_service.h"
12#include "base/stl_util.h"
13#include "extensions/browser/verified_contents.h"
14#include "extensions/common/extension.h"
15#include "extensions/common/extension_paths.h"
16#include "testing/gtest/include/gtest/gtest.h"
17
18namespace extensions {
19
20namespace {
21
22std::string DecodeBase64Url(const std::string& encoded) {
23  std::string fixed_up_base64 = encoded;
24  if (!VerifiedContents::FixupBase64Encoding(&fixed_up_base64))
25    return std::string();
26  std::string decoded;
27  if (!base::Base64Decode(fixed_up_base64, &decoded))
28    return std::string();
29  return decoded;
30}
31
32bool GetPublicKey(const base::FilePath& path, std::string* public_key) {
33  std::string public_key_pem;
34  if (!base::ReadFileToString(path, &public_key_pem))
35    return false;
36  if (!Extension::ParsePEMKeyBytes(public_key_pem, public_key))
37    return false;
38  return true;
39}
40
41}  // namespace
42
43TEST(VerifiedContents, Simple) {
44  // Figure out our test data directory.
45  base::FilePath path;
46  PathService::Get(DIR_TEST_DATA, &path);
47  path = path.AppendASCII("content_verifier/");
48
49  // Initialize the VerifiedContents object.
50  std::string public_key;
51  ASSERT_TRUE(GetPublicKey(path.AppendASCII("public_key.pem"), &public_key));
52  VerifiedContents contents(reinterpret_cast<const uint8*>(public_key.data()),
53                            public_key.size());
54  base::FilePath verified_contents_path =
55      path.AppendASCII("verified_contents.json");
56
57  ASSERT_TRUE(contents.InitFrom(verified_contents_path, false));
58
59  // Make sure we get expected values.
60  EXPECT_EQ(contents.block_size(), 4096);
61  EXPECT_EQ(contents.extension_id(), "abcdefghijklmnopabcdefghijklmnop");
62  EXPECT_EQ("1.2.3", contents.version().GetString());
63
64  EXPECT_TRUE(contents.TreeHashRootEquals(
65      base::FilePath::FromUTF8Unsafe("manifest.json"),
66      DecodeBase64Url("-vyyIIn7iSCzg7X3ICUI5wZa3tG7w7vyiCckxZdJGfs")));
67
68  EXPECT_TRUE(contents.TreeHashRootEquals(
69      base::FilePath::FromUTF8Unsafe("background.js"),
70      DecodeBase64Url("txHiG5KQvNoPOSH5FbQo9Zb5gJ23j3oFB0Ru9DOnziw")));
71
72  base::FilePath foo_bar_html =
73      base::FilePath(FILE_PATH_LITERAL("foo")).AppendASCII("bar.html");
74  EXPECT_FALSE(foo_bar_html.IsAbsolute());
75  EXPECT_TRUE(contents.TreeHashRootEquals(
76      foo_bar_html,
77      DecodeBase64Url("L37LFbT_hmtxRL7AfGZN9YTpW6yoz_ZiQ1opLJn1NZU")));
78
79  base::FilePath nonexistent = base::FilePath::FromUTF8Unsafe("nonexistent");
80  EXPECT_FALSE(contents.HasTreeHashRoot(nonexistent));
81
82  EXPECT_TRUE(contents.TreeHashRootEquals(
83      base::FilePath::FromUTF8Unsafe("lowercase.html"),
84      DecodeBase64Url("HpLotLGCmmOdKYvGQmD3OkXMKGs458dbanY4WcfAZI0")));
85  EXPECT_TRUE(contents.TreeHashRootEquals(
86      base::FilePath::FromUTF8Unsafe("Lowercase.Html"),
87      DecodeBase64Url("HpLotLGCmmOdKYvGQmD3OkXMKGs458dbanY4WcfAZI0")));
88  EXPECT_TRUE(contents.TreeHashRootEquals(
89      base::FilePath::FromUTF8Unsafe("LOWERCASE.HTML"),
90      DecodeBase64Url("HpLotLGCmmOdKYvGQmD3OkXMKGs458dbanY4WcfAZI0")));
91
92  EXPECT_TRUE(contents.TreeHashRootEquals(
93      base::FilePath::FromUTF8Unsafe("ALLCAPS.HTML"),
94      DecodeBase64Url("bl-eV8ENowvtw6P14D4X1EP0mlcMoG-_aOx5o9C1364")));
95  EXPECT_TRUE(contents.TreeHashRootEquals(
96      base::FilePath::FromUTF8Unsafe("AllCaps.Html"),
97      DecodeBase64Url("bl-eV8ENowvtw6P14D4X1EP0mlcMoG-_aOx5o9C1364")));
98  EXPECT_TRUE(contents.TreeHashRootEquals(
99      base::FilePath::FromUTF8Unsafe("allcaps.html"),
100      DecodeBase64Url("bl-eV8ENowvtw6P14D4X1EP0mlcMoG-_aOx5o9C1364")));
101
102  EXPECT_TRUE(contents.TreeHashRootEquals(
103      base::FilePath::FromUTF8Unsafe("MixedCase.Html"),
104      DecodeBase64Url("zEAO9FwciigMNy3NtU2XNb-dS5TQMmVNx0T9h7WvXbQ")));
105  EXPECT_TRUE(contents.TreeHashRootEquals(
106      base::FilePath::FromUTF8Unsafe("MIXEDCASE.HTML"),
107      DecodeBase64Url("zEAO9FwciigMNy3NtU2XNb-dS5TQMmVNx0T9h7WvXbQ")));
108  EXPECT_TRUE(contents.TreeHashRootEquals(
109      base::FilePath::FromUTF8Unsafe("mixedcase.html"),
110      DecodeBase64Url("zEAO9FwciigMNy3NtU2XNb-dS5TQMmVNx0T9h7WvXbQ")));
111  EXPECT_TRUE(contents.TreeHashRootEquals(
112      base::FilePath::FromUTF8Unsafe("mIxedcAse.Html"),
113      DecodeBase64Url("zEAO9FwciigMNy3NtU2XNb-dS5TQMmVNx0T9h7WvXbQ")));
114
115  EXPECT_TRUE(contents.TreeHashRootEquals(
116      base::FilePath::FromUTF8Unsafe("mIxedcAse.Html"),
117      DecodeBase64Url("nKRqUcJg1_QZWAeCb4uFd5ouC0McuGavKp8TFDRqBgg")));
118  EXPECT_TRUE(contents.TreeHashRootEquals(
119      base::FilePath::FromUTF8Unsafe("MIXEDCASE.HTML"),
120      DecodeBase64Url("nKRqUcJg1_QZWAeCb4uFd5ouC0McuGavKp8TFDRqBgg")));
121  EXPECT_TRUE(contents.TreeHashRootEquals(
122      base::FilePath::FromUTF8Unsafe("mixedcase.html"),
123      DecodeBase64Url("nKRqUcJg1_QZWAeCb4uFd5ouC0McuGavKp8TFDRqBgg")));
124  EXPECT_TRUE(contents.TreeHashRootEquals(
125      base::FilePath::FromUTF8Unsafe("MixedCase.Html"),
126      DecodeBase64Url("nKRqUcJg1_QZWAeCb4uFd5ouC0McuGavKp8TFDRqBgg")));
127}
128
129}  // namespace extensions
130