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 "extensions/browser/content_hash_reader.h"
6
7#include "base/base64.h"
8#include "base/file_util.h"
9#include "base/json/json_reader.h"
10#include "base/strings/string_util.h"
11#include "base/values.h"
12#include "crypto/sha2.h"
13#include "extensions/browser/computed_hashes.h"
14#include "extensions/browser/content_hash_tree.h"
15#include "extensions/browser/verified_contents.h"
16#include "extensions/common/extension.h"
17#include "extensions/common/file_util.h"
18
19using base::DictionaryValue;
20using base::ListValue;
21using base::Value;
22
23namespace extensions {
24
25ContentHashReader::ContentHashReader(const std::string& extension_id,
26                                     const base::Version& extension_version,
27                                     const base::FilePath& extension_root,
28                                     const base::FilePath& relative_path,
29                                     const ContentVerifierKey& key)
30    : extension_id_(extension_id),
31      extension_version_(extension_version.GetString()),
32      extension_root_(extension_root),
33      relative_path_(relative_path),
34      key_(key),
35      status_(NOT_INITIALIZED),
36      have_verified_contents_(false),
37      have_computed_hashes_(false),
38      block_size_(0) {
39}
40
41ContentHashReader::~ContentHashReader() {
42}
43
44bool ContentHashReader::Init() {
45  DCHECK_EQ(status_, NOT_INITIALIZED);
46  status_ = FAILURE;
47  base::FilePath verified_contents_path =
48      file_util::GetVerifiedContentsPath(extension_root_);
49
50  if (!base::PathExists(verified_contents_path))
51    return false;
52
53  verified_contents_.reset(new VerifiedContents(key_.data, key_.size));
54  if (!verified_contents_->InitFrom(verified_contents_path, false) ||
55      !verified_contents_->valid_signature() ||
56      !verified_contents_->version().Equals(extension_version_) ||
57      verified_contents_->extension_id() != extension_id_)
58    return false;
59
60  have_verified_contents_ = true;
61
62  base::FilePath computed_hashes_path =
63      file_util::GetComputedHashesPath(extension_root_);
64  if (!base::PathExists(computed_hashes_path))
65    return false;
66
67  ComputedHashes::Reader reader;
68  if (!reader.InitFromFile(computed_hashes_path))
69    return false;
70
71  have_computed_hashes_ = true;
72
73  if (!reader.GetHashes(relative_path_, &block_size_, &hashes_) ||
74      block_size_ % crypto::kSHA256Length != 0)
75    return false;
76
77  const std::string* expected_root =
78      verified_contents_->GetTreeHashRoot(relative_path_);
79  if (!expected_root)
80    return false;
81
82  std::string root =
83      ComputeTreeHashRoot(hashes_, block_size_ / crypto::kSHA256Length);
84  if (*expected_root != root)
85    return false;
86
87  status_ = SUCCESS;
88  return true;
89}
90
91int ContentHashReader::block_count() const {
92  DCHECK(status_ != NOT_INITIALIZED);
93  return hashes_.size();
94}
95
96int ContentHashReader::block_size() const {
97  DCHECK(status_ != NOT_INITIALIZED);
98  return block_size_;
99}
100
101bool ContentHashReader::GetHashForBlock(int block_index,
102                                        const std::string** result) const {
103  if (status_ != SUCCESS)
104    return false;
105  DCHECK(block_index >= 0);
106
107  if (static_cast<unsigned>(block_index) >= hashes_.size())
108    return false;
109  *result = &hashes_[block_index];
110
111  return true;
112}
113
114}  // namespace extensions
115